main code working
This commit is contained in:
parent
aa1b4419a7
commit
0943a8d46c
14
README.md
14
README.md
|
@ -1,4 +1,16 @@
|
||||||
# CaesiumCLT
|
# CaesiumCLT
|
||||||
Caesium Command Line Tools
|
Caesium Command Line Tools
|
||||||
|
|
||||||
This is a WIP README. To be updated.
|
Usage: cclt [OPTION] INPUT...
|
||||||
|
Compress your pictures up to 90% without visible quality loss.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-q set output file quality between [1-100], ignored for non-JPEGs
|
||||||
|
-e keeps EXIF info during compression
|
||||||
|
-o output to set folder
|
||||||
|
-l use lossless optimization
|
||||||
|
-s scale to value expressed as percentage (e.g. 20%)
|
||||||
|
-R if input is a folder scans subfolders too
|
||||||
|
-h display this help and exit
|
||||||
|
-v output version information and exit
|
||||||
|
|
||||||
|
|
12
compress.h
12
compress.h
|
@ -1,18 +1,6 @@
|
||||||
#ifndef CCTL_COMPRESS
|
#ifndef CCTL_COMPRESS
|
||||||
#define CCTL_COMPRESS
|
#define CCTL_COMPRESS
|
||||||
|
|
||||||
#include <jpeglib.h>
|
|
||||||
|
|
||||||
typedef struct cclt_compress_parameters {
|
|
||||||
int quality;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int smoothing_factor;
|
|
||||||
J_COLOR_SPACE color_space;
|
|
||||||
J_DCT_METHOD dct_method;
|
|
||||||
int exif_copy;
|
|
||||||
} cclt_compress_parameters;
|
|
||||||
|
|
||||||
void cclt_compress(char* output_file, unsigned char* image_buffer);
|
void cclt_compress(char* output_file, unsigned char* image_buffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
#include "lossless.h"
|
#include "lossless.h"
|
||||||
|
|
||||||
int cclt_optimize(char* input_file, char* output_file) {
|
int cclt_optimize(char* input_file, char* output_file) {
|
||||||
|
|
||||||
//File pointer for both input and output
|
//File pointer for both input and output
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
|
|
||||||
//Those will hold the input/output structs
|
//Those will hold the input/output structs
|
||||||
struct jpeg_decompress_struct srcinfo;
|
struct jpeg_decompress_struct srcinfo;
|
||||||
struct jpeg_compress_struct dstinfo;
|
struct jpeg_compress_struct dstinfo;
|
||||||
|
@ -33,7 +32,7 @@ int cclt_optimize(char* input_file, char* output_file) {
|
||||||
//Check for errors
|
//Check for errors
|
||||||
//TODO Use UNIX error messages
|
//TODO Use UNIX error messages
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
printf("Failed to open file \"%s\"\n", input_file);
|
printf("INPUT: Failed to open file \"%s\"\n", input_file);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +55,11 @@ int cclt_optimize(char* input_file, char* output_file) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
//Open the output one instead
|
//Open the output one instead
|
||||||
fp = fopen(output_file, "w");
|
fp = fopen(output_file, "w+");
|
||||||
//Check for errors
|
//Check for errors
|
||||||
//TODO Use UNIX error messages
|
//TODO Use UNIX error messages
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
printf("Failed to open file \"%s\"\n", output_file);
|
printf("OUTPUT: Failed to open file \"%s\"\n", output_file);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
175
main.c
175
main.c
|
@ -2,59 +2,88 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "lossless.h"
|
#include "lossless.h"
|
||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#define VERSION "1.9.9"
|
#define VERSION "1.9.9 BETA"
|
||||||
#define BUILD 20150508
|
#define BUILD 20150509
|
||||||
|
|
||||||
/* PARAMETERS:
|
/* PARAMETERS:
|
||||||
-q quality
|
-q quality
|
||||||
-e exif
|
-e exif
|
||||||
-o output file
|
-o output folder
|
||||||
-v version
|
-v version
|
||||||
-l lossless
|
-l lossless
|
||||||
-s scale
|
-s scale
|
||||||
-h help
|
-h help
|
||||||
-R recursive
|
-R recursive
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
|
cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
|
||||||
cclt_compress_parameters parameters;
|
|
||||||
|
//Initialize default params
|
||||||
|
cclt_compress_parameters parameters = initialize_compression_parameters();
|
||||||
int c;
|
int c;
|
||||||
char *qvalue = NULL;
|
|
||||||
char *evalue = NULL;
|
|
||||||
char *ovalue = NULL;
|
|
||||||
char *svalue = NULL;
|
|
||||||
|
|
||||||
while ((c = getopt (argc, argv, "q:ve:lo:s:hR")) != -1) {
|
while (optind < argc) {
|
||||||
switch (c) {
|
if ((c = getopt (argc, argv, "q:velo:s:hR")) != -1) {
|
||||||
case 'v':
|
switch (c) {
|
||||||
printf("CCLT - Caesium Command Line Tool - Version %s (Build: %d)\n", VERSION, BUILD);
|
case 'v':
|
||||||
break;
|
printf("CCLT - Caesium Command Line Tool - Version %s (Build: %d)\n", VERSION, BUILD);
|
||||||
case '?':
|
exit(0);
|
||||||
if (optopt == 'q' || optopt == 'e' || optopt == 'o' || optopt == 's') {
|
break;
|
||||||
//fprintf (stderr, "Option -%c requires an argument.\n", optopt);
|
case '?':
|
||||||
//Arguments without values
|
if (optopt == 'q' || optopt == 'o' || optopt == 's') {
|
||||||
exit(-1);
|
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
|
||||||
}
|
//Arguments without values
|
||||||
else if (isprint(optopt)) {
|
exit(-1);
|
||||||
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
|
}
|
||||||
}
|
else if (isprint(optopt)) {
|
||||||
else {
|
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
|
||||||
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
|
}
|
||||||
}
|
else {
|
||||||
break;
|
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
|
||||||
case 'q':
|
}
|
||||||
qvalue = optarg;
|
break;
|
||||||
break;
|
case ':':
|
||||||
case 'e':
|
fprintf(stderr, "Parameter expected.\n");
|
||||||
evalue = optarg;
|
break;
|
||||||
break;
|
case 'q':
|
||||||
default:
|
parameters.quality = string_to_int(optarg);
|
||||||
abort();
|
break;
|
||||||
|
case 'e':
|
||||||
|
parameters.exif_copy = 1;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
parameters.lossless = 1;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
parameters.output_folder = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
parameters.scaling_factor = string_to_int(optarg);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
print_help();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int i = 0;
|
||||||
|
parameters.input_files = (char**) malloc ((argc - optind) * sizeof (char*));
|
||||||
|
while (optind < argc) {
|
||||||
|
parameters.input_files[i] = (char*) malloc (strlen(argv[optind]) * sizeof(char)); //TODO Necessary??
|
||||||
|
parameters.input_files[i] = argv[optind];
|
||||||
|
parameters.input_files_count = i + 1;
|
||||||
|
optind++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,16 +91,70 @@ cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char *argv[]) {
|
int main (int argc, char *argv[]) {
|
||||||
|
errno = 0;
|
||||||
cclt_compress_parameters parameters;
|
//Parse arguments
|
||||||
|
cclt_compress_parameters pars = parse_arguments(argc, argv);
|
||||||
//Check if there's at least one argument
|
|
||||||
if (argc <= 1) {
|
|
||||||
printf("CCLT requires at least one argument. Aborting.\n");
|
|
||||||
return -1;
|
//Either -l or -q must be set but not together
|
||||||
|
if ((pars.lossless == 1) ^ (pars.quality > 0) == 0) {
|
||||||
|
//Both or none are set
|
||||||
|
if (pars.lossless == 1 && pars.quality != -1) {
|
||||||
|
fprintf(stderr, "-l option can't be used with -q. Either use one or the other. Aborting.\n");
|
||||||
|
exit(-1);
|
||||||
|
} else if (pars.lossless == 0 && pars.quality == -1) {
|
||||||
|
fprintf(stderr, "Either -l or -q must be set. Aborting.\n");
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//One of them is set
|
||||||
|
//If -q is set check it is within the 1-100 range
|
||||||
|
if (!(pars.quality >= 1 && pars.quality <= 100) && pars.lossless == 0) {
|
||||||
|
fprintf(stderr, "Quality must be within a [1-100] range. Aborting.\n");
|
||||||
|
exit(-3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters = parse_arguments(argc, argv);
|
//Check if you set the input files
|
||||||
|
if (pars.input_files_count == 0) {
|
||||||
return 0;
|
fprintf(stderr, "No input files. Aborting.\n");
|
||||||
|
exit(-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if there's a valid scaling factor
|
||||||
|
if (pars.scaling_factor <= 0) {
|
||||||
|
fprintf(stderr, "Scaling factor must be > 0. Aborting.\n");
|
||||||
|
exit(-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the output folder exists, otherwise create it
|
||||||
|
if (pars.output_folder == NULL) {
|
||||||
|
fprintf(stderr, "No -o option pointing to the destination folder. Aborting.\n");
|
||||||
|
exit(-4);
|
||||||
|
} else {
|
||||||
|
if (mkdir(pars.output_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
perror("mkdir");
|
||||||
|
exit(-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < pars.input_files_count; i++) {
|
||||||
|
|
||||||
|
char* output_filename = pars.output_folder;
|
||||||
|
char* i_tmp = (char*) malloc (strlen(pars.input_files[i]) * sizeof(char));
|
||||||
|
strcpy(i_tmp, pars.input_files[i]);
|
||||||
|
if (output_filename[strlen(pars.output_folder -1)] != '/') {
|
||||||
|
strcat(pars.output_folder, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
output_filename = strcat(pars.output_folder, i_tmp);
|
||||||
|
cclt_optimize(pars.input_files[i], output_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 983 KiB |
|
@ -0,0 +1,74 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <jpeglib.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
cclt_compress_parameters initialize_compression_parameters() {
|
||||||
|
cclt_compress_parameters par;
|
||||||
|
|
||||||
|
par.quality = 0;
|
||||||
|
par.width = 0;
|
||||||
|
par.height = 0;
|
||||||
|
par.smoothing_factor = 50;
|
||||||
|
par.scaling_factor = 100;
|
||||||
|
//par.color_space = NULL; TODO Must set?
|
||||||
|
//par.dct_method = NULL; TODO Must set?
|
||||||
|
par.output_folder = NULL;
|
||||||
|
par.exif_copy = 0;
|
||||||
|
par.lossless = 0;
|
||||||
|
par.input_files_count = 0;
|
||||||
|
//par.input_files = (char**) malloc (55 * sizeof(char));
|
||||||
|
return par;
|
||||||
|
}
|
||||||
|
|
||||||
|
int string_to_int(char* in_string) {
|
||||||
|
int value = 0;
|
||||||
|
char* endptr;
|
||||||
|
errno = 0; //Error checking
|
||||||
|
|
||||||
|
value = strtol(in_string, &endptr, 0); //Convert the string
|
||||||
|
|
||||||
|
//Check errors
|
||||||
|
if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN))
|
||||||
|
|| (errno != 0 && value == 0)) {
|
||||||
|
perror("strtol");
|
||||||
|
exit(-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr == in_string) {
|
||||||
|
fprintf(stderr, "Parse error: No digits were found for -q option. Aborting.\n");
|
||||||
|
exit(-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_help() {
|
||||||
|
fprintf(stdout,
|
||||||
|
"Usage: cclt [OPTION] INPUT...\n"
|
||||||
|
"Compress your pictures up to 90% without visible quality loss.\n\n"
|
||||||
|
|
||||||
|
"Options:\n"
|
||||||
|
"\t-q\tset output file quality between [1-100], ignored for non-JPEGs\n"
|
||||||
|
"\t-e\tkeeps EXIF info during compression\n"
|
||||||
|
"\t-o\tcompress to custom folder\n"
|
||||||
|
"\t-l\tuse lossless optimization\n"
|
||||||
|
"\t-s\tscale to value, expressed as percentage (e.g. 20%)\n"
|
||||||
|
"\t-R\tif input is a folder, scan subfolders too\n"
|
||||||
|
"\t-h\tdisplay this help and exit\n"
|
||||||
|
"\t-v\toutput version information and exit\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_progress(int current, int max, char* message) {
|
||||||
|
fprintf(stdout, "\e[?25l");
|
||||||
|
fprintf(stdout, "\r%s[%d\%]", message, current * 100 / max);
|
||||||
|
if (current == max) {
|
||||||
|
fprintf(stdout, "\e[?25h\n");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef CCTL_UTILS
|
||||||
|
#define CCTL_UTILS
|
||||||
|
|
||||||
|
#include <jpeglib.h>
|
||||||
|
|
||||||
|
typedef struct cclt_compress_parameters {
|
||||||
|
int quality;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int smoothing_factor;
|
||||||
|
int scaling_factor;
|
||||||
|
char* output_folder;
|
||||||
|
J_COLOR_SPACE color_space;
|
||||||
|
J_DCT_METHOD dct_method;
|
||||||
|
int exif_copy;
|
||||||
|
int lossless;
|
||||||
|
char** input_files;
|
||||||
|
int input_files_count;
|
||||||
|
} cclt_compress_parameters;
|
||||||
|
|
||||||
|
cclt_compress_parameters initialize_compression_parameters();
|
||||||
|
|
||||||
|
int string_to_int(char* in_string);
|
||||||
|
void print_help();
|
||||||
|
void print_progress(int current, int max, char* message);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue