commit 048b0f1b34bef029ec1dea48c9dc7fa9ff51a733ad8d891714ddbb5843bb1fef Author: Petr Gajdos Date: Fri Dec 10 14:42:49 2010 +0000 osc copypac from project:home:pgajdos package:libjpeg-turbo revision:19 OBS-URL: https://build.opensuse.org/package/show/graphics/libjpeg-turbo?expand=0&rev=1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/baselibs.conf b/baselibs.conf new file mode 100644 index 0000000..03f8c62 --- /dev/null +++ b/baselibs.conf @@ -0,0 +1,2 @@ +libjpeg62 +libjpeg62-devel diff --git a/libjpeg-turbo-1.0.1-int32.patch b/libjpeg-turbo-1.0.1-int32.patch new file mode 100644 index 0000000..39909ef --- /dev/null +++ b/libjpeg-turbo-1.0.1-int32.patch @@ -0,0 +1,11 @@ +--- jmorecfg.h ++++ jmorecfg.h +@@ -158,7 +158,7 @@ + /* INT32 must hold at least signed 32-bit values. */ + + #ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +-typedef long INT32; ++typedef int INT32; + #endif + + /* Datatype used for image dimensions. The JPEG standard only supports diff --git a/libjpeg-turbo-1.0.1-jpegtran.patch b/libjpeg-turbo-1.0.1-jpegtran.patch new file mode 100644 index 0000000..8d38b56 --- /dev/null +++ b/libjpeg-turbo-1.0.1-jpegtran.patch @@ -0,0 +1,1934 @@ +--- jerror.h ++++ jerror.h +@@ -45,6 +45,7 @@ + JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") + JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") + JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") ++JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") + JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") + JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") + JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +--- jpegtran.1 ++++ jpegtran.1 +@@ -131,6 +131,40 @@ + .B \-rot 180 -trim + trims both edges. + .PP ++If you are only interested by perfect transformation, add the ++.B \-perfect ++switch: ++.TP ++.B \-perfect ++Fails with an error if the transformation is not perfect. For example ++you may want to do ++.TP ++.B (jpegtran \-rot 90 -perfect foo.jpg || djpeg foo.jpg| pnmflip \-r90 | cjpeg) ++to do a perfect rotation if available or an approximated one if ++not. ++.PP ++We also offer a lossless-crop option, which discards data outside a given ++image region but losslessly preserves what is inside. Like the rotate and ++flip transforms, lossless crop is restricted by the JPEG format: the upper ++left corner of the selected region must fall on an iMCU boundary. If this ++does not hold for the given crop parameters, we silently move the upper left ++corner up and/or left to make it so, simultaneously increasing the region ++dimensions to keep the lower right crop corner unchanged. (Thus, the ++output image covers at least the requested region, but may cover more.) ++ ++Note: ++.B \-perfect ++and ++.B lossless-crop ++are enhancements from http://sylvana.net/jpegcrop/ that may not be available on ++other systems. ++ ++The image can be losslessly cropped by giving the switch: ++.TP ++.B \-crop WxH+X+Y ++Crop to a rectangular subarea of width W, height H starting at point X,Y. ++.PP ++.PP + Another not-strictly-lossless transformation switch is: + .TP + .B \-grayscale +@@ -231,7 +265,9 @@ + .PP + The transform options can't transform odd-size images perfectly. Use + .B \-trim +-if you don't like the results without it. ++or ++.B \-perfect ++if you don't like the results. + .PP + The entire image is read into memory and then written out again, even in + cases where this isn't really necessary. Expect swapping on large images, +--- jpegtran.c ++++ jpegtran.c +@@ -1,7 +1,7 @@ + /* + * jpegtran.c + * +- * Copyright (C) 1995-1997, Thomas G. Lane. ++ * Copyright (C) 1995-2001, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * +@@ -64,8 +64,10 @@ + #endif + #if TRANSFORMS_SUPPORTED + fprintf(stderr, "Switches for modifying the image:\n"); ++ fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n"); + fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n"); + fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n"); ++ fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n"); + fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n"); + fprintf(stderr, " -transpose Transpose image\n"); + fprintf(stderr, " -transverse Transverse transpose image\n"); +@@ -133,7 +135,9 @@ + copyoption = JCOPYOPT_DEFAULT; + transformoption.transform = JXFORM_NONE; + transformoption.trim = FALSE; ++ transformoption.perfect = FALSE; + transformoption.force_grayscale = FALSE; ++ transformoption.crop = FALSE; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ +@@ -160,7 +164,7 @@ + exit(EXIT_FAILURE); + #endif + +- } else if (keymatch(arg, "copy", 1)) { ++ } else if (keymatch(arg, "copy", 2)) { + /* Select which extra markers to copy. */ + if (++argn >= argc) /* advance to next argument */ + usage(); +@@ -173,6 +177,20 @@ + } else + usage(); + ++ } else if (keymatch(arg, "crop", 2)) { ++ /* Perform lossless cropping. */ ++#if TRANSFORMS_SUPPORTED ++ if (++argn >= argc) /* advance to next argument */ ++ usage(); ++ if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) { ++ fprintf(stderr, "%s: bogus -crop argument '%s'\n", ++ progname, argv[argn]); ++ exit(EXIT_FAILURE); ++ } ++#else ++ select_transform(JXFORM_NONE); /* force an error */ ++#endif ++ + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ +@@ -233,7 +251,12 @@ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + +- } else if (keymatch(arg, "progressive", 1)) { ++ } else if (keymatch(arg, "perfect", 2)) { ++ /* Fail if there is any partial edge MCUs that the transform can't ++ * handle. */ ++ transformoption.perfect = TRUE; ++ ++ } else if (keymatch(arg, "progressive", 2)) { + /* Select simple progressive mode. */ + #ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; +@@ -342,8 +365,10 @@ + jvirt_barray_ptr * src_coef_arrays; + jvirt_barray_ptr * dst_coef_arrays; + int file_index; +- FILE * input_file; +- FILE * output_file; ++ /* We assume all-in-memory processing and can therefore use only a ++ * single file pointer for sequential input and output operation. ++ */ ++ FILE * fp; + + /* On Mac, fetch a command line. */ + #ifdef USE_CCOMMAND +@@ -406,24 +431,13 @@ + + /* Open the input file. */ + if (file_index < argc) { +- if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { +- fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); ++ if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { ++ fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +- input_file = read_stdin(); +- } +- +- /* Open the output file. */ +- if (outfilename != NULL) { +- if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { +- fprintf(stderr, "%s: can't open %s\n", progname, outfilename); +- exit(EXIT_FAILURE); +- } +- } else { +- /* default output file is stdout */ +- output_file = write_stdout(); ++ fp = read_stdin(); + } + + #ifdef PROGRESS_REPORT +@@ -431,7 +445,7 @@ + #endif + + /* Specify data source for decompression */ +- jpeg_stdio_src(&srcinfo, input_file); ++ jpeg_stdio_src(&srcinfo, fp); + + /* Enable saving of extra markers that we want to copy */ + jcopy_markers_setup(&srcinfo, copyoption); +@@ -443,6 +457,15 @@ + * jpeg_read_coefficients so that memory allocation will be done right. + */ + #if TRANSFORMS_SUPPORTED ++ /* Fails right away if -perfect is given and transformation is not perfect. ++ */ ++ if (transformoption.perfect && ++ !jtransform_perfect_transform(srcinfo.image_width, srcinfo.image_height, ++ srcinfo.max_h_samp_factor * DCTSIZE, srcinfo.max_v_samp_factor * DCTSIZE, ++ transformoption.transform)) { ++ fprintf(stderr, "%s: transformation is not perfect\n", progname); ++ exit(EXIT_FAILURE); ++ } + jtransform_request_workspace(&srcinfo, &transformoption); + #endif + +@@ -463,11 +486,32 @@ + dst_coef_arrays = src_coef_arrays; + #endif + ++ /* Close input file, if we opened it. ++ * Note: we assume that jpeg_read_coefficients consumed all input ++ * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will ++ * only consume more while (! cinfo->inputctl->eoi_reached). ++ * We cannot call jpeg_finish_decompress here since we still need the ++ * virtual arrays allocated from the source object for processing. ++ */ ++ if (fp != stdin) ++ fclose(fp); ++ ++ /* Open the output file. */ ++ if (outfilename != NULL) { ++ if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { ++ fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename); ++ exit(EXIT_FAILURE); ++ } ++ } else { ++ /* default output file is stdout */ ++ fp = write_stdout(); ++ } ++ + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ +- jpeg_stdio_dest(&dstinfo, output_file); ++ jpeg_stdio_dest(&dstinfo, fp); + + /* Start compressor (note no image data is actually written here) */ + jpeg_write_coefficients(&dstinfo, dst_coef_arrays); +@@ -488,11 +532,9 @@ + (void) jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + +- /* Close files, if we opened them */ +- if (input_file != stdin) +- fclose(input_file); +- if (output_file != stdout) +- fclose(output_file); ++ /* Close output file, if we opened it */ ++ if (fp != stdout) ++ fclose(fp); + + #ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &dstinfo); +--- transupp.c ++++ transupp.c +@@ -1,7 +1,7 @@ + /* + * transupp.c + * +- * Copyright (C) 1997, Thomas G. Lane. ++ * Copyright (C) 1997-2001, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * +@@ -20,6 +20,7 @@ + #include "jinclude.h" + #include "jpeglib.h" + #include "transupp.h" /* My own external interface */ ++#include /* to declare isdigit() */ + + + #if TRANSFORMS_SUPPORTED +@@ -28,7 +29,8 @@ + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. +- * Thanks to Guido Vollbeding for the initial design and code of this feature. ++ * Thanks to Guido Vollbeding for the initial design and code of this feature, ++ * and to Ben Jackson for introducing the cropping feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the +@@ -42,6 +44,13 @@ + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * ++ * If cropping or trimming is involved, the destination arrays may be smaller ++ * than the source arrays. Note it is not possible to do horizontal flip ++ * in-place when a nonzero Y crop offset is specified, since we'd have to move ++ * data from one block row to another but the virtual array manager doesn't ++ * guarantee we can touch more than one row at a time. So in that case, ++ * we have to use a separate destination array. ++ * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the +@@ -54,20 +63,65 @@ + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. +- * 5. All the routines assume that the source and destination buffers are ++ * 5. When "crop" is in effect, the destination's dimensions will be the ++ * cropped values but the source's will be uncropped. Each transform ++ * routine is responsible for picking up source data starting at the ++ * correct X and Y offset for the crop region. (The X and Y offsets ++ * passed to the transform routines are measured in iMCU blocks of the ++ * destination.) ++ * 6. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. +- * Notes 2,3,4 boil down to this: generally we should use the destination's +- * dimensions and ignore the source's. + */ + + + LOCAL(void) +-do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, +- jvirt_barray_ptr *src_coef_arrays) +-/* Horizontal flip; done in-place, so no separate dest array is required */ ++do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, ++ jvirt_barray_ptr *src_coef_arrays, ++ jvirt_barray_ptr *dst_coef_arrays) ++/* Crop. This is only used when no rotate/flip is requested with the crop. */ ++{ ++ JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; ++ int ci, offset_y; ++ JBLOCKARRAY src_buffer, dst_buffer; ++ jpeg_component_info *compptr; ++ ++ /* We simply have to copy the right amount of data (the destination's ++ * image size) starting at the given X and Y offsets in the source. ++ */ ++ for (ci = 0; ci < dstinfo->num_components; ci++) { ++ compptr = dstinfo->comp_info + ci; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; ++ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; ++ dst_blk_y += compptr->v_samp_factor) { ++ dst_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ++ (JDIMENSION) compptr->v_samp_factor, TRUE); ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, ++ (JDIMENSION) compptr->v_samp_factor, FALSE); ++ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { ++ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, ++ dst_buffer[offset_y], ++ compptr->width_in_blocks); ++ } ++ } ++ } ++} ++ ++ ++LOCAL(void) ++do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, ++ jvirt_barray_ptr *src_coef_arrays) ++/* Horizontal flip; done in-place, so no separate dest array is required. ++ * NB: this only works when y_crop_offset is zero. ++ */ + { +- JDIMENSION MCU_cols, comp_width, blk_x, blk_y; ++ JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; +@@ -79,17 +133,19 @@ + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + 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, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { ++ /* Do the mirroring */ + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; +@@ -105,6 +161,79 @@ + *ptr2++ = -temp1; + } + } ++ if (x_crop_blocks > 0) { ++ /* Now left-justify the portion of the data to be kept. ++ * We can't use a single jcopy_block_row() call because that routine ++ * depends on memcpy(), whose behavior is unspecified for overlapping ++ * source and destination areas. Sigh. ++ */ ++ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { ++ jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, ++ buffer[offset_y] + blk_x, ++ (JDIMENSION) 1); ++ } ++ } ++ } ++ } ++ } ++} ++ ++ ++LOCAL(void) ++do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, ++ jvirt_barray_ptr *src_coef_arrays, ++ jvirt_barray_ptr *dst_coef_arrays) ++/* Horizontal flip in general cropping case */ ++{ ++ JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; ++ int ci, k, offset_y; ++ JBLOCKARRAY src_buffer, dst_buffer; ++ JBLOCKROW src_row_ptr, dst_row_ptr; ++ JCOEFPTR src_ptr, dst_ptr; ++ jpeg_component_info *compptr; ++ ++ /* Here we must output into a separate array because we can't touch ++ * different rows of a single virtual array simultaneously. Otherwise, ++ * this is essentially the same as the routine above. ++ */ ++ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ ++ for (ci = 0; ci < dstinfo->num_components; ci++) { ++ compptr = dstinfo->comp_info + ci; ++ comp_width = MCU_cols * compptr->h_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; ++ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; ++ dst_blk_y += compptr->v_samp_factor) { ++ dst_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ++ (JDIMENSION) compptr->v_samp_factor, TRUE); ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, ++ (JDIMENSION) compptr->v_samp_factor, FALSE); ++ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { ++ dst_row_ptr = dst_buffer[offset_y]; ++ src_row_ptr = src_buffer[offset_y]; ++ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Do the mirrorable blocks */ ++ dst_ptr = dst_row_ptr[dst_blk_x]; ++ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; ++ /* this unrolled loop doesn't need to know which row it's on... */ ++ for (k = 0; k < DCTSIZE2; k += 2) { ++ *dst_ptr++ = *src_ptr++; /* copy even column */ ++ *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ ++ } ++ } else { ++ /* Copy last partial block(s) verbatim */ ++ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, ++ dst_row_ptr + dst_blk_x, ++ (JDIMENSION) 1); ++ } ++ } + } + } + } +@@ -113,11 +242,13 @@ + + LOCAL(void) + do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* Vertical flip */ + { + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; +@@ -131,33 +262,38 @@ + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], +- comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, ++ comp_height - y_crop_blocks - dst_blk_y - ++ (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; ++ src_row_ptr += x_crop_blocks; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; +@@ -173,7 +309,8 @@ + } + } else { + /* Just copy row verbatim. */ +- jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], ++ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, ++ dst_buffer[offset_y], + compptr->width_in_blocks); + } + } +@@ -184,11 +321,12 @@ + + LOCAL(void) + do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* Transpose source into destination */ + { +- JDIMENSION dst_blk_x, dst_blk_y; ++ JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; +@@ -201,6 +339,8 @@ + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -210,11 +350,12 @@ + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -228,6 +369,7 @@ + + LOCAL(void) + do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* 90 degree rotation is equivalent to +@@ -237,6 +379,7 @@ + */ + { + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; +@@ -246,11 +389,13 @@ + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -259,15 +404,26 @@ + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { +- src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, +- (JDIMENSION) compptr->h_samp_factor, FALSE); ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Block is within the mirrorable area. */ ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ comp_width - x_crop_blocks - dst_blk_x - ++ (JDIMENSION) compptr->h_samp_factor, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } else { ++ /* Edge blocks are transposed but not mirrored. */ ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; +- if (dst_blk_x < comp_width) { ++ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ +- dst_ptr = dst_buffer[offset_y] +- [comp_width - dst_blk_x - offset_x - 1]; ++ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -277,7 +433,8 @@ + } + } else { + /* Edge blocks are transposed but not mirrored. */ +- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -292,6 +449,7 @@ + + LOCAL(void) + do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* 270 degree rotation is equivalent to +@@ -301,6 +459,7 @@ + */ + { + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; +@@ -310,11 +469,13 @@ + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -324,14 +485,15 @@ + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] +- [comp_height - dst_blk_y - offset_y - 1]; ++ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -341,7 +503,8 @@ + } + } else { + /* Edge blocks are transposed but not mirrored. */ +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; ++ src_ptr = src_buffer[offset_x] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -356,6 +519,7 @@ + + LOCAL(void) + do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* 180 degree rotation is equivalent to +@@ -365,89 +529,93 @@ + */ + { + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], +- comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, ++ comp_height - y_crop_blocks - dst_blk_y - ++ (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { +- if (dst_blk_y < comp_height) { ++ dst_row_ptr = dst_buffer[offset_y]; ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ +- dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; +- /* Process the blocks that can be mirrored both ways. */ +- for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { ++ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; +- for (i = 0; i < DCTSIZE; i += 2) { +- /* For even row, negate every odd column. */ +- for (j = 0; j < DCTSIZE; j += 2) { +- *dst_ptr++ = *src_ptr++; +- *dst_ptr++ = - *src_ptr++; ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Process the blocks that can be mirrored both ways. */ ++ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; ++ for (i = 0; i < DCTSIZE; i += 2) { ++ /* For even row, negate every odd column. */ ++ for (j = 0; j < DCTSIZE; j += 2) { ++ *dst_ptr++ = *src_ptr++; ++ *dst_ptr++ = - *src_ptr++; ++ } ++ /* For odd row, negate every even column. */ ++ for (j = 0; j < DCTSIZE; j += 2) { ++ *dst_ptr++ = - *src_ptr++; ++ *dst_ptr++ = *src_ptr++; ++ } + } +- /* For odd row, negate every even column. */ +- for (j = 0; j < DCTSIZE; j += 2) { +- *dst_ptr++ = - *src_ptr++; +- *dst_ptr++ = *src_ptr++; ++ } else { ++ /* Any remaining right-edge blocks are only mirrored vertically. */ ++ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; ++ for (i = 0; i < DCTSIZE; i += 2) { ++ for (j = 0; j < DCTSIZE; j++) ++ *dst_ptr++ = *src_ptr++; ++ for (j = 0; j < DCTSIZE; j++) ++ *dst_ptr++ = - *src_ptr++; + } + } + } +- /* Any remaining right-edge blocks are only mirrored vertically. */ +- for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { +- dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[dst_blk_x]; +- for (i = 0; i < DCTSIZE; i += 2) { +- for (j = 0; j < DCTSIZE; j++) +- *dst_ptr++ = *src_ptr++; +- for (j = 0; j < DCTSIZE; j++) +- *dst_ptr++ = - *src_ptr++; +- } +- } + } else { + /* Remaining rows are just mirrored horizontally. */ +- dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; +- /* Process the blocks that can be mirrored. */ +- for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { +- dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; +- for (i = 0; i < DCTSIZE2; i += 2) { +- *dst_ptr++ = *src_ptr++; +- *dst_ptr++ = - *src_ptr++; ++ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Process the blocks that can be mirrored. */ ++ dst_ptr = dst_row_ptr[dst_blk_x]; ++ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; ++ for (i = 0; i < DCTSIZE2; i += 2) { ++ *dst_ptr++ = *src_ptr++; ++ *dst_ptr++ = - *src_ptr++; ++ } ++ } else { ++ /* Any remaining right-edge blocks are only copied. */ ++ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, ++ dst_row_ptr + dst_blk_x, ++ (JDIMENSION) 1); + } + } +- /* Any remaining right-edge blocks are only copied. */ +- for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { +- dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[dst_blk_x]; +- for (i = 0; i < DCTSIZE2; i++) +- *dst_ptr++ = *src_ptr++; +- } + } + } + } +@@ -457,6 +625,7 @@ + + LOCAL(void) + do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* Transverse transpose is equivalent to +@@ -470,18 +639,21 @@ + */ + { + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -490,17 +662,26 @@ + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { +- src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, +- (JDIMENSION) compptr->h_samp_factor, FALSE); ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Block is within the mirrorable area. */ ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ comp_width - x_crop_blocks - dst_blk_x - ++ (JDIMENSION) compptr->h_samp_factor, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } else { ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { +- if (dst_blk_y < comp_height) { +- src_ptr = src_buffer[offset_x] +- [comp_height - dst_blk_y - offset_y - 1]; +- if (dst_blk_x < comp_width) { ++ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ if (y_crop_blocks + dst_blk_y < comp_height) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ +- dst_ptr = dst_buffer[offset_y] +- [comp_width - dst_blk_x - offset_x - 1]; ++ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] ++ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -516,7 +697,8 @@ + } + } else { + /* Right-edge blocks are mirrored in y only */ +- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x] ++ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -526,11 +708,10 @@ + } + } + } else { +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; +- if (dst_blk_x < comp_width) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ +- dst_ptr = dst_buffer[offset_y] +- [comp_width - dst_blk_x - offset_x - 1]; ++ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -540,7 +721,8 @@ + } + } else { + /* At lower right corner, just transpose, no mirroring */ +- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -554,8 +736,116 @@ + } + + ++/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. ++ * Returns TRUE if valid integer found, FALSE if not. ++ * *strptr is advanced over the digit string, and *result is set to its value. ++ */ ++ ++LOCAL(boolean) ++jt_read_integer (const char ** strptr, JDIMENSION * result) ++{ ++ const char * ptr = *strptr; ++ JDIMENSION val = 0; ++ ++ for (; isdigit(*ptr); ptr++) { ++ val = val * 10 + (JDIMENSION) (*ptr - '0'); ++ } ++ *result = val; ++ if (ptr == *strptr) ++ return FALSE; /* oops, no digits */ ++ *strptr = ptr; ++ return TRUE; ++} ++ ++ ++/* Parse a crop specification (written in X11 geometry style). ++ * The routine returns TRUE if the spec string is valid, FALSE if not. ++ * ++ * The crop spec string should have the format ++ * x{+-}{+-} ++ * where width, height, xoffset, and yoffset are unsigned integers. ++ * Each of the elements can be omitted to indicate a default value. ++ * (A weakness of this style is that it is not possible to omit xoffset ++ * while specifying yoffset, since they look alike.) ++ * ++ * This code is loosely based on XParseGeometry from the X11 distribution. ++ */ ++ ++GLOBAL(boolean) ++jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) ++{ ++ info->crop = FALSE; ++ info->crop_width_set = JCROP_UNSET; ++ info->crop_height_set = JCROP_UNSET; ++ info->crop_xoffset_set = JCROP_UNSET; ++ info->crop_yoffset_set = JCROP_UNSET; ++ ++ if (isdigit(*spec)) { ++ /* fetch width */ ++ if (! jt_read_integer(&spec, &info->crop_width)) ++ return FALSE; ++ info->crop_width_set = JCROP_POS; ++ } ++ if (*spec == 'x' || *spec == 'X') { ++ /* fetch height */ ++ spec++; ++ if (! jt_read_integer(&spec, &info->crop_height)) ++ return FALSE; ++ info->crop_height_set = JCROP_POS; ++ } ++ if (*spec == '+' || *spec == '-') { ++ /* fetch xoffset */ ++ info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; ++ spec++; ++ if (! jt_read_integer(&spec, &info->crop_xoffset)) ++ return FALSE; ++ } ++ if (*spec == '+' || *spec == '-') { ++ /* fetch yoffset */ ++ info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; ++ spec++; ++ if (! jt_read_integer(&spec, &info->crop_yoffset)) ++ return FALSE; ++ } ++ /* We had better have gotten to the end of the string. */ ++ if (*spec != '\0') ++ return FALSE; ++ info->crop = TRUE; ++ return TRUE; ++} ++ ++ ++/* Trim off any partial iMCUs on the indicated destination edge */ ++ ++LOCAL(void) ++trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) ++{ ++ JDIMENSION MCU_cols; ++ ++ MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE); ++ if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == ++ full_width / (info->max_h_samp_factor * DCTSIZE)) ++ info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE); ++} ++ ++LOCAL(void) ++trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) ++{ ++ JDIMENSION MCU_rows; ++ ++ MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE); ++ if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == ++ full_height / (info->max_v_samp_factor * DCTSIZE)) ++ info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE); ++} ++ ++ + /* Request any required workspace. + * ++ * This routine figures out the size that the output image will be ++ * (which implies that all the transform parameters must be set before ++ * it is called). ++ * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. +@@ -569,9 +859,13 @@ + jpeg_transform_info *info) + { + jvirt_barray_ptr *coef_arrays = NULL; ++ boolean need_workspace, transpose_it; + jpeg_component_info *compptr; +- int ci; ++ JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs; ++ JDIMENSION width_in_blocks, height_in_blocks; ++ int ci, h_samp_factor, v_samp_factor; + ++ /* Determine number of components in output image */ + if (info->force_grayscale && + srcinfo->jpeg_color_space == JCS_YCbCr && + srcinfo->num_components == 3) { +@@ -581,55 +875,181 @@ + /* Process all the components */ + info->num_components = srcinfo->num_components; + } ++ /* If there is only one output component, force the iMCU size to be 1; ++ * else use the source iMCU size. (This allows us to do the right thing ++ * when reducing color to grayscale, and also provides a handy way of ++ * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) ++ */ ++ ++ switch (info->transform) { ++ case JXFORM_TRANSPOSE: ++ case JXFORM_TRANSVERSE: ++ case JXFORM_ROT_90: ++ case JXFORM_ROT_270: ++ info->output_width = srcinfo->image_height; ++ info->output_height = srcinfo->image_width; ++ if (info->num_components == 1) { ++ info->max_h_samp_factor = 1; ++ info->max_v_samp_factor = 1; ++ } else { ++ info->max_h_samp_factor = srcinfo->max_v_samp_factor; ++ info->max_v_samp_factor = srcinfo->max_h_samp_factor; ++ } ++ break; ++ default: ++ info->output_width = srcinfo->image_width; ++ info->output_height = srcinfo->image_height; ++ if (info->num_components == 1) { ++ info->max_h_samp_factor = 1; ++ info->max_v_samp_factor = 1; ++ } else { ++ info->max_h_samp_factor = srcinfo->max_h_samp_factor; ++ info->max_v_samp_factor = srcinfo->max_v_samp_factor; ++ } ++ break; ++ } ++ ++ /* If cropping has been requested, compute the crop area's position and ++ * dimensions, ensuring that its upper left corner falls at an iMCU boundary. ++ */ ++ if (info->crop) { ++ /* Insert default values for unset crop parameters */ ++ if (info->crop_xoffset_set == JCROP_UNSET) ++ info->crop_xoffset = 0; /* default to +0 */ ++ if (info->crop_yoffset_set == JCROP_UNSET) ++ info->crop_yoffset = 0; /* default to +0 */ ++ if (info->crop_xoffset >= info->output_width || ++ info->crop_yoffset >= info->output_height) ++ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); ++ if (info->crop_width_set == JCROP_UNSET) ++ info->crop_width = info->output_width - info->crop_xoffset; ++ if (info->crop_height_set == JCROP_UNSET) ++ info->crop_height = info->output_height - info->crop_yoffset; ++ /* Ensure parameters are valid */ ++ if (info->crop_width <= 0 || info->crop_width > info->output_width || ++ info->crop_height <= 0 || info->crop_height > info->output_height || ++ info->crop_xoffset > info->output_width - info->crop_width || ++ info->crop_yoffset > info->output_height - info->crop_height) ++ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); ++ /* Convert negative crop offsets into regular offsets */ ++ if (info->crop_xoffset_set == JCROP_NEG) ++ xoffset = info->output_width - info->crop_width - info->crop_xoffset; ++ else ++ xoffset = info->crop_xoffset; ++ if (info->crop_yoffset_set == JCROP_NEG) ++ yoffset = info->output_height - info->crop_height - info->crop_yoffset; ++ else ++ yoffset = info->crop_yoffset; ++ /* Now adjust so that upper left corner falls at an iMCU boundary */ ++ info->output_width = ++ info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE)); ++ info->output_height = ++ info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE)); ++ /* Save x/y offsets measured in iMCUs */ ++ info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE); ++ info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE); ++ } else { ++ info->x_crop_offset = 0; ++ info->y_crop_offset = 0; ++ } + ++ /* Figure out whether we need workspace arrays, ++ * and if so whether they are transposed relative to the source. ++ */ ++ need_workspace = FALSE; ++ transpose_it = FALSE; + switch (info->transform) { + case JXFORM_NONE: ++ if (info->x_crop_offset != 0 || info->y_crop_offset != 0) ++ need_workspace = TRUE; ++ /* No workspace needed if neither cropping nor transforming */ ++ break; + case JXFORM_FLIP_H: +- /* Don't need a workspace array */ ++ if (info->trim) ++ trim_right_edge(info, srcinfo->image_width); ++ if (info->y_crop_offset != 0) ++ need_workspace = TRUE; ++ /* do_flip_h_no_crop doesn't need a workspace array */ + break; + case JXFORM_FLIP_V: +- case JXFORM_ROT_180: +- /* Need workspace arrays having same dimensions as source image. +- * Note that we allocate arrays padded out to the next iMCU boundary, +- * so that transform routines need not worry about missing edge blocks. +- */ +- coef_arrays = (jvirt_barray_ptr *) +- (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, +- SIZEOF(jvirt_barray_ptr) * info->num_components); +- for (ci = 0; ci < info->num_components; ci++) { +- compptr = srcinfo->comp_info + ci; +- coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) +- ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, +- (JDIMENSION) jround_up((long) compptr->width_in_blocks, +- (long) compptr->h_samp_factor), +- (JDIMENSION) jround_up((long) compptr->height_in_blocks, +- (long) compptr->v_samp_factor), +- (JDIMENSION) compptr->v_samp_factor); +- } ++ if (info->trim) ++ trim_bottom_edge(info, srcinfo->image_height); ++ /* Need workspace arrays having same dimensions as source image. */ ++ need_workspace = TRUE; + break; + case JXFORM_TRANSPOSE: ++ /* transpose does NOT have to trim anything */ ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; + case JXFORM_TRANSVERSE: ++ if (info->trim) { ++ trim_right_edge(info, srcinfo->image_height); ++ trim_bottom_edge(info, srcinfo->image_width); ++ } ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; + case JXFORM_ROT_90: ++ if (info->trim) ++ trim_right_edge(info, srcinfo->image_height); ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; ++ case JXFORM_ROT_180: ++ if (info->trim) { ++ trim_right_edge(info, srcinfo->image_width); ++ trim_bottom_edge(info, srcinfo->image_height); ++ } ++ /* Need workspace arrays having same dimensions as source image. */ ++ need_workspace = TRUE; ++ break; + case JXFORM_ROT_270: +- /* Need workspace arrays having transposed dimensions. +- * Note that we allocate arrays padded out to the next iMCU boundary, +- * so that transform routines need not worry about missing edge blocks. +- */ ++ if (info->trim) ++ trim_bottom_edge(info, srcinfo->image_width); ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; ++ } ++ ++ /* Allocate workspace if needed. ++ * Note that we allocate arrays padded out to the next iMCU boundary, ++ * so that transform routines need not worry about missing edge blocks. ++ */ ++ if (need_workspace) { + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, +- SIZEOF(jvirt_barray_ptr) * info->num_components); ++ SIZEOF(jvirt_barray_ptr) * info->num_components); ++ width_in_iMCUs = (JDIMENSION) ++ jdiv_round_up((long) info->output_width, ++ (long) (info->max_h_samp_factor * DCTSIZE)); ++ height_in_iMCUs = (JDIMENSION) ++ jdiv_round_up((long) info->output_height, ++ (long) (info->max_v_samp_factor * DCTSIZE)); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; ++ if (info->num_components == 1) { ++ /* we're going to force samp factors to 1x1 in this case */ ++ h_samp_factor = v_samp_factor = 1; ++ } else if (transpose_it) { ++ h_samp_factor = compptr->v_samp_factor; ++ v_samp_factor = compptr->h_samp_factor; ++ } else { ++ h_samp_factor = compptr->h_samp_factor; ++ v_samp_factor = compptr->v_samp_factor; ++ } ++ width_in_blocks = width_in_iMCUs * h_samp_factor; ++ height_in_blocks = height_in_iMCUs * v_samp_factor; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, +- (JDIMENSION) jround_up((long) compptr->height_in_blocks, +- (long) compptr->v_samp_factor), +- (JDIMENSION) jround_up((long) compptr->width_in_blocks, +- (long) compptr->h_samp_factor), +- (JDIMENSION) compptr->h_samp_factor); ++ width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); + } +- break; + } ++ + info->workspace_coef_arrays = coef_arrays; + } + +@@ -642,14 +1062,8 @@ + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; +- JDIMENSION dtemp; + UINT16 qtemp; + +- /* Transpose basic image dimensions */ +- dtemp = dstinfo->image_width; +- dstinfo->image_width = dstinfo->image_height; +- dstinfo->image_height = dtemp; +- + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; +@@ -674,46 +1088,159 @@ + } + + +-/* Trim off any partial iMCUs on the indicated destination edge */ ++/* Adjust Exif image parameters. ++ * ++ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. ++ */ + + LOCAL(void) +-trim_right_edge (j_compress_ptr dstinfo) ++adjust_exif_parameters (JOCTET FAR * data, unsigned int length, ++ JDIMENSION new_width, JDIMENSION new_height) + { +- int ci, max_h_samp_factor; +- JDIMENSION MCU_cols; ++ boolean is_motorola; /* Flag for byte order */ ++ unsigned int number_of_tags, tagnum; ++ unsigned int firstoffset, offset; ++ JDIMENSION new_value; ++ ++ if (length < 12) return; /* Length of an IFD entry */ ++ ++ /* Discover byte order */ ++ if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) ++ is_motorola = FALSE; ++ else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) ++ is_motorola = TRUE; ++ else ++ return; ++ ++ /* Check Tag Mark */ ++ if (is_motorola) { ++ if (GETJOCTET(data[2]) != 0) return; ++ if (GETJOCTET(data[3]) != 0x2A) return; ++ } else { ++ if (GETJOCTET(data[3]) != 0) return; ++ if (GETJOCTET(data[2]) != 0x2A) return; ++ } + +- /* We have to compute max_h_samp_factor ourselves, +- * because it hasn't been set yet in the destination +- * (and we don't want to use the source's value). +- */ +- max_h_samp_factor = 1; +- for (ci = 0; ci < dstinfo->num_components; ci++) { +- int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; +- max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); ++ /* Get first IFD offset (offset to IFD0) */ ++ if (is_motorola) { ++ if (GETJOCTET(data[4]) != 0) return; ++ if (GETJOCTET(data[5]) != 0) return; ++ firstoffset = GETJOCTET(data[6]); ++ firstoffset <<= 8; ++ firstoffset += GETJOCTET(data[7]); ++ } else { ++ if (GETJOCTET(data[7]) != 0) return; ++ if (GETJOCTET(data[6]) != 0) return; ++ firstoffset = GETJOCTET(data[5]); ++ firstoffset <<= 8; ++ firstoffset += GETJOCTET(data[4]); + } +- MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); +- if (MCU_cols > 0) /* can't trim to 0 pixels */ +- dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); +-} ++ if (firstoffset > length - 2) return; /* check end of data segment */ + +-LOCAL(void) +-trim_bottom_edge (j_compress_ptr dstinfo) +-{ +- int ci, max_v_samp_factor; +- JDIMENSION MCU_rows; ++ /* Get the number of directory entries contained in this IFD */ ++ if (is_motorola) { ++ number_of_tags = GETJOCTET(data[firstoffset]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[firstoffset+1]); ++ } else { ++ number_of_tags = GETJOCTET(data[firstoffset+1]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[firstoffset]); ++ } ++ if (number_of_tags == 0) return; ++ firstoffset += 2; + +- /* We have to compute max_v_samp_factor ourselves, +- * because it hasn't been set yet in the destination +- * (and we don't want to use the source's value). +- */ +- max_v_samp_factor = 1; +- for (ci = 0; ci < dstinfo->num_components; ci++) { +- int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; +- max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); ++ /* Search for ExifSubIFD offset Tag in IFD0 */ ++ for (;;) { ++ if (firstoffset > length - 12) return; /* check end of data segment */ ++ /* Get Tag number */ ++ if (is_motorola) { ++ tagnum = GETJOCTET(data[firstoffset]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[firstoffset+1]); ++ } else { ++ tagnum = GETJOCTET(data[firstoffset+1]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[firstoffset]); ++ } ++ if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ ++ if (--number_of_tags == 0) return; ++ firstoffset += 12; + } +- MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); +- if (MCU_rows > 0) /* can't trim to 0 pixels */ +- dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); ++ ++ /* Get the ExifSubIFD offset */ ++ if (is_motorola) { ++ if (GETJOCTET(data[firstoffset+8]) != 0) return; ++ if (GETJOCTET(data[firstoffset+9]) != 0) return; ++ offset = GETJOCTET(data[firstoffset+10]); ++ offset <<= 8; ++ offset += GETJOCTET(data[firstoffset+11]); ++ } else { ++ if (GETJOCTET(data[firstoffset+11]) != 0) return; ++ if (GETJOCTET(data[firstoffset+10]) != 0) return; ++ offset = GETJOCTET(data[firstoffset+9]); ++ offset <<= 8; ++ offset += GETJOCTET(data[firstoffset+8]); ++ } ++ if (offset > length - 2) return; /* check end of data segment */ ++ ++ /* Get the number of directory entries contained in this SubIFD */ ++ if (is_motorola) { ++ number_of_tags = GETJOCTET(data[offset]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[offset+1]); ++ } else { ++ number_of_tags = GETJOCTET(data[offset+1]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[offset]); ++ } ++ if (number_of_tags < 2) return; ++ offset += 2; ++ ++ /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ ++ do { ++ if (offset > length - 12) return; /* check end of data segment */ ++ /* Get Tag number */ ++ if (is_motorola) { ++ tagnum = GETJOCTET(data[offset]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[offset+1]); ++ } else { ++ tagnum = GETJOCTET(data[offset+1]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[offset]); ++ } ++ if (tagnum == 0xA002 || tagnum == 0xA003) { ++ if (tagnum == 0xA002) ++ new_value = new_width; /* ExifImageWidth Tag */ ++ else ++ new_value = new_height; /* ExifImageHeight Tag */ ++ if (is_motorola) { ++ data[offset+2] = 0; /* Format = unsigned long (4 octets) */ ++ data[offset+3] = 4; ++ data[offset+4] = 0; /* Number Of Components = 1 */ ++ data[offset+5] = 0; ++ data[offset+6] = 0; ++ data[offset+7] = 1; ++ data[offset+8] = 0; ++ data[offset+9] = 0; ++ data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); ++ data[offset+11] = (JOCTET)(new_value & 0xFF); ++ } else { ++ data[offset+2] = 4; /* Format = unsigned long (4 octets) */ ++ data[offset+3] = 0; ++ data[offset+4] = 1; /* Number Of Components = 1 */ ++ data[offset+5] = 0; ++ data[offset+6] = 0; ++ data[offset+7] = 0; ++ data[offset+8] = (JOCTET)(new_value & 0xFF); ++ data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); ++ data[offset+10] = 0; ++ data[offset+11] = 0; ++ } ++ } ++ offset += 12; ++ } while (--number_of_tags); + } + + +@@ -736,18 +1263,22 @@ + { + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { +- /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed +- * properly. Among other things, the target h_samp_factor & v_samp_factor +- * will get set to 1, which typically won't match the source. +- * In fact we do this even if the source is already grayscale; that +- * provides an easy way of coercing a grayscale JPEG with funny sampling +- * factors to the customary 1,1. (Some decoders fail on other factors.) ++ /* First, ensure we have YCbCr or grayscale data, and that the source's ++ * Y channel is full resolution. (No reasonable person would make Y ++ * be less than full resolution, so actually coping with that case ++ * isn't worth extra code space. But we check it to avoid crashing.) + */ +- if ((dstinfo->jpeg_color_space == JCS_YCbCr && +- dstinfo->num_components == 3) || +- (dstinfo->jpeg_color_space == JCS_GRAYSCALE && +- dstinfo->num_components == 1)) { +- /* We have to preserve the source's quantization table number. */ ++ if (((dstinfo->jpeg_color_space == JCS_YCbCr && ++ dstinfo->num_components == 3) || ++ (dstinfo->jpeg_color_space == JCS_GRAYSCALE && ++ dstinfo->num_components == 1)) && ++ srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && ++ srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { ++ /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed ++ * properly. Among other things, it sets the target h_samp_factor & ++ * v_samp_factor to 1, which typically won't match the source. ++ * We have to preserve the source's quantization table number, however. ++ */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; +@@ -755,50 +1286,52 @@ + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } ++ } else if (info->num_components == 1) { ++ /* For a single-component source, we force the destination sampling factors ++ * to 1x1, with or without force_grayscale. This is useful because some ++ * decoders choke on grayscale images with other sampling factors. ++ */ ++ dstinfo->comp_info[0].h_samp_factor = 1; ++ dstinfo->comp_info[0].v_samp_factor = 1; + } + +- /* Correct the destination's image dimensions etc if necessary */ ++ /* Correct the destination's image dimensions as necessary ++ * for crop and rotate/flip operations. ++ */ ++ dstinfo->image_width = info->output_width; ++ dstinfo->image_height = info->output_height; ++ ++ /* Transpose destination image parameters */ + switch (info->transform) { +- case JXFORM_NONE: +- /* Nothing to do */ +- break; +- case JXFORM_FLIP_H: +- if (info->trim) +- trim_right_edge(dstinfo); +- break; +- case JXFORM_FLIP_V: +- if (info->trim) +- trim_bottom_edge(dstinfo); +- break; + case JXFORM_TRANSPOSE: +- transpose_critical_parameters(dstinfo); +- /* transpose does NOT have to trim anything */ +- break; + case JXFORM_TRANSVERSE: +- transpose_critical_parameters(dstinfo); +- if (info->trim) { +- trim_right_edge(dstinfo); +- trim_bottom_edge(dstinfo); +- } +- break; + case JXFORM_ROT_90: +- transpose_critical_parameters(dstinfo); +- if (info->trim) +- trim_right_edge(dstinfo); +- break; +- case JXFORM_ROT_180: +- if (info->trim) { +- trim_right_edge(dstinfo); +- trim_bottom_edge(dstinfo); +- } +- break; + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); +- if (info->trim) +- trim_bottom_edge(dstinfo); + break; + } + ++ /* Adjust Exif properties */ ++ if (srcinfo->marker_list != NULL && ++ srcinfo->marker_list->marker == JPEG_APP0+1 && ++ srcinfo->marker_list->data_length >= 6 && ++ GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && ++ GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && ++ GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && ++ GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && ++ GETJOCTET(srcinfo->marker_list->data[4]) == 0 && ++ GETJOCTET(srcinfo->marker_list->data[5]) == 0) { ++ /* Suppress output of JFIF marker */ ++ dstinfo->write_JFIF_header = FALSE; ++ /* Adjust Exif image parameters */ ++ if (dstinfo->image_width != srcinfo->image_width || ++ dstinfo->image_height != srcinfo->image_height) ++ /* Align data segment to start of TIFF structure for parsing */ ++ adjust_exif_parameters(srcinfo->marker_list->data + 6, ++ srcinfo->marker_list->data_length - 6, ++ dstinfo->image_width, dstinfo->image_height); ++ } ++ + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; +@@ -816,40 +1349,108 @@ + */ + + GLOBAL(void) +-jtransform_execute_transformation (j_decompress_ptr srcinfo, +- j_compress_ptr dstinfo, +- jvirt_barray_ptr *src_coef_arrays, +- jpeg_transform_info *info) ++jtransform_execute_transform (j_decompress_ptr srcinfo, ++ j_compress_ptr dstinfo, ++ jvirt_barray_ptr *src_coef_arrays, ++ jpeg_transform_info *info) + { + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + ++ /* Note: conditions tested here should match those in switch statement ++ * in jtransform_request_workspace() ++ */ + switch (info->transform) { + case JXFORM_NONE: ++ if (info->x_crop_offset != 0 || info->y_crop_offset != 0) ++ do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_FLIP_H: +- do_flip_h(srcinfo, dstinfo, src_coef_arrays); ++ if (info->y_crop_offset != 0) ++ do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); ++ else ++ do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, ++ src_coef_arrays); + break; + case JXFORM_FLIP_V: +- do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: +- do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: +- do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: +- do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: +- do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: +- do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + } + } + ++/* jtransform_perfect_transform ++ * ++ * Determine whether lossless transformation is perfectly ++ * possible for a specified image and transformation. ++ * ++ * Inputs: ++ * image_width, image_height: source image dimensions. ++ * MCU_width, MCU_height: pixel dimensions of MCU. ++ * transform: transformation identifier. ++ * Parameter sources from initialized jpeg_struct ++ * (after reading source header): ++ * image_width = cinfo.image_width ++ * image_height = cinfo.image_height ++ * MCU_width = cinfo.max_h_samp_factor * DCTSIZE ++ * MCU_height = cinfo.max_v_samp_factor * DCTSIZE ++ * Result: ++ * TRUE = perfect transformation possible ++ * FALSE = perfect transformation not possible ++ * (may use custom action then) ++ */ ++ ++GLOBAL(boolean) ++jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, ++ int MCU_width, int MCU_height, ++ JXFORM_CODE transform) ++{ ++ boolean result = TRUE; /* initialize TRUE */ ++ ++ switch (transform) { ++ case JXFORM_FLIP_H: ++ case JXFORM_ROT_270: ++ if (image_width % (JDIMENSION) MCU_width) ++ result = FALSE; ++ break; ++ case JXFORM_FLIP_V: ++ case JXFORM_ROT_90: ++ if (image_height % (JDIMENSION) MCU_height) ++ result = FALSE; ++ break; ++ case JXFORM_TRANSVERSE: ++ case JXFORM_ROT_180: ++ if (image_width % (JDIMENSION) MCU_width) ++ result = FALSE; ++ if (image_height % (JDIMENSION) MCU_height) ++ result = FALSE; ++ break; ++ } ++ ++ return result; ++} ++ + #endif /* TRANSFORMS_SUPPORTED */ + + +--- transupp.h ++++ transupp.h +@@ -1,7 +1,7 @@ + /* + * transupp.h + * +- * Copyright (C) 1997, Thomas G. Lane. ++ * Copyright (C) 1997-2001, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * +@@ -22,32 +22,6 @@ + #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ + #endif + +-/* Short forms of external names for systems with brain-damaged linkers. */ +- +-#ifdef NEED_SHORT_EXTERNAL_NAMES +-#define jtransform_request_workspace jTrRequest +-#define jtransform_adjust_parameters jTrAdjust +-#define jtransform_execute_transformation jTrExec +-#define jcopy_markers_setup jCMrkSetup +-#define jcopy_markers_execute jCMrkExec +-#endif /* NEED_SHORT_EXTERNAL_NAMES */ +- +- +-/* +- * Codes for supported types of image transformations. +- */ +- +-typedef enum { +- JXFORM_NONE, /* no transformation */ +- JXFORM_FLIP_H, /* horizontal flip */ +- JXFORM_FLIP_V, /* vertical flip */ +- JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ +- JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ +- JXFORM_ROT_90, /* 90-degree clockwise rotation */ +- JXFORM_ROT_180, /* 180-degree rotation */ +- JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +-} JXFORM_CODE; +- + /* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images +@@ -75,6 +49,19 @@ + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * ++ * We also offer a lossless-crop option, which discards data outside a given ++ * image region but losslessly preserves what is inside. Like the rotate and ++ * flip transforms, lossless crop is restricted by the JPEG format: the upper ++ * left corner of the selected region must fall on an iMCU boundary. If this ++ * does not hold for the given crop parameters, we silently move the upper left ++ * corner up and/or left to make it so, simultaneously increasing the region ++ * dimensions to keep the lower right crop corner unchanged. (Thus, the ++ * output image covers at least the requested region, but may cover more.) ++ * ++ * If both crop and a rotate/flip transform are requested, the crop is applied ++ * last --- that is, the crop region is specified in terms of the destination ++ * image. ++ * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of +@@ -83,20 +70,89 @@ + * be aware of the option to know how many components to work on. + */ + ++ ++/* Short forms of external names for systems with brain-damaged linkers. */ ++ ++#ifdef NEED_SHORT_EXTERNAL_NAMES ++#define jtransform_parse_crop_spec jTrParCrop ++#define jtransform_request_workspace jTrRequest ++#define jtransform_adjust_parameters jTrAdjust ++#define jtransform_execute_transform jTrExec ++#define jtransform_perfect_transform jTrPerfect ++#define jcopy_markers_setup jCMrkSetup ++#define jcopy_markers_execute jCMrkExec ++#endif /* NEED_SHORT_EXTERNAL_NAMES */ ++ ++ ++/* ++ * Codes for supported types of image transformations. ++ */ ++ ++typedef enum { ++ JXFORM_NONE, /* no transformation */ ++ JXFORM_FLIP_H, /* horizontal flip */ ++ JXFORM_FLIP_V, /* vertical flip */ ++ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ ++ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ ++ JXFORM_ROT_90, /* 90-degree clockwise rotation */ ++ JXFORM_ROT_180, /* 180-degree rotation */ ++ JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ ++} JXFORM_CODE; ++ ++/* ++ * Codes for crop parameters, which can individually be unspecified, ++ * positive, or negative. (Negative width or height makes no sense, though.) ++ */ ++ ++typedef enum { ++ JCROP_UNSET, ++ JCROP_POS, ++ JCROP_NEG ++} JCROP_CODE; ++ ++/* ++ * Transform parameters struct. ++ * NB: application must not change any elements of this struct after ++ * calling jtransform_request_workspace. ++ */ ++ + typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ ++ boolean perfect; /* if TRUE, fail if partial MCUs are requested */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ ++ boolean crop; /* if TRUE, crop source image */ ++ ++ /* Crop parameters: application need not set these unless crop is TRUE. ++ * These can be filled in by jtransform_parse_crop_spec(). ++ */ ++ JDIMENSION crop_width; /* Width of selected region */ ++ JCROP_CODE crop_width_set; ++ JDIMENSION crop_height; /* Height of selected region */ ++ JCROP_CODE crop_height_set; ++ JDIMENSION crop_xoffset; /* X offset of selected region */ ++ JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ ++ JDIMENSION crop_yoffset; /* Y offset of selected region */ ++ JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ ++ JDIMENSION output_width; /* cropped destination dimensions */ ++ JDIMENSION output_height; ++ JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ ++ JDIMENSION y_crop_offset; ++ int max_h_samp_factor; /* destination iMCU size */ ++ int max_v_samp_factor; + } jpeg_transform_info; + + + #if TRANSFORMS_SUPPORTED + ++/* Parse a crop specification (written in X11 geometry style) */ ++EXTERN(boolean) jtransform_parse_crop_spec ++ JPP((jpeg_transform_info *info, const char *spec)); + /* Request any required workspace */ + EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +@@ -106,10 +162,24 @@ + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + /* Execute the actual transformation, if any */ +-EXTERN(void) jtransform_execute_transformation ++EXTERN(void) jtransform_execute_transform + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); ++/* Determine whether lossless transformation is perfectly ++ * possible for a specified image and transformation. ++ */ ++EXTERN(boolean) jtransform_perfect_transform ++ JPP((JDIMENSION image_width, JDIMENSION image_height, ++ int MCU_width, int MCU_height, ++ JXFORM_CODE transform)); ++ ++/* jtransform_execute_transform used to be called ++ * jtransform_execute_transformation, but some compilers complain about ++ * routine names that long. This macro is here to avoid breaking any ++ * old source code that uses the original name... ++ */ ++#define jtransform_execute_transformation jtransform_execute_transform + + #endif /* TRANSFORMS_SUPPORTED */ + diff --git a/libjpeg-turbo-1.0.1-rh639672.patch b/libjpeg-turbo-1.0.1-rh639672.patch new file mode 100644 index 0000000..0081a7d --- /dev/null +++ b/libjpeg-turbo-1.0.1-rh639672.patch @@ -0,0 +1,1283 @@ +From 195345e454d3df7ff9c07c3d36881ec52e789af2 Mon Sep 17 00:00:00 2001 +From: Mukund Sivaraman +Date: Sun, 3 Oct 2010 12:23:41 +0530 +Subject: [PATCH] Add support for decoding arithmetic coded content + +This is based on a patch by Guido Vollbeding , which +included code to both encode and decode arithmetic coded content. + +This patch only adds the decoding portion. No new arithmetic coded +content can be produced, but existing arithmetic coded content can +be decoded. + +libjpeg-turbo with this patch has been tested with some arithmetic +coded images (digital photographs). +--- + Makefile.am | 17 +- + README.arithmetic | 215 +++++++++++++++ + jaricom.c | 149 +++++++++++ + jdarith.c | 762 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + jdmaster.c | 2 +- + jdtrans.c | 2 +- + jerror.h | 2 + + jmorecfg.h | 2 +- + jpegint.h | 2 + + 9 files changed, 1142 insertions(+), 11 deletions(-) + create mode 100644 README.arithmetic + create mode 100644 jaricom.c + create mode 100644 jdarith.c + +diff --git a/Makefile.am b/Makefile.am +index f8552ea..1eee598 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -7,14 +7,15 @@ nodist_include_HEADERS = jconfig.h + HDRS = jchuff.h jdct.h jdhuff.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h jsimd.h jsimddct.h + +-libjpeg_la_SOURCES = $(HDRS) jcapimin.c jcapistd.c jccoefct.c jccolor.c \ +- jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \ +- jcomapi.c jcparam.c jcphuff.c jcprepct.c jcsample.c jctrans.c \ +- jdapimin.c jdapistd.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \ +- jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \ +- jdmerge.c jdphuff.c jdpostct.c jdsample.c jdtrans.c jerror.c \ +- jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c \ +- jidctred.c jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c ++libjpeg_la_SOURCES = $(HDRS) jaricom.c jcapimin.c jcapistd.c \ ++ jccoefct.c jccolor.c jcdctmgr.c jchuff.c jcinit.c jcmainct.c \ ++ jcmarker.c jcmaster.c jcomapi.c jcparam.c jcphuff.c jcprepct.c \ ++ jcsample.c jctrans.c jdapimin.c jdapistd.c jdarith.c \ ++ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ ++ jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ ++ jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ ++ jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c \ ++ jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c + + libturbojpeg_la_SOURCES = $(libjpeg_la_SOURCES) turbojpegl.c turbojpeg.h \ + turbojpeg-mapfile +diff --git a/README.arithmetic b/README.arithmetic +new file mode 100644 +index 0000000..0dd3b9a +--- /dev/null ++++ b/README.arithmetic +@@ -0,0 +1,215 @@ ++JPEG arithmetic encoding and decoding portable software implementation ++====================================================================== ++ ++Release of 28-Mar-98 by Guido Vollbeding ++============================================================= ++ ++Primary URLs: ++ ++ http://sylvana.net/jpeg-ari/ ++ (directory containing the actual archive files:) ++ ++ http://sylvana.net/jpeg-ari/jpeg-ari-28mar98.tar.gz ++ ++ http://sylvana.net/jpeg-ari/jpeg-ari.zip ++ ++ ++DISCLAIMER ++========== ++ ++This package is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++It is possible that certain products which can be built using this ++software modules might form inventions protected by patent rights in ++some countries (e.g. by patents about arithmetic coding algorithms ++owned by IBM and AT&T in the USA). Provision of this software by the ++author does NOT include any licenses for any patents. ++In those countries where a patent license is required for certain ++applications of this software modules, you will have to obtain such ++a license yourself. ++ ++See Annex L in the JPEG spec for further information ++and a list of relevant patents. ++ ++ ++What is it? ++=========== ++ ++This is my implementation of the arithmetic encoding and decoding ++back-end for JPEG as specified in the ++ ++ ISO/IEC International Standard 10918-1 and CCITT Recommendation ++ ITU-T T.81, "Information Technology - Digital Compression and ++ Coding of Continuous-tone Still Images, Part 1: Requirements ++ and Guidelines". ++ ++Arithmetic coding is a state-of-the-art lossless entropy data ++compression method which offers better compression performance ++than the well-established Huffman entropy coding process. ++ ++The JPEG standard specifies a particular arithmetic coding scheme ++to be used optionally as alternative to Huffman coding. ++ ++ ++Who needs it? ++============= ++ ++This package might be of interest for people who are looking for ++enhanced state-of-the-art image compression technologies. ++ ++It is intended to provide a reasonable tool for experimental, ++comparison and evaluation purposes. ++ ++See the Disclaimer above for restricted conditions of usage. ++ ++ ++How does it work? ++================= ++ ++This distribution is organized as add-on to the widespread ++Independent JPEG Group's JPEG software. ++ ++Thus, once you managed to install the IJG software distribution ++successfully, there should be no additional problems (portability ++issues etc.) to incorporate this package into the library, ++and usage is straightforward. ++ ++Transcode given JPEG files simply with a command like ++ ++ jpegtran -arithmetic [-progressive] < orig.jpg > arit.jpg ++ ++into an arithmetic coded version LOSSLESSLY! Since there are ++practically no applications in existence which can handle such ++files, you can only transform it back with the same tool ++ ++ jpegtran [-optimize] [-progressive] < arit.jpg > orig2.jpg ++ ++to verify correct operation. ++ ++Thus, you can easily verify the enhanced compression performance ++of the arithmetic coding version compared to the Huffman (with ++fixed or custom tables) version. ++ ++The claim to evaluate was that arithmetic coding gives an average ++5-10% compression improvement against Huffman. ++Early tests with this implementation support this claim, and you ++can perform tests with own material. ++ ++Here are some actual results: ++ ++% ./jpegtran -optimize < testorig.jpg > testopt.jpg ++% ./jpegtran -arithmetic < testorig.jpg > testarit.jpg ++% ./jpegtran < testarit.jpg > testorig2.jpg ++% ./jpegtran -arithmetic -progressive < testorig.jpg > testaritp.jpg ++% ./jpegtran < testaritp.jpg > testorig3.jpg ++% ./jpegtran -optimize < ../butterfly.jpg > ../buttopt.jpg ++% ./jpegtran -progressive < ../butterfly.jpg > ../buttprog.jpg ++% ./jpegtran -arithmetic < ../butterfly.jpg > ../buttarit.jpg ++% ./jpegtran < ../buttarit.jpg > ../butterfly2.jpg ++% ./jpegtran -arithmetic -progressive < ../butterfly.jpg > ../buttaritp.jpg ++% ./jpegtran < ../buttaritp.jpg > ../butterfly3.jpg ++% ls -l test*.jpg ++-rw-r--r-- 1 guivol 5153 Apr 13 18:51 testarit.jpg ++-rw-r--r-- 1 guivol 5186 Apr 13 18:51 testaritp.jpg ++-rw-r--r-- 1 guivol 5756 Apr 2 15:10 testimg.jpg ++-rw-r--r-- 1 guivol 5645 Apr 2 15:10 testimgp.jpg ++-rw-r--r-- 1 guivol 5463 Apr 13 18:51 testopt.jpg ++-rw-r--r-- 1 guivol 5770 Apr 2 15:10 testorig.jpg ++-rw-r--r-- 1 guivol 5770 Apr 13 18:51 testorig2.jpg ++-rw-r--r-- 1 guivol 5770 Apr 13 18:51 testorig3.jpg ++-rw-r--r-- 1 guivol 5655 Apr 2 15:10 testprog.jpg ++% ls -l ../butt*.jpg ++-rw-r--r-- 1 guivol 460091 Apr 13 18:52 ../buttarit.jpg ++-rw-r--r-- 1 guivol 453703 Apr 13 18:52 ../buttaritp.jpg ++-rw-r--r-- 1 guivol 527823 Nov 19 18:41 ../butterfly.jpg ++-rw-r--r-- 1 guivol 527823 Apr 13 18:52 ../butterfly2.jpg ++-rw-r--r-- 1 guivol 527823 Apr 13 18:52 ../butterfly3.jpg ++-rw-r--r-- 1 guivol 511834 Apr 13 18:52 ../buttopt.jpg ++-rw-r--r-- 1 guivol 492237 Apr 13 18:52 ../buttprog.jpg ++% ++ ++Note that arithmetic coding requires only a single processing ++pass due to its fully-adaptive nature, and compared to one-pass ++(fixed tables) Huffman the arithmetic coded version consistently ++achieves 10% compression improvement. ++Compared with two-pass (custom tables) Huffman the improvement ++is 5-10%. ++ ++Note that I wasn't able yet to cross-check interoperability of ++the produced files with other implementations. ++Thus, I can't be sure that the files are compliant to the spec, ++but I hope so and the tests support it. ++The encoding and decoding processes should be correct anyway, ++however, in the sense that they are complementary to each other ++and thus retain data integrity. ++ ++I would appreciate any indications for compliance or interoperability ++with other implementations from somebody. ++Please let me know if you are able to cross-check something. ++ ++ ++Installation ++============ ++ ++The installation is a 2-stage procedure: ++ ++1. Preparing the IJG package for potential incorporation ++ of the arithmetic coding feature. ++ ++2. Incorporation of the actual arithmetic coding modules ++ and enabling the feature for usage. ++ ++The reason for this 2-stage process is the hope to make ++step 1 obsolete in future IJG releases. ++The actual implementation should remain separate IMHO due ++to the different usage conditions. ++ ++Step 1: ++ ++1.1. Copy all files from the subdirectory 'patchv6b' into ++ the IJG software's v6b source directory. ++ This includes minor patches to some files and 3 extra ++ files which hold place for the actual implementation. ++ ++1.2. Update your Makefile/Projectfile for the inclusion of ++ the 3 extra files. This will be done automatically ++ if you use a configure-generated makefile and type ++ './configure' (reconfigure). ++ ++1.3. Recompile ('make'). ++ ++See the file 'PATCHES' in 'patchv6b' for details. ++ ++Step 2: ++ ++2.1. Replace the 3 placeholder files by the actual implementation ++ modules. ++ ++2.2. Enable application support of the new features by #defining ++ C_ARITH_CODING_SUPPORTED and D_ARITH_CODING_SUPPORTED ++ in 'jmorecfg.h'. ++ ++2.3. Recompile ('make'). ++ ++Note that I suggest to add 3 placeholder files to the IJG ++distribution. This would remove the need for system-dependent ++changes (Makefiles) and thus considerably simplify the actual ++installation for systems without a configure-generated makefile. ++ ++ ++References ++========== ++ ++- The Independent JPEG Group's software ++ ++- JBIG-KIT lossless image compression library by Markus Kuhn ++ ++- William B. Pennebaker, Joan L. Mitchell: ++ "JPEG Still Image Data Compression Standard", ++ Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. ++ ++- jpeg-faq (http://www.faqs.org/faqs/jpeg-faq/) ++ ++- compression-faq (http://www.faqs.org/faqs/compression-faq/) +diff --git a/jaricom.c b/jaricom.c +new file mode 100644 +index 0000000..e4292b0 +--- /dev/null ++++ b/jaricom.c +@@ -0,0 +1,149 @@ ++/* ++ * jaricom.c ++ * ++ * Copyright (C) 1997, Guido Vollbeding . ++ * This file is NOT part of the Independent JPEG Group's software ++ * for legal reasons. ++ * See the accompanying README file for conditions of distribution and use. ++ * ++ * This file contains probability estimation tables for common use in ++ * arithmetic entropy encoding and decoding routines. ++ * ++ * This data represents Table D.2 in the JPEG spec (ISO/IEC IS 10918-1 ++ * and CCITT Recommendation ITU-T T.81) and Table 24 in the JBIG spec ++ * (ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82). ++ */ ++ ++#define JPEG_INTERNALS ++#include "jinclude.h" ++#include "jpeglib.h" ++ ++/* The following #define specifies the packing of the four components ++ * into the compact INT32 representation. ++ * Note that this formula must match the actual arithmetic encoder ++ * and decoder implementation. The implementation has to be changed ++ * if this formula is changed. ++ * The current organisation is leaned on Markus Kuhn's JBIG ++ * implementation (jbig_tab.c). ++ */ ++ ++#define V(a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b) ++ ++const INT32 jaritab[113] = { ++/* ++ * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS ++ */ ++/* 0 */ V( 0x5a1d, 1, 1, 1 ), ++/* 1 */ V( 0x2586, 14, 2, 0 ), ++/* 2 */ V( 0x1114, 16, 3, 0 ), ++/* 3 */ V( 0x080b, 18, 4, 0 ), ++/* 4 */ V( 0x03d8, 20, 5, 0 ), ++/* 5 */ V( 0x01da, 23, 6, 0 ), ++/* 6 */ V( 0x00e5, 25, 7, 0 ), ++/* 7 */ V( 0x006f, 28, 8, 0 ), ++/* 8 */ V( 0x0036, 30, 9, 0 ), ++/* 9 */ V( 0x001a, 33, 10, 0 ), ++/* 10 */ V( 0x000d, 35, 11, 0 ), ++/* 11 */ V( 0x0006, 9, 12, 0 ), ++/* 12 */ V( 0x0003, 10, 13, 0 ), ++/* 13 */ V( 0x0001, 12, 13, 0 ), ++/* 14 */ V( 0x5a7f, 15, 15, 1 ), ++/* 15 */ V( 0x3f25, 36, 16, 0 ), ++/* 16 */ V( 0x2cf2, 38, 17, 0 ), ++/* 17 */ V( 0x207c, 39, 18, 0 ), ++/* 18 */ V( 0x17b9, 40, 19, 0 ), ++/* 19 */ V( 0x1182, 42, 20, 0 ), ++/* 20 */ V( 0x0cef, 43, 21, 0 ), ++/* 21 */ V( 0x09a1, 45, 22, 0 ), ++/* 22 */ V( 0x072f, 46, 23, 0 ), ++/* 23 */ V( 0x055c, 48, 24, 0 ), ++/* 24 */ V( 0x0406, 49, 25, 0 ), ++/* 25 */ V( 0x0303, 51, 26, 0 ), ++/* 26 */ V( 0x0240, 52, 27, 0 ), ++/* 27 */ V( 0x01b1, 54, 28, 0 ), ++/* 28 */ V( 0x0144, 56, 29, 0 ), ++/* 29 */ V( 0x00f5, 57, 30, 0 ), ++/* 30 */ V( 0x00b7, 59, 31, 0 ), ++/* 31 */ V( 0x008a, 60, 32, 0 ), ++/* 32 */ V( 0x0068, 62, 33, 0 ), ++/* 33 */ V( 0x004e, 63, 34, 0 ), ++/* 34 */ V( 0x003b, 32, 35, 0 ), ++/* 35 */ V( 0x002c, 33, 9, 0 ), ++/* 36 */ V( 0x5ae1, 37, 37, 1 ), ++/* 37 */ V( 0x484c, 64, 38, 0 ), ++/* 38 */ V( 0x3a0d, 65, 39, 0 ), ++/* 39 */ V( 0x2ef1, 67, 40, 0 ), ++/* 40 */ V( 0x261f, 68, 41, 0 ), ++/* 41 */ V( 0x1f33, 69, 42, 0 ), ++/* 42 */ V( 0x19a8, 70, 43, 0 ), ++/* 43 */ V( 0x1518, 72, 44, 0 ), ++/* 44 */ V( 0x1177, 73, 45, 0 ), ++/* 45 */ V( 0x0e74, 74, 46, 0 ), ++/* 46 */ V( 0x0bfb, 75, 47, 0 ), ++/* 47 */ V( 0x09f8, 77, 48, 0 ), ++/* 48 */ V( 0x0861, 78, 49, 0 ), ++/* 49 */ V( 0x0706, 79, 50, 0 ), ++/* 50 */ V( 0x05cd, 48, 51, 0 ), ++/* 51 */ V( 0x04de, 50, 52, 0 ), ++/* 52 */ V( 0x040f, 50, 53, 0 ), ++/* 53 */ V( 0x0363, 51, 54, 0 ), ++/* 54 */ V( 0x02d4, 52, 55, 0 ), ++/* 55 */ V( 0x025c, 53, 56, 0 ), ++/* 56 */ V( 0x01f8, 54, 57, 0 ), ++/* 57 */ V( 0x01a4, 55, 58, 0 ), ++/* 58 */ V( 0x0160, 56, 59, 0 ), ++/* 59 */ V( 0x0125, 57, 60, 0 ), ++/* 60 */ V( 0x00f6, 58, 61, 0 ), ++/* 61 */ V( 0x00cb, 59, 62, 0 ), ++/* 62 */ V( 0x00ab, 61, 63, 0 ), ++/* 63 */ V( 0x008f, 61, 32, 0 ), ++/* 64 */ V( 0x5b12, 65, 65, 1 ), ++/* 65 */ V( 0x4d04, 80, 66, 0 ), ++/* 66 */ V( 0x412c, 81, 67, 0 ), ++/* 67 */ V( 0x37d8, 82, 68, 0 ), ++/* 68 */ V( 0x2fe8, 83, 69, 0 ), ++/* 69 */ V( 0x293c, 84, 70, 0 ), ++/* 70 */ V( 0x2379, 86, 71, 0 ), ++/* 71 */ V( 0x1edf, 87, 72, 0 ), ++/* 72 */ V( 0x1aa9, 87, 73, 0 ), ++/* 73 */ V( 0x174e, 72, 74, 0 ), ++/* 74 */ V( 0x1424, 72, 75, 0 ), ++/* 75 */ V( 0x119c, 74, 76, 0 ), ++/* 76 */ V( 0x0f6b, 74, 77, 0 ), ++/* 77 */ V( 0x0d51, 75, 78, 0 ), ++/* 78 */ V( 0x0bb6, 77, 79, 0 ), ++/* 79 */ V( 0x0a40, 77, 48, 0 ), ++/* 80 */ V( 0x5832, 80, 81, 1 ), ++/* 81 */ V( 0x4d1c, 88, 82, 0 ), ++/* 82 */ V( 0x438e, 89, 83, 0 ), ++/* 83 */ V( 0x3bdd, 90, 84, 0 ), ++/* 84 */ V( 0x34ee, 91, 85, 0 ), ++/* 85 */ V( 0x2eae, 92, 86, 0 ), ++/* 86 */ V( 0x299a, 93, 87, 0 ), ++/* 87 */ V( 0x2516, 86, 71, 0 ), ++/* 88 */ V( 0x5570, 88, 89, 1 ), ++/* 89 */ V( 0x4ca9, 95, 90, 0 ), ++/* 90 */ V( 0x44d9, 96, 91, 0 ), ++/* 91 */ V( 0x3e22, 97, 92, 0 ), ++/* 92 */ V( 0x3824, 99, 93, 0 ), ++/* 93 */ V( 0x32b4, 99, 94, 0 ), ++/* 94 */ V( 0x2e17, 93, 86, 0 ), ++/* 95 */ V( 0x56a8, 95, 96, 1 ), ++/* 96 */ V( 0x4f46, 101, 97, 0 ), ++/* 97 */ V( 0x47e5, 102, 98, 0 ), ++/* 98 */ V( 0x41cf, 103, 99, 0 ), ++/* 99 */ V( 0x3c3d, 104, 100, 0 ), ++/* 100 */ V( 0x375e, 99, 93, 0 ), ++/* 101 */ V( 0x5231, 105, 102, 0 ), ++/* 102 */ V( 0x4c0f, 106, 103, 0 ), ++/* 103 */ V( 0x4639, 107, 104, 0 ), ++/* 104 */ V( 0x415e, 103, 99, 0 ), ++/* 105 */ V( 0x5627, 105, 106, 1 ), ++/* 106 */ V( 0x50e7, 108, 107, 0 ), ++/* 107 */ V( 0x4b85, 109, 103, 0 ), ++/* 108 */ V( 0x5597, 110, 109, 0 ), ++/* 109 */ V( 0x504f, 111, 107, 0 ), ++/* 110 */ V( 0x5a10, 110, 111, 1 ), ++/* 111 */ V( 0x5522, 112, 109, 0 ), ++/* 112 */ V( 0x59eb, 112, 111, 1 ) ++}; +diff --git a/jdarith.c b/jdarith.c +new file mode 100644 +index 0000000..1ef513e +--- /dev/null ++++ b/jdarith.c +@@ -0,0 +1,762 @@ ++/* ++ * jdarith.c ++ * ++ * Copyright (C) 1997, Guido Vollbeding . ++ * This file is NOT part of the Independent JPEG Group's software ++ * for legal reasons. ++ * See the accompanying README file for conditions of distribution and use. ++ * ++ * This file contains portable arithmetic entropy decoding routines for JPEG ++ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81). ++ * ++ * Both sequential and progressive modes are supported in this single module. ++ * ++ * Suspension is not currently supported in this module. ++ */ ++ ++#define JPEG_INTERNALS ++#include "jinclude.h" ++#include "jpeglib.h" ++ ++ ++/* Expanded entropy decoder object for arithmetic decoding. */ ++ ++typedef struct { ++ struct jpeg_entropy_decoder pub; /* public fields */ ++ ++ INT32 c; /* C register, base of coding interval + input bit buffer */ ++ INT32 a; /* A register, normalized size of coding interval */ ++ int ct; /* bit shift counter, # of bits left in bit buffer part of C */ ++ /* init: ct = -16 */ ++ /* run: ct = 0..7 */ ++ /* error: ct = -1 */ ++ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ ++ int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */ ++ ++ unsigned int restarts_to_go; /* MCUs left in this restart interval */ ++ ++ /* Pointers to statistics areas (these workspaces have image lifespan) */ ++ unsigned char * dc_stats[NUM_ARITH_TBLS]; ++ unsigned char * ac_stats[NUM_ARITH_TBLS]; ++} arith_entropy_decoder; ++ ++typedef arith_entropy_decoder * arith_entropy_ptr; ++ ++/* The following two definitions specify the allocation chunk size ++ * for the statistics area. ++ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least ++ * 49 statistics bins for DC, and 245 statistics bins for AC coding. ++ * Note that we use one additional AC bin for codings with fixed ++ * probability (0.5), thus the minimum number for AC is 246. ++ * ++ * We use a compact representation with 1 byte per statistics bin, ++ * thus the numbers directly represent byte sizes. ++ * This 1 byte per statistics bin contains the meaning of the MPS ++ * (more probable symbol) in the highest bit (mask 0x80), and the ++ * index into the probability estimation state machine table ++ * in the lower bits (mask 0x7F). ++ */ ++ ++#define DC_STAT_BINS 64 ++#define AC_STAT_BINS 256 ++ ++ ++LOCAL(int) ++get_byte (j_decompress_ptr cinfo) ++/* Read next input byte; we do not support suspension in this module. */ ++{ ++ struct jpeg_source_mgr * src = cinfo->src; ++ ++ if (src->bytes_in_buffer == 0) ++ if (! (*src->fill_input_buffer) (cinfo)) ++ ERREXIT(cinfo, JERR_CANT_SUSPEND); ++ src->bytes_in_buffer--; ++ return GETJOCTET(*src->next_input_byte++); ++} ++ ++ ++/* ++ * The core arithmetic decoding routine (common in JPEG and JBIG). ++ * This needs to go as fast as possible. ++ * Machine-dependent optimization facilities ++ * are not utilized in this portable implementation. ++ * However, this code should be fairly efficient and ++ * may be a good base for further optimizations anyway. ++ * ++ * Return value is 0 or 1 (binary decision). ++ * ++ * Note: I've changed the handling of the code base & bit ++ * buffer register C compared to other implementations ++ * based on the standards layout & procedures. ++ * While it also contains both the actual base of the ++ * coding interval (16 bits) and the next-bits buffer, ++ * the cut-point between these two parts is floating ++ * (instead of fixed) with the bit shift counter CT. ++ * Thus, we also need only one (variable instead of ++ * fixed size) shift for the LPS/MPS decision, and ++ * we can get away with any renormalization update ++ * of C (except for new data insertion, of course). ++ * ++ * I've also introduced a new scheme for accessing ++ * the probability estimation state machine table, ++ * derived from Markus Kuhn's JBIG implementation. ++ */ ++ ++LOCAL(int) ++arith_decode (j_decompress_ptr cinfo, unsigned char *st) ++{ ++ extern const INT32 jaritab[]; ++ register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; ++ register unsigned char nl, nm; ++ register INT32 qe, temp; ++ register int sv, data; ++ ++ /* Renormalization & data input per section D.2.6 */ ++ while (e->a < 0x8000L) { ++ if (--e->ct < 0) { ++ /* Need to fetch next data byte */ ++ if (cinfo->unread_marker) ++ data = 0; /* stuff zero data */ ++ else { ++ data = get_byte(cinfo); /* read next input byte */ ++ if (data == 0xFF) { /* zero stuff or marker code */ ++ do data = get_byte(cinfo); ++ while (data == 0xFF); /* swallow extra 0xFF bytes */ ++ if (data == 0) ++ data = 0xFF; /* discard stuffed zero byte */ ++ else { ++ /* Note: Different from the Huffman decoder, hitting ++ * a marker while processing the compressed data ++ * segment is legal in arithmetic coding. ++ * The convention is to supply zero data ++ * then until decoding is complete. ++ */ ++ cinfo->unread_marker = data; ++ data = 0; ++ } ++ } ++ } ++ e->c = (e->c << 8) | data; /* insert data into C register */ ++ if ((e->ct += 8) < 0) /* update bit shift counter */ ++ /* Need more initial bytes */ ++ if (++e->ct == 0) ++ /* Got 2 initial bytes -> re-init A and exit loop */ ++ e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */ ++ } ++ e->a <<= 1; ++ } ++ ++ /* Fetch values from our compact representation of Table D.2: ++ * Qe values and probability estimation state machine ++ */ ++ sv = *st; ++ qe = jaritab[sv & 0x7F]; /* => Qe_Value */ ++ nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */ ++ nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */ ++ ++ /* Decode & estimation procedures per sections D.2.4 & D.2.5 */ ++ temp = e->a - qe; ++ e->a = temp; ++ temp <<= e->ct; ++ if (e->c >= temp) { ++ e->c -= temp; ++ /* Conditional LPS (less probable symbol) exchange */ ++ if (e->a < qe) { ++ e->a = qe; ++ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ ++ } else { ++ e->a = qe; ++ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ ++ sv ^= 0x80; /* Exchange LPS/MPS */ ++ } ++ } else if (e->a < 0x8000L) { ++ /* Conditional MPS (more probable symbol) exchange */ ++ if (e->a < qe) { ++ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ ++ sv ^= 0x80; /* Exchange LPS/MPS */ ++ } else { ++ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ ++ } ++ } ++ ++ return sv >> 7; ++} ++ ++ ++/* ++ * Check for a restart marker & resynchronize decoder. ++ */ ++ ++LOCAL(void) ++process_restart (j_decompress_ptr cinfo) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ int ci; ++ jpeg_component_info * compptr; ++ ++ /* Advance past the RSTn marker */ ++ if (! (*cinfo->marker->read_restart_marker) (cinfo)) ++ ERREXIT(cinfo, JERR_CANT_SUSPEND); ++ ++ for (ci = 0; ci < cinfo->comps_in_scan; ci++) { ++ compptr = cinfo->cur_comp_info[ci]; ++ /* Re-initialize statistics areas */ ++ if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) { ++ MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); ++ /* Reset DC predictions to 0 */ ++ entropy->last_dc_val[ci] = 0; ++ entropy->dc_context[ci] = 0; ++ } ++ if (cinfo->progressive_mode == 0 || cinfo->Ss) { ++ MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); ++ } ++ } ++ ++ /* Reset arithmetic decoding variables */ ++ entropy->c = 0; ++ entropy->a = 0; ++ entropy->ct = -16; /* force reading 2 initial bytes to fill C */ ++ ++ /* Reset restart counter */ ++ entropy->restarts_to_go = cinfo->restart_interval; ++} ++ ++ ++/* ++ * Arithmetic MCU decoding. ++ * Each of these routines decodes and returns one MCU's worth of ++ * arithmetic-compressed coefficients. ++ * The coefficients are reordered from zigzag order into natural array order, ++ * but are not dequantized. ++ * ++ * The i'th block of the MCU is stored into the block pointed to by ++ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. ++ */ ++ ++/* ++ * MCU decoding for DC initial scan (either spectral selection, ++ * or first pass of successive approximation). ++ */ ++ ++METHODDEF(boolean) ++decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ JBLOCKROW block; ++ unsigned char *st; ++ int blkn, ci, tbl, sign; ++ int v, m; ++ ++ /* Process restart marker if needed */ ++ if (cinfo->restart_interval) { ++ if (entropy->restarts_to_go == 0) ++ process_restart(cinfo); ++ entropy->restarts_to_go--; ++ } ++ ++ if (entropy->ct == -1) return TRUE; /* if error do nothing */ ++ ++ /* Outer loop handles each block in the MCU */ ++ ++ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { ++ block = MCU_data[blkn]; ++ ci = cinfo->MCU_membership[blkn]; ++ tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; ++ ++ /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ ++ ++ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ ++ st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; ++ ++ /* Figure F.19: Decode_DC_DIFF */ ++ if (arith_decode(cinfo, st) == 0) ++ entropy->dc_context[ci] = 0; ++ else { ++ /* Figure F.21: Decoding nonzero value v */ ++ /* Figure F.22: Decoding the sign of v */ ++ sign = arith_decode(cinfo, st + 1); ++ st += 2; st += sign; ++ /* Figure F.23: Decoding the magnitude category of v */ ++ if ((m = arith_decode(cinfo, st)) != 0) { ++ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ ++ while (arith_decode(cinfo, st)) { ++ if ((m <<= 1) == 0x8000) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* magnitude overflow */ ++ return TRUE; ++ } ++ st += 1; ++ } ++ } ++ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ ++ if (m < (int) (((INT32) 1 << cinfo->arith_dc_L[tbl]) >> 1)) ++ entropy->dc_context[ci] = 0; /* zero diff category */ ++ else if (m > (int) (((INT32) 1 << cinfo->arith_dc_U[tbl]) >> 1)) ++ entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ ++ else ++ entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ ++ v = m; ++ /* Figure F.24: Decoding the magnitude bit pattern of v */ ++ st += 14; ++ while (m >>= 1) ++ if (arith_decode(cinfo, st)) v |= m; ++ v += 1; if (sign) v = -v; ++ entropy->last_dc_val[ci] += v; ++ } ++ ++ /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */ ++ (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * MCU decoding for AC initial scan (either spectral selection, ++ * or first pass of successive approximation). ++ */ ++ ++METHODDEF(boolean) ++decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ JBLOCKROW block; ++ unsigned char *st; ++ int tbl, sign, k; ++ int v, m; ++ ++ /* Process restart marker if needed */ ++ if (cinfo->restart_interval) { ++ if (entropy->restarts_to_go == 0) ++ process_restart(cinfo); ++ entropy->restarts_to_go--; ++ } ++ ++ if (entropy->ct == -1) return TRUE; /* if error do nothing */ ++ ++ /* There is always only one block per MCU */ ++ block = MCU_data[0]; ++ tbl = cinfo->cur_comp_info[0]->ac_tbl_no; ++ ++ /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ ++ ++ /* Figure F.20: Decode_AC_coefficients */ ++ for (k = cinfo->Ss; k <= cinfo->Se; k++) { ++ st = entropy->ac_stats[tbl] + 3 * (k - 1); ++ if (arith_decode(cinfo, st)) break; /* EOB flag */ ++ while (arith_decode(cinfo, st + 1) == 0) { ++ st += 3; k++; ++ if (k > cinfo->Se) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* spectral overflow */ ++ return TRUE; ++ } ++ } ++ /* Figure F.21: Decoding nonzero value v */ ++ /* Figure F.22: Decoding the sign of v */ ++ entropy->ac_stats[tbl][245] = 0; ++ sign = arith_decode(cinfo, entropy->ac_stats[tbl] + 245); ++ st += 2; ++ /* Figure F.23: Decoding the magnitude category of v */ ++ if ((m = arith_decode(cinfo, st)) != 0) { ++ if (arith_decode(cinfo, st)) { ++ m <<= 1; ++ st = entropy->ac_stats[tbl] + ++ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); ++ while (arith_decode(cinfo, st)) { ++ if ((m <<= 1) == 0x8000) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* magnitude overflow */ ++ return TRUE; ++ } ++ st += 1; ++ } ++ } ++ } ++ v = m; ++ /* Figure F.24: Decoding the magnitude bit pattern of v */ ++ st += 14; ++ while (m >>= 1) ++ if (arith_decode(cinfo, st)) v |= m; ++ v += 1; if (sign) v = -v; ++ /* Scale and output coefficient in natural (dezigzagged) order */ ++ (*block)[jpeg_natural_order[k]] = (JCOEF) (v << cinfo->Al); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * MCU decoding for DC successive approximation refinement scan. ++ */ ++ ++METHODDEF(boolean) ++decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ unsigned char st[4]; ++ int p1, blkn; ++ ++ /* Process restart marker if needed */ ++ if (cinfo->restart_interval) { ++ if (entropy->restarts_to_go == 0) ++ process_restart(cinfo); ++ entropy->restarts_to_go--; ++ } ++ ++ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ ++ ++ /* Outer loop handles each block in the MCU */ ++ ++ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { ++ st[0] = 0; /* use fixed probability estimation */ ++ /* Encoded data is simply the next bit of the two's-complement DC value */ ++ if (arith_decode(cinfo, st)) ++ MCU_data[blkn][0][0] |= p1; ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * MCU decoding for AC successive approximation refinement scan. ++ */ ++ ++METHODDEF(boolean) ++decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ JBLOCKROW block; ++ JCOEFPTR thiscoef; ++ unsigned char *st; ++ int tbl, k, kex; ++ int p1, m1; ++ ++ /* Process restart marker if needed */ ++ if (cinfo->restart_interval) { ++ if (entropy->restarts_to_go == 0) ++ process_restart(cinfo); ++ entropy->restarts_to_go--; ++ } ++ ++ if (entropy->ct == -1) return TRUE; /* if error do nothing */ ++ ++ /* There is always only one block per MCU */ ++ block = MCU_data[0]; ++ tbl = cinfo->cur_comp_info[0]->ac_tbl_no; ++ ++ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ ++ m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ ++ ++ /* Establish EOBx (previous stage end-of-block) index */ ++ for (kex = cinfo->Se + 1; kex > 1; kex--) ++ if ((*block)[jpeg_natural_order[kex - 1]]) break; ++ ++ for (k = cinfo->Ss; k <= cinfo->Se; k++) { ++ st = entropy->ac_stats[tbl] + 3 * (k - 1); ++ if (k >= kex) ++ if (arith_decode(cinfo, st)) break; /* EOB flag */ ++ for (;;) { ++ thiscoef = *block + jpeg_natural_order[k]; ++ if (*thiscoef) { /* previously nonzero coef */ ++ if (arith_decode(cinfo, st + 2)) ++ if (*thiscoef < 0) ++ *thiscoef += m1; ++ else ++ *thiscoef += p1; ++ break; ++ } ++ if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */ ++ entropy->ac_stats[tbl][245] = 0; ++ if (arith_decode(cinfo, entropy->ac_stats[tbl] + 245)) ++ *thiscoef = m1; ++ else ++ *thiscoef = p1; ++ break; ++ } ++ st += 3; k++; ++ if (k > cinfo->Se) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* spectral overflow */ ++ return TRUE; ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Decode one MCU's worth of arithmetic-compressed coefficients. ++ */ ++ ++METHODDEF(boolean) ++decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ jpeg_component_info * compptr; ++ JBLOCKROW block; ++ unsigned char *st; ++ int blkn, ci, tbl, sign, k; ++ int v, m; ++ ++ /* Process restart marker if needed */ ++ if (cinfo->restart_interval) { ++ if (entropy->restarts_to_go == 0) ++ process_restart(cinfo); ++ entropy->restarts_to_go--; ++ } ++ ++ if (entropy->ct == -1) return TRUE; /* if error do nothing */ ++ ++ /* Outer loop handles each block in the MCU */ ++ ++ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { ++ block = MCU_data[blkn]; ++ ci = cinfo->MCU_membership[blkn]; ++ compptr = cinfo->cur_comp_info[ci]; ++ ++ /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ ++ ++ tbl = compptr->dc_tbl_no; ++ ++ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ ++ st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; ++ ++ /* Figure F.19: Decode_DC_DIFF */ ++ if (arith_decode(cinfo, st) == 0) ++ entropy->dc_context[ci] = 0; ++ else { ++ /* Figure F.21: Decoding nonzero value v */ ++ /* Figure F.22: Decoding the sign of v */ ++ sign = arith_decode(cinfo, st + 1); ++ st += 2; st += sign; ++ /* Figure F.23: Decoding the magnitude category of v */ ++ if ((m = arith_decode(cinfo, st)) != 0) { ++ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ ++ while (arith_decode(cinfo, st)) { ++ if ((m <<= 1) == 0x8000) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* magnitude overflow */ ++ return TRUE; ++ } ++ st += 1; ++ } ++ } ++ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ ++ if (m < (int) (((INT32) 1 << cinfo->arith_dc_L[tbl]) >> 1)) ++ entropy->dc_context[ci] = 0; /* zero diff category */ ++ else if (m > (int) (((INT32) 1 << cinfo->arith_dc_U[tbl]) >> 1)) ++ entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ ++ else ++ entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ ++ v = m; ++ /* Figure F.24: Decoding the magnitude bit pattern of v */ ++ st += 14; ++ while (m >>= 1) ++ if (arith_decode(cinfo, st)) v |= m; ++ v += 1; if (sign) v = -v; ++ entropy->last_dc_val[ci] += v; ++ } ++ ++ (*block)[0] = (JCOEF) entropy->last_dc_val[ci]; ++ ++ /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ ++ ++ tbl = compptr->ac_tbl_no; ++ ++ /* Figure F.20: Decode_AC_coefficients */ ++ for (k = 1; k < DCTSIZE2; k++) { ++ st = entropy->ac_stats[tbl] + 3 * (k - 1); ++ if (arith_decode(cinfo, st)) break; /* EOB flag */ ++ while (arith_decode(cinfo, st + 1) == 0) { ++ st += 3; k++; ++ if (k >= DCTSIZE2) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* spectral overflow */ ++ return TRUE; ++ } ++ } ++ /* Figure F.21: Decoding nonzero value v */ ++ /* Figure F.22: Decoding the sign of v */ ++ entropy->ac_stats[tbl][245] = 0; ++ sign = arith_decode(cinfo, entropy->ac_stats[tbl] + 245); ++ st += 2; ++ /* Figure F.23: Decoding the magnitude category of v */ ++ if ((m = arith_decode(cinfo, st)) != 0) { ++ if (arith_decode(cinfo, st)) { ++ m <<= 1; ++ st = entropy->ac_stats[tbl] + ++ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); ++ while (arith_decode(cinfo, st)) { ++ if ((m <<= 1) == 0x8000) { ++ WARNMS(cinfo, JWRN_ARITH_BAD_CODE); ++ entropy->ct = -1; /* magnitude overflow */ ++ return TRUE; ++ } ++ st += 1; ++ } ++ } ++ } ++ v = m; ++ /* Figure F.24: Decoding the magnitude bit pattern of v */ ++ st += 14; ++ while (m >>= 1) ++ if (arith_decode(cinfo, st)) v |= m; ++ v += 1; if (sign) v = -v; ++ (*block)[jpeg_natural_order[k]] = (JCOEF) v; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Initialize for an arithmetic-compressed scan. ++ */ ++ ++METHODDEF(void) ++start_pass (j_decompress_ptr cinfo) ++{ ++ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; ++ int ci, tbl; ++ jpeg_component_info * compptr; ++ ++ if (cinfo->progressive_mode) { ++ /* Validate progressive scan parameters */ ++ if (cinfo->Ss == 0) { ++ if (cinfo->Se != 0) ++ goto bad; ++ } else { ++ /* need not check Ss/Se < 0 since they came from unsigned bytes */ ++ if (cinfo->Se < cinfo->Ss || cinfo->Se >= DCTSIZE2) ++ goto bad; ++ /* AC scans may have only one component */ ++ if (cinfo->comps_in_scan != 1) ++ goto bad; ++ } ++ if (cinfo->Ah != 0) { ++ /* Successive approximation refinement scan: must have Al = Ah-1. */ ++ if (cinfo->Ah-1 != cinfo->Al) ++ goto bad; ++ } ++ if (cinfo->Al > 13) { /* need not check for < 0 */ ++ bad: ++ ERREXIT4(cinfo, JERR_BAD_PROGRESSION, ++ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); ++ } ++ /* Update progression status, and verify that scan order is legal. ++ * Note that inter-scan inconsistencies are treated as warnings ++ * not fatal errors ... not clear if this is right way to behave. ++ */ ++ for (ci = 0; ci < cinfo->comps_in_scan; ci++) { ++ int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; ++ int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; ++ if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ ++ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); ++ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { ++ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; ++ if (cinfo->Ah != expected) ++ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); ++ coef_bit_ptr[coefi] = cinfo->Al; ++ } ++ } ++ /* Select MCU decoding routine */ ++ if (cinfo->Ah == 0) { ++ if (cinfo->Ss == 0) ++ entropy->pub.decode_mcu = decode_mcu_DC_first; ++ else ++ entropy->pub.decode_mcu = decode_mcu_AC_first; ++ } else { ++ if (cinfo->Ss == 0) ++ entropy->pub.decode_mcu = decode_mcu_DC_refine; ++ else ++ entropy->pub.decode_mcu = decode_mcu_AC_refine; ++ } ++ } else { ++ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. ++ * This ought to be an error condition, but we make it a warning because ++ * there are some baseline files out there with all zeroes in these bytes. ++ */ ++ if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || ++ cinfo->Ah != 0 || cinfo->Al != 0) ++ WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); ++ /* Select MCU decoding routine */ ++ entropy->pub.decode_mcu = decode_mcu; ++ } ++ ++ for (ci = 0; ci < cinfo->comps_in_scan; ci++) { ++ compptr = cinfo->cur_comp_info[ci]; ++ /* Allocate & initialize requested statistics areas */ ++ if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) { ++ tbl = compptr->dc_tbl_no; ++ if (tbl < 0 || tbl >= NUM_ARITH_TBLS) ++ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); ++ if (entropy->dc_stats[tbl] == NULL) ++ entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) ++ ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS); ++ MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); ++ /* Initialize DC predictions to 0 */ ++ entropy->last_dc_val[ci] = 0; ++ entropy->dc_context[ci] = 0; ++ } ++ if (cinfo->progressive_mode == 0 || cinfo->Ss) { ++ tbl = compptr->ac_tbl_no; ++ if (tbl < 0 || tbl >= NUM_ARITH_TBLS) ++ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); ++ if (entropy->ac_stats[tbl] == NULL) ++ entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) ++ ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS); ++ MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); ++ } ++ } ++ ++ /* Initialize arithmetic decoding variables */ ++ entropy->c = 0; ++ entropy->a = 0; ++ entropy->ct = -16; /* force reading 2 initial bytes to fill C */ ++ ++ /* Initialize restart counter */ ++ entropy->restarts_to_go = cinfo->restart_interval; ++} ++ ++ ++/* ++ * Module initialization routine for arithmetic entropy decoding. ++ */ ++ ++GLOBAL(void) ++jinit_arith_decoder (j_decompress_ptr cinfo) ++{ ++ arith_entropy_ptr entropy; ++ int i; ++ ++ entropy = (arith_entropy_ptr) ++ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, ++ SIZEOF(arith_entropy_decoder)); ++ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; ++ entropy->pub.start_pass = start_pass; ++ ++ /* Mark tables unallocated */ ++ for (i = 0; i < NUM_ARITH_TBLS; i++) { ++ entropy->dc_stats[i] = NULL; ++ entropy->ac_stats[i] = NULL; ++ } ++ ++ if (cinfo->progressive_mode) { ++ /* Create progression status table */ ++ int *coef_bit_ptr, ci; ++ cinfo->coef_bits = (int (*)[DCTSIZE2]) ++ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, ++ cinfo->num_components*DCTSIZE2*SIZEOF(int)); ++ coef_bit_ptr = & cinfo->coef_bits[0][0]; ++ for (ci = 0; ci < cinfo->num_components; ci++) ++ for (i = 0; i < DCTSIZE2; i++) ++ *coef_bit_ptr++ = -1; ++ } ++} +diff --git a/jdmaster.c b/jdmaster.c +index 8314b67..537abc7 100644 +--- a/jdmaster.c ++++ b/jdmaster.c +@@ -384,7 +384,7 @@ master_selection (j_decompress_ptr cinfo) + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +- ERREXIT(cinfo, JERR_ARITH_NOTIMPL); ++ jinit_arith_decoder(cinfo); + } else { + if (cinfo->progressive_mode) { + #ifdef D_PROGRESSIVE_SUPPORTED +diff --git a/jdtrans.c b/jdtrans.c +index 6c0ab71..fcc9ae9 100644 +--- a/jdtrans.c ++++ b/jdtrans.c +@@ -101,7 +101,7 @@ transdecode_master_selection (j_decompress_ptr cinfo) + + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { +- ERREXIT(cinfo, JERR_ARITH_NOTIMPL); ++ jinit_arith_decoder(cinfo); + } else { + if (cinfo->progressive_mode) { + #ifdef D_PROGRESSIVE_SUPPORTED +diff --git a/jerror.h b/jerror.h +index fc2fffe..109e3d3 100644 +--- a/jerror.h ++++ b/jerror.h +@@ -93,6 +93,7 @@ JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") + JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") + JMESSAGE(JERR_NOTIMPL, "Not implemented yet") + JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") ++JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") + JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") + JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") + JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +@@ -170,6 +171,7 @@ JMESSAGE(JTRC_UNKNOWN_IDS, + JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") + JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") + JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") ++JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") + JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") + JMESSAGE(JWRN_EXTRANEOUS_DATA, +diff --git a/jmorecfg.h b/jmorecfg.h +index 0e7fb72..4d66335 100644 +--- a/jmorecfg.h ++++ b/jmorecfg.h +@@ -283,7 +283,7 @@ typedef int boolean; + + /* Decoder capability options: */ + +-#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ ++#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ + #define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ + #define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ + #define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +diff --git a/jpegint.h b/jpegint.h +index 7a31f51..78bb1cf 100644 +--- a/jpegint.h ++++ b/jpegint.h +@@ -313,6 +313,7 @@ struct jpeg_color_quantizer { + #define jinit_marker_reader jIMReader + #define jinit_huff_decoder jIHDecoder + #define jinit_phuff_decoder jIPHDecoder ++#define jinit_arith_decoder jIADecoder + #define jinit_inverse_dct jIIDCT + #define jinit_upsampler jIUpsampler + #define jinit_color_deconverter jIDColor +@@ -358,6 +359,7 @@ EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); + EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); + EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); + EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); ++EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); + EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); + EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); + EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +-- +1.7.2.3 + diff --git a/libjpeg-turbo-1.0.1-tiff-ojpeg.patch b/libjpeg-turbo-1.0.1-tiff-ojpeg.patch new file mode 100644 index 0000000..5a3f129 --- /dev/null +++ b/libjpeg-turbo-1.0.1-tiff-ojpeg.patch @@ -0,0 +1,38 @@ +--- jdhuff.c ++++ jdhuff.c +@@ -649,3 +649,35 @@ + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } + } ++/* ++ * BEWARE OF KLUDGE: This subroutine is a hack for decoding illegal JPEG-in- ++ * TIFF encapsulations produced by Microsoft's Wang Imaging ++ * for Windows application with the public-domain TIFF Library. Based upon an ++ * examination of selected output files, this program apparently divides a JPEG ++ * bit-stream into consecutive horizontal TIFF "strips", such that the JPEG ++ * encoder's/decoder's DC coefficients for each image component are reset before ++ * each "strip". Moreover, a "strip" is not necessarily encoded in a multiple ++ * of 8 bits, so one must sometimes discard 1-7 bits at the end of each "strip" ++ * for alignment to the next input-Byte storage boundary. IJG JPEG Library ++ * decoder state is not normally exposed to client applications, so this sub- ++ * routine provides the TIFF Library with a "hook" to make these corrections. ++ * It should be called after "jpeg_start_decompress()" and before ++ * "jpeg_finish_decompress()", just before decoding each "strip" using ++ * "jpeg_read_raw_data()" or "jpeg_read_scanlines()". ++ * ++ * This kludge is not sanctioned or supported by the Independent JPEG Group, and ++ * future changes to the IJG JPEG Library might invalidate it. Do not send bug ++ * reports about this code to IJG developers. Instead, contact the author for ++ * advice: Scott B. Marovich , Hewlett-Packard Labs, 6/01. ++ */ ++GLOBAL(void) ++jpeg_reset_huff_decode (register j_decompress_ptr cinfo,register float *refbw) ++{ register huff_entropy_ptr entropy = (huff_entropy_ptr)cinfo->entropy; ++ register int ci = 0; ++ ++ /* Re-initialize DC predictions */ ++ do entropy->saved.last_dc_val[ci] = -refbw[ci << 1]; ++ while (++ci < cinfo->comps_in_scan); ++ /* Discard encoded input bits, up to the next Byte boundary */ ++ entropy->bitstate.bits_left &= ~7; ++} diff --git a/libjpeg-turbo-1.0.1.tar.bz2 b/libjpeg-turbo-1.0.1.tar.bz2 new file mode 100644 index 0000000..0bd9310 --- /dev/null +++ b/libjpeg-turbo-1.0.1.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1675a911b30e9612ef9d3684cc8fb34d199150f878943495ed00c51a16ebae92 +size 1054917 diff --git a/libjpeg-turbo.changes b/libjpeg-turbo.changes new file mode 100644 index 0000000..e3f28a8 --- /dev/null +++ b/libjpeg-turbo.changes @@ -0,0 +1,11 @@ +------------------------------------------------------------------- +Fri Dec 10 13:02:58 UTC 2010 - pgajdos@novell.com + +- this jpeg version will be the default to the prejudice of jpeg8 + from now on + +------------------------------------------------------------------- +Sun Nov 7 12:53:26 UTC 2010 - prusnak@opensuse.org + +- created package based on Fedora one (v 1.0.1) + diff --git a/libjpeg-turbo.spec b/libjpeg-turbo.spec new file mode 100644 index 0000000..12a67f6 --- /dev/null +++ b/libjpeg-turbo.spec @@ -0,0 +1,141 @@ +# +# spec file for package jpeg-turbo +# +# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + +Name: libjpeg-turbo +License: wxWindows Library Licence 3.1 +Group: Productivity/Graphics/Convertors +AutoReqProv: on +Version: 1.0.1 +Release: 1 +Summary: A MMX/SSE2 accelerated library for manipulating JPEG image files +Url: http://sourceforge.net/projects/libjpeg-turbo +BuildRequires: nasm gcc-c++ +Provides: jpeg = %{version} +Obsoletes: jpeg +Conflicts: jpeg8 +Source0: %{name}-%{version}.tar.bz2 +Source1: baselibs.conf +Patch0: %{name}-%{version}-int32.patch +Patch1: %{name}-%{version}-tiff-ojpeg.patch +Patch2: %{name}-%{version}-jpegtran.patch +Patch3: %{name}-%{version}-rh639672.patch +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +The libjpeg-turbo package contains a library of functions for manipulating +JPEG images. + +%package -n libjpeg62 + + +License: BSD3c(or similar) +Summary: The MMX/SSE accelerated JPEG compression/decompression library +Version: 62.0.0 +Provides: libjpeg6 = %{version} +Obsoletes: libjpeg6 +Group: System/Libraries +AutoReqProv: on +# bug437293 +%ifarch ppc64 +Obsoletes: libjpeg-64bit +%endif +# + +%description -n libjpeg62 +This library contains MMX/SSE accelerated functions for manipulating +JPEG images. + + +Authors: +-------- + Rob Hooft + Michael Mauldin + +%package -n libjpeg62-devel +License: BSD3c(or similar) +Summary: Development Tools for applications which will use the Libjpeg Library +Version: 62.0.0 +Group: Development/Libraries/C and C++ +Requires: libjpeg62 = %{version} +Provides: libjpeg-devel = %{version} +Obsoletes: libjpeg-devel +Conflicts: libjpeg8-devel +# bug437293 +%ifarch ppc64 +Obsoletes: libjpeg-devel-64bit +%endif +# + +%description -n libjpeg62-devel +The libjpeg-devel package includes the header files and libraries +necessary for compiling and linking programs which will manipulate JPEG +files using the libjpeg library. + + + +%prep +%setup -q +%patch0 +%patch1 +%patch2 +%patch3 -p1 + +%build +autoreconf -fiv +%configure --disable-static +make %{?_smp_mflags} + +%check +make test libdir=%{_libdir} + +%install +make install DESTDIR=$RPM_BUILD_ROOT +# Fix perms +chmod -x README-turbo.txt +# Remove unwanted files +rm -f $RPM_BUILD_ROOT%{_libdir}/lib{,turbo}jpeg.la +# Don't distribute libjpegturbo because it is unversioned +rm -f $RPM_BUILD_ROOT%{_includedir}/turbojpeg.h +rm -f $RPM_BUILD_ROOT%{_libdir}/libturbojpeg.so + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -n libjpeg62 -p /sbin/ldconfig + +%postun -n libjpeg62 -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%doc README README-turbo.txt change.log ChangeLog.txt LGPL.txt LICENSE.txt +/usr/bin/* +%doc %{_mandir}/man1/* + +%files -n libjpeg62 +%defattr(-,root,root) +%{_libdir}/libjpeg.so.62.0.0 +%{_libdir}/libjpeg.so.62 + +%files -n libjpeg62-devel +%defattr(-,root,root) +/usr/include/*.h +%{_libdir}/libjpeg.so +%doc coderules.doc jconfig.doc libjpeg.doc structure.doc example.c + +%changelog diff --git a/ready b/ready new file mode 100644 index 0000000..473a0f4