Decompression/Compression routine added

This commit is contained in:
Matteo Paonessa 2015-05-18 23:52:56 +02:00
parent 91ae054346
commit 8c71d0d93b
10 changed files with 241 additions and 117 deletions

View File

@ -20,7 +20,9 @@ See INSTALL for more details.
---------- ----------
###### TODO ###### TODO
A lot of things. A more detailed list will come later on. * Lossy compression
* Lossless scale
*
---------- ----------

View File

@ -1,4 +1,4 @@
bin_PROGRAMS = caesiumclt bin_PROGRAMS = caesiumclt
caesiumclt_SOURCES = main.c utils.c lossless.c compress.c caesiumclt_SOURCES = main.c utils.c lossless.c compress.c
caesiumclt_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -ljpeg -std=c99 caesiumclt_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -ljpeg -lturbojpeg -std=c99
caesiumclt_OBJCFLAGS = -D_FILE_OFFSET_BITS=64 -ljpeg caesiumclt_OBJCFLAGS = -D_FILE_OFFSET_BITS=64 -ljpeg -lturbojpeg

View File

@ -253,8 +253,8 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
caesiumclt_SOURCES = main.c utils.c lossless.c compress.c caesiumclt_SOURCES = main.c utils.c lossless.c compress.c
caesiumclt_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -ljpeg -std=c99 caesiumclt_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -ljpeg -lturbojpeg -std=c99
caesiumclt_OBJCFLAGS = -D_FILE_OFFSET_BITS=64 -ljpeg caesiumclt_OBJCFLAGS = -D_FILE_OFFSET_BITS=64 -ljpeg -lturbojpeg
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:

View File

@ -1,11 +1,13 @@
#include <setjmp.h> #include <setjmp.h>
#include <stdio.h> #include <stdio.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <turbojpeg.h>
#include <stdlib.h> #include <stdlib.h>
#include "compress.h" #include "compress.h"
#include "utils.h"
void cclt_compress(char* output_file, unsigned char* image_buffer) void cclt_compress(char* output_file, unsigned char* image_buffer, cclt_compress_parameters* pars)
{ {
struct jpeg_compress_struct cinfo; struct jpeg_compress_struct cinfo;
@ -15,8 +17,8 @@ void cclt_compress(char* output_file, unsigned char* image_buffer)
int row_stride; int row_stride;
if ((outfile = fopen(output_file, "wb")) == NULL) { if ((outfile = fopen(output_file, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", output_file); fprintf(stderr, "can't open %s\n", output_file);
exit(1); exit(1);
} }
cinfo.err = jpeg_std_error(&jerr); cinfo.err = jpeg_std_error(&jerr);
@ -24,35 +26,34 @@ void cclt_compress(char* output_file, unsigned char* image_buffer)
jpeg_create_compress(&cinfo); jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile); jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = 80; cinfo.image_width = pars->width;
cinfo.image_height = 80; cinfo.image_height = pars->height;
cinfo.input_components = 3; cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB; cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo); jpeg_set_defaults(&cinfo);
cinfo.dct_method = JDCT_FLOAT; cinfo.dct_method = pars->dct_method;
cinfo.optimize_coding = TRUE; cinfo.optimize_coding = TRUE;
cinfo.smoothing_factor = 50; cinfo.smoothing_factor = pars->smoothing_factor;
jpeg_set_quality(&cinfo, 80, TRUE ); jpeg_set_quality(&cinfo, pars->quality, TRUE);
jpeg_set_colorspace(&cinfo, JCS_RGB); jpeg_set_colorspace(&cinfo, JCS_RGB);
jpeg_start_compress(&cinfo, TRUE); jpeg_start_compress(&cinfo, TRUE);
//TODO cambia row_stride = pars->width * 3;
row_stride = 80 * 3;//image_width * 3;
while (cinfo.next_scanline < cinfo.image_height) { while (cinfo.next_scanline < cinfo.image_height) {
printf("%d%%\r", cinfo.next_scanline * 100 / cinfo.image_height); //printf("%d%%\r", cinfo.next_scanline * 100 / cinfo.image_height);
row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride]; row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1); (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
} }
printf("%d%%\n", cinfo.next_scanline * 100 / cinfo.image_height); //printf("%d%%\n", cinfo.next_scanline * 100 / cinfo.image_height);
jpeg_finish_compress(&cinfo); jpeg_finish_compress(&cinfo);
@ -62,3 +63,47 @@ void cclt_compress(char* output_file, unsigned char* image_buffer)
jpeg_destroy_compress(&cinfo); jpeg_destroy_compress(&cinfo);
} }
unsigned char* cclt_decompress(char* fileName, cclt_compress_parameters* pars) {
FILE *file = NULL;
int res = 0;
long int sourceJpegBufferSize = 0;
unsigned char* sourceJpegBuffer = NULL;
tjhandle tjDecompressHandle;
int fileWidth = 0, fileHeight = 0, jpegSubsamp = 0;
file = fopen(fileName, "rb");
res = fseek(file, 0, SEEK_END);
sourceJpegBufferSize = ftell(file);
sourceJpegBuffer = tjAlloc(sourceJpegBufferSize);
res = fseek(file, 0, SEEK_SET);
res = fread(sourceJpegBuffer, (long)sourceJpegBufferSize, 1, file);
tjDecompressHandle = tjInitDecompress();
res = tjDecompressHeader2(tjDecompressHandle, sourceJpegBuffer, sourceJpegBufferSize, &fileWidth, &fileHeight, &jpegSubsamp);
int destWidth = fileWidth;
int destHeight = fileHeight;
pars->color_space = jpegSubsamp;
unsigned char* temp = tjAlloc(destHeight * destWidth * tjPixelSize[TJPF_RGB]);
res = tjDecompress2(tjDecompressHandle,
sourceJpegBuffer,
sourceJpegBufferSize,
temp,
destWidth,
0,
destHeight,
TJPF_RGB,
TJFLAG_ACCURATEDCT);
pars->width = destWidth;
pars->height = destHeight;
return temp;
}

View File

@ -1,6 +1,9 @@
#ifndef CCTL_COMPRESS #ifndef CCLT_COMPRESS
#define CCTL_COMPRESS #define CCLT_COMPRESS
void cclt_compress(char* output_file, unsigned char* image_buffer); #include "utils.h"
void cclt_compress(char* output_file, unsigned char* image_buffer, cclt_compress_parameters* pars);
unsigned char* cclt_decompress(char* fileName, cclt_compress_parameters* pars);
#endif #endif

View File

@ -4,10 +4,11 @@
#include <stdlib.h> #include <stdlib.h>
#include "lossless.h" #include "lossless.h"
#include "utils.h"
int cclt_optimize(char* input_file, char* output_file) { int cclt_optimize(char* input_file, char* output_file, int exif_flag) {
//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;
@ -17,8 +18,8 @@ int cclt_optimize(char* input_file, char* output_file) {
struct jpeg_error_mgr jsrcerr, jdsterr; struct jpeg_error_mgr jsrcerr, jdsterr;
//Input/Output array coefficents //Input/Output array coefficents
jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr* src_coef_arrays;
jvirt_barray_ptr * dst_coef_arrays; jvirt_barray_ptr* dst_coef_arrays;
//Set errors and create the compress/decompress istances //Set errors and create the compress/decompress istances
srcinfo.err = jpeg_std_error(&jsrcerr); srcinfo.err = jpeg_std_error(&jsrcerr);
@ -38,12 +39,20 @@ int cclt_optimize(char* input_file, char* output_file) {
//Create the IO istance for the input file //Create the IO istance for the input file
jpeg_stdio_src(&srcinfo, fp); jpeg_stdio_src(&srcinfo, fp);
//Save EXIF info
if (exif_flag == 1) {
for (int m = 0; m < 16; m++) {
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
src_coef_arrays = jpeg_read_coefficients(&srcinfo); src_coef_arrays = jpeg_read_coefficients(&srcinfo);
//jcopy_markers_setup(&srcinfo, copyoption);
//Copy parameters //Copy parameters
jpeg_copy_critical_parameters(&srcinfo, &dstinfo); jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
@ -56,7 +65,7 @@ int cclt_optimize(char* input_file, char* output_file) {
//Open the output one instead //Open the output one instead
fp = fopen(output_file, "w+"); fp = fopen(output_file, "w+");
//Check for errors //Check for errors
//TODO Use UNIX error messages //TODO Use UNIX error messages
if (fp == NULL) { if (fp == NULL) {
printf("OUTPUT: Failed to open file \"%s\"\n", output_file); printf("OUTPUT: Failed to open file \"%s\"\n", output_file);
@ -66,13 +75,18 @@ int cclt_optimize(char* input_file, char* output_file) {
//CRITICAL - This is the optimization step //CRITICAL - This is the optimization step
dstinfo.optimize_coding = TRUE; dstinfo.optimize_coding = TRUE;
jpeg_simple_progression(&dstinfo); jpeg_simple_progression(&dstinfo);
//dstinfo.dct_method = JDCT_ISLOW;
//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
if (exif_flag == 1) {
jcopy_markers_execute(&srcinfo, &dstinfo);
}
//Free memory and finish //Free memory and finish
jpeg_finish_compress(&dstinfo); jpeg_finish_compress(&dstinfo);

View File

@ -1,6 +1,6 @@
#ifndef CCTL_LOSSLESS #ifndef CCLT_LOSSLESS
#define CCTL_LOSSLESS #define CCLT_LOSSLESS
int cclt_optimize(char* input_file, char* output_file); int cclt_optimize(char* input_file, char* output_file, int exif_flag);
#endif #endif

View File

@ -12,88 +12,19 @@
#include "compress.h" #include "compress.h"
#include "utils.h" #include "utils.h"
#define APP_VERSION "1.9.9 BETA"
#define BUILD 20150515
/* PARAMETERS: /* PARAMETERS:
-q quality -q quality
-e exif -e exif v
-o output folder -o output folder v
-v version -v version v
-l lossless -l lossless v
-s scale -s scale
-h help -h help v
-R recursive -R recursive
*/ */
//TODO Use a general fuction to support folder separators //TODO Use a general fuction to support folder separators
cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
//Initialize default params
cclt_compress_parameters parameters = initialize_compression_parameters();
int c;
while (optind < argc) {
if ((c = getopt (argc, argv, "q:velo:s:hR")) != -1) {
switch (c) {
case 'v':
printf("CCLT - Caesium Command Line Tools - Version %s (Build: %d)\n", APP_VERSION, BUILD);
exit(0);
break;
case '?':
if (optopt == 'q' || optopt == 'o' || optopt == 's') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
//Arguments without values
exit(-1);
}
else if (isprint(optopt)) {
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
}
else {
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
}
break;
case ':':
fprintf(stderr, "Parameter expected.\n");
break;
case 'q':
parameters.quality = string_to_int(optarg);
break;
case 'e':
parameters.exif_copy = 1;
break;
case 'l':
parameters.lossless = 1;
break;
case 'o':
parameters.output_folder = optarg;
break;
case 's':
parameters.scaling_factor = string_to_int(optarg);
break;
case 'h':
print_help();
break;
default:
abort();
}
} else {
int i = 0;
parameters.input_files = (char**) malloc ((argc - optind) * sizeof (char*));
while (optind < argc) {
parameters.input_files[i] = (char*) malloc (strlen(argv[optind]) * sizeof(char)); //TODO Necessary??
parameters.input_files[i] = argv[optind];
parameters.input_files_count = i + 1;
optind++;
i++;
}
}
}
return parameters;
}
int main (int argc, char *argv[]) { int main (int argc, char *argv[]) {
struct stat st_buf; struct stat st_buf;
errno = 0; errno = 0;
@ -138,9 +69,8 @@ int main (int argc, char *argv[]) {
fprintf(stderr, "No -o option pointing to the destination folder. Aborting.\n"); fprintf(stderr, "No -o option pointing to the destination folder. Aborting.\n");
exit(-4); exit(-4);
} else { } else {
if (mkdir(pars.output_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) { if (mkpath(pars.output_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) {
if (errno != EEXIST) { if (errno != EEXIST) {
perror("mkdir");
exit(-5); exit(-5);
} }
} }
@ -153,7 +83,7 @@ int main (int argc, char *argv[]) {
for (int i = 0; i < pars.input_files_count; i++) { for (int i = 0; i < pars.input_files_count; i++) {
off_t i_size, o_size; off_t i_size, o_size;
int status; //Pointer for stat() call int status; //Pointer for stat() call
char* output_filename = (char*) malloc (strlen(pars.output_folder) * sizeof(char)); char* output_filename = (char*) malloc ((strlen(pars.output_folder) + 2) * sizeof(char));
char* i_tmp = (char*) malloc (strlen(pars.input_files[i]) * sizeof(char)); char* i_tmp = (char*) malloc (strlen(pars.input_files[i]) * sizeof(char));
strcpy(i_tmp, pars.input_files[i]); strcpy(i_tmp, pars.input_files[i]);
@ -163,7 +93,9 @@ int main (int argc, char *argv[]) {
if (output_filename[strlen(pars.output_folder - 1)] != '/') { if (output_filename[strlen(pars.output_folder - 1)] != '/') {
strcat(output_filename, "/"); strcat(output_filename, "/");
} }
output_filename = realloc(output_filename, (strlen(output_filename) + strlen(get_filename_with_extension(i_tmp)) + 1) * sizeof(char));
output_filename = strcat(output_filename, get_filename_with_extension(i_tmp)); output_filename = strcat(output_filename, get_filename_with_extension(i_tmp));
//TODO OVERALL progress update? //TODO OVERALL progress update?
@ -183,7 +115,6 @@ int main (int argc, char *argv[]) {
} }
//Get input file size //Get input file size
//On 32bit system, compile with -D_FILE_OFFSET_BITS=64
i_size = st_buf.st_size; i_size = st_buf.st_size;
i_t_size += i_size; i_t_size += i_size;
@ -192,9 +123,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);
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);
cclt_compress(output_filename, buffer, &pars);
} }
//Get output stats //Get output stats

View File

@ -6,6 +6,10 @@
#include <stdio.h> #include <stdio.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <getopt.h>
#include <ctype.h>
#include "utils.h" #include "utils.h"
@ -15,14 +19,15 @@ 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 = 50; par.smoothing_factor = 100;
par.scaling_factor = 100; par.scaling_factor = 100;
//par.color_space = NULL; TODO Must set? par.color_space = JCS_RGB;
//par.dct_method = NULL; TODO Must set? par.dct_method = JDCT_ISLOW;
par.output_folder = NULL; par.output_folder = NULL;
par.exif_copy = 0; par.exif_copy = 0;
par.lossless = 0; par.lossless = 0;
par.input_files_count = 0; par.input_files_count = 0;
return par; return par;
} }
@ -73,9 +78,124 @@ void print_progress(int current, int max, char* message) {
} }
} }
//TODO Recheck
int mkpath(const char *pathname, mode_t mode) {
char parent[PATH_MAX], *p;
/* make a parent directory path */
strncpy(parent, pathname, sizeof(parent));
parent[sizeof(parent) - 1] = '\0';
for(p = parent + strlen(parent); *p != '/' && p != parent; p--);
*p = '\0';
/* try make parent directory */
if(p != parent && mkpath(parent, mode) != 0)
return -1;
/* make this one if parent has been made */
if(mkdir(pathname, mode) == 0)
return 0;
/* if it already exists that is fine */
if(errno == EEXIST)
return 0;
return -1;
}
char* get_filename_with_extension(char* full_path) { char* get_filename_with_extension(char* full_path) {
char* dest; char* dest;
dest = strrchr(full_path, '/') + 1; dest = strrchr(full_path, '/') + 1;
return dest; return dest;
} }
void jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo) {
jpeg_saved_marker_ptr marker;
for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
if (dstinfo->write_JFIF_header &&
marker->marker == JPEG_APP0 &&
marker->data_length >= 5 &&
GETJOCTET(marker->data[0]) == 0x4A &&
GETJOCTET(marker->data[1]) == 0x46 &&
GETJOCTET(marker->data[2]) == 0x49 &&
GETJOCTET(marker->data[3]) == 0x46 &&
GETJOCTET(marker->data[4]) == 0)
continue;
if (dstinfo->write_Adobe_marker &&
marker->marker == JPEG_APP0+14 &&
marker->data_length >= 5 &&
GETJOCTET(marker->data[0]) == 0x41 &&
GETJOCTET(marker->data[1]) == 0x64 &&
GETJOCTET(marker->data[2]) == 0x6F &&
GETJOCTET(marker->data[3]) == 0x62 &&
GETJOCTET(marker->data[4]) == 0x65)
continue;
jpeg_write_marker(dstinfo, marker->marker,
marker->data, marker->data_length);
}
}
cclt_compress_parameters parse_arguments(int argc, char* argv[]) {
//Initialize default params
cclt_compress_parameters parameters = initialize_compression_parameters();
int c;
while (optind < argc) {
if ((c = getopt (argc, argv, "q:velo:s:hR")) != -1) {
switch (c) {
case 'v':
printf("CCLT - Caesium Command Line Tools - Version %s (Build: %d)\n", APP_VERSION, BUILD);
exit(0);
break;
case '?':
if (optopt == 'q' || optopt == 'o' || optopt == 's') {
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
//Arguments without values
exit(-1);
}
else if (isprint(optopt)) {
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
}
else {
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
}
break;
case ':':
fprintf(stderr, "Parameter expected.\n");
break;
case 'q':
parameters.quality = string_to_int(optarg);
break;
case 'e':
parameters.exif_copy = 1;
break;
case 'l':
parameters.lossless = 1;
break;
case 'o':
parameters.output_folder = optarg;
break;
case 's':
parameters.scaling_factor = string_to_int(optarg);
break;
case 'h':
print_help();
break;
default:
abort();
}
} else {
int i = 0;
parameters.input_files = (char**) malloc ((argc - optind) * sizeof (char*));
while (optind < argc) {
parameters.input_files[i] = (char*) malloc (strlen(argv[optind]) * sizeof(char)); //TODO Necessary??
parameters.input_files[i] = argv[optind];
parameters.input_files_count = i + 1;
optind++;
i++;
}
}
}
return parameters;
}

View File

@ -1,8 +1,11 @@
#ifndef CCTL_UTILS #ifndef CCLT_UTILS
#define CCTL_UTILS #define CCLT_UTILS
#include <jpeglib.h> #include <jpeglib.h>
#define APP_VERSION "1.9.9 BETA"
#define BUILD 20150515
typedef struct cclt_compress_parameters { typedef struct cclt_compress_parameters {
int quality; int quality;
int width; int width;
@ -24,5 +27,8 @@ int string_to_int(char* in_string);
void print_help(); void print_help();
void print_progress(int current, int max, char* message); void print_progress(int current, int max, char* message);
char* get_filename_with_extension(char* full_path); 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[]);
#endif #endif