Solved output file string issues

This commit is contained in:
Matteo Paonessa 2016-12-28 16:33:45 +01:00
parent 0300036b4c
commit 5e1d546c9d
8 changed files with 137 additions and 64 deletions

View File

@ -1,4 +1,15 @@
cmake_minimum_required(VERSION 2.8.11)
project(caesium_clt)
# The version number.
set(VERSION_MAJOR 0)
set(VERSION_MINOR 10)
set(VERSION_PATCH 0)
configure_file(
"src/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
include_directories("${PROJECT_BINARY_DIR}")
add_subdirectory(src)

View File

@ -1,17 +1,19 @@
## Caesium Command Line Tools
##### CCLT - v0.9.1-beta (build 20160808) - Copyright © Matteo Paonessa, 2016. All Rights Reserved.
## Caesium CommandLineTools
##### caesium-clt - v0.10.0-beta (build 20161219) - Copyright © Matteo Paonessa, 2016. All Rights Reserved.
----------
###### REQUIREMENTS
* [mozjpeg](https://github.com/mozilla/mozjpeg)
* [zopflipng](https://github.com/google/zopfli)
* [lodepng](https://github.com/lvandeve/lodepng)
* [libcaesium](https://github.com/mozilla/mozjpeg)
###### Included libraries
* [optparse](https://github.com/skeeto/optparse)
* [tinydir](https://github.com/cxong/tinydir)
----------
###### TESTED PLATFORMS
* Mac OS X El Capitan (v10.11.4)
* Mac OS X Sierra (v10.12.1)
* Arch Linux
----------
@ -60,13 +62,13 @@ $ caesiumclt -q 0 -R -o ~/output/ ~/Pictures
* 0.10.0-beta - Switched to cmake and libcaesium
* 0.9.1-beta - Initial development stage
Check the [Commits](https://github.com/Lymphatus/CaesiumCLT/commits/master) for a detailed list of changes.
Check the [Commits](https://github.com/Lymphatus/caesium-clt/commits/master) for a detailed list of changes.
----------
###### RESOURCES
* CaesiumCLT website - [http://saerasoft.com/caesium/clt](http://saerasoft.com/caesium/clt)
* caesium-clt website - [http://saerasoft.com/caesium/clt](http://saerasoft.com/caesium/clt)
* Caesium website - [http://saerasoft.com/caesium](http://saerasoft.com/caesium)
* CaesiumCLT Git Repository - [https://github.com/Lymphatus/CaesiumCLT](https://github.com/Lymphatus/CaesiumCLT)
* caesium-clt Git Repository - [https://github.com/Lymphatus/CaesiumCLT](https://github.com/Lymphatus/caesium-clt)
* Author website - SaeraSoft - [http://saerasoft.com](http://saerasoft.com)
* Twitter - [Matteo Paonessa](https://twitter.com/MatteoPaonessa)

4
src/config.h.in Normal file
View File

@ -0,0 +1,4 @@
#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@
#define VERSION_PATCH @VERSION_PATCH@

View File

@ -4,6 +4,7 @@
#include "helper.h"
#include "optparse.h"
#include "utils.h"
#include "config.h"
void initialize_jpeg_parameters(cs_image_pars *options)
{
@ -38,18 +39,18 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
{
struct optparse opts;
//Initialize application options
cclt_options result = {NULL, NULL, false, false, 0};
cclt_options result = {NULL, NULL, false, false, 0, 0, 0};
//Parse command line args
optparse_init(&opts, argv);
struct optparse_long longopts[] = {
{"quality", 'q', OPTPARSE_REQUIRED},
{"exif", 'e', OPTPARSE_NONE},
{"output", 'o', OPTPARSE_REQUIRED},
{"recursive", 'R', OPTPARSE_NONE},
{"quality", 'q', OPTPARSE_REQUIRED},
{"exif", 'e', OPTPARSE_NONE},
{"output", 'o', OPTPARSE_REQUIRED},
{"recursive", 'R', OPTPARSE_NONE},
{"keep-structure", 'S', OPTPARSE_NONE},
{"version", 'v', OPTPARSE_NONE},
{"help", 'h', OPTPARSE_NONE},
{"version", 'v', OPTPARSE_NONE},
{"help", 'h', OPTPARSE_NONE},
{0}
};
int option;
@ -58,22 +59,31 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
switch (option) {
case 'q':
options->jpeg.quality = atoi(opts.optarg);
if (options->jpeg.quality < 0 || options->jpeg.quality > 100) {
//TODO Trigger a error
exit(EXIT_FAILURE);
}
break;
case 'e':
options->jpeg.exif_copy = true;
break;
case 'o':
result.output_folder = malloc((strlen(opts.optarg) + 1) * sizeof(char));
strncpy(result.output_folder, opts.optarg, strlen(opts.optarg) + 1);
if (opts.optarg[strlen(opts.optarg) - 1] == '/') {
result.output_folder = malloc((strlen(opts.optarg) + 1) * sizeof(char));
snprintf(result.output_folder, strlen(opts.optarg) + 1, "%s", opts.optarg);
} else {
result.output_folder = malloc((strlen(opts.optarg) + 2) * sizeof(char));
snprintf(result.output_folder, strlen(opts.optarg) + 2, "%s/", opts.optarg);
}
break;
case 'R':
result.recursive = true;
result.recursive = true;
break;
case 'S':
result.keep_structure = true;
break;
case 'v':
fprintf(stdout, "%s-%d\n", APP_VERSION_STRING, BUILD);
fprintf(stdout, "%d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
exit(EXIT_SUCCESS);
case 'h':
print_help();
@ -89,11 +99,8 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
char *arg;
bool files_flag = false, folders_flag = false;
while ((arg = optparse_arg(&opts))) {
//TODO Check if there's a folder and change behaviour accordingly
//Check if it's a directory and add its content
if (is_directory(arg)) {
//NOTE Scanning a folder with this function does not check if we are actually getting images
//The actual check is performed by the library
int count = 0;
count = scan_folder(arg, &result, result.recursive);
if (count == 0) {
@ -101,10 +108,9 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
}
} else {
result.input_files = realloc(result.input_files, (result.files_count + 1) * sizeof(char*));
result.input_files = realloc(result.input_files, (result.files_count + 1) * sizeof(char *));
result.input_files[result.files_count] = malloc((strlen(arg) + 1) * sizeof(char));
//TODO Replace with strdup for alloc
strncpy(result.input_files[result.files_count], arg, strlen(opts.optarg) + 1);
snprintf(result.input_files[result.files_count], strlen(arg) + 1, "%s", arg);
result.files_count++;
}
}
@ -118,8 +124,10 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
int start_compression(cclt_options *options, cs_image_pars *parameters)
{
int compressed_files = 0;
off_t input_file_size = 0;
off_t output_file_size = 0;
//TODO Support folder structure
int status = 0;
//Create the output folder if does not exists
if (mkpath(options->output_folder, 0777) == -1) {
@ -128,21 +136,35 @@ int start_compression(cclt_options *options, cs_image_pars *parameters)
}
for (int i = 0; i < options->files_count; i++) {
//TODO remove unnecessary "/"s
char *filename = get_filename(options->input_files[i]);
char *output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 2) * sizeof(char));
strncpy(output_full_path, options->output_folder, strlen(options->output_folder));
strcat(output_full_path, "/");
strcat(output_full_path, filename);
char *output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 1) * sizeof(char));
snprintf(output_full_path, (strlen(filename) + strlen(options->output_folder) + 1), "%s%s", options->output_folder, filename);
fprintf(stdout, "(%d/%d) %s -> %s\n",
i + 1,
options->files_count,
filename,
output_full_path);
fprintf(stdout,
"Compressing %s in %s\n", filename, output_full_path);
cs_compress(options->input_files[i], output_full_path, parameters);
input_file_size = get_file_size(options->input_files[i]);
options->input_total_size += input_file_size;
if (cs_compress(options->input_files[i], output_full_path, parameters)) {
compressed_files++;
output_file_size = get_file_size(output_full_path);
options->output_total_size += output_file_size;
fprintf(stdout, "%s -> %s [%.2f%%]\n",
get_human_size(input_file_size),
get_human_size(output_file_size),
((float) output_file_size - input_file_size) * 100 / input_file_size);
} else {
options->input_total_size -= get_file_size(options->input_files[i]);
}
free(output_full_path);
}
return status;
return compressed_files;
}

View File

@ -3,12 +3,15 @@
#include <caesium.h>
typedef struct cclt_options {
typedef struct cclt_options
{
char **input_files;
char *output_folder;
bool recursive;
bool keep_structure;
int files_count;
off_t input_total_size;
off_t output_total_size;
} cclt_options;

View File

@ -10,7 +10,6 @@
int main(int argc, char* argv[]) {
errno = 0;
long execution_ms = 0;
int compression_status = 0;
cs_image_pars compress_options;
cclt_options options;
@ -20,8 +19,7 @@ int main(int argc, char* argv[]) {
//Start a timer before calling the compression
clock_t start = clock(), diff;
//TODO Compress here
compression_status = start_compression(&options, &compress_options);
start_compression(&options, &compress_options);
//Cleanup the two memory allocated objects
free(options.output_folder);
@ -32,9 +30,14 @@ int main(int argc, char* argv[]) {
execution_ms = diff * 1000 / CLOCKS_PER_SEC;
//Output the compression results
fprintf(stdout,
"Performed in %lum%lus%lums\n",
execution_ms / 1000 / 60, execution_ms / 1000 % 60, execution_ms % 1000);
fprintf(stdout, "-------------------------------\nCompression completed in "
"%lum%lus%lums\n%s -> %s [%.2f%% | %s]\n",
execution_ms / 1000 / 60, execution_ms / 1000 % 60, execution_ms % 1000,
get_human_size(options.input_total_size), get_human_size(options.output_total_size),
((float)options.output_total_size - options.input_total_size) * 100 / options.input_total_size,
get_human_size((options.output_total_size - options.input_total_size)));
exit(EXIT_SUCCESS);
}

View File

@ -3,6 +3,7 @@
#include <sys/stat.h>
#include <caesium.h>
#include <limits.h>
#include <math.h>
#include "utils.h"
#include "tinydir.h"
@ -15,31 +16,27 @@ void print_help()
"Compress your pictures up to 90%% without visible quality loss.\n\n"
"Options:\n"
"\t-q, --quality\t\t\tset output file quality between [0-100], 0 for optimization\n"
"\t-e, --exif\t\t\t\tkeeps EXIF info during compression\n"
"\t-o, --output\t\t\toutput folder\n"
"\t-R, --recursive\t\t\tif input is a folder, scan subfolders too\n"
"\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-R, --recursive\t\tif input is a folder, scan subfolders too\n"
//TODO Remove this warning
"\t-S, --keep-structure\tkeep the folder structure [Not active yet], use with -R\n"
"\t-h, --help\t\t\t\tdisplay this help and exit\n"
"\t-v, --version\t\t\toutput version information and exit\n\n");
"\t-h, --help\t\tdisplay this help and exit\n"
"\t-v, --version\t\toutput version information and exit\n\n");
exit(EXIT_SUCCESS);
}
int is_directory(const char *path)
bool is_directory(const char *path)
{
tinydir_dir dir;
tinydir_file file;
bool is_dir = false;
tinydir_open(&dir, path);
if (tinydir_file_open(&file, path) == -1) {
//TODO Error
exit(EXIT_FAILURE);
}
tinydir_readfile(&dir, &file);
is_dir = (bool) file.is_dir;
tinydir_close(&dir);
return is_dir;
return (bool) file.is_dir;
}
int scan_folder(const char *directory, cclt_options *options, bool recursive)
@ -114,3 +111,34 @@ char *get_filename(char *full_path)
return token;
}
off_t get_file_size(const char *path)
{
tinydir_file file;
if (tinydir_file_open(&file, path) == -1) {
//TODO Error
exit(EXIT_FAILURE);
}
return file._s.st_size;
}
char* get_human_size(off_t size) {
//We should not get more than TB images
char* unit[5] = {"B", "KB", "MB", "GB", "TB"};
//Index of the array containing the correct unit
double order = floor(log2(labs(size)) / 10);
//Alloc enough size for the final string
char* final = (char*) malloc(((int) (floor(log10(labs(size))) + 4)) * sizeof(char));
//If the order exceeds 4, something is fishy
if (order > 4) {
order = 4;
}
//Copy the formatted string into the buffer
sprintf(final, "%.2f %s", size / (pow(1024, order)), unit[(int)order]);
//And return it
return final;
}

View File

@ -7,13 +7,9 @@
#include "helper.h"
#define APP_VERSION_STRING "0.10.0"
#define APP_VERSION_NUMBER 0100
#define BUILD 20161215
void print_help();
int is_directory(const char *path);
bool is_directory(const char *path);
int scan_folder(const char *directory, cclt_options *options, bool recursive);
@ -21,5 +17,9 @@ int mkpath(const char *pathname, mode_t mode);
char *get_filename(char * full_path);
off_t get_file_size(const char *path);
char* get_human_size(off_t size);
#endif //CAESIUM_CLT_UTILS_H