| /* |
| * 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 |
| } |
| } |