Compression interface polished
Now uses libjpeg-turbo and keeps EXIFs
This commit is contained in:
parent
8c71d0d93b
commit
08500f84dc
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
11
src/main.c
11
src/main.c
|
@ -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
|
||||||
|
|
17
src/utils.c
17
src/utils.c
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue