Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 231941 Details for
Bug 306679
media-gfx/digikam-1.2.0: Image rotation is broken
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch which fixes libjpeg v8a issue
jpeglossless_transforms_libjpeg-v8a.patch (text/plain), 189.00 KB, created by
Martin Gysel (bearsh)
on 2010-05-18 11:07:08 UTC
(
hide
)
Description:
patch which fixes libjpeg v8a issue
Filename:
MIME Type:
Creator:
Martin Gysel (bearsh)
Created:
2010-05-18 11:07:08 UTC
Size:
189.00 KB
patch
obsolete
>Index: jpeglossless/transupp.v7.cpp >=================================================================== >--- jpeglossless/transupp.v7.cpp (Revision 0) >+++ jpeglossless/transupp.v7.cpp (Revision 1115335) >@@ -0,0 +1,1552 @@ >+/* >+ * transupp.c >+ * >+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. >+ * This file is part of the Independent JPEG Group's software. >+ * For conditions of distribution and use, see the accompanying README file. >+ * >+ * This file contains image transformation routines and other utility code >+ * used by the jpegtran sample application. These are NOT part of the core >+ * JPEG library. But we keep these routines separate from jpegtran.c to >+ * ease the task of maintaining jpegtran-like programs that have other user >+ * interfaces. >+ */ >+ >+/* Although this file really shouldn't have access to the library internals, >+ * it's helpful to let it call jround_up() and jcopy_block_row(). >+ */ >+#define JPEG_INTERNALS >+ >+// LibJPEG includes >+ >+extern "C" >+{ >+#include "jinclude.h" >+#include "jpeglib.h" >+} >+ >+// Local includes >+ >+#include "transupp.h" /* My own external interface */ >+#include <ctype.h> /* to declare isdigit() */ >+ >+namespace KIPIJPEGLossLessPlugin >+{ >+ >+#if TRANSFORMS_SUPPORTED >+ >+/* >+ * 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, >+ * 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 >+ * fastest option for images larger than main memory. >+ * >+ * The other routines require a set of destination virtual arrays, so they >+ * need twice as much memory as jpegtran normally does. The destination >+ * arrays are always written in normal scan order (top to bottom) because >+ * the virtual array manager expects this. The source arrays will be scanned >+ * in the corresponding order, which means multiple passes through the source >+ * 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 >+ * source JPEG object, and therefore should be manipulated by calling the >+ * source's memory manager. >+ * 2. The destination's component count should be used. It may be smaller >+ * than the source's when forcing to grayscale. >+ * 3. Likewise the destination's sampling factors should be used. When >+ * forcing to grayscale the destination's sampling factors will be all 1, >+ * 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. 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. >+ */ >+ >+ >+LOCAL(void) >+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, x_crop_blocks; >+ int ci, k, offset_y; >+ JBLOCKARRAY buffer; >+ JCOEFPTR ptr1, ptr2; >+ JCOEF temp1, temp2; >+ jpeg_component_info *compptr; >+ >+ /* Horizontal mirroring of DCT blocks is accomplished by swapping >+ * pairs of blocks in-place. Within a DCT block, we perform horizontal >+ * mirroring by changing the signs of odd-numbered columns. >+ * Partial iMCUs at the right edge are left untouched. >+ */ >+ 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]; >+ /* this unrolled loop doesn't need to know which row it's on... */ >+ for (k = 0; k < DCTSIZE2; k += 2) { >+ temp1 = *ptr1; /* swap even column */ >+ temp2 = *ptr2; >+ *ptr1++ = temp2; >+ *ptr2++ = temp1; >+ temp1 = *ptr1; /* swap odd column with sign change */ >+ temp2 = *ptr2; >+ *ptr1++ = -temp2; >+ *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); >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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; >+ JCOEFPTR src_ptr, dst_ptr; >+ jpeg_component_info *compptr; >+ >+ /* We output into a separate array because we can't touch different >+ * rows of the source virtual array simultaneously. Otherwise, this >+ * is a pretty straightforward analog of horizontal flip. >+ * Within a DCT block, vertical mirroring is done by changing the signs >+ * of odd-numbered rows. >+ * Partial iMCUs at the bottom edge are copied verbatim. >+ */ >+ 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 (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 - 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 + y_crop_blocks, >+ (JDIMENSION) compptr->v_samp_factor, FALSE); >+ } >+ for (offset_y = 0; offset_y < compptr->v_samp_factor; 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]; >+ 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]; >+ src_ptr = src_row_ptr[dst_blk_x]; >+ for (i = 0; i < DCTSIZE; i += 2) { >+ /* copy even row */ >+ for (j = 0; j < DCTSIZE; j++) >+ *dst_ptr++ = *src_ptr++; >+ /* copy odd row with sign change */ >+ for (j = 0; j < DCTSIZE; j++) >+ *dst_ptr++ = - *src_ptr++; >+ } >+ } >+ } else { >+ /* Just copy row verbatim. */ >+ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, >+ dst_buffer[offset_y], >+ compptr->width_in_blocks); >+ } >+ } >+ } >+ } >+} >+ >+ >+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, 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; >+ >+ /* Transposing pixels within a block just requires transposing the >+ * DCT coefficients. >+ * Partial iMCUs at the edges require no special treatment; we simply >+ * process all the available DCT blocks for every component. >+ */ >+ 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); >+ 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 + 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]; >+ 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]; >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. Transposing the image; >+ * 2. Horizontal mirroring. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ 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; >+ jpeg_component_info *compptr; >+ >+ /* Because of the horizontal mirror step, we can't process partial iMCUs >+ * at the (output) right edge properly. They just get transposed and >+ * not mirrored. >+ */ >+ 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) >+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, >+ (JDIMENSION) compptr->v_samp_factor, TRUE); >+ 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) { >+ 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++) { >+ 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. */ >+ 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]; >+ i++; >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } else { >+ /* Edge blocks are transposed but not mirrored. */ >+ 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]; >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. Horizontal mirroring; >+ * 2. Transposing the image. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ 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; >+ jpeg_component_info *compptr; >+ >+ /* Because of the horizontal mirror step, we can't process partial iMCUs >+ * at the (output) bottom edge properly. They just get transposed and >+ * not mirrored. >+ */ >+ 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) >+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, >+ (JDIMENSION) compptr->v_samp_factor, TRUE); >+ 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 + 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 (y_crop_blocks + dst_blk_y < comp_height) { >+ /* Block is within the mirrorable area. */ >+ 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } else { >+ /* Edge blocks are transposed but not mirrored. */ >+ 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]; >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. Vertical mirroring; >+ * 2. Horizontal mirroring. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ 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 = 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 (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 - 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 + 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]; >+ if (y_crop_blocks + dst_blk_y < comp_height) { >+ /* Row is within the mirrorable area. */ >+ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; >+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { >+ dst_ptr = dst_row_ptr[dst_blk_x]; >+ 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++; >+ } >+ } >+ } 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++; >+ } >+ } >+ } >+ } else { >+ /* Remaining rows are just mirrored horizontally. */ >+ 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) { >+ /* 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); >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. 180 degree rotation; >+ * 2. Transposition; >+ * or >+ * 1. Horizontal mirroring; >+ * 2. Transposition; >+ * 3. Horizontal mirroring. >+ * These steps are merged into a single processing routine. >+ */ >+{ >+ 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 = 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) >+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, >+ (JDIMENSION) compptr->v_samp_factor, TRUE); >+ 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) { >+ 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++) { >+ 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. */ >+ 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ i++; >+ for (j = 0; j < DCTSIZE; j++) { >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } else { >+ /* Right-edge blocks are mirrored in y only */ >+ 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } else { >+ if (x_crop_blocks + dst_blk_x < comp_width) { >+ /* Bottom-edge blocks are mirrored in x only */ >+ 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]; >+ i++; >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } else { >+ /* At lower right corner, just transpose, no mirroring */ >+ 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]; >+ } >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+/* 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 >+ * <width>x<height>{+-}<xoffset>{+-}<yoffset> >+ * 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->iMCU_sample_width); >+ if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == >+ full_width / (info->iMCU_sample_width)) >+ info->output_width = MCU_cols * (info->iMCU_sample_width); >+} >+ >+LOCAL(void) >+trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) >+{ >+ JDIMENSION MCU_rows; >+ >+ MCU_rows = info->output_height / (info->iMCU_sample_height); >+ if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == >+ full_height / (info->iMCU_sample_height)) >+ info->output_height = MCU_rows * (info->iMCU_sample_height); >+} >+ >+ >+/* 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. >+ * Hence, this routine must be called after jpeg_read_header (which reads >+ * the image dimensions) and before jpeg_read_coefficients (which realizes >+ * the source's virtual arrays). >+ */ >+ >+// NB: changed from transupp.c in libjpeg >+GLOBAL(boolean) >+jtransform_request_workspace (j_decompress_ptr srcinfo, >+ jpeg_transform_info *info) >+{ >+ jvirt_barray_ptr *coef_arrays = NULL; >+ boolean need_workspace, transpose_it; >+ jpeg_component_info *compptr; >+ 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) { >+ /* We'll only process the first component */ >+ info->num_components = 1; >+ } else { >+ /* 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->iMCU_sample_width = DCTSIZE; >+ info->iMCU_sample_height = DCTSIZE; >+ } else { >+ info->iMCU_sample_width = >+ srcinfo->max_v_samp_factor * DCTSIZE; >+ info->iMCU_sample_height = >+ srcinfo->max_h_samp_factor * DCTSIZE; >+ } >+ break; >+ default: >+ info->output_width = srcinfo->image_width; >+ info->output_height = srcinfo->image_height; >+ if (info->num_components == 1) { >+ info->iMCU_sample_width = DCTSIZE; >+ info->iMCU_sample_height = DCTSIZE; >+ } else { >+ info->iMCU_sample_width = >+ srcinfo->max_h_samp_factor * DCTSIZE; >+ info->iMCU_sample_height = >+ srcinfo->max_v_samp_factor * DCTSIZE; >+ } >+ 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->iMCU_sample_width)); >+ info->output_height = >+ info->crop_height + (yoffset % (info->iMCU_sample_height)); >+ /* Save x/y offsets measured in iMCUs */ >+ info->x_crop_offset = xoffset / (info->iMCU_sample_width); >+ info->y_crop_offset = yoffset / (info->iMCU_sample_height); >+ } 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: >+ 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: >+ 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: >+ 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); >+ width_in_iMCUs = (JDIMENSION) >+ jdiv_round_up((long) info->output_width, >+ (long) (info->iMCU_sample_width)); >+ height_in_iMCUs = (JDIMENSION) >+ jdiv_round_up((long) info->output_height, >+ (long) (info->iMCU_sample_height)); >+ 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, >+ width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); >+ } >+ } >+ >+ info->workspace_coef_arrays = coef_arrays; >+ >+ return TRUE; >+} >+ >+ >+/* Transpose destination image parameters */ >+ >+LOCAL(void) >+transpose_critical_parameters (j_compress_ptr dstinfo) >+{ >+ int tblno, i, j, ci, itemp; >+ jpeg_component_info *compptr; >+ JQUANT_TBL *qtblptr; >+ UINT16 qtemp; >+ >+ /* Transpose sampling factors */ >+ for (ci = 0; ci < dstinfo->num_components; ci++) { >+ compptr = dstinfo->comp_info + ci; >+ itemp = compptr->h_samp_factor; >+ compptr->h_samp_factor = compptr->v_samp_factor; >+ compptr->v_samp_factor = itemp; >+ } >+ >+ /* Transpose quantization tables */ >+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { >+ qtblptr = dstinfo->quant_tbl_ptrs[tblno]; >+ if (qtblptr != NULL) { >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < i; j++) { >+ qtemp = qtblptr->quantval[i*DCTSIZE+j]; >+ qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; >+ qtblptr->quantval[j*DCTSIZE+i] = qtemp; >+ } >+ } >+ } >+ } >+} >+ >+ >+/* Adjust Exif image parameters. >+ * >+ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. >+ */ >+ >+LOCAL(void) >+adjust_exif_parameters (JOCTET FAR * data, unsigned int length, >+ JDIMENSION new_width, JDIMENSION new_height) >+{ >+ 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; >+ } >+ >+ /* 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]); >+ } >+ if (firstoffset > length - 2) return; /* check end of data segment */ >+ >+ /* 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; >+ >+ /* 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; >+ } >+ >+ /* 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); >+} >+ >+ >+/* Adjust output image parameters as needed. >+ * >+ * This must be called after jpeg_copy_critical_parameters() >+ * and before jpeg_write_coefficients(). >+ * >+ * The return value is the set of virtual coefficient arrays to be written >+ * (either the ones allocated by jtransform_request_workspace, or the >+ * original source data arrays). The caller will need to pass this value >+ * to jpeg_write_coefficients(). >+ */ >+ >+GLOBAL(jvirt_barray_ptr *) >+jtransform_adjust_parameters (j_decompress_ptr srcinfo, >+ j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jpeg_transform_info *info) >+{ >+ /* If force-to-grayscale is requested, adjust destination parameters */ >+ if (info->force_grayscale) { >+ /* 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)) && >+ 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; >+ } else { >+ /* 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 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_TRANSPOSE: >+ case JXFORM_TRANSVERSE: >+ case JXFORM_ROT_90: >+ case JXFORM_ROT_270: >+ transpose_critical_parameters(dstinfo); >+ break; >+ default: >+ 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; >+ return src_coef_arrays; >+} >+ >+ >+/* Execute the actual transformation, if any. >+ * >+ * This must be called *after* jpeg_write_coefficients, because it depends >+ * on jpeg_write_coefficients to have computed subsidiary values such as >+ * the per-component width and height fields in the destination object. >+ * >+ * Note that some transformations will modify the source data arrays! >+ */ >+ >+GLOBAL(void) >+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: >+ 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, info->x_crop_offset, info->y_crop_offset, >+ src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_TRANSPOSE: >+ 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, info->x_crop_offset, info->y_crop_offset, >+ src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_90: >+ 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, info->x_crop_offset, info->y_crop_offset, >+ src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_270: >+ 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; >+ default: >+ break; >+ } >+ >+ return result; >+} >+ >+#endif /* TRANSFORMS_SUPPORTED */ >+ >+ >+/* Setup decompression object to save desired markers in memory. >+ * This must be called before jpeg_read_header() to have the desired effect. >+ */ >+ >+GLOBAL(void) >+jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) >+{ >+#ifdef SAVE_MARKERS_SUPPORTED >+ int m; >+ >+ /* Save comments except under NONE option */ >+ if (option != JCOPYOPT_NONE) { >+ jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); >+ } >+ /* Save all types of APPn markers iff ALL option */ >+ if (option == JCOPYOPT_ALL) { >+ for (m = 0; m < 16; m++) >+ jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); >+ } >+#endif /* SAVE_MARKERS_SUPPORTED */ >+} >+ >+/* Copy markers saved in the given source object to the destination object. >+ * This should be called just after jpeg_start_compress() or >+ * jpeg_write_coefficients(). >+ * Note that those routines will have written the SOI, and also the >+ * JFIF APP0 or Adobe APP14 markers if selected. >+ */ >+ >+GLOBAL(void) >+jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ JCOPY_OPTION option) >+{ >+ jpeg_saved_marker_ptr marker; >+ >+ /* In the current implementation, we don't actually need to examine the >+ * option flag here; we just copy everything that got saved. >+ * But to avoid confusion, we do not output JFIF and Adobe APP14 markers >+ * if the encoder library already wrote one. >+ */ >+ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { >+ if (dstinfo->write_JFIF_header && >+ marker->marker == JPEG_APP0 && >+ marker->data_length >= 5 && >+ GETJOCTET(marker->data[0]) == 0x4A && >+ GETJOCTET(marker->data[1]) == 0x46 && >+ GETJOCTET(marker->data[2]) == 0x49 && >+ GETJOCTET(marker->data[3]) == 0x46 && >+ GETJOCTET(marker->data[4]) == 0) >+ continue; /* reject duplicate JFIF */ >+ if (dstinfo->write_Adobe_marker && >+ marker->marker == JPEG_APP0+14 && >+ marker->data_length >= 5 && >+ GETJOCTET(marker->data[0]) == 0x41 && >+ GETJOCTET(marker->data[1]) == 0x64 && >+ GETJOCTET(marker->data[2]) == 0x6F && >+ GETJOCTET(marker->data[3]) == 0x62 && >+ GETJOCTET(marker->data[4]) == 0x65) >+ continue; /* reject duplicate Adobe */ >+#ifdef NEED_FAR_POINTERS >+ /* We could use jpeg_write_marker if the data weren't FAR... */ >+ { >+ unsigned int i; >+ jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); >+ for (i = 0; i < marker->data_length; i++) >+ jpeg_write_m_byte(dstinfo, marker->data[i]); >+ } >+#else >+ jpeg_write_marker(dstinfo, marker->marker, >+ marker->data, marker->data_length); >+#endif >+ } >+} >+ >+} // namespace KIPIJPEGLossLessPlugin >Index: jpeglossless/transupp.v6b.cpp >=================================================================== >--- jpeglossless/transupp.v6b.cpp (Revision 0) >+++ jpeglossless/transupp.v6b.cpp (Revision 1115335) >@@ -0,0 +1,984 @@ >+/* >+ * transupp.c >+ * >+ * Copyright (C) 1997, 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. >+ * >+ * This file contains image transformation routines and other utility code >+ * used by the jpegtran sample application. These are NOT part of the core >+ * JPEG library. But we keep these routines separate from jpegtran.c to >+ * ease the task of maintaining jpegtran-like programs that have other user >+ * interfaces. >+ */ >+ >+// Local includes >+ >+#include "transupp.h" /* My own external interface */ >+ >+namespace KIPIJPEGLossLessPlugin >+{ >+ >+#if TRANSFORMS_SUPPORTED >+ >+/* >+ * 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. >+ * >+ * Horizontal flipping is done in-place, using a single top-to-bottom >+ * pass through the virtual source array. It will thus be much the >+ * fastest option for images larger than main memory. >+ * >+ * The other routines require a set of destination virtual arrays, so they >+ * need twice as much memory as jpegtran normally does. The destination >+ * arrays are always written in normal scan order (top to bottom) because >+ * the virtual array manager expects this. The source arrays will be scanned >+ * in the corresponding order, which means multiple passes through the source >+ * arrays for most of the transforms. That could result in much thrashing >+ * if the image is larger than main memory. >+ * >+ * Some notes about the operating environment of the individual transform >+ * routines: >+ * 1. Both the source and destination virtual arrays are allocated from the >+ * source JPEG object, and therefore should be manipulated by calling the >+ * source's memory manager. >+ * 2. The destination's component count should be used. It may be smaller >+ * than the source's when forcing to grayscale. >+ * 3. Likewise the destination's sampling factors should be used. When >+ * forcing to grayscale the destination's sampling factors will be all 1, >+ * 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 >+ * 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 */ >+{ >+ JDIMENSION MCU_cols, comp_width, blk_x, blk_y; >+ int ci, k, offset_y; >+ JBLOCKARRAY buffer; >+ JCOEFPTR ptr1, ptr2; >+ JCOEF temp1, temp2; >+ jpeg_component_info *compptr; >+ >+ /* Horizontal mirroring of DCT blocks is accomplished by swapping >+ * pairs of blocks in-place. Within a DCT block, we perform horizontal >+ * 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); >+ >+ for (ci = 0; ci < dstinfo->num_components; ci++) { >+ compptr = dstinfo->comp_info + ci; >+ comp_width = MCU_cols * 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++) { >+ 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]; >+ /* this unrolled loop doesn't need to know which row it's on... */ >+ for (k = 0; k < DCTSIZE2; k += 2) { >+ temp1 = *ptr1; /* swap even column */ >+ temp2 = *ptr2; >+ *ptr1++ = temp2; >+ *ptr2++ = temp1; >+ temp1 = *ptr1; /* swap odd column with sign change */ >+ temp2 = *ptr2; >+ *ptr1++ = -temp2; >+ *ptr2++ = -temp1; >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+LOCAL(void) >+do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ 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; >+ 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; >+ >+ /* We output into a separate array because we can't touch different >+ * rows of the source virtual array simultaneously. Otherwise, this >+ * is a pretty straightforward analog of horizontal flip. >+ * Within a DCT block, vertical mirroring is done by changing the signs >+ * of odd-numbered rows. >+ * Partial iMCUs at the bottom edge are copied verbatim. >+ */ >+ MCU_rows = dstinfo->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; >+ 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) { >+ /* 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, >+ (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, >+ (JDIMENSION) compptr->v_samp_factor, FALSE); >+ } >+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { >+ if (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]; >+ 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[dst_blk_x]; >+ for (i = 0; i < DCTSIZE; i += 2) { >+ /* copy even row */ >+ for (j = 0; j < DCTSIZE; j++) >+ *dst_ptr++ = *src_ptr++; >+ /* copy odd row with sign change */ >+ for (j = 0; j < DCTSIZE; j++) >+ *dst_ptr++ = - *src_ptr++; >+ } >+ } >+ } else { >+ /* Just copy row verbatim. */ >+ jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], >+ compptr->width_in_blocks); >+ } >+ } >+ } >+ } >+} >+ >+ >+LOCAL(void) >+do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jvirt_barray_ptr *dst_coef_arrays) >+/* Transpose source into destination */ >+{ >+ JDIMENSION dst_blk_x, dst_blk_y; >+ int ci, i, j, offset_x, offset_y; >+ JBLOCKARRAY src_buffer, dst_buffer; >+ JCOEFPTR src_ptr, dst_ptr; >+ jpeg_component_info *compptr; >+ >+ /* Transposing pixels within a block just requires transposing the >+ * DCT coefficients. >+ * Partial iMCUs at the edges require no special treatment; we simply >+ * process all the available DCT blocks for every component. >+ */ >+ for (ci = 0; ci < dstinfo->num_components; ci++) { >+ compptr = dstinfo->comp_info + ci; >+ 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); >+ 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); >+ 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]; >+ for (i = 0; i < DCTSIZE; i++) >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+LOCAL(void) >+do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jvirt_barray_ptr *dst_coef_arrays) >+/* 90 degree rotation is equivalent to >+ * 1. Transposing the image; >+ * 2. Horizontal mirroring. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; >+ int ci, i, j, offset_x, offset_y; >+ JBLOCKARRAY src_buffer, dst_buffer; >+ JCOEFPTR src_ptr, dst_ptr; >+ jpeg_component_info *compptr; >+ >+ /* Because of the horizontal mirror step, we can't process partial iMCUs >+ * at the (output) right edge properly. They just get transposed and >+ * not mirrored. >+ */ >+ MCU_cols = dstinfo->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; >+ 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); >+ 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); >+ 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) { >+ /* Block is within the mirrorable area. */ >+ dst_ptr = dst_buffer[offset_y] >+ [comp_width - dst_blk_x - offset_x - 1]; >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ i++; >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } else { >+ /* Edge blocks are transposed but not mirrored. */ >+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; >+ for (i = 0; i < DCTSIZE; i++) >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+LOCAL(void) >+do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jvirt_barray_ptr *dst_coef_arrays) >+/* 270 degree rotation is equivalent to >+ * 1. Horizontal mirroring; >+ * 2. Transposing the image. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; >+ int ci, i, j, offset_x, offset_y; >+ JBLOCKARRAY src_buffer, dst_buffer; >+ JCOEFPTR src_ptr, dst_ptr; >+ jpeg_component_info *compptr; >+ >+ /* Because of the horizontal mirror step, we can't process partial iMCUs >+ * at the (output) bottom edge properly. They just get transposed and >+ * not mirrored. >+ */ >+ MCU_rows = dstinfo->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; >+ 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); >+ 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); >+ 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) { >+ /* Block is within the mirrorable area. */ >+ src_ptr = src_buffer[offset_x] >+ [comp_height - 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } else { >+ /* Edge blocks are transposed but not mirrored. */ >+ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; >+ for (i = 0; i < DCTSIZE; i++) >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+LOCAL(void) >+do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jvirt_barray_ptr *dst_coef_arrays) >+/* 180 degree rotation is equivalent to >+ * 1. Vertical mirroring; >+ * 2. Horizontal mirroring. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; >+ 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); >+ >+ 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; >+ 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) { >+ /* 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, >+ (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, >+ (JDIMENSION) compptr->v_samp_factor, FALSE); >+ } >+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { >+ if (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++) { >+ 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++; >+ } >+ /* For odd row, negate every even column. */ >+ for (j = 0; j < DCTSIZE; j += 2) { >+ *dst_ptr++ = - *src_ptr++; >+ *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++; >+ } >+ } >+ /* 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++; >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+LOCAL(void) >+do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jvirt_barray_ptr *dst_coef_arrays) >+/* Transverse transpose is equivalent to >+ * 1. 180 degree rotation; >+ * 2. Transposition; >+ * or >+ * 1. Horizontal mirroring; >+ * 2. Transposition; >+ * 3. Horizontal mirroring. >+ * These steps are merged into a single processing routine. >+ */ >+{ >+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; >+ 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); >+ >+ 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; >+ 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); >+ 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); >+ 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) { >+ /* Block is within the mirrorable area. */ >+ dst_ptr = dst_buffer[offset_y] >+ [comp_width - dst_blk_x - offset_x - 1]; >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < DCTSIZE; j++) { >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ i++; >+ for (j = 0; j < DCTSIZE; j++) { >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } else { >+ /* Right-edge blocks are mirrored in y only */ >+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < DCTSIZE; j++) { >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } else { >+ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; >+ if (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]; >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ i++; >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } else { >+ /* At lower right corner, just transpose, no mirroring */ >+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; >+ for (i = 0; i < DCTSIZE; i++) >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+/* Request any required workspace. >+ * >+ * 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. >+ * Hence, this routine must be called after jpeg_read_header (which reads >+ * the image dimensions) and before jpeg_read_coefficients (which realizes >+ * the source's virtual arrays). >+ */ >+ >+// NB: changed from transupp.c in libjpeg >+GLOBAL(boolean) >+jtransform_request_workspace (j_decompress_ptr srcinfo, >+ jpeg_transform_info *info) >+{ >+ jvirt_barray_ptr *coef_arrays = NULL; >+ jpeg_component_info *compptr; >+ int ci; >+ >+ if (info->force_grayscale && >+ srcinfo->jpeg_color_space == JCS_YCbCr && >+ srcinfo->num_components == 3) { >+ /* We'll only process the first component */ >+ info->num_components = 1; >+ } else { >+ /* Process all the components */ >+ info->num_components = srcinfo->num_components; >+ } >+ >+ switch (info->transform) { >+ case JXFORM_NONE: >+ case JXFORM_FLIP_H: >+ /* Don'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); >+ } >+ break; >+ case JXFORM_TRANSPOSE: >+ case JXFORM_TRANSVERSE: >+ case JXFORM_ROT_90: >+ 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. >+ */ >+ 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->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); >+ } >+ break; >+ } >+ info->workspace_coef_arrays = coef_arrays; >+ >+ return TRUE; >+} >+ >+ >+/* Transpose destination image parameters */ >+ >+LOCAL(void) >+transpose_critical_parameters (j_compress_ptr dstinfo) >+{ >+ 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; >+ itemp = compptr->h_samp_factor; >+ compptr->h_samp_factor = compptr->v_samp_factor; >+ compptr->v_samp_factor = itemp; >+ } >+ >+ /* Transpose quantization tables */ >+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { >+ qtblptr = dstinfo->quant_tbl_ptrs[tblno]; >+ if (qtblptr != NULL) { >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < i; j++) { >+ qtemp = qtblptr->quantval[i*DCTSIZE+j]; >+ qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; >+ qtblptr->quantval[j*DCTSIZE+i] = qtemp; >+ } >+ } >+ } >+ } >+} >+ >+ >+/* Trim off any partial iMCUs on the indicated destination edge */ >+ >+LOCAL(void) >+trim_right_edge (j_compress_ptr dstinfo) >+{ >+ int ci, max_h_samp_factor; >+ JDIMENSION MCU_cols; >+ >+ /* 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); >+ } >+ 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); >+} >+ >+LOCAL(void) >+trim_bottom_edge (j_compress_ptr dstinfo) >+{ >+ int ci, max_v_samp_factor; >+ JDIMENSION MCU_rows; >+ >+ /* 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); >+ } >+ 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); >+} >+ >+ >+/* Adjust output image parameters as needed. >+ * >+ * This must be called after jpeg_copy_critical_parameters() >+ * and before jpeg_write_coefficients(). >+ * >+ * The return value is the set of virtual coefficient arrays to be written >+ * (either the ones allocated by jtransform_request_workspace, or the >+ * original source data arrays). The caller will need to pass this value >+ * to jpeg_write_coefficients(). >+ */ >+ >+GLOBAL(jvirt_barray_ptr *) >+jtransform_adjust_parameters (j_decompress_ptr srcinfo, >+ j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jpeg_transform_info *info) >+{ >+ /* 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.) >+ */ >+ 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. */ >+ 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; >+ } else { >+ /* Sorry, can't do it */ >+ ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); >+ } >+ } >+ >+ /* Correct the destination's image dimensions etc if necessary */ >+ 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; >+ } >+ >+ /* Return the appropriate output data set */ >+ if (info->workspace_coef_arrays != NULL) >+ return info->workspace_coef_arrays; >+ return src_coef_arrays; >+} >+ >+ >+/* Execute the actual transformation, if any. >+ * >+ * This must be called *after* jpeg_write_coefficients, because it depends >+ * on jpeg_write_coefficients to have computed subsidiary values such as >+ * the per-component width and height fields in the destination object. >+ * >+ * Note that some transformations will modify the source data arrays! >+ */ >+ >+// NB: changed from transupp.c in libjpeg >+GLOBAL(void) >+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; >+ >+ switch (info->transform) { >+ case JXFORM_NONE: >+ break; >+ case JXFORM_FLIP_H: >+ do_flip_h(srcinfo, dstinfo, src_coef_arrays); >+ break; >+ case JXFORM_FLIP_V: >+ do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_TRANSPOSE: >+ do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_TRANSVERSE: >+ do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_90: >+ do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_180: >+ do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_270: >+ do_rot_270(srcinfo, dstinfo, 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 * cinfo.block_size >+ * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size >+ * 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; >+ default: >+ break; >+ } >+ >+ return result; >+} >+ >+#endif /* TRANSFORMS_SUPPORTED */ >+ >+ >+/* Setup decompression object to save desired markers in memory. >+ * This must be called before jpeg_read_header() to have the desired effect. >+ */ >+ >+GLOBAL(void) >+jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) >+{ >+#ifdef SAVE_MARKERS_SUPPORTED >+ int m; >+ >+ /* Save comments except under NONE option */ >+ if (option != JCOPYOPT_NONE) { >+ jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); >+ } >+ /* Save all types of APPn markers iff ALL option */ >+ if (option == JCOPYOPT_ALL) { >+ for (m = 0; m < 16; m++) >+ jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); >+ } >+#endif /* SAVE_MARKERS_SUPPORTED */ >+} >+ >+/* Copy markers saved in the given source object to the destination object. >+ * This should be called just after jpeg_start_compress() or >+ * jpeg_write_coefficients(). >+ * Note that those routines will have written the SOI, and also the >+ * JFIF APP0 or Adobe APP14 markers if selected. >+ */ >+ >+GLOBAL(void) >+jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ JCOPY_OPTION option) >+{ >+ jpeg_saved_marker_ptr marker; >+ >+ /* In the current implementation, we don't actually need to examine the >+ * option flag here; we just copy everything that got saved. >+ * But to avoid confusion, we do not output JFIF and Adobe APP14 markers >+ * if the encoder library already wrote one. >+ */ >+ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { >+ if (dstinfo->write_JFIF_header && >+ marker->marker == JPEG_APP0 && >+ marker->data_length >= 5 && >+ GETJOCTET(marker->data[0]) == 0x4A && >+ GETJOCTET(marker->data[1]) == 0x46 && >+ GETJOCTET(marker->data[2]) == 0x49 && >+ GETJOCTET(marker->data[3]) == 0x46 && >+ GETJOCTET(marker->data[4]) == 0) >+ continue; /* reject duplicate JFIF */ >+ if (dstinfo->write_Adobe_marker && >+ marker->marker == JPEG_APP0+14 && >+ marker->data_length >= 5 && >+ GETJOCTET(marker->data[0]) == 0x41 && >+ GETJOCTET(marker->data[1]) == 0x64 && >+ GETJOCTET(marker->data[2]) == 0x6F && >+ GETJOCTET(marker->data[3]) == 0x62 && >+ GETJOCTET(marker->data[4]) == 0x65) >+ continue; /* reject duplicate Adobe */ >+#ifdef NEED_FAR_POINTERS >+ /* We could use jpeg_write_marker if the data weren't FAR... */ >+ { >+ unsigned int i; >+ jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); >+ for (i = 0; i < marker->data_length; i++) >+ jpeg_write_m_byte(dstinfo, marker->data[i]); >+ } >+#else >+ jpeg_write_marker(dstinfo, marker->marker, >+ marker->data, marker->data_length); >+#endif >+ } >+} >+ >+} // namespace KIPIJPEGLossLessPlugin >Index: jpeglossless/transupp.v8a.cpp >=================================================================== >--- jpeglossless/transupp.v8a.cpp (Revision 0) >+++ jpeglossless/transupp.v8a.cpp (Revision 1115335) >@@ -0,0 +1,1596 @@ >+/* >+ * transupp.c >+ * >+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. >+ * This file is part of the Independent JPEG Group's software. >+ * For conditions of distribution and use, see the accompanying README file. >+ * >+ * This file contains image transformation routines and other utility code >+ * used by the jpegtran sample application. These are NOT part of the core >+ * JPEG library. But we keep these routines separate from jpegtran.c to >+ * ease the task of maintaining jpegtran-like programs that have other user >+ * interfaces. >+ */ >+ >+/* Although this file really shouldn't have access to the library internals, >+ * it's helpful to let it call jround_up() and jcopy_block_row(). >+ */ >+#define JPEG_INTERNALS >+ >+// LibJPEG includes >+ >+extern "C" >+{ >+#include "jinclude.h" >+#include "jpeglib.h" >+} >+ >+// Local includes >+ >+#include "transupp.h" /* My own external interface */ >+#include <ctype.h> /* to declare isdigit() */ >+ >+namespace KIPIJPEGLossLessPlugin >+{ >+ >+#if TRANSFORMS_SUPPORTED >+ >+/* >+ * 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, >+ * 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 >+ * fastest option for images larger than main memory. >+ * >+ * The other routines require a set of destination virtual arrays, so they >+ * need twice as much memory as jpegtran normally does. The destination >+ * arrays are always written in normal scan order (top to bottom) because >+ * the virtual array manager expects this. The source arrays will be scanned >+ * in the corresponding order, which means multiple passes through the source >+ * 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 >+ * source JPEG object, and therefore should be manipulated by calling the >+ * source's memory manager. >+ * 2. The destination's component count should be used. It may be smaller >+ * than the source's when forcing to grayscale. >+ * 3. Likewise the destination's sampling factors should be used. When >+ * forcing to grayscale the destination's sampling factors will be all 1, >+ * 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. 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. >+ */ >+ >+ >+ >+LOCAL(void) >+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, x_crop_blocks; >+ int ci, k, offset_y; >+ JBLOCKARRAY buffer; >+ JCOEFPTR ptr1, ptr2; >+ JCOEF temp1, temp2; >+ jpeg_component_info *compptr; >+ >+ /* Horizontal mirroring of DCT blocks is accomplished by swapping >+ * pairs of blocks in-place. Within a DCT block, we perform horizontal >+ * mirroring by changing the signs of odd-numbered columns. >+ * Partial iMCUs at the right edge are left untouched. >+ */ >+ MCU_cols = srcinfo->output_width / >+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); >+ >+ 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]; >+ /* this unrolled loop doesn't need to know which row it's on... */ >+ for (k = 0; k < DCTSIZE2; k += 2) { >+ temp1 = *ptr1; /* swap even column */ >+ temp2 = *ptr2; >+ *ptr1++ = temp2; >+ *ptr2++ = temp1; >+ temp1 = *ptr1; /* swap odd column with sign change */ >+ temp2 = *ptr2; >+ *ptr1++ = -temp2; >+ *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->output_width / >+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); >+ >+ 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); >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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; >+ JCOEFPTR src_ptr, dst_ptr; >+ jpeg_component_info *compptr; >+ >+ /* We output into a separate array because we can't touch different >+ * rows of the source virtual array simultaneously. Otherwise, this >+ * is a pretty straightforward analog of horizontal flip. >+ * Within a DCT block, vertical mirroring is done by changing the signs >+ * of odd-numbered rows. >+ * Partial iMCUs at the bottom edge are copied verbatim. >+ */ >+ MCU_rows = srcinfo->output_height / >+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); >+ >+ 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 (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 - 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 + y_crop_blocks, >+ (JDIMENSION) compptr->v_samp_factor, FALSE); >+ } >+ for (offset_y = 0; offset_y < compptr->v_samp_factor; 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]; >+ 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]; >+ src_ptr = src_row_ptr[dst_blk_x]; >+ for (i = 0; i < DCTSIZE; i += 2) { >+ /* copy even row */ >+ for (j = 0; j < DCTSIZE; j++) >+ *dst_ptr++ = *src_ptr++; >+ /* copy odd row with sign change */ >+ for (j = 0; j < DCTSIZE; j++) >+ *dst_ptr++ = - *src_ptr++; >+ } >+ } >+ } else { >+ /* Just copy row verbatim. */ >+ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, >+ dst_buffer[offset_y], >+ compptr->width_in_blocks); >+ } >+ } >+ } >+ } >+} >+ >+ >+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, 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; >+ >+ /* Transposing pixels within a block just requires transposing the >+ * DCT coefficients. >+ * Partial iMCUs at the edges require no special treatment; we simply >+ * process all the available DCT blocks for every component. >+ */ >+ 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); >+ 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 + 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]; >+ 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]; >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. Transposing the image; >+ * 2. Horizontal mirroring. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ 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; >+ jpeg_component_info *compptr; >+ >+ /* Because of the horizontal mirror step, we can't process partial iMCUs >+ * at the (output) right edge properly. They just get transposed and >+ * not mirrored. >+ */ >+ MCU_cols = srcinfo->output_height / >+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); >+ >+ 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); >+ 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) { >+ 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++) { >+ 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. */ >+ 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]; >+ i++; >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } else { >+ /* Edge blocks are transposed but not mirrored. */ >+ 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]; >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. Horizontal mirroring; >+ * 2. Transposing the image. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ 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; >+ jpeg_component_info *compptr; >+ >+ /* Because of the horizontal mirror step, we can't process partial iMCUs >+ * at the (output) bottom edge properly. They just get transposed and >+ * not mirrored. >+ */ >+ MCU_rows = srcinfo->output_width / >+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); >+ >+ 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); >+ 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 + 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 (y_crop_blocks + dst_blk_y < comp_height) { >+ /* Block is within the mirrorable area. */ >+ 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } else { >+ /* Edge blocks are transposed but not mirrored. */ >+ 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]; >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. Vertical mirroring; >+ * 2. Horizontal mirroring. >+ * These two steps are merged into a single processing routine. >+ */ >+{ >+ 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 = srcinfo->output_width / >+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); >+ MCU_rows = srcinfo->output_height / >+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); >+ >+ 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 (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 - 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 + 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]; >+ if (y_crop_blocks + dst_blk_y < comp_height) { >+ /* Row is within the mirrorable area. */ >+ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; >+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { >+ dst_ptr = dst_row_ptr[dst_blk_x]; >+ 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++; >+ } >+ } >+ } 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++; >+ } >+ } >+ } >+ } else { >+ /* Remaining rows are just mirrored horizontally. */ >+ 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) { >+ /* 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); >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+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 >+ * 1. 180 degree rotation; >+ * 2. Transposition; >+ * or >+ * 1. Horizontal mirroring; >+ * 2. Transposition; >+ * 3. Horizontal mirroring. >+ * These steps are merged into a single processing routine. >+ */ >+{ >+ 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 = srcinfo->output_height / >+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); >+ MCU_rows = srcinfo->output_width / >+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); >+ >+ 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); >+ 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) { >+ 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++) { >+ 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. */ >+ 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ i++; >+ for (j = 0; j < DCTSIZE; j++) { >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } else { >+ /* Right-edge blocks are mirrored in y only */ >+ 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]; >+ j++; >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } >+ } >+ } else { >+ if (x_crop_blocks + dst_blk_x < comp_width) { >+ /* Bottom-edge blocks are mirrored in x only */ >+ 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]; >+ i++; >+ for (j = 0; j < DCTSIZE; j++) >+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >+ } >+ } else { >+ /* At lower right corner, just transpose, no mirroring */ >+ 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]; >+ } >+ } >+ } >+ } >+ } >+ } >+ } >+} >+ >+ >+/* 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 >+ * <width>x<height>{+-}<xoffset>{+-}<yoffset> >+ * 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->iMCU_sample_width; >+ if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == >+ full_width / info->iMCU_sample_width) >+ info->output_width = MCU_cols * info->iMCU_sample_width; >+} >+ >+LOCAL(void) >+trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) >+{ >+ JDIMENSION MCU_rows; >+ >+ MCU_rows = info->output_height / info->iMCU_sample_height; >+ if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == >+ full_height / info->iMCU_sample_height) >+ info->output_height = MCU_rows * info->iMCU_sample_height; >+} >+ >+ >+/* 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. >+ * Hence, this routine must be called after jpeg_read_header (which reads >+ * the image dimensions) and before jpeg_read_coefficients (which realizes >+ * the source's virtual arrays). >+ * >+ * This function returns FALSE right away if -perfect is given >+ * and transformation is not perfect. Otherwise returns TRUE. >+ */ >+ >+GLOBAL(boolean) >+jtransform_request_workspace (j_decompress_ptr srcinfo, >+ jpeg_transform_info *info) >+{ >+ jvirt_barray_ptr *coef_arrays; >+ boolean need_workspace, transpose_it; >+ jpeg_component_info *compptr; >+ JDIMENSION xoffset, yoffset; >+ JDIMENSION 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) >+ /* We'll only process the first component */ >+ info->num_components = 1; >+ else >+ /* Process all the components */ >+ info->num_components = srcinfo->num_components; >+ >+ /* Compute output image dimensions and related values. */ >+ jpeg_core_output_dimensions(srcinfo); >+ >+ /* Return right away if -perfect is given and transformation is not perfect. >+ */ >+ if (info->perfect) { >+ if (info->num_components == 1) { >+ if (!jtransform_perfect_transform(srcinfo->output_width, >+ srcinfo->output_height, >+ srcinfo->min_DCT_h_scaled_size, >+ srcinfo->min_DCT_v_scaled_size, >+ info->transform)) >+ return FALSE; >+ } else { >+ if (!jtransform_perfect_transform(srcinfo->output_width, >+ srcinfo->output_height, >+ srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size, >+ srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size, >+ info->transform)) >+ return FALSE; >+ } >+ } >+ >+ /* 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->output_height; >+ info->output_height = srcinfo->output_width; >+ if (info->num_components == 1) { >+ info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size; >+ info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size; >+ } else { >+ info->iMCU_sample_width = >+ srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; >+ info->iMCU_sample_height = >+ srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; >+ } >+ break; >+ default: >+ info->output_width = srcinfo->output_width; >+ info->output_height = srcinfo->output_height; >+ if (info->num_components == 1) { >+ info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size; >+ info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size; >+ } else { >+ info->iMCU_sample_width = >+ srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; >+ info->iMCU_sample_height = >+ srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; >+ } >+ 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->iMCU_sample_width); >+ info->output_height = >+ info->crop_height + (yoffset % info->iMCU_sample_height); >+ /* Save x/y offsets measured in iMCUs */ >+ info->x_crop_offset = xoffset / info->iMCU_sample_width; >+ info->y_crop_offset = yoffset / info->iMCU_sample_height; >+ } 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: >+ if (info->trim) >+ trim_right_edge(info, srcinfo->output_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: >+ if (info->trim) >+ trim_bottom_edge(info, srcinfo->output_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->output_height); >+ trim_bottom_edge(info, srcinfo->output_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->output_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->output_width); >+ trim_bottom_edge(info, srcinfo->output_height); >+ } >+ /* Need workspace arrays having same dimensions as source image. */ >+ need_workspace = TRUE; >+ break; >+ case JXFORM_ROT_270: >+ if (info->trim) >+ trim_bottom_edge(info, srcinfo->output_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); >+ width_in_iMCUs = (JDIMENSION) >+ jdiv_round_up((long) info->output_width, >+ (long) info->iMCU_sample_width); >+ height_in_iMCUs = (JDIMENSION) >+ jdiv_round_up((long) info->output_height, >+ (long) info->iMCU_sample_height); >+ 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, >+ width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); >+ } >+ info->workspace_coef_arrays = coef_arrays; >+ } else >+ info->workspace_coef_arrays = NULL; >+ >+ return TRUE; >+} >+ >+ >+/* Transpose destination image parameters */ >+ >+LOCAL(void) >+transpose_critical_parameters (j_compress_ptr dstinfo) >+{ >+ int tblno, i, j, ci, itemp; >+ jpeg_component_info *compptr; >+ JQUANT_TBL *qtblptr; >+ JDIMENSION jtemp; >+ UINT16 qtemp; >+ >+ /* Transpose image dimensions */ >+ jtemp = dstinfo->image_width; >+ dstinfo->image_width = dstinfo->image_height; >+ dstinfo->image_height = jtemp; >+ itemp = dstinfo->min_DCT_h_scaled_size; >+ dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; >+ dstinfo->min_DCT_v_scaled_size = itemp; >+ >+ /* Transpose sampling factors */ >+ for (ci = 0; ci < dstinfo->num_components; ci++) { >+ compptr = dstinfo->comp_info + ci; >+ itemp = compptr->h_samp_factor; >+ compptr->h_samp_factor = compptr->v_samp_factor; >+ compptr->v_samp_factor = itemp; >+ } >+ >+ /* Transpose quantization tables */ >+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { >+ qtblptr = dstinfo->quant_tbl_ptrs[tblno]; >+ if (qtblptr != NULL) { >+ for (i = 0; i < DCTSIZE; i++) { >+ for (j = 0; j < i; j++) { >+ qtemp = qtblptr->quantval[i*DCTSIZE+j]; >+ qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; >+ qtblptr->quantval[j*DCTSIZE+i] = qtemp; >+ } >+ } >+ } >+ } >+} >+ >+ >+/* Adjust Exif image parameters. >+ * >+ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. >+ */ >+ >+LOCAL(void) >+adjust_exif_parameters (JOCTET FAR * data, unsigned int length, >+ JDIMENSION new_width, JDIMENSION new_height) >+{ >+ 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; >+ } >+ >+ /* 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]); >+ } >+ if (firstoffset > length - 2) return; /* check end of data segment */ >+ >+ /* 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; >+ >+ /* 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; >+ } >+ >+ /* 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); >+} >+ >+ >+/* Adjust output image parameters as needed. >+ * >+ * This must be called after jpeg_copy_critical_parameters() >+ * and before jpeg_write_coefficients(). >+ * >+ * The return value is the set of virtual coefficient arrays to be written >+ * (either the ones allocated by jtransform_request_workspace, or the >+ * original source data arrays). The caller will need to pass this value >+ * to jpeg_write_coefficients(). >+ */ >+ >+GLOBAL(jvirt_barray_ptr *) >+jtransform_adjust_parameters (j_decompress_ptr srcinfo, >+ j_compress_ptr dstinfo, >+ jvirt_barray_ptr *src_coef_arrays, >+ jpeg_transform_info *info) >+{ >+ /* If force-to-grayscale is requested, adjust destination parameters */ >+ if (info->force_grayscale) { >+ /* 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)) && >+ 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; >+ } else { >+ /* 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 as necessary >+ * for rotate/flip, resize, and crop operations. >+ */ >+ dstinfo->jpeg_width = info->output_width; >+ dstinfo->jpeg_height = info->output_height; >+ >+ /* Transpose destination image parameters */ >+ switch (info->transform) { >+ case JXFORM_TRANSPOSE: >+ case JXFORM_TRANSVERSE: >+ case JXFORM_ROT_90: >+ case JXFORM_ROT_270: >+ transpose_critical_parameters(dstinfo); >+ break; >+ default: >+ 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->jpeg_width != srcinfo->image_width || >+ dstinfo->jpeg_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->jpeg_width, dstinfo->jpeg_height); >+ } >+ >+ /* Return the appropriate output data set */ >+ if (info->workspace_coef_arrays != NULL) >+ return info->workspace_coef_arrays; >+ return src_coef_arrays; >+} >+ >+ >+/* Execute the actual transformation, if any. >+ * >+ * This must be called *after* jpeg_write_coefficients, because it depends >+ * on jpeg_write_coefficients to have computed subsidiary values such as >+ * the per-component width and height fields in the destination object. >+ * >+ * Note that some transformations will modify the source data arrays! >+ */ >+ >+GLOBAL(void) >+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: >+ 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, info->x_crop_offset, info->y_crop_offset, >+ src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_TRANSPOSE: >+ 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, info->x_crop_offset, info->y_crop_offset, >+ src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_90: >+ 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, info->x_crop_offset, info->y_crop_offset, >+ src_coef_arrays, dst_coef_arrays); >+ break; >+ case JXFORM_ROT_270: >+ 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 * cinfo.block_size >+ * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size >+ * 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; >+ default: >+ break; >+ } >+ >+ return result; >+} >+ >+#endif /* TRANSFORMS_SUPPORTED */ >+ >+ >+/* Setup decompression object to save desired markers in memory. >+ * This must be called before jpeg_read_header() to have the desired effect. >+ */ >+ >+GLOBAL(void) >+jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) >+{ >+#ifdef SAVE_MARKERS_SUPPORTED >+ int m; >+ >+ /* Save comments except under NONE option */ >+ if (option != JCOPYOPT_NONE) { >+ jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); >+ } >+ /* Save all types of APPn markers iff ALL option */ >+ if (option == JCOPYOPT_ALL) { >+ for (m = 0; m < 16; m++) >+ jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); >+ } >+#endif /* SAVE_MARKERS_SUPPORTED */ >+} >+ >+/* Copy markers saved in the given source object to the destination object. >+ * This should be called just after jpeg_start_compress() or >+ * jpeg_write_coefficients(). >+ * Note that those routines will have written the SOI, and also the >+ * JFIF APP0 or Adobe APP14 markers if selected. >+ */ >+ >+GLOBAL(void) >+jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >+ JCOPY_OPTION /*option*/) >+{ >+ jpeg_saved_marker_ptr marker; >+ >+ /* In the current implementation, we don't actually need to examine the >+ * option flag here; we just copy everything that got saved. >+ * But to avoid confusion, we do not output JFIF and Adobe APP14 markers >+ * if the encoder library already wrote one. >+ */ >+ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { >+ if (dstinfo->write_JFIF_header && >+ marker->marker == JPEG_APP0 && >+ marker->data_length >= 5 && >+ GETJOCTET(marker->data[0]) == 0x4A && >+ GETJOCTET(marker->data[1]) == 0x46 && >+ GETJOCTET(marker->data[2]) == 0x49 && >+ GETJOCTET(marker->data[3]) == 0x46 && >+ GETJOCTET(marker->data[4]) == 0) >+ continue; /* reject duplicate JFIF */ >+ if (dstinfo->write_Adobe_marker && >+ marker->marker == JPEG_APP0+14 && >+ marker->data_length >= 5 && >+ GETJOCTET(marker->data[0]) == 0x41 && >+ GETJOCTET(marker->data[1]) == 0x64 && >+ GETJOCTET(marker->data[2]) == 0x6F && >+ GETJOCTET(marker->data[3]) == 0x62 && >+ GETJOCTET(marker->data[4]) == 0x65) >+ continue; /* reject duplicate Adobe */ >+#ifdef NEED_FAR_POINTERS >+ /* We could use jpeg_write_marker if the data weren't FAR... */ >+ { >+ unsigned int i; >+ jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); >+ for (i = 0; i < marker->data_length; i++) >+ jpeg_write_m_byte(dstinfo, marker->data[i]); >+ } >+#else >+ jpeg_write_marker(dstinfo, marker->marker, >+ marker->data, marker->data_length); >+#endif >+ } >+} >+ >+} // namespace KIPIJPEGLossLessPlugin >Index: jpeglossless/transupp.cpp >=================================================================== >--- jpeglossless/transupp.cpp (Revision 1115334) >+++ jpeglossless/transupp.cpp (Revision 1115335) >@@ -1,7 +1,7 @@ > /* >- * transupp.c >+ * transupp.cpp > * >- * Copyright (C) 1997, Thomas G. Lane. >+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. > * This file is part of the Independent JPEG Group's software. > * For conditions of distribution and use, see the accompanying README file. > * >@@ -25,916 +25,16 @@ > #include "jpeglib.h" > } > >-// Local includes >+// transupp.c appears to be tied rather tightly to the library version. >+// For example, the one from libjpeg v6b will not work properly with >+// libjpeg v8. So include the correct one for the current version of >+// libjpeg. > >-#include "transupp.h" /* My own external interface */ >- >-namespace KIPIJPEGLossLessPlugin >-{ >- >-#if TRANSFORMS_SUPPORTED >- >-/* >- * 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. >- * >- * Horizontal flipping is done in-place, using a single top-to-bottom >- * pass through the virtual source array. It will thus be much the >- * fastest option for images larger than main memory. >- * >- * The other routines require a set of destination virtual arrays, so they >- * need twice as much memory as jpegtran normally does. The destination >- * arrays are always written in normal scan order (top to bottom) because >- * the virtual array manager expects this. The source arrays will be scanned >- * in the corresponding order, which means multiple passes through the source >- * arrays for most of the transforms. That could result in much thrashing >- * if the image is larger than main memory. >- * >- * Some notes about the operating environment of the individual transform >- * routines: >- * 1. Both the source and destination virtual arrays are allocated from the >- * source JPEG object, and therefore should be manipulated by calling the >- * source's memory manager. >- * 2. The destination's component count should be used. It may be smaller >- * than the source's when forcing to grayscale. >- * 3. Likewise the destination's sampling factors should be used. When >- * forcing to grayscale the destination's sampling factors will be all 1, >- * 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 >- * 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 */ >-{ >- JDIMENSION MCU_cols, comp_width, blk_x, blk_y; >- int ci, k, offset_y; >- JBLOCKARRAY buffer; >- JCOEFPTR ptr1, ptr2; >- JCOEF temp1, temp2; >- jpeg_component_info *compptr; >- >- /* Horizontal mirroring of DCT blocks is accomplished by swapping >- * pairs of blocks in-place. Within a DCT block, we perform horizontal >- * 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); >- >- for (ci = 0; ci < dstinfo->num_components; ci++) { >- compptr = dstinfo->comp_info + ci; >- comp_width = MCU_cols * 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++) { >- 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]; >- /* this unrolled loop doesn't need to know which row it's on... */ >- for (k = 0; k < DCTSIZE2; k += 2) { >- temp1 = *ptr1; /* swap even column */ >- temp2 = *ptr2; >- *ptr1++ = temp2; >- *ptr2++ = temp1; >- temp1 = *ptr1; /* swap odd column with sign change */ >- temp2 = *ptr2; >- *ptr1++ = -temp2; >- *ptr2++ = -temp1; >- } >- } >- } >- } >- } >-} >- >- >-LOCAL(void) >-do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- 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; >- 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; >- >- /* We output into a separate array because we can't touch different >- * rows of the source virtual array simultaneously. Otherwise, this >- * is a pretty straightforward analog of horizontal flip. >- * Within a DCT block, vertical mirroring is done by changing the signs >- * of odd-numbered rows. >- * Partial iMCUs at the bottom edge are copied verbatim. >- */ >- MCU_rows = dstinfo->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; >- 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) { >- /* 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, >- (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, >- (JDIMENSION) compptr->v_samp_factor, FALSE); >- } >- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { >- if (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]; >- 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[dst_blk_x]; >- for (i = 0; i < DCTSIZE; i += 2) { >- /* copy even row */ >- for (j = 0; j < DCTSIZE; j++) >- *dst_ptr++ = *src_ptr++; >- /* copy odd row with sign change */ >- for (j = 0; j < DCTSIZE; j++) >- *dst_ptr++ = - *src_ptr++; >- } >- } >- } else { >- /* Just copy row verbatim. */ >- jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], >- compptr->width_in_blocks); >- } >- } >- } >- } >-} >- >- >-LOCAL(void) >-do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- jvirt_barray_ptr *src_coef_arrays, >- jvirt_barray_ptr *dst_coef_arrays) >-/* Transpose source into destination */ >-{ >- JDIMENSION dst_blk_x, dst_blk_y; >- int ci, i, j, offset_x, offset_y; >- JBLOCKARRAY src_buffer, dst_buffer; >- JCOEFPTR src_ptr, dst_ptr; >- jpeg_component_info *compptr; >- >- /* Transposing pixels within a block just requires transposing the >- * DCT coefficients. >- * Partial iMCUs at the edges require no special treatment; we simply >- * process all the available DCT blocks for every component. >- */ >- for (ci = 0; ci < dstinfo->num_components; ci++) { >- compptr = dstinfo->comp_info + ci; >- 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); >- 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); >- 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]; >- for (i = 0; i < DCTSIZE; i++) >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- } >- } >- } >- } >- } >-} >- >- >-LOCAL(void) >-do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- jvirt_barray_ptr *src_coef_arrays, >- jvirt_barray_ptr *dst_coef_arrays) >-/* 90 degree rotation is equivalent to >- * 1. Transposing the image; >- * 2. Horizontal mirroring. >- * These two steps are merged into a single processing routine. >- */ >-{ >- JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; >- int ci, i, j, offset_x, offset_y; >- JBLOCKARRAY src_buffer, dst_buffer; >- JCOEFPTR src_ptr, dst_ptr; >- jpeg_component_info *compptr; >- >- /* Because of the horizontal mirror step, we can't process partial iMCUs >- * at the (output) right edge properly. They just get transposed and >- * not mirrored. >- */ >- MCU_cols = dstinfo->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; >- 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); >- 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); >- 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) { >- /* Block is within the mirrorable area. */ >- dst_ptr = dst_buffer[offset_y] >- [comp_width - dst_blk_x - offset_x - 1]; >- for (i = 0; i < DCTSIZE; i++) { >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- i++; >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >- } >- } else { >- /* Edge blocks are transposed but not mirrored. */ >- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; >- for (i = 0; i < DCTSIZE; i++) >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- } >- } >- } >- } >- } >- } >-} >- >- >-LOCAL(void) >-do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- jvirt_barray_ptr *src_coef_arrays, >- jvirt_barray_ptr *dst_coef_arrays) >-/* 270 degree rotation is equivalent to >- * 1. Horizontal mirroring; >- * 2. Transposing the image. >- * These two steps are merged into a single processing routine. >- */ >-{ >- JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; >- int ci, i, j, offset_x, offset_y; >- JBLOCKARRAY src_buffer, dst_buffer; >- JCOEFPTR src_ptr, dst_ptr; >- jpeg_component_info *compptr; >- >- /* Because of the horizontal mirror step, we can't process partial iMCUs >- * at the (output) bottom edge properly. They just get transposed and >- * not mirrored. >- */ >- MCU_rows = dstinfo->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; >- 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); >- 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); >- 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) { >- /* Block is within the mirrorable area. */ >- src_ptr = src_buffer[offset_x] >- [comp_height - 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]; >- j++; >- dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >- } >- } >- } else { >- /* Edge blocks are transposed but not mirrored. */ >- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; >- for (i = 0; i < DCTSIZE; i++) >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- } >- } >- } >- } >- } >- } >-} >- >- >-LOCAL(void) >-do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- jvirt_barray_ptr *src_coef_arrays, >- jvirt_barray_ptr *dst_coef_arrays) >-/* 180 degree rotation is equivalent to >- * 1. Vertical mirroring; >- * 2. Horizontal mirroring. >- * These two steps are merged into a single processing routine. >- */ >-{ >- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; >- 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); >- >- 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; >- 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) { >- /* 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, >- (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, >- (JDIMENSION) compptr->v_samp_factor, FALSE); >- } >- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { >- if (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++) { >- 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++; >- } >- /* For odd row, negate every even column. */ >- for (j = 0; j < DCTSIZE; j += 2) { >- *dst_ptr++ = - *src_ptr++; >- *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++; >- } >- } >- /* 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++; >- } >- } >- } >- } >- } >-} >- >- >-LOCAL(void) >-do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- jvirt_barray_ptr *src_coef_arrays, >- jvirt_barray_ptr *dst_coef_arrays) >-/* Transverse transpose is equivalent to >- * 1. 180 degree rotation; >- * 2. Transposition; >- * or >- * 1. Horizontal mirroring; >- * 2. Transposition; >- * 3. Horizontal mirroring. >- * These steps are merged into a single processing routine. >- */ >-{ >- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; >- 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); >- >- 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; >- 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); >- 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); >- 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) { >- /* Block is within the mirrorable area. */ >- dst_ptr = dst_buffer[offset_y] >- [comp_width - dst_blk_x - offset_x - 1]; >- for (i = 0; i < DCTSIZE; i++) { >- for (j = 0; j < DCTSIZE; j++) { >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- j++; >- dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >- } >- i++; >- for (j = 0; j < DCTSIZE; j++) { >- dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >- j++; >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- } >- } >- } else { >- /* Right-edge blocks are mirrored in y only */ >- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; >- for (i = 0; i < DCTSIZE; i++) { >- for (j = 0; j < DCTSIZE; j++) { >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- j++; >- dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >- } >- } >- } >- } else { >- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; >- if (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]; >- for (i = 0; i < DCTSIZE; i++) { >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- i++; >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; >- } >- } else { >- /* At lower right corner, just transpose, no mirroring */ >- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; >- for (i = 0; i < DCTSIZE; i++) >- for (j = 0; j < DCTSIZE; j++) >- dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; >- } >- } >- } >- } >- } >- } >- } >-} >- >- >-/* Request any required workspace. >- * >- * 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. >- * Hence, this routine must be called after jpeg_read_header (which reads >- * the image dimensions) and before jpeg_read_coefficients (which realizes >- * the source's virtual arrays). >- */ >- >-GLOBAL(void) >-jtransform_request_workspace (j_decompress_ptr srcinfo, >- jpeg_transform_info *info) >-{ >- jvirt_barray_ptr *coef_arrays = NULL; >- jpeg_component_info *compptr; >- int ci; >- >- if (info->force_grayscale && >- srcinfo->jpeg_color_space == JCS_YCbCr && >- srcinfo->num_components == 3) { >- /* We'll only process the first component */ >- info->num_components = 1; >- } else { >- /* Process all the components */ >- info->num_components = srcinfo->num_components; >- } >- >- switch (info->transform) { >- case JXFORM_NONE: >- case JXFORM_FLIP_H: >- /* Don'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); >- } >- break; >- case JXFORM_TRANSPOSE: >- case JXFORM_TRANSVERSE: >- case JXFORM_ROT_90: >- 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. >- */ >- 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->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); >- } >- break; >- } >- info->workspace_coef_arrays = coef_arrays; >-} >- >- >-/* Transpose destination image parameters */ >- >-LOCAL(void) >-transpose_critical_parameters (j_compress_ptr dstinfo) >-{ >- 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; >- itemp = compptr->h_samp_factor; >- compptr->h_samp_factor = compptr->v_samp_factor; >- compptr->v_samp_factor = itemp; >- } >- >- /* Transpose quantization tables */ >- for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { >- qtblptr = dstinfo->quant_tbl_ptrs[tblno]; >- if (qtblptr != NULL) { >- for (i = 0; i < DCTSIZE; i++) { >- for (j = 0; j < i; j++) { >- qtemp = qtblptr->quantval[i*DCTSIZE+j]; >- qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; >- qtblptr->quantval[j*DCTSIZE+i] = qtemp; >- } >- } >- } >- } >-} >- >- >-/* Trim off any partial iMCUs on the indicated destination edge */ >- >-LOCAL(void) >-trim_right_edge (j_compress_ptr dstinfo) >-{ >- int ci, max_h_samp_factor; >- JDIMENSION MCU_cols; >- >- /* 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); >- } >- 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); >-} >- >-LOCAL(void) >-trim_bottom_edge (j_compress_ptr dstinfo) >-{ >- int ci, max_v_samp_factor; >- JDIMENSION MCU_rows; >- >- /* 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); >- } >- 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); >-} >- >- >-/* Adjust output image parameters as needed. >- * >- * This must be called after jpeg_copy_critical_parameters() >- * and before jpeg_write_coefficients(). >- * >- * The return value is the set of virtual coefficient arrays to be written >- * (either the ones allocated by jtransform_request_workspace, or the >- * original source data arrays). The caller will need to pass this value >- * to jpeg_write_coefficients(). >- */ >- >-GLOBAL(jvirt_barray_ptr *) >-jtransform_adjust_parameters (j_decompress_ptr /*srcinfo*/, >- j_compress_ptr dstinfo, >- jvirt_barray_ptr *src_coef_arrays, >- jpeg_transform_info *info) >-{ >- /* 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.) >- */ >- 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. */ >- 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; >- } else { >- /* Sorry, can't do it */ >- ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); >- } >- } >- >- /* Correct the destination's image dimensions etc if necessary */ >- 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; >- } >- >- /* Return the appropriate output data set */ >- if (info->workspace_coef_arrays != NULL) >- return info->workspace_coef_arrays; >- return src_coef_arrays; >-} >- >- >-/* Execute the actual transformation, if any. >- * >- * This must be called *after* jpeg_write_coefficients, because it depends >- * on jpeg_write_coefficients to have computed subsidiary values such as >- * the per-component width and height fields in the destination object. >- * >- * Note that some transformations will modify the source data arrays! >- */ >- >-GLOBAL(void) >-jtransform_execute_transformation (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; >- >- switch (info->transform) { >- case JXFORM_NONE: >- break; >- case JXFORM_FLIP_H: >- do_flip_h(srcinfo, dstinfo, src_coef_arrays); >- break; >- case JXFORM_FLIP_V: >- do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >- break; >- case JXFORM_TRANSPOSE: >- do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >- break; >- case JXFORM_TRANSVERSE: >- do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >- break; >- case JXFORM_ROT_90: >- do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >- break; >- case JXFORM_ROT_180: >- do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >- break; >- case JXFORM_ROT_270: >- do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); >- break; >- } >-} >- >-#endif /* TRANSFORMS_SUPPORTED */ >- >- >-/* Setup decompression object to save desired markers in memory. >- * This must be called before jpeg_read_header() to have the desired effect. >- */ >- >-GLOBAL(void) >-jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) >-{ >-#ifdef SAVE_MARKERS_SUPPORTED >- int m; >- >- /* Save comments except under NONE option */ >- if (option != JCOPYOPT_NONE) { >- jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); >- } >- /* Save all types of APPn markers iff ALL option */ >- if (option == JCOPYOPT_ALL) { >- for (m = 0; m < 16; m++) >- jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); >- } >-#endif /* SAVE_MARKERS_SUPPORTED */ >-} >- >-/* Copy markers saved in the given source object to the destination object. >- * This should be called just after jpeg_start_compress() or >- * jpeg_write_coefficients(). >- * Note that those routines will have written the SOI, and also the >- * JFIF APP0 or Adobe APP14 markers if selected. >- */ >- >-GLOBAL(void) >-jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, >- JCOPY_OPTION /*option*/) >-{ >- jpeg_saved_marker_ptr marker; >- >- /* In the current implementation, we don't actually need to examine the >- * option flag here; we just copy everything that got saved. >- * But to avoid confusion, we do not output JFIF and Adobe APP14 markers >- * if the encoder library already wrote one. >- */ >- for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { >- if (dstinfo->write_JFIF_header && >- marker->marker == JPEG_APP0 && >- marker->data_length >= 5 && >- GETJOCTET(marker->data[0]) == 0x4A && >- GETJOCTET(marker->data[1]) == 0x46 && >- GETJOCTET(marker->data[2]) == 0x49 && >- GETJOCTET(marker->data[3]) == 0x46 && >- GETJOCTET(marker->data[4]) == 0) >- continue; /* reject duplicate JFIF */ >- if (dstinfo->write_Adobe_marker && >- marker->marker == JPEG_APP0+14 && >- marker->data_length >= 5 && >- GETJOCTET(marker->data[0]) == 0x41 && >- GETJOCTET(marker->data[1]) == 0x64 && >- GETJOCTET(marker->data[2]) == 0x6F && >- GETJOCTET(marker->data[3]) == 0x62 && >- GETJOCTET(marker->data[4]) == 0x65) >- continue; /* reject duplicate Adobe */ >-#ifdef NEED_FAR_POINTERS >- /* We could use jpeg_write_marker if the data weren't FAR... */ >- { >- unsigned int i; >- jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); >- for (i = 0; i < marker->data_length; i++) >- jpeg_write_m_byte(dstinfo, marker->data[i]); >- } >+#if JPEG_LIB_VERSION < 70 >+#include "transupp.v6b.cpp" >+#elif JPEG_LIB_VERSION < 80 >+#include "transupp.v7.cpp" > #else >- jpeg_write_marker(dstinfo, marker->marker, >- marker->data, marker->data_length); >+#include "transupp.v8a.cpp" > #endif >- } >-} > >-} // namespace KIPIJPEGLossLessPlugin >Index: jpeglossless/jpegtransform.cpp >=================================================================== >--- jpeglossless/jpegtransform.cpp (Revision 1115334) >+++ jpeglossless/jpegtransform.cpp (Revision 1115335) >@@ -189,8 +189,10 @@ > JCOPY_OPTION copyoption = JCOPYOPT_ALL; > jpeg_transform_info transformoption; > >+ transformoption.perfect = false; > transformoption.force_grayscale = false; > transformoption.trim = false; >+ transformoption.crop = false; > > struct jpeg_decompress_struct srcinfo; > struct jpeg_compress_struct dstinfo; >Index: jpeglossless/transupp.h >=================================================================== >--- jpeglossless/transupp.h (Revision 1115334) >+++ jpeglossless/transupp.h (Revision 1115335) >@@ -1,7 +1,7 @@ > /* > * transupp.h > * >- * Copyright (C) 1997, Thomas G. Lane. >+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. > * This file is part of the Independent JPEG Group's software. > * For conditions of distribution and use, see the accompanying README file. > * >@@ -25,36 +25,10 @@ > > /* If you happen not to want the image transform support, disable it here */ > #ifndef TRANSFORMS_SUPPORTED >-#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ >+#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 > * whose dimensions aren't multiples of the iMCU size. The right and bottom >@@ -81,6 +55,24 @@ > * (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.) >+ * >+ * We also provide a lossless-resize option, which is kind of a lossless-crop >+ * operation in the DCT coefficient block domain - it discards higher-order >+ * coefficients and losslessly preserves lower-order coefficients of a >+ * sub-block. >+ * >+ * Rotate/flip transform, resize, and crop can be requested together in a >+ * single invocation. The crop is applied last --- that is, the crop region >+ * is specified in terms of the destination image after transform/resize. >+ * > * 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 >@@ -89,22 +81,94 @@ > * 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 iMCU_sample_width; /* destination iMCU size */ >+ int iMCU_sample_height; > } jpeg_transform_info; > > > #if TRANSFORMS_SUPPORTED > >+#if 0 >+// requires libjpeg v7+, so disabled until we require that version >+/* Parse a crop specification (written in X11 geometry style) */ >+EXTERN(boolean) jtransform_parse_crop_spec >+ JPP((jpeg_transform_info *info, const char *spec)); >+#endif > /* Request any required workspace */ >-EXTERN(void) jtransform_request_workspace >+EXTERN(boolean) jtransform_request_workspace > JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); > /* Adjust output image parameters */ > EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters >@@ -112,11 +176,25 @@ > 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 */ > >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 306679
:
221563
|
231937
| 231941