Using Rust libcaesium
This commit is contained in:
parent
8be97e4201
commit
91ac6ff742
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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)
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
||||||
|
|
140
src/helper.c
140
src/helper.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
20
src/helper.h
20
src/helper.h
|
@ -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
|
||||||
|
|
14
src/main.c
14
src/main.c
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue