diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bd85c4..79b3550 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,17 +7,20 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # The version number. set(VERSION_MAJOR 0) -set(VERSION_MINOR 2) -set(VERSION_PATCH 2) +set(VERSION_MINOR 3) +set(VERSION_PATCH 0) configure_file( "caesium/config.h.in" "${PROJECT_BINARY_DIR}/config.h" ) +link_directories(/usr/local/lib) + include_directories("${PROJECT_BINARY_DIR}") if (NOT WIN32) include_directories(/opt/mozjpeg/include) + include_directories(/usr/local/include) if(EXISTS /opt/mozjpeg/lib64) link_directories(/opt/mozjpeg/lib64) diff --git a/README.md b/README.md index 7ae933a..e07a0ca 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Binaries not available yet. Please refer to the compilation section below. Libcaesium exposes one single function to compress, auto-detecting the input file type: ```C bool cs_compress(const char *input, - const char *output, + char *output, cs_image_pars *options); ``` #### Parameters @@ -46,7 +46,7 @@ typedef struct cs_jpeg_pars The first 3 parameters matters, in term of compression, while the others will be set by the compressor/decompressor during the compression progress and thus they will be overwritten. - **quality**: in a range from 0 to 100, the quality of the resulting image. **Note** that 0 means _optimization_ (see below). Default: 0. -- **exif_copy**: set it to _true_ to copy EXIF tag info after compression. Default: false; +- **exif_copy**: set it to _true_ to copy EXIF tag info after compression. Default: false. - **dct_method**: one of the turbojpeg DCT flags. Default: TJFLAG_FASTDCT. ### PNG diff --git a/caesium/CMakeLists.txt b/caesium/CMakeLists.txt index 1cae1e4..59e14e8 100644 --- a/caesium/CMakeLists.txt +++ b/caesium/CMakeLists.txt @@ -4,7 +4,9 @@ else() set(CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}") endif() -find_library(zoflipng zopflipng /usr/local/lib) +link_directories(/usr/local/lib) + +find_library(zopflipng zopflipng /usr/local/lib) find_library(jpeg jpeg /opt/mozjpeg/lib) find_library(turbojpeg turbojpeg /opt/mozjpeg/lib) diff --git a/caesium/caesium.c b/caesium/caesium.c index c69d4c1..9ce7f3b 100644 --- a/caesium/caesium.c +++ b/caesium/caesium.c @@ -25,11 +25,13 @@ bool cs_compress(const char *input_path, const char *output_path, cs_image_pars display_error(WARNING, 103); } else if (type == CS_JPEG) { if (options->jpeg.quality != 0) { - cs_jpeg_compress(output_path, cs_jpeg_decompress(input_path, &options->jpeg), &options->jpeg); + result = cs_jpeg_compress(output_path, cs_jpeg_decompress(input_path, &options->jpeg), &options->jpeg); //The output is now the new input for optimization - result = cs_jpeg_optimize(output_path, output_path, options->jpeg.exif_copy, input_path); + if (result) { + result = cs_jpeg_optimize(output_path, output_path, &options->jpeg, input_path); + } } else { - result = cs_jpeg_optimize(input_path, output_path, options->jpeg.exif_copy, input_path); + result = cs_jpeg_optimize(input_path, output_path, &options->jpeg, input_path); } } else if (type == CS_PNG) { result = cs_png_optimize(input_path, output_path, &options->png); @@ -47,12 +49,12 @@ void initialize_jpeg_parameters(cs_image_pars *options) void initialize_png_parameters(cs_image_pars *par) { - par->png.iterations = 10; - par->png.iterations_large = 5; - par->png.block_split_strategy = 4; + par->png.iterations = 2; + par->png.iterations_large = 1; + par->png.block_split_strategy = 0; par->png.lossy_8 = true; par->png.transparent = true; - par->png.auto_filter_strategy = 1; + par->png.auto_filter_strategy = true; } cs_image_pars initialize_parameters() diff --git a/caesium/caesium.h b/caesium/caesium.h index cba71c1..86c710e 100644 --- a/caesium/caesium.h +++ b/caesium/caesium.h @@ -6,6 +6,7 @@ extern "C" { #endif #include +#include typedef struct cs_jpeg_pars { diff --git a/caesium/error.c b/caesium/error.c index 35b0683..96057b0 100644 --- a/caesium/error.c +++ b/caesium/error.c @@ -33,6 +33,14 @@ const char *get_error_message(int code) return "Failed to open JPEG file while compressing"; case 204: return "Failed to open JPEG file while decompressing"; + case 205: + return "Failed to retrieve input JPEG file size"; + case 206: + return "Input JPEG file is too big"; + case 207: + return "Compressor failed"; + case 208: + return "Compressor failed"; //PNG related errors case 300: diff --git a/caesium/jpeg.c b/caesium/jpeg.c index 3d41356..b6147cf 100644 --- a/caesium/jpeg.c +++ b/caesium/jpeg.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "jpeg.h" #include "error.h" @@ -28,14 +29,14 @@ struct jpeg_decompress_struct cs_get_markers(const char *input) jpeg_save_markers(&einfo, JPEG_APP0 + m, 0xFFFF); } - jpeg_read_header(&einfo, TRUE); + jpeg_read_header(&einfo, true); fclose(fp); return einfo; } -bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif, const char *exif_src) +bool cs_jpeg_optimize(const char *input_file, const char *output_file, cs_jpeg_pars *options, const char *exif_src) { //File pointer for both input and output FILE *fp; @@ -66,14 +67,14 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif jpeg_stdio_src(&srcinfo, fp); //Save EXIF info - if (exif) { + if (options->exif_copy) { for (int m = 0; m < 16; m++) { jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF); } } //Read the input headers - (void) jpeg_read_header(&srcinfo, TRUE); + (void) jpeg_read_header(&srcinfo, true); //Read input coefficents @@ -94,9 +95,7 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif } //CRITICAL - This is the optimization step - dstinfo.optimize_coding = TRUE; - //Progressive - jpeg_simple_progression(&dstinfo); + dstinfo.optimize_coding = true; //Set the output file parameters jpeg_stdio_dest(&dstinfo, fp); @@ -105,7 +104,7 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif jpeg_write_coefficients(&dstinfo, dst_coef_arrays); //Write EXIF - if (exif) { + if (options->exif_copy) { if (strcmp(input_file, exif_src) == 0) { jcopy_markers_execute(&srcinfo, &dstinfo); } else { @@ -128,24 +127,23 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif return true; } -void cs_jpeg_compress(const char *output_file, unsigned char *image_buffer, cs_jpeg_pars *options) +bool cs_jpeg_compress(const char *output_file, unsigned char *image_buffer, cs_jpeg_pars *options) { FILE *fp; tjhandle tjCompressHandle; unsigned char *output_buffer; unsigned long output_size = 0; - + output_buffer = NULL; + int result = 0; //Check for errors if ((fp = fopen(output_file, "wb")) == NULL) { display_error(ERROR, 203); } - output_buffer = NULL; tjCompressHandle = tjInitCompress(); - //TODO Error checks - tjCompress2(tjCompressHandle, + result = tjCompress2(tjCompressHandle, image_buffer, options->width, 0, @@ -156,35 +154,45 @@ void cs_jpeg_compress(const char *output_file, unsigned char *image_buffer, cs_j options->subsample, options->quality, options->dct_method); - - fwrite(output_buffer, output_size, 1, fp); + if (result == -1) { + display_error(ERROR, 207); + } else { + fwrite(output_buffer, output_size, 1, fp); + } fclose(fp); tjDestroy(tjCompressHandle); tjFree(output_buffer); tjFree(image_buffer); + + return true; } unsigned char *cs_jpeg_decompress(const char *fileName, cs_jpeg_pars *options) { - //TODO This has a lot of non checked errors that may occur FILE *fp; long sourceJpegBufferSize = 0; unsigned char *sourceJpegBuffer = NULL; tjhandle tjDecompressHandle; - int fileWidth = 0, fileHeight = 0, jpegSubsamp = 0, colorSpace = 0; + int fileWidth = 0, fileHeight = 0, jpegSubsamp = 0, colorSpace = 0, result = 0; if ((fp = fopen(fileName, "rb")) == NULL) { display_error(ERROR, 204); } fseek(fp, 0, SEEK_END); sourceJpegBufferSize = ftell(fp); - sourceJpegBuffer = tjAlloc(sourceJpegBufferSize); + if (sourceJpegBufferSize == -1) { + display_error(ERROR, 205); + } + if (sourceJpegBufferSize > INT_MAX) { + display_error(ERROR, 206); + } + sourceJpegBuffer = tjAlloc((int) sourceJpegBufferSize); fseek(fp, 0, SEEK_SET); fread(sourceJpegBuffer, (size_t) sourceJpegBufferSize, 1, fp); tjDecompressHandle = tjInitDecompress(); - tjDecompressHeader3(tjDecompressHandle, sourceJpegBuffer, sourceJpegBufferSize, &fileWidth, &fileHeight, + tjDecompressHeader3(tjDecompressHandle, sourceJpegBuffer, (unsigned long) sourceJpegBufferSize, &fileWidth, &fileHeight, &jpegSubsamp, &colorSpace); options->width = fileWidth; @@ -195,15 +203,18 @@ unsigned char *cs_jpeg_decompress(const char *fileName, cs_jpeg_pars *options) unsigned char *temp = tjAlloc(options->width * options->height * tjPixelSize[options->color_space]); - tjDecompress2(tjDecompressHandle, + result = tjDecompress2(tjDecompressHandle, sourceJpegBuffer, - sourceJpegBufferSize, + (unsigned long) sourceJpegBufferSize, temp, options->width, 0, options->height, options->color_space, options->dct_method); + if (result == -1) { + display_error(ERROR, 208); + } tjDestroy(tjDecompressHandle); tjFree(sourceJpegBuffer); diff --git a/caesium/jpeg.h b/caesium/jpeg.h index 2e77be5..2d7d97f 100644 --- a/caesium/jpeg.h +++ b/caesium/jpeg.h @@ -5,11 +5,11 @@ #include "caesium.h" -bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif, const char *exif_src); +bool cs_jpeg_optimize(const char *input_file, const char *output_file, cs_jpeg_pars *options, const char *exif_src); struct jpeg_decompress_struct cs_get_markers(const char *input); -void cs_jpeg_compress(const char *output_file, unsigned char *image_buffer, cs_jpeg_pars *options); +bool cs_jpeg_compress(const char *output_file, unsigned char *image_buffer, cs_jpeg_pars *options); unsigned char *cs_jpeg_decompress(const char *fileName, cs_jpeg_pars *options); diff --git a/caesium/png.c b/caesium/png.c index 32df8d5..c5a0e17 100644 --- a/caesium/png.c +++ b/caesium/png.c @@ -13,6 +13,7 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options { bool result = false; CZopfliPNGOptions png_options; + int error_code = 0; CZopfliPNGSetDefaults(&png_options); @@ -32,7 +33,7 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options png_options.auto_filter_strategy = options->auto_filter_strategy; if (lodepng_load_file(&orig_buffer, &orig_buffer_size, input) != 0) { - display_error(ERROR, 300); + error_code = 300; goto cleanup; } @@ -42,12 +43,12 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options 0, &resultpng, &resultpng_size) != 0) { - display_error(ERROR, 301); + error_code = 301; goto cleanup; } if (lodepng_save_file(resultpng, resultpng_size, output) != 0) { - display_error(ERROR, 302); + error_code = 302; goto cleanup; } @@ -56,5 +57,8 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options cleanup: free(orig_buffer); free(resultpng); + if (error_code != 0) { + display_error(ERROR, error_code); + } return result; } diff --git a/demo/main.c b/demo/main.c index 1cdf325..f9abacf 100644 --- a/demo/main.c +++ b/demo/main.c @@ -5,7 +5,7 @@ int main(int argc, char *argv[]) { - fprintf(stdout, "libcaesium demo application v%d.%d.%d\n\n", + fprintf(stdout, "libcaesium demo application v%d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) } cs_image_pars options = initialize_parameters(); - cs_compress(argv[1], argv[2], &options); + bool result = cs_compress(argv[1], argv[2], &options); - exit(EXIT_SUCCESS); + exit(result); } \ No newline at end of file diff --git a/install.sh b/install.sh index fe85865..7a6f533 100755 --- a/install.sh +++ b/install.sh @@ -11,7 +11,7 @@ mkdir build && cd build ../configure make && sudo make install -cd $SOURCE +cd ${SOURCE} #zopflipng git clone https://github.com/google/zopfli.git @@ -23,4 +23,4 @@ sudo ln -s libzopflipng.so.1.0.0 /usr/lib/libzopflipng.so.1 sudo mkdir /usr/include/zopflipng sudo cp src/zopflipng/zopflipng_lib.h /usr/include/zopflipng -cd $SOURCE +cd ${SOURCE}