diff --git a/CMakeLists.txt b/CMakeLists.txt index e613397..e588331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(caesiumclt) # The version number. set(VERSION_MAJOR 0) -set(VERSION_MINOR 11) +set(VERSION_MINOR 12) set(VERSION_PATCH 0) configure_file( diff --git a/src/error.c b/src/error.c index e2e6b21..c290249 100644 --- a/src/error.c +++ b/src/error.c @@ -44,6 +44,10 @@ const char *get_error_message(int code) return "-S has no effect without -R."; case 12: return "Cannot set output folder inside the input one"; + case 13: + return "Scale factor must be > 0 and <= 1.0. Setting it to 1.0."; + case 14: + return "Scale factor parsing error."; default: return "Unrecognized error."; diff --git a/src/helper.c b/src/helper.c index e98ef82..c09ffb8 100644 --- a/src/helper.c +++ b/src/helper.c @@ -24,6 +24,7 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) {"quality", 'q', OPTPARSE_REQUIRED}, {"exif", 'e', OPTPARSE_NONE}, {"output", 'o', OPTPARSE_REQUIRED}, + {"scale", 's', OPTPARSE_REQUIRED}, {"recursive", 'R', OPTPARSE_NONE}, {"keep-structure", 'S', OPTPARSE_NONE}, {"dry-run", 'd', OPTPARSE_NONE}, @@ -36,7 +37,7 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) while ((option = optparse_long(&opts, longopts, NULL)) != -1) { switch (option) { case 'q': - options->jpeg.quality = (int) strtol(opts.optarg, (char **) NULL, 10);; + options->jpeg.quality = (int) strtol(opts.optarg, (char **) NULL, 10); if (options->jpeg.quality < 0 || options->jpeg.quality > 100) { display_error(ERROR, 1); } @@ -59,6 +60,9 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) #endif } break; + case 's': + options->jpeg.scale_factor = options->png.scale_factor = parse_scale_factor(opts.optarg); + break; case 'R': parameters.recursive = true; break; @@ -107,14 +111,14 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) if (is_directory(resolved_path)) { if (!files_flag) { folders_flag = true; - - if (resolved_path[strlen(resolved_path) - 1] != '/' && resolved_path[strlen(resolved_path) - 1] != '\\') { + size_t len = strlen(resolved_path); + if (resolved_path[len - 1] != '/' && resolved_path[strlen(resolved_path) - 1] != '\\') { #ifdef _WIN32 - resolved_path[strlen(resolved_path)] = '\\'; + resolved_path[len] = '\\'; #else - resolved_path[strlen(resolved_path)] = '/'; + resolved_path[len] = '/'; #endif - resolved_path[strlen(resolved_path)] = '\0'; + resolved_path[len + 1] = '\0'; } snprintf(parameters.input_folder, strlen(resolved_path) + 1, "%s", resolved_path); diff --git a/src/utils.c b/src/utils.c index 7914c4b..34c813f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -21,6 +21,7 @@ void print_help() "\t-q, --quality\t\tset output file quality between [0-100], 0 for optimization\n" "\t-e, --exif\t\tkeeps EXIF info during compression\n" "\t-o, --output\t\toutput folder\n" + "\t-s, --scale\t\tscale the image. Allowed values are [.x, 0.x, n/d, xx%%].\n\t\t\t\tMust be > 0 and <= 1.0.\n" "\t-R, --recursive\t\tif input is a folder, scan subfolders too\n" "\t-S, --keep-structure\tkeep the folder structure, use with -R\n" "\t-d, --dry-run\t\tdo not really compress files but just show output paths\n" @@ -168,6 +169,79 @@ bool file_exists(const char *file_path) return (stat(file_path, &buffer) == 0); } +int strndx(const char *string, const char search) +{ + char *pointer = strchr(string, search); + if (pointer == NULL) { + return -1; + } else { + return (int) (pointer - string); + } +} + +double parse_scale_factor(const char *factor_string) +{ + /* + * We're gonna accept scaling factor as such: + * a. 0.5 or .5 or 1 + * b. 3/4 + * c. 80% + * We're gonna test a. last since it's "standard" + */ + int index; + bool parse_error = false; + double scale_factor = 1.0; + + if ((index = strndx(factor_string, '/')) != -1 + && strndx(factor_string, '%') == -1) { + if (index == 0 || index == strlen(factor_string) - 1) { + parse_error = true; + } else { + char *num_str = malloc((index + 1) * sizeof(char)); + char *den_str = malloc((strlen(factor_string) - index) * sizeof(char)); + snprintf(num_str, index + 1, "%s", factor_string); + snprintf(den_str, strlen(factor_string) - index, "%s", factor_string + index + 1); + long num = strtol(num_str, (char **) NULL, 10); + long den = strtol(den_str, (char **) NULL, 10); + if (num > 0 && den > 0) { + scale_factor = (double) num / (double) den; + } else { + parse_error = true; + } + } + } else if ((index = strndx(factor_string, '%')) != -1 + && strndx(factor_string, '/') == -1) { + if (index != strlen(factor_string) - 1) { + parse_error = true; + } else { + char *num_str = malloc((index + 1) * sizeof(char)); + snprintf(num_str, index + 1, "%s", factor_string); + long num = strtol(num_str, (char **) NULL, 10); + scale_factor = (double) num / 100.0; + free(num_str); + } + } else { + // Maybe it's just a number! + char *endstr; + scale_factor = strtod(factor_string, &endstr); + if (scale_factor == 0.0 || endstr[0] != '\0') { + parse_error = true; + } + } + + if (parse_error) { + display_error(WARNING, 14); + exit(-14); + } + + if (scale_factor <= 0 || scale_factor > 1.0) { + display_error(WARNING, 13); + return 1.0; + } + return scale_factor; +} + + #ifdef _WIN32 char *str_replace(char *orig, char *rep, char *with) { char *result; // the return string diff --git a/src/utils.h b/src/utils.h index 87de3c6..2acc863 100644 --- a/src/utils.h +++ b/src/utils.h @@ -23,6 +23,10 @@ int mkpath(const char *pathname); bool file_exists(const char* file_path); +int strndx(const char* string, const char search); + +double parse_scale_factor(const char* factor_string); + #ifdef _WIN32 char *str_replace(char *orig, char *rep, char *with); char *strsep(char **stringp, const char *delim);