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