Solved output file string issues
This commit is contained in:
parent
0300036b4c
commit
5e1d546c9d
|
@ -1,4 +1,15 @@
|
||||||
cmake_minimum_required(VERSION 2.8.11)
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
project(caesium_clt)
|
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)
|
add_subdirectory(src)
|
20
README.md
20
README.md
|
@ -1,17 +1,19 @@
|
||||||
## Caesium Command Line Tools
|
## Caesium CommandLineTools
|
||||||
##### CCLT - v0.9.1-beta (build 20160808) - Copyright © Matteo Paonessa, 2016. All Rights Reserved.
|
##### caesium-clt - v0.10.0-beta (build 20161219) - Copyright © Matteo Paonessa, 2016. All Rights Reserved.
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
###### REQUIREMENTS
|
###### REQUIREMENTS
|
||||||
* [mozjpeg](https://github.com/mozilla/mozjpeg)
|
* [libcaesium](https://github.com/mozilla/mozjpeg)
|
||||||
* [zopflipng](https://github.com/google/zopfli)
|
|
||||||
* [lodepng](https://github.com/lvandeve/lodepng)
|
###### Included libraries
|
||||||
|
* [optparse](https://github.com/skeeto/optparse)
|
||||||
|
* [tinydir](https://github.com/cxong/tinydir)
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
###### TESTED PLATFORMS
|
###### TESTED PLATFORMS
|
||||||
* Mac OS X El Capitan (v10.11.4)
|
* Mac OS X Sierra (v10.12.1)
|
||||||
* Arch Linux
|
* Arch Linux
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
@ -60,13 +62,13 @@ $ caesiumclt -q 0 -R -o ~/output/ ~/Pictures
|
||||||
* 0.10.0-beta - Switched to cmake and libcaesium
|
* 0.10.0-beta - Switched to cmake and libcaesium
|
||||||
* 0.9.1-beta - Initial development stage
|
* 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
|
###### 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)
|
* 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)
|
* Author website - SaeraSoft - [http://saerasoft.com](http://saerasoft.com)
|
||||||
* Twitter - [Matteo Paonessa](https://twitter.com/MatteoPaonessa)
|
* Twitter - [Matteo Paonessa](https://twitter.com/MatteoPaonessa)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#define VERSION_MAJOR @VERSION_MAJOR@
|
||||||
|
#define VERSION_MINOR @VERSION_MINOR@
|
||||||
|
#define VERSION_PATCH @VERSION_PATCH@
|
||||||
|
|
60
src/helper.c
60
src/helper.c
|
@ -4,6 +4,7 @@
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "optparse.h"
|
#include "optparse.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
void initialize_jpeg_parameters(cs_image_pars *options)
|
void initialize_jpeg_parameters(cs_image_pars *options)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +39,7 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
||||||
{
|
{
|
||||||
struct optparse opts;
|
struct optparse opts;
|
||||||
//Initialize application options
|
//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
|
//Parse command line args
|
||||||
optparse_init(&opts, argv);
|
optparse_init(&opts, argv);
|
||||||
|
@ -58,13 +59,22 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case 'q':
|
case 'q':
|
||||||
options->jpeg.quality = atoi(opts.optarg);
|
options->jpeg.quality = atoi(opts.optarg);
|
||||||
|
if (options->jpeg.quality < 0 || options->jpeg.quality > 100) {
|
||||||
|
//TODO Trigger a error
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
options->jpeg.exif_copy = true;
|
options->jpeg.exif_copy = true;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
|
if (opts.optarg[strlen(opts.optarg) - 1] == '/') {
|
||||||
result.output_folder = malloc((strlen(opts.optarg) + 1) * sizeof(char));
|
result.output_folder = malloc((strlen(opts.optarg) + 1) * sizeof(char));
|
||||||
strncpy(result.output_folder, opts.optarg, strlen(opts.optarg) + 1);
|
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;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
result.recursive = true;
|
result.recursive = true;
|
||||||
|
@ -73,7 +83,7 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
||||||
result.keep_structure = true;
|
result.keep_structure = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
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);
|
exit(EXIT_SUCCESS);
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help();
|
print_help();
|
||||||
|
@ -89,11 +99,8 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
||||||
char *arg;
|
char *arg;
|
||||||
bool files_flag = false, folders_flag = false;
|
bool files_flag = false, folders_flag = false;
|
||||||
while ((arg = optparse_arg(&opts))) {
|
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
|
//Check if it's a directory and add its content
|
||||||
if (is_directory(arg)) {
|
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;
|
int count = 0;
|
||||||
count = scan_folder(arg, &result, result.recursive);
|
count = scan_folder(arg, &result, result.recursive);
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
@ -101,10 +108,9 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} 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));
|
result.input_files[result.files_count] = malloc((strlen(arg) + 1) * sizeof(char));
|
||||||
//TODO Replace with strdup for alloc
|
snprintf(result.input_files[result.files_count], strlen(arg) + 1, "%s", arg);
|
||||||
strncpy(result.input_files[result.files_count], arg, strlen(opts.optarg) + 1);
|
|
||||||
result.files_count++;
|
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 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
|
//TODO Support folder structure
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
//Create the output folder if does not exists
|
//Create the output folder if does not exists
|
||||||
if (mkpath(options->output_folder, 0777) == -1) {
|
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++) {
|
for (int i = 0; i < options->files_count; i++) {
|
||||||
//TODO remove unnecessary "/"s
|
|
||||||
char *filename = get_filename(options->input_files[i]);
|
char *filename = get_filename(options->input_files[i]);
|
||||||
char *output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 2) * sizeof(char));
|
char *output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 1) * sizeof(char));
|
||||||
strncpy(output_full_path, options->output_folder, strlen(options->output_folder));
|
snprintf(output_full_path, (strlen(filename) + strlen(options->output_folder) + 1), "%s%s", options->output_folder, filename);
|
||||||
strcat(output_full_path, "/");
|
|
||||||
strcat(output_full_path, filename);
|
|
||||||
|
|
||||||
|
fprintf(stdout, "(%d/%d) %s -> %s\n",
|
||||||
|
i + 1,
|
||||||
|
options->files_count,
|
||||||
|
filename,
|
||||||
|
output_full_path);
|
||||||
|
|
||||||
fprintf(stdout,
|
input_file_size = get_file_size(options->input_files[i]);
|
||||||
"Compressing %s in %s\n", filename, output_full_path);
|
options->input_total_size += input_file_size;
|
||||||
cs_compress(options->input_files[i], output_full_path, parameters);
|
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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
free(output_full_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return compressed_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,15 @@
|
||||||
|
|
||||||
#include <caesium.h>
|
#include <caesium.h>
|
||||||
|
|
||||||
typedef struct cclt_options {
|
typedef struct cclt_options
|
||||||
|
{
|
||||||
char **input_files;
|
char **input_files;
|
||||||
char *output_folder;
|
char *output_folder;
|
||||||
bool recursive;
|
bool recursive;
|
||||||
bool keep_structure;
|
bool keep_structure;
|
||||||
int files_count;
|
int files_count;
|
||||||
|
off_t input_total_size;
|
||||||
|
off_t output_total_size;
|
||||||
} cclt_options;
|
} cclt_options;
|
||||||
|
|
||||||
|
|
||||||
|
|
15
src/main.c
15
src/main.c
|
@ -10,7 +10,6 @@
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
long execution_ms = 0;
|
long execution_ms = 0;
|
||||||
int compression_status = 0;
|
|
||||||
cs_image_pars compress_options;
|
cs_image_pars compress_options;
|
||||||
cclt_options options;
|
cclt_options options;
|
||||||
|
|
||||||
|
@ -20,8 +19,7 @@ int main(int argc, char* argv[]) {
|
||||||
//Start a timer before calling the compression
|
//Start a timer before calling the compression
|
||||||
clock_t start = clock(), diff;
|
clock_t start = clock(), diff;
|
||||||
|
|
||||||
//TODO Compress here
|
start_compression(&options, &compress_options);
|
||||||
compression_status = start_compression(&options, &compress_options);
|
|
||||||
|
|
||||||
//Cleanup the two memory allocated objects
|
//Cleanup the two memory allocated objects
|
||||||
free(options.output_folder);
|
free(options.output_folder);
|
||||||
|
@ -32,9 +30,14 @@ int main(int argc, char* argv[]) {
|
||||||
execution_ms = diff * 1000 / CLOCKS_PER_SEC;
|
execution_ms = diff * 1000 / CLOCKS_PER_SEC;
|
||||||
|
|
||||||
//Output the compression results
|
//Output the compression results
|
||||||
fprintf(stdout,
|
|
||||||
"Performed in %lum%lus%lums\n",
|
fprintf(stdout, "-------------------------------\nCompression completed in "
|
||||||
execution_ms / 1000 / 60, execution_ms / 1000 % 60, execution_ms % 1000);
|
"%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);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
60
src/utils.c
60
src/utils.c
|
@ -3,6 +3,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <caesium.h>
|
#include <caesium.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "tinydir.h"
|
#include "tinydir.h"
|
||||||
|
|
||||||
|
@ -15,31 +16,27 @@ void print_help()
|
||||||
"Compress your pictures up to 90%% without visible quality loss.\n\n"
|
"Compress your pictures up to 90%% without visible quality loss.\n\n"
|
||||||
|
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
"\t-q, --quality\t\t\tset output file quality between [0-100], 0 for optimization\n"
|
"\t-q, --quality\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-e, --exif\t\tkeeps EXIF info during compression\n"
|
||||||
"\t-o, --output\t\t\toutput folder\n"
|
"\t-o, --output\t\toutput folder\n"
|
||||||
"\t-R, --recursive\t\t\tif input is a folder, scan subfolders too\n"
|
"\t-R, --recursive\t\tif input is a folder, scan subfolders too\n"
|
||||||
//TODO Remove this warning
|
//TODO Remove this warning
|
||||||
"\t-S, --keep-structure\tkeep the folder structure [Not active yet], use with -R\n"
|
"\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-h, --help\t\tdisplay this help and exit\n"
|
||||||
"\t-v, --version\t\t\toutput version information and exit\n\n");
|
"\t-v, --version\t\toutput version information and exit\n\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_directory(const char *path)
|
bool is_directory(const char *path)
|
||||||
{
|
{
|
||||||
tinydir_dir dir;
|
|
||||||
tinydir_file file;
|
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);
|
return (bool) file.is_dir;
|
||||||
is_dir = (bool) file.is_dir;
|
|
||||||
|
|
||||||
tinydir_close(&dir);
|
|
||||||
|
|
||||||
return is_dir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int scan_folder(const char *directory, cclt_options *options, bool recursive)
|
int scan_folder(const char *directory, cclt_options *options, bool recursive)
|
||||||
|
@ -114,3 +111,34 @@ char *get_filename(char *full_path)
|
||||||
return token;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
10
src/utils.h
10
src/utils.h
|
@ -7,13 +7,9 @@
|
||||||
|
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
|
|
||||||
#define APP_VERSION_STRING "0.10.0"
|
|
||||||
#define APP_VERSION_NUMBER 0100
|
|
||||||
#define BUILD 20161215
|
|
||||||
|
|
||||||
void print_help();
|
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);
|
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);
|
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
|
#endif //CAESIUM_CLT_UTILS_H
|
||||||
|
|
Loading…
Reference in New Issue