Compression interface polished

Now uses libjpeg-turbo and keeps EXIFs
This commit is contained in:
Matteo Paonessa 2015-05-19 18:35:32 +02:00
parent 8c71d0d93b
commit 08500f84dc
6 changed files with 109 additions and 68 deletions

View File

@ -7,60 +7,45 @@
#include "compress.h" #include "compress.h"
#include "utils.h" #include "utils.h"
void cclt_compress(char* output_file, unsigned char* image_buffer, cclt_compress_parameters* pars) //TODO Error handling
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr; void cclt_compress(char* output_file, unsigned char* image_buffer, cclt_compress_parameters* pars) {
FILE * outfile; FILE* fp;
JSAMPROW row_pointer[1]; tjhandle tjCompressHandle;
int row_stride; unsigned char* output_buffer;
int status;
unsigned long output_size = 0;
if ((outfile = fopen(output_file, "wb")) == NULL) { fp = fopen(output_file, "wb");
fprintf(stderr, "can't open %s\n", output_file);
exit(1);
}
cinfo.err = jpeg_std_error(&jerr); //Check for errors
//TODO Use UNIX error messages
if (fp == NULL) {
printf("INPUT: Failed to open output \"%s\"\n", output_file);
return;
}
jpeg_create_compress(&cinfo); output_buffer = NULL;
jpeg_stdio_dest(&cinfo, outfile); tjCompressHandle = tjInitCompress();
cinfo.image_width = pars->width; status = tjCompress2(tjCompressHandle,
cinfo.image_height = pars->height; image_buffer,
cinfo.input_components = 3; pars->width,
cinfo.in_color_space = JCS_RGB; 0,
pars->height,
jpeg_set_defaults(&cinfo); pars->color_space,
&output_buffer,
cinfo.dct_method = pars->dct_method; &output_size,
cinfo.optimize_coding = TRUE; pars->subsample,
cinfo.smoothing_factor = pars->smoothing_factor; pars->quality,
jpeg_set_quality(&cinfo, pars->quality, TRUE); pars->dct_method);
jpeg_set_colorspace(&cinfo, JCS_RGB);
fwrite(output_buffer, 1, output_size, fp);
jpeg_start_compress(&cinfo, TRUE); fclose(fp);
tjDestroy(tjCompressHandle);
row_stride = pars->width * 3; tjFree(output_buffer);
while (cinfo.next_scanline < cinfo.image_height) {
//printf("%d%%\r", cinfo.next_scanline * 100 / cinfo.image_height);
row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
//printf("%d%%\n", cinfo.next_scanline * 100 / cinfo.image_height);
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
} }
@ -85,7 +70,7 @@ unsigned char* cclt_decompress(char* fileName, cclt_compress_parameters* pars) {
int destWidth = fileWidth; int destWidth = fileWidth;
int destHeight = fileHeight; int destHeight = fileHeight;
pars->color_space = jpegSubsamp; pars->subsample = jpegSubsamp;
@ -99,9 +84,11 @@ unsigned char* cclt_decompress(char* fileName, cclt_compress_parameters* pars) {
destWidth, destWidth,
0, 0,
destHeight, destHeight,
TJPF_RGB, pars->color_space,
TJFLAG_ACCURATEDCT); TJFLAG_ACCURATEDCT);
tjDestroy(tjDecompressHandle);
pars->width = destWidth; pars->width = destWidth;
pars->height = destHeight; pars->height = destHeight;

View File

@ -2,19 +2,53 @@
#include <stdio.h> #include <stdio.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "lossless.h" #include "lossless.h"
#include "utils.h" #include "utils.h"
int cclt_optimize(char* input_file, char* output_file, int exif_flag) { struct jpeg_decompress_struct cclt_get_markers(char* input) {
FILE* fp;
struct jpeg_decompress_struct einfo;
struct jpeg_error_mgr eerr;
einfo.err = jpeg_std_error(&eerr);
jpeg_create_decompress(&einfo);
//Open the input file
fp = fopen(input, "r");
//Check for errors
//TODO Use UNIX error messages
if (fp == NULL) {
printf("INPUT: Failed to open exif file \"%s\"\n", input);
exit(-13);
}
//Create the IO istance for the input file
jpeg_stdio_src(&einfo, fp);
//Save EXIF info
for (int m = 0; m < 16; m++) {
jpeg_save_markers(&einfo, JPEG_APP0 + m, 0xFFFF);
}
jpeg_read_header(&einfo, TRUE);
fclose(fp);
return einfo;
}
int cclt_optimize(char* input_file, char* output_file, int exif_flag, char* exif_src) {
//File pointer for both input and output //File pointer for both input and output
FILE* fp; FILE* fp;
//Those will hold the input/output structs //Those will hold the input/output structs
struct jpeg_decompress_struct srcinfo; struct jpeg_decompress_struct srcinfo;
struct jpeg_compress_struct dstinfo; struct jpeg_compress_struct dstinfo;
//Error Handling //Error handling
struct jpeg_error_mgr jsrcerr, jdsterr; struct jpeg_error_mgr jsrcerr, jdsterr;
//Input/Output array coefficents //Input/Output array coefficents
@ -43,7 +77,7 @@ int cclt_optimize(char* input_file, char* output_file, int exif_flag) {
//Save EXIF info //Save EXIF info
if (exif_flag == 1) { if (exif_flag == 1) {
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);
} }
} }
@ -74,21 +108,28 @@ int cclt_optimize(char* input_file, char* output_file, int exif_flag) {
//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); jpeg_simple_progression(&dstinfo);
//Set the output file parameters //Set the output file parameters
jpeg_stdio_dest(&dstinfo, fp); jpeg_stdio_dest(&dstinfo, fp);
//Actually write the coefficents //Actually write the coefficents
jpeg_write_coefficients(&dstinfo, dst_coef_arrays); jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
//Write EXIF //Write EXIF
if (exif_flag == 1) { if (exif_flag == 1) {
jcopy_markers_execute(&srcinfo, &dstinfo); if (strcmp(input_file, exif_src) == 0) {
jcopy_markers_execute(&srcinfo, &dstinfo);
} else {
//For standard compression EXIF data
struct jpeg_decompress_struct einfo = cclt_get_markers(exif_src);
jcopy_markers_execute(&einfo, &dstinfo);
jpeg_destroy_decompress(&einfo);
}
} }
//Free memory and finish //Finish and free
jpeg_finish_compress(&dstinfo); jpeg_finish_compress(&dstinfo);
jpeg_destroy_compress(&dstinfo); jpeg_destroy_compress(&dstinfo);
(void) jpeg_finish_decompress(&srcinfo); (void) jpeg_finish_decompress(&srcinfo);

View File

@ -1,6 +1,7 @@
#ifndef CCLT_LOSSLESS #ifndef CCLT_LOSSLESS
#define CCLT_LOSSLESS #define CCLT_LOSSLESS
int cclt_optimize(char* input_file, char* output_file, int exif_flag); int cclt_optimize(char* input_file, char* output_file, int exif_flag, char* exif_src);
struct jpeg_decompress_struct cclt_get_markers(char* input);
#endif #endif

View File

@ -7,13 +7,14 @@
#include <dirent.h> #include <dirent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <libexif/exif-data.h>
#include "lossless.h" #include "lossless.h"
#include "compress.h" #include "compress.h"
#include "utils.h" #include "utils.h"
/* PARAMETERS: /* PARAMETERS:
-q quality -q quality v
-e exif v -e exif v
-o output folder v -o output folder v
-v version v -v version v
@ -123,12 +124,12 @@ int main (int argc, char *argv[]) {
//Lossless optmization requested //Lossless optmization requested
if (pars.lossless != 0) { if (pars.lossless != 0) {
cclt_optimize(pars.input_files[i], output_filename, pars.exif_copy, pars.input_files[i]);
cclt_optimize(pars.input_files[i], output_filename, pars.exif_copy);
} else { } else {
//TODO Standard compression requested //TODO Standard compression requested
unsigned char* buffer = cclt_decompress(pars.input_files[i], &pars); //unsigned char* buffer = cclt_decompress(pars.input_files[i], &pars);
cclt_compress(output_filename, buffer, &pars); //cclt_compress(output_filename, buffer, &pars);
cclt_compress_routine(pars.input_files[i], output_filename, &pars);
} }
//Get output stats //Get output stats

View File

@ -5,6 +5,7 @@
#include <setjmp.h> #include <setjmp.h>
#include <stdio.h> #include <stdio.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <turbojpeg.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <getopt.h> #include <getopt.h>
@ -12,6 +13,8 @@
#include "utils.h" #include "utils.h"
#include "compress.h"
#include "lossless.h"
cclt_compress_parameters initialize_compression_parameters() { cclt_compress_parameters initialize_compression_parameters() {
cclt_compress_parameters par; cclt_compress_parameters par;
@ -19,10 +22,9 @@ cclt_compress_parameters initialize_compression_parameters() {
par.quality = 0; par.quality = 0;
par.width = 0; par.width = 0;
par.height = 0; par.height = 0;
par.smoothing_factor = 100;
par.scaling_factor = 100; par.scaling_factor = 100;
par.color_space = JCS_RGB; par.color_space = TJPF_RGB;
par.dct_method = JDCT_ISLOW; par.dct_method = TJFLAG_FASTDCT;
par.output_folder = NULL; par.output_folder = NULL;
par.exif_copy = 0; par.exif_copy = 0;
par.lossless = 0; par.lossless = 0;
@ -198,4 +200,11 @@ cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
} }
return parameters; return parameters;
} }
void cclt_compress_routine(char* input, char* output, cclt_compress_parameters* pars) {
cclt_compress(output, cclt_decompress(input, pars), pars);
cclt_optimize(output, output, pars->exif_copy, input);
}

View File

@ -2,6 +2,7 @@
#define CCLT_UTILS #define CCLT_UTILS
#include <jpeglib.h> #include <jpeglib.h>
#include <turbojpeg.h>
#define APP_VERSION "1.9.9 BETA" #define APP_VERSION "1.9.9 BETA"
#define BUILD 20150515 #define BUILD 20150515
@ -10,15 +11,15 @@ typedef struct cclt_compress_parameters {
int quality; int quality;
int width; int width;
int height; int height;
int smoothing_factor;
int scaling_factor; int scaling_factor;
char* output_folder; char* output_folder;
J_COLOR_SPACE color_space; int color_space;
J_DCT_METHOD dct_method; int dct_method;
int exif_copy; int exif_copy;
int lossless; int lossless;
char** input_files; char** input_files;
int input_files_count; int input_files_count;
enum TJSAMP subsample;
} cclt_compress_parameters; } cclt_compress_parameters;
cclt_compress_parameters initialize_compression_parameters(); cclt_compress_parameters initialize_compression_parameters();
@ -30,5 +31,6 @@ char* get_filename_with_extension(char* full_path);
void jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo); void jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo);
int mkpath(const char *pathname, mode_t mode); int mkpath(const char *pathname, mode_t mode);
cclt_compress_parameters parse_arguments(int argc, char* argv[]); cclt_compress_parameters parse_arguments(int argc, char* argv[]);
void cclt_compress_routine(char* input, char* output,cclt_compress_parameters* pars);
#endif #endif