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