This commit is contained in:
Matteo Paonessa 2017-06-03 12:22:23 +02:00
parent 9eb1f94c0a
commit 4e4aae1a9f
10 changed files with 78 additions and 37 deletions

View File

@ -7,8 +7,8 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# The version number. # The version number.
set(VERSION_MAJOR 0) set(VERSION_MAJOR 0)
set(VERSION_MINOR 2) set(VERSION_MINOR 3)
set(VERSION_PATCH 2) set(VERSION_PATCH 0)
configure_file( configure_file(
"caesium/config.h.in" "caesium/config.h.in"

View File

@ -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: Libcaesium exposes one single function to compress, auto-detecting the input file type:
```C ```C
bool cs_compress(const char *input, bool cs_compress(const char *input,
const char *output, char *output,
cs_image_pars *options); cs_image_pars *options);
``` ```
#### Parameters #### Parameters
@ -41,13 +41,15 @@ typedef struct cs_jpeg_pars
int quality; int quality;
bool exif_copy; bool exif_copy;
int dct_method; int dct_method;
bool progressive;
} cs_jpeg_pars; } cs_jpeg_pars;
``` ```
The first 3 parameters matters, in term of compression, while the others will be set by the compressor/decompressor 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. 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. - **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. - **dct_method**: one of the turbojpeg DCT flags. Default: TJFLAG_FASTDCT.
- **progressive**: set to _true_ to output a progressive JPEG, _false_ for scanline. Default: false.
### PNG ### PNG
```C ```C

View File

@ -6,7 +6,7 @@
#include "png.h" #include "png.h"
#include "jpeg.h" #include "jpeg.h"
bool cs_compress(const char *input_path, const char *output_path, cs_image_pars *options) bool cs_compress(const char *input_path, char *output_path, cs_image_pars *options)
{ {
FILE *pInputFile; FILE *pInputFile;
image_type type; image_type type;
@ -21,15 +21,23 @@ bool cs_compress(const char *input_path, const char *output_path, cs_image_pars
fclose(pInputFile); fclose(pInputFile);
//Same input and output, we need to use a temporary file
if (strcmp(input_path, output_path) == 0) {
output_path = realloc(output_path, (strlen(output_path) + 4) * sizeof(char));
snprintf(output_path, strlen(output_path) + 4, "%s.cs", output_path);
}
if (type == UNKN) { if (type == UNKN) {
display_error(WARNING, 103); display_error(WARNING, 103);
} else if (type == CS_JPEG) { } else if (type == CS_JPEG) {
if (options->jpeg.quality != 0) { 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 //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 { } 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) { } else if (type == CS_PNG) {
result = cs_png_optimize(input_path, output_path, &options->png); result = cs_png_optimize(input_path, output_path, &options->png);
@ -43,6 +51,7 @@ void initialize_jpeg_parameters(cs_image_pars *options)
options->jpeg.quality = 0; options->jpeg.quality = 0;
options->jpeg.exif_copy = false; options->jpeg.exif_copy = false;
options->jpeg.dct_method = 2048; options->jpeg.dct_method = 2048;
options->jpeg.progressive = false;
} }
void initialize_png_parameters(cs_image_pars *par) void initialize_png_parameters(cs_image_pars *par)

View File

@ -6,12 +6,14 @@ extern "C" {
#endif #endif
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
typedef struct cs_jpeg_pars typedef struct cs_jpeg_pars
{ {
int quality; int quality;
bool exif_copy; bool exif_copy;
int dct_method; int dct_method;
bool progressive;
/* /*
* Parameters you have no reason to set as they will be * Parameters you have no reason to set as they will be
* overwritten during the process * overwritten during the process
@ -51,7 +53,7 @@ typedef enum error_level
WARNING = 1 WARNING = 1
} error_level; } error_level;
bool cs_compress(const char *input_path, const char *output_path, cs_image_pars *options); bool cs_compress(const char *input_path, char *output_path, cs_image_pars *options);
cs_image_pars initialize_parameters(); cs_image_pars initialize_parameters();
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -33,6 +33,14 @@ const char *get_error_message(int code)
return "Failed to open JPEG file while compressing"; return "Failed to open JPEG file while compressing";
case 204: case 204:
return "Failed to open JPEG file while decompressing"; 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 //PNG related errors
case 300: case 300:

View File

@ -2,6 +2,7 @@
#include <jpeglib.h> #include <jpeglib.h>
#include <string.h> #include <string.h>
#include <turbojpeg.h> #include <turbojpeg.h>
#include <limits.h>
#include "jpeg.h" #include "jpeg.h"
#include "error.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_save_markers(&einfo, JPEG_APP0 + m, 0xFFFF);
} }
jpeg_read_header(&einfo, TRUE); jpeg_read_header(&einfo, true);
fclose(fp); fclose(fp);
return einfo; 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 pointer for both input and output
FILE *fp; 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); jpeg_stdio_src(&srcinfo, fp);
//Save EXIF info //Save EXIF info
if (exif) { if (options->exif_copy) {
for (int m = 0; m < 16; m++) { for (int m = 0; m < 16; m++) {
jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF); jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF);
} }
} }
//Read the input headers //Read the input headers
(void) jpeg_read_header(&srcinfo, TRUE); (void) jpeg_read_header(&srcinfo, true);
//Read input coefficents //Read input coefficents
@ -94,9 +95,12 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif
} }
//CRITICAL - This is the optimization step //CRITICAL - This is the optimization step
dstinfo.optimize_coding = TRUE; dstinfo.optimize_coding = true;
//TODO
//Progressive //Progressive
if (options->progressive) {
jpeg_simple_progression(&dstinfo); jpeg_simple_progression(&dstinfo);
}
//Set the output file parameters //Set the output file parameters
jpeg_stdio_dest(&dstinfo, fp); jpeg_stdio_dest(&dstinfo, fp);
@ -105,7 +109,7 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif
jpeg_write_coefficients(&dstinfo, dst_coef_arrays); jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
//Write EXIF //Write EXIF
if (exif) { if (options->exif_copy) {
if (strcmp(input_file, exif_src) == 0) { if (strcmp(input_file, exif_src) == 0) {
jcopy_markers_execute(&srcinfo, &dstinfo); jcopy_markers_execute(&srcinfo, &dstinfo);
} else { } else {
@ -128,24 +132,23 @@ bool cs_jpeg_optimize(const char *input_file, const char *output_file, bool exif
return true; 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; FILE *fp;
tjhandle tjCompressHandle; tjhandle tjCompressHandle;
unsigned char *output_buffer; unsigned char *output_buffer;
unsigned long output_size = 0; unsigned long output_size = 0;
output_buffer = NULL;
int result = 0;
//Check for errors //Check for errors
if ((fp = fopen(output_file, "wb")) == NULL) { if ((fp = fopen(output_file, "wb")) == NULL) {
display_error(ERROR, 203); display_error(ERROR, 203);
} }
output_buffer = NULL;
tjCompressHandle = tjInitCompress(); tjCompressHandle = tjInitCompress();
//TODO Error checks result = tjCompress2(tjCompressHandle,
tjCompress2(tjCompressHandle,
image_buffer, image_buffer,
options->width, options->width,
0, 0,
@ -156,35 +159,45 @@ void cs_jpeg_compress(const char *output_file, unsigned char *image_buffer, cs_j
options->subsample, options->subsample,
options->quality, options->quality,
options->dct_method); options->dct_method);
if (result == -1) {
display_error(ERROR, 207);
} else {
fwrite(output_buffer, output_size, 1, fp); fwrite(output_buffer, output_size, 1, fp);
}
fclose(fp); fclose(fp);
tjDestroy(tjCompressHandle); tjDestroy(tjCompressHandle);
tjFree(output_buffer); tjFree(output_buffer);
tjFree(image_buffer); tjFree(image_buffer);
return true;
} }
unsigned char *cs_jpeg_decompress(const char *fileName, cs_jpeg_pars *options) 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; FILE *fp;
long sourceJpegBufferSize = 0; long sourceJpegBufferSize = 0;
unsigned char *sourceJpegBuffer = NULL; unsigned char *sourceJpegBuffer = NULL;
tjhandle tjDecompressHandle; 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) { if ((fp = fopen(fileName, "rb")) == NULL) {
display_error(ERROR, 204); display_error(ERROR, 204);
} }
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
sourceJpegBufferSize = ftell(fp); 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); fseek(fp, 0, SEEK_SET);
fread(sourceJpegBuffer, (size_t) sourceJpegBufferSize, 1, fp); fread(sourceJpegBuffer, (size_t) sourceJpegBufferSize, 1, fp);
tjDecompressHandle = tjInitDecompress(); tjDecompressHandle = tjInitDecompress();
tjDecompressHeader3(tjDecompressHandle, sourceJpegBuffer, sourceJpegBufferSize, &fileWidth, &fileHeight, tjDecompressHeader3(tjDecompressHandle, sourceJpegBuffer, (unsigned long) sourceJpegBufferSize, &fileWidth, &fileHeight,
&jpegSubsamp, &colorSpace); &jpegSubsamp, &colorSpace);
options->width = fileWidth; options->width = fileWidth;
@ -195,15 +208,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]); unsigned char *temp = tjAlloc(options->width * options->height * tjPixelSize[options->color_space]);
tjDecompress2(tjDecompressHandle, result = tjDecompress2(tjDecompressHandle,
sourceJpegBuffer, sourceJpegBuffer,
sourceJpegBufferSize, (unsigned long) sourceJpegBufferSize,
temp, temp,
options->width, options->width,
0, 0,
options->height, options->height,
options->color_space, options->color_space,
options->dct_method); options->dct_method);
if (result == -1) {
display_error(ERROR, 208);
}
tjDestroy(tjDecompressHandle); tjDestroy(tjDecompressHandle);
tjFree(sourceJpegBuffer); tjFree(sourceJpegBuffer);

View File

@ -5,11 +5,11 @@
#include "caesium.h" #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); 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); unsigned char *cs_jpeg_decompress(const char *fileName, cs_jpeg_pars *options);

View File

@ -13,6 +13,7 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options
{ {
bool result = false; bool result = false;
CZopfliPNGOptions png_options; CZopfliPNGOptions png_options;
int error_code = 0;
CZopfliPNGSetDefaults(&png_options); 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; png_options.auto_filter_strategy = options->auto_filter_strategy;
if (lodepng_load_file(&orig_buffer, &orig_buffer_size, input) != 0) { if (lodepng_load_file(&orig_buffer, &orig_buffer_size, input) != 0) {
display_error(ERROR, 300); error_code = 300;
goto cleanup; goto cleanup;
} }
@ -42,12 +43,12 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options
0, 0,
&resultpng, &resultpng,
&resultpng_size) != 0) { &resultpng_size) != 0) {
display_error(ERROR, 301); error_code = 301;
goto cleanup; goto cleanup;
} }
if (lodepng_save_file(resultpng, resultpng_size, output) != 0) { if (lodepng_save_file(resultpng, resultpng_size, output) != 0) {
display_error(ERROR, 302); error_code = 302;
goto cleanup; goto cleanup;
} }
@ -56,5 +57,8 @@ bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options
cleanup: cleanup:
free(orig_buffer); free(orig_buffer);
free(resultpng); free(resultpng);
if (error_code != 0) {
display_error(ERROR, error_code);
}
return result; return result;
} }

View File

@ -5,7 +5,7 @@
int main(int argc, char *argv[]) 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_MAJOR,
VERSION_MINOR, VERSION_MINOR,
VERSION_PATCH); VERSION_PATCH);

View File

@ -11,7 +11,7 @@ mkdir build && cd build
../configure ../configure
make && sudo make install make && sudo make install
cd $SOURCE cd ${SOURCE}
#zopflipng #zopflipng
git clone https://github.com/google/zopfli.git 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 mkdir /usr/include/zopflipng
sudo cp src/zopflipng/zopflipng_lib.h /usr/include/zopflipng sudo cp src/zopflipng/zopflipng_lib.h /usr/include/zopflipng
cd $SOURCE cd ${SOURCE}