Index: third_party/libjpeg_turbo/transupp.c |
=================================================================== |
--- third_party/libjpeg_turbo/transupp.c (revision 0) |
+++ third_party/libjpeg_turbo/transupp.c (revision 0) |
@@ -0,0 +1,928 @@ |
+/* |
+ * 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. |
+ */ |
+ |
+/* 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 |
+ |
+#include "jinclude.h" |
+#include "jpeglib.h" |
+#include "transupp.h" /* My own external interface */ |
+ |
+ |
+#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]); |
+ } |
+#else |
+ jpeg_write_marker(dstinfo, marker->marker, |
+ marker->data, marker->data_length); |
+#endif |
+ } |
+} |