1 diff -urN fbida-2.07.orig/jpeg/transupp.c fbida-2.07/jpeg/transupp.c
2 --- fbida-2.07.orig/jpeg/transupp.c 2010-03-02 09:22:37.000000000 +0100
3 +++ fbida-2.07/jpeg/transupp.c 2010-03-02 09:24:09.000000000 +0100
8 - * Copyright (C) 1997, Thomas G. Lane.
9 + * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
10 * This file is part of the Independent JPEG Group's software.
11 * For conditions of distribution and use, see the accompanying README file.
16 #include "transupp.h" /* My own external interface */
17 +#include <ctype.h> /* to declare isdigit() */
20 #if TRANSFORMS_SUPPORTED
22 * Lossless image transformation routines. These routines work on DCT
23 * coefficient arrays and thus do not require any lossy decompression
24 * or recompression of the image.
25 - * Thanks to Guido Vollbeding for the initial design and code of this feature.
26 + * Thanks to Guido Vollbeding for the initial design and code of this feature,
27 + * and to Ben Jackson for introducing the cropping feature.
29 * Horizontal flipping is done in-place, using a single top-to-bottom
30 * pass through the virtual source array. It will thus be much the
32 * arrays for most of the transforms. That could result in much thrashing
33 * if the image is larger than main memory.
35 + * If cropping or trimming is involved, the destination arrays may be smaller
36 + * than the source arrays. Note it is not possible to do horizontal flip
37 + * in-place when a nonzero Y crop offset is specified, since we'd have to move
38 + * data from one block row to another but the virtual array manager doesn't
39 + * guarantee we can touch more than one row at a time. So in that case,
40 + * we have to use a separate destination array.
42 * Some notes about the operating environment of the individual transform
44 * 1. Both the source and destination virtual arrays are allocated from the
46 * and we may as well take that as the effective iMCU size.
47 * 4. When "trim" is in effect, the destination's dimensions will be the
48 * trimmed values but the source's will be untrimmed.
49 - * 5. All the routines assume that the source and destination buffers are
50 + * 5. When "crop" is in effect, the destination's dimensions will be the
51 + * cropped values but the source's will be uncropped. Each transform
52 + * routine is responsible for picking up source data starting at the
53 + * correct X and Y offset for the crop region. (The X and Y offsets
54 + * passed to the transform routines are measured in iMCU blocks of the
56 + * 6. All the routines assume that the source and destination buffers are
57 * padded out to a full iMCU boundary. This is true, although for the
58 * source buffer it is an undocumented property of jdcoefct.c.
59 - * Notes 2,3,4 boil down to this: generally we should use the destination's
60 - * dimensions and ignore the source's.
65 -do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
66 - jvirt_barray_ptr *src_coef_arrays)
67 -/* Horizontal flip; done in-place, so no separate dest array is required */
68 +do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
69 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
70 + jvirt_barray_ptr *src_coef_arrays,
71 + jvirt_barray_ptr *dst_coef_arrays)
72 +/* Crop. This is only used when no rotate/flip is requested with the crop. */
74 + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
76 + JBLOCKARRAY src_buffer, dst_buffer;
77 + jpeg_component_info *compptr;
79 + /* We simply have to copy the right amount of data (the destination's
80 + * image size) starting at the given X and Y offsets in the source.
82 + for (ci = 0; ci < dstinfo->num_components; ci++) {
83 + compptr = dstinfo->comp_info + ci;
84 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
85 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
86 + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
87 + dst_blk_y += compptr->v_samp_factor) {
88 + dst_buffer = (*srcinfo->mem->access_virt_barray)
89 + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
90 + (JDIMENSION) compptr->v_samp_factor, TRUE);
91 + src_buffer = (*srcinfo->mem->access_virt_barray)
92 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
93 + dst_blk_y + y_crop_blocks,
94 + (JDIMENSION) compptr->v_samp_factor, FALSE);
95 + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
96 + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
97 + dst_buffer[offset_y],
98 + compptr->width_in_blocks);
106 +do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
107 + JDIMENSION x_crop_offset,
108 + jvirt_barray_ptr *src_coef_arrays)
109 +/* Horizontal flip; done in-place, so no separate dest array is required.
110 + * NB: this only works when y_crop_offset is zero.
113 - JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
114 + JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
119 * mirroring by changing the signs of odd-numbered columns.
120 * Partial iMCUs at the right edge are left untouched.
122 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
123 + MCU_cols = srcinfo->output_width /
124 + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
126 for (ci = 0; ci < dstinfo->num_components; ci++) {
127 compptr = dstinfo->comp_info + ci;
128 comp_width = MCU_cols * compptr->h_samp_factor;
129 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
130 for (blk_y = 0; blk_y < compptr->height_in_blocks;
131 blk_y += compptr->v_samp_factor) {
132 buffer = (*srcinfo->mem->access_virt_barray)
133 ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
134 (JDIMENSION) compptr->v_samp_factor, TRUE);
135 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
136 + /* Do the mirroring */
137 for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
138 ptr1 = buffer[offset_y][blk_x];
139 ptr2 = buffer[offset_y][comp_width - blk_x - 1];
144 + if (x_crop_blocks > 0) {
145 + /* Now left-justify the portion of the data to be kept.
146 + * We can't use a single jcopy_block_row() call because that routine
147 + * depends on memcpy(), whose behavior is unspecified for overlapping
148 + * source and destination areas. Sigh.
150 + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
151 + jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
152 + buffer[offset_y] + blk_x,
163 +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
164 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
165 + jvirt_barray_ptr *src_coef_arrays,
166 + jvirt_barray_ptr *dst_coef_arrays)
167 +/* Horizontal flip in general cropping case */
169 + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
170 + JDIMENSION x_crop_blocks, y_crop_blocks;
171 + int ci, k, offset_y;
172 + JBLOCKARRAY src_buffer, dst_buffer;
173 + JBLOCKROW src_row_ptr, dst_row_ptr;
174 + JCOEFPTR src_ptr, dst_ptr;
175 + jpeg_component_info *compptr;
177 + /* Here we must output into a separate array because we can't touch
178 + * different rows of a single virtual array simultaneously. Otherwise,
179 + * this is essentially the same as the routine above.
181 + MCU_cols = srcinfo->output_width /
182 + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
184 + for (ci = 0; ci < dstinfo->num_components; ci++) {
185 + compptr = dstinfo->comp_info + ci;
186 + comp_width = MCU_cols * compptr->h_samp_factor;
187 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
188 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
189 + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
190 + dst_blk_y += compptr->v_samp_factor) {
191 + dst_buffer = (*srcinfo->mem->access_virt_barray)
192 + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
193 + (JDIMENSION) compptr->v_samp_factor, TRUE);
194 + src_buffer = (*srcinfo->mem->access_virt_barray)
195 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
196 + dst_blk_y + y_crop_blocks,
197 + (JDIMENSION) compptr->v_samp_factor, FALSE);
198 + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
199 + dst_row_ptr = dst_buffer[offset_y];
200 + src_row_ptr = src_buffer[offset_y];
201 + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
202 + if (x_crop_blocks + dst_blk_x < comp_width) {
203 + /* Do the mirrorable blocks */
204 + dst_ptr = dst_row_ptr[dst_blk_x];
205 + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
206 + /* this unrolled loop doesn't need to know which row it's on... */
207 + for (k = 0; k < DCTSIZE2; k += 2) {
208 + *dst_ptr++ = *src_ptr++; /* copy even column */
209 + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
212 + /* Copy last partial block(s) verbatim */
213 + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
214 + dst_row_ptr + dst_blk_x,
221 @@ -113,11 +244,13 @@
224 do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
225 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
226 jvirt_barray_ptr *src_coef_arrays,
227 jvirt_barray_ptr *dst_coef_arrays)
230 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
231 + JDIMENSION x_crop_blocks, y_crop_blocks;
232 int ci, i, j, offset_y;
233 JBLOCKARRAY src_buffer, dst_buffer;
234 JBLOCKROW src_row_ptr, dst_row_ptr;
235 @@ -131,33 +264,39 @@
236 * of odd-numbered rows.
237 * Partial iMCUs at the bottom edge are copied verbatim.
239 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
240 + MCU_rows = srcinfo->output_height /
241 + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
243 for (ci = 0; ci < dstinfo->num_components; ci++) {
244 compptr = dstinfo->comp_info + ci;
245 comp_height = MCU_rows * compptr->v_samp_factor;
246 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
247 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
248 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
249 dst_blk_y += compptr->v_samp_factor) {
250 dst_buffer = (*srcinfo->mem->access_virt_barray)
251 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
252 (JDIMENSION) compptr->v_samp_factor, TRUE);
253 - if (dst_blk_y < comp_height) {
254 + if (y_crop_blocks + dst_blk_y < comp_height) {
255 /* Row is within the mirrorable area. */
256 src_buffer = (*srcinfo->mem->access_virt_barray)
257 ((j_common_ptr) srcinfo, src_coef_arrays[ci],
258 - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
259 + comp_height - y_crop_blocks - dst_blk_y -
260 + (JDIMENSION) compptr->v_samp_factor,
261 (JDIMENSION) compptr->v_samp_factor, FALSE);
263 /* Bottom-edge blocks will be copied verbatim. */
264 src_buffer = (*srcinfo->mem->access_virt_barray)
265 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
266 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
267 + dst_blk_y + y_crop_blocks,
268 (JDIMENSION) compptr->v_samp_factor, FALSE);
270 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
271 - if (dst_blk_y < comp_height) {
272 + if (y_crop_blocks + dst_blk_y < comp_height) {
273 /* Row is within the mirrorable area. */
274 dst_row_ptr = dst_buffer[offset_y];
275 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
276 + src_row_ptr += x_crop_blocks;
277 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
279 dst_ptr = dst_row_ptr[dst_blk_x];
283 /* Just copy row verbatim. */
284 - jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
285 + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
286 + dst_buffer[offset_y],
287 compptr->width_in_blocks);
290 @@ -184,11 +324,12 @@
293 do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
294 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
295 jvirt_barray_ptr *src_coef_arrays,
296 jvirt_barray_ptr *dst_coef_arrays)
297 /* Transpose source into destination */
299 - JDIMENSION dst_blk_x, dst_blk_y;
300 + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
301 int ci, i, j, offset_x, offset_y;
302 JBLOCKARRAY src_buffer, dst_buffer;
303 JCOEFPTR src_ptr, dst_ptr;
306 for (ci = 0; ci < dstinfo->num_components; ci++) {
307 compptr = dstinfo->comp_info + ci;
308 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
309 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
310 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
311 dst_blk_y += compptr->v_samp_factor) {
312 dst_buffer = (*srcinfo->mem->access_virt_barray)
313 @@ -210,11 +353,12 @@
314 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
315 dst_blk_x += compptr->h_samp_factor) {
316 src_buffer = (*srcinfo->mem->access_virt_barray)
317 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
318 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
319 + dst_blk_x + x_crop_blocks,
320 (JDIMENSION) compptr->h_samp_factor, FALSE);
321 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
322 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
323 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
324 + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
325 for (i = 0; i < DCTSIZE; i++)
326 for (j = 0; j < DCTSIZE; j++)
327 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
331 do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
332 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
333 jvirt_barray_ptr *src_coef_arrays,
334 jvirt_barray_ptr *dst_coef_arrays)
335 /* 90 degree rotation is equivalent to
339 JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
340 + JDIMENSION x_crop_blocks, y_crop_blocks;
341 int ci, i, j, offset_x, offset_y;
342 JBLOCKARRAY src_buffer, dst_buffer;
343 JCOEFPTR src_ptr, dst_ptr;
344 @@ -246,11 +392,14 @@
345 * at the (output) right edge properly. They just get transposed and
348 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
349 + MCU_cols = srcinfo->output_height /
350 + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
352 for (ci = 0; ci < dstinfo->num_components; ci++) {
353 compptr = dstinfo->comp_info + ci;
354 comp_width = MCU_cols * compptr->h_samp_factor;
355 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
356 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
357 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
358 dst_blk_y += compptr->v_samp_factor) {
359 dst_buffer = (*srcinfo->mem->access_virt_barray)
360 @@ -259,15 +408,26 @@
361 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
362 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
363 dst_blk_x += compptr->h_samp_factor) {
364 - src_buffer = (*srcinfo->mem->access_virt_barray)
365 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
366 - (JDIMENSION) compptr->h_samp_factor, FALSE);
367 + if (x_crop_blocks + dst_blk_x < comp_width) {
368 + /* Block is within the mirrorable area. */
369 + src_buffer = (*srcinfo->mem->access_virt_barray)
370 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
371 + comp_width - x_crop_blocks - dst_blk_x -
372 + (JDIMENSION) compptr->h_samp_factor,
373 + (JDIMENSION) compptr->h_samp_factor, FALSE);
375 + /* Edge blocks are transposed but not mirrored. */
376 + src_buffer = (*srcinfo->mem->access_virt_barray)
377 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
378 + dst_blk_x + x_crop_blocks,
379 + (JDIMENSION) compptr->h_samp_factor, FALSE);
381 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
382 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
383 - if (dst_blk_x < comp_width) {
384 + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
385 + if (x_crop_blocks + dst_blk_x < comp_width) {
386 /* Block is within the mirrorable area. */
387 - dst_ptr = dst_buffer[offset_y]
388 - [comp_width - dst_blk_x - offset_x - 1];
389 + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
390 + [dst_blk_y + offset_y + y_crop_blocks];
391 for (i = 0; i < DCTSIZE; i++) {
392 for (j = 0; j < DCTSIZE; j++)
393 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
397 /* Edge blocks are transposed but not mirrored. */
398 - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
399 + src_ptr = src_buffer[offset_x]
400 + [dst_blk_y + offset_y + y_crop_blocks];
401 for (i = 0; i < DCTSIZE; i++)
402 for (j = 0; j < DCTSIZE; j++)
403 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
407 do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
408 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
409 jvirt_barray_ptr *src_coef_arrays,
410 jvirt_barray_ptr *dst_coef_arrays)
411 /* 270 degree rotation is equivalent to
415 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
416 + JDIMENSION x_crop_blocks, y_crop_blocks;
417 int ci, i, j, offset_x, offset_y;
418 JBLOCKARRAY src_buffer, dst_buffer;
419 JCOEFPTR src_ptr, dst_ptr;
420 @@ -310,11 +473,14 @@
421 * at the (output) bottom edge properly. They just get transposed and
424 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
425 + MCU_rows = srcinfo->output_width /
426 + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
428 for (ci = 0; ci < dstinfo->num_components; ci++) {
429 compptr = dstinfo->comp_info + ci;
430 comp_height = MCU_rows * compptr->v_samp_factor;
431 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
432 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
433 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
434 dst_blk_y += compptr->v_samp_factor) {
435 dst_buffer = (*srcinfo->mem->access_virt_barray)
436 @@ -324,14 +490,15 @@
437 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
438 dst_blk_x += compptr->h_samp_factor) {
439 src_buffer = (*srcinfo->mem->access_virt_barray)
440 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
441 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
442 + dst_blk_x + x_crop_blocks,
443 (JDIMENSION) compptr->h_samp_factor, FALSE);
444 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
445 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
446 - if (dst_blk_y < comp_height) {
447 + if (y_crop_blocks + dst_blk_y < comp_height) {
448 /* Block is within the mirrorable area. */
449 src_ptr = src_buffer[offset_x]
450 - [comp_height - dst_blk_y - offset_y - 1];
451 + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
452 for (i = 0; i < DCTSIZE; i++) {
453 for (j = 0; j < DCTSIZE; j++) {
454 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
458 /* Edge blocks are transposed but not mirrored. */
459 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
460 + src_ptr = src_buffer[offset_x]
461 + [dst_blk_y + offset_y + y_crop_blocks];
462 for (i = 0; i < DCTSIZE; i++)
463 for (j = 0; j < DCTSIZE; j++)
464 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
468 do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
469 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
470 jvirt_barray_ptr *src_coef_arrays,
471 jvirt_barray_ptr *dst_coef_arrays)
472 /* 180 degree rotation is equivalent to
473 @@ -365,89 +534,95 @@
476 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
477 + JDIMENSION x_crop_blocks, y_crop_blocks;
478 int ci, i, j, offset_y;
479 JBLOCKARRAY src_buffer, dst_buffer;
480 JBLOCKROW src_row_ptr, dst_row_ptr;
481 JCOEFPTR src_ptr, dst_ptr;
482 jpeg_component_info *compptr;
484 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
485 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
486 + MCU_cols = srcinfo->output_width /
487 + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
488 + MCU_rows = srcinfo->output_height /
489 + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
491 for (ci = 0; ci < dstinfo->num_components; ci++) {
492 compptr = dstinfo->comp_info + ci;
493 comp_width = MCU_cols * compptr->h_samp_factor;
494 comp_height = MCU_rows * compptr->v_samp_factor;
495 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
496 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
497 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
498 dst_blk_y += compptr->v_samp_factor) {
499 dst_buffer = (*srcinfo->mem->access_virt_barray)
500 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
501 (JDIMENSION) compptr->v_samp_factor, TRUE);
502 - if (dst_blk_y < comp_height) {
503 + if (y_crop_blocks + dst_blk_y < comp_height) {
504 /* Row is within the vertically mirrorable area. */
505 src_buffer = (*srcinfo->mem->access_virt_barray)
506 ((j_common_ptr) srcinfo, src_coef_arrays[ci],
507 - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
508 + comp_height - y_crop_blocks - dst_blk_y -
509 + (JDIMENSION) compptr->v_samp_factor,
510 (JDIMENSION) compptr->v_samp_factor, FALSE);
512 /* Bottom-edge rows are only mirrored horizontally. */
513 src_buffer = (*srcinfo->mem->access_virt_barray)
514 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
515 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
516 + dst_blk_y + y_crop_blocks,
517 (JDIMENSION) compptr->v_samp_factor, FALSE);
519 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
520 - if (dst_blk_y < comp_height) {
521 + dst_row_ptr = dst_buffer[offset_y];
522 + if (y_crop_blocks + dst_blk_y < comp_height) {
523 /* Row is within the mirrorable area. */
524 - dst_row_ptr = dst_buffer[offset_y];
525 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
526 - /* Process the blocks that can be mirrored both ways. */
527 - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
528 + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
529 dst_ptr = dst_row_ptr[dst_blk_x];
530 - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
531 - for (i = 0; i < DCTSIZE; i += 2) {
532 - /* For even row, negate every odd column. */
533 - for (j = 0; j < DCTSIZE; j += 2) {
534 - *dst_ptr++ = *src_ptr++;
535 - *dst_ptr++ = - *src_ptr++;
536 + if (x_crop_blocks + dst_blk_x < comp_width) {
537 + /* Process the blocks that can be mirrored both ways. */
538 + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
539 + for (i = 0; i < DCTSIZE; i += 2) {
540 + /* For even row, negate every odd column. */
541 + for (j = 0; j < DCTSIZE; j += 2) {
542 + *dst_ptr++ = *src_ptr++;
543 + *dst_ptr++ = - *src_ptr++;
545 + /* For odd row, negate every even column. */
546 + for (j = 0; j < DCTSIZE; j += 2) {
547 + *dst_ptr++ = - *src_ptr++;
548 + *dst_ptr++ = *src_ptr++;
551 - /* For odd row, negate every even column. */
552 - for (j = 0; j < DCTSIZE; j += 2) {
553 - *dst_ptr++ = - *src_ptr++;
554 - *dst_ptr++ = *src_ptr++;
556 + /* Any remaining right-edge blocks are only mirrored vertically. */
557 + src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
558 + for (i = 0; i < DCTSIZE; i += 2) {
559 + for (j = 0; j < DCTSIZE; j++)
560 + *dst_ptr++ = *src_ptr++;
561 + for (j = 0; j < DCTSIZE; j++)
562 + *dst_ptr++ = - *src_ptr++;
566 - /* Any remaining right-edge blocks are only mirrored vertically. */
567 - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
568 - dst_ptr = dst_row_ptr[dst_blk_x];
569 - src_ptr = src_row_ptr[dst_blk_x];
570 - for (i = 0; i < DCTSIZE; i += 2) {
571 - for (j = 0; j < DCTSIZE; j++)
572 - *dst_ptr++ = *src_ptr++;
573 - for (j = 0; j < DCTSIZE; j++)
574 - *dst_ptr++ = - *src_ptr++;
578 /* Remaining rows are just mirrored horizontally. */
579 - dst_row_ptr = dst_buffer[offset_y];
580 src_row_ptr = src_buffer[offset_y];
581 - /* Process the blocks that can be mirrored. */
582 - for (dst_blk_x = 0; dst_blk_x < comp_width; 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 < DCTSIZE2; i += 2) {
586 - *dst_ptr++ = *src_ptr++;
587 - *dst_ptr++ = - *src_ptr++;
588 + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
589 + if (x_crop_blocks + dst_blk_x < comp_width) {
590 + /* Process the blocks that can be mirrored. */
591 + dst_ptr = dst_row_ptr[dst_blk_x];
592 + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
593 + for (i = 0; i < DCTSIZE2; i += 2) {
594 + *dst_ptr++ = *src_ptr++;
595 + *dst_ptr++ = - *src_ptr++;
598 + /* Any remaining right-edge blocks are only copied. */
599 + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
600 + dst_row_ptr + dst_blk_x,
604 - /* Any remaining right-edge blocks are only copied. */
605 - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
606 - dst_ptr = dst_row_ptr[dst_blk_x];
607 - src_ptr = src_row_ptr[dst_blk_x];
608 - for (i = 0; i < DCTSIZE2; i++)
609 - *dst_ptr++ = *src_ptr++;
617 do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
618 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
619 jvirt_barray_ptr *src_coef_arrays,
620 jvirt_barray_ptr *dst_coef_arrays)
621 /* Transverse transpose is equivalent to
622 @@ -470,18 +646,23 @@
625 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
626 + JDIMENSION x_crop_blocks, y_crop_blocks;
627 int ci, i, j, offset_x, offset_y;
628 JBLOCKARRAY src_buffer, dst_buffer;
629 JCOEFPTR src_ptr, dst_ptr;
630 jpeg_component_info *compptr;
632 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
633 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
634 + MCU_cols = srcinfo->output_height /
635 + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
636 + MCU_rows = srcinfo->output_width /
637 + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
639 for (ci = 0; ci < dstinfo->num_components; ci++) {
640 compptr = dstinfo->comp_info + ci;
641 comp_width = MCU_cols * compptr->h_samp_factor;
642 comp_height = MCU_rows * compptr->v_samp_factor;
643 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
644 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
645 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
646 dst_blk_y += compptr->v_samp_factor) {
647 dst_buffer = (*srcinfo->mem->access_virt_barray)
648 @@ -490,17 +671,26 @@
649 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
650 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
651 dst_blk_x += compptr->h_samp_factor) {
652 - src_buffer = (*srcinfo->mem->access_virt_barray)
653 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
654 - (JDIMENSION) compptr->h_samp_factor, FALSE);
655 + if (x_crop_blocks + dst_blk_x < comp_width) {
656 + /* Block is within the mirrorable area. */
657 + src_buffer = (*srcinfo->mem->access_virt_barray)
658 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
659 + comp_width - x_crop_blocks - dst_blk_x -
660 + (JDIMENSION) compptr->h_samp_factor,
661 + (JDIMENSION) compptr->h_samp_factor, FALSE);
663 + src_buffer = (*srcinfo->mem->access_virt_barray)
664 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
665 + dst_blk_x + x_crop_blocks,
666 + (JDIMENSION) compptr->h_samp_factor, FALSE);
668 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
669 - if (dst_blk_y < comp_height) {
670 - src_ptr = src_buffer[offset_x]
671 - [comp_height - dst_blk_y - offset_y - 1];
672 - if (dst_blk_x < comp_width) {
673 + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
674 + if (y_crop_blocks + dst_blk_y < comp_height) {
675 + if (x_crop_blocks + dst_blk_x < comp_width) {
676 /* Block is within the mirrorable area. */
677 - dst_ptr = dst_buffer[offset_y]
678 - [comp_width - dst_blk_x - offset_x - 1];
679 + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
680 + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
681 for (i = 0; i < DCTSIZE; i++) {
682 for (j = 0; j < DCTSIZE; j++) {
683 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
687 /* Right-edge blocks are mirrored in y only */
688 - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
689 + src_ptr = src_buffer[offset_x]
690 + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
691 for (i = 0; i < DCTSIZE; i++) {
692 for (j = 0; j < DCTSIZE; j++) {
693 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
694 @@ -526,11 +717,10 @@
698 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
699 - if (dst_blk_x < comp_width) {
700 + if (x_crop_blocks + dst_blk_x < comp_width) {
701 /* Bottom-edge blocks are mirrored in x only */
702 - dst_ptr = dst_buffer[offset_y]
703 - [comp_width - dst_blk_x - offset_x - 1];
704 + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
705 + [dst_blk_y + offset_y + y_crop_blocks];
706 for (i = 0; i < DCTSIZE; i++) {
707 for (j = 0; j < DCTSIZE; j++)
708 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
712 /* At lower right corner, just transpose, no mirroring */
713 - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
714 + src_ptr = src_buffer[offset_x]
715 + [dst_blk_y + offset_y + y_crop_blocks];
716 for (i = 0; i < DCTSIZE; i++)
717 for (j = 0; j < DCTSIZE; j++)
718 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
719 @@ -554,83 +745,353 @@
723 +/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
724 + * Returns TRUE if valid integer found, FALSE if not.
725 + * *strptr is advanced over the digit string, and *result is set to its value.
729 +jt_read_integer (const char ** strptr, JDIMENSION * result)
731 + const char * ptr = *strptr;
732 + JDIMENSION val = 0;
734 + for (; isdigit(*ptr); ptr++) {
735 + val = val * 10 + (JDIMENSION) (*ptr - '0');
738 + if (ptr == *strptr)
739 + return FALSE; /* oops, no digits */
745 +/* Parse a crop specification (written in X11 geometry style).
746 + * The routine returns TRUE if the spec string is valid, FALSE if not.
748 + * The crop spec string should have the format
749 + * <width>x<height>{+-}<xoffset>{+-}<yoffset>
750 + * where width, height, xoffset, and yoffset are unsigned integers.
751 + * Each of the elements can be omitted to indicate a default value.
752 + * (A weakness of this style is that it is not possible to omit xoffset
753 + * while specifying yoffset, since they look alike.)
755 + * This code is loosely based on XParseGeometry from the X11 distribution.
759 +jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
761 + info->crop = FALSE;
762 + info->crop_width_set = JCROP_UNSET;
763 + info->crop_height_set = JCROP_UNSET;
764 + info->crop_xoffset_set = JCROP_UNSET;
765 + info->crop_yoffset_set = JCROP_UNSET;
767 + if (isdigit(*spec)) {
769 + if (! jt_read_integer(&spec, &info->crop_width))
771 + info->crop_width_set = JCROP_POS;
773 + if (*spec == 'x' || *spec == 'X') {
776 + if (! jt_read_integer(&spec, &info->crop_height))
778 + info->crop_height_set = JCROP_POS;
780 + if (*spec == '+' || *spec == '-') {
781 + /* fetch xoffset */
782 + info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
784 + if (! jt_read_integer(&spec, &info->crop_xoffset))
787 + if (*spec == '+' || *spec == '-') {
788 + /* fetch yoffset */
789 + info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
791 + if (! jt_read_integer(&spec, &info->crop_yoffset))
794 + /* We had better have gotten to the end of the string. */
802 +/* Trim off any partial iMCUs on the indicated destination edge */
805 +trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
807 + JDIMENSION MCU_cols;
809 + MCU_cols = info->output_width / info->iMCU_sample_width;
810 + if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
811 + full_width / info->iMCU_sample_width)
812 + info->output_width = MCU_cols * info->iMCU_sample_width;
816 +trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
818 + JDIMENSION MCU_rows;
820 + MCU_rows = info->output_height / info->iMCU_sample_height;
821 + if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
822 + full_height / info->iMCU_sample_height)
823 + info->output_height = MCU_rows * info->iMCU_sample_height;
827 /* Request any required workspace.
829 + * This routine figures out the size that the output image will be
830 + * (which implies that all the transform parameters must be set before
833 * We allocate the workspace virtual arrays from the source decompression
834 * object, so that all the arrays (both the original data and the workspace)
835 * will be taken into account while making memory management decisions.
836 * Hence, this routine must be called after jpeg_read_header (which reads
837 * the image dimensions) and before jpeg_read_coefficients (which realizes
838 * the source's virtual arrays).
840 + * This function returns FALSE right away if -perfect is given
841 + * and transformation is not perfect. Otherwise returns TRUE.
846 jtransform_request_workspace (j_decompress_ptr srcinfo,
847 jpeg_transform_info *info)
849 - jvirt_barray_ptr *coef_arrays = NULL;
850 + jvirt_barray_ptr *coef_arrays;
851 + boolean need_workspace, transpose_it;
852 jpeg_component_info *compptr;
854 + JDIMENSION xoffset, yoffset;
855 + JDIMENSION width_in_iMCUs, height_in_iMCUs;
856 + JDIMENSION width_in_blocks, height_in_blocks;
857 + int ci, h_samp_factor, v_samp_factor;
859 + /* Determine number of components in output image */
860 if (info->force_grayscale &&
861 srcinfo->jpeg_color_space == JCS_YCbCr &&
862 - srcinfo->num_components == 3) {
863 + srcinfo->num_components == 3)
864 /* We'll only process the first component */
865 info->num_components = 1;
868 /* Process all the components */
869 info->num_components = srcinfo->num_components;
871 + /* Compute output image dimensions and related values. */
872 + jpeg_core_output_dimensions(srcinfo);
874 + /* Return right away if -perfect is given and transformation is not perfect.
876 + if (info->perfect) {
877 + if (info->num_components == 1) {
878 + if (!jtransform_perfect_transform(srcinfo->output_width,
879 + srcinfo->output_height,
880 + srcinfo->min_DCT_h_scaled_size,
881 + srcinfo->min_DCT_v_scaled_size,
885 + if (!jtransform_perfect_transform(srcinfo->output_width,
886 + srcinfo->output_height,
887 + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size,
888 + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size,
894 + /* If there is only one output component, force the iMCU size to be 1;
895 + * else use the source iMCU size. (This allows us to do the right thing
896 + * when reducing color to grayscale, and also provides a handy way of
897 + * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
899 + switch (info->transform) {
900 + case JXFORM_TRANSPOSE:
901 + case JXFORM_TRANSVERSE:
902 + case JXFORM_ROT_90:
903 + case JXFORM_ROT_270:
904 + info->output_width = srcinfo->output_height;
905 + info->output_height = srcinfo->output_width;
906 + if (info->num_components == 1) {
907 + info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;
908 + info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;
910 + info->iMCU_sample_width =
911 + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
912 + info->iMCU_sample_height =
913 + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
917 + info->output_width = srcinfo->output_width;
918 + info->output_height = srcinfo->output_height;
919 + if (info->num_components == 1) {
920 + info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;
921 + info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;
923 + info->iMCU_sample_width =
924 + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
925 + info->iMCU_sample_height =
926 + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
931 + /* If cropping has been requested, compute the crop area's position and
932 + * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
935 + /* Insert default values for unset crop parameters */
936 + if (info->crop_xoffset_set == JCROP_UNSET)
937 + info->crop_xoffset = 0; /* default to +0 */
938 + if (info->crop_yoffset_set == JCROP_UNSET)
939 + info->crop_yoffset = 0; /* default to +0 */
940 + if (info->crop_xoffset >= info->output_width ||
941 + info->crop_yoffset >= info->output_height)
942 + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
943 + if (info->crop_width_set == JCROP_UNSET)
944 + info->crop_width = info->output_width - info->crop_xoffset;
945 + if (info->crop_height_set == JCROP_UNSET)
946 + info->crop_height = info->output_height - info->crop_yoffset;
947 + /* Ensure parameters are valid */
948 + if (info->crop_width <= 0 || info->crop_width > info->output_width ||
949 + info->crop_height <= 0 || info->crop_height > info->output_height ||
950 + info->crop_xoffset > info->output_width - info->crop_width ||
951 + info->crop_yoffset > info->output_height - info->crop_height)
952 + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
953 + /* Convert negative crop offsets into regular offsets */
954 + if (info->crop_xoffset_set == JCROP_NEG)
955 + xoffset = info->output_width - info->crop_width - info->crop_xoffset;
957 + xoffset = info->crop_xoffset;
958 + if (info->crop_yoffset_set == JCROP_NEG)
959 + yoffset = info->output_height - info->crop_height - info->crop_yoffset;
961 + yoffset = info->crop_yoffset;
962 + /* Now adjust so that upper left corner falls at an iMCU boundary */
963 + info->output_width =
964 + info->crop_width + (xoffset % info->iMCU_sample_width);
965 + info->output_height =
966 + info->crop_height + (yoffset % info->iMCU_sample_height);
967 + /* Save x/y offsets measured in iMCUs */
968 + info->x_crop_offset = xoffset / info->iMCU_sample_width;
969 + info->y_crop_offset = yoffset / info->iMCU_sample_height;
971 + info->x_crop_offset = 0;
972 + info->y_crop_offset = 0;
975 + /* Figure out whether we need workspace arrays,
976 + * and if so whether they are transposed relative to the source.
978 + need_workspace = FALSE;
979 + transpose_it = FALSE;
980 switch (info->transform) {
982 + if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
983 + need_workspace = TRUE;
984 + /* No workspace needed if neither cropping nor transforming */
987 - /* Don't need a workspace array */
989 + trim_right_edge(info, srcinfo->output_width);
990 + if (info->y_crop_offset != 0)
991 + need_workspace = TRUE;
992 + /* do_flip_h_no_crop doesn't need a workspace array */
995 - case JXFORM_ROT_180:
996 - /* Need workspace arrays having same dimensions as source image.
997 - * Note that we allocate arrays padded out to the next iMCU boundary,
998 - * so that transform routines need not worry about missing edge blocks.
1000 - coef_arrays = (jvirt_barray_ptr *)
1001 - (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1002 - SIZEOF(jvirt_barray_ptr) * info->num_components);
1003 - for (ci = 0; ci < info->num_components; ci++) {
1004 - compptr = srcinfo->comp_info + ci;
1005 - coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1006 - ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1007 - (JDIMENSION) jround_up((long) compptr->width_in_blocks,
1008 - (long) compptr->h_samp_factor),
1009 - (JDIMENSION) jround_up((long) compptr->height_in_blocks,
1010 - (long) compptr->v_samp_factor),
1011 - (JDIMENSION) compptr->v_samp_factor);
1014 + trim_bottom_edge(info, srcinfo->output_height);
1015 + /* Need workspace arrays having same dimensions as source image. */
1016 + need_workspace = TRUE;
1018 case JXFORM_TRANSPOSE:
1019 + /* transpose does NOT have to trim anything */
1020 + /* Need workspace arrays having transposed dimensions. */
1021 + need_workspace = TRUE;
1022 + transpose_it = TRUE;
1024 case JXFORM_TRANSVERSE:
1026 + trim_right_edge(info, srcinfo->output_height);
1027 + trim_bottom_edge(info, srcinfo->output_width);
1029 + /* Need workspace arrays having transposed dimensions. */
1030 + need_workspace = TRUE;
1031 + transpose_it = TRUE;
1035 + trim_right_edge(info, srcinfo->output_height);
1036 + /* Need workspace arrays having transposed dimensions. */
1037 + need_workspace = TRUE;
1038 + transpose_it = TRUE;
1040 + case JXFORM_ROT_180:
1042 + trim_right_edge(info, srcinfo->output_width);
1043 + trim_bottom_edge(info, srcinfo->output_height);
1045 + /* Need workspace arrays having same dimensions as source image. */
1046 + need_workspace = TRUE;
1048 case JXFORM_ROT_270:
1049 - /* Need workspace arrays having transposed dimensions.
1050 - * Note that we allocate arrays padded out to the next iMCU boundary,
1051 - * so that transform routines need not worry about missing edge blocks.
1054 + trim_bottom_edge(info, srcinfo->output_width);
1055 + /* Need workspace arrays having transposed dimensions. */
1056 + need_workspace = TRUE;
1057 + transpose_it = TRUE;
1061 + /* Allocate workspace if needed.
1062 + * Note that we allocate arrays padded out to the next iMCU boundary,
1063 + * so that transform routines need not worry about missing edge blocks.
1065 + if (need_workspace) {
1066 coef_arrays = (jvirt_barray_ptr *)
1067 (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1068 - SIZEOF(jvirt_barray_ptr) * info->num_components);
1069 + SIZEOF(jvirt_barray_ptr) * info->num_components);
1070 + width_in_iMCUs = (JDIMENSION)
1071 + jdiv_round_up((long) info->output_width,
1072 + (long) info->iMCU_sample_width);
1073 + height_in_iMCUs = (JDIMENSION)
1074 + jdiv_round_up((long) info->output_height,
1075 + (long) info->iMCU_sample_height);
1076 for (ci = 0; ci < info->num_components; ci++) {
1077 compptr = srcinfo->comp_info + ci;
1078 + if (info->num_components == 1) {
1079 + /* we're going to force samp factors to 1x1 in this case */
1080 + h_samp_factor = v_samp_factor = 1;
1081 + } else if (transpose_it) {
1082 + h_samp_factor = compptr->v_samp_factor;
1083 + v_samp_factor = compptr->h_samp_factor;
1085 + h_samp_factor = compptr->h_samp_factor;
1086 + v_samp_factor = compptr->v_samp_factor;
1088 + width_in_blocks = width_in_iMCUs * h_samp_factor;
1089 + height_in_blocks = height_in_iMCUs * v_samp_factor;
1090 coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1091 ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1092 - (JDIMENSION) jround_up((long) compptr->height_in_blocks,
1093 - (long) compptr->v_samp_factor),
1094 - (JDIMENSION) jround_up((long) compptr->width_in_blocks,
1095 - (long) compptr->h_samp_factor),
1096 - (JDIMENSION) compptr->h_samp_factor);
1097 + width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
1101 - info->workspace_coef_arrays = coef_arrays;
1102 + info->workspace_coef_arrays = coef_arrays;
1104 + info->workspace_coef_arrays = NULL;
1110 @@ -642,13 +1103,16 @@
1111 int tblno, i, j, ci, itemp;
1112 jpeg_component_info *compptr;
1113 JQUANT_TBL *qtblptr;
1118 - /* Transpose basic image dimensions */
1119 - dtemp = dstinfo->image_width;
1120 + /* Transpose image dimensions */
1121 + jtemp = dstinfo->image_width;
1122 dstinfo->image_width = dstinfo->image_height;
1123 - dstinfo->image_height = dtemp;
1124 + dstinfo->image_height = jtemp;
1125 + itemp = dstinfo->min_DCT_h_scaled_size;
1126 + dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
1127 + dstinfo->min_DCT_v_scaled_size = itemp;
1129 /* Transpose sampling factors */
1130 for (ci = 0; ci < dstinfo->num_components; ci++) {
1131 @@ -674,46 +1138,159 @@
1135 -/* Trim off any partial iMCUs on the indicated destination edge */
1136 +/* Adjust Exif image parameters.
1138 + * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1142 -trim_right_edge (j_compress_ptr dstinfo)
1143 +adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
1144 + JDIMENSION new_width, JDIMENSION new_height)
1146 - int ci, max_h_samp_factor;
1147 - JDIMENSION MCU_cols;
1148 + boolean is_motorola; /* Flag for byte order */
1149 + unsigned int number_of_tags, tagnum;
1150 + unsigned int firstoffset, offset;
1151 + JDIMENSION new_value;
1153 + if (length < 12) return; /* Length of an IFD entry */
1155 + /* Discover byte order */
1156 + if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
1157 + is_motorola = FALSE;
1158 + else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
1159 + is_motorola = TRUE;
1163 + /* Check Tag Mark */
1164 + if (is_motorola) {
1165 + if (GETJOCTET(data[2]) != 0) return;
1166 + if (GETJOCTET(data[3]) != 0x2A) return;
1168 + if (GETJOCTET(data[3]) != 0) return;
1169 + if (GETJOCTET(data[2]) != 0x2A) return;
1172 - /* We have to compute max_h_samp_factor ourselves,
1173 - * because it hasn't been set yet in the destination
1174 - * (and we don't want to use the source's value).
1176 - max_h_samp_factor = 1;
1177 - for (ci = 0; ci < dstinfo->num_components; ci++) {
1178 - int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor;
1179 - max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor);
1180 + /* Get first IFD offset (offset to IFD0) */
1181 + if (is_motorola) {
1182 + if (GETJOCTET(data[4]) != 0) return;
1183 + if (GETJOCTET(data[5]) != 0) return;
1184 + firstoffset = GETJOCTET(data[6]);
1185 + firstoffset <<= 8;
1186 + firstoffset += GETJOCTET(data[7]);
1188 + if (GETJOCTET(data[7]) != 0) return;
1189 + if (GETJOCTET(data[6]) != 0) return;
1190 + firstoffset = GETJOCTET(data[5]);
1191 + firstoffset <<= 8;
1192 + firstoffset += GETJOCTET(data[4]);
1194 - MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE);
1195 - if (MCU_cols > 0) /* can't trim to 0 pixels */
1196 - dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE);
1198 + if (firstoffset > length - 2) return; /* check end of data segment */
1201 -trim_bottom_edge (j_compress_ptr dstinfo)
1203 - int ci, max_v_samp_factor;
1204 - JDIMENSION MCU_rows;
1205 + /* Get the number of directory entries contained in this IFD */
1206 + if (is_motorola) {
1207 + number_of_tags = GETJOCTET(data[firstoffset]);
1208 + number_of_tags <<= 8;
1209 + number_of_tags += GETJOCTET(data[firstoffset+1]);
1211 + number_of_tags = GETJOCTET(data[firstoffset+1]);
1212 + number_of_tags <<= 8;
1213 + number_of_tags += GETJOCTET(data[firstoffset]);
1215 + if (number_of_tags == 0) return;
1218 - /* We have to compute max_v_samp_factor ourselves,
1219 - * because it hasn't been set yet in the destination
1220 - * (and we don't want to use the source's value).
1222 - max_v_samp_factor = 1;
1223 - for (ci = 0; ci < dstinfo->num_components; ci++) {
1224 - int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor;
1225 - max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor);
1226 + /* Search for ExifSubIFD offset Tag in IFD0 */
1228 + if (firstoffset > length - 12) return; /* check end of data segment */
1229 + /* Get Tag number */
1230 + if (is_motorola) {
1231 + tagnum = GETJOCTET(data[firstoffset]);
1233 + tagnum += GETJOCTET(data[firstoffset+1]);
1235 + tagnum = GETJOCTET(data[firstoffset+1]);
1237 + tagnum += GETJOCTET(data[firstoffset]);
1239 + if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1240 + if (--number_of_tags == 0) return;
1241 + firstoffset += 12;
1244 + /* Get the ExifSubIFD offset */
1245 + if (is_motorola) {
1246 + if (GETJOCTET(data[firstoffset+8]) != 0) return;
1247 + if (GETJOCTET(data[firstoffset+9]) != 0) return;
1248 + offset = GETJOCTET(data[firstoffset+10]);
1250 + offset += GETJOCTET(data[firstoffset+11]);
1252 + if (GETJOCTET(data[firstoffset+11]) != 0) return;
1253 + if (GETJOCTET(data[firstoffset+10]) != 0) return;
1254 + offset = GETJOCTET(data[firstoffset+9]);
1256 + offset += GETJOCTET(data[firstoffset+8]);
1258 + if (offset > length - 2) return; /* check end of data segment */
1260 + /* Get the number of directory entries contained in this SubIFD */
1261 + if (is_motorola) {
1262 + number_of_tags = GETJOCTET(data[offset]);
1263 + number_of_tags <<= 8;
1264 + number_of_tags += GETJOCTET(data[offset+1]);
1266 + number_of_tags = GETJOCTET(data[offset+1]);
1267 + number_of_tags <<= 8;
1268 + number_of_tags += GETJOCTET(data[offset]);
1270 - MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE);
1271 - if (MCU_rows > 0) /* can't trim to 0 pixels */
1272 - dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE);
1273 + if (number_of_tags < 2) return;
1276 + /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1278 + if (offset > length - 12) return; /* check end of data segment */
1279 + /* Get Tag number */
1280 + if (is_motorola) {
1281 + tagnum = GETJOCTET(data[offset]);
1283 + tagnum += GETJOCTET(data[offset+1]);
1285 + tagnum = GETJOCTET(data[offset+1]);
1287 + tagnum += GETJOCTET(data[offset]);
1289 + if (tagnum == 0xA002 || tagnum == 0xA003) {
1290 + if (tagnum == 0xA002)
1291 + new_value = new_width; /* ExifImageWidth Tag */
1293 + new_value = new_height; /* ExifImageHeight Tag */
1294 + if (is_motorola) {
1295 + data[offset+2] = 0; /* Format = unsigned long (4 octets) */
1296 + data[offset+3] = 4;
1297 + data[offset+4] = 0; /* Number Of Components = 1 */
1298 + data[offset+5] = 0;
1299 + data[offset+6] = 0;
1300 + data[offset+7] = 1;
1301 + data[offset+8] = 0;
1302 + data[offset+9] = 0;
1303 + data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
1304 + data[offset+11] = (JOCTET)(new_value & 0xFF);
1306 + data[offset+2] = 4; /* Format = unsigned long (4 octets) */
1307 + data[offset+3] = 0;
1308 + data[offset+4] = 1; /* Number Of Components = 1 */
1309 + data[offset+5] = 0;
1310 + data[offset+6] = 0;
1311 + data[offset+7] = 0;
1312 + data[offset+8] = (JOCTET)(new_value & 0xFF);
1313 + data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
1314 + data[offset+10] = 0;
1315 + data[offset+11] = 0;
1319 + } while (--number_of_tags);
1323 @@ -736,18 +1313,22 @@
1325 /* If force-to-grayscale is requested, adjust destination parameters */
1326 if (info->force_grayscale) {
1327 - /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1328 - * properly. Among other things, the target h_samp_factor & v_samp_factor
1329 - * will get set to 1, which typically won't match the source.
1330 - * In fact we do this even if the source is already grayscale; that
1331 - * provides an easy way of coercing a grayscale JPEG with funny sampling
1332 - * factors to the customary 1,1. (Some decoders fail on other factors.)
1333 + /* First, ensure we have YCbCr or grayscale data, and that the source's
1334 + * Y channel is full resolution. (No reasonable person would make Y
1335 + * be less than full resolution, so actually coping with that case
1336 + * isn't worth extra code space. But we check it to avoid crashing.)
1338 - if ((dstinfo->jpeg_color_space == JCS_YCbCr &&
1339 - dstinfo->num_components == 3) ||
1340 - (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1341 - dstinfo->num_components == 1)) {
1342 - /* We have to preserve the source's quantization table number. */
1343 + if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
1344 + dstinfo->num_components == 3) ||
1345 + (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1346 + dstinfo->num_components == 1)) &&
1347 + srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
1348 + srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
1349 + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1350 + * properly. Among other things, it sets the target h_samp_factor &
1351 + * v_samp_factor to 1, which typically won't match the source.
1352 + * We have to preserve the source's quantization table number, however.
1354 int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
1355 jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
1356 dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
1357 @@ -755,50 +1336,54 @@
1358 /* Sorry, can't do it */
1359 ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
1361 + } else if (info->num_components == 1) {
1362 + /* For a single-component source, we force the destination sampling factors
1363 + * to 1x1, with or without force_grayscale. This is useful because some
1364 + * decoders choke on grayscale images with other sampling factors.
1366 + dstinfo->comp_info[0].h_samp_factor = 1;
1367 + dstinfo->comp_info[0].v_samp_factor = 1;
1370 - /* Correct the destination's image dimensions etc if necessary */
1371 + /* Correct the destination's image dimensions as necessary
1372 + * for rotate/flip, resize, and crop operations.
1374 + dstinfo->jpeg_width = info->output_width;
1375 + dstinfo->jpeg_height = info->output_height;
1377 + /* Transpose destination image parameters */
1378 switch (info->transform) {
1380 - /* Nothing to do */
1382 - case JXFORM_FLIP_H:
1384 - trim_right_edge(dstinfo);
1386 - case JXFORM_FLIP_V:
1388 - trim_bottom_edge(dstinfo);
1390 case JXFORM_TRANSPOSE:
1391 - transpose_critical_parameters(dstinfo);
1392 - /* transpose does NOT have to trim anything */
1394 case JXFORM_TRANSVERSE:
1395 - transpose_critical_parameters(dstinfo);
1397 - trim_right_edge(dstinfo);
1398 - trim_bottom_edge(dstinfo);
1402 - transpose_critical_parameters(dstinfo);
1404 - trim_right_edge(dstinfo);
1406 - case JXFORM_ROT_180:
1408 - trim_right_edge(dstinfo);
1409 - trim_bottom_edge(dstinfo);
1412 case JXFORM_ROT_270:
1413 transpose_critical_parameters(dstinfo);
1415 - trim_bottom_edge(dstinfo);
1421 + /* Adjust Exif properties */
1422 + if (srcinfo->marker_list != NULL &&
1423 + srcinfo->marker_list->marker == JPEG_APP0+1 &&
1424 + srcinfo->marker_list->data_length >= 6 &&
1425 + GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
1426 + GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
1427 + GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
1428 + GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
1429 + GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
1430 + GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
1431 + /* Suppress output of JFIF marker */
1432 + dstinfo->write_JFIF_header = FALSE;
1433 + /* Adjust Exif image parameters */
1434 + if (dstinfo->jpeg_width != srcinfo->image_width ||
1435 + dstinfo->jpeg_height != srcinfo->image_height)
1436 + /* Align data segment to start of TIFF structure for parsing */
1437 + adjust_exif_parameters(srcinfo->marker_list->data + 6,
1438 + srcinfo->marker_list->data_length - 6,
1439 + dstinfo->jpeg_width, dstinfo->jpeg_height);
1442 /* Return the appropriate output data set */
1443 if (info->workspace_coef_arrays != NULL)
1444 return info->workspace_coef_arrays;
1445 @@ -816,40 +1401,110 @@
1449 -jtransform_execute_transformation (j_decompress_ptr srcinfo,
1450 - j_compress_ptr dstinfo,
1451 - jvirt_barray_ptr *src_coef_arrays,
1452 - jpeg_transform_info *info)
1453 +jtransform_execute_transform (j_decompress_ptr srcinfo,
1454 + j_compress_ptr dstinfo,
1455 + jvirt_barray_ptr *src_coef_arrays,
1456 + jpeg_transform_info *info)
1458 jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
1460 + /* Note: conditions tested here should match those in switch statement
1461 + * in jtransform_request_workspace()
1463 switch (info->transform) {
1465 + if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1466 + do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1467 + src_coef_arrays, dst_coef_arrays);
1470 - do_flip_h(srcinfo, dstinfo, src_coef_arrays);
1471 + if (info->y_crop_offset != 0)
1472 + do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1473 + src_coef_arrays, dst_coef_arrays);
1475 + do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
1479 - do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1480 + do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1481 + src_coef_arrays, dst_coef_arrays);
1483 case JXFORM_TRANSPOSE:
1484 - do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1485 + do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1486 + src_coef_arrays, dst_coef_arrays);
1488 case JXFORM_TRANSVERSE:
1489 - do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1490 + do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1491 + src_coef_arrays, dst_coef_arrays);
1494 - do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1495 + do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1496 + src_coef_arrays, dst_coef_arrays);
1498 case JXFORM_ROT_180:
1499 - do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1500 + do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1501 + src_coef_arrays, dst_coef_arrays);
1503 case JXFORM_ROT_270:
1504 - do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1505 + do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1506 + src_coef_arrays, dst_coef_arrays);
1511 +/* jtransform_perfect_transform
1513 + * Determine whether lossless transformation is perfectly
1514 + * possible for a specified image and transformation.
1517 + * image_width, image_height: source image dimensions.
1518 + * MCU_width, MCU_height: pixel dimensions of MCU.
1519 + * transform: transformation identifier.
1520 + * Parameter sources from initialized jpeg_struct
1521 + * (after reading source header):
1522 + * image_width = cinfo.image_width
1523 + * image_height = cinfo.image_height
1524 + * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
1525 + * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
1527 + * TRUE = perfect transformation possible
1528 + * FALSE = perfect transformation not possible
1529 + * (may use custom action then)
1533 +jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
1534 + int MCU_width, int MCU_height,
1535 + JXFORM_CODE transform)
1537 + boolean result = TRUE; /* initialize TRUE */
1539 + switch (transform) {
1540 + case JXFORM_FLIP_H:
1541 + case JXFORM_ROT_270:
1542 + if (image_width % (JDIMENSION) MCU_width)
1545 + case JXFORM_FLIP_V:
1546 + case JXFORM_ROT_90:
1547 + if (image_height % (JDIMENSION) MCU_height)
1550 + case JXFORM_TRANSVERSE:
1551 + case JXFORM_ROT_180:
1552 + if (image_width % (JDIMENSION) MCU_width)
1554 + if (image_height % (JDIMENSION) MCU_height)
1564 #endif /* TRANSFORMS_SUPPORTED */
1567 diff -urN fbida-2.07.orig/jpeg/transupp.h fbida-2.07/jpeg/transupp.h
1568 --- fbida-2.07.orig/jpeg/transupp.h 2010-03-02 09:22:37.000000000 +0100
1569 +++ fbida-2.07/jpeg/transupp.h 2010-03-02 09:24:15.000000000 +0100
1574 - * Copyright (C) 1997, Thomas G. Lane.
1575 + * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
1576 * This file is part of the Independent JPEG Group's software.
1577 * For conditions of distribution and use, see the accompanying README file.
1580 #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */
1583 -/* Short forms of external names for systems with brain-damaged linkers. */
1585 -#ifdef NEED_SHORT_EXTERNAL_NAMES
1586 -#define jtransform_request_workspace jTrRequest
1587 -#define jtransform_adjust_parameters jTrAdjust
1588 -#define jtransform_execute_transformation jTrExec
1589 -#define jcopy_markers_setup jCMrkSetup
1590 -#define jcopy_markers_execute jCMrkExec
1591 -#endif /* NEED_SHORT_EXTERNAL_NAMES */
1595 - * Codes for supported types of image transformations.
1599 - JXFORM_NONE, /* no transformation */
1600 - JXFORM_FLIP_H, /* horizontal flip */
1601 - JXFORM_FLIP_V, /* vertical flip */
1602 - JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */
1603 - JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
1604 - JXFORM_ROT_90, /* 90-degree clockwise rotation */
1605 - JXFORM_ROT_180, /* 180-degree rotation */
1606 - JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */
1610 * Although rotating and flipping data expressed as DCT coefficients is not
1611 * hard, there is an asymmetry in the JPEG format specification for images
1613 * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
1614 * followed by -rot 180 -trim trims both edges.)
1616 + * We also offer a lossless-crop option, which discards data outside a given
1617 + * image region but losslessly preserves what is inside. Like the rotate and
1618 + * flip transforms, lossless crop is restricted by the JPEG format: the upper
1619 + * left corner of the selected region must fall on an iMCU boundary. If this
1620 + * does not hold for the given crop parameters, we silently move the upper left
1621 + * corner up and/or left to make it so, simultaneously increasing the region
1622 + * dimensions to keep the lower right crop corner unchanged. (Thus, the
1623 + * output image covers at least the requested region, but may cover more.)
1625 + * We also provide a lossless-resize option, which is kind of a lossless-crop
1626 + * operation in the DCT coefficient block domain - it discards higher-order
1627 + * coefficients and losslessly preserves lower-order coefficients of a
1630 + * Rotate/flip transform, resize, and crop can be requested together in a
1631 + * single invocation. The crop is applied last --- that is, the crop region
1632 + * is specified in terms of the destination image after transform/resize.
1634 * We also offer a "force to grayscale" option, which simply discards the
1635 * chrominance channels of a YCbCr image. This is lossless in the sense that
1636 * the luminance channel is preserved exactly. It's not the same kind of
1638 * be aware of the option to know how many components to work on.
1642 +/* Short forms of external names for systems with brain-damaged linkers. */
1644 +#ifdef NEED_SHORT_EXTERNAL_NAMES
1645 +#define jtransform_parse_crop_spec jTrParCrop
1646 +#define jtransform_request_workspace jTrRequest
1647 +#define jtransform_adjust_parameters jTrAdjust
1648 +#define jtransform_execute_transform jTrExec
1649 +#define jtransform_perfect_transform jTrPerfect
1650 +#define jcopy_markers_setup jCMrkSetup
1651 +#define jcopy_markers_execute jCMrkExec
1652 +#endif /* NEED_SHORT_EXTERNAL_NAMES */
1656 + * Codes for supported types of image transformations.
1660 + JXFORM_NONE, /* no transformation */
1661 + JXFORM_FLIP_H, /* horizontal flip */
1662 + JXFORM_FLIP_V, /* vertical flip */
1663 + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */
1664 + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
1665 + JXFORM_ROT_90, /* 90-degree clockwise rotation */
1666 + JXFORM_ROT_180, /* 180-degree rotation */
1667 + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */
1671 + * Codes for crop parameters, which can individually be unspecified,
1672 + * positive, or negative. (Negative width or height makes no sense, though.)
1682 + * Transform parameters struct.
1683 + * NB: application must not change any elements of this struct after
1684 + * calling jtransform_request_workspace.
1688 /* Options: set by caller */
1689 JXFORM_CODE transform; /* image transform operator */
1690 + boolean perfect; /* if TRUE, fail if partial MCUs are requested */
1691 boolean trim; /* if TRUE, trim partial MCUs as needed */
1692 boolean force_grayscale; /* if TRUE, convert color image to grayscale */
1693 + boolean crop; /* if TRUE, crop source image */
1695 + /* Crop parameters: application need not set these unless crop is TRUE.
1696 + * These can be filled in by jtransform_parse_crop_spec().
1698 + JDIMENSION crop_width; /* Width of selected region */
1699 + JCROP_CODE crop_width_set;
1700 + JDIMENSION crop_height; /* Height of selected region */
1701 + JCROP_CODE crop_height_set;
1702 + JDIMENSION crop_xoffset; /* X offset of selected region */
1703 + JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */
1704 + JDIMENSION crop_yoffset; /* Y offset of selected region */
1705 + JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */
1707 /* Internal workspace: caller should not touch these */
1708 int num_components; /* # of components in workspace */
1709 jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */
1710 + JDIMENSION output_width; /* cropped destination dimensions */
1711 + JDIMENSION output_height;
1712 + JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */
1713 + JDIMENSION y_crop_offset;
1714 + int iMCU_sample_width; /* destination iMCU size */
1715 + int iMCU_sample_height;
1716 } jpeg_transform_info;
1719 #if TRANSFORMS_SUPPORTED
1721 +/* Parse a crop specification (written in X11 geometry style) */
1722 +EXTERN(boolean) jtransform_parse_crop_spec
1723 + JPP((jpeg_transform_info *info, const char *spec));
1724 /* Request any required workspace */
1725 -EXTERN(void) jtransform_request_workspace
1726 +EXTERN(boolean) jtransform_request_workspace
1727 JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));
1728 /* Adjust output image parameters */
1729 EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters
1730 @@ -106,10 +167,24 @@
1731 jvirt_barray_ptr *src_coef_arrays,
1732 jpeg_transform_info *info));
1733 /* Execute the actual transformation, if any */
1734 -EXTERN(void) jtransform_execute_transformation
1735 +EXTERN(void) jtransform_execute_transform
1736 JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1737 jvirt_barray_ptr *src_coef_arrays,
1738 jpeg_transform_info *info));
1739 +/* Determine whether lossless transformation is perfectly
1740 + * possible for a specified image and transformation.
1742 +EXTERN(boolean) jtransform_perfect_transform
1743 + JPP((JDIMENSION image_width, JDIMENSION image_height,
1744 + int MCU_width, int MCU_height,
1745 + JXFORM_CODE transform));
1747 +/* jtransform_execute_transform used to be called
1748 + * jtransform_execute_transformation, but some compilers complain about
1749 + * routine names that long. This macro is here to avoid breaking any
1750 + * old source code that uses the original name...
1752 +#define jtransform_execute_transformation jtransform_execute_transform
1754 #endif /* TRANSFORMS_SUPPORTED */