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