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 "utils.h"
|
||||
|
||||
void cclt_compress(char* output_file, unsigned char* image_buffer, cclt_compress_parameters* pars)
|
||||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
//TODO Error handling
|
||||
|
||||
struct jpeg_error_mgr jerr;
|
||||
FILE * outfile;
|
||||
JSAMPROW row_pointer[1];
|
||||
int row_stride;
|
||||
void cclt_compress(char* output_file, unsigned char* image_buffer, cclt_compress_parameters* pars) {
|
||||
FILE* fp;
|
||||
tjhandle tjCompressHandle;
|
||||
unsigned char* output_buffer;
|
||||
int status;
|
||||
unsigned long output_size = 0;
|
||||
|
||||
if ((outfile = fopen(output_file, "wb")) == NULL) {
|
||||
fprintf(stderr, "can't open %s\n", output_file);
|
||||
exit(1);
|
||||
}
|
||||
fp = fopen(output_file, "wb");
|
||||
|
||||
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);
|
||||
jpeg_stdio_dest(&cinfo, outfile);
|
||||
output_buffer = NULL;
|
||||
tjCompressHandle = tjInitCompress();
|
||||
|
||||
cinfo.image_width = pars->width;
|
||||
cinfo.image_height = pars->height;
|
||||
cinfo.input_components = 3;
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
|
||||
jpeg_set_defaults(&cinfo);
|
||||
|
||||
cinfo.dct_method = pars->dct_method;
|
||||
cinfo.optimize_coding = TRUE;
|
||||
cinfo.smoothing_factor = pars->smoothing_factor;
|
||||
jpeg_set_quality(&cinfo, pars->quality, TRUE);
|
||||
jpeg_set_colorspace(&cinfo, JCS_RGB);
|
||||
status = tjCompress2(tjCompressHandle,
|
||||
image_buffer,
|
||||
pars->width,
|
||||
0,
|
||||
pars->height,
|
||||
pars->color_space,
|
||||
&output_buffer,
|
||||
&output_size,
|
||||
pars->subsample,
|
||||
pars->quality,
|
||||
pars->dct_method);
|
||||
|
||||
|
||||
fwrite(output_buffer, 1, output_size, fp);
|
||||
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
row_stride = pars->width * 3;
|
||||
|
||||
|
||||
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);
|
||||
fclose(fp);
|
||||
tjDestroy(tjCompressHandle);
|
||||
tjFree(output_buffer);
|
||||
|
||||
}
|
||||
|
||||
|
@ -85,7 +70,7 @@ unsigned char* cclt_decompress(char* fileName, cclt_compress_parameters* pars) {
|
|||
|
||||
int destWidth = fileWidth;
|
||||
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,
|
||||
0,
|
||||
destHeight,
|
||||
TJPF_RGB,
|
||||
pars->color_space,
|
||||
TJFLAG_ACCURATEDCT);
|
||||
|
||||
tjDestroy(tjDecompressHandle);
|
||||
|
||||
pars->width = destWidth;
|
||||
pars->height = destHeight;
|
||||
|
||||
|
|
|
@ -2,19 +2,53 @@
|
|||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lossless.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* fp;
|
||||
|
||||
//Those will hold the input/output structs
|
||||
struct jpeg_decompress_struct srcinfo;
|
||||
struct jpeg_compress_struct dstinfo;
|
||||
|
||||
//Error Handling
|
||||
|
||||
//Error handling
|
||||
struct jpeg_error_mgr jsrcerr, jdsterr;
|
||||
|
||||
//Input/Output array coefficents
|
||||
|
@ -43,7 +77,7 @@ int cclt_optimize(char* input_file, char* output_file, int exif_flag) {
|
|||
//Save EXIF info
|
||||
if (exif_flag == 1) {
|
||||
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
|
||||
dstinfo.optimize_coding = TRUE;
|
||||
//Progressive
|
||||
jpeg_simple_progression(&dstinfo);
|
||||
|
||||
//Set the output file parameters
|
||||
jpeg_stdio_dest(&dstinfo, fp);
|
||||
|
||||
|
||||
//Actually write the coefficents
|
||||
jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
|
||||
|
||||
//Write EXIF
|
||||
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_destroy_compress(&dstinfo);
|
||||
(void) jpeg_finish_decompress(&srcinfo);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef 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
|
||||
|
|
11
src/main.c
11
src/main.c
|
@ -7,13 +7,14 @@
|
|||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <libexif/exif-data.h>
|
||||
|
||||
#include "lossless.h"
|
||||
#include "compress.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* PARAMETERS:
|
||||
-q quality
|
||||
-q quality v
|
||||
-e exif v
|
||||
-o output folder v
|
||||
-v version v
|
||||
|
@ -123,12 +124,12 @@ int main (int argc, char *argv[]) {
|
|||
|
||||
//Lossless optmization requested
|
||||
if (pars.lossless != 0) {
|
||||
|
||||
cclt_optimize(pars.input_files[i], output_filename, pars.exif_copy);
|
||||
cclt_optimize(pars.input_files[i], output_filename, pars.exif_copy, pars.input_files[i]);
|
||||
} else {
|
||||
//TODO Standard compression requested
|
||||
unsigned char* buffer = cclt_decompress(pars.input_files[i], &pars);
|
||||
cclt_compress(output_filename, buffer, &pars);
|
||||
//unsigned char* buffer = cclt_decompress(pars.input_files[i], &pars);
|
||||
//cclt_compress(output_filename, buffer, &pars);
|
||||
cclt_compress_routine(pars.input_files[i], output_filename, &pars);
|
||||
}
|
||||
|
||||
//Get output stats
|
||||
|
|
17
src/utils.c
17
src/utils.c
|
@ -5,6 +5,7 @@
|
|||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <turbojpeg.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <getopt.h>
|
||||
|
@ -12,6 +13,8 @@
|
|||
|
||||
|
||||
#include "utils.h"
|
||||
#include "compress.h"
|
||||
#include "lossless.h"
|
||||
|
||||
cclt_compress_parameters initialize_compression_parameters() {
|
||||
cclt_compress_parameters par;
|
||||
|
@ -19,10 +22,9 @@ cclt_compress_parameters initialize_compression_parameters() {
|
|||
par.quality = 0;
|
||||
par.width = 0;
|
||||
par.height = 0;
|
||||
par.smoothing_factor = 100;
|
||||
par.scaling_factor = 100;
|
||||
par.color_space = JCS_RGB;
|
||||
par.dct_method = JDCT_ISLOW;
|
||||
par.color_space = TJPF_RGB;
|
||||
par.dct_method = TJFLAG_FASTDCT;
|
||||
par.output_folder = NULL;
|
||||
par.exif_copy = 0;
|
||||
par.lossless = 0;
|
||||
|
@ -198,4 +200,11 @@ cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
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
|
||||
|
||||
#include <jpeglib.h>
|
||||
#include <turbojpeg.h>
|
||||
|
||||
#define APP_VERSION "1.9.9 BETA"
|
||||
#define BUILD 20150515
|
||||
|
@ -10,15 +11,15 @@ typedef struct cclt_compress_parameters {
|
|||
int quality;
|
||||
int width;
|
||||
int height;
|
||||
int smoothing_factor;
|
||||
int scaling_factor;
|
||||
char* output_folder;
|
||||
J_COLOR_SPACE color_space;
|
||||
J_DCT_METHOD dct_method;
|
||||
int color_space;
|
||||
int dct_method;
|
||||
int exif_copy;
|
||||
int lossless;
|
||||
char** input_files;
|
||||
int input_files_count;
|
||||
enum TJSAMP subsample;
|
||||
} cclt_compress_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);
|
||||
int mkpath(const char *pathname, mode_t mode);
|
||||
cclt_compress_parameters parse_arguments(int argc, char* argv[]);
|
||||
void cclt_compress_routine(char* input, char* output,cclt_compress_parameters* pars);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue