Created
March 21, 2015 23:00
-
-
Save CoolOppo/50caab75faed4cac2117 to your computer and use it in GitHub Desktop.
Decompresses JPEG files in order to compress them with a stronger algorithm if needed. Then, the files can be recompressed from the decompressed representation of them to a JPEG, without actually lossily re-encoding.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jpg2dct is a program to expand the DCT coefficients in a JPEG file to | |
make the file more compressible to other compression programs. | |
For example: | |
842,468 a10.jpg (input file, from maximumcompression.com) | |
833,336 a10.pmd (a10.jpg compressed with ppmd -o2) | |
5,972,404 a10.dct (after processing a10.jpg with jpg2dct) | |
770,302 a10.pmd (a10.dct compressed with ppmd -o2) | |
Usage: jpg2dct -i input -o output [-v] [-a] [-c] [-u] | |
Options: | |
-v verbose comments | |
-a ascii input/output | |
-c (re)compress as JPEG | |
-s shrink unused zero bits | |
-u store Huffman tables | |
Use '-' instead of input/output to assign stdin or stdout. | |
Or for help, use -h | |
Input and output default to standard input and output. | |
Redirection works even in Windows, e.g. | |
jpg2dct < file.jpg > file.dct | |
jpg2dct -c < file.dct > file.jpg | |
jpg2dct is lossy in that the new file.jpg is not bytewise identical | |
to the original, although it is pixel for pixel identical. (Converting | |
both files to .bmp produce identical results). In particular, EXIF | |
headers are not preserved, Huffman and quantization tables are reformatted | |
to their own segments, and restart markers are removed. Unless -u is used, | |
the Huffman codes may be different, so that the restored file might be larger. | |
In particular, a10.jpg in the example above is restored to 856,024 bytes. | |
If converted with -u then the restored file is 842,200 bytes. | |
-s produces a smaller file.dct, although this usually does not help | |
compression. -a is useful for viewing the decoded output. | |
jpg2dct accepts baseline and progressive mode Huffman coded JPEG images. | |
It does not fully implement the JPEG standard, but neither does most other | |
software. It does read any JPEG image you are likely to encounter. | |
jpg2dct.exe was compiled in MinGW g++ 3.4.2 as follows: | |
gcc -O2 -Os -s -fomit-frame-pointer -I\jpeg-6b jpg2dct.c \jpeg-6b\libjpeg.a -o jpg2dct.exe | |
where \jpeg-6b contains the IJG JPEG library from http://www.ijg.org/ | |
jpg2dct can be compiled in Linux as follows: | |
1. Copy this file in the JPEG library source directory | |
2. Compile the library from source | |
3. Type 'bash jpg2dct.c' | |
jpg2dct is Copyright (C) 2007, Jean-Pierre Demailly and released | |
under the GPL version 3. See http://www.gnu.org/copyleft/gpl.html | |
The original release was Sept. 4, 2007. It was ported to Windows | |
by Matt Mahoney on Sept. 15, 2007. The port consisted of adding | |
the following line to jpg2dct.c: | |
#include <fcntl.h> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define DUMMY \ | |
CC=gcc ; set -ex; \ | |
$CC -Wall -O2 -I. -c -o jpg2dct.o jpg2dct.c ; \ | |
$CC -o jpg2dct jpg2dct.o libjpeg.a ; \ | |
exit | |
/* $CC -o jpg2dct jpg2dct.o -ljpeg -L/usr/lib ; */ | |
/* | |
* jpg2dct.c | |
* | |
* Copyright (C) 2007, Jean-Pierre Demailly | |
* Released under the GPL version 3 | |
* | |
* This program converts a JPEG image into a non compressed file of its | |
* dct coefficients. In this way, stronger compressors than the | |
* default huffman algorithm can be used for compression, resulting | |
* to files of smaller size. Typical use : | |
* | |
* compressed to approximately 60% of their original size without any | |
* data loss. | |
* | |
* Compile instructions : | |
* 1. Copy this file in the JPEG library source directory | |
* 2. Compile the library from source | |
* 3. Type 'bash jpg2dct.c' | |
* | |
* To compile in MinGW g++ for Windows, assuming IJG JPEG library is in \jpeg-6b | |
* gcc -O2 -Os -s -fomit-frame-pointer -I\jpeg-6b jpg2dct.c \jpeg-6b\libjpeg.a -o jpg2dct.exe | |
* | |
* For help: jpg2dct -h | |
*/ | |
/* #define SHOW_STATS */ | |
#include <fcntl.h> /* Added by Matt Mahoney for MinGW Windows port */ | |
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ | |
#include "jversion.h" /* for version message */ | |
#include "transupp.h" /* for version message */ | |
#include "jmemsys.h" | |
#include "jpegint.h" | |
typedef struct jvirt_barray_control { | |
JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ | |
JDIMENSION rows_in_array; /* total virtual array height */ | |
JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ | |
JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ | |
JDIMENSION rows_in_mem; /* height of memory buffer */ | |
JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ | |
JDIMENSION cur_start_row; /* first logical row # in the buffer */ | |
JDIMENSION first_undef_row; /* row # of first uninitialized row */ | |
boolean pre_zero; /* pre-zero mode requested? */ | |
boolean dirty; /* do current buffer contents need written? */ | |
boolean b_s_open; /* is backing-store data valid? */ | |
jvirt_barray_ptr next; /* link to next virtual barray control block */ | |
backing_store_info b_s_info; /* System-dependent control info */ | |
} jvirt_barray_control; | |
/* | |
* Argument-parsing code. | |
* The switch parser is designed to be useful with DOS-style command line | |
* syntax, ie, intermixed switches and file names, where only the switches | |
* to the left of a given file name affect processing of that file. | |
* The main program in this file doesn't actually use this capability... | |
*/ | |
static const char * progname; /* program name for error messages */ | |
static JCOPY_OPTION copyoption = JCOPYOPT_ALL; /* -copy switch */ | |
/* | |
* Routines to establish binary I/O mode for stdin and stdout. | |
* Non-Unix systems often require some hacking to get out of text mode. | |
*/ | |
GLOBAL(FILE *) | |
read_stdin (void) | |
{ | |
FILE * input_file = stdin; | |
#ifdef USE_SETMODE /* need to hack file mode? */ | |
setmode(fileno(stdin), O_BINARY); | |
#endif | |
#ifdef USE_FDOPEN /* need to re-open in binary mode? */ | |
if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) { | |
fprintf(stderr, "Cannot reopen stdin\n"); | |
exit(EXIT_FAILURE); | |
} | |
#endif | |
return input_file; | |
} | |
GLOBAL(FILE *) | |
write_stdout (void) | |
{ | |
FILE * output_file = stdout; | |
#ifdef USE_SETMODE /* need to hack file mode? */ | |
setmode(fileno(stdout), O_BINARY); | |
#endif | |
#ifdef USE_FDOPEN /* need to re-open in binary mode? */ | |
if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { | |
fprintf(stderr, "Cannot reopen stdout\n"); | |
exit(EXIT_FAILURE); | |
} | |
#endif | |
return output_file; | |
} | |
/* Setup decompression object to save desired markers in memory. | |
* This must be called before jpeg_read_header() to have the desired effect. | |
*/ | |
void | |
jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) | |
{ | |
#ifdef SAVE_MARKERS_SUPPORTED | |
int m; | |
/* Save comments except under NONE option */ | |
if (option != JCOPYOPT_NONE) { | |
jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); | |
} | |
/* Save all types of APPn markers iff ALL option */ | |
if (option == JCOPYOPT_ALL) { | |
for (m = 0; m < 16; m++) | |
jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); | |
} | |
#endif /* SAVE_MARKERS_SUPPORTED */ | |
} | |
/* | |
* The main program. | |
*/ | |
#define HEADER_SIZE 64 | |
#define HUFF_TBL_SIZE 273 | |
#if 0 | |
const int jpeg_natural_order[DCTSIZE2] = { | |
0, 1, 8, 16, 9, 2, 3, 10, | |
17, 24, 32, 25, 18, 11, 4, 5, | |
12, 19, 26, 33, 40, 48, 41, 34, | |
27, 20, 13, 6, 7, 14, 21, 28, | |
35, 42, 49, 56, 57, 50, 43, 36, | |
29, 22, 15, 23, 30, 37, 44, 51, | |
58, 59, 52, 45, 38, 31, 39, 46, | |
53, 60, 61, 54, 47, 55, 62, 63 | |
}; | |
const int jpeg_zigzag_order[DCTSIZE2] = { | |
0, 1, 5, 6, 14, 15, 27, 28, | |
2, 4, 7, 13, 16, 26, 29, 42, | |
3, 8, 12, 17, 25, 30, 41, 43, | |
9, 11, 18, 24, 31, 40, 44, 53, | |
10, 19, 23, 32, 39, 45, 52, 54, | |
20, 22, 33, 38, 46, 51, 55, 60, | |
21, 34, 37, 47, 50, 56, 59, 61, | |
35, 36, 48, 49, 57, 58, 62, 63 | |
}; | |
#endif | |
void usage() | |
{ | |
fprintf(stderr, "\ | |
Usage: jpg2dct -i input -o output [-v] [-a] [-c] [-u]\n\ | |
Options:\n\ | |
\t-v\tverbose comments\n\ | |
\t-a\tascii input/output\n\ | |
\t-c\t(re)compress as JPEG\n\ | |
\t-s\tshrink unused zero bits\n\ | |
\t-u\tstore Huffman tables\n\ | |
Use '-' instead of input/output to assign stdin or stdout.\n\ | |
"); | |
exit(0); | |
} | |
unsigned short | |
twist(unsigned short n) | |
{ | |
if (n & 0x8000) | |
return ((n<<1)|1) ^ 0xfffe; | |
else | |
return n<<1; | |
} | |
unsigned short | |
untwist(unsigned short n) | |
{ | |
if (n & 1) | |
return ((n ^ 0xfffe) >> 1) | 0x8000; | |
else | |
return n>>1; | |
} | |
int | |
main (int argc, char **argv) | |
{ | |
struct jpeg_decompress_struct srcinfo; | |
struct jpeg_compress_struct dstinfo; | |
struct jpeg_error_mgr jsrcerr, jdsterr; | |
jvirt_barray_ptr * src_coef_arrays; | |
jvirt_barray_ptr * dst_coef_arrays; | |
char * file_input = NULL; | |
char * file_output = NULL; | |
unsigned char hptr[HEADER_SIZE]; | |
unsigned char *cptr; | |
JQUANT_TBL ** qtblptr; | |
JHUFF_TBL ** htblptr; | |
JDIMENSION blk_x, blk_y; | |
JBLOCKARRAY buffer; | |
jpeg_component_info *compptr; | |
int compress = 0, ascii = 0, verbose = 0, skip_huff = -1; | |
int ci, tblno, i, j, dy, ind; | |
int num_qtab, num_dctab, num_actab; | |
long int total = 0; | |
FILE * f_in; | |
FILE * f_out; | |
unsigned int mix = 0; | |
int count = 0, shrink = 0; | |
int dct_factor = 2*DCTSIZE2; | |
#ifdef SHOW_STATS | |
/* statistics on values */ | |
int val1[DCTSIZE2], val2[DCTSIZE2]; | |
memset(val1, 0, SIZEOF(val1)); | |
memset(val2, 0, SIZEOF(val2)); | |
#endif | |
progname = argv[0]; | |
if (progname == NULL || progname[0] == 0) | |
progname = "jpg2dct"; /* in case C library doesn't provide it */ | |
for (ci=1; ci<argc; ci++) { | |
if (ci<argc-1 && !strcmp(argv[ci], "-i")) | |
file_input = argv[++ci]; | |
else | |
if (ci<argc-1 && !strcmp(argv[ci], "-o")) | |
file_output = argv[++ci]; | |
else | |
if (!strcmp(argv[ci], "-a")) | |
ascii = 1; | |
else | |
if (!strcmp(argv[ci], "-c")) | |
compress = 1; | |
else | |
if (!strcmp(argv[ci], "-s")) { | |
shrink = 1; | |
dct_factor = 88; | |
} | |
else | |
if (!strcmp(argv[ci], "-u")) | |
skip_huff = 1; | |
else | |
if (!strcmp(argv[ci], "-v")) | |
verbose = 1; | |
else | |
usage(); | |
} | |
/* Open the input file. */ | |
if (file_input) { | |
if ((f_in = fopen(file_input, READ_BINARY)) == NULL) { | |
fprintf(stderr, "%s: can't open %s for reading\n", progname, file_input); | |
exit(EXIT_FAILURE); | |
} | |
} else { | |
/* default input file is stdin */ | |
file_input = "-"; | |
f_in = read_stdin(); | |
} | |
/* Open the output file. */ | |
if (file_output) { | |
if ((f_out = fopen(file_output, WRITE_BINARY)) == NULL) { | |
fprintf(stderr, "%s: can't open %s for writing\n", progname,file_output); | |
exit(EXIT_FAILURE); | |
} | |
} else { | |
/* default output file is stdout */ | |
file_output = "-"; | |
f_out = write_stdout(); | |
} | |
if (compress) { | |
dstinfo.err = jpeg_std_error(&jdsterr); | |
jpeg_create_compress(&dstinfo); | |
jpeg_stdio_dest(&dstinfo, f_out); | |
/* first check magic string */ | |
JFREAD(f_in, hptr, 8); | |
hptr[8] = '\0'; | |
if (!strcmp((char *)hptr, "JFIFDCT\n")) | |
shrink = 0; | |
else | |
if (!strcmp((char *)hptr, "JFIFdct\n")) { | |
shrink = 1; | |
dct_factor = 88; | |
} else { | |
fprintf(stderr, "'%s' is not a JPEG DCT file !!\n", file_input); | |
exit(-1); | |
} | |
JFREAD(f_in, hptr, HEADER_SIZE); | |
MEMCOPY(&dstinfo.image_width, hptr, 4); | |
MEMCOPY(&dstinfo.image_height, hptr+4, 4); | |
MEMCOPY(&dstinfo.input_components, hptr+8, 4); | |
MEMCOPY(&dstinfo.in_color_space, hptr+12, 4); | |
MEMCOPY(&dstinfo.progressive_mode, hptr+16, 4); | |
MEMCOPY(&num_qtab, hptr+52, 4); | |
MEMCOPY(&num_dctab, hptr+56, 4); | |
MEMCOPY(&num_actab, hptr+60, 4); | |
dstinfo.jpeg_color_space = dstinfo.in_color_space; | |
dstinfo.num_components = dstinfo.input_components; | |
if (verbose) { | |
fprintf(stderr, | |
"Converting %s DCT file '%s' into JPEG file '%s' :\n", | |
(ascii)?"ascii":"binary", file_input, file_output); | |
fprintf(stderr, "image info header: %d bytes\n", HEADER_SIZE); | |
fprintf(stderr, | |
" width=%d, height=%d, num_components=%d, color_space=%d\n", | |
dstinfo.image_width, dstinfo.image_height, | |
dstinfo.input_components, dstinfo.in_color_space); | |
fprintf(stderr, | |
" num quant_tables=%d dc_huff_tables=%d ac_huff_tables=%d\n", | |
num_qtab, num_dctab, num_actab); | |
} | |
jpeg_set_defaults(&dstinfo); | |
dstinfo.raw_data_in = TRUE; | |
jpeg_set_colorspace(&dstinfo, dstinfo.jpeg_color_space); | |
MEMCOPY(&dstinfo.data_precision, hptr+20, 4); | |
MEMCOPY(&dstinfo.CCIR601_sampling, hptr+24, 4); | |
for (tblno = 0; tblno < num_qtab; tblno++) { | |
qtblptr = &dstinfo.quant_tbl_ptrs[tblno]; | |
if (*qtblptr == NULL) | |
*qtblptr = jpeg_alloc_quant_table((j_common_ptr)&dstinfo); | |
JFREAD(f_in, (*qtblptr)->quantval, 2*DCTSIZE2); | |
(*qtblptr)->sent_table = FALSE; | |
if (verbose) | |
fprintf(stderr, "quantization table[%d]: %d uint16\n", tblno, DCTSIZE2); | |
} | |
for (tblno = 0; tblno < num_dctab; tblno++) { | |
htblptr = &dstinfo.dc_huff_tbl_ptrs[tblno]; | |
if (*htblptr == NULL) | |
*htblptr = jpeg_alloc_huff_table((j_common_ptr)&dstinfo); | |
JFREAD(f_in, (*htblptr), HUFF_TBL_SIZE); | |
(*htblptr)->sent_table = FALSE; | |
if (verbose) | |
fprintf(stderr, "dc huff table[%d]: %d bytes\n", tblno, HUFF_TBL_SIZE); | |
} | |
for (tblno = 0; tblno < num_actab; tblno++) { | |
htblptr = &dstinfo.ac_huff_tbl_ptrs[tblno]; | |
if (*htblptr == NULL) | |
*htblptr = jpeg_alloc_huff_table((j_common_ptr)&dstinfo); | |
JFREAD(f_in, (*htblptr), HUFF_TBL_SIZE); | |
(*htblptr)->sent_table = FALSE; | |
if (verbose) | |
fprintf(stderr, "ac huff table[%d]: %d bytes\n", tblno, HUFF_TBL_SIZE); | |
} | |
MEMCOPY(&dstinfo.num_components, hptr+8, 4); | |
if (dstinfo.num_components < 1 || | |
dstinfo.num_components > MAX_COMPONENTS) | |
ERREXIT2(&dstinfo, JERR_COMPONENT_COUNT, dstinfo.num_components, | |
MAX_COMPONENTS); | |
for (ci = 0; ci < dstinfo.num_components; ci++) { | |
JFREAD(f_in, &dstinfo.comp_info[ci].component_id, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].component_index, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].width_in_blocks, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].height_in_blocks, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].h_samp_factor, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].v_samp_factor, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].quant_tbl_no, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].dc_tbl_no, 4); | |
JFREAD(f_in, &dstinfo.comp_info[ci].ac_tbl_no, 4); | |
/* | |
if (dstinfo.comp_info[ci].h_samp_factor>dstinfo.max_h_samp_factor) | |
dstinfo.max_h_samp_factor = dstinfo.comp_info[ci].h_samp_factor; | |
if (dstinfo.comp_info[ci].v_samp_factor>dstinfo.max_v_samp_factor) | |
dstinfo.max_v_samp_factor = dstinfo.comp_info[ci].v_samp_factor; | |
*/ | |
if (verbose) { | |
fprintf(stderr, "component header[%d] : 36 bytes\n", ci); | |
fprintf(stderr, | |
" id=%d idx=%d, %d x %d blocks, sampling %d %d, quant=%d, dc_no=%d ac_no=%d\n", | |
dstinfo.comp_info[ci].component_id, | |
dstinfo.comp_info[ci].component_index, | |
dstinfo.comp_info[ci].width_in_blocks, | |
dstinfo.comp_info[ci].height_in_blocks, | |
dstinfo.comp_info[ci].h_samp_factor, | |
dstinfo.comp_info[ci].v_samp_factor, | |
dstinfo.comp_info[ci].quant_tbl_no, | |
dstinfo.comp_info[ci].dc_tbl_no, | |
dstinfo.comp_info[ci].ac_tbl_no); | |
} | |
/* Note: we do not copy the source's Huffman table assignments; | |
* instead we rely on jpeg_set_colorspace to have made a suitable choice. | |
*/ | |
} | |
MEMCOPY(&i, hptr+36, 4); | |
if (i) { | |
if (i == 1) { | |
MEMCOPY(&dstinfo.JFIF_major_version, hptr+28, 4); | |
MEMCOPY(&dstinfo.JFIF_minor_version, hptr+32, 4); | |
} | |
MEMCOPY(&dstinfo.density_unit, hptr+40, 4); | |
MEMCOPY(&dstinfo.X_density, hptr+44, 4); | |
MEMCOPY(&dstinfo.Y_density, hptr+48, 4); | |
} | |
if (dstinfo.progressive_mode) jpeg_simple_progression(&dstinfo); | |
dst_coef_arrays = (jvirt_barray_ptr *) | |
(dstinfo.mem->alloc_small) ((j_common_ptr)&dstinfo, JPOOL_IMAGE, | |
sizeof(jvirt_barray_ptr) * dstinfo.num_components); | |
for (ci=0; ci<dstinfo.num_components; ci++) { | |
compptr = &dstinfo.comp_info[ci]; | |
dst_coef_arrays[ci] = (dstinfo.mem->request_virt_barray) | |
((j_common_ptr) &dstinfo, JPOOL_IMAGE, TRUE, | |
compptr->width_in_blocks+1, compptr->height_in_blocks+1, | |
(JDIMENSION) compptr->v_samp_factor); | |
} | |
(dstinfo.mem->realize_virt_arrays)((j_common_ptr) &dstinfo); | |
for (ind=0; ind<2*DCTSIZE2; ind++) | |
for (ci=0; ci<dstinfo.num_components; ci++) { | |
compptr = &dstinfo.comp_info[ci]; | |
for (blk_y=0; blk_y<compptr->height_in_blocks; | |
blk_y += compptr->v_samp_factor) { | |
buffer = (dstinfo.mem->access_virt_barray) | |
((j_common_ptr) &dstinfo, dst_coef_arrays[ci], blk_y, | |
(JDIMENSION) compptr->v_samp_factor, TRUE); | |
if (!ascii) | |
for (dy=0; dy<compptr->v_samp_factor; dy++) | |
for (blk_x=0; blk_x<compptr->width_in_blocks; blk_x++) { | |
char data[3]; | |
unsigned short s; | |
i = ind % DCTSIZE2; | |
if (ind<DCTSIZE2) { | |
JFREAD(f_in, data, 1); | |
data[1] ='\0'; | |
memcpy(&buffer[dy][blk_x][jpeg_natural_order[i]], data, 2); | |
} else { | |
memcpy(data, &buffer[dy][blk_x][jpeg_natural_order[i]], 2); | |
if (shrink) { | |
if (count == 0) { | |
mix = 0; | |
JFREAD(f_in, &mix, 3); | |
} | |
data[1] = (mix>>21) & 0x07; | |
mix = mix << 3; | |
count = (count +1) % 8; | |
} else | |
JFREAD(f_in, data+1, 1); | |
memcpy(&s, data, 2); | |
s = untwist(s); | |
memcpy(&buffer[dy][blk_x][jpeg_natural_order[i]], &s, 2); | |
} | |
} | |
} | |
if (verbose && ind==(2*ci*DCTSIZE2)/dstinfo.num_components) | |
fprintf(stderr, "component dct data[%d] %d x %d blocks: %d bytes\n", | |
ci, compptr->width_in_blocks, compptr->height_in_blocks, | |
dct_factor*compptr->width_in_blocks*compptr->height_in_blocks); | |
} | |
fclose(f_in); | |
jpeg_write_coefficients(&dstinfo, dst_coef_arrays); | |
jpeg_finish_compress(&dstinfo); | |
jpeg_destroy_compress(&dstinfo); | |
fprintf(stderr, "written '%s', color_space=%d, width=%d height=%d\n", | |
file_output, dstinfo.jpeg_color_space, | |
dstinfo.image_width, dstinfo.image_height); | |
} else { | |
srcinfo.err = jpeg_std_error(&jsrcerr); | |
jpeg_create_decompress(&srcinfo); | |
#ifdef NEED_SIGNAL_CATCHER | |
enable_signal_catcher((j_common_ptr) &srcinfo); | |
#endif | |
jpeg_stdio_src(&srcinfo, f_in); | |
jcopy_markers_setup(&srcinfo, copyoption); | |
(void) jpeg_read_header(&srcinfo, TRUE); | |
src_coef_arrays = jpeg_read_coefficients(&srcinfo); | |
if (f_in != stdin) fclose(f_in); | |
if (verbose) | |
fprintf(stderr, | |
"Converting JPEG image '%s' to %s DCT output '%s' :\n", | |
file_input, (ascii)?"ascii":"binary", file_output); | |
num_qtab = 0; | |
for (tblno=0; tblno<NUM_QUANT_TBLS; tblno++) | |
if (srcinfo.quant_tbl_ptrs[tblno] != NULL) ++num_qtab; | |
num_dctab = 0; | |
for (tblno=0; tblno<NUM_HUFF_TBLS; tblno++) | |
if (srcinfo.dc_huff_tbl_ptrs[tblno] != NULL) ++num_dctab; | |
num_actab = 0; | |
for (tblno=0; tblno<NUM_HUFF_TBLS; tblno++) | |
if (srcinfo.ac_huff_tbl_ptrs[tblno] != NULL) ++num_actab; | |
num_dctab *= skip_huff; | |
num_actab *= skip_huff; | |
if (ascii) { | |
fprintf(f_out, "image info header: %d bytes\n", HEADER_SIZE+8); | |
} else { | |
if (shrink) | |
JFWRITE(f_out, "JFIFdct\n", 8); | |
else | |
JFWRITE(f_out, "JFIFDCT\n", 8); | |
MEMCOPY(hptr, &srcinfo.image_width, 4); | |
MEMCOPY(hptr+4, &srcinfo.image_height, 4); | |
MEMCOPY(hptr+8, &srcinfo.num_components, 4); | |
MEMCOPY(hptr+12, &srcinfo.jpeg_color_space, 4); | |
MEMCOPY(hptr+16, &srcinfo.progressive_mode, 4); | |
MEMCOPY(hptr+20, &srcinfo.data_precision, 4); | |
MEMCOPY(hptr+24, &srcinfo.CCIR601_sampling, 4); | |
MEMCOPY(hptr+28, &srcinfo.JFIF_major_version, 4); | |
MEMCOPY(hptr+32, &srcinfo.JFIF_minor_version, 4); | |
MEMCOPY(hptr+36, &srcinfo.saw_JFIF_marker, 4); | |
MEMCOPY(hptr+40, &srcinfo.density_unit, 4); | |
MEMCOPY(hptr+44, &srcinfo.X_density, 4); | |
MEMCOPY(hptr+48, &srcinfo.Y_density, 4); | |
MEMCOPY(hptr+52, &num_qtab, 4); | |
MEMCOPY(hptr+56, &num_dctab, 4); | |
MEMCOPY(hptr+60, &num_actab, 4); | |
JFWRITE(f_out, hptr, HEADER_SIZE); | |
total = 8+HEADER_SIZE; | |
} | |
if (verbose) { | |
fprintf(stderr, "image info header: %d bytes\n", HEADER_SIZE); | |
fprintf(stderr, | |
" width=%d, height=%d, num_components=%d, color_space=%d\n", | |
srcinfo.image_width, srcinfo.image_height, | |
srcinfo.num_components, srcinfo.jpeg_color_space); | |
fprintf(stderr, | |
" num quant_tables=%d dc_huff_tables=%d ac_huff_tables=%d\n", | |
num_qtab, num_dctab, num_actab); | |
} | |
for (tblno=0; tblno<num_qtab; tblno++) { | |
if (ascii) { | |
fprintf(f_out, "quantization table[%d]: %d uint16\n",tblno, DCTSIZE2); | |
cptr = (unsigned char *)&srcinfo.quant_tbl_ptrs[tblno]; | |
for (i=0; i<DCTSIZE2; i++) { | |
j = (UINT16)(*cptr++)<<8; | |
j |= (UINT16)*cptr++; | |
fprintf(f_out, "%u\n", j); | |
} | |
} else { | |
JFWRITE(f_out, srcinfo.quant_tbl_ptrs[tblno]->quantval, 2*DCTSIZE2); | |
total += 2*DCTSIZE2; | |
} | |
if (verbose) | |
fprintf(stderr, "quantization table[%d]: %d uint16\n", tblno, DCTSIZE2); | |
} | |
for (tblno=0; tblno<num_dctab; tblno++) { | |
if (ascii) { | |
fprintf(f_out, "dc huffman table[%d]: %d bytes\n",tblno, HUFF_TBL_SIZE); | |
cptr = (unsigned char *)&srcinfo.dc_huff_tbl_ptrs[tblno]; | |
for (i=0; i<DCTSIZE2; i++) { | |
j = (UINT16)(*cptr++)<<8; | |
j |= (UINT16)*cptr++; | |
fprintf(f_out, "%u\n", j); | |
} | |
} else { | |
JFWRITE(f_out, srcinfo.dc_huff_tbl_ptrs[tblno], HUFF_TBL_SIZE); | |
total += HUFF_TBL_SIZE; | |
} | |
if (verbose) | |
fprintf(stderr, "dc huffman table[%d]: %d bytes\n", tblno, HUFF_TBL_SIZE); | |
} | |
for (tblno=0; tblno<num_actab; tblno++) { | |
if (ascii) { | |
fprintf(f_out, "ac huffman table[%d]: %d bytes\n",tblno, HUFF_TBL_SIZE); | |
cptr = (unsigned char *)&srcinfo.ac_huff_tbl_ptrs[tblno]; | |
for (i=0; i<DCTSIZE2; i++) { | |
j = (UINT16)(*cptr++)<<8; | |
j |= (UINT16)*cptr++; | |
fprintf(f_out, "%u\n", j); | |
} | |
} else { | |
JFWRITE(f_out, srcinfo.ac_huff_tbl_ptrs[tblno], HUFF_TBL_SIZE); | |
total += HUFF_TBL_SIZE; | |
} | |
if (verbose) | |
fprintf(stderr, "ac huffman table[%d]: %d bytes\n", tblno, | |
HUFF_TBL_SIZE); | |
} | |
for (ci=0; ci<srcinfo.num_components; ci++) { | |
compptr = &srcinfo.comp_info[ci]; | |
if (ascii) { | |
fprintf(f_out, "component header[%d]: %d bytes\n", | |
ci, sizeof(jpeg_component_info)); | |
} else { | |
JFWRITE(f_out, &srcinfo.comp_info[ci].component_id, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].component_index, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].width_in_blocks, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].height_in_blocks, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].h_samp_factor, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].v_samp_factor, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].quant_tbl_no, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].dc_tbl_no, 4); | |
JFWRITE(f_out, &srcinfo.comp_info[ci].ac_tbl_no, 4); | |
total += 36; | |
} | |
if (verbose) { | |
fprintf(stderr, "component header[%d] : 36 bytes\n", ci); | |
fprintf(stderr, | |
" id=%d idx=%d, %d x %d blocks, sampling %d %d, quant=%d, dc_no=%d ac_no=%d\n", | |
srcinfo.comp_info[ci].component_id, | |
srcinfo.comp_info[ci].component_index, | |
srcinfo.comp_info[ci].width_in_blocks, | |
srcinfo.comp_info[ci].height_in_blocks, | |
srcinfo.comp_info[ci].h_samp_factor, | |
srcinfo.comp_info[ci].v_samp_factor, | |
srcinfo.comp_info[ci].quant_tbl_no, | |
srcinfo.comp_info[ci].dc_tbl_no, | |
srcinfo.comp_info[ci].ac_tbl_no); | |
} | |
} | |
for (ind=0; ind<2*DCTSIZE2; ind++) | |
for (ci=0; ci<srcinfo.num_components; ci++) { | |
compptr = &srcinfo.comp_info[ci]; | |
buffer = (srcinfo.mem->access_virt_barray) | |
((j_common_ptr) &srcinfo, src_coef_arrays[ci], 0, | |
(JDIMENSION) compptr->v_samp_factor, FALSE); | |
if (ascii) { | |
fprintf(f_out, "component dct data[%d] %d x %d: %d bytes\n", | |
ci, compptr->width_in_blocks, compptr->height_in_blocks, | |
dct_factor*compptr->width_in_blocks*compptr->height_in_blocks); | |
for (blk_y=0; blk_y<compptr->height_in_blocks; ++blk_y) { | |
for (blk_x=0; blk_x<compptr->width_in_blocks; ++blk_x) { | |
fprintf(f_out, "DCT block [%d %d]:\n", blk_x, blk_y); | |
for (ind=0; ind<DCTSIZE2; ind++) { | |
fprintf(f_out, "%6d ", (short)buffer[blk_y][blk_x][ind]); | |
if (ind%8==7) fprintf(f_out, "\n"); | |
} | |
fprintf(f_out, "\n"); | |
} | |
} | |
} else { | |
for (blk_y=0; blk_y<compptr->height_in_blocks; | |
blk_y += compptr->v_samp_factor) { | |
buffer = (srcinfo.mem->access_virt_barray) | |
((j_common_ptr) &srcinfo, src_coef_arrays[ci], blk_y, | |
(JDIMENSION) compptr->v_samp_factor, FALSE); | |
if (!ascii) | |
for (dy=0; dy<compptr->v_samp_factor; dy++) | |
for (blk_x=0; blk_x<compptr->width_in_blocks; blk_x++) { | |
char data[3]; | |
unsigned short s; | |
#ifdef SHOW_STATS | |
short u; | |
if (ind<DCTSIZE2) { | |
u = buffer[dy][blk_x][jpeg_natural_order[ind]]; | |
if (u!=0) ++val1[ind]; | |
if (abs(u)>127) ++val2[ind]; | |
} | |
#endif | |
i = ind % DCTSIZE2; | |
memcpy(&s, &buffer[dy][blk_x][jpeg_natural_order[i]], 2); | |
s = twist(s); | |
memcpy(data, &s, 2); | |
if (ind<DCTSIZE2) | |
JFWRITE(f_out, data, 1); | |
else { | |
if (shrink) { | |
mix = mix << 3; | |
mix |= (unsigned char)(data[1] & 0x07); | |
count = (count + 1) % 8; | |
if (count == 0) { | |
JFWRITE(f_out, &mix, 3); | |
mix = 0; | |
} | |
} else | |
JFWRITE(f_out, data+1, 1); | |
} | |
} | |
} | |
} | |
if (ind==(2*ci*DCTSIZE2)/srcinfo.num_components) { | |
i = dct_factor*compptr->width_in_blocks*compptr->height_in_blocks; | |
if (verbose) | |
fprintf(stderr, "component dct data[%d] %d x %d blocks: %d bytes\n", | |
ci, compptr->width_in_blocks, compptr->height_in_blocks, i); | |
total += i; | |
} | |
} | |
(void) jpeg_finish_decompress(&srcinfo); | |
jpeg_destroy_decompress(&srcinfo); | |
if (f_out != stdout) fclose(f_out); | |
if (verbose) | |
fprintf(stderr, | |
"written '%s', color_space=%d, width=%d height=%d, size=%ld\n", | |
file_output, srcinfo.jpeg_color_space, | |
srcinfo.image_width, srcinfo.image_height, total); | |
#ifdef SHOW_STATS | |
fprintf(stderr, "index #(>0) #(>127)\n"); | |
for (ind=0; ind<DCTSIZE2; ind++) | |
fprintf(stderr, "[%2d] %8d %8d\n", ind, val1[ind], val2[ind]); | |
#endif | |
} | |
return 0; /* suppress no-return-value warnings */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment