Index: third_party/libjpeg_turbo/transupp.c |
=================================================================== |
--- third_party/libjpeg_turbo/transupp.c (revision 95020) |
+++ third_party/libjpeg_turbo/transupp.c (working copy) |
@@ -1,7 +1,8 @@ |
/* |
* transupp.c |
* |
- * Copyright (C) 1997, Thomas G. Lane. |
+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. |
+ * Copyright (C) 2010, D. R. Commander. |
* This file is part of the Independent JPEG Group's software. |
* For conditions of distribution and use, see the accompanying README file. |
* |
@@ -20,15 +21,27 @@ |
#include "jinclude.h" |
#include "jpeglib.h" |
#include "transupp.h" /* My own external interface */ |
+#include "jpegcomp.h" |
+#include <ctype.h> /* to declare isdigit() */ |
+#if JPEG_LIB_VERSION >= 70 |
+#define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size |
+#define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size |
+#else |
+#define dstinfo_min_DCT_h_scaled_size DCTSIZE |
+#define dstinfo_min_DCT_v_scaled_size DCTSIZE |
+#endif |
+ |
+ |
#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. |
+ * Thanks to Guido Vollbeding for the initial design and code of this feature, |
+ * and to Ben Jackson for introducing the cropping feature. |
* |
* Horizontal flipping is done in-place, using a single top-to-bottom |
* pass through the virtual source array. It will thus be much the |
@@ -42,6 +55,13 @@ |
* arrays for most of the transforms. That could result in much thrashing |
* if the image is larger than main memory. |
* |
+ * If cropping or trimming is involved, the destination arrays may be smaller |
+ * than the source arrays. Note it is not possible to do horizontal flip |
+ * in-place when a nonzero Y crop offset is specified, since we'd have to move |
+ * data from one block row to another but the virtual array manager doesn't |
+ * guarantee we can touch more than one row at a time. So in that case, |
+ * we have to use a separate destination array. |
+ * |
* Some notes about the operating environment of the individual transform |
* routines: |
* 1. Both the source and destination virtual arrays are allocated from the |
@@ -54,20 +74,65 @@ |
* and we may as well take that as the effective iMCU size. |
* 4. When "trim" is in effect, the destination's dimensions will be the |
* trimmed values but the source's will be untrimmed. |
- * 5. All the routines assume that the source and destination buffers are |
+ * 5. When "crop" is in effect, the destination's dimensions will be the |
+ * cropped values but the source's will be uncropped. Each transform |
+ * routine is responsible for picking up source data starting at the |
+ * correct X and Y offset for the crop region. (The X and Y offsets |
+ * passed to the transform routines are measured in iMCU blocks of the |
+ * destination.) |
+ * 6. All the routines assume that the source and destination buffers are |
* padded out to a full iMCU boundary. This is true, although for the |
* source buffer it is an undocumented property of jdcoefct.c. |
- * Notes 2,3,4 boil down to this: generally we should use the destination's |
- * dimensions and ignore the source's. |
*/ |
LOCAL(void) |
-do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
- jvirt_barray_ptr *src_coef_arrays) |
-/* Horizontal flip; done in-place, so no separate dest array is required */ |
+do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
+ jvirt_barray_ptr *src_coef_arrays, |
+ jvirt_barray_ptr *dst_coef_arrays) |
+/* Crop. This is only used when no rotate/flip is requested with the crop. */ |
{ |
- JDIMENSION MCU_cols, comp_width, blk_x, blk_y; |
+ 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; |
@@ -79,17 +144,20 @@ |
* mirroring by changing the signs of odd-numbered columns. |
* Partial iMCUs at the right edge are left untouched. |
*/ |
- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); |
+ MCU_cols = srcinfo->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]; |
@@ -105,6 +173,18 @@ |
*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); |
+ } |
+ } |
} |
} |
} |
@@ -112,12 +192,76 @@ |
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; |
@@ -131,33 +275,39 @@ |
* of odd-numbered rows. |
* Partial iMCUs at the bottom edge are copied verbatim. |
*/ |
- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); |
+ MCU_rows = srcinfo->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 (dst_blk_y < comp_height) { |
+ if (y_crop_blocks + dst_blk_y < comp_height) { |
/* Row is within the mirrorable area. */ |
src_buffer = (*srcinfo->mem->access_virt_barray) |
((j_common_ptr) srcinfo, src_coef_arrays[ci], |
- comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, |
+ comp_height - y_crop_blocks - dst_blk_y - |
+ (JDIMENSION) compptr->v_samp_factor, |
(JDIMENSION) compptr->v_samp_factor, FALSE); |
} else { |
/* Bottom-edge blocks will be copied verbatim. */ |
src_buffer = (*srcinfo->mem->access_virt_barray) |
- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ dst_blk_y + y_crop_blocks, |
(JDIMENSION) compptr->v_samp_factor, FALSE); |
} |
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
- if (dst_blk_y < comp_height) { |
+ if (y_crop_blocks + dst_blk_y < comp_height) { |
/* Row is within the mirrorable area. */ |
dst_row_ptr = dst_buffer[offset_y]; |
src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; |
+ src_row_ptr += x_crop_blocks; |
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
dst_blk_x++) { |
dst_ptr = dst_row_ptr[dst_blk_x]; |
@@ -173,7 +323,8 @@ |
} |
} else { |
/* Just copy row verbatim. */ |
- jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], |
+ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, |
+ dst_buffer[offset_y], |
compptr->width_in_blocks); |
} |
} |
@@ -184,11 +335,12 @@ |
LOCAL(void) |
do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
jvirt_barray_ptr *src_coef_arrays, |
jvirt_barray_ptr *dst_coef_arrays) |
/* Transpose source into destination */ |
{ |
- JDIMENSION dst_blk_x, dst_blk_y; |
+ JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; |
int ci, i, j, offset_x, offset_y; |
JBLOCKARRAY src_buffer, dst_buffer; |
JCOEFPTR src_ptr, dst_ptr; |
@@ -201,6 +353,8 @@ |
*/ |
for (ci = 0; ci < dstinfo->num_components; ci++) { |
compptr = dstinfo->comp_info + ci; |
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
dst_blk_y += compptr->v_samp_factor) { |
dst_buffer = (*srcinfo->mem->access_virt_barray) |
@@ -210,11 +364,12 @@ |
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
dst_blk_x += compptr->h_samp_factor) { |
src_buffer = (*srcinfo->mem->access_virt_barray) |
- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ dst_blk_x + x_crop_blocks, |
(JDIMENSION) compptr->h_samp_factor, FALSE); |
for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; |
dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
+ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; |
for (i = 0; i < DCTSIZE; i++) |
for (j = 0; j < DCTSIZE; j++) |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -228,6 +383,7 @@ |
LOCAL(void) |
do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
jvirt_barray_ptr *src_coef_arrays, |
jvirt_barray_ptr *dst_coef_arrays) |
/* 90 degree rotation is equivalent to |
@@ -237,6 +393,7 @@ |
*/ |
{ |
JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; |
+ JDIMENSION x_crop_blocks, y_crop_blocks; |
int ci, i, j, offset_x, offset_y; |
JBLOCKARRAY src_buffer, dst_buffer; |
JCOEFPTR src_ptr, dst_ptr; |
@@ -246,11 +403,14 @@ |
* at the (output) right edge properly. They just get transposed and |
* not mirrored. |
*/ |
- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); |
+ MCU_cols = srcinfo->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) |
@@ -259,15 +419,26 @@ |
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
dst_blk_x += compptr->h_samp_factor) { |
- src_buffer = (*srcinfo->mem->access_virt_barray) |
- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, |
- (JDIMENSION) compptr->h_samp_factor, FALSE); |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
+ /* Block is within the mirrorable area. */ |
+ src_buffer = (*srcinfo->mem->access_virt_barray) |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ comp_width - x_crop_blocks - dst_blk_x - |
+ (JDIMENSION) compptr->h_samp_factor, |
+ (JDIMENSION) compptr->h_samp_factor, FALSE); |
+ } else { |
+ /* Edge blocks are transposed but not mirrored. */ |
+ src_buffer = (*srcinfo->mem->access_virt_barray) |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ dst_blk_x + x_crop_blocks, |
+ (JDIMENSION) compptr->h_samp_factor, FALSE); |
+ } |
for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; |
- if (dst_blk_x < comp_width) { |
+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
/* Block is within the mirrorable area. */ |
- dst_ptr = dst_buffer[offset_y] |
- [comp_width - dst_blk_x - offset_x - 1]; |
+ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] |
+ [dst_blk_y + offset_y + y_crop_blocks]; |
for (i = 0; i < DCTSIZE; i++) { |
for (j = 0; j < DCTSIZE; j++) |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -277,7 +448,8 @@ |
} |
} else { |
/* Edge blocks are transposed but not mirrored. */ |
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
+ src_ptr = src_buffer[offset_x] |
+ [dst_blk_y + offset_y + y_crop_blocks]; |
for (i = 0; i < DCTSIZE; i++) |
for (j = 0; j < DCTSIZE; j++) |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -292,6 +464,7 @@ |
LOCAL(void) |
do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
jvirt_barray_ptr *src_coef_arrays, |
jvirt_barray_ptr *dst_coef_arrays) |
/* 270 degree rotation is equivalent to |
@@ -301,6 +474,7 @@ |
*/ |
{ |
JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; |
+ JDIMENSION x_crop_blocks, y_crop_blocks; |
int ci, i, j, offset_x, offset_y; |
JBLOCKARRAY src_buffer, dst_buffer; |
JCOEFPTR src_ptr, dst_ptr; |
@@ -310,11 +484,14 @@ |
* at the (output) bottom edge properly. They just get transposed and |
* not mirrored. |
*/ |
- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); |
+ MCU_rows = srcinfo->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) |
@@ -324,14 +501,15 @@ |
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
dst_blk_x += compptr->h_samp_factor) { |
src_buffer = (*srcinfo->mem->access_virt_barray) |
- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ dst_blk_x + x_crop_blocks, |
(JDIMENSION) compptr->h_samp_factor, FALSE); |
for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
- if (dst_blk_y < comp_height) { |
+ if (y_crop_blocks + dst_blk_y < comp_height) { |
/* Block is within the mirrorable area. */ |
src_ptr = src_buffer[offset_x] |
- [comp_height - dst_blk_y - offset_y - 1]; |
+ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; |
for (i = 0; i < DCTSIZE; i++) { |
for (j = 0; j < DCTSIZE; j++) { |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -341,7 +519,8 @@ |
} |
} else { |
/* Edge blocks are transposed but not mirrored. */ |
- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; |
+ src_ptr = src_buffer[offset_x] |
+ [dst_blk_y + offset_y + y_crop_blocks]; |
for (i = 0; i < DCTSIZE; i++) |
for (j = 0; j < DCTSIZE; j++) |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -356,6 +535,7 @@ |
LOCAL(void) |
do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
jvirt_barray_ptr *src_coef_arrays, |
jvirt_barray_ptr *dst_coef_arrays) |
/* 180 degree rotation is equivalent to |
@@ -365,89 +545,95 @@ |
*/ |
{ |
JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; |
+ JDIMENSION x_crop_blocks, y_crop_blocks; |
int ci, i, j, offset_y; |
JBLOCKARRAY src_buffer, dst_buffer; |
JBLOCKROW src_row_ptr, dst_row_ptr; |
JCOEFPTR src_ptr, dst_ptr; |
jpeg_component_info *compptr; |
- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); |
- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); |
+ MCU_cols = srcinfo->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 (dst_blk_y < comp_height) { |
+ if (y_crop_blocks + dst_blk_y < comp_height) { |
/* Row is within the vertically mirrorable area. */ |
src_buffer = (*srcinfo->mem->access_virt_barray) |
((j_common_ptr) srcinfo, src_coef_arrays[ci], |
- comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, |
+ comp_height - y_crop_blocks - dst_blk_y - |
+ (JDIMENSION) compptr->v_samp_factor, |
(JDIMENSION) compptr->v_samp_factor, FALSE); |
} else { |
/* Bottom-edge rows are only mirrored horizontally. */ |
src_buffer = (*srcinfo->mem->access_virt_barray) |
- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ dst_blk_y + y_crop_blocks, |
(JDIMENSION) compptr->v_samp_factor, FALSE); |
} |
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
- if (dst_blk_y < comp_height) { |
+ dst_row_ptr = dst_buffer[offset_y]; |
+ if (y_crop_blocks + dst_blk_y < comp_height) { |
/* Row is within the mirrorable area. */ |
- dst_row_ptr = dst_buffer[offset_y]; |
src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; |
- /* Process the blocks that can be mirrored both ways. */ |
- for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { |
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { |
dst_ptr = dst_row_ptr[dst_blk_x]; |
- src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; |
- for (i = 0; i < DCTSIZE; i += 2) { |
- /* For even row, negate every odd column. */ |
- for (j = 0; j < DCTSIZE; j += 2) { |
- *dst_ptr++ = *src_ptr++; |
- *dst_ptr++ = - *src_ptr++; |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
+ /* Process the blocks that can be mirrored both ways. */ |
+ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; |
+ for (i = 0; i < DCTSIZE; i += 2) { |
+ /* For even row, negate every odd column. */ |
+ for (j = 0; j < DCTSIZE; j += 2) { |
+ *dst_ptr++ = *src_ptr++; |
+ *dst_ptr++ = - *src_ptr++; |
+ } |
+ /* For odd row, negate every even column. */ |
+ for (j = 0; j < DCTSIZE; j += 2) { |
+ *dst_ptr++ = - *src_ptr++; |
+ *dst_ptr++ = *src_ptr++; |
+ } |
} |
- /* For odd row, negate every even column. */ |
- for (j = 0; j < DCTSIZE; j += 2) { |
- *dst_ptr++ = - *src_ptr++; |
- *dst_ptr++ = *src_ptr++; |
+ } else { |
+ /* Any remaining right-edge blocks are only mirrored vertically. */ |
+ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; |
+ for (i = 0; i < DCTSIZE; i += 2) { |
+ for (j = 0; j < DCTSIZE; j++) |
+ *dst_ptr++ = *src_ptr++; |
+ for (j = 0; j < DCTSIZE; j++) |
+ *dst_ptr++ = - *src_ptr++; |
} |
} |
} |
- /* Any remaining right-edge blocks are only mirrored vertically. */ |
- for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { |
- dst_ptr = dst_row_ptr[dst_blk_x]; |
- src_ptr = src_row_ptr[dst_blk_x]; |
- for (i = 0; i < DCTSIZE; i += 2) { |
- for (j = 0; j < DCTSIZE; j++) |
- *dst_ptr++ = *src_ptr++; |
- for (j = 0; j < DCTSIZE; j++) |
- *dst_ptr++ = - *src_ptr++; |
- } |
- } |
} else { |
/* Remaining rows are just mirrored horizontally. */ |
- dst_row_ptr = dst_buffer[offset_y]; |
src_row_ptr = src_buffer[offset_y]; |
- /* Process the blocks that can be mirrored. */ |
- for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { |
- dst_ptr = dst_row_ptr[dst_blk_x]; |
- src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; |
- for (i = 0; i < DCTSIZE2; i += 2) { |
- *dst_ptr++ = *src_ptr++; |
- *dst_ptr++ = - *src_ptr++; |
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
+ /* Process the blocks that can be mirrored. */ |
+ dst_ptr = dst_row_ptr[dst_blk_x]; |
+ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; |
+ for (i = 0; i < DCTSIZE2; i += 2) { |
+ *dst_ptr++ = *src_ptr++; |
+ *dst_ptr++ = - *src_ptr++; |
+ } |
+ } else { |
+ /* Any remaining right-edge blocks are only copied. */ |
+ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, |
+ dst_row_ptr + dst_blk_x, |
+ (JDIMENSION) 1); |
} |
} |
- /* Any remaining right-edge blocks are only copied. */ |
- for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { |
- dst_ptr = dst_row_ptr[dst_blk_x]; |
- src_ptr = src_row_ptr[dst_blk_x]; |
- for (i = 0; i < DCTSIZE2; i++) |
- *dst_ptr++ = *src_ptr++; |
- } |
} |
} |
} |
@@ -457,6 +643,7 @@ |
LOCAL(void) |
do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
jvirt_barray_ptr *src_coef_arrays, |
jvirt_barray_ptr *dst_coef_arrays) |
/* Transverse transpose is equivalent to |
@@ -470,18 +657,23 @@ |
*/ |
{ |
JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; |
+ JDIMENSION x_crop_blocks, y_crop_blocks; |
int ci, i, j, offset_x, offset_y; |
JBLOCKARRAY src_buffer, dst_buffer; |
JCOEFPTR src_ptr, dst_ptr; |
jpeg_component_info *compptr; |
- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); |
- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); |
+ MCU_cols = srcinfo->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) |
@@ -490,17 +682,26 @@ |
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
dst_blk_x += compptr->h_samp_factor) { |
- src_buffer = (*srcinfo->mem->access_virt_barray) |
- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, |
- (JDIMENSION) compptr->h_samp_factor, FALSE); |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
+ /* Block is within the mirrorable area. */ |
+ src_buffer = (*srcinfo->mem->access_virt_barray) |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ comp_width - x_crop_blocks - dst_blk_x - |
+ (JDIMENSION) compptr->h_samp_factor, |
+ (JDIMENSION) compptr->h_samp_factor, FALSE); |
+ } else { |
+ src_buffer = (*srcinfo->mem->access_virt_barray) |
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], |
+ dst_blk_x + x_crop_blocks, |
+ (JDIMENSION) compptr->h_samp_factor, FALSE); |
+ } |
for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
- if (dst_blk_y < comp_height) { |
- src_ptr = src_buffer[offset_x] |
- [comp_height - dst_blk_y - offset_y - 1]; |
- if (dst_blk_x < comp_width) { |
+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
+ if (y_crop_blocks + dst_blk_y < comp_height) { |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
/* Block is within the mirrorable area. */ |
- dst_ptr = dst_buffer[offset_y] |
- [comp_width - dst_blk_x - offset_x - 1]; |
+ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] |
+ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; |
for (i = 0; i < DCTSIZE; i++) { |
for (j = 0; j < DCTSIZE; j++) { |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -516,7 +717,8 @@ |
} |
} else { |
/* Right-edge blocks are mirrored in y only */ |
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
+ src_ptr = src_buffer[offset_x] |
+ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; |
for (i = 0; i < DCTSIZE; i++) { |
for (j = 0; j < DCTSIZE; j++) { |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -526,11 +728,10 @@ |
} |
} |
} else { |
- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; |
- if (dst_blk_x < comp_width) { |
+ if (x_crop_blocks + dst_blk_x < comp_width) { |
/* Bottom-edge blocks are mirrored in x only */ |
- dst_ptr = dst_buffer[offset_y] |
- [comp_width - dst_blk_x - offset_x - 1]; |
+ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] |
+ [dst_blk_y + offset_y + y_crop_blocks]; |
for (i = 0; i < DCTSIZE; i++) { |
for (j = 0; j < DCTSIZE; j++) |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -540,7 +741,8 @@ |
} |
} else { |
/* At lower right corner, just transpose, no mirroring */ |
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
+ src_ptr = src_buffer[offset_x] |
+ [dst_blk_y + offset_y + y_crop_blocks]; |
for (i = 0; i < DCTSIZE; i++) |
for (j = 0; j < DCTSIZE; j++) |
dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; |
@@ -554,83 +756,358 @@ |
} |
+/* 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(void) |
+GLOBAL(boolean) |
jtransform_request_workspace (j_decompress_ptr srcinfo, |
jpeg_transform_info *info) |
{ |
- jvirt_barray_ptr *coef_arrays = NULL; |
+ jvirt_barray_ptr *coef_arrays; |
+ boolean need_workspace, transpose_it; |
jpeg_component_info *compptr; |
- int ci; |
+ 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) { |
+ srcinfo->num_components == 3) |
/* We'll only process the first component */ |
info->num_components = 1; |
- } else { |
+ else |
/* Process all the components */ |
info->num_components = srcinfo->num_components; |
+ |
+ /* Compute output image dimensions and related values. */ |
+#if JPEG_LIB_VERSION >= 80 |
+ jpeg_core_output_dimensions(srcinfo); |
+#else |
+ srcinfo->output_width = srcinfo->image_width; |
+ srcinfo->output_height = srcinfo->image_height; |
+#endif |
+ |
+ /* 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: |
- /* Don't need a workspace array */ |
+ if (info->trim) |
+ trim_right_edge(info, srcinfo->output_width); |
+ if (info->y_crop_offset != 0 || info->slow_hflip) |
+ need_workspace = TRUE; |
+ /* do_flip_h_no_crop doesn't need a workspace array */ |
break; |
case JXFORM_FLIP_V: |
- case JXFORM_ROT_180: |
- /* Need workspace arrays having same dimensions as source image. |
- * Note that we allocate arrays padded out to the next iMCU boundary, |
- * so that transform routines need not worry about missing edge blocks. |
- */ |
- coef_arrays = (jvirt_barray_ptr *) |
- (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, |
- SIZEOF(jvirt_barray_ptr) * info->num_components); |
- for (ci = 0; ci < info->num_components; ci++) { |
- compptr = srcinfo->comp_info + ci; |
- coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) |
- ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, |
- (JDIMENSION) jround_up((long) compptr->width_in_blocks, |
- (long) compptr->h_samp_factor), |
- (JDIMENSION) jround_up((long) compptr->height_in_blocks, |
- (long) compptr->v_samp_factor), |
- (JDIMENSION) compptr->v_samp_factor); |
- } |
+ if (info->trim) |
+ trim_bottom_edge(info, srcinfo->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: |
- /* Need workspace arrays having transposed dimensions. |
- * Note that we allocate arrays padded out to the next iMCU boundary, |
- * so that transform routines need not worry about missing edge blocks. |
- */ |
+ if (info->trim) |
+ trim_bottom_edge(info, srcinfo->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); |
+ 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, |
- (JDIMENSION) jround_up((long) compptr->height_in_blocks, |
- (long) compptr->v_samp_factor), |
- (JDIMENSION) jround_up((long) compptr->width_in_blocks, |
- (long) compptr->h_samp_factor), |
- (JDIMENSION) compptr->h_samp_factor); |
+ width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); |
} |
- break; |
- } |
- info->workspace_coef_arrays = coef_arrays; |
+ info->workspace_coef_arrays = coef_arrays; |
+ } else |
+ info->workspace_coef_arrays = NULL; |
+ |
+ return TRUE; |
} |
@@ -642,13 +1119,18 @@ |
int tblno, i, j, ci, itemp; |
jpeg_component_info *compptr; |
JQUANT_TBL *qtblptr; |
- JDIMENSION dtemp; |
+ JDIMENSION jtemp; |
UINT16 qtemp; |
- /* Transpose basic image dimensions */ |
- dtemp = dstinfo->image_width; |
+ /* Transpose image dimensions */ |
+ jtemp = dstinfo->image_width; |
dstinfo->image_width = dstinfo->image_height; |
- dstinfo->image_height = dtemp; |
+ dstinfo->image_height = jtemp; |
+#if JPEG_LIB_VERSION >= 70 |
+ 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; |
+#endif |
/* Transpose sampling factors */ |
for (ci = 0; ci < dstinfo->num_components; ci++) { |
@@ -674,46 +1156,159 @@ |
} |
-/* Trim off any partial iMCUs on the indicated destination edge */ |
+/* Adjust Exif image parameters. |
+ * |
+ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. |
+ */ |
LOCAL(void) |
-trim_right_edge (j_compress_ptr dstinfo) |
+adjust_exif_parameters (JOCTET FAR * data, unsigned int length, |
+ JDIMENSION new_width, JDIMENSION new_height) |
{ |
- int ci, max_h_samp_factor; |
- JDIMENSION MCU_cols; |
+ boolean is_motorola; /* Flag for byte order */ |
+ unsigned int number_of_tags, tagnum; |
+ unsigned int firstoffset, offset; |
+ JDIMENSION new_value; |
- /* 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); |
+ 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; |
} |
- 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; |
+ /* 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 */ |
- /* 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); |
+ /* 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]); |
} |
- 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); |
+ 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); |
} |
@@ -736,18 +1331,22 @@ |
{ |
/* If force-to-grayscale is requested, adjust destination parameters */ |
if (info->force_grayscale) { |
- /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed |
- * properly. Among other things, the target h_samp_factor & v_samp_factor |
- * will get set to 1, which typically won't match the source. |
- * In fact we do this even if the source is already grayscale; that |
- * provides an easy way of coercing a grayscale JPEG with funny sampling |
- * factors to the customary 1,1. (Some decoders fail on other factors.) |
+ /* First, ensure we have YCbCr or grayscale data, and that the source's |
+ * Y channel is full resolution. (No reasonable person would make Y |
+ * be less than full resolution, so actually coping with that case |
+ * isn't worth extra code space. But we check it to avoid crashing.) |
*/ |
- if ((dstinfo->jpeg_color_space == JCS_YCbCr && |
- dstinfo->num_components == 3) || |
- (dstinfo->jpeg_color_space == JCS_GRAYSCALE && |
- dstinfo->num_components == 1)) { |
- /* We have to preserve the source's quantization table number. */ |
+ if (((dstinfo->jpeg_color_space == JCS_YCbCr && |
+ dstinfo->num_components == 3) || |
+ (dstinfo->jpeg_color_space == JCS_GRAYSCALE && |
+ dstinfo->num_components == 1)) && |
+ srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && |
+ srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { |
+ /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed |
+ * properly. Among other things, it sets the target h_samp_factor & |
+ * v_samp_factor to 1, which typically won't match the source. |
+ * We have to preserve the source's quantization table number, however. |
+ */ |
int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; |
jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); |
dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; |
@@ -755,50 +1354,66 @@ |
/* Sorry, can't do it */ |
ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); |
} |
+ } else if (info->num_components == 1) { |
+ /* For a single-component source, we force the destination sampling factors |
+ * to 1x1, with or without force_grayscale. This is useful because some |
+ * decoders choke on grayscale images with other sampling factors. |
+ */ |
+ dstinfo->comp_info[0].h_samp_factor = 1; |
+ dstinfo->comp_info[0].v_samp_factor = 1; |
} |
- /* Correct the destination's image dimensions etc if necessary */ |
+ /* Correct the destination's image dimensions as necessary |
+ * for rotate/flip, resize, and crop operations. |
+ */ |
+#if JPEG_LIB_VERSION >= 70 |
+ dstinfo->jpeg_width = info->output_width; |
+ dstinfo->jpeg_height = info->output_height; |
+#endif |
+ |
+ /* Transpose destination image parameters */ |
switch (info->transform) { |
- case JXFORM_NONE: |
- /* Nothing to do */ |
- break; |
- case JXFORM_FLIP_H: |
- if (info->trim) |
- trim_right_edge(dstinfo); |
- break; |
- case JXFORM_FLIP_V: |
- if (info->trim) |
- trim_bottom_edge(dstinfo); |
- break; |
case JXFORM_TRANSPOSE: |
- transpose_critical_parameters(dstinfo); |
- /* transpose does NOT have to trim anything */ |
- break; |
case JXFORM_TRANSVERSE: |
- transpose_critical_parameters(dstinfo); |
- if (info->trim) { |
- trim_right_edge(dstinfo); |
- trim_bottom_edge(dstinfo); |
- } |
- break; |
case JXFORM_ROT_90: |
+ case JXFORM_ROT_270: |
+#if JPEG_LIB_VERSION < 70 |
+ dstinfo->image_width = info->output_height; |
+ dstinfo->image_height = info->output_width; |
+#endif |
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); |
- } |
+ default: |
+#if JPEG_LIB_VERSION < 70 |
+ dstinfo->image_width = info->output_width; |
+ dstinfo->image_height = info->output_height; |
+#endif |
break; |
- case JXFORM_ROT_270: |
- transpose_critical_parameters(dstinfo); |
- if (info->trim) |
- trim_bottom_edge(dstinfo); |
- break; |
} |
+ /* Adjust Exif properties */ |
+ if (srcinfo->marker_list != NULL && |
+ srcinfo->marker_list->marker == JPEG_APP0+1 && |
+ srcinfo->marker_list->data_length >= 6 && |
+ GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && |
+ GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && |
+ GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && |
+ GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && |
+ GETJOCTET(srcinfo->marker_list->data[4]) == 0 && |
+ GETJOCTET(srcinfo->marker_list->data[5]) == 0) { |
+ /* Suppress output of JFIF marker */ |
+ dstinfo->write_JFIF_header = FALSE; |
+#if JPEG_LIB_VERSION >= 70 |
+ /* 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); |
+#endif |
+ } |
+ |
/* Return the appropriate output data set */ |
if (info->workspace_coef_arrays != NULL) |
return info->workspace_coef_arrays; |
@@ -816,40 +1431,110 @@ |
*/ |
GLOBAL(void) |
-jtransform_execute_transformation (j_decompress_ptr srcinfo, |
- j_compress_ptr dstinfo, |
- jvirt_barray_ptr *src_coef_arrays, |
- jpeg_transform_info *info) |
+jtransform_execute_transform (j_decompress_ptr srcinfo, |
+ j_compress_ptr dstinfo, |
+ jvirt_barray_ptr *src_coef_arrays, |
+ jpeg_transform_info *info) |
{ |
jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; |
+ /* Note: conditions tested here should match those in switch statement |
+ * in jtransform_request_workspace() |
+ */ |
switch (info->transform) { |
case JXFORM_NONE: |
+ if (info->x_crop_offset != 0 || info->y_crop_offset != 0) |
+ do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
case JXFORM_FLIP_H: |
- do_flip_h(srcinfo, dstinfo, src_coef_arrays); |
+ if (info->y_crop_offset != 0 || info->slow_hflip) |
+ do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
+ else |
+ do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, |
+ src_coef_arrays); |
break; |
case JXFORM_FLIP_V: |
- do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); |
+ do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
case JXFORM_TRANSPOSE: |
- do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); |
+ do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
case JXFORM_TRANSVERSE: |
- do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); |
+ do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
case JXFORM_ROT_90: |
- do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); |
+ do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
case JXFORM_ROT_180: |
- do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); |
+ do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
case JXFORM_ROT_270: |
- do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); |
+ do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
+ src_coef_arrays, dst_coef_arrays); |
break; |
} |
} |
+/* jtransform_perfect_transform |
+ * |
+ * Determine whether lossless transformation is perfectly |
+ * possible for a specified image and transformation. |
+ * |
+ * Inputs: |
+ * image_width, image_height: source image dimensions. |
+ * MCU_width, MCU_height: pixel dimensions of MCU. |
+ * transform: transformation identifier. |
+ * Parameter sources from initialized jpeg_struct |
+ * (after reading source header): |
+ * image_width = cinfo.image_width |
+ * image_height = cinfo.image_height |
+ * MCU_width = cinfo.max_h_samp_factor * 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 */ |