1 diff -Nur jpeg-6b.orig/jerror.h jpeg-6b/jerror.h
2 --- jpeg-6b.orig/jerror.h 1997-10-18 20:59:10.000000000 +0200
3 +++ jpeg-6b/jerror.h 2000-03-05 23:34:27.000000000 +0100
5 JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
6 JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
7 JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
8 +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
9 JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
10 JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
11 JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
12 diff -Nur jpeg-6b.orig/jpegtran.c jpeg-6b/jpegtran.c
13 --- jpeg-6b.orig/jpegtran.c 1997-07-24 04:37:26.000000000 +0200
14 +++ jpeg-6b/jpegtran.c 2003-09-21 21:30:21.000000000 +0200
19 - * Copyright (C) 1995-1997, Thomas G. Lane.
20 + * Copyright (C) 1995-2001, Thomas G. Lane.
21 * This file is part of the Independent JPEG Group's software.
22 * For conditions of distribution and use, see the accompanying README file.
26 #if TRANSFORMS_SUPPORTED
27 fprintf(stderr, "Switches for modifying the image:\n");
28 + fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n");
29 fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
30 fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
31 + fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n");
32 fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
33 fprintf(stderr, " -transpose Transpose image\n");
34 fprintf(stderr, " -transverse Transverse transpose image\n");
36 copyoption = JCOPYOPT_DEFAULT;
37 transformoption.transform = JXFORM_NONE;
38 transformoption.trim = FALSE;
39 + transformoption.perfect = FALSE;
40 transformoption.force_grayscale = FALSE;
41 + transformoption.crop = FALSE;
42 cinfo->err->trace_level = 0;
44 /* Scan command line options, adjust parameters */
49 - } else if (keymatch(arg, "copy", 1)) {
50 + } else if (keymatch(arg, "copy", 2)) {
51 /* Select which extra markers to copy. */
52 if (++argn >= argc) /* advance to next argument */
58 + } else if (keymatch(arg, "crop", 2)) {
59 + /* Perform lossless cropping. */
60 +#if TRANSFORMS_SUPPORTED
61 + if (++argn >= argc) /* advance to next argument */
63 + if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
64 + fprintf(stderr, "%s: bogus -crop argument '%s'\n",
65 + progname, argv[argn]);
69 + select_transform(JXFORM_NONE); /* force an error */
72 } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
73 /* Enable debug printouts. */
74 /* On first -d, print version identification */
77 outfilename = argv[argn]; /* save it away for later use */
79 - } else if (keymatch(arg, "progressive", 1)) {
80 + } else if (keymatch(arg, "perfect", 2)) {
81 + /* Fail if there is any partial edge MCUs that the transform can't
83 + transformoption.perfect = TRUE;
85 + } else if (keymatch(arg, "progressive", 2)) {
86 /* Select simple progressive mode. */
87 #ifdef C_PROGRESSIVE_SUPPORTED
88 simple_progressive = TRUE;
90 jvirt_barray_ptr * src_coef_arrays;
91 jvirt_barray_ptr * dst_coef_arrays;
95 + /* We assume all-in-memory processing and can therefore use only a
96 + * single file pointer for sequential input and output operation.
100 /* On Mac, fetch a command line. */
102 @@ -406,24 +431,13 @@
104 /* Open the input file. */
105 if (file_index < argc) {
106 - if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
107 - fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
108 + if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
109 + fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]);
113 /* default input file is stdin */
114 - input_file = read_stdin();
117 - /* Open the output file. */
118 - if (outfilename != NULL) {
119 - if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
120 - fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
121 - exit(EXIT_FAILURE);
124 - /* default output file is stdout */
125 - output_file = write_stdout();
129 #ifdef PROGRESS_REPORT
133 /* Specify data source for decompression */
134 - jpeg_stdio_src(&srcinfo, input_file);
135 + jpeg_stdio_src(&srcinfo, fp);
137 /* Enable saving of extra markers that we want to copy */
138 jcopy_markers_setup(&srcinfo, copyoption);
140 * jpeg_read_coefficients so that memory allocation will be done right.
142 #if TRANSFORMS_SUPPORTED
143 + /* Fails right away if -perfect is given and transformation is not perfect.
145 + if (transformoption.perfect &&
146 + !jtransform_perfect_transform(srcinfo.image_width, srcinfo.image_height,
147 + srcinfo.max_h_samp_factor * DCTSIZE, srcinfo.max_v_samp_factor * DCTSIZE,
148 + transformoption.transform)) {
149 + fprintf(stderr, "%s: transformation is not perfect\n", progname);
150 + exit(EXIT_FAILURE);
152 jtransform_request_workspace(&srcinfo, &transformoption);
155 @@ -463,11 +486,32 @@
156 dst_coef_arrays = src_coef_arrays;
159 + /* Close input file, if we opened it.
160 + * Note: we assume that jpeg_read_coefficients consumed all input
161 + * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
162 + * only consume more while (! cinfo->inputctl->eoi_reached).
163 + * We cannot call jpeg_finish_decompress here since we still need the
164 + * virtual arrays allocated from the source object for processing.
169 + /* Open the output file. */
170 + if (outfilename != NULL) {
171 + if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {
172 + fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename);
173 + exit(EXIT_FAILURE);
176 + /* default output file is stdout */
177 + fp = write_stdout();
180 /* Adjust default compression parameters by re-parsing the options */
181 file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
183 /* Specify data destination for compression */
184 - jpeg_stdio_dest(&dstinfo, output_file);
185 + jpeg_stdio_dest(&dstinfo, fp);
187 /* Start compressor (note no image data is actually written here) */
188 jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
190 (void) jpeg_finish_decompress(&srcinfo);
191 jpeg_destroy_decompress(&srcinfo);
193 - /* Close files, if we opened them */
194 - if (input_file != stdin)
195 - fclose(input_file);
196 - if (output_file != stdout)
197 - fclose(output_file);
198 + /* Close output file, if we opened it */
202 #ifdef PROGRESS_REPORT
203 end_progress_monitor((j_common_ptr) &dstinfo);
204 diff -Nur jpeg-6b.orig/transupp.c jpeg-6b/transupp.c
205 --- jpeg-6b.orig/transupp.c 1997-08-10 02:15:26.000000000 +0200
206 +++ jpeg-6b/transupp.c 2003-09-21 22:50:33.000000000 +0200
211 - * Copyright (C) 1997, Thomas G. Lane.
212 + * Copyright (C) 1997-2001, Thomas G. Lane.
213 * This file is part of the Independent JPEG Group's software.
214 * For conditions of distribution and use, see the accompanying README file.
217 #include "jinclude.h"
219 #include "transupp.h" /* My own external interface */
220 +#include <ctype.h> /* to declare isdigit() */
223 #if TRANSFORMS_SUPPORTED
225 * Lossless image transformation routines. These routines work on DCT
226 * coefficient arrays and thus do not require any lossy decompression
227 * or recompression of the image.
228 - * Thanks to Guido Vollbeding for the initial design and code of this feature.
229 + * Thanks to Guido Vollbeding for the initial design and code of this feature,
230 + * and to Ben Jackson for introducing the cropping feature.
232 * Horizontal flipping is done in-place, using a single top-to-bottom
233 * pass through the virtual source array. It will thus be much the
235 * arrays for most of the transforms. That could result in much thrashing
236 * if the image is larger than main memory.
238 + * If cropping or trimming is involved, the destination arrays may be smaller
239 + * than the source arrays. Note it is not possible to do horizontal flip
240 + * in-place when a nonzero Y crop offset is specified, since we'd have to move
241 + * data from one block row to another but the virtual array manager doesn't
242 + * guarantee we can touch more than one row at a time. So in that case,
243 + * we have to use a separate destination array.
245 * Some notes about the operating environment of the individual transform
247 * 1. Both the source and destination virtual arrays are allocated from the
249 * and we may as well take that as the effective iMCU size.
250 * 4. When "trim" is in effect, the destination's dimensions will be the
251 * trimmed values but the source's will be untrimmed.
252 - * 5. All the routines assume that the source and destination buffers are
253 + * 5. When "crop" is in effect, the destination's dimensions will be the
254 + * cropped values but the source's will be uncropped. Each transform
255 + * routine is responsible for picking up source data starting at the
256 + * correct X and Y offset for the crop region. (The X and Y offsets
257 + * passed to the transform routines are measured in iMCU blocks of the
259 + * 6. All the routines assume that the source and destination buffers are
260 * padded out to a full iMCU boundary. This is true, although for the
261 * source buffer it is an undocumented property of jdcoefct.c.
262 - * Notes 2,3,4 boil down to this: generally we should use the destination's
263 - * dimensions and ignore the source's.
268 -do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
269 - jvirt_barray_ptr *src_coef_arrays)
270 -/* Horizontal flip; done in-place, so no separate dest array is required */
271 +do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
272 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
273 + jvirt_barray_ptr *src_coef_arrays,
274 + jvirt_barray_ptr *dst_coef_arrays)
275 +/* Crop. This is only used when no rotate/flip is requested with the crop. */
277 + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
279 + JBLOCKARRAY src_buffer, dst_buffer;
280 + jpeg_component_info *compptr;
282 + /* We simply have to copy the right amount of data (the destination's
283 + * image size) starting at the given X and Y offsets in the source.
285 + for (ci = 0; ci < dstinfo->num_components; ci++) {
286 + compptr = dstinfo->comp_info + ci;
287 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
288 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
289 + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
290 + dst_blk_y += compptr->v_samp_factor) {
291 + dst_buffer = (*srcinfo->mem->access_virt_barray)
292 + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
293 + (JDIMENSION) compptr->v_samp_factor, TRUE);
294 + src_buffer = (*srcinfo->mem->access_virt_barray)
295 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
296 + dst_blk_y + y_crop_blocks,
297 + (JDIMENSION) compptr->v_samp_factor, FALSE);
298 + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
299 + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
300 + dst_buffer[offset_y],
301 + compptr->width_in_blocks);
309 +do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
310 + JDIMENSION x_crop_offset,
311 + jvirt_barray_ptr *src_coef_arrays)
312 +/* Horizontal flip; done in-place, so no separate dest array is required.
313 + * NB: this only works when y_crop_offset is zero.
316 - JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
317 + JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
322 * mirroring by changing the signs of odd-numbered columns.
323 * Partial iMCUs at the right edge are left untouched.
325 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
326 + MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
328 for (ci = 0; ci < dstinfo->num_components; ci++) {
329 compptr = dstinfo->comp_info + ci;
330 comp_width = MCU_cols * compptr->h_samp_factor;
331 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
332 for (blk_y = 0; blk_y < compptr->height_in_blocks;
333 blk_y += compptr->v_samp_factor) {
334 buffer = (*srcinfo->mem->access_virt_barray)
335 ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
336 (JDIMENSION) compptr->v_samp_factor, TRUE);
337 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
338 + /* Do the mirroring */
339 for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
340 ptr1 = buffer[offset_y][blk_x];
341 ptr2 = buffer[offset_y][comp_width - blk_x - 1];
346 + if (x_crop_blocks > 0) {
347 + /* Now left-justify the portion of the data to be kept.
348 + * We can't use a single jcopy_block_row() call because that routine
349 + * depends on memcpy(), whose behavior is unspecified for overlapping
350 + * source and destination areas. Sigh.
352 + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
353 + jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
354 + buffer[offset_y] + blk_x,
365 +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
366 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
367 + jvirt_barray_ptr *src_coef_arrays,
368 + jvirt_barray_ptr *dst_coef_arrays)
369 +/* Horizontal flip in general cropping case */
371 + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
372 + JDIMENSION x_crop_blocks, y_crop_blocks;
373 + int ci, k, offset_y;
374 + JBLOCKARRAY src_buffer, dst_buffer;
375 + JBLOCKROW src_row_ptr, dst_row_ptr;
376 + JCOEFPTR src_ptr, dst_ptr;
377 + jpeg_component_info *compptr;
379 + /* Here we must output into a separate array because we can't touch
380 + * different rows of a single virtual array simultaneously. Otherwise,
381 + * this is essentially the same as the routine above.
383 + MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
385 + for (ci = 0; ci < dstinfo->num_components; ci++) {
386 + compptr = dstinfo->comp_info + ci;
387 + comp_width = MCU_cols * compptr->h_samp_factor;
388 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
389 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
390 + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
391 + dst_blk_y += compptr->v_samp_factor) {
392 + dst_buffer = (*srcinfo->mem->access_virt_barray)
393 + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
394 + (JDIMENSION) compptr->v_samp_factor, TRUE);
395 + src_buffer = (*srcinfo->mem->access_virt_barray)
396 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
397 + dst_blk_y + y_crop_blocks,
398 + (JDIMENSION) compptr->v_samp_factor, FALSE);
399 + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
400 + dst_row_ptr = dst_buffer[offset_y];
401 + src_row_ptr = src_buffer[offset_y];
402 + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
403 + if (x_crop_blocks + dst_blk_x < comp_width) {
404 + /* Do the mirrorable blocks */
405 + dst_ptr = dst_row_ptr[dst_blk_x];
406 + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
407 + /* this unrolled loop doesn't need to know which row it's on... */
408 + for (k = 0; k < DCTSIZE2; k += 2) {
409 + *dst_ptr++ = *src_ptr++; /* copy even column */
410 + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
413 + /* Copy last partial block(s) verbatim */
414 + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
415 + dst_row_ptr + dst_blk_x,
422 @@ -113,11 +242,13 @@
425 do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
426 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
427 jvirt_barray_ptr *src_coef_arrays,
428 jvirt_barray_ptr *dst_coef_arrays)
431 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
432 + JDIMENSION x_crop_blocks, y_crop_blocks;
433 int ci, i, j, offset_y;
434 JBLOCKARRAY src_buffer, dst_buffer;
435 JBLOCKROW src_row_ptr, dst_row_ptr;
436 @@ -131,33 +262,38 @@
437 * of odd-numbered rows.
438 * Partial iMCUs at the bottom edge are copied verbatim.
440 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
441 + MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
443 for (ci = 0; ci < dstinfo->num_components; ci++) {
444 compptr = dstinfo->comp_info + ci;
445 comp_height = MCU_rows * compptr->v_samp_factor;
446 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
447 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
448 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
449 dst_blk_y += compptr->v_samp_factor) {
450 dst_buffer = (*srcinfo->mem->access_virt_barray)
451 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
452 (JDIMENSION) compptr->v_samp_factor, TRUE);
453 - if (dst_blk_y < comp_height) {
454 + if (y_crop_blocks + dst_blk_y < comp_height) {
455 /* Row is within the mirrorable area. */
456 src_buffer = (*srcinfo->mem->access_virt_barray)
457 ((j_common_ptr) srcinfo, src_coef_arrays[ci],
458 - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
459 + comp_height - y_crop_blocks - dst_blk_y -
460 + (JDIMENSION) compptr->v_samp_factor,
461 (JDIMENSION) compptr->v_samp_factor, FALSE);
463 /* Bottom-edge blocks will be copied verbatim. */
464 src_buffer = (*srcinfo->mem->access_virt_barray)
465 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
466 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
467 + dst_blk_y + y_crop_blocks,
468 (JDIMENSION) compptr->v_samp_factor, FALSE);
470 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
471 - if (dst_blk_y < comp_height) {
472 + if (y_crop_blocks + dst_blk_y < comp_height) {
473 /* Row is within the mirrorable area. */
474 dst_row_ptr = dst_buffer[offset_y];
475 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
476 + src_row_ptr += x_crop_blocks;
477 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
479 dst_ptr = dst_row_ptr[dst_blk_x];
483 /* Just copy row verbatim. */
484 - jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
485 + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
486 + dst_buffer[offset_y],
487 compptr->width_in_blocks);
490 @@ -184,11 +321,12 @@
493 do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
494 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
495 jvirt_barray_ptr *src_coef_arrays,
496 jvirt_barray_ptr *dst_coef_arrays)
497 /* Transpose source into destination */
499 - JDIMENSION dst_blk_x, dst_blk_y;
500 + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
501 int ci, i, j, offset_x, offset_y;
502 JBLOCKARRAY src_buffer, dst_buffer;
503 JCOEFPTR src_ptr, dst_ptr;
506 for (ci = 0; ci < dstinfo->num_components; ci++) {
507 compptr = dstinfo->comp_info + ci;
508 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
509 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
510 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
511 dst_blk_y += compptr->v_samp_factor) {
512 dst_buffer = (*srcinfo->mem->access_virt_barray)
513 @@ -210,11 +350,12 @@
514 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
515 dst_blk_x += compptr->h_samp_factor) {
516 src_buffer = (*srcinfo->mem->access_virt_barray)
517 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
518 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
519 + dst_blk_x + x_crop_blocks,
520 (JDIMENSION) compptr->h_samp_factor, FALSE);
521 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
522 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
523 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
524 + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
525 for (i = 0; i < DCTSIZE; i++)
526 for (j = 0; j < DCTSIZE; j++)
527 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
531 do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
532 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
533 jvirt_barray_ptr *src_coef_arrays,
534 jvirt_barray_ptr *dst_coef_arrays)
535 /* 90 degree rotation is equivalent to
539 JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
540 + JDIMENSION x_crop_blocks, y_crop_blocks;
541 int ci, i, j, offset_x, offset_y;
542 JBLOCKARRAY src_buffer, dst_buffer;
543 JCOEFPTR src_ptr, dst_ptr;
544 @@ -246,11 +389,13 @@
545 * at the (output) right edge properly. They just get transposed and
548 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
549 + MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE);
551 for (ci = 0; ci < dstinfo->num_components; ci++) {
552 compptr = dstinfo->comp_info + ci;
553 comp_width = MCU_cols * compptr->h_samp_factor;
554 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
555 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
556 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
557 dst_blk_y += compptr->v_samp_factor) {
558 dst_buffer = (*srcinfo->mem->access_virt_barray)
559 @@ -259,15 +404,26 @@
560 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
561 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
562 dst_blk_x += compptr->h_samp_factor) {
563 - src_buffer = (*srcinfo->mem->access_virt_barray)
564 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
565 - (JDIMENSION) compptr->h_samp_factor, FALSE);
566 + if (x_crop_blocks + dst_blk_x < comp_width) {
567 + /* Block is within the mirrorable area. */
568 + src_buffer = (*srcinfo->mem->access_virt_barray)
569 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
570 + comp_width - x_crop_blocks - dst_blk_x -
571 + (JDIMENSION) compptr->h_samp_factor,
572 + (JDIMENSION) compptr->h_samp_factor, FALSE);
574 + /* Edge blocks are transposed but not mirrored. */
575 + src_buffer = (*srcinfo->mem->access_virt_barray)
576 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
577 + dst_blk_x + x_crop_blocks,
578 + (JDIMENSION) compptr->h_samp_factor, FALSE);
580 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
581 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
582 - if (dst_blk_x < comp_width) {
583 + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
584 + if (x_crop_blocks + dst_blk_x < comp_width) {
585 /* Block is within the mirrorable area. */
586 - dst_ptr = dst_buffer[offset_y]
587 - [comp_width - dst_blk_x - offset_x - 1];
588 + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
589 + [dst_blk_y + offset_y + y_crop_blocks];
590 for (i = 0; i < DCTSIZE; i++) {
591 for (j = 0; j < DCTSIZE; j++)
592 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
596 /* Edge blocks are transposed but not mirrored. */
597 - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
598 + src_ptr = src_buffer[offset_x]
599 + [dst_blk_y + offset_y + y_crop_blocks];
600 for (i = 0; i < DCTSIZE; i++)
601 for (j = 0; j < DCTSIZE; j++)
602 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
606 do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
607 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
608 jvirt_barray_ptr *src_coef_arrays,
609 jvirt_barray_ptr *dst_coef_arrays)
610 /* 270 degree rotation is equivalent to
614 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
615 + JDIMENSION x_crop_blocks, y_crop_blocks;
616 int ci, i, j, offset_x, offset_y;
617 JBLOCKARRAY src_buffer, dst_buffer;
618 JCOEFPTR src_ptr, dst_ptr;
619 @@ -310,11 +469,13 @@
620 * at the (output) bottom edge properly. They just get transposed and
623 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
624 + MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE);
626 for (ci = 0; ci < dstinfo->num_components; ci++) {
627 compptr = dstinfo->comp_info + ci;
628 comp_height = MCU_rows * compptr->v_samp_factor;
629 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
630 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
631 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
632 dst_blk_y += compptr->v_samp_factor) {
633 dst_buffer = (*srcinfo->mem->access_virt_barray)
634 @@ -324,14 +485,15 @@
635 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
636 dst_blk_x += compptr->h_samp_factor) {
637 src_buffer = (*srcinfo->mem->access_virt_barray)
638 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
639 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
640 + dst_blk_x + x_crop_blocks,
641 (JDIMENSION) compptr->h_samp_factor, FALSE);
642 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
643 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
644 - if (dst_blk_y < comp_height) {
645 + if (y_crop_blocks + dst_blk_y < comp_height) {
646 /* Block is within the mirrorable area. */
647 src_ptr = src_buffer[offset_x]
648 - [comp_height - dst_blk_y - offset_y - 1];
649 + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
650 for (i = 0; i < DCTSIZE; i++) {
651 for (j = 0; j < DCTSIZE; j++) {
652 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
656 /* Edge blocks are transposed but not mirrored. */
657 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
658 + src_ptr = src_buffer[offset_x]
659 + [dst_blk_y + offset_y + y_crop_blocks];
660 for (i = 0; i < DCTSIZE; i++)
661 for (j = 0; j < DCTSIZE; j++)
662 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
666 do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
667 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
668 jvirt_barray_ptr *src_coef_arrays,
669 jvirt_barray_ptr *dst_coef_arrays)
670 /* 180 degree rotation is equivalent to
671 @@ -365,89 +529,93 @@
674 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
675 + JDIMENSION x_crop_blocks, y_crop_blocks;
676 int ci, i, j, offset_y;
677 JBLOCKARRAY src_buffer, dst_buffer;
678 JBLOCKROW src_row_ptr, dst_row_ptr;
679 JCOEFPTR src_ptr, dst_ptr;
680 jpeg_component_info *compptr;
682 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
683 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
684 + MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
685 + MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
687 for (ci = 0; ci < dstinfo->num_components; ci++) {
688 compptr = dstinfo->comp_info + ci;
689 comp_width = MCU_cols * compptr->h_samp_factor;
690 comp_height = MCU_rows * compptr->v_samp_factor;
691 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
692 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
693 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
694 dst_blk_y += compptr->v_samp_factor) {
695 dst_buffer = (*srcinfo->mem->access_virt_barray)
696 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
697 (JDIMENSION) compptr->v_samp_factor, TRUE);
698 - if (dst_blk_y < comp_height) {
699 + if (y_crop_blocks + dst_blk_y < comp_height) {
700 /* Row is within the vertically mirrorable area. */
701 src_buffer = (*srcinfo->mem->access_virt_barray)
702 ((j_common_ptr) srcinfo, src_coef_arrays[ci],
703 - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
704 + comp_height - y_crop_blocks - dst_blk_y -
705 + (JDIMENSION) compptr->v_samp_factor,
706 (JDIMENSION) compptr->v_samp_factor, FALSE);
708 /* Bottom-edge rows are only mirrored horizontally. */
709 src_buffer = (*srcinfo->mem->access_virt_barray)
710 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
711 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
712 + dst_blk_y + y_crop_blocks,
713 (JDIMENSION) compptr->v_samp_factor, FALSE);
715 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
716 - if (dst_blk_y < comp_height) {
717 + dst_row_ptr = dst_buffer[offset_y];
718 + if (y_crop_blocks + dst_blk_y < comp_height) {
719 /* Row is within the mirrorable area. */
720 - dst_row_ptr = dst_buffer[offset_y];
721 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
722 - /* Process the blocks that can be mirrored both ways. */
723 - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
724 + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
725 dst_ptr = dst_row_ptr[dst_blk_x];
726 - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
727 - for (i = 0; i < DCTSIZE; i += 2) {
728 - /* For even row, negate every odd column. */
729 - for (j = 0; j < DCTSIZE; j += 2) {
730 - *dst_ptr++ = *src_ptr++;
731 - *dst_ptr++ = - *src_ptr++;
732 + if (x_crop_blocks + dst_blk_x < comp_width) {
733 + /* Process the blocks that can be mirrored both ways. */
734 + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
735 + for (i = 0; i < DCTSIZE; i += 2) {
736 + /* For even row, negate every odd column. */
737 + for (j = 0; j < DCTSIZE; j += 2) {
738 + *dst_ptr++ = *src_ptr++;
739 + *dst_ptr++ = - *src_ptr++;
741 + /* For odd row, negate every even column. */
742 + for (j = 0; j < DCTSIZE; j += 2) {
743 + *dst_ptr++ = - *src_ptr++;
744 + *dst_ptr++ = *src_ptr++;
747 - /* For odd row, negate every even column. */
748 - for (j = 0; j < DCTSIZE; j += 2) {
749 - *dst_ptr++ = - *src_ptr++;
750 - *dst_ptr++ = *src_ptr++;
752 + /* Any remaining right-edge blocks are only mirrored vertically. */
753 + src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
754 + for (i = 0; i < DCTSIZE; i += 2) {
755 + for (j = 0; j < DCTSIZE; j++)
756 + *dst_ptr++ = *src_ptr++;
757 + for (j = 0; j < DCTSIZE; j++)
758 + *dst_ptr++ = - *src_ptr++;
762 - /* Any remaining right-edge blocks are only mirrored vertically. */
763 - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
764 - dst_ptr = dst_row_ptr[dst_blk_x];
765 - src_ptr = src_row_ptr[dst_blk_x];
766 - for (i = 0; i < DCTSIZE; i += 2) {
767 - for (j = 0; j < DCTSIZE; j++)
768 - *dst_ptr++ = *src_ptr++;
769 - for (j = 0; j < DCTSIZE; j++)
770 - *dst_ptr++ = - *src_ptr++;
774 /* Remaining rows are just mirrored horizontally. */
775 - dst_row_ptr = dst_buffer[offset_y];
776 src_row_ptr = src_buffer[offset_y];
777 - /* Process the blocks that can be mirrored. */
778 - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
779 - dst_ptr = dst_row_ptr[dst_blk_x];
780 - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
781 - for (i = 0; i < DCTSIZE2; i += 2) {
782 - *dst_ptr++ = *src_ptr++;
783 - *dst_ptr++ = - *src_ptr++;
784 + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
785 + if (x_crop_blocks + dst_blk_x < comp_width) {
786 + /* Process the blocks that can be mirrored. */
787 + dst_ptr = dst_row_ptr[dst_blk_x];
788 + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
789 + for (i = 0; i < DCTSIZE2; i += 2) {
790 + *dst_ptr++ = *src_ptr++;
791 + *dst_ptr++ = - *src_ptr++;
794 + /* Any remaining right-edge blocks are only copied. */
795 + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
796 + dst_row_ptr + dst_blk_x,
800 - /* Any remaining right-edge blocks are only copied. */
801 - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
802 - dst_ptr = dst_row_ptr[dst_blk_x];
803 - src_ptr = src_row_ptr[dst_blk_x];
804 - for (i = 0; i < DCTSIZE2; i++)
805 - *dst_ptr++ = *src_ptr++;
813 do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
814 + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
815 jvirt_barray_ptr *src_coef_arrays,
816 jvirt_barray_ptr *dst_coef_arrays)
817 /* Transverse transpose is equivalent to
818 @@ -470,18 +639,21 @@
821 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
822 + JDIMENSION x_crop_blocks, y_crop_blocks;
823 int ci, i, j, offset_x, offset_y;
824 JBLOCKARRAY src_buffer, dst_buffer;
825 JCOEFPTR src_ptr, dst_ptr;
826 jpeg_component_info *compptr;
828 - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
829 - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
830 + MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE);
831 + MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE);
833 for (ci = 0; ci < dstinfo->num_components; ci++) {
834 compptr = dstinfo->comp_info + ci;
835 comp_width = MCU_cols * compptr->h_samp_factor;
836 comp_height = MCU_rows * compptr->v_samp_factor;
837 + x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
838 + y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
839 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
840 dst_blk_y += compptr->v_samp_factor) {
841 dst_buffer = (*srcinfo->mem->access_virt_barray)
842 @@ -490,17 +662,26 @@
843 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
844 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
845 dst_blk_x += compptr->h_samp_factor) {
846 - src_buffer = (*srcinfo->mem->access_virt_barray)
847 - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
848 - (JDIMENSION) compptr->h_samp_factor, FALSE);
849 + if (x_crop_blocks + dst_blk_x < comp_width) {
850 + /* Block is within the mirrorable area. */
851 + src_buffer = (*srcinfo->mem->access_virt_barray)
852 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
853 + comp_width - x_crop_blocks - dst_blk_x -
854 + (JDIMENSION) compptr->h_samp_factor,
855 + (JDIMENSION) compptr->h_samp_factor, FALSE);
857 + src_buffer = (*srcinfo->mem->access_virt_barray)
858 + ((j_common_ptr) srcinfo, src_coef_arrays[ci],
859 + dst_blk_x + x_crop_blocks,
860 + (JDIMENSION) compptr->h_samp_factor, FALSE);
862 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
863 - if (dst_blk_y < comp_height) {
864 - src_ptr = src_buffer[offset_x]
865 - [comp_height - dst_blk_y - offset_y - 1];
866 - if (dst_blk_x < comp_width) {
867 + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
868 + if (y_crop_blocks + dst_blk_y < comp_height) {
869 + if (x_crop_blocks + dst_blk_x < comp_width) {
870 /* Block is within the mirrorable area. */
871 - dst_ptr = dst_buffer[offset_y]
872 - [comp_width - dst_blk_x - offset_x - 1];
873 + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
874 + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
875 for (i = 0; i < DCTSIZE; i++) {
876 for (j = 0; j < DCTSIZE; j++) {
877 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
881 /* Right-edge blocks are mirrored in y only */
882 - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
883 + src_ptr = src_buffer[offset_x]
884 + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
885 for (i = 0; i < DCTSIZE; i++) {
886 for (j = 0; j < DCTSIZE; j++) {
887 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
888 @@ -526,11 +708,10 @@
892 - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
893 - if (dst_blk_x < comp_width) {
894 + if (x_crop_blocks + dst_blk_x < comp_width) {
895 /* Bottom-edge blocks are mirrored in x only */
896 - dst_ptr = dst_buffer[offset_y]
897 - [comp_width - dst_blk_x - offset_x - 1];
898 + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
899 + [dst_blk_y + offset_y + y_crop_blocks];
900 for (i = 0; i < DCTSIZE; i++) {
901 for (j = 0; j < DCTSIZE; j++)
902 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
906 /* At lower right corner, just transpose, no mirroring */
907 - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
908 + src_ptr = src_buffer[offset_x]
909 + [dst_blk_y + offset_y + y_crop_blocks];
910 for (i = 0; i < DCTSIZE; i++)
911 for (j = 0; j < DCTSIZE; j++)
912 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
913 @@ -554,8 +736,116 @@
917 +/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
918 + * Returns TRUE if valid integer found, FALSE if not.
919 + * *strptr is advanced over the digit string, and *result is set to its value.
923 +jt_read_integer (const char ** strptr, JDIMENSION * result)
925 + const char * ptr = *strptr;
926 + JDIMENSION val = 0;
928 + for (; isdigit(*ptr); ptr++) {
929 + val = val * 10 + (JDIMENSION) (*ptr - '0');
932 + if (ptr == *strptr)
933 + return FALSE; /* oops, no digits */
939 +/* Parse a crop specification (written in X11 geometry style).
940 + * The routine returns TRUE if the spec string is valid, FALSE if not.
942 + * The crop spec string should have the format
943 + * <width>x<height>{+-}<xoffset>{+-}<yoffset>
944 + * where width, height, xoffset, and yoffset are unsigned integers.
945 + * Each of the elements can be omitted to indicate a default value.
946 + * (A weakness of this style is that it is not possible to omit xoffset
947 + * while specifying yoffset, since they look alike.)
949 + * This code is loosely based on XParseGeometry from the X11 distribution.
953 +jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
955 + info->crop = FALSE;
956 + info->crop_width_set = JCROP_UNSET;
957 + info->crop_height_set = JCROP_UNSET;
958 + info->crop_xoffset_set = JCROP_UNSET;
959 + info->crop_yoffset_set = JCROP_UNSET;
961 + if (isdigit(*spec)) {
963 + if (! jt_read_integer(&spec, &info->crop_width))
965 + info->crop_width_set = JCROP_POS;
967 + if (*spec == 'x' || *spec == 'X') {
970 + if (! jt_read_integer(&spec, &info->crop_height))
972 + info->crop_height_set = JCROP_POS;
974 + if (*spec == '+' || *spec == '-') {
975 + /* fetch xoffset */
976 + info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
978 + if (! jt_read_integer(&spec, &info->crop_xoffset))
981 + if (*spec == '+' || *spec == '-') {
982 + /* fetch yoffset */
983 + info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
985 + if (! jt_read_integer(&spec, &info->crop_yoffset))
988 + /* We had better have gotten to the end of the string. */
996 +/* Trim off any partial iMCUs on the indicated destination edge */
999 +trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
1001 + JDIMENSION MCU_cols;
1003 + MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE);
1004 + if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
1005 + full_width / (info->max_h_samp_factor * DCTSIZE))
1006 + info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE);
1010 +trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
1012 + JDIMENSION MCU_rows;
1014 + MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE);
1015 + if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
1016 + full_height / (info->max_v_samp_factor * DCTSIZE))
1017 + info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE);
1021 /* Request any required workspace.
1023 + * This routine figures out the size that the output image will be
1024 + * (which implies that all the transform parameters must be set before
1027 * We allocate the workspace virtual arrays from the source decompression
1028 * object, so that all the arrays (both the original data and the workspace)
1029 * will be taken into account while making memory management decisions.
1030 @@ -569,9 +859,13 @@
1031 jpeg_transform_info *info)
1033 jvirt_barray_ptr *coef_arrays = NULL;
1034 + boolean need_workspace, transpose_it;
1035 jpeg_component_info *compptr;
1037 + JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs;
1038 + JDIMENSION width_in_blocks, height_in_blocks;
1039 + int ci, h_samp_factor, v_samp_factor;
1041 + /* Determine number of components in output image */
1042 if (info->force_grayscale &&
1043 srcinfo->jpeg_color_space == JCS_YCbCr &&
1044 srcinfo->num_components == 3) {
1045 @@ -581,55 +875,181 @@
1046 /* Process all the components */
1047 info->num_components = srcinfo->num_components;
1049 + /* If there is only one output component, force the iMCU size to be 1;
1050 + * else use the source iMCU size. (This allows us to do the right thing
1051 + * when reducing color to grayscale, and also provides a handy way of
1052 + * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
1055 + switch (info->transform) {
1056 + case JXFORM_TRANSPOSE:
1057 + case JXFORM_TRANSVERSE:
1058 + case JXFORM_ROT_90:
1059 + case JXFORM_ROT_270:
1060 + info->output_width = srcinfo->image_height;
1061 + info->output_height = srcinfo->image_width;
1062 + if (info->num_components == 1) {
1063 + info->max_h_samp_factor = 1;
1064 + info->max_v_samp_factor = 1;
1066 + info->max_h_samp_factor = srcinfo->max_v_samp_factor;
1067 + info->max_v_samp_factor = srcinfo->max_h_samp_factor;
1071 + info->output_width = srcinfo->image_width;
1072 + info->output_height = srcinfo->image_height;
1073 + if (info->num_components == 1) {
1074 + info->max_h_samp_factor = 1;
1075 + info->max_v_samp_factor = 1;
1077 + info->max_h_samp_factor = srcinfo->max_h_samp_factor;
1078 + info->max_v_samp_factor = srcinfo->max_v_samp_factor;
1083 + /* If cropping has been requested, compute the crop area's position and
1084 + * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
1087 + /* Insert default values for unset crop parameters */
1088 + if (info->crop_xoffset_set == JCROP_UNSET)
1089 + info->crop_xoffset = 0; /* default to +0 */
1090 + if (info->crop_yoffset_set == JCROP_UNSET)
1091 + info->crop_yoffset = 0; /* default to +0 */
1092 + if (info->crop_xoffset >= info->output_width ||
1093 + info->crop_yoffset >= info->output_height)
1094 + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1095 + if (info->crop_width_set == JCROP_UNSET)
1096 + info->crop_width = info->output_width - info->crop_xoffset;
1097 + if (info->crop_height_set == JCROP_UNSET)
1098 + info->crop_height = info->output_height - info->crop_yoffset;
1099 + /* Ensure parameters are valid */
1100 + if (info->crop_width <= 0 || info->crop_width > info->output_width ||
1101 + info->crop_height <= 0 || info->crop_height > info->output_height ||
1102 + info->crop_xoffset > info->output_width - info->crop_width ||
1103 + info->crop_yoffset > info->output_height - info->crop_height)
1104 + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1105 + /* Convert negative crop offsets into regular offsets */
1106 + if (info->crop_xoffset_set == JCROP_NEG)
1107 + xoffset = info->output_width - info->crop_width - info->crop_xoffset;
1109 + xoffset = info->crop_xoffset;
1110 + if (info->crop_yoffset_set == JCROP_NEG)
1111 + yoffset = info->output_height - info->crop_height - info->crop_yoffset;
1113 + yoffset = info->crop_yoffset;
1114 + /* Now adjust so that upper left corner falls at an iMCU boundary */
1115 + info->output_width =
1116 + info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE));
1117 + info->output_height =
1118 + info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE));
1119 + /* Save x/y offsets measured in iMCUs */
1120 + info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE);
1121 + info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE);
1123 + info->x_crop_offset = 0;
1124 + info->y_crop_offset = 0;
1127 + /* Figure out whether we need workspace arrays,
1128 + * and if so whether they are transposed relative to the source.
1130 + need_workspace = FALSE;
1131 + transpose_it = FALSE;
1132 switch (info->transform) {
1134 + if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1135 + need_workspace = TRUE;
1136 + /* No workspace needed if neither cropping nor transforming */
1139 - /* Don't need a workspace array */
1141 + trim_right_edge(info, srcinfo->image_width);
1142 + if (info->y_crop_offset != 0)
1143 + need_workspace = TRUE;
1144 + /* do_flip_h_no_crop doesn't need a workspace array */
1147 - case JXFORM_ROT_180:
1148 - /* Need workspace arrays having same dimensions as source image.
1149 - * Note that we allocate arrays padded out to the next iMCU boundary,
1150 - * so that transform routines need not worry about missing edge blocks.
1152 - coef_arrays = (jvirt_barray_ptr *)
1153 - (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1154 - SIZEOF(jvirt_barray_ptr) * info->num_components);
1155 - for (ci = 0; ci < info->num_components; ci++) {
1156 - compptr = srcinfo->comp_info + ci;
1157 - coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1158 - ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1159 - (JDIMENSION) jround_up((long) compptr->width_in_blocks,
1160 - (long) compptr->h_samp_factor),
1161 - (JDIMENSION) jround_up((long) compptr->height_in_blocks,
1162 - (long) compptr->v_samp_factor),
1163 - (JDIMENSION) compptr->v_samp_factor);
1166 + trim_bottom_edge(info, srcinfo->image_height);
1167 + /* Need workspace arrays having same dimensions as source image. */
1168 + need_workspace = TRUE;
1170 case JXFORM_TRANSPOSE:
1171 + /* transpose does NOT have to trim anything */
1172 + /* Need workspace arrays having transposed dimensions. */
1173 + need_workspace = TRUE;
1174 + transpose_it = TRUE;
1176 case JXFORM_TRANSVERSE:
1178 + trim_right_edge(info, srcinfo->image_height);
1179 + trim_bottom_edge(info, srcinfo->image_width);
1181 + /* Need workspace arrays having transposed dimensions. */
1182 + need_workspace = TRUE;
1183 + transpose_it = TRUE;
1187 + trim_right_edge(info, srcinfo->image_height);
1188 + /* Need workspace arrays having transposed dimensions. */
1189 + need_workspace = TRUE;
1190 + transpose_it = TRUE;
1192 + case JXFORM_ROT_180:
1194 + trim_right_edge(info, srcinfo->image_width);
1195 + trim_bottom_edge(info, srcinfo->image_height);
1197 + /* Need workspace arrays having same dimensions as source image. */
1198 + need_workspace = TRUE;
1200 case JXFORM_ROT_270:
1201 - /* Need workspace arrays having transposed dimensions.
1202 - * Note that we allocate arrays padded out to the next iMCU boundary,
1203 - * so that transform routines need not worry about missing edge blocks.
1206 + trim_bottom_edge(info, srcinfo->image_width);
1207 + /* Need workspace arrays having transposed dimensions. */
1208 + need_workspace = TRUE;
1209 + transpose_it = TRUE;
1213 + /* Allocate workspace if needed.
1214 + * Note that we allocate arrays padded out to the next iMCU boundary,
1215 + * so that transform routines need not worry about missing edge blocks.
1217 + if (need_workspace) {
1218 coef_arrays = (jvirt_barray_ptr *)
1219 (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1220 - SIZEOF(jvirt_barray_ptr) * info->num_components);
1221 + SIZEOF(jvirt_barray_ptr) * info->num_components);
1222 + width_in_iMCUs = (JDIMENSION)
1223 + jdiv_round_up((long) info->output_width,
1224 + (long) (info->max_h_samp_factor * DCTSIZE));
1225 + height_in_iMCUs = (JDIMENSION)
1226 + jdiv_round_up((long) info->output_height,
1227 + (long) (info->max_v_samp_factor * DCTSIZE));
1228 for (ci = 0; ci < info->num_components; ci++) {
1229 compptr = srcinfo->comp_info + ci;
1230 + if (info->num_components == 1) {
1231 + /* we're going to force samp factors to 1x1 in this case */
1232 + h_samp_factor = v_samp_factor = 1;
1233 + } else if (transpose_it) {
1234 + h_samp_factor = compptr->v_samp_factor;
1235 + v_samp_factor = compptr->h_samp_factor;
1237 + h_samp_factor = compptr->h_samp_factor;
1238 + v_samp_factor = compptr->v_samp_factor;
1240 + width_in_blocks = width_in_iMCUs * h_samp_factor;
1241 + height_in_blocks = height_in_iMCUs * v_samp_factor;
1242 coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1243 ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1244 - (JDIMENSION) jround_up((long) compptr->height_in_blocks,
1245 - (long) compptr->v_samp_factor),
1246 - (JDIMENSION) jround_up((long) compptr->width_in_blocks,
1247 - (long) compptr->h_samp_factor),
1248 - (JDIMENSION) compptr->h_samp_factor);
1249 + width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
1254 info->workspace_coef_arrays = coef_arrays;
1257 @@ -642,14 +1062,8 @@
1258 int tblno, i, j, ci, itemp;
1259 jpeg_component_info *compptr;
1260 JQUANT_TBL *qtblptr;
1264 - /* Transpose basic image dimensions */
1265 - dtemp = dstinfo->image_width;
1266 - dstinfo->image_width = dstinfo->image_height;
1267 - dstinfo->image_height = dtemp;
1269 /* Transpose sampling factors */
1270 for (ci = 0; ci < dstinfo->num_components; ci++) {
1271 compptr = dstinfo->comp_info + ci;
1272 @@ -674,46 +1088,159 @@
1276 -/* Trim off any partial iMCUs on the indicated destination edge */
1277 +/* Adjust Exif image parameters.
1279 + * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1283 -trim_right_edge (j_compress_ptr dstinfo)
1284 +adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
1285 + JDIMENSION new_width, JDIMENSION new_height)
1287 - int ci, max_h_samp_factor;
1288 - JDIMENSION MCU_cols;
1289 + boolean is_motorola; /* Flag for byte order */
1290 + unsigned int number_of_tags, tagnum;
1291 + unsigned int firstoffset, offset;
1292 + JDIMENSION new_value;
1294 + if (length < 12) return; /* Length of an IFD entry */
1296 + /* Discover byte order */
1297 + if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
1298 + is_motorola = FALSE;
1299 + else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
1300 + is_motorola = TRUE;
1304 + /* Check Tag Mark */
1305 + if (is_motorola) {
1306 + if (GETJOCTET(data[2]) != 0) return;
1307 + if (GETJOCTET(data[3]) != 0x2A) return;
1309 + if (GETJOCTET(data[3]) != 0) return;
1310 + if (GETJOCTET(data[2]) != 0x2A) return;
1313 - /* We have to compute max_h_samp_factor ourselves,
1314 - * because it hasn't been set yet in the destination
1315 - * (and we don't want to use the source's value).
1317 - max_h_samp_factor = 1;
1318 - for (ci = 0; ci < dstinfo->num_components; ci++) {
1319 - int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor;
1320 - max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor);
1321 + /* Get first IFD offset (offset to IFD0) */
1322 + if (is_motorola) {
1323 + if (GETJOCTET(data[4]) != 0) return;
1324 + if (GETJOCTET(data[5]) != 0) return;
1325 + firstoffset = GETJOCTET(data[6]);
1326 + firstoffset <<= 8;
1327 + firstoffset += GETJOCTET(data[7]);
1329 + if (GETJOCTET(data[7]) != 0) return;
1330 + if (GETJOCTET(data[6]) != 0) return;
1331 + firstoffset = GETJOCTET(data[5]);
1332 + firstoffset <<= 8;
1333 + firstoffset += GETJOCTET(data[4]);
1335 - MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE);
1336 - if (MCU_cols > 0) /* can't trim to 0 pixels */
1337 - dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE);
1339 + if (firstoffset > length - 2) return; /* check end of data segment */
1342 -trim_bottom_edge (j_compress_ptr dstinfo)
1344 - int ci, max_v_samp_factor;
1345 - JDIMENSION MCU_rows;
1346 + /* Get the number of directory entries contained in this IFD */
1347 + if (is_motorola) {
1348 + number_of_tags = GETJOCTET(data[firstoffset]);
1349 + number_of_tags <<= 8;
1350 + number_of_tags += GETJOCTET(data[firstoffset+1]);
1352 + number_of_tags = GETJOCTET(data[firstoffset+1]);
1353 + number_of_tags <<= 8;
1354 + number_of_tags += GETJOCTET(data[firstoffset]);
1356 + if (number_of_tags == 0) return;
1359 - /* We have to compute max_v_samp_factor ourselves,
1360 - * because it hasn't been set yet in the destination
1361 - * (and we don't want to use the source's value).
1363 - max_v_samp_factor = 1;
1364 - for (ci = 0; ci < dstinfo->num_components; ci++) {
1365 - int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor;
1366 - max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor);
1367 + /* Search for ExifSubIFD offset Tag in IFD0 */
1369 + if (firstoffset > length - 12) return; /* check end of data segment */
1370 + /* Get Tag number */
1371 + if (is_motorola) {
1372 + tagnum = GETJOCTET(data[firstoffset]);
1374 + tagnum += GETJOCTET(data[firstoffset+1]);
1376 + tagnum = GETJOCTET(data[firstoffset+1]);
1378 + tagnum += GETJOCTET(data[firstoffset]);
1380 + if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1381 + if (--number_of_tags == 0) return;
1382 + firstoffset += 12;
1384 - MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE);
1385 - if (MCU_rows > 0) /* can't trim to 0 pixels */
1386 - dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE);
1388 + /* Get the ExifSubIFD offset */
1389 + if (is_motorola) {
1390 + if (GETJOCTET(data[firstoffset+8]) != 0) return;
1391 + if (GETJOCTET(data[firstoffset+9]) != 0) return;
1392 + offset = GETJOCTET(data[firstoffset+10]);
1394 + offset += GETJOCTET(data[firstoffset+11]);
1396 + if (GETJOCTET(data[firstoffset+11]) != 0) return;
1397 + if (GETJOCTET(data[firstoffset+10]) != 0) return;
1398 + offset = GETJOCTET(data[firstoffset+9]);
1400 + offset += GETJOCTET(data[firstoffset+8]);
1402 + if (offset > length - 2) return; /* check end of data segment */
1404 + /* Get the number of directory entries contained in this SubIFD */
1405 + if (is_motorola) {
1406 + number_of_tags = GETJOCTET(data[offset]);
1407 + number_of_tags <<= 8;
1408 + number_of_tags += GETJOCTET(data[offset+1]);
1410 + number_of_tags = GETJOCTET(data[offset+1]);
1411 + number_of_tags <<= 8;
1412 + number_of_tags += GETJOCTET(data[offset]);
1414 + if (number_of_tags < 2) return;
1417 + /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1419 + if (offset > length - 12) return; /* check end of data segment */
1420 + /* Get Tag number */
1421 + if (is_motorola) {
1422 + tagnum = GETJOCTET(data[offset]);
1424 + tagnum += GETJOCTET(data[offset+1]);
1426 + tagnum = GETJOCTET(data[offset+1]);
1428 + tagnum += GETJOCTET(data[offset]);
1430 + if (tagnum == 0xA002 || tagnum == 0xA003) {
1431 + if (tagnum == 0xA002)
1432 + new_value = new_width; /* ExifImageWidth Tag */
1434 + new_value = new_height; /* ExifImageHeight Tag */
1435 + if (is_motorola) {
1436 + data[offset+2] = 0; /* Format = unsigned long (4 octets) */
1437 + data[offset+3] = 4;
1438 + data[offset+4] = 0; /* Number Of Components = 1 */
1439 + data[offset+5] = 0;
1440 + data[offset+6] = 0;
1441 + data[offset+7] = 1;
1442 + data[offset+8] = 0;
1443 + data[offset+9] = 0;
1444 + data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
1445 + data[offset+11] = (JOCTET)(new_value & 0xFF);
1447 + data[offset+2] = 4; /* Format = unsigned long (4 octets) */
1448 + data[offset+3] = 0;
1449 + data[offset+4] = 1; /* Number Of Components = 1 */
1450 + data[offset+5] = 0;
1451 + data[offset+6] = 0;
1452 + data[offset+7] = 0;
1453 + data[offset+8] = (JOCTET)(new_value & 0xFF);
1454 + data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
1455 + data[offset+10] = 0;
1456 + data[offset+11] = 0;
1460 + } while (--number_of_tags);
1464 @@ -736,18 +1263,22 @@
1466 /* If force-to-grayscale is requested, adjust destination parameters */
1467 if (info->force_grayscale) {
1468 - /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1469 - * properly. Among other things, the target h_samp_factor & v_samp_factor
1470 - * will get set to 1, which typically won't match the source.
1471 - * In fact we do this even if the source is already grayscale; that
1472 - * provides an easy way of coercing a grayscale JPEG with funny sampling
1473 - * factors to the customary 1,1. (Some decoders fail on other factors.)
1474 + /* First, ensure we have YCbCr or grayscale data, and that the source's
1475 + * Y channel is full resolution. (No reasonable person would make Y
1476 + * be less than full resolution, so actually coping with that case
1477 + * isn't worth extra code space. But we check it to avoid crashing.)
1479 - if ((dstinfo->jpeg_color_space == JCS_YCbCr &&
1480 - dstinfo->num_components == 3) ||
1481 - (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1482 - dstinfo->num_components == 1)) {
1483 - /* We have to preserve the source's quantization table number. */
1484 + if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
1485 + dstinfo->num_components == 3) ||
1486 + (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1487 + dstinfo->num_components == 1)) &&
1488 + srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
1489 + srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
1490 + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1491 + * properly. Among other things, it sets the target h_samp_factor &
1492 + * v_samp_factor to 1, which typically won't match the source.
1493 + * We have to preserve the source's quantization table number, however.
1495 int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
1496 jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
1497 dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
1498 @@ -755,50 +1286,52 @@
1499 /* Sorry, can't do it */
1500 ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
1502 + } else if (info->num_components == 1) {
1503 + /* For a single-component source, we force the destination sampling factors
1504 + * to 1x1, with or without force_grayscale. This is useful because some
1505 + * decoders choke on grayscale images with other sampling factors.
1507 + dstinfo->comp_info[0].h_samp_factor = 1;
1508 + dstinfo->comp_info[0].v_samp_factor = 1;
1511 - /* Correct the destination's image dimensions etc if necessary */
1512 + /* Correct the destination's image dimensions as necessary
1513 + * for crop and rotate/flip operations.
1515 + dstinfo->image_width = info->output_width;
1516 + dstinfo->image_height = info->output_height;
1518 + /* Transpose destination image parameters */
1519 switch (info->transform) {
1521 - /* Nothing to do */
1523 - case JXFORM_FLIP_H:
1525 - trim_right_edge(dstinfo);
1527 - case JXFORM_FLIP_V:
1529 - trim_bottom_edge(dstinfo);
1531 case JXFORM_TRANSPOSE:
1532 - transpose_critical_parameters(dstinfo);
1533 - /* transpose does NOT have to trim anything */
1535 case JXFORM_TRANSVERSE:
1536 - transpose_critical_parameters(dstinfo);
1538 - trim_right_edge(dstinfo);
1539 - trim_bottom_edge(dstinfo);
1543 - transpose_critical_parameters(dstinfo);
1545 - trim_right_edge(dstinfo);
1547 - case JXFORM_ROT_180:
1549 - trim_right_edge(dstinfo);
1550 - trim_bottom_edge(dstinfo);
1553 case JXFORM_ROT_270:
1554 transpose_critical_parameters(dstinfo);
1556 - trim_bottom_edge(dstinfo);
1560 + /* Adjust Exif properties */
1561 + if (srcinfo->marker_list != NULL &&
1562 + srcinfo->marker_list->marker == JPEG_APP0+1 &&
1563 + srcinfo->marker_list->data_length >= 6 &&
1564 + GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
1565 + GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
1566 + GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
1567 + GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
1568 + GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
1569 + GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
1570 + /* Suppress output of JFIF marker */
1571 + dstinfo->write_JFIF_header = FALSE;
1572 + /* Adjust Exif image parameters */
1573 + if (dstinfo->image_width != srcinfo->image_width ||
1574 + dstinfo->image_height != srcinfo->image_height)
1575 + /* Align data segment to start of TIFF structure for parsing */
1576 + adjust_exif_parameters(srcinfo->marker_list->data + 6,
1577 + srcinfo->marker_list->data_length - 6,
1578 + dstinfo->image_width, dstinfo->image_height);
1581 /* Return the appropriate output data set */
1582 if (info->workspace_coef_arrays != NULL)
1583 return info->workspace_coef_arrays;
1584 @@ -816,40 +1349,108 @@
1588 -jtransform_execute_transformation (j_decompress_ptr srcinfo,
1589 - j_compress_ptr dstinfo,
1590 - jvirt_barray_ptr *src_coef_arrays,
1591 - jpeg_transform_info *info)
1592 +jtransform_execute_transform (j_decompress_ptr srcinfo,
1593 + j_compress_ptr dstinfo,
1594 + jvirt_barray_ptr *src_coef_arrays,
1595 + jpeg_transform_info *info)
1597 jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
1599 + /* Note: conditions tested here should match those in switch statement
1600 + * in jtransform_request_workspace()
1602 switch (info->transform) {
1604 + if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1605 + do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1606 + src_coef_arrays, dst_coef_arrays);
1609 - do_flip_h(srcinfo, dstinfo, src_coef_arrays);
1610 + if (info->y_crop_offset != 0)
1611 + do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1612 + src_coef_arrays, dst_coef_arrays);
1614 + do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
1618 - do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1619 + do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1620 + src_coef_arrays, dst_coef_arrays);
1622 case JXFORM_TRANSPOSE:
1623 - do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1624 + do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1625 + src_coef_arrays, dst_coef_arrays);
1627 case JXFORM_TRANSVERSE:
1628 - do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1629 + do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1630 + src_coef_arrays, dst_coef_arrays);
1633 - do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1634 + do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1635 + src_coef_arrays, dst_coef_arrays);
1637 case JXFORM_ROT_180:
1638 - do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1639 + do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1640 + src_coef_arrays, dst_coef_arrays);
1642 case JXFORM_ROT_270:
1643 - do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
1644 + do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1645 + src_coef_arrays, dst_coef_arrays);
1650 +/* jtransform_perfect_transform
1652 + * Determine whether lossless transformation is perfectly
1653 + * possible for a specified image and transformation.
1656 + * image_width, image_height: source image dimensions.
1657 + * MCU_width, MCU_height: pixel dimensions of MCU.
1658 + * transform: transformation identifier.
1659 + * Parameter sources from initialized jpeg_struct
1660 + * (after reading source header):
1661 + * image_width = cinfo.image_width
1662 + * image_height = cinfo.image_height
1663 + * MCU_width = cinfo.max_h_samp_factor * DCTSIZE
1664 + * MCU_height = cinfo.max_v_samp_factor * DCTSIZE
1666 + * TRUE = perfect transformation possible
1667 + * FALSE = perfect transformation not possible
1668 + * (may use custom action then)
1672 +jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
1673 + int MCU_width, int MCU_height,
1674 + JXFORM_CODE transform)
1676 + boolean result = TRUE; /* initialize TRUE */
1678 + switch (transform) {
1679 + case JXFORM_FLIP_H:
1680 + case JXFORM_ROT_270:
1681 + if (image_width % (JDIMENSION) MCU_width)
1684 + case JXFORM_FLIP_V:
1685 + case JXFORM_ROT_90:
1686 + if (image_height % (JDIMENSION) MCU_height)
1689 + case JXFORM_TRANSVERSE:
1690 + case JXFORM_ROT_180:
1691 + if (image_width % (JDIMENSION) MCU_width)
1693 + if (image_height % (JDIMENSION) MCU_height)
1701 #endif /* TRANSFORMS_SUPPORTED */
1704 diff -Nur jpeg-6b.orig/transupp.h jpeg-6b/transupp.h
1705 --- jpeg-6b.orig/transupp.h 1997-07-24 04:39:12.000000000 +0200
1706 +++ jpeg-6b/transupp.h 2003-09-21 22:53:08.000000000 +0200
1711 - * Copyright (C) 1997, Thomas G. Lane.
1712 + * Copyright (C) 1997-2001, Thomas G. Lane.
1713 * This file is part of the Independent JPEG Group's software.
1714 * For conditions of distribution and use, see the accompanying README file.
1717 #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */
1720 -/* Short forms of external names for systems with brain-damaged linkers. */
1722 -#ifdef NEED_SHORT_EXTERNAL_NAMES
1723 -#define jtransform_request_workspace jTrRequest
1724 -#define jtransform_adjust_parameters jTrAdjust
1725 -#define jtransform_execute_transformation jTrExec
1726 -#define jcopy_markers_setup jCMrkSetup
1727 -#define jcopy_markers_execute jCMrkExec
1728 -#endif /* NEED_SHORT_EXTERNAL_NAMES */
1732 - * Codes for supported types of image transformations.
1736 - JXFORM_NONE, /* no transformation */
1737 - JXFORM_FLIP_H, /* horizontal flip */
1738 - JXFORM_FLIP_V, /* vertical flip */
1739 - JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */
1740 - JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
1741 - JXFORM_ROT_90, /* 90-degree clockwise rotation */
1742 - JXFORM_ROT_180, /* 180-degree rotation */
1743 - JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */
1747 * Although rotating and flipping data expressed as DCT coefficients is not
1748 * hard, there is an asymmetry in the JPEG format specification for images
1750 * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
1751 * followed by -rot 180 -trim trims both edges.)
1753 + * We also offer a lossless-crop option, which discards data outside a given
1754 + * image region but losslessly preserves what is inside. Like the rotate and
1755 + * flip transforms, lossless crop is restricted by the JPEG format: the upper
1756 + * left corner of the selected region must fall on an iMCU boundary. If this
1757 + * does not hold for the given crop parameters, we silently move the upper left
1758 + * corner up and/or left to make it so, simultaneously increasing the region
1759 + * dimensions to keep the lower right crop corner unchanged. (Thus, the
1760 + * output image covers at least the requested region, but may cover more.)
1762 + * If both crop and a rotate/flip transform are requested, the crop is applied
1763 + * last --- that is, the crop region is specified in terms of the destination
1766 * We also offer a "force to grayscale" option, which simply discards the
1767 * chrominance channels of a YCbCr image. This is lossless in the sense that
1768 * the luminance channel is preserved exactly. It's not the same kind of
1770 * be aware of the option to know how many components to work on.
1774 +/* Short forms of external names for systems with brain-damaged linkers. */
1776 +#ifdef NEED_SHORT_EXTERNAL_NAMES
1777 +#define jtransform_parse_crop_spec jTrParCrop
1778 +#define jtransform_request_workspace jTrRequest
1779 +#define jtransform_adjust_parameters jTrAdjust
1780 +#define jtransform_execute_transform jTrExec
1781 +#define jtransform_perfect_transform jTrPerfect
1782 +#define jcopy_markers_setup jCMrkSetup
1783 +#define jcopy_markers_execute jCMrkExec
1784 +#endif /* NEED_SHORT_EXTERNAL_NAMES */
1788 + * Codes for supported types of image transformations.
1792 + JXFORM_NONE, /* no transformation */
1793 + JXFORM_FLIP_H, /* horizontal flip */
1794 + JXFORM_FLIP_V, /* vertical flip */
1795 + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */
1796 + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
1797 + JXFORM_ROT_90, /* 90-degree clockwise rotation */
1798 + JXFORM_ROT_180, /* 180-degree rotation */
1799 + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */
1803 + * Codes for crop parameters, which can individually be unspecified,
1804 + * positive, or negative. (Negative width or height makes no sense, though.)
1814 + * Transform parameters struct.
1815 + * NB: application must not change any elements of this struct after
1816 + * calling jtransform_request_workspace.
1820 /* Options: set by caller */
1821 JXFORM_CODE transform; /* image transform operator */
1822 + boolean perfect; /* if TRUE, fail if partial MCUs are requested */
1823 boolean trim; /* if TRUE, trim partial MCUs as needed */
1824 boolean force_grayscale; /* if TRUE, convert color image to grayscale */
1825 + boolean crop; /* if TRUE, crop source image */
1827 + /* Crop parameters: application need not set these unless crop is TRUE.
1828 + * These can be filled in by jtransform_parse_crop_spec().
1830 + JDIMENSION crop_width; /* Width of selected region */
1831 + JCROP_CODE crop_width_set;
1832 + JDIMENSION crop_height; /* Height of selected region */
1833 + JCROP_CODE crop_height_set;
1834 + JDIMENSION crop_xoffset; /* X offset of selected region */
1835 + JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */
1836 + JDIMENSION crop_yoffset; /* Y offset of selected region */
1837 + JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */
1839 /* Internal workspace: caller should not touch these */
1840 int num_components; /* # of components in workspace */
1841 jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */
1842 + JDIMENSION output_width; /* cropped destination dimensions */
1843 + JDIMENSION output_height;
1844 + JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */
1845 + JDIMENSION y_crop_offset;
1846 + int max_h_samp_factor; /* destination iMCU size */
1847 + int max_v_samp_factor;
1848 } jpeg_transform_info;
1851 #if TRANSFORMS_SUPPORTED
1853 +/* Parse a crop specification (written in X11 geometry style) */
1854 +EXTERN(boolean) jtransform_parse_crop_spec
1855 + JPP((jpeg_transform_info *info, const char *spec));
1856 /* Request any required workspace */
1857 EXTERN(void) jtransform_request_workspace
1858 JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));
1859 @@ -106,10 +162,24 @@
1860 jvirt_barray_ptr *src_coef_arrays,
1861 jpeg_transform_info *info));
1862 /* Execute the actual transformation, if any */
1863 -EXTERN(void) jtransform_execute_transformation
1864 +EXTERN(void) jtransform_execute_transform
1865 JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1866 jvirt_barray_ptr *src_coef_arrays,
1867 jpeg_transform_info *info));
1868 +/* Determine whether lossless transformation is perfectly
1869 + * possible for a specified image and transformation.
1871 +EXTERN(boolean) jtransform_perfect_transform
1872 + JPP((JDIMENSION image_width, JDIMENSION image_height,
1873 + int MCU_width, int MCU_height,
1874 + JXFORM_CODE transform));
1876 +/* jtransform_execute_transform used to be called
1877 + * jtransform_execute_transformation, but some compilers complain about
1878 + * routine names that long. This macro is here to avoid breaking any
1879 + * old source code that uses the original name...
1881 +#define jtransform_execute_transformation jtransform_execute_transform
1883 #endif /* TRANSFORMS_SUPPORTED */