Using Rust libcaesium

This commit is contained in:
Matteo Paonessa 2021-10-23 21:49:43 +02:00
parent 8be97e4201
commit 91ac6ff742
10 changed files with 111 additions and 94 deletions

View File

@ -23,6 +23,6 @@ before_install:
before_script: before_script:
- mkdir build - mkdir build
- cd build - cd build
- cmake .. - cmake .. -DLIBCAESIUM_PATH=libcaesium/target/release
script: make script: make

View File

@ -11,16 +11,13 @@ You will also need cmake if you want to compile it from source.
For Windows you just need to download the latest release package from [here](https://github.com/Lymphatus/caesium-clt/releases). For Windows you just need to download the latest release package from [here](https://github.com/Lymphatus/caesium-clt/releases).
Unzip the package using your favorite software, open it and run `caesiumclt.exe` from the Command Prompt or PowerShell. Unzip the package using your favorite software, open it and run `caesiumclt.exe` from the Command Prompt or PowerShell.
### MacOS X ### MacOS X and Linux
**NOTE:** Homebrew installation will come soon. Use Linux instructions below for now.
### Linux
Download the latest release package from [here](https://github.com/Lymphatus/caesium-clt/releases) or clone from git. Download the latest release package from [here](https://github.com/Lymphatus/caesium-clt/releases) or clone from git.
Then run: Then run:
$ cd caesium-clt $ cd caesium-clt
$ mkdir build && cd build $ mkdir build && cd build
$ cmake .. $ cmake .. -DLIBCAESIUM_PATH=/your/libcaesium/path/dir
$ make $ make
$ sudo make install $ sudo make install

View File

@ -3,10 +3,4 @@
#libcaesium #libcaesium
git clone https://github.com/Lymphatus/libcaesium.git git clone https://github.com/Lymphatus/libcaesium.git
cd libcaesium || exit cd libcaesium || exit
sudo chmod +x install.sh cargo build --release
./install.sh
mkdir build
cd build || exit
cmake ..
make
sudo make install

View File

@ -7,7 +7,6 @@ FILE(GLOB CVendorHeaders vendor/*.h)
add_executable(caesiumclt ${CVendorSources} ${CVendorHeaders} ${CSources} ${CHeaders}) add_executable(caesiumclt ${CVendorSources} ${CVendorHeaders} ${CSources} ${CHeaders})
target_link_libraries(caesiumclt LINK_PUBLIC caesium) target_link_libraries(caesiumclt LINK_PUBLIC caesium m)
target_link_libraries(caesiumclt LINK_PUBLIC m)
install(TARGETS caesiumclt DESTINATION bin) install(TARGETS caesiumclt DESTINATION bin)

View File

@ -16,7 +16,6 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <caesium.h>
#include <stdlib.h> #include <stdlib.h>
#include "error.h" #include "error.h"

View File

@ -18,6 +18,12 @@
#ifndef CAESIUMCLT_ERROR_H #ifndef CAESIUMCLT_ERROR_H
#define CAESIUMCLT_ERROR_H #define CAESIUMCLT_ERROR_H
typedef enum error_level
{
ERROR = 0,
WARNING = 1
} error_level;
void display_error(error_level level, int code); void display_error(error_level level, int code);
const char *get_error_message(int code); const char *get_error_message(int code);

View File

@ -31,7 +31,7 @@
#include "error.h" #include "error.h"
#include "shared.h" #include "shared.h"
cclt_options parse_arguments(char **argv, cs_image_pars *options) { cclt_options parse_arguments(char **argv, C_CSParameters *options) {
struct optparse opts; struct optparse opts;
//Initialize application options //Initialize application options
cclt_options parameters = {NULL, "", "", false, false, 0, 0, 0, false, all}; cclt_options parameters = {NULL, "", "", false, false, 0, 0, 0, false, all};
@ -52,58 +52,64 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) {
{0} {0}
}; };
optparse_init(&opts, argv); optparse_init(&opts, argv);
int option; int option;
while ((option = optparse_long(&opts, longopts, NULL)) != -1) { int quality = 0;
switch (option) { while ((option = optparse_long(&opts, longopts, NULL)) != -1) {
case 'q': switch (option) {
options->jpeg.quality = (int) strtol(opts.optarg, (char **) NULL, 10); case 'q':
if (options->jpeg.quality < 0 || options->jpeg.quality > 100) { quality = (int) strtol(opts.optarg, (char **) NULL, 10);
display_error(ERROR, 1); if (quality < 0 || quality > 100) {
} display_error(ERROR, 1);
break; }
case 'e': if (quality == 0) {
options->jpeg.exif_copy = true; options->optimize = true;
break; } else {
case 'o': options->jpeg_quality = quality;
if (opts.optarg[0] == '~') { options->png_level = parse_png_quality(quality);
snprintf(parameters.output_folder, strlen(opts.optarg) + 1, "%s", opts.optarg); options->webp_quality = quality;
} else { options->gif_quality = quality;
}
break;
case 'e':
options->keep_metadata = true;
break;
case 'o':
if (opts.optarg[0] == '~') {
snprintf(parameters.output_folder, strlen(opts.optarg) + 1, "%s", opts.optarg);
} else {
#ifdef _WIN32 #ifdef _WIN32
_fullpath(parameters.output_folder, opts.optarg, MAX_PATH); _fullpath(parameters.output_folder, opts.optarg, MAX_PATH);
#else #else
char* computedPath = realpath(opts.optarg, parameters.output_folder); char *computedPath = realpath(opts.optarg, parameters.output_folder);
if (computedPath == NULL) { if (computedPath == NULL) {
//Folder does not exists and may just fail on some systems, like Docker Alpine //Folder does not exists and may just fail on some systems, like Docker Alpine
if (errno == 2) { if (errno == 2) {
if (mkpath(opts.optarg) == 0) { if (mkpath(opts.optarg) == 0) {
computedPath = realpath(opts.optarg, parameters.output_folder); computedPath = realpath(opts.optarg, parameters.output_folder);
if (computedPath == NULL) { if (computedPath == NULL) {
//Just throw an error here //Just throw an error here
display_error(ERROR, 16); display_error(ERROR, 16);
} }
} else { } else {
display_error(ERROR, 17); display_error(ERROR, 17);
} }
} else { } else {
display_error(ERROR, 16); display_error(ERROR, 16);
} }
} }
#endif #endif
} }
int pathlen = (int)strlen(parameters.output_folder); int pathlen = (int) strlen(parameters.output_folder);
if (parameters.output_folder[pathlen - 1] != '/' && if (parameters.output_folder[pathlen - 1] != '/' &&
parameters.output_folder[pathlen - 1] != '\\') { parameters.output_folder[pathlen - 1] != '\\') {
// append the extra slash/backslash // append the extra slash/backslash
#ifdef _WIN32 #ifdef _WIN32
snprintf(parameters.output_folder+pathlen, 2, "\\"); snprintf(parameters.output_folder + pathlen, 2, "\\");
#else #else
snprintf(parameters.output_folder + pathlen, 2, "/"); snprintf(parameters.output_folder + pathlen, 2, "/");
#endif #endif
} }
break; break;
case 's':
options->jpeg.scale_factor = options->png.scale_factor = parse_scale_factor(opts.optarg);
break;
case 'R': case 'R':
parameters.recursive = true; parameters.recursive = true;
break; break;
@ -119,9 +125,9 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) {
case 'v': case 'v':
print_to_console(stdout, 1, "%d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); print_to_console(stdout, 1, "%d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'Q': case 'Q':
verbose = 0; verbose = 0;
break; break;
case 'h': case 'h':
print_help(); print_help();
break; break;
@ -136,7 +142,7 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) {
bool files_flag = false, folders_flag = false; bool files_flag = false, folders_flag = false;
char resolved_path[MAX_PATH_SIZE]; char resolved_path[MAX_PATH_SIZE];
print_to_console(stdout, verbose,"%s\n", "Collecting files..."); print_to_console(stdout, verbose, "%s\n", "Collecting files...");
while ((arg = optparse_arg(&opts))) { while ((arg = optparse_arg(&opts))) {
if (folders_flag) { if (folders_flag) {
@ -154,20 +160,20 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) {
#else #else
snprintf(resolved_path, strlen(arg) + 1, "%s/", arg); snprintf(resolved_path, strlen(arg) + 1, "%s/", arg);
#endif #endif
} }
} else { } else {
#ifdef _WIN32 #ifdef _WIN32
_fullpath(resolved_path, arg, MAX_PATH); _fullpath(resolved_path, arg, MAX_PATH);
#else #else
realpath(arg, resolved_path); realpath(arg, resolved_path);
#endif #endif
} }
if (is_directory(resolved_path)) { if (is_directory(resolved_path)) {
if (!files_flag) { if (!files_flag) {
folders_flag = true; folders_flag = true;
size_t len = strlen(resolved_path); size_t len = strlen(resolved_path);
if (resolved_path[len - 1] != '/' && resolved_path[strlen(resolved_path) - 1] != '\\') { if (resolved_path[len - 1] != '/' && resolved_path[strlen(resolved_path) - 1] != '\\') {
#ifdef _WIN32 #ifdef _WIN32
resolved_path[len] = '\\'; resolved_path[len] = '\\';
#else #else
@ -221,11 +227,11 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options) {
return parameters; return parameters;
} }
int start_compression(cclt_options *options, cs_image_pars *parameters) { int start_compression(cclt_options *options, struct C_CSParameters parameters) {
int compressed_files = 0; int compressed_files = 0;
off_t input_file_size = 0; off_t input_file_size;
off_t output_file_size = 0; off_t output_file_size;
//Create the output folder if does not exists //Create the output folder if it does not exist
if (mkpath(options->output_folder) == -1) { if (mkpath(options->output_folder) == -1) {
display_error(ERROR, 5); display_error(ERROR, 5);
} }
@ -235,8 +241,7 @@ int start_compression(cclt_options *options, cs_image_pars *parameters) {
char *output_full_path = NULL; char *output_full_path = NULL;
char *original_output_full_path = NULL; char *original_output_full_path = NULL;
bool overwriting = false; bool overwriting = false;
off_t file_size = 0; off_t file_size;
int compression_error_code = 0;
//If we don't need to keep the structure, we put all the files in one folder by just the filename //If we don't need to keep the structure, we put all the files in one folder by just the filename
if (!options->keep_structure) { if (!options->keep_structure) {
output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 1) * sizeof(char)); output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 1) * sizeof(char));
@ -300,14 +305,14 @@ int start_compression(cclt_options *options, cs_image_pars *parameters) {
} }
print_to_console(stdout, verbose, "(%d/%d) %s -> %s\nCompressing...", print_to_console(stdout, verbose, "(%d/%d) %s -> %s\nCompressing...",
i + 1, i + 1,
options->files_count, options->files_count,
filename, filename,
f_exists ? original_output_full_path : output_full_path); f_exists ? original_output_full_path : output_full_path);
fflush(stdout); fflush(stdout);
//Prevent compression if running in dry mode //Prevent compression if running in dry mode
if (!options->dry_run) { if (!options->dry_run) {
if (cs_compress(options->input_files[i], output_full_path, parameters, &compression_error_code)) { if (c_compress(options->input_files[i], output_full_path, parameters)) {
compressed_files++; compressed_files++;
output_file_size = get_file_size(output_full_path); output_file_size = get_file_size(output_full_path);
@ -322,12 +327,11 @@ int start_compression(cclt_options *options, cs_image_pars *parameters) {
} }
options->output_total_size += output_file_size; options->output_total_size += output_file_size;
print_to_console(stdout, verbose, "\r%s -> %s [%.2f%%]\n", print_to_console(stdout, verbose, "\r%s -> %s [%.2f%%]\n",
human_input_size, human_input_size,
human_output_size, human_output_size,
((float) output_file_size - input_file_size) * 100 / input_file_size); ((float) output_file_size - (float) input_file_size) * 100 / (float) input_file_size);
} else { } else {
print_to_console(stdout, verbose, "\n"); print_to_console(stderr, verbose, "\nCompression failed\n");
print_to_console(stderr, verbose, "Compression failed with error %d\n", compression_error_code);
options->input_total_size -= get_file_size(options->input_files[i]); options->input_total_size -= get_file_size(options->input_files[i]);
} }
} }
@ -340,7 +344,7 @@ int start_compression(cclt_options *options, cs_image_pars *parameters) {
rename(output_full_path, original_output_full_path); rename(output_full_path, original_output_full_path);
} }
free_and_go_on_with_next_file: free_and_go_on_with_next_file:
free(original_output_full_path); free(original_output_full_path);
free(output_full_path); free(output_full_path);
} }

View File

@ -18,12 +18,12 @@
#ifndef CAESIUM_CLT_HELPER_H #ifndef CAESIUM_CLT_HELPER_H
#define CAESIUM_CLT_HELPER_H #define CAESIUM_CLT_HELPER_H
#include <caesium.h>
#ifdef _WIN32 #ifdef _WIN32
#define MAX_PATH_SIZE _MAX_PATH #define MAX_PATH_SIZE _MAX_PATH
#else #else
#include <limits.h> #include <limits.h>
#include <stdbool.h>
#define MAX_PATH_SIZE PATH_MAX #define MAX_PATH_SIZE PATH_MAX
#endif #endif
@ -34,6 +34,18 @@ typedef enum overwrite_policy {
all all
} overwrite_policy; } overwrite_policy;
typedef struct C_CSParameters {
bool keep_metadata;
unsigned int jpeg_quality;
unsigned int png_level;
bool png_force_zopfli;
unsigned int gif_quality;
unsigned int webp_quality;
bool optimize;
} C_CSParameters;
extern bool c_compress(const char *i, const char *o, struct C_CSParameters params);
typedef struct cclt_options typedef struct cclt_options
{ {
char **input_files; char **input_files;
@ -50,8 +62,8 @@ typedef struct cclt_options
cclt_options parse_arguments(char *argv[], cs_image_pars *options); cclt_options parse_arguments(char *argv[], C_CSParameters *options);
int start_compression(cclt_options *options, cs_image_pars *parameters); int start_compression(cclt_options *options, struct C_CSParameters parameters);
#endif //CAESIUM_CLT_HELPER_H #endif //CAESIUM_CLT_HELPER_H

View File

@ -18,7 +18,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
#include <caesium.h>
#include "utils.h" #include "utils.h"
#include "shared.h" #include "shared.h"
@ -31,18 +30,25 @@ int main(int argc, char *argv[])
} }
long compression_time = 0; long compression_time = 0;
cs_image_pars compress_options;
cclt_options options; cclt_options options;
//Initialize the default parameters //Initialize the default parameters
compress_options = initialize_parameters(); C_CSParameters compress_options = {
false,
80,
3,
false,
20,
60,
false
};
//Set them according to command line parameters //Set them according to command line parameters
options = parse_arguments(argv, &compress_options); options = parse_arguments(argv, &compress_options);
//Start a timer before calling the compression //Start a timer before calling the compression
clock_t start = clock(), diff; clock_t start = clock(), diff;
start_compression(&options, &compress_options); start_compression(&options, compress_options);
//Cleanup the memory allocated objects //Cleanup the memory allocated objects
free(options.input_files); free(options.input_files);

View File

@ -38,12 +38,12 @@ bool file_exists(const char* file_path);
int strndx(const char* string, char search); int strndx(const char* string, char search);
double parse_scale_factor(const char* factor_string);
overwrite_policy parse_overwrite_policy(const char* overwrite_string); overwrite_policy parse_overwrite_policy(const char* overwrite_string);
void print_to_console(FILE* buffer, int verbose, const char* format, ...); void print_to_console(FILE* buffer, int verbose, const char* format, ...);
int parse_png_quality(int quality);
#ifdef _WIN32 #ifdef _WIN32
char *str_replace(char *orig, char *rep, char *with); char *str_replace(char *orig, char *rep, char *with);
char *strsep(char **stringp, const char *delim); char *strsep(char **stringp, const char *delim);