Skip to content

Instantly share code, notes, and snippets.

@CoolOppo
Created March 21, 2015 23:00
Show Gist options
  • Save CoolOppo/50caab75faed4cac2117 to your computer and use it in GitHub Desktop.
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.
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>
#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