Merge branch '0.3.0'
This commit is contained in:
commit
9fd0fa5f27
|
@ -7,17 +7,20 @@ 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"
|
||||||
"${PROJECT_BINARY_DIR}/config.h"
|
"${PROJECT_BINARY_DIR}/config.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
link_directories(/usr/local/lib)
|
||||||
|
|
||||||
include_directories("${PROJECT_BINARY_DIR}")
|
include_directories("${PROJECT_BINARY_DIR}")
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
include_directories(/opt/mozjpeg/include)
|
include_directories(/opt/mozjpeg/include)
|
||||||
|
include_directories(/usr/local/include)
|
||||||
|
|
||||||
if(EXISTS /opt/mozjpeg/lib64)
|
if(EXISTS /opt/mozjpeg/lib64)
|
||||||
link_directories(/opt/mozjpeg/lib64)
|
link_directories(/opt/mozjpeg/lib64)
|
||||||
|
|
|
@ -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
|
||||||
|
@ -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
|
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.
|
||||||
|
|
||||||
### PNG
|
### PNG
|
||||||
|
|
|
@ -4,7 +4,9 @@ else()
|
||||||
set(CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}")
|
||||||
endif()
|
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(jpeg jpeg /opt/mozjpeg/lib)
|
||||||
find_library(turbojpeg turbojpeg /opt/mozjpeg/lib)
|
find_library(turbojpeg turbojpeg /opt/mozjpeg/lib)
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,13 @@ bool cs_compress(const char *input_path, const char *output_path, cs_image_pars
|
||||||
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);
|
||||||
|
@ -47,12 +49,12 @@ void initialize_jpeg_parameters(cs_image_pars *options)
|
||||||
|
|
||||||
void initialize_png_parameters(cs_image_pars *par)
|
void initialize_png_parameters(cs_image_pars *par)
|
||||||
{
|
{
|
||||||
par->png.iterations = 10;
|
par->png.iterations = 2;
|
||||||
par->png.iterations_large = 5;
|
par->png.iterations_large = 1;
|
||||||
par->png.block_split_strategy = 4;
|
par->png.block_split_strategy = 0;
|
||||||
par->png.lossy_8 = true;
|
par->png.lossy_8 = true;
|
||||||
par->png.transparent = true;
|
par->png.transparent = true;
|
||||||
par->png.auto_filter_strategy = 1;
|
par->png.auto_filter_strategy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cs_image_pars initialize_parameters()
|
cs_image_pars initialize_parameters()
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct cs_jpeg_pars
|
typedef struct cs_jpeg_pars
|
||||||
{
|
{
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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,7 @@ 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;
|
||||||
//Progressive
|
|
||||||
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 +104,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 +127,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 +154,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 +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]);
|
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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -16,7 +16,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
cs_image_pars options = initialize_parameters();
|
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);
|
||||||
}
|
}
|
|
@ -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}
|
||||||
|
|
Loading…
Reference in New Issue