1*4882a593SmuzhiyunAdd patch by Ondrej Sury to migrate to libjpeg-turbo (Closes: #763263)
2*4882a593Smuzhiyun
3*4882a593SmuzhiyunIndex: fbida-2.10/jpeg/62/jpegcomp.h
4*4882a593Smuzhiyun===================================================================
5*4882a593Smuzhiyun--- /dev/null
6*4882a593Smuzhiyun+++ fbida-2.10/jpeg/62/jpegcomp.h
7*4882a593Smuzhiyun@@ -0,0 +1,30 @@
8*4882a593Smuzhiyun+/*
9*4882a593Smuzhiyun+ * jpegcomp.h
10*4882a593Smuzhiyun+ *
11*4882a593Smuzhiyun+ * Copyright (C) 2010, D. R. Commander
12*4882a593Smuzhiyun+ * For conditions of distribution and use, see the accompanying README file.
13*4882a593Smuzhiyun+ *
14*4882a593Smuzhiyun+ * JPEG compatibility macros
15*4882a593Smuzhiyun+ * These declarations are considered internal to the JPEG library; most
16*4882a593Smuzhiyun+ * applications using the library shouldn't need to include this file.
17*4882a593Smuzhiyun+ */
18*4882a593Smuzhiyun+
19*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 70
20*4882a593Smuzhiyun+#define _DCT_scaled_size DCT_h_scaled_size
21*4882a593Smuzhiyun+#define _DCT_h_scaled_size DCT_h_scaled_size
22*4882a593Smuzhiyun+#define _DCT_v_scaled_size DCT_v_scaled_size
23*4882a593Smuzhiyun+#define _min_DCT_scaled_size min_DCT_h_scaled_size
24*4882a593Smuzhiyun+#define _min_DCT_h_scaled_size min_DCT_h_scaled_size
25*4882a593Smuzhiyun+#define _min_DCT_v_scaled_size min_DCT_v_scaled_size
26*4882a593Smuzhiyun+#define _jpeg_width jpeg_width
27*4882a593Smuzhiyun+#define _jpeg_height jpeg_height
28*4882a593Smuzhiyun+#else
29*4882a593Smuzhiyun+#define _DCT_scaled_size DCT_scaled_size
30*4882a593Smuzhiyun+#define _DCT_h_scaled_size DCT_scaled_size
31*4882a593Smuzhiyun+#define _DCT_v_scaled_size DCT_scaled_size
32*4882a593Smuzhiyun+#define _min_DCT_scaled_size min_DCT_scaled_size
33*4882a593Smuzhiyun+#define _min_DCT_h_scaled_size min_DCT_scaled_size
34*4882a593Smuzhiyun+#define _min_DCT_v_scaled_size min_DCT_scaled_size
35*4882a593Smuzhiyun+#define _jpeg_width image_width
36*4882a593Smuzhiyun+#define _jpeg_height image_height
37*4882a593Smuzhiyun+#endif
38*4882a593SmuzhiyunIndex: fbida-2.10/jpeg/62/transupp.c
39*4882a593Smuzhiyun===================================================================
40*4882a593Smuzhiyun--- fbida-2.10.orig/jpeg/62/transupp.c
41*4882a593Smuzhiyun+++ fbida-2.10/jpeg/62/transupp.c
42*4882a593Smuzhiyun@@ -1,8 +1,10 @@
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun  * transupp.c
45*4882a593Smuzhiyun  *
46*4882a593Smuzhiyun- * Copyright (C) 1997, Thomas G. Lane.
47*4882a593Smuzhiyun- * This file is part of the Independent JPEG Group's software.
48*4882a593Smuzhiyun+ * This file was part of the Independent JPEG Group's software:
49*4882a593Smuzhiyun+ * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
50*4882a593Smuzhiyun+ * libjpeg-turbo Modifications:
51*4882a593Smuzhiyun+ * Copyright (C) 2010, D. R. Commander.
52*4882a593Smuzhiyun  * For conditions of distribution and use, see the accompanying README file.
53*4882a593Smuzhiyun  *
54*4882a593Smuzhiyun  * This file contains image transformation routines and other utility code
55*4882a593Smuzhiyun@@ -20,6 +22,17 @@
56*4882a593Smuzhiyun #include "jinclude.h"
57*4882a593Smuzhiyun #include "jpeglib.h"
58*4882a593Smuzhiyun #include "transupp.h"		/* My own external interface */
59*4882a593Smuzhiyun+#include "jpegcomp.h"
60*4882a593Smuzhiyun+#include <ctype.h>		/* to declare isdigit() */
61*4882a593Smuzhiyun+
62*4882a593Smuzhiyun+
63*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 70
64*4882a593Smuzhiyun+#define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size
65*4882a593Smuzhiyun+#define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size
66*4882a593Smuzhiyun+#else
67*4882a593Smuzhiyun+#define dstinfo_min_DCT_h_scaled_size DCTSIZE
68*4882a593Smuzhiyun+#define dstinfo_min_DCT_v_scaled_size DCTSIZE
69*4882a593Smuzhiyun+#endif
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun #if TRANSFORMS_SUPPORTED
73*4882a593Smuzhiyun@@ -28,7 +41,8 @@
74*4882a593Smuzhiyun  * Lossless image transformation routines.  These routines work on DCT
75*4882a593Smuzhiyun  * coefficient arrays and thus do not require any lossy decompression
76*4882a593Smuzhiyun  * or recompression of the image.
77*4882a593Smuzhiyun- * Thanks to Guido Vollbeding for the initial design and code of this feature.
78*4882a593Smuzhiyun+ * Thanks to Guido Vollbeding for the initial design and code of this feature,
79*4882a593Smuzhiyun+ * and to Ben Jackson for introducing the cropping feature.
80*4882a593Smuzhiyun  *
81*4882a593Smuzhiyun  * Horizontal flipping is done in-place, using a single top-to-bottom
82*4882a593Smuzhiyun  * pass through the virtual source array.  It will thus be much the
83*4882a593Smuzhiyun@@ -42,6 +56,13 @@
84*4882a593Smuzhiyun  * arrays for most of the transforms.  That could result in much thrashing
85*4882a593Smuzhiyun  * if the image is larger than main memory.
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun+ * If cropping or trimming is involved, the destination arrays may be smaller
88*4882a593Smuzhiyun+ * than the source arrays.  Note it is not possible to do horizontal flip
89*4882a593Smuzhiyun+ * in-place when a nonzero Y crop offset is specified, since we'd have to move
90*4882a593Smuzhiyun+ * data from one block row to another but the virtual array manager doesn't
91*4882a593Smuzhiyun+ * guarantee we can touch more than one row at a time.  So in that case,
92*4882a593Smuzhiyun+ * we have to use a separate destination array.
93*4882a593Smuzhiyun+ *
94*4882a593Smuzhiyun  * Some notes about the operating environment of the individual transform
95*4882a593Smuzhiyun  * routines:
96*4882a593Smuzhiyun  * 1. Both the source and destination virtual arrays are allocated from the
97*4882a593Smuzhiyun@@ -54,20 +75,65 @@
98*4882a593Smuzhiyun  *    and we may as well take that as the effective iMCU size.
99*4882a593Smuzhiyun  * 4. When "trim" is in effect, the destination's dimensions will be the
100*4882a593Smuzhiyun  *    trimmed values but the source's will be untrimmed.
101*4882a593Smuzhiyun- * 5. All the routines assume that the source and destination buffers are
102*4882a593Smuzhiyun+ * 5. When "crop" is in effect, the destination's dimensions will be the
103*4882a593Smuzhiyun+ *    cropped values but the source's will be uncropped.  Each transform
104*4882a593Smuzhiyun+ *    routine is responsible for picking up source data starting at the
105*4882a593Smuzhiyun+ *    correct X and Y offset for the crop region.  (The X and Y offsets
106*4882a593Smuzhiyun+ *    passed to the transform routines are measured in iMCU blocks of the
107*4882a593Smuzhiyun+ *    destination.)
108*4882a593Smuzhiyun+ * 6. All the routines assume that the source and destination buffers are
109*4882a593Smuzhiyun  *    padded out to a full iMCU boundary.  This is true, although for the
110*4882a593Smuzhiyun  *    source buffer it is an undocumented property of jdcoefct.c.
111*4882a593Smuzhiyun- * Notes 2,3,4 boil down to this: generally we should use the destination's
112*4882a593Smuzhiyun- * dimensions and ignore the source's.
113*4882a593Smuzhiyun  */
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun LOCAL(void)
117*4882a593Smuzhiyun-do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
118*4882a593Smuzhiyun-	   jvirt_barray_ptr *src_coef_arrays)
119*4882a593Smuzhiyun-/* Horizontal flip; done in-place, so no separate dest array is required */
120*4882a593Smuzhiyun+do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
121*4882a593Smuzhiyun+	 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
122*4882a593Smuzhiyun+	 jvirt_barray_ptr *src_coef_arrays,
123*4882a593Smuzhiyun+	 jvirt_barray_ptr *dst_coef_arrays)
124*4882a593Smuzhiyun+/* Crop.  This is only used when no rotate/flip is requested with the crop. */
125*4882a593Smuzhiyun+{
126*4882a593Smuzhiyun+  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
127*4882a593Smuzhiyun+  int ci, offset_y;
128*4882a593Smuzhiyun+  JBLOCKARRAY src_buffer, dst_buffer;
129*4882a593Smuzhiyun+  jpeg_component_info *compptr;
130*4882a593Smuzhiyun+
131*4882a593Smuzhiyun+  /* We simply have to copy the right amount of data (the destination's
132*4882a593Smuzhiyun+   * image size) starting at the given X and Y offsets in the source.
133*4882a593Smuzhiyun+   */
134*4882a593Smuzhiyun+  for (ci = 0; ci < dstinfo->num_components; ci++) {
135*4882a593Smuzhiyun+    compptr = dstinfo->comp_info + ci;
136*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
137*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
138*4882a593Smuzhiyun+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
139*4882a593Smuzhiyun+	 dst_blk_y += compptr->v_samp_factor) {
140*4882a593Smuzhiyun+      dst_buffer = (*srcinfo->mem->access_virt_barray)
141*4882a593Smuzhiyun+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
142*4882a593Smuzhiyun+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
143*4882a593Smuzhiyun+      src_buffer = (*srcinfo->mem->access_virt_barray)
144*4882a593Smuzhiyun+	((j_common_ptr) srcinfo, src_coef_arrays[ci],
145*4882a593Smuzhiyun+	 dst_blk_y + y_crop_blocks,
146*4882a593Smuzhiyun+	 (JDIMENSION) compptr->v_samp_factor, FALSE);
147*4882a593Smuzhiyun+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
148*4882a593Smuzhiyun+	jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
149*4882a593Smuzhiyun+			dst_buffer[offset_y],
150*4882a593Smuzhiyun+			compptr->width_in_blocks);
151*4882a593Smuzhiyun+      }
152*4882a593Smuzhiyun+    }
153*4882a593Smuzhiyun+  }
154*4882a593Smuzhiyun+}
155*4882a593Smuzhiyun+
156*4882a593Smuzhiyun+
157*4882a593Smuzhiyun+LOCAL(void)
158*4882a593Smuzhiyun+do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
159*4882a593Smuzhiyun+		   JDIMENSION x_crop_offset,
160*4882a593Smuzhiyun+		   jvirt_barray_ptr *src_coef_arrays)
161*4882a593Smuzhiyun+/* Horizontal flip; done in-place, so no separate dest array is required.
162*4882a593Smuzhiyun+ * NB: this only works when y_crop_offset is zero.
163*4882a593Smuzhiyun+ */
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun-  JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
166*4882a593Smuzhiyun+  JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
167*4882a593Smuzhiyun   int ci, k, offset_y;
168*4882a593Smuzhiyun   JBLOCKARRAY buffer;
169*4882a593Smuzhiyun   JCOEFPTR ptr1, ptr2;
170*4882a593Smuzhiyun@@ -79,17 +145,20 @@ do_flip_h (j_decompress_ptr srcinfo, j_c
171*4882a593Smuzhiyun    * mirroring by changing the signs of odd-numbered columns.
172*4882a593Smuzhiyun    * Partial iMCUs at the right edge are left untouched.
173*4882a593Smuzhiyun    */
174*4882a593Smuzhiyun-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
175*4882a593Smuzhiyun+  MCU_cols = srcinfo->output_width /
176*4882a593Smuzhiyun+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
179*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
180*4882a593Smuzhiyun     comp_width = MCU_cols * compptr->h_samp_factor;
181*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
182*4882a593Smuzhiyun     for (blk_y = 0; blk_y < compptr->height_in_blocks;
183*4882a593Smuzhiyun 	 blk_y += compptr->v_samp_factor) {
184*4882a593Smuzhiyun       buffer = (*srcinfo->mem->access_virt_barray)
185*4882a593Smuzhiyun 	((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
186*4882a593Smuzhiyun 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
187*4882a593Smuzhiyun       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
188*4882a593Smuzhiyun+	/* Do the mirroring */
189*4882a593Smuzhiyun 	for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
190*4882a593Smuzhiyun 	  ptr1 = buffer[offset_y][blk_x];
191*4882a593Smuzhiyun 	  ptr2 = buffer[offset_y][comp_width - blk_x - 1];
192*4882a593Smuzhiyun@@ -105,6 +174,80 @@ do_flip_h (j_decompress_ptr srcinfo, j_c
193*4882a593Smuzhiyun 	    *ptr2++ = -temp1;
194*4882a593Smuzhiyun 	  }
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun+	if (x_crop_blocks > 0) {
197*4882a593Smuzhiyun+	  /* Now left-justify the portion of the data to be kept.
198*4882a593Smuzhiyun+	   * We can't use a single jcopy_block_row() call because that routine
199*4882a593Smuzhiyun+	   * depends on memcpy(), whose behavior is unspecified for overlapping
200*4882a593Smuzhiyun+	   * source and destination areas.  Sigh.
201*4882a593Smuzhiyun+	   */
202*4882a593Smuzhiyun+	  for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
203*4882a593Smuzhiyun+	    jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
204*4882a593Smuzhiyun+			    buffer[offset_y] + blk_x,
205*4882a593Smuzhiyun+			    (JDIMENSION) 1);
206*4882a593Smuzhiyun+	  }
207*4882a593Smuzhiyun+	}
208*4882a593Smuzhiyun+      }
209*4882a593Smuzhiyun+    }
210*4882a593Smuzhiyun+  }
211*4882a593Smuzhiyun+}
212*4882a593Smuzhiyun+
213*4882a593Smuzhiyun+
214*4882a593Smuzhiyun+LOCAL(void)
215*4882a593Smuzhiyun+do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
216*4882a593Smuzhiyun+	   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
217*4882a593Smuzhiyun+	   jvirt_barray_ptr *src_coef_arrays,
218*4882a593Smuzhiyun+	   jvirt_barray_ptr *dst_coef_arrays)
219*4882a593Smuzhiyun+/* Horizontal flip in general cropping case */
220*4882a593Smuzhiyun+{
221*4882a593Smuzhiyun+  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
222*4882a593Smuzhiyun+  JDIMENSION x_crop_blocks, y_crop_blocks;
223*4882a593Smuzhiyun+  int ci, k, offset_y;
224*4882a593Smuzhiyun+  JBLOCKARRAY src_buffer, dst_buffer;
225*4882a593Smuzhiyun+  JBLOCKROW src_row_ptr, dst_row_ptr;
226*4882a593Smuzhiyun+  JCOEFPTR src_ptr, dst_ptr;
227*4882a593Smuzhiyun+  jpeg_component_info *compptr;
228*4882a593Smuzhiyun+
229*4882a593Smuzhiyun+  /* Here we must output into a separate array because we can't touch
230*4882a593Smuzhiyun+   * different rows of a single virtual array simultaneously.  Otherwise,
231*4882a593Smuzhiyun+   * this is essentially the same as the routine above.
232*4882a593Smuzhiyun+   */
233*4882a593Smuzhiyun+  MCU_cols = srcinfo->output_width /
234*4882a593Smuzhiyun+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
235*4882a593Smuzhiyun+
236*4882a593Smuzhiyun+  for (ci = 0; ci < dstinfo->num_components; ci++) {
237*4882a593Smuzhiyun+    compptr = dstinfo->comp_info + ci;
238*4882a593Smuzhiyun+    comp_width = MCU_cols * compptr->h_samp_factor;
239*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
240*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
241*4882a593Smuzhiyun+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
242*4882a593Smuzhiyun+	 dst_blk_y += compptr->v_samp_factor) {
243*4882a593Smuzhiyun+      dst_buffer = (*srcinfo->mem->access_virt_barray)
244*4882a593Smuzhiyun+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
245*4882a593Smuzhiyun+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
246*4882a593Smuzhiyun+      src_buffer = (*srcinfo->mem->access_virt_barray)
247*4882a593Smuzhiyun+	((j_common_ptr) srcinfo, src_coef_arrays[ci],
248*4882a593Smuzhiyun+	 dst_blk_y + y_crop_blocks,
249*4882a593Smuzhiyun+	 (JDIMENSION) compptr->v_samp_factor, FALSE);
250*4882a593Smuzhiyun+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
251*4882a593Smuzhiyun+	dst_row_ptr = dst_buffer[offset_y];
252*4882a593Smuzhiyun+	src_row_ptr = src_buffer[offset_y];
253*4882a593Smuzhiyun+	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
254*4882a593Smuzhiyun+	  if (x_crop_blocks + dst_blk_x < comp_width) {
255*4882a593Smuzhiyun+	    /* Do the mirrorable blocks */
256*4882a593Smuzhiyun+	    dst_ptr = dst_row_ptr[dst_blk_x];
257*4882a593Smuzhiyun+	    src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
258*4882a593Smuzhiyun+	    /* this unrolled loop doesn't need to know which row it's on... */
259*4882a593Smuzhiyun+	    for (k = 0; k < DCTSIZE2; k += 2) {
260*4882a593Smuzhiyun+	      *dst_ptr++ = *src_ptr++;	 /* copy even column */
261*4882a593Smuzhiyun+	      *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
262*4882a593Smuzhiyun+	    }
263*4882a593Smuzhiyun+	  } else {
264*4882a593Smuzhiyun+	    /* Copy last partial block(s) verbatim */
265*4882a593Smuzhiyun+	    jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
266*4882a593Smuzhiyun+			    dst_row_ptr + dst_blk_x,
267*4882a593Smuzhiyun+			    (JDIMENSION) 1);
268*4882a593Smuzhiyun+	  }
269*4882a593Smuzhiyun+	}
270*4882a593Smuzhiyun       }
271*4882a593Smuzhiyun     }
272*4882a593Smuzhiyun   }
273*4882a593Smuzhiyun@@ -113,11 +256,13 @@ do_flip_h (j_decompress_ptr srcinfo, j_c
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun LOCAL(void)
276*4882a593Smuzhiyun do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
277*4882a593Smuzhiyun+	   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
278*4882a593Smuzhiyun 	   jvirt_barray_ptr *src_coef_arrays,
279*4882a593Smuzhiyun 	   jvirt_barray_ptr *dst_coef_arrays)
280*4882a593Smuzhiyun /* Vertical flip */
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
283*4882a593Smuzhiyun+  JDIMENSION x_crop_blocks, y_crop_blocks;
284*4882a593Smuzhiyun   int ci, i, j, offset_y;
285*4882a593Smuzhiyun   JBLOCKARRAY src_buffer, dst_buffer;
286*4882a593Smuzhiyun   JBLOCKROW src_row_ptr, dst_row_ptr;
287*4882a593Smuzhiyun@@ -131,33 +276,39 @@ do_flip_v (j_decompress_ptr srcinfo, j_c
288*4882a593Smuzhiyun    * of odd-numbered rows.
289*4882a593Smuzhiyun    * Partial iMCUs at the bottom edge are copied verbatim.
290*4882a593Smuzhiyun    */
291*4882a593Smuzhiyun-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
292*4882a593Smuzhiyun+  MCU_rows = srcinfo->output_height /
293*4882a593Smuzhiyun+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
296*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
297*4882a593Smuzhiyun     comp_height = MCU_rows * compptr->v_samp_factor;
298*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
299*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
300*4882a593Smuzhiyun     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
301*4882a593Smuzhiyun 	 dst_blk_y += compptr->v_samp_factor) {
302*4882a593Smuzhiyun       dst_buffer = (*srcinfo->mem->access_virt_barray)
303*4882a593Smuzhiyun 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
304*4882a593Smuzhiyun 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
305*4882a593Smuzhiyun-      if (dst_blk_y < comp_height) {
306*4882a593Smuzhiyun+      if (y_crop_blocks + dst_blk_y < comp_height) {
307*4882a593Smuzhiyun 	/* Row is within the mirrorable area. */
308*4882a593Smuzhiyun 	src_buffer = (*srcinfo->mem->access_virt_barray)
309*4882a593Smuzhiyun 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
310*4882a593Smuzhiyun-	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
311*4882a593Smuzhiyun+	   comp_height - y_crop_blocks - dst_blk_y -
312*4882a593Smuzhiyun+	   (JDIMENSION) compptr->v_samp_factor,
313*4882a593Smuzhiyun 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
314*4882a593Smuzhiyun       } else {
315*4882a593Smuzhiyun 	/* Bottom-edge blocks will be copied verbatim. */
316*4882a593Smuzhiyun 	src_buffer = (*srcinfo->mem->access_virt_barray)
317*4882a593Smuzhiyun-	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
318*4882a593Smuzhiyun+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
319*4882a593Smuzhiyun+	   dst_blk_y + y_crop_blocks,
320*4882a593Smuzhiyun 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
321*4882a593Smuzhiyun       }
322*4882a593Smuzhiyun       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
323*4882a593Smuzhiyun-	if (dst_blk_y < comp_height) {
324*4882a593Smuzhiyun+	if (y_crop_blocks + dst_blk_y < comp_height) {
325*4882a593Smuzhiyun 	  /* Row is within the mirrorable area. */
326*4882a593Smuzhiyun 	  dst_row_ptr = dst_buffer[offset_y];
327*4882a593Smuzhiyun 	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
328*4882a593Smuzhiyun+	  src_row_ptr += x_crop_blocks;
329*4882a593Smuzhiyun 	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
330*4882a593Smuzhiyun 	       dst_blk_x++) {
331*4882a593Smuzhiyun 	    dst_ptr = dst_row_ptr[dst_blk_x];
332*4882a593Smuzhiyun@@ -173,7 +324,8 @@ do_flip_v (j_decompress_ptr srcinfo, j_c
333*4882a593Smuzhiyun 	  }
334*4882a593Smuzhiyun 	} else {
335*4882a593Smuzhiyun 	  /* Just copy row verbatim. */
336*4882a593Smuzhiyun-	  jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
337*4882a593Smuzhiyun+	  jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
338*4882a593Smuzhiyun+			  dst_buffer[offset_y],
339*4882a593Smuzhiyun 			  compptr->width_in_blocks);
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun       }
342*4882a593Smuzhiyun@@ -184,11 +336,12 @@ do_flip_v (j_decompress_ptr srcinfo, j_c
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun LOCAL(void)
345*4882a593Smuzhiyun do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
346*4882a593Smuzhiyun+	      JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
347*4882a593Smuzhiyun 	      jvirt_barray_ptr *src_coef_arrays,
348*4882a593Smuzhiyun 	      jvirt_barray_ptr *dst_coef_arrays)
349*4882a593Smuzhiyun /* Transpose source into destination */
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun-  JDIMENSION dst_blk_x, dst_blk_y;
352*4882a593Smuzhiyun+  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
353*4882a593Smuzhiyun   int ci, i, j, offset_x, offset_y;
354*4882a593Smuzhiyun   JBLOCKARRAY src_buffer, dst_buffer;
355*4882a593Smuzhiyun   JCOEFPTR src_ptr, dst_ptr;
356*4882a593Smuzhiyun@@ -201,6 +354,8 @@ do_transpose (j_decompress_ptr srcinfo,
357*4882a593Smuzhiyun    */
358*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
359*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
360*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
361*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
362*4882a593Smuzhiyun     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
363*4882a593Smuzhiyun 	 dst_blk_y += compptr->v_samp_factor) {
364*4882a593Smuzhiyun       dst_buffer = (*srcinfo->mem->access_virt_barray)
365*4882a593Smuzhiyun@@ -210,11 +365,12 @@ do_transpose (j_decompress_ptr srcinfo,
366*4882a593Smuzhiyun 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
367*4882a593Smuzhiyun 	     dst_blk_x += compptr->h_samp_factor) {
368*4882a593Smuzhiyun 	  src_buffer = (*srcinfo->mem->access_virt_barray)
369*4882a593Smuzhiyun-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
370*4882a593Smuzhiyun+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci],
371*4882a593Smuzhiyun+	     dst_blk_x + x_crop_blocks,
372*4882a593Smuzhiyun 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
373*4882a593Smuzhiyun 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
374*4882a593Smuzhiyun-	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
375*4882a593Smuzhiyun 	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
376*4882a593Smuzhiyun+	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
377*4882a593Smuzhiyun 	    for (i = 0; i < DCTSIZE; i++)
378*4882a593Smuzhiyun 	      for (j = 0; j < DCTSIZE; j++)
379*4882a593Smuzhiyun 		dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
380*4882a593Smuzhiyun@@ -228,6 +384,7 @@ do_transpose (j_decompress_ptr srcinfo,
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun LOCAL(void)
383*4882a593Smuzhiyun do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
384*4882a593Smuzhiyun+	   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
385*4882a593Smuzhiyun 	   jvirt_barray_ptr *src_coef_arrays,
386*4882a593Smuzhiyun 	   jvirt_barray_ptr *dst_coef_arrays)
387*4882a593Smuzhiyun /* 90 degree rotation is equivalent to
388*4882a593Smuzhiyun@@ -237,6 +394,7 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c
389*4882a593Smuzhiyun  */
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
392*4882a593Smuzhiyun+  JDIMENSION x_crop_blocks, y_crop_blocks;
393*4882a593Smuzhiyun   int ci, i, j, offset_x, offset_y;
394*4882a593Smuzhiyun   JBLOCKARRAY src_buffer, dst_buffer;
395*4882a593Smuzhiyun   JCOEFPTR src_ptr, dst_ptr;
396*4882a593Smuzhiyun@@ -246,11 +404,14 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c
397*4882a593Smuzhiyun    * at the (output) right edge properly.  They just get transposed and
398*4882a593Smuzhiyun    * not mirrored.
399*4882a593Smuzhiyun    */
400*4882a593Smuzhiyun-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
401*4882a593Smuzhiyun+  MCU_cols = srcinfo->output_height /
402*4882a593Smuzhiyun+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
405*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
406*4882a593Smuzhiyun     comp_width = MCU_cols * compptr->h_samp_factor;
407*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
408*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
409*4882a593Smuzhiyun     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
410*4882a593Smuzhiyun 	 dst_blk_y += compptr->v_samp_factor) {
411*4882a593Smuzhiyun       dst_buffer = (*srcinfo->mem->access_virt_barray)
412*4882a593Smuzhiyun@@ -259,15 +420,26 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c
413*4882a593Smuzhiyun       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
414*4882a593Smuzhiyun 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
415*4882a593Smuzhiyun 	     dst_blk_x += compptr->h_samp_factor) {
416*4882a593Smuzhiyun-	  src_buffer = (*srcinfo->mem->access_virt_barray)
417*4882a593Smuzhiyun-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
418*4882a593Smuzhiyun-	     (JDIMENSION) compptr->h_samp_factor, FALSE);
419*4882a593Smuzhiyun+	  if (x_crop_blocks + dst_blk_x < comp_width) {
420*4882a593Smuzhiyun+	    /* Block is within the mirrorable area. */
421*4882a593Smuzhiyun+	    src_buffer = (*srcinfo->mem->access_virt_barray)
422*4882a593Smuzhiyun+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
423*4882a593Smuzhiyun+	       comp_width - x_crop_blocks - dst_blk_x -
424*4882a593Smuzhiyun+	       (JDIMENSION) compptr->h_samp_factor,
425*4882a593Smuzhiyun+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
426*4882a593Smuzhiyun+	  } else {
427*4882a593Smuzhiyun+	    /* Edge blocks are transposed but not mirrored. */
428*4882a593Smuzhiyun+	    src_buffer = (*srcinfo->mem->access_virt_barray)
429*4882a593Smuzhiyun+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
430*4882a593Smuzhiyun+	       dst_blk_x + x_crop_blocks,
431*4882a593Smuzhiyun+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
432*4882a593Smuzhiyun+	  }
433*4882a593Smuzhiyun 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
434*4882a593Smuzhiyun-	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
435*4882a593Smuzhiyun-	    if (dst_blk_x < comp_width) {
436*4882a593Smuzhiyun+	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
437*4882a593Smuzhiyun+	    if (x_crop_blocks + dst_blk_x < comp_width) {
438*4882a593Smuzhiyun 	      /* Block is within the mirrorable area. */
439*4882a593Smuzhiyun-	      dst_ptr = dst_buffer[offset_y]
440*4882a593Smuzhiyun-		[comp_width - dst_blk_x - offset_x - 1];
441*4882a593Smuzhiyun+	      src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
442*4882a593Smuzhiyun+		[dst_blk_y + offset_y + y_crop_blocks];
443*4882a593Smuzhiyun 	      for (i = 0; i < DCTSIZE; i++) {
444*4882a593Smuzhiyun 		for (j = 0; j < DCTSIZE; j++)
445*4882a593Smuzhiyun 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
446*4882a593Smuzhiyun@@ -277,7 +449,8 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c
447*4882a593Smuzhiyun 	      }
448*4882a593Smuzhiyun 	    } else {
449*4882a593Smuzhiyun 	      /* Edge blocks are transposed but not mirrored. */
450*4882a593Smuzhiyun-	      dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
451*4882a593Smuzhiyun+	      src_ptr = src_buffer[offset_x]
452*4882a593Smuzhiyun+		[dst_blk_y + offset_y + y_crop_blocks];
453*4882a593Smuzhiyun 	      for (i = 0; i < DCTSIZE; i++)
454*4882a593Smuzhiyun 		for (j = 0; j < DCTSIZE; j++)
455*4882a593Smuzhiyun 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
456*4882a593Smuzhiyun@@ -292,6 +465,7 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun LOCAL(void)
459*4882a593Smuzhiyun do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
460*4882a593Smuzhiyun+	    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
461*4882a593Smuzhiyun 	    jvirt_barray_ptr *src_coef_arrays,
462*4882a593Smuzhiyun 	    jvirt_barray_ptr *dst_coef_arrays)
463*4882a593Smuzhiyun /* 270 degree rotation is equivalent to
464*4882a593Smuzhiyun@@ -301,6 +475,7 @@ do_rot_270 (j_decompress_ptr srcinfo, j_
465*4882a593Smuzhiyun  */
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
468*4882a593Smuzhiyun+  JDIMENSION x_crop_blocks, y_crop_blocks;
469*4882a593Smuzhiyun   int ci, i, j, offset_x, offset_y;
470*4882a593Smuzhiyun   JBLOCKARRAY src_buffer, dst_buffer;
471*4882a593Smuzhiyun   JCOEFPTR src_ptr, dst_ptr;
472*4882a593Smuzhiyun@@ -310,11 +485,14 @@ do_rot_270 (j_decompress_ptr srcinfo, j_
473*4882a593Smuzhiyun    * at the (output) bottom edge properly.  They just get transposed and
474*4882a593Smuzhiyun    * not mirrored.
475*4882a593Smuzhiyun    */
476*4882a593Smuzhiyun-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
477*4882a593Smuzhiyun+  MCU_rows = srcinfo->output_width /
478*4882a593Smuzhiyun+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
481*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
482*4882a593Smuzhiyun     comp_height = MCU_rows * compptr->v_samp_factor;
483*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
484*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
485*4882a593Smuzhiyun     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
486*4882a593Smuzhiyun 	 dst_blk_y += compptr->v_samp_factor) {
487*4882a593Smuzhiyun       dst_buffer = (*srcinfo->mem->access_virt_barray)
488*4882a593Smuzhiyun@@ -324,14 +502,15 @@ do_rot_270 (j_decompress_ptr srcinfo, j_
489*4882a593Smuzhiyun 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
490*4882a593Smuzhiyun 	     dst_blk_x += compptr->h_samp_factor) {
491*4882a593Smuzhiyun 	  src_buffer = (*srcinfo->mem->access_virt_barray)
492*4882a593Smuzhiyun-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
493*4882a593Smuzhiyun+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci],
494*4882a593Smuzhiyun+	     dst_blk_x + x_crop_blocks,
495*4882a593Smuzhiyun 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
496*4882a593Smuzhiyun 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
497*4882a593Smuzhiyun 	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
498*4882a593Smuzhiyun-	    if (dst_blk_y < comp_height) {
499*4882a593Smuzhiyun+	    if (y_crop_blocks + dst_blk_y < comp_height) {
500*4882a593Smuzhiyun 	      /* Block is within the mirrorable area. */
501*4882a593Smuzhiyun 	      src_ptr = src_buffer[offset_x]
502*4882a593Smuzhiyun-		[comp_height - dst_blk_y - offset_y - 1];
503*4882a593Smuzhiyun+		[comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
504*4882a593Smuzhiyun 	      for (i = 0; i < DCTSIZE; i++) {
505*4882a593Smuzhiyun 		for (j = 0; j < DCTSIZE; j++) {
506*4882a593Smuzhiyun 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
507*4882a593Smuzhiyun@@ -341,7 +520,8 @@ do_rot_270 (j_decompress_ptr srcinfo, j_
508*4882a593Smuzhiyun 	      }
509*4882a593Smuzhiyun 	    } else {
510*4882a593Smuzhiyun 	      /* Edge blocks are transposed but not mirrored. */
511*4882a593Smuzhiyun-	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
512*4882a593Smuzhiyun+	      src_ptr = src_buffer[offset_x]
513*4882a593Smuzhiyun+		[dst_blk_y + offset_y + y_crop_blocks];
514*4882a593Smuzhiyun 	      for (i = 0; i < DCTSIZE; i++)
515*4882a593Smuzhiyun 		for (j = 0; j < DCTSIZE; j++)
516*4882a593Smuzhiyun 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
517*4882a593Smuzhiyun@@ -356,6 +536,7 @@ do_rot_270 (j_decompress_ptr srcinfo, j_
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun LOCAL(void)
520*4882a593Smuzhiyun do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
521*4882a593Smuzhiyun+	    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
522*4882a593Smuzhiyun 	    jvirt_barray_ptr *src_coef_arrays,
523*4882a593Smuzhiyun 	    jvirt_barray_ptr *dst_coef_arrays)
524*4882a593Smuzhiyun /* 180 degree rotation is equivalent to
525*4882a593Smuzhiyun@@ -365,89 +546,95 @@ do_rot_180 (j_decompress_ptr srcinfo, j_
526*4882a593Smuzhiyun  */
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
529*4882a593Smuzhiyun+  JDIMENSION x_crop_blocks, y_crop_blocks;
530*4882a593Smuzhiyun   int ci, i, j, offset_y;
531*4882a593Smuzhiyun   JBLOCKARRAY src_buffer, dst_buffer;
532*4882a593Smuzhiyun   JBLOCKROW src_row_ptr, dst_row_ptr;
533*4882a593Smuzhiyun   JCOEFPTR src_ptr, dst_ptr;
534*4882a593Smuzhiyun   jpeg_component_info *compptr;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
537*4882a593Smuzhiyun-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
538*4882a593Smuzhiyun+  MCU_cols = srcinfo->output_width /
539*4882a593Smuzhiyun+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
540*4882a593Smuzhiyun+  MCU_rows = srcinfo->output_height /
541*4882a593Smuzhiyun+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
544*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
545*4882a593Smuzhiyun     comp_width = MCU_cols * compptr->h_samp_factor;
546*4882a593Smuzhiyun     comp_height = MCU_rows * compptr->v_samp_factor;
547*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
548*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
549*4882a593Smuzhiyun     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
550*4882a593Smuzhiyun 	 dst_blk_y += compptr->v_samp_factor) {
551*4882a593Smuzhiyun       dst_buffer = (*srcinfo->mem->access_virt_barray)
552*4882a593Smuzhiyun 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
553*4882a593Smuzhiyun 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
554*4882a593Smuzhiyun-      if (dst_blk_y < comp_height) {
555*4882a593Smuzhiyun+      if (y_crop_blocks + dst_blk_y < comp_height) {
556*4882a593Smuzhiyun 	/* Row is within the vertically mirrorable area. */
557*4882a593Smuzhiyun 	src_buffer = (*srcinfo->mem->access_virt_barray)
558*4882a593Smuzhiyun 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
559*4882a593Smuzhiyun-	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
560*4882a593Smuzhiyun+	   comp_height - y_crop_blocks - dst_blk_y -
561*4882a593Smuzhiyun+	   (JDIMENSION) compptr->v_samp_factor,
562*4882a593Smuzhiyun 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
563*4882a593Smuzhiyun       } else {
564*4882a593Smuzhiyun 	/* Bottom-edge rows are only mirrored horizontally. */
565*4882a593Smuzhiyun 	src_buffer = (*srcinfo->mem->access_virt_barray)
566*4882a593Smuzhiyun-	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
567*4882a593Smuzhiyun+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
568*4882a593Smuzhiyun+	   dst_blk_y + y_crop_blocks,
569*4882a593Smuzhiyun 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
570*4882a593Smuzhiyun       }
571*4882a593Smuzhiyun       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
572*4882a593Smuzhiyun-	if (dst_blk_y < comp_height) {
573*4882a593Smuzhiyun+	dst_row_ptr = dst_buffer[offset_y];
574*4882a593Smuzhiyun+	if (y_crop_blocks + dst_blk_y < comp_height) {
575*4882a593Smuzhiyun 	  /* Row is within the mirrorable area. */
576*4882a593Smuzhiyun-	  dst_row_ptr = dst_buffer[offset_y];
577*4882a593Smuzhiyun 	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
578*4882a593Smuzhiyun-	  /* Process the blocks that can be mirrored both ways. */
579*4882a593Smuzhiyun-	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
580*4882a593Smuzhiyun+	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
581*4882a593Smuzhiyun 	    dst_ptr = dst_row_ptr[dst_blk_x];
582*4882a593Smuzhiyun-	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
583*4882a593Smuzhiyun-	    for (i = 0; i < DCTSIZE; i += 2) {
584*4882a593Smuzhiyun-	      /* For even row, negate every odd column. */
585*4882a593Smuzhiyun-	      for (j = 0; j < DCTSIZE; j += 2) {
586*4882a593Smuzhiyun-		*dst_ptr++ = *src_ptr++;
587*4882a593Smuzhiyun-		*dst_ptr++ = - *src_ptr++;
588*4882a593Smuzhiyun+	    if (x_crop_blocks + dst_blk_x < comp_width) {
589*4882a593Smuzhiyun+	      /* Process the blocks that can be mirrored both ways. */
590*4882a593Smuzhiyun+	      src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
591*4882a593Smuzhiyun+	      for (i = 0; i < DCTSIZE; i += 2) {
592*4882a593Smuzhiyun+		/* For even row, negate every odd column. */
593*4882a593Smuzhiyun+		for (j = 0; j < DCTSIZE; j += 2) {
594*4882a593Smuzhiyun+		  *dst_ptr++ = *src_ptr++;
595*4882a593Smuzhiyun+		  *dst_ptr++ = - *src_ptr++;
596*4882a593Smuzhiyun+		}
597*4882a593Smuzhiyun+		/* For odd row, negate every even column. */
598*4882a593Smuzhiyun+		for (j = 0; j < DCTSIZE; j += 2) {
599*4882a593Smuzhiyun+		  *dst_ptr++ = - *src_ptr++;
600*4882a593Smuzhiyun+		  *dst_ptr++ = *src_ptr++;
601*4882a593Smuzhiyun+		}
602*4882a593Smuzhiyun 	      }
603*4882a593Smuzhiyun-	      /* For odd row, negate every even column. */
604*4882a593Smuzhiyun-	      for (j = 0; j < DCTSIZE; j += 2) {
605*4882a593Smuzhiyun-		*dst_ptr++ = - *src_ptr++;
606*4882a593Smuzhiyun-		*dst_ptr++ = *src_ptr++;
607*4882a593Smuzhiyun+	    } else {
608*4882a593Smuzhiyun+	      /* Any remaining right-edge blocks are only mirrored vertically. */
609*4882a593Smuzhiyun+	      src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
610*4882a593Smuzhiyun+	      for (i = 0; i < DCTSIZE; i += 2) {
611*4882a593Smuzhiyun+		for (j = 0; j < DCTSIZE; j++)
612*4882a593Smuzhiyun+		  *dst_ptr++ = *src_ptr++;
613*4882a593Smuzhiyun+		for (j = 0; j < DCTSIZE; j++)
614*4882a593Smuzhiyun+		  *dst_ptr++ = - *src_ptr++;
615*4882a593Smuzhiyun 	      }
616*4882a593Smuzhiyun 	    }
617*4882a593Smuzhiyun 	  }
618*4882a593Smuzhiyun-	  /* Any remaining right-edge blocks are only mirrored vertically. */
619*4882a593Smuzhiyun-	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
620*4882a593Smuzhiyun-	    dst_ptr = dst_row_ptr[dst_blk_x];
621*4882a593Smuzhiyun-	    src_ptr = src_row_ptr[dst_blk_x];
622*4882a593Smuzhiyun-	    for (i = 0; i < DCTSIZE; i += 2) {
623*4882a593Smuzhiyun-	      for (j = 0; j < DCTSIZE; j++)
624*4882a593Smuzhiyun-		*dst_ptr++ = *src_ptr++;
625*4882a593Smuzhiyun-	      for (j = 0; j < DCTSIZE; j++)
626*4882a593Smuzhiyun-		*dst_ptr++ = - *src_ptr++;
627*4882a593Smuzhiyun-	    }
628*4882a593Smuzhiyun-	  }
629*4882a593Smuzhiyun 	} else {
630*4882a593Smuzhiyun 	  /* Remaining rows are just mirrored horizontally. */
631*4882a593Smuzhiyun-	  dst_row_ptr = dst_buffer[offset_y];
632*4882a593Smuzhiyun 	  src_row_ptr = src_buffer[offset_y];
633*4882a593Smuzhiyun-	  /* Process the blocks that can be mirrored. */
634*4882a593Smuzhiyun-	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
635*4882a593Smuzhiyun-	    dst_ptr = dst_row_ptr[dst_blk_x];
636*4882a593Smuzhiyun-	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
637*4882a593Smuzhiyun-	    for (i = 0; i < DCTSIZE2; i += 2) {
638*4882a593Smuzhiyun-	      *dst_ptr++ = *src_ptr++;
639*4882a593Smuzhiyun-	      *dst_ptr++ = - *src_ptr++;
640*4882a593Smuzhiyun+	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
641*4882a593Smuzhiyun+	    if (x_crop_blocks + dst_blk_x < comp_width) {
642*4882a593Smuzhiyun+	      /* Process the blocks that can be mirrored. */
643*4882a593Smuzhiyun+	      dst_ptr = dst_row_ptr[dst_blk_x];
644*4882a593Smuzhiyun+	      src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
645*4882a593Smuzhiyun+	      for (i = 0; i < DCTSIZE2; i += 2) {
646*4882a593Smuzhiyun+		*dst_ptr++ = *src_ptr++;
647*4882a593Smuzhiyun+		*dst_ptr++ = - *src_ptr++;
648*4882a593Smuzhiyun+	      }
649*4882a593Smuzhiyun+	    } else {
650*4882a593Smuzhiyun+	      /* Any remaining right-edge blocks are only copied. */
651*4882a593Smuzhiyun+	      jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
652*4882a593Smuzhiyun+			      dst_row_ptr + dst_blk_x,
653*4882a593Smuzhiyun+			      (JDIMENSION) 1);
654*4882a593Smuzhiyun 	    }
655*4882a593Smuzhiyun 	  }
656*4882a593Smuzhiyun-	  /* Any remaining right-edge blocks are only copied. */
657*4882a593Smuzhiyun-	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
658*4882a593Smuzhiyun-	    dst_ptr = dst_row_ptr[dst_blk_x];
659*4882a593Smuzhiyun-	    src_ptr = src_row_ptr[dst_blk_x];
660*4882a593Smuzhiyun-	    for (i = 0; i < DCTSIZE2; i++)
661*4882a593Smuzhiyun-	      *dst_ptr++ = *src_ptr++;
662*4882a593Smuzhiyun-	  }
663*4882a593Smuzhiyun 	}
664*4882a593Smuzhiyun       }
665*4882a593Smuzhiyun     }
666*4882a593Smuzhiyun@@ -457,6 +644,7 @@ do_rot_180 (j_decompress_ptr srcinfo, j_
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun LOCAL(void)
669*4882a593Smuzhiyun do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
670*4882a593Smuzhiyun+	       JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
671*4882a593Smuzhiyun 	       jvirt_barray_ptr *src_coef_arrays,
672*4882a593Smuzhiyun 	       jvirt_barray_ptr *dst_coef_arrays)
673*4882a593Smuzhiyun /* Transverse transpose is equivalent to
674*4882a593Smuzhiyun@@ -470,18 +658,23 @@ do_transverse (j_decompress_ptr srcinfo,
675*4882a593Smuzhiyun  */
676*4882a593Smuzhiyun {
677*4882a593Smuzhiyun   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
678*4882a593Smuzhiyun+  JDIMENSION x_crop_blocks, y_crop_blocks;
679*4882a593Smuzhiyun   int ci, i, j, offset_x, offset_y;
680*4882a593Smuzhiyun   JBLOCKARRAY src_buffer, dst_buffer;
681*4882a593Smuzhiyun   JCOEFPTR src_ptr, dst_ptr;
682*4882a593Smuzhiyun   jpeg_component_info *compptr;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
685*4882a593Smuzhiyun-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
686*4882a593Smuzhiyun+  MCU_cols = srcinfo->output_height /
687*4882a593Smuzhiyun+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
688*4882a593Smuzhiyun+  MCU_rows = srcinfo->output_width /
689*4882a593Smuzhiyun+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
692*4882a593Smuzhiyun     compptr = dstinfo->comp_info + ci;
693*4882a593Smuzhiyun     comp_width = MCU_cols * compptr->h_samp_factor;
694*4882a593Smuzhiyun     comp_height = MCU_rows * compptr->v_samp_factor;
695*4882a593Smuzhiyun+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
696*4882a593Smuzhiyun+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
697*4882a593Smuzhiyun     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
698*4882a593Smuzhiyun 	 dst_blk_y += compptr->v_samp_factor) {
699*4882a593Smuzhiyun       dst_buffer = (*srcinfo->mem->access_virt_barray)
700*4882a593Smuzhiyun@@ -490,17 +683,26 @@ do_transverse (j_decompress_ptr srcinfo,
701*4882a593Smuzhiyun       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
702*4882a593Smuzhiyun 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
703*4882a593Smuzhiyun 	     dst_blk_x += compptr->h_samp_factor) {
704*4882a593Smuzhiyun-	  src_buffer = (*srcinfo->mem->access_virt_barray)
705*4882a593Smuzhiyun-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
706*4882a593Smuzhiyun-	     (JDIMENSION) compptr->h_samp_factor, FALSE);
707*4882a593Smuzhiyun+	  if (x_crop_blocks + dst_blk_x < comp_width) {
708*4882a593Smuzhiyun+	    /* Block is within the mirrorable area. */
709*4882a593Smuzhiyun+	    src_buffer = (*srcinfo->mem->access_virt_barray)
710*4882a593Smuzhiyun+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
711*4882a593Smuzhiyun+	       comp_width - x_crop_blocks - dst_blk_x -
712*4882a593Smuzhiyun+	       (JDIMENSION) compptr->h_samp_factor,
713*4882a593Smuzhiyun+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
714*4882a593Smuzhiyun+	  } else {
715*4882a593Smuzhiyun+	    src_buffer = (*srcinfo->mem->access_virt_barray)
716*4882a593Smuzhiyun+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
717*4882a593Smuzhiyun+	       dst_blk_x + x_crop_blocks,
718*4882a593Smuzhiyun+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
719*4882a593Smuzhiyun+	  }
720*4882a593Smuzhiyun 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
721*4882a593Smuzhiyun-	    if (dst_blk_y < comp_height) {
722*4882a593Smuzhiyun-	      src_ptr = src_buffer[offset_x]
723*4882a593Smuzhiyun-		[comp_height - dst_blk_y - offset_y - 1];
724*4882a593Smuzhiyun-	      if (dst_blk_x < comp_width) {
725*4882a593Smuzhiyun+	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
726*4882a593Smuzhiyun+	    if (y_crop_blocks + dst_blk_y < comp_height) {
727*4882a593Smuzhiyun+	      if (x_crop_blocks + dst_blk_x < comp_width) {
728*4882a593Smuzhiyun 		/* Block is within the mirrorable area. */
729*4882a593Smuzhiyun-		dst_ptr = dst_buffer[offset_y]
730*4882a593Smuzhiyun-		  [comp_width - dst_blk_x - offset_x - 1];
731*4882a593Smuzhiyun+		src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
732*4882a593Smuzhiyun+		  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
733*4882a593Smuzhiyun 		for (i = 0; i < DCTSIZE; i++) {
734*4882a593Smuzhiyun 		  for (j = 0; j < DCTSIZE; j++) {
735*4882a593Smuzhiyun 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
736*4882a593Smuzhiyun@@ -516,7 +718,8 @@ do_transverse (j_decompress_ptr srcinfo,
737*4882a593Smuzhiyun 		}
738*4882a593Smuzhiyun 	      } else {
739*4882a593Smuzhiyun 		/* Right-edge blocks are mirrored in y only */
740*4882a593Smuzhiyun-		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
741*4882a593Smuzhiyun+		src_ptr = src_buffer[offset_x]
742*4882a593Smuzhiyun+		  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
743*4882a593Smuzhiyun 		for (i = 0; i < DCTSIZE; i++) {
744*4882a593Smuzhiyun 		  for (j = 0; j < DCTSIZE; j++) {
745*4882a593Smuzhiyun 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
746*4882a593Smuzhiyun@@ -526,11 +729,10 @@ do_transverse (j_decompress_ptr srcinfo,
747*4882a593Smuzhiyun 		}
748*4882a593Smuzhiyun 	      }
749*4882a593Smuzhiyun 	    } else {
750*4882a593Smuzhiyun-	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
751*4882a593Smuzhiyun-	      if (dst_blk_x < comp_width) {
752*4882a593Smuzhiyun+	      if (x_crop_blocks + dst_blk_x < comp_width) {
753*4882a593Smuzhiyun 		/* Bottom-edge blocks are mirrored in x only */
754*4882a593Smuzhiyun-		dst_ptr = dst_buffer[offset_y]
755*4882a593Smuzhiyun-		  [comp_width - dst_blk_x - offset_x - 1];
756*4882a593Smuzhiyun+		src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
757*4882a593Smuzhiyun+		  [dst_blk_y + offset_y + y_crop_blocks];
758*4882a593Smuzhiyun 		for (i = 0; i < DCTSIZE; i++) {
759*4882a593Smuzhiyun 		  for (j = 0; j < DCTSIZE; j++)
760*4882a593Smuzhiyun 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
761*4882a593Smuzhiyun@@ -540,7 +742,8 @@ do_transverse (j_decompress_ptr srcinfo,
762*4882a593Smuzhiyun 		}
763*4882a593Smuzhiyun 	      } else {
764*4882a593Smuzhiyun 		/* At lower right corner, just transpose, no mirroring */
765*4882a593Smuzhiyun-		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
766*4882a593Smuzhiyun+		src_ptr = src_buffer[offset_x]
767*4882a593Smuzhiyun+		  [dst_blk_y + offset_y + y_crop_blocks];
768*4882a593Smuzhiyun 		for (i = 0; i < DCTSIZE; i++)
769*4882a593Smuzhiyun 		  for (j = 0; j < DCTSIZE; j++)
770*4882a593Smuzhiyun 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
771*4882a593Smuzhiyun@@ -554,83 +757,372 @@ do_transverse (j_decompress_ptr srcinfo,
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun+/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
776*4882a593Smuzhiyun+ * Returns TRUE if valid integer found, FALSE if not.
777*4882a593Smuzhiyun+ * *strptr is advanced over the digit string, and *result is set to its value.
778*4882a593Smuzhiyun+ */
779*4882a593Smuzhiyun+
780*4882a593Smuzhiyun+LOCAL(boolean)
781*4882a593Smuzhiyun+jt_read_integer (const char ** strptr, JDIMENSION * result)
782*4882a593Smuzhiyun+{
783*4882a593Smuzhiyun+  const char * ptr = *strptr;
784*4882a593Smuzhiyun+  JDIMENSION val = 0;
785*4882a593Smuzhiyun+
786*4882a593Smuzhiyun+  for (; isdigit(*ptr); ptr++) {
787*4882a593Smuzhiyun+    val = val * 10 + (JDIMENSION) (*ptr - '0');
788*4882a593Smuzhiyun+  }
789*4882a593Smuzhiyun+  *result = val;
790*4882a593Smuzhiyun+  if (ptr == *strptr)
791*4882a593Smuzhiyun+    return FALSE;		/* oops, no digits */
792*4882a593Smuzhiyun+  *strptr = ptr;
793*4882a593Smuzhiyun+  return TRUE;
794*4882a593Smuzhiyun+}
795*4882a593Smuzhiyun+
796*4882a593Smuzhiyun+
797*4882a593Smuzhiyun+/* Parse a crop specification (written in X11 geometry style).
798*4882a593Smuzhiyun+ * The routine returns TRUE if the spec string is valid, FALSE if not.
799*4882a593Smuzhiyun+ *
800*4882a593Smuzhiyun+ * The crop spec string should have the format
801*4882a593Smuzhiyun+ *	<width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset>
802*4882a593Smuzhiyun+ * where width, height, xoffset, and yoffset are unsigned integers.
803*4882a593Smuzhiyun+ * Each of the elements can be omitted to indicate a default value.
804*4882a593Smuzhiyun+ * (A weakness of this style is that it is not possible to omit xoffset
805*4882a593Smuzhiyun+ * while specifying yoffset, since they look alike.)
806*4882a593Smuzhiyun+ *
807*4882a593Smuzhiyun+ * This code is loosely based on XParseGeometry from the X11 distribution.
808*4882a593Smuzhiyun+ */
809*4882a593Smuzhiyun+
810*4882a593Smuzhiyun+GLOBAL(boolean)
811*4882a593Smuzhiyun+jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
812*4882a593Smuzhiyun+{
813*4882a593Smuzhiyun+  info->crop = FALSE;
814*4882a593Smuzhiyun+  info->crop_width_set = JCROP_UNSET;
815*4882a593Smuzhiyun+  info->crop_height_set = JCROP_UNSET;
816*4882a593Smuzhiyun+  info->crop_xoffset_set = JCROP_UNSET;
817*4882a593Smuzhiyun+  info->crop_yoffset_set = JCROP_UNSET;
818*4882a593Smuzhiyun+
819*4882a593Smuzhiyun+  if (isdigit(*spec)) {
820*4882a593Smuzhiyun+    /* fetch width */
821*4882a593Smuzhiyun+    if (! jt_read_integer(&spec, &info->crop_width))
822*4882a593Smuzhiyun+      return FALSE;
823*4882a593Smuzhiyun+    if (*spec == 'f' || *spec == 'F') {
824*4882a593Smuzhiyun+      spec++;
825*4882a593Smuzhiyun+      info->crop_width_set = JCROP_FORCE;
826*4882a593Smuzhiyun+    } else
827*4882a593Smuzhiyun+      info->crop_width_set = JCROP_POS;
828*4882a593Smuzhiyun+  }
829*4882a593Smuzhiyun+  if (*spec == 'x' || *spec == 'X') {
830*4882a593Smuzhiyun+    /* fetch height */
831*4882a593Smuzhiyun+    spec++;
832*4882a593Smuzhiyun+    if (! jt_read_integer(&spec, &info->crop_height))
833*4882a593Smuzhiyun+      return FALSE;
834*4882a593Smuzhiyun+    if (*spec == 'f' || *spec == 'F') {
835*4882a593Smuzhiyun+      spec++;
836*4882a593Smuzhiyun+      info->crop_height_set = JCROP_FORCE;
837*4882a593Smuzhiyun+    } else
838*4882a593Smuzhiyun+      info->crop_height_set = JCROP_POS;
839*4882a593Smuzhiyun+  }
840*4882a593Smuzhiyun+  if (*spec == '+' || *spec == '-') {
841*4882a593Smuzhiyun+    /* fetch xoffset */
842*4882a593Smuzhiyun+    info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
843*4882a593Smuzhiyun+    spec++;
844*4882a593Smuzhiyun+    if (! jt_read_integer(&spec, &info->crop_xoffset))
845*4882a593Smuzhiyun+      return FALSE;
846*4882a593Smuzhiyun+  }
847*4882a593Smuzhiyun+  if (*spec == '+' || *spec == '-') {
848*4882a593Smuzhiyun+    /* fetch yoffset */
849*4882a593Smuzhiyun+    info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
850*4882a593Smuzhiyun+    spec++;
851*4882a593Smuzhiyun+    if (! jt_read_integer(&spec, &info->crop_yoffset))
852*4882a593Smuzhiyun+      return FALSE;
853*4882a593Smuzhiyun+  }
854*4882a593Smuzhiyun+  /* We had better have gotten to the end of the string. */
855*4882a593Smuzhiyun+  if (*spec != '\0')
856*4882a593Smuzhiyun+    return FALSE;
857*4882a593Smuzhiyun+  info->crop = TRUE;
858*4882a593Smuzhiyun+  return TRUE;
859*4882a593Smuzhiyun+}
860*4882a593Smuzhiyun+
861*4882a593Smuzhiyun+
862*4882a593Smuzhiyun+/* Trim off any partial iMCUs on the indicated destination edge */
863*4882a593Smuzhiyun+
864*4882a593Smuzhiyun+LOCAL(void)
865*4882a593Smuzhiyun+trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
866*4882a593Smuzhiyun+{
867*4882a593Smuzhiyun+  JDIMENSION MCU_cols;
868*4882a593Smuzhiyun+
869*4882a593Smuzhiyun+  MCU_cols = info->output_width / info->iMCU_sample_width;
870*4882a593Smuzhiyun+  if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
871*4882a593Smuzhiyun+      full_width / info->iMCU_sample_width)
872*4882a593Smuzhiyun+    info->output_width = MCU_cols * info->iMCU_sample_width;
873*4882a593Smuzhiyun+}
874*4882a593Smuzhiyun+
875*4882a593Smuzhiyun+LOCAL(void)
876*4882a593Smuzhiyun+trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
877*4882a593Smuzhiyun+{
878*4882a593Smuzhiyun+  JDIMENSION MCU_rows;
879*4882a593Smuzhiyun+
880*4882a593Smuzhiyun+  MCU_rows = info->output_height / info->iMCU_sample_height;
881*4882a593Smuzhiyun+  if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
882*4882a593Smuzhiyun+      full_height / info->iMCU_sample_height)
883*4882a593Smuzhiyun+    info->output_height = MCU_rows * info->iMCU_sample_height;
884*4882a593Smuzhiyun+}
885*4882a593Smuzhiyun+
886*4882a593Smuzhiyun+
887*4882a593Smuzhiyun /* Request any required workspace.
888*4882a593Smuzhiyun  *
889*4882a593Smuzhiyun+ * This routine figures out the size that the output image will be
890*4882a593Smuzhiyun+ * (which implies that all the transform parameters must be set before
891*4882a593Smuzhiyun+ * it is called).
892*4882a593Smuzhiyun+ *
893*4882a593Smuzhiyun  * We allocate the workspace virtual arrays from the source decompression
894*4882a593Smuzhiyun  * object, so that all the arrays (both the original data and the workspace)
895*4882a593Smuzhiyun  * will be taken into account while making memory management decisions.
896*4882a593Smuzhiyun  * Hence, this routine must be called after jpeg_read_header (which reads
897*4882a593Smuzhiyun  * the image dimensions) and before jpeg_read_coefficients (which realizes
898*4882a593Smuzhiyun  * the source's virtual arrays).
899*4882a593Smuzhiyun+ *
900*4882a593Smuzhiyun+ * This function returns FALSE right away if -perfect is given
901*4882a593Smuzhiyun+ * and transformation is not perfect.  Otherwise returns TRUE.
902*4882a593Smuzhiyun  */
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun-GLOBAL(void)
905*4882a593Smuzhiyun+GLOBAL(boolean)
906*4882a593Smuzhiyun jtransform_request_workspace (j_decompress_ptr srcinfo,
907*4882a593Smuzhiyun 			      jpeg_transform_info *info)
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun-  jvirt_barray_ptr *coef_arrays = NULL;
910*4882a593Smuzhiyun+  jvirt_barray_ptr *coef_arrays;
911*4882a593Smuzhiyun+  boolean need_workspace, transpose_it;
912*4882a593Smuzhiyun   jpeg_component_info *compptr;
913*4882a593Smuzhiyun-  int ci;
914*4882a593Smuzhiyun+  JDIMENSION xoffset, yoffset;
915*4882a593Smuzhiyun+  JDIMENSION width_in_iMCUs, height_in_iMCUs;
916*4882a593Smuzhiyun+  JDIMENSION width_in_blocks, height_in_blocks;
917*4882a593Smuzhiyun+  int ci, h_samp_factor, v_samp_factor;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun+  /* Determine number of components in output image */
920*4882a593Smuzhiyun   if (info->force_grayscale &&
921*4882a593Smuzhiyun       srcinfo->jpeg_color_space == JCS_YCbCr &&
922*4882a593Smuzhiyun-      srcinfo->num_components == 3) {
923*4882a593Smuzhiyun+      srcinfo->num_components == 3)
924*4882a593Smuzhiyun     /* We'll only process the first component */
925*4882a593Smuzhiyun     info->num_components = 1;
926*4882a593Smuzhiyun-  } else {
927*4882a593Smuzhiyun+  else
928*4882a593Smuzhiyun     /* Process all the components */
929*4882a593Smuzhiyun     info->num_components = srcinfo->num_components;
930*4882a593Smuzhiyun+
931*4882a593Smuzhiyun+  /* Compute output image dimensions and related values. */
932*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 80
933*4882a593Smuzhiyun+  jpeg_core_output_dimensions(srcinfo);
934*4882a593Smuzhiyun+#else
935*4882a593Smuzhiyun+  srcinfo->output_width = srcinfo->image_width;
936*4882a593Smuzhiyun+  srcinfo->output_height = srcinfo->image_height;
937*4882a593Smuzhiyun+#endif
938*4882a593Smuzhiyun+
939*4882a593Smuzhiyun+  /* Return right away if -perfect is given and transformation is not perfect.
940*4882a593Smuzhiyun+   */
941*4882a593Smuzhiyun+  if (info->perfect) {
942*4882a593Smuzhiyun+    if (info->num_components == 1) {
943*4882a593Smuzhiyun+      if (!jtransform_perfect_transform(srcinfo->output_width,
944*4882a593Smuzhiyun+	  srcinfo->output_height,
945*4882a593Smuzhiyun+	  srcinfo->_min_DCT_h_scaled_size,
946*4882a593Smuzhiyun+	  srcinfo->_min_DCT_v_scaled_size,
947*4882a593Smuzhiyun+	  info->transform))
948*4882a593Smuzhiyun+	return FALSE;
949*4882a593Smuzhiyun+    } else {
950*4882a593Smuzhiyun+      if (!jtransform_perfect_transform(srcinfo->output_width,
951*4882a593Smuzhiyun+	  srcinfo->output_height,
952*4882a593Smuzhiyun+	  srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size,
953*4882a593Smuzhiyun+	  srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size,
954*4882a593Smuzhiyun+	  info->transform))
955*4882a593Smuzhiyun+	return FALSE;
956*4882a593Smuzhiyun+    }
957*4882a593Smuzhiyun+  }
958*4882a593Smuzhiyun+
959*4882a593Smuzhiyun+  /* If there is only one output component, force the iMCU size to be 1;
960*4882a593Smuzhiyun+   * else use the source iMCU size.  (This allows us to do the right thing
961*4882a593Smuzhiyun+   * when reducing color to grayscale, and also provides a handy way of
962*4882a593Smuzhiyun+   * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
963*4882a593Smuzhiyun+   */
964*4882a593Smuzhiyun+  switch (info->transform) {
965*4882a593Smuzhiyun+  case JXFORM_TRANSPOSE:
966*4882a593Smuzhiyun+  case JXFORM_TRANSVERSE:
967*4882a593Smuzhiyun+  case JXFORM_ROT_90:
968*4882a593Smuzhiyun+  case JXFORM_ROT_270:
969*4882a593Smuzhiyun+    info->output_width = srcinfo->output_height;
970*4882a593Smuzhiyun+    info->output_height = srcinfo->output_width;
971*4882a593Smuzhiyun+    if (info->num_components == 1) {
972*4882a593Smuzhiyun+      info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size;
973*4882a593Smuzhiyun+      info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size;
974*4882a593Smuzhiyun+    } else {
975*4882a593Smuzhiyun+      info->iMCU_sample_width =
976*4882a593Smuzhiyun+	srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
977*4882a593Smuzhiyun+      info->iMCU_sample_height =
978*4882a593Smuzhiyun+	srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
979*4882a593Smuzhiyun+    }
980*4882a593Smuzhiyun+    break;
981*4882a593Smuzhiyun+  default:
982*4882a593Smuzhiyun+    info->output_width = srcinfo->output_width;
983*4882a593Smuzhiyun+    info->output_height = srcinfo->output_height;
984*4882a593Smuzhiyun+    if (info->num_components == 1) {
985*4882a593Smuzhiyun+      info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size;
986*4882a593Smuzhiyun+      info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size;
987*4882a593Smuzhiyun+    } else {
988*4882a593Smuzhiyun+      info->iMCU_sample_width =
989*4882a593Smuzhiyun+	srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
990*4882a593Smuzhiyun+      info->iMCU_sample_height =
991*4882a593Smuzhiyun+	srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
992*4882a593Smuzhiyun+    }
993*4882a593Smuzhiyun+    break;
994*4882a593Smuzhiyun   }
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun+  /* If cropping has been requested, compute the crop area's position and
997*4882a593Smuzhiyun+   * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
998*4882a593Smuzhiyun+   */
999*4882a593Smuzhiyun+  if (info->crop) {
1000*4882a593Smuzhiyun+    /* Insert default values for unset crop parameters */
1001*4882a593Smuzhiyun+    if (info->crop_xoffset_set == JCROP_UNSET)
1002*4882a593Smuzhiyun+      info->crop_xoffset = 0;	/* default to +0 */
1003*4882a593Smuzhiyun+    if (info->crop_yoffset_set == JCROP_UNSET)
1004*4882a593Smuzhiyun+      info->crop_yoffset = 0;	/* default to +0 */
1005*4882a593Smuzhiyun+    if (info->crop_xoffset >= info->output_width ||
1006*4882a593Smuzhiyun+	info->crop_yoffset >= info->output_height)
1007*4882a593Smuzhiyun+      ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1008*4882a593Smuzhiyun+    if (info->crop_width_set == JCROP_UNSET)
1009*4882a593Smuzhiyun+      info->crop_width = info->output_width - info->crop_xoffset;
1010*4882a593Smuzhiyun+    if (info->crop_height_set == JCROP_UNSET)
1011*4882a593Smuzhiyun+      info->crop_height = info->output_height - info->crop_yoffset;
1012*4882a593Smuzhiyun+    /* Ensure parameters are valid */
1013*4882a593Smuzhiyun+    if (info->crop_width <= 0 || info->crop_width > info->output_width ||
1014*4882a593Smuzhiyun+	info->crop_height <= 0 || info->crop_height > info->output_height ||
1015*4882a593Smuzhiyun+	info->crop_xoffset > info->output_width - info->crop_width ||
1016*4882a593Smuzhiyun+	info->crop_yoffset > info->output_height - info->crop_height)
1017*4882a593Smuzhiyun+      ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1018*4882a593Smuzhiyun+    /* Convert negative crop offsets into regular offsets */
1019*4882a593Smuzhiyun+    if (info->crop_xoffset_set == JCROP_NEG)
1020*4882a593Smuzhiyun+      xoffset = info->output_width - info->crop_width - info->crop_xoffset;
1021*4882a593Smuzhiyun+    else
1022*4882a593Smuzhiyun+      xoffset = info->crop_xoffset;
1023*4882a593Smuzhiyun+    if (info->crop_yoffset_set == JCROP_NEG)
1024*4882a593Smuzhiyun+      yoffset = info->output_height - info->crop_height - info->crop_yoffset;
1025*4882a593Smuzhiyun+    else
1026*4882a593Smuzhiyun+      yoffset = info->crop_yoffset;
1027*4882a593Smuzhiyun+    /* Now adjust so that upper left corner falls at an iMCU boundary */
1028*4882a593Smuzhiyun+    if (info->crop_width_set == JCROP_FORCE)
1029*4882a593Smuzhiyun+      info->output_width = info->crop_width;
1030*4882a593Smuzhiyun+    else
1031*4882a593Smuzhiyun+      info->output_width =
1032*4882a593Smuzhiyun+        info->crop_width + (xoffset % info->iMCU_sample_width);
1033*4882a593Smuzhiyun+    if (info->crop_height_set == JCROP_FORCE)
1034*4882a593Smuzhiyun+      info->output_height = info->crop_height;
1035*4882a593Smuzhiyun+    else
1036*4882a593Smuzhiyun+      info->output_height =
1037*4882a593Smuzhiyun+        info->crop_height + (yoffset % info->iMCU_sample_height);
1038*4882a593Smuzhiyun+    /* Save x/y offsets measured in iMCUs */
1039*4882a593Smuzhiyun+    info->x_crop_offset = xoffset / info->iMCU_sample_width;
1040*4882a593Smuzhiyun+    info->y_crop_offset = yoffset / info->iMCU_sample_height;
1041*4882a593Smuzhiyun+  } else {
1042*4882a593Smuzhiyun+    info->x_crop_offset = 0;
1043*4882a593Smuzhiyun+    info->y_crop_offset = 0;
1044*4882a593Smuzhiyun+  }
1045*4882a593Smuzhiyun+
1046*4882a593Smuzhiyun+  /* Figure out whether we need workspace arrays,
1047*4882a593Smuzhiyun+   * and if so whether they are transposed relative to the source.
1048*4882a593Smuzhiyun+   */
1049*4882a593Smuzhiyun+  need_workspace = FALSE;
1050*4882a593Smuzhiyun+  transpose_it = FALSE;
1051*4882a593Smuzhiyun   switch (info->transform) {
1052*4882a593Smuzhiyun   case JXFORM_NONE:
1053*4882a593Smuzhiyun+    if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1054*4882a593Smuzhiyun+      need_workspace = TRUE;
1055*4882a593Smuzhiyun+    /* No workspace needed if neither cropping nor transforming */
1056*4882a593Smuzhiyun+    break;
1057*4882a593Smuzhiyun   case JXFORM_FLIP_H:
1058*4882a593Smuzhiyun-    /* Don't need a workspace array */
1059*4882a593Smuzhiyun+    if (info->trim)
1060*4882a593Smuzhiyun+      trim_right_edge(info, srcinfo->output_width);
1061*4882a593Smuzhiyun+    if (info->y_crop_offset != 0 || info->slow_hflip)
1062*4882a593Smuzhiyun+      need_workspace = TRUE;
1063*4882a593Smuzhiyun+    /* do_flip_h_no_crop doesn't need a workspace array */
1064*4882a593Smuzhiyun     break;
1065*4882a593Smuzhiyun   case JXFORM_FLIP_V:
1066*4882a593Smuzhiyun-  case JXFORM_ROT_180:
1067*4882a593Smuzhiyun-    /* Need workspace arrays having same dimensions as source image.
1068*4882a593Smuzhiyun-     * Note that we allocate arrays padded out to the next iMCU boundary,
1069*4882a593Smuzhiyun-     * so that transform routines need not worry about missing edge blocks.
1070*4882a593Smuzhiyun-     */
1071*4882a593Smuzhiyun-    coef_arrays = (jvirt_barray_ptr *)
1072*4882a593Smuzhiyun-      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1073*4882a593Smuzhiyun-	SIZEOF(jvirt_barray_ptr) * info->num_components);
1074*4882a593Smuzhiyun-    for (ci = 0; ci < info->num_components; ci++) {
1075*4882a593Smuzhiyun-      compptr = srcinfo->comp_info + ci;
1076*4882a593Smuzhiyun-      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1077*4882a593Smuzhiyun-	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1078*4882a593Smuzhiyun-	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
1079*4882a593Smuzhiyun-				(long) compptr->h_samp_factor),
1080*4882a593Smuzhiyun-	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
1081*4882a593Smuzhiyun-				(long) compptr->v_samp_factor),
1082*4882a593Smuzhiyun-	 (JDIMENSION) compptr->v_samp_factor);
1083*4882a593Smuzhiyun-    }
1084*4882a593Smuzhiyun+    if (info->trim)
1085*4882a593Smuzhiyun+      trim_bottom_edge(info, srcinfo->output_height);
1086*4882a593Smuzhiyun+    /* Need workspace arrays having same dimensions as source image. */
1087*4882a593Smuzhiyun+    need_workspace = TRUE;
1088*4882a593Smuzhiyun     break;
1089*4882a593Smuzhiyun   case JXFORM_TRANSPOSE:
1090*4882a593Smuzhiyun+    /* transpose does NOT have to trim anything */
1091*4882a593Smuzhiyun+    /* Need workspace arrays having transposed dimensions. */
1092*4882a593Smuzhiyun+    need_workspace = TRUE;
1093*4882a593Smuzhiyun+    transpose_it = TRUE;
1094*4882a593Smuzhiyun+    break;
1095*4882a593Smuzhiyun   case JXFORM_TRANSVERSE:
1096*4882a593Smuzhiyun+    if (info->trim) {
1097*4882a593Smuzhiyun+      trim_right_edge(info, srcinfo->output_height);
1098*4882a593Smuzhiyun+      trim_bottom_edge(info, srcinfo->output_width);
1099*4882a593Smuzhiyun+    }
1100*4882a593Smuzhiyun+    /* Need workspace arrays having transposed dimensions. */
1101*4882a593Smuzhiyun+    need_workspace = TRUE;
1102*4882a593Smuzhiyun+    transpose_it = TRUE;
1103*4882a593Smuzhiyun+    break;
1104*4882a593Smuzhiyun   case JXFORM_ROT_90:
1105*4882a593Smuzhiyun+    if (info->trim)
1106*4882a593Smuzhiyun+      trim_right_edge(info, srcinfo->output_height);
1107*4882a593Smuzhiyun+    /* Need workspace arrays having transposed dimensions. */
1108*4882a593Smuzhiyun+    need_workspace = TRUE;
1109*4882a593Smuzhiyun+    transpose_it = TRUE;
1110*4882a593Smuzhiyun+    break;
1111*4882a593Smuzhiyun+  case JXFORM_ROT_180:
1112*4882a593Smuzhiyun+    if (info->trim) {
1113*4882a593Smuzhiyun+      trim_right_edge(info, srcinfo->output_width);
1114*4882a593Smuzhiyun+      trim_bottom_edge(info, srcinfo->output_height);
1115*4882a593Smuzhiyun+    }
1116*4882a593Smuzhiyun+    /* Need workspace arrays having same dimensions as source image. */
1117*4882a593Smuzhiyun+    need_workspace = TRUE;
1118*4882a593Smuzhiyun+    break;
1119*4882a593Smuzhiyun   case JXFORM_ROT_270:
1120*4882a593Smuzhiyun-    /* Need workspace arrays having transposed dimensions.
1121*4882a593Smuzhiyun-     * Note that we allocate arrays padded out to the next iMCU boundary,
1122*4882a593Smuzhiyun-     * so that transform routines need not worry about missing edge blocks.
1123*4882a593Smuzhiyun-     */
1124*4882a593Smuzhiyun+    if (info->trim)
1125*4882a593Smuzhiyun+      trim_bottom_edge(info, srcinfo->output_width);
1126*4882a593Smuzhiyun+    /* Need workspace arrays having transposed dimensions. */
1127*4882a593Smuzhiyun+    need_workspace = TRUE;
1128*4882a593Smuzhiyun+    transpose_it = TRUE;
1129*4882a593Smuzhiyun+    break;
1130*4882a593Smuzhiyun+  }
1131*4882a593Smuzhiyun+
1132*4882a593Smuzhiyun+  /* Allocate workspace if needed.
1133*4882a593Smuzhiyun+   * Note that we allocate arrays padded out to the next iMCU boundary,
1134*4882a593Smuzhiyun+   * so that transform routines need not worry about missing edge blocks.
1135*4882a593Smuzhiyun+   */
1136*4882a593Smuzhiyun+  if (need_workspace) {
1137*4882a593Smuzhiyun     coef_arrays = (jvirt_barray_ptr *)
1138*4882a593Smuzhiyun       (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1139*4882a593Smuzhiyun-	SIZEOF(jvirt_barray_ptr) * info->num_components);
1140*4882a593Smuzhiyun+		SIZEOF(jvirt_barray_ptr) * info->num_components);
1141*4882a593Smuzhiyun+    width_in_iMCUs = (JDIMENSION)
1142*4882a593Smuzhiyun+      jdiv_round_up((long) info->output_width,
1143*4882a593Smuzhiyun+		    (long) info->iMCU_sample_width);
1144*4882a593Smuzhiyun+    height_in_iMCUs = (JDIMENSION)
1145*4882a593Smuzhiyun+      jdiv_round_up((long) info->output_height,
1146*4882a593Smuzhiyun+		    (long) info->iMCU_sample_height);
1147*4882a593Smuzhiyun     for (ci = 0; ci < info->num_components; ci++) {
1148*4882a593Smuzhiyun       compptr = srcinfo->comp_info + ci;
1149*4882a593Smuzhiyun+      if (info->num_components == 1) {
1150*4882a593Smuzhiyun+	/* we're going to force samp factors to 1x1 in this case */
1151*4882a593Smuzhiyun+	h_samp_factor = v_samp_factor = 1;
1152*4882a593Smuzhiyun+      } else if (transpose_it) {
1153*4882a593Smuzhiyun+	h_samp_factor = compptr->v_samp_factor;
1154*4882a593Smuzhiyun+	v_samp_factor = compptr->h_samp_factor;
1155*4882a593Smuzhiyun+      } else {
1156*4882a593Smuzhiyun+	h_samp_factor = compptr->h_samp_factor;
1157*4882a593Smuzhiyun+	v_samp_factor = compptr->v_samp_factor;
1158*4882a593Smuzhiyun+      }
1159*4882a593Smuzhiyun+      width_in_blocks = width_in_iMCUs * h_samp_factor;
1160*4882a593Smuzhiyun+      height_in_blocks = height_in_iMCUs * v_samp_factor;
1161*4882a593Smuzhiyun       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1162*4882a593Smuzhiyun 	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1163*4882a593Smuzhiyun-	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
1164*4882a593Smuzhiyun-				(long) compptr->v_samp_factor),
1165*4882a593Smuzhiyun-	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
1166*4882a593Smuzhiyun-				(long) compptr->h_samp_factor),
1167*4882a593Smuzhiyun-	 (JDIMENSION) compptr->h_samp_factor);
1168*4882a593Smuzhiyun+	 width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
1169*4882a593Smuzhiyun     }
1170*4882a593Smuzhiyun-    break;
1171*4882a593Smuzhiyun-  }
1172*4882a593Smuzhiyun-  info->workspace_coef_arrays = coef_arrays;
1173*4882a593Smuzhiyun+    info->workspace_coef_arrays = coef_arrays;
1174*4882a593Smuzhiyun+  } else
1175*4882a593Smuzhiyun+    info->workspace_coef_arrays = NULL;
1176*4882a593Smuzhiyun+
1177*4882a593Smuzhiyun+  return TRUE;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun@@ -642,13 +1134,18 @@ transpose_critical_parameters (j_compres
1182*4882a593Smuzhiyun   int tblno, i, j, ci, itemp;
1183*4882a593Smuzhiyun   jpeg_component_info *compptr;
1184*4882a593Smuzhiyun   JQUANT_TBL *qtblptr;
1185*4882a593Smuzhiyun-  JDIMENSION dtemp;
1186*4882a593Smuzhiyun+  JDIMENSION jtemp;
1187*4882a593Smuzhiyun   UINT16 qtemp;
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun-  /* Transpose basic image dimensions */
1190*4882a593Smuzhiyun-  dtemp = dstinfo->image_width;
1191*4882a593Smuzhiyun+  /* Transpose image dimensions */
1192*4882a593Smuzhiyun+  jtemp = dstinfo->image_width;
1193*4882a593Smuzhiyun   dstinfo->image_width = dstinfo->image_height;
1194*4882a593Smuzhiyun-  dstinfo->image_height = dtemp;
1195*4882a593Smuzhiyun+  dstinfo->image_height = jtemp;
1196*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 70
1197*4882a593Smuzhiyun+  itemp = dstinfo->min_DCT_h_scaled_size;
1198*4882a593Smuzhiyun+  dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
1199*4882a593Smuzhiyun+  dstinfo->min_DCT_v_scaled_size = itemp;
1200*4882a593Smuzhiyun+#endif
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun   /* Transpose sampling factors */
1203*4882a593Smuzhiyun   for (ci = 0; ci < dstinfo->num_components; ci++) {
1204*4882a593Smuzhiyun@@ -674,47 +1171,162 @@ transpose_critical_parameters (j_compres
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun-/* Trim off any partial iMCUs on the indicated destination edge */
1209*4882a593Smuzhiyun+/* Adjust Exif image parameters.
1210*4882a593Smuzhiyun+ *
1211*4882a593Smuzhiyun+ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1212*4882a593Smuzhiyun+ */
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 70
1215*4882a593Smuzhiyun LOCAL(void)
1216*4882a593Smuzhiyun-trim_right_edge (j_compress_ptr dstinfo)
1217*4882a593Smuzhiyun+adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
1218*4882a593Smuzhiyun+			JDIMENSION new_width, JDIMENSION new_height)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun-  int ci, max_h_samp_factor;
1221*4882a593Smuzhiyun-  JDIMENSION MCU_cols;
1222*4882a593Smuzhiyun+  boolean is_motorola; /* Flag for byte order */
1223*4882a593Smuzhiyun+  unsigned int number_of_tags, tagnum;
1224*4882a593Smuzhiyun+  unsigned int firstoffset, offset;
1225*4882a593Smuzhiyun+  JDIMENSION new_value;
1226*4882a593Smuzhiyun+
1227*4882a593Smuzhiyun+  if (length < 12) return; /* Length of an IFD entry */
1228*4882a593Smuzhiyun+
1229*4882a593Smuzhiyun+  /* Discover byte order */
1230*4882a593Smuzhiyun+  if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
1231*4882a593Smuzhiyun+    is_motorola = FALSE;
1232*4882a593Smuzhiyun+  else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
1233*4882a593Smuzhiyun+    is_motorola = TRUE;
1234*4882a593Smuzhiyun+  else
1235*4882a593Smuzhiyun+    return;
1236*4882a593Smuzhiyun+
1237*4882a593Smuzhiyun+  /* Check Tag Mark */
1238*4882a593Smuzhiyun+  if (is_motorola) {
1239*4882a593Smuzhiyun+    if (GETJOCTET(data[2]) != 0) return;
1240*4882a593Smuzhiyun+    if (GETJOCTET(data[3]) != 0x2A) return;
1241*4882a593Smuzhiyun+  } else {
1242*4882a593Smuzhiyun+    if (GETJOCTET(data[3]) != 0) return;
1243*4882a593Smuzhiyun+    if (GETJOCTET(data[2]) != 0x2A) return;
1244*4882a593Smuzhiyun+  }
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun-  /* We have to compute max_h_samp_factor ourselves,
1247*4882a593Smuzhiyun-   * because it hasn't been set yet in the destination
1248*4882a593Smuzhiyun-   * (and we don't want to use the source's value).
1249*4882a593Smuzhiyun-   */
1250*4882a593Smuzhiyun-  max_h_samp_factor = 1;
1251*4882a593Smuzhiyun-  for (ci = 0; ci < dstinfo->num_components; ci++) {
1252*4882a593Smuzhiyun-    int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor;
1253*4882a593Smuzhiyun-    max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor);
1254*4882a593Smuzhiyun+  /* Get first IFD offset (offset to IFD0) */
1255*4882a593Smuzhiyun+  if (is_motorola) {
1256*4882a593Smuzhiyun+    if (GETJOCTET(data[4]) != 0) return;
1257*4882a593Smuzhiyun+    if (GETJOCTET(data[5]) != 0) return;
1258*4882a593Smuzhiyun+    firstoffset = GETJOCTET(data[6]);
1259*4882a593Smuzhiyun+    firstoffset <<= 8;
1260*4882a593Smuzhiyun+    firstoffset += GETJOCTET(data[7]);
1261*4882a593Smuzhiyun+  } else {
1262*4882a593Smuzhiyun+    if (GETJOCTET(data[7]) != 0) return;
1263*4882a593Smuzhiyun+    if (GETJOCTET(data[6]) != 0) return;
1264*4882a593Smuzhiyun+    firstoffset = GETJOCTET(data[5]);
1265*4882a593Smuzhiyun+    firstoffset <<= 8;
1266*4882a593Smuzhiyun+    firstoffset += GETJOCTET(data[4]);
1267*4882a593Smuzhiyun   }
1268*4882a593Smuzhiyun-  MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE);
1269*4882a593Smuzhiyun-  if (MCU_cols > 0)		/* can't trim to 0 pixels */
1270*4882a593Smuzhiyun-    dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE);
1271*4882a593Smuzhiyun-}
1272*4882a593Smuzhiyun+  if (firstoffset > length - 2) return; /* check end of data segment */
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun-LOCAL(void)
1275*4882a593Smuzhiyun-trim_bottom_edge (j_compress_ptr dstinfo)
1276*4882a593Smuzhiyun-{
1277*4882a593Smuzhiyun-  int ci, max_v_samp_factor;
1278*4882a593Smuzhiyun-  JDIMENSION MCU_rows;
1279*4882a593Smuzhiyun+  /* Get the number of directory entries contained in this IFD */
1280*4882a593Smuzhiyun+  if (is_motorola) {
1281*4882a593Smuzhiyun+    number_of_tags = GETJOCTET(data[firstoffset]);
1282*4882a593Smuzhiyun+    number_of_tags <<= 8;
1283*4882a593Smuzhiyun+    number_of_tags += GETJOCTET(data[firstoffset+1]);
1284*4882a593Smuzhiyun+  } else {
1285*4882a593Smuzhiyun+    number_of_tags = GETJOCTET(data[firstoffset+1]);
1286*4882a593Smuzhiyun+    number_of_tags <<= 8;
1287*4882a593Smuzhiyun+    number_of_tags += GETJOCTET(data[firstoffset]);
1288*4882a593Smuzhiyun+  }
1289*4882a593Smuzhiyun+  if (number_of_tags == 0) return;
1290*4882a593Smuzhiyun+  firstoffset += 2;
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun-  /* We have to compute max_v_samp_factor ourselves,
1293*4882a593Smuzhiyun-   * because it hasn't been set yet in the destination
1294*4882a593Smuzhiyun-   * (and we don't want to use the source's value).
1295*4882a593Smuzhiyun-   */
1296*4882a593Smuzhiyun-  max_v_samp_factor = 1;
1297*4882a593Smuzhiyun-  for (ci = 0; ci < dstinfo->num_components; ci++) {
1298*4882a593Smuzhiyun-    int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor;
1299*4882a593Smuzhiyun-    max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor);
1300*4882a593Smuzhiyun+  /* Search for ExifSubIFD offset Tag in IFD0 */
1301*4882a593Smuzhiyun+  for (;;) {
1302*4882a593Smuzhiyun+    if (firstoffset > length - 12) return; /* check end of data segment */
1303*4882a593Smuzhiyun+    /* Get Tag number */
1304*4882a593Smuzhiyun+    if (is_motorola) {
1305*4882a593Smuzhiyun+      tagnum = GETJOCTET(data[firstoffset]);
1306*4882a593Smuzhiyun+      tagnum <<= 8;
1307*4882a593Smuzhiyun+      tagnum += GETJOCTET(data[firstoffset+1]);
1308*4882a593Smuzhiyun+    } else {
1309*4882a593Smuzhiyun+      tagnum = GETJOCTET(data[firstoffset+1]);
1310*4882a593Smuzhiyun+      tagnum <<= 8;
1311*4882a593Smuzhiyun+      tagnum += GETJOCTET(data[firstoffset]);
1312*4882a593Smuzhiyun+    }
1313*4882a593Smuzhiyun+    if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1314*4882a593Smuzhiyun+    if (--number_of_tags == 0) return;
1315*4882a593Smuzhiyun+    firstoffset += 12;
1316*4882a593Smuzhiyun+  }
1317*4882a593Smuzhiyun+
1318*4882a593Smuzhiyun+  /* Get the ExifSubIFD offset */
1319*4882a593Smuzhiyun+  if (is_motorola) {
1320*4882a593Smuzhiyun+    if (GETJOCTET(data[firstoffset+8]) != 0) return;
1321*4882a593Smuzhiyun+    if (GETJOCTET(data[firstoffset+9]) != 0) return;
1322*4882a593Smuzhiyun+    offset = GETJOCTET(data[firstoffset+10]);
1323*4882a593Smuzhiyun+    offset <<= 8;
1324*4882a593Smuzhiyun+    offset += GETJOCTET(data[firstoffset+11]);
1325*4882a593Smuzhiyun+  } else {
1326*4882a593Smuzhiyun+    if (GETJOCTET(data[firstoffset+11]) != 0) return;
1327*4882a593Smuzhiyun+    if (GETJOCTET(data[firstoffset+10]) != 0) return;
1328*4882a593Smuzhiyun+    offset = GETJOCTET(data[firstoffset+9]);
1329*4882a593Smuzhiyun+    offset <<= 8;
1330*4882a593Smuzhiyun+    offset += GETJOCTET(data[firstoffset+8]);
1331*4882a593Smuzhiyun+  }
1332*4882a593Smuzhiyun+  if (offset > length - 2) return; /* check end of data segment */
1333*4882a593Smuzhiyun+
1334*4882a593Smuzhiyun+  /* Get the number of directory entries contained in this SubIFD */
1335*4882a593Smuzhiyun+  if (is_motorola) {
1336*4882a593Smuzhiyun+    number_of_tags = GETJOCTET(data[offset]);
1337*4882a593Smuzhiyun+    number_of_tags <<= 8;
1338*4882a593Smuzhiyun+    number_of_tags += GETJOCTET(data[offset+1]);
1339*4882a593Smuzhiyun+  } else {
1340*4882a593Smuzhiyun+    number_of_tags = GETJOCTET(data[offset+1]);
1341*4882a593Smuzhiyun+    number_of_tags <<= 8;
1342*4882a593Smuzhiyun+    number_of_tags += GETJOCTET(data[offset]);
1343*4882a593Smuzhiyun   }
1344*4882a593Smuzhiyun-  MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE);
1345*4882a593Smuzhiyun-  if (MCU_rows > 0)		/* can't trim to 0 pixels */
1346*4882a593Smuzhiyun-    dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE);
1347*4882a593Smuzhiyun+  if (number_of_tags < 2) return;
1348*4882a593Smuzhiyun+  offset += 2;
1349*4882a593Smuzhiyun+
1350*4882a593Smuzhiyun+  /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1351*4882a593Smuzhiyun+  do {
1352*4882a593Smuzhiyun+    if (offset > length - 12) return; /* check end of data segment */
1353*4882a593Smuzhiyun+    /* Get Tag number */
1354*4882a593Smuzhiyun+    if (is_motorola) {
1355*4882a593Smuzhiyun+      tagnum = GETJOCTET(data[offset]);
1356*4882a593Smuzhiyun+      tagnum <<= 8;
1357*4882a593Smuzhiyun+      tagnum += GETJOCTET(data[offset+1]);
1358*4882a593Smuzhiyun+    } else {
1359*4882a593Smuzhiyun+      tagnum = GETJOCTET(data[offset+1]);
1360*4882a593Smuzhiyun+      tagnum <<= 8;
1361*4882a593Smuzhiyun+      tagnum += GETJOCTET(data[offset]);
1362*4882a593Smuzhiyun+    }
1363*4882a593Smuzhiyun+    if (tagnum == 0xA002 || tagnum == 0xA003) {
1364*4882a593Smuzhiyun+      if (tagnum == 0xA002)
1365*4882a593Smuzhiyun+	new_value = new_width; /* ExifImageWidth Tag */
1366*4882a593Smuzhiyun+      else
1367*4882a593Smuzhiyun+	new_value = new_height; /* ExifImageHeight Tag */
1368*4882a593Smuzhiyun+      if (is_motorola) {
1369*4882a593Smuzhiyun+	data[offset+2] = 0; /* Format = unsigned long (4 octets) */
1370*4882a593Smuzhiyun+	data[offset+3] = 4;
1371*4882a593Smuzhiyun+	data[offset+4] = 0; /* Number Of Components = 1 */
1372*4882a593Smuzhiyun+	data[offset+5] = 0;
1373*4882a593Smuzhiyun+	data[offset+6] = 0;
1374*4882a593Smuzhiyun+	data[offset+7] = 1;
1375*4882a593Smuzhiyun+	data[offset+8] = 0;
1376*4882a593Smuzhiyun+	data[offset+9] = 0;
1377*4882a593Smuzhiyun+	data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
1378*4882a593Smuzhiyun+	data[offset+11] = (JOCTET)(new_value & 0xFF);
1379*4882a593Smuzhiyun+      } else {
1380*4882a593Smuzhiyun+	data[offset+2] = 4; /* Format = unsigned long (4 octets) */
1381*4882a593Smuzhiyun+	data[offset+3] = 0;
1382*4882a593Smuzhiyun+	data[offset+4] = 1; /* Number Of Components = 1 */
1383*4882a593Smuzhiyun+	data[offset+5] = 0;
1384*4882a593Smuzhiyun+	data[offset+6] = 0;
1385*4882a593Smuzhiyun+	data[offset+7] = 0;
1386*4882a593Smuzhiyun+	data[offset+8] = (JOCTET)(new_value & 0xFF);
1387*4882a593Smuzhiyun+	data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
1388*4882a593Smuzhiyun+	data[offset+10] = 0;
1389*4882a593Smuzhiyun+	data[offset+11] = 0;
1390*4882a593Smuzhiyun+      }
1391*4882a593Smuzhiyun+    }
1392*4882a593Smuzhiyun+    offset += 12;
1393*4882a593Smuzhiyun+  } while (--number_of_tags);
1394*4882a593Smuzhiyun }
1395*4882a593Smuzhiyun+#endif
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun
1398*4882a593Smuzhiyun /* Adjust output image parameters as needed.
1399*4882a593Smuzhiyun@@ -736,18 +1348,22 @@ jtransform_adjust_parameters (j_decompre
1400*4882a593Smuzhiyun {
1401*4882a593Smuzhiyun   /* If force-to-grayscale is requested, adjust destination parameters */
1402*4882a593Smuzhiyun   if (info->force_grayscale) {
1403*4882a593Smuzhiyun-    /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1404*4882a593Smuzhiyun-     * properly.  Among other things, the target h_samp_factor & v_samp_factor
1405*4882a593Smuzhiyun-     * will get set to 1, which typically won't match the source.
1406*4882a593Smuzhiyun-     * In fact we do this even if the source is already grayscale; that
1407*4882a593Smuzhiyun-     * provides an easy way of coercing a grayscale JPEG with funny sampling
1408*4882a593Smuzhiyun-     * factors to the customary 1,1.  (Some decoders fail on other factors.)
1409*4882a593Smuzhiyun+    /* First, ensure we have YCbCr or grayscale data, and that the source's
1410*4882a593Smuzhiyun+     * Y channel is full resolution.  (No reasonable person would make Y
1411*4882a593Smuzhiyun+     * be less than full resolution, so actually coping with that case
1412*4882a593Smuzhiyun+     * isn't worth extra code space.  But we check it to avoid crashing.)
1413*4882a593Smuzhiyun      */
1414*4882a593Smuzhiyun-    if ((dstinfo->jpeg_color_space == JCS_YCbCr &&
1415*4882a593Smuzhiyun-	 dstinfo->num_components == 3) ||
1416*4882a593Smuzhiyun-	(dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1417*4882a593Smuzhiyun-	 dstinfo->num_components == 1)) {
1418*4882a593Smuzhiyun-      /* We have to preserve the source's quantization table number. */
1419*4882a593Smuzhiyun+    if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
1420*4882a593Smuzhiyun+	  dstinfo->num_components == 3) ||
1421*4882a593Smuzhiyun+	 (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1422*4882a593Smuzhiyun+	  dstinfo->num_components == 1)) &&
1423*4882a593Smuzhiyun+	srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
1424*4882a593Smuzhiyun+	srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
1425*4882a593Smuzhiyun+      /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1426*4882a593Smuzhiyun+       * properly.  Among other things, it sets the target h_samp_factor &
1427*4882a593Smuzhiyun+       * v_samp_factor to 1, which typically won't match the source.
1428*4882a593Smuzhiyun+       * We have to preserve the source's quantization table number, however.
1429*4882a593Smuzhiyun+       */
1430*4882a593Smuzhiyun       int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
1431*4882a593Smuzhiyun       jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
1432*4882a593Smuzhiyun       dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
1433*4882a593Smuzhiyun@@ -755,50 +1371,66 @@ jtransform_adjust_parameters (j_decompre
1434*4882a593Smuzhiyun       /* Sorry, can't do it */
1435*4882a593Smuzhiyun       ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
1436*4882a593Smuzhiyun     }
1437*4882a593Smuzhiyun+  } else if (info->num_components == 1) {
1438*4882a593Smuzhiyun+    /* For a single-component source, we force the destination sampling factors
1439*4882a593Smuzhiyun+     * to 1x1, with or without force_grayscale.  This is useful because some
1440*4882a593Smuzhiyun+     * decoders choke on grayscale images with other sampling factors.
1441*4882a593Smuzhiyun+     */
1442*4882a593Smuzhiyun+    dstinfo->comp_info[0].h_samp_factor = 1;
1443*4882a593Smuzhiyun+    dstinfo->comp_info[0].v_samp_factor = 1;
1444*4882a593Smuzhiyun   }
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun-  /* Correct the destination's image dimensions etc if necessary */
1447*4882a593Smuzhiyun+  /* Correct the destination's image dimensions as necessary
1448*4882a593Smuzhiyun+   * for rotate/flip, resize, and crop operations.
1449*4882a593Smuzhiyun+   */
1450*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 70
1451*4882a593Smuzhiyun+  dstinfo->jpeg_width = info->output_width;
1452*4882a593Smuzhiyun+  dstinfo->jpeg_height = info->output_height;
1453*4882a593Smuzhiyun+#endif
1454*4882a593Smuzhiyun+
1455*4882a593Smuzhiyun+  /* Transpose destination image parameters */
1456*4882a593Smuzhiyun   switch (info->transform) {
1457*4882a593Smuzhiyun-  case JXFORM_NONE:
1458*4882a593Smuzhiyun-    /* Nothing to do */
1459*4882a593Smuzhiyun-    break;
1460*4882a593Smuzhiyun-  case JXFORM_FLIP_H:
1461*4882a593Smuzhiyun-    if (info->trim)
1462*4882a593Smuzhiyun-      trim_right_edge(dstinfo);
1463*4882a593Smuzhiyun-    break;
1464*4882a593Smuzhiyun-  case JXFORM_FLIP_V:
1465*4882a593Smuzhiyun-    if (info->trim)
1466*4882a593Smuzhiyun-      trim_bottom_edge(dstinfo);
1467*4882a593Smuzhiyun-    break;
1468*4882a593Smuzhiyun   case JXFORM_TRANSPOSE:
1469*4882a593Smuzhiyun-    transpose_critical_parameters(dstinfo);
1470*4882a593Smuzhiyun-    /* transpose does NOT have to trim anything */
1471*4882a593Smuzhiyun-    break;
1472*4882a593Smuzhiyun   case JXFORM_TRANSVERSE:
1473*4882a593Smuzhiyun-    transpose_critical_parameters(dstinfo);
1474*4882a593Smuzhiyun-    if (info->trim) {
1475*4882a593Smuzhiyun-      trim_right_edge(dstinfo);
1476*4882a593Smuzhiyun-      trim_bottom_edge(dstinfo);
1477*4882a593Smuzhiyun-    }
1478*4882a593Smuzhiyun-    break;
1479*4882a593Smuzhiyun   case JXFORM_ROT_90:
1480*4882a593Smuzhiyun-    transpose_critical_parameters(dstinfo);
1481*4882a593Smuzhiyun-    if (info->trim)
1482*4882a593Smuzhiyun-      trim_right_edge(dstinfo);
1483*4882a593Smuzhiyun-    break;
1484*4882a593Smuzhiyun-  case JXFORM_ROT_180:
1485*4882a593Smuzhiyun-    if (info->trim) {
1486*4882a593Smuzhiyun-      trim_right_edge(dstinfo);
1487*4882a593Smuzhiyun-      trim_bottom_edge(dstinfo);
1488*4882a593Smuzhiyun-    }
1489*4882a593Smuzhiyun-    break;
1490*4882a593Smuzhiyun   case JXFORM_ROT_270:
1491*4882a593Smuzhiyun+#if JPEG_LIB_VERSION < 70
1492*4882a593Smuzhiyun+    dstinfo->image_width = info->output_height;
1493*4882a593Smuzhiyun+    dstinfo->image_height = info->output_width;
1494*4882a593Smuzhiyun+#endif
1495*4882a593Smuzhiyun     transpose_critical_parameters(dstinfo);
1496*4882a593Smuzhiyun-    if (info->trim)
1497*4882a593Smuzhiyun-      trim_bottom_edge(dstinfo);
1498*4882a593Smuzhiyun+    break;
1499*4882a593Smuzhiyun+  default:
1500*4882a593Smuzhiyun+#if JPEG_LIB_VERSION < 70
1501*4882a593Smuzhiyun+    dstinfo->image_width = info->output_width;
1502*4882a593Smuzhiyun+    dstinfo->image_height = info->output_height;
1503*4882a593Smuzhiyun+#endif
1504*4882a593Smuzhiyun     break;
1505*4882a593Smuzhiyun   }
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun+  /* Adjust Exif properties */
1508*4882a593Smuzhiyun+  if (srcinfo->marker_list != NULL &&
1509*4882a593Smuzhiyun+      srcinfo->marker_list->marker == JPEG_APP0+1 &&
1510*4882a593Smuzhiyun+      srcinfo->marker_list->data_length >= 6 &&
1511*4882a593Smuzhiyun+      GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
1512*4882a593Smuzhiyun+      GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
1513*4882a593Smuzhiyun+      GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
1514*4882a593Smuzhiyun+      GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
1515*4882a593Smuzhiyun+      GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
1516*4882a593Smuzhiyun+      GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
1517*4882a593Smuzhiyun+    /* Suppress output of JFIF marker */
1518*4882a593Smuzhiyun+    dstinfo->write_JFIF_header = FALSE;
1519*4882a593Smuzhiyun+#if JPEG_LIB_VERSION >= 70
1520*4882a593Smuzhiyun+    /* Adjust Exif image parameters */
1521*4882a593Smuzhiyun+    if (dstinfo->jpeg_width != srcinfo->image_width ||
1522*4882a593Smuzhiyun+	dstinfo->jpeg_height != srcinfo->image_height)
1523*4882a593Smuzhiyun+      /* Align data segment to start of TIFF structure for parsing */
1524*4882a593Smuzhiyun+      adjust_exif_parameters(srcinfo->marker_list->data + 6,
1525*4882a593Smuzhiyun+	srcinfo->marker_list->data_length - 6,
1526*4882a593Smuzhiyun+	dstinfo->jpeg_width, dstinfo->jpeg_height);
1527*4882a593Smuzhiyun+#endif
1528*4882a593Smuzhiyun+  }
1529*4882a593Smuzhiyun+
1530*4882a593Smuzhiyun   /* Return the appropriate output data set */
1531*4882a593Smuzhiyun   if (info->workspace_coef_arrays != NULL)
1532*4882a593Smuzhiyun     return info->workspace_coef_arrays;
1533*4882a593Smuzhiyun@@ -816,40 +1448,110 @@ jtransform_adjust_parameters (j_decompre
1534*4882a593Smuzhiyun  */
1535*4882a593Smuzhiyun
1536*4882a593Smuzhiyun GLOBAL(void)
1537*4882a593Smuzhiyun-jtransform_execute_transformation (j_decompress_ptr srcinfo,
1538*4882a593Smuzhiyun-				   j_compress_ptr dstinfo,
1539*4882a593Smuzhiyun-				   jvirt_barray_ptr *src_coef_arrays,
1540*4882a593Smuzhiyun-				   jpeg_transform_info *info)
1541*4882a593Smuzhiyun+jtransform_execute_transform (j_decompress_ptr srcinfo,
1542*4882a593Smuzhiyun+			      j_compress_ptr dstinfo,
1543*4882a593Smuzhiyun+			      jvirt_barray_ptr *src_coef_arrays,
1544*4882a593Smuzhiyun+			      jpeg_transform_info *info)
1545*4882a593Smuzhiyun {
1546*4882a593Smuzhiyun   jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
1547*4882a593Smuzhiyun
1548*4882a593Smuzhiyun+  /* Note: conditions tested here should match those in switch statement
1549*4882a593Smuzhiyun+   * in jtransform_request_workspace()
1550*4882a593Smuzhiyun+   */
1551*4882a593Smuzhiyun   switch (info->transform) {
1552*4882a593Smuzhiyun   case JXFORM_NONE:
1553*4882a593Smuzhiyun+    if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1554*4882a593Smuzhiyun+      do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1555*4882a593Smuzhiyun+	      src_coef_arrays, dst_coef_arrays);
1556*4882a593Smuzhiyun     break;
1557*4882a593Smuzhiyun   case JXFORM_FLIP_H:
1558*4882a593Smuzhiyun-    do_flip_h(srcinfo, dstinfo, src_coef_arrays);
1559*4882a593Smuzhiyun+    if (info->y_crop_offset != 0 || info->slow_hflip)
1560*4882a593Smuzhiyun+      do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1561*4882a593Smuzhiyun+		src_coef_arrays, dst_coef_arrays);
1562*4882a593Smuzhiyun+    else
1563*4882a593Smuzhiyun+      do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
1564*4882a593Smuzhiyun+			src_coef_arrays);
1565*4882a593Smuzhiyun     break;
1566*4882a593Smuzhiyun   case JXFORM_FLIP_V:
1567*4882a593Smuzhiyun-    do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1568*4882a593Smuzhiyun+    do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1569*4882a593Smuzhiyun+	      src_coef_arrays, dst_coef_arrays);
1570*4882a593Smuzhiyun     break;
1571*4882a593Smuzhiyun   case JXFORM_TRANSPOSE:
1572*4882a593Smuzhiyun-    do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1573*4882a593Smuzhiyun+    do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1574*4882a593Smuzhiyun+		 src_coef_arrays, dst_coef_arrays);
1575*4882a593Smuzhiyun     break;
1576*4882a593Smuzhiyun   case JXFORM_TRANSVERSE:
1577*4882a593Smuzhiyun-    do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1578*4882a593Smuzhiyun+    do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1579*4882a593Smuzhiyun+		  src_coef_arrays, dst_coef_arrays);
1580*4882a593Smuzhiyun     break;
1581*4882a593Smuzhiyun   case JXFORM_ROT_90:
1582*4882a593Smuzhiyun-    do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1583*4882a593Smuzhiyun+    do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1584*4882a593Smuzhiyun+	      src_coef_arrays, dst_coef_arrays);
1585*4882a593Smuzhiyun     break;
1586*4882a593Smuzhiyun   case JXFORM_ROT_180:
1587*4882a593Smuzhiyun-    do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1588*4882a593Smuzhiyun+    do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1589*4882a593Smuzhiyun+	       src_coef_arrays, dst_coef_arrays);
1590*4882a593Smuzhiyun     break;
1591*4882a593Smuzhiyun   case JXFORM_ROT_270:
1592*4882a593Smuzhiyun-    do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1593*4882a593Smuzhiyun+    do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1594*4882a593Smuzhiyun+	       src_coef_arrays, dst_coef_arrays);
1595*4882a593Smuzhiyun     break;
1596*4882a593Smuzhiyun   }
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun+/* jtransform_perfect_transform
1600*4882a593Smuzhiyun+ *
1601*4882a593Smuzhiyun+ * Determine whether lossless transformation is perfectly
1602*4882a593Smuzhiyun+ * possible for a specified image and transformation.
1603*4882a593Smuzhiyun+ *
1604*4882a593Smuzhiyun+ * Inputs:
1605*4882a593Smuzhiyun+ *   image_width, image_height: source image dimensions.
1606*4882a593Smuzhiyun+ *   MCU_width, MCU_height: pixel dimensions of MCU.
1607*4882a593Smuzhiyun+ *   transform: transformation identifier.
1608*4882a593Smuzhiyun+ * Parameter sources from initialized jpeg_struct
1609*4882a593Smuzhiyun+ * (after reading source header):
1610*4882a593Smuzhiyun+ *   image_width = cinfo.image_width
1611*4882a593Smuzhiyun+ *   image_height = cinfo.image_height
1612*4882a593Smuzhiyun+ *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
1613*4882a593Smuzhiyun+ *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
1614*4882a593Smuzhiyun+ * Result:
1615*4882a593Smuzhiyun+ *   TRUE = perfect transformation possible
1616*4882a593Smuzhiyun+ *   FALSE = perfect transformation not possible
1617*4882a593Smuzhiyun+ *           (may use custom action then)
1618*4882a593Smuzhiyun+ */
1619*4882a593Smuzhiyun+
1620*4882a593Smuzhiyun+GLOBAL(boolean)
1621*4882a593Smuzhiyun+jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
1622*4882a593Smuzhiyun+			     int MCU_width, int MCU_height,
1623*4882a593Smuzhiyun+			     JXFORM_CODE transform)
1624*4882a593Smuzhiyun+{
1625*4882a593Smuzhiyun+  boolean result = TRUE; /* initialize TRUE */
1626*4882a593Smuzhiyun+
1627*4882a593Smuzhiyun+  switch (transform) {
1628*4882a593Smuzhiyun+  case JXFORM_FLIP_H:
1629*4882a593Smuzhiyun+  case JXFORM_ROT_270:
1630*4882a593Smuzhiyun+    if (image_width % (JDIMENSION) MCU_width)
1631*4882a593Smuzhiyun+      result = FALSE;
1632*4882a593Smuzhiyun+    break;
1633*4882a593Smuzhiyun+  case JXFORM_FLIP_V:
1634*4882a593Smuzhiyun+  case JXFORM_ROT_90:
1635*4882a593Smuzhiyun+    if (image_height % (JDIMENSION) MCU_height)
1636*4882a593Smuzhiyun+      result = FALSE;
1637*4882a593Smuzhiyun+    break;
1638*4882a593Smuzhiyun+  case JXFORM_TRANSVERSE:
1639*4882a593Smuzhiyun+  case JXFORM_ROT_180:
1640*4882a593Smuzhiyun+    if (image_width % (JDIMENSION) MCU_width)
1641*4882a593Smuzhiyun+      result = FALSE;
1642*4882a593Smuzhiyun+    if (image_height % (JDIMENSION) MCU_height)
1643*4882a593Smuzhiyun+      result = FALSE;
1644*4882a593Smuzhiyun+    break;
1645*4882a593Smuzhiyun+  default:
1646*4882a593Smuzhiyun+    break;
1647*4882a593Smuzhiyun+  }
1648*4882a593Smuzhiyun+
1649*4882a593Smuzhiyun+  return result;
1650*4882a593Smuzhiyun+}
1651*4882a593Smuzhiyun+
1652*4882a593Smuzhiyun #endif /* TRANSFORMS_SUPPORTED */
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun
1655*4882a593SmuzhiyunIndex: fbida-2.10/jpeg/62/transupp.h
1656*4882a593Smuzhiyun===================================================================
1657*4882a593Smuzhiyun--- fbida-2.10.orig/jpeg/62/transupp.h
1658*4882a593Smuzhiyun+++ fbida-2.10/jpeg/62/transupp.h
1659*4882a593Smuzhiyun@@ -1,7 +1,7 @@
1660*4882a593Smuzhiyun /*
1661*4882a593Smuzhiyun  * transupp.h
1662*4882a593Smuzhiyun  *
1663*4882a593Smuzhiyun- * Copyright (C) 1997, Thomas G. Lane.
1664*4882a593Smuzhiyun+ * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
1665*4882a593Smuzhiyun  * This file is part of the Independent JPEG Group's software.
1666*4882a593Smuzhiyun  * For conditions of distribution and use, see the accompanying README file.
1667*4882a593Smuzhiyun  *
1668*4882a593Smuzhiyun@@ -22,32 +22,6 @@
1669*4882a593Smuzhiyun #define TRANSFORMS_SUPPORTED 1		/* 0 disables transform code */
1670*4882a593Smuzhiyun #endif
1671*4882a593Smuzhiyun
1672*4882a593Smuzhiyun-/* Short forms of external names for systems with brain-damaged linkers. */
1673*4882a593Smuzhiyun-
1674*4882a593Smuzhiyun-#ifdef NEED_SHORT_EXTERNAL_NAMES
1675*4882a593Smuzhiyun-#define jtransform_request_workspace		jTrRequest
1676*4882a593Smuzhiyun-#define jtransform_adjust_parameters		jTrAdjust
1677*4882a593Smuzhiyun-#define jtransform_execute_transformation	jTrExec
1678*4882a593Smuzhiyun-#define jcopy_markers_setup			jCMrkSetup
1679*4882a593Smuzhiyun-#define jcopy_markers_execute			jCMrkExec
1680*4882a593Smuzhiyun-#endif /* NEED_SHORT_EXTERNAL_NAMES */
1681*4882a593Smuzhiyun-
1682*4882a593Smuzhiyun-
1683*4882a593Smuzhiyun-/*
1684*4882a593Smuzhiyun- * Codes for supported types of image transformations.
1685*4882a593Smuzhiyun- */
1686*4882a593Smuzhiyun-
1687*4882a593Smuzhiyun-typedef enum {
1688*4882a593Smuzhiyun-	JXFORM_NONE,		/* no transformation */
1689*4882a593Smuzhiyun-	JXFORM_FLIP_H,		/* horizontal flip */
1690*4882a593Smuzhiyun-	JXFORM_FLIP_V,		/* vertical flip */
1691*4882a593Smuzhiyun-	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
1692*4882a593Smuzhiyun-	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
1693*4882a593Smuzhiyun-	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
1694*4882a593Smuzhiyun-	JXFORM_ROT_180,		/* 180-degree rotation */
1695*4882a593Smuzhiyun-	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
1696*4882a593Smuzhiyun-} JXFORM_CODE;
1697*4882a593Smuzhiyun-
1698*4882a593Smuzhiyun /*
1699*4882a593Smuzhiyun  * Although rotating and flipping data expressed as DCT coefficients is not
1700*4882a593Smuzhiyun  * hard, there is an asymmetry in the JPEG format specification for images
1701*4882a593Smuzhiyun@@ -75,6 +49,25 @@ typedef enum {
1702*4882a593Smuzhiyun  * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
1703*4882a593Smuzhiyun  * followed by -rot 180 -trim trims both edges.)
1704*4882a593Smuzhiyun  *
1705*4882a593Smuzhiyun+ * We also offer a lossless-crop option, which discards data outside a given
1706*4882a593Smuzhiyun+ * image region but losslessly preserves what is inside.  Like the rotate and
1707*4882a593Smuzhiyun+ * flip transforms, lossless crop is restricted by the JPEG format: the upper
1708*4882a593Smuzhiyun+ * left corner of the selected region must fall on an iMCU boundary.  If this
1709*4882a593Smuzhiyun+ * does not hold for the given crop parameters, we silently move the upper left
1710*4882a593Smuzhiyun+ * corner up and/or left to make it so, simultaneously increasing the region
1711*4882a593Smuzhiyun+ * dimensions to keep the lower right crop corner unchanged.  (Thus, the
1712*4882a593Smuzhiyun+ * output image covers at least the requested region, but may cover more.)
1713*4882a593Smuzhiyun+ * The adjustment of the region dimensions may be optionally disabled.
1714*4882a593Smuzhiyun+ *
1715*4882a593Smuzhiyun+ * We also provide a lossless-resize option, which is kind of a lossless-crop
1716*4882a593Smuzhiyun+ * operation in the DCT coefficient block domain - it discards higher-order
1717*4882a593Smuzhiyun+ * coefficients and losslessly preserves lower-order coefficients of a
1718*4882a593Smuzhiyun+ * sub-block.
1719*4882a593Smuzhiyun+ *
1720*4882a593Smuzhiyun+ * Rotate/flip transform, resize, and crop can be requested together in a
1721*4882a593Smuzhiyun+ * single invocation.  The crop is applied last --- that is, the crop region
1722*4882a593Smuzhiyun+ * is specified in terms of the destination image after transform/resize.
1723*4882a593Smuzhiyun+ *
1724*4882a593Smuzhiyun  * We also offer a "force to grayscale" option, which simply discards the
1725*4882a593Smuzhiyun  * chrominance channels of a YCbCr image.  This is lossless in the sense that
1726*4882a593Smuzhiyun  * the luminance channel is preserved exactly.  It's not the same kind of
1727*4882a593Smuzhiyun@@ -83,22 +76,100 @@ typedef enum {
1728*4882a593Smuzhiyun  * be aware of the option to know how many components to work on.
1729*4882a593Smuzhiyun  */
1730*4882a593Smuzhiyun
1731*4882a593Smuzhiyun+
1732*4882a593Smuzhiyun+/* Short forms of external names for systems with brain-damaged linkers. */
1733*4882a593Smuzhiyun+
1734*4882a593Smuzhiyun+#ifdef NEED_SHORT_EXTERNAL_NAMES
1735*4882a593Smuzhiyun+#define jtransform_parse_crop_spec	jTrParCrop
1736*4882a593Smuzhiyun+#define jtransform_request_workspace	jTrRequest
1737*4882a593Smuzhiyun+#define jtransform_adjust_parameters	jTrAdjust
1738*4882a593Smuzhiyun+#define jtransform_execute_transform	jTrExec
1739*4882a593Smuzhiyun+#define jtransform_perfect_transform	jTrPerfect
1740*4882a593Smuzhiyun+#define jcopy_markers_setup		jCMrkSetup
1741*4882a593Smuzhiyun+#define jcopy_markers_execute		jCMrkExec
1742*4882a593Smuzhiyun+#endif /* NEED_SHORT_EXTERNAL_NAMES */
1743*4882a593Smuzhiyun+
1744*4882a593Smuzhiyun+
1745*4882a593Smuzhiyun+/*
1746*4882a593Smuzhiyun+ * Codes for supported types of image transformations.
1747*4882a593Smuzhiyun+ */
1748*4882a593Smuzhiyun+
1749*4882a593Smuzhiyun+typedef enum {
1750*4882a593Smuzhiyun+	JXFORM_NONE,		/* no transformation */
1751*4882a593Smuzhiyun+	JXFORM_FLIP_H,		/* horizontal flip */
1752*4882a593Smuzhiyun+	JXFORM_FLIP_V,		/* vertical flip */
1753*4882a593Smuzhiyun+	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
1754*4882a593Smuzhiyun+	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
1755*4882a593Smuzhiyun+	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
1756*4882a593Smuzhiyun+	JXFORM_ROT_180,		/* 180-degree rotation */
1757*4882a593Smuzhiyun+	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
1758*4882a593Smuzhiyun+} JXFORM_CODE;
1759*4882a593Smuzhiyun+
1760*4882a593Smuzhiyun+/*
1761*4882a593Smuzhiyun+ * Codes for crop parameters, which can individually be unspecified,
1762*4882a593Smuzhiyun+ * positive or negative for xoffset or yoffset,
1763*4882a593Smuzhiyun+ * positive or forced for width or height.
1764*4882a593Smuzhiyun+ */
1765*4882a593Smuzhiyun+
1766*4882a593Smuzhiyun+typedef enum {
1767*4882a593Smuzhiyun+        JCROP_UNSET,
1768*4882a593Smuzhiyun+        JCROP_POS,
1769*4882a593Smuzhiyun+        JCROP_NEG,
1770*4882a593Smuzhiyun+        JCROP_FORCE
1771*4882a593Smuzhiyun+} JCROP_CODE;
1772*4882a593Smuzhiyun+
1773*4882a593Smuzhiyun+/*
1774*4882a593Smuzhiyun+ * Transform parameters struct.
1775*4882a593Smuzhiyun+ * NB: application must not change any elements of this struct after
1776*4882a593Smuzhiyun+ * calling jtransform_request_workspace.
1777*4882a593Smuzhiyun+ */
1778*4882a593Smuzhiyun+
1779*4882a593Smuzhiyun typedef struct {
1780*4882a593Smuzhiyun   /* Options: set by caller */
1781*4882a593Smuzhiyun   JXFORM_CODE transform;	/* image transform operator */
1782*4882a593Smuzhiyun+  boolean perfect;		/* if TRUE, fail if partial MCUs are requested */
1783*4882a593Smuzhiyun   boolean trim;			/* if TRUE, trim partial MCUs as needed */
1784*4882a593Smuzhiyun   boolean force_grayscale;	/* if TRUE, convert color image to grayscale */
1785*4882a593Smuzhiyun+  boolean crop;			/* if TRUE, crop source image */
1786*4882a593Smuzhiyun+  boolean slow_hflip;  /* For best performance, the JXFORM_FLIP_H transform
1787*4882a593Smuzhiyun+                          normally modifies the source coefficients in place.
1788*4882a593Smuzhiyun+                          Setting this to TRUE will instead use a slower,
1789*4882a593Smuzhiyun+                          double-buffered algorithm, which leaves the source
1790*4882a593Smuzhiyun+                          coefficients in tact (necessary if other transformed
1791*4882a593Smuzhiyun+                          images must be generated from the same set of
1792*4882a593Smuzhiyun+                          coefficients. */
1793*4882a593Smuzhiyun+
1794*4882a593Smuzhiyun+  /* Crop parameters: application need not set these unless crop is TRUE.
1795*4882a593Smuzhiyun+   * These can be filled in by jtransform_parse_crop_spec().
1796*4882a593Smuzhiyun+   */
1797*4882a593Smuzhiyun+  JDIMENSION crop_width;	/* Width of selected region */
1798*4882a593Smuzhiyun+  JCROP_CODE crop_width_set;	/* (forced disables adjustment) */
1799*4882a593Smuzhiyun+  JDIMENSION crop_height;	/* Height of selected region */
1800*4882a593Smuzhiyun+  JCROP_CODE crop_height_set;	/* (forced disables adjustment) */
1801*4882a593Smuzhiyun+  JDIMENSION crop_xoffset;	/* X offset of selected region */
1802*4882a593Smuzhiyun+  JCROP_CODE crop_xoffset_set;	/* (negative measures from right edge) */
1803*4882a593Smuzhiyun+  JDIMENSION crop_yoffset;	/* Y offset of selected region */
1804*4882a593Smuzhiyun+  JCROP_CODE crop_yoffset_set;	/* (negative measures from bottom edge) */
1805*4882a593Smuzhiyun
1806*4882a593Smuzhiyun   /* Internal workspace: caller should not touch these */
1807*4882a593Smuzhiyun   int num_components;		/* # of components in workspace */
1808*4882a593Smuzhiyun   jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */
1809*4882a593Smuzhiyun+  JDIMENSION output_width;	/* cropped destination dimensions */
1810*4882a593Smuzhiyun+  JDIMENSION output_height;
1811*4882a593Smuzhiyun+  JDIMENSION x_crop_offset;	/* destination crop offsets measured in iMCUs */
1812*4882a593Smuzhiyun+  JDIMENSION y_crop_offset;
1813*4882a593Smuzhiyun+  int iMCU_sample_width;	/* destination iMCU size */
1814*4882a593Smuzhiyun+  int iMCU_sample_height;
1815*4882a593Smuzhiyun } jpeg_transform_info;
1816*4882a593Smuzhiyun
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun #if TRANSFORMS_SUPPORTED
1819*4882a593Smuzhiyun
1820*4882a593Smuzhiyun+/* Parse a crop specification (written in X11 geometry style) */
1821*4882a593Smuzhiyun+EXTERN(boolean) jtransform_parse_crop_spec
1822*4882a593Smuzhiyun+	JPP((jpeg_transform_info *info, const char *spec));
1823*4882a593Smuzhiyun /* Request any required workspace */
1824*4882a593Smuzhiyun-EXTERN(void) jtransform_request_workspace
1825*4882a593Smuzhiyun+EXTERN(boolean) jtransform_request_workspace
1826*4882a593Smuzhiyun 	JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));
1827*4882a593Smuzhiyun /* Adjust output image parameters */
1828*4882a593Smuzhiyun EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters
1829*4882a593Smuzhiyun@@ -106,10 +177,24 @@ EXTERN(jvirt_barray_ptr *) jtransform_ad
1830*4882a593Smuzhiyun 	     jvirt_barray_ptr *src_coef_arrays,
1831*4882a593Smuzhiyun 	     jpeg_transform_info *info));
1832*4882a593Smuzhiyun /* Execute the actual transformation, if any */
1833*4882a593Smuzhiyun-EXTERN(void) jtransform_execute_transformation
1834*4882a593Smuzhiyun+EXTERN(void) jtransform_execute_transform
1835*4882a593Smuzhiyun 	JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1836*4882a593Smuzhiyun 	     jvirt_barray_ptr *src_coef_arrays,
1837*4882a593Smuzhiyun 	     jpeg_transform_info *info));
1838*4882a593Smuzhiyun+/* Determine whether lossless transformation is perfectly
1839*4882a593Smuzhiyun+ * possible for a specified image and transformation.
1840*4882a593Smuzhiyun+ */
1841*4882a593Smuzhiyun+EXTERN(boolean) jtransform_perfect_transform
1842*4882a593Smuzhiyun+	JPP((JDIMENSION image_width, JDIMENSION image_height,
1843*4882a593Smuzhiyun+	     int MCU_width, int MCU_height,
1844*4882a593Smuzhiyun+	     JXFORM_CODE transform));
1845*4882a593Smuzhiyun+
1846*4882a593Smuzhiyun+/* jtransform_execute_transform used to be called
1847*4882a593Smuzhiyun+ * jtransform_execute_transformation, but some compilers complain about
1848*4882a593Smuzhiyun+ * routine names that long.  This macro is here to avoid breaking any
1849*4882a593Smuzhiyun+ * old source code that uses the original name...
1850*4882a593Smuzhiyun+ */
1851*4882a593Smuzhiyun+#define jtransform_execute_transformation	jtransform_execute_transform
1852*4882a593Smuzhiyun
1853*4882a593Smuzhiyun #endif /* TRANSFORMS_SUPPORTED */
1854*4882a593Smuzhiyun
1855