]> git.pld-linux.org Git - packages/libjpeg.git/blob - libjpeg-crop.patch
- croppatch in diff form
[packages/libjpeg.git] / libjpeg-crop.patch
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
4 @@ -45,6 +45,7 @@
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
15 @@ -1,7 +1,7 @@
16  /*
17   * jpegtran.c
18   *
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.
23   *
24 @@ -64,8 +64,10 @@
25  #endif
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");
35 @@ -133,7 +135,9 @@
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;
43  
44    /* Scan command line options, adjust parameters */
45 @@ -160,7 +164,7 @@
46        exit(EXIT_FAILURE);
47  #endif
48  
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 */
53         usage();
54 @@ -173,6 +177,20 @@
55        } else
56         usage();
57  
58 +    } else if (keymatch(arg, "crop", 2)) {
59 +      /* Perform lossless cropping. */
60 +#if TRANSFORMS_SUPPORTED
61 +      if (++argn >= argc)      /* advance to next argument */
62 +       usage();
63 +      if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
64 +       fprintf(stderr, "%s: bogus -crop argument '%s'\n",
65 +               progname, argv[argn]);
66 +       exit(EXIT_FAILURE);
67 +      }
68 +#else
69 +      select_transform(JXFORM_NONE);   /* force an error */
70 +#endif
71 +
72      } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
73        /* Enable debug printouts. */
74        /* On first -d, print version identification */
75 @@ -233,7 +251,12 @@
76         usage();
77        outfilename = argv[argn];        /* save it away for later use */
78  
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
82 +       * handle. */
83 +      transformoption.perfect = TRUE;
84 +
85 +    } else if (keymatch(arg, "progressive", 2)) {
86        /* Select simple progressive mode. */
87  #ifdef C_PROGRESSIVE_SUPPORTED
88        simple_progressive = TRUE;
89 @@ -342,8 +365,10 @@
90    jvirt_barray_ptr * src_coef_arrays;
91    jvirt_barray_ptr * dst_coef_arrays;
92    int file_index;
93 -  FILE * input_file;
94 -  FILE * output_file;
95 +  /* We assume all-in-memory processing and can therefore use only a
96 +   * single file pointer for sequential input and output operation. 
97 +   */
98 +  FILE * fp;
99  
100    /* On Mac, fetch a command line. */
101  #ifdef USE_CCOMMAND
102 @@ -406,24 +431,13 @@
103  
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]);
110        exit(EXIT_FAILURE);
111      }
112    } else {
113      /* default input file is stdin */
114 -    input_file = read_stdin();
115 -  }
116 -
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);
122 -    }
123 -  } else {
124 -    /* default output file is stdout */
125 -    output_file = write_stdout();
126 +    fp = read_stdin();
127    }
128  
129  #ifdef PROGRESS_REPORT
130 @@ -431,7 +445,7 @@
131  #endif
132  
133    /* Specify data source for decompression */
134 -  jpeg_stdio_src(&srcinfo, input_file);
135 +  jpeg_stdio_src(&srcinfo, fp);
136  
137    /* Enable saving of extra markers that we want to copy */
138    jcopy_markers_setup(&srcinfo, copyoption);
139 @@ -443,6 +457,15 @@
140     * jpeg_read_coefficients so that memory allocation will be done right.
141     */
142  #if TRANSFORMS_SUPPORTED
143 +  /* Fails right away if -perfect is given and transformation is not perfect.
144 +   */
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);
151 +  }
152    jtransform_request_workspace(&srcinfo, &transformoption);
153  #endif
154  
155 @@ -463,11 +486,32 @@
156    dst_coef_arrays = src_coef_arrays;
157  #endif
158  
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.
165 +   */
166 +  if (fp != stdin)
167 +    fclose(fp);
168 +
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);
174 +    }
175 +  } else {
176 +    /* default output file is stdout */
177 +    fp = write_stdout();
178 +  }
179 +
180    /* Adjust default compression parameters by re-parsing the options */
181    file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
182  
183    /* Specify data destination for compression */
184 -  jpeg_stdio_dest(&dstinfo, output_file);
185 +  jpeg_stdio_dest(&dstinfo, fp);
186  
187    /* Start compressor (note no image data is actually written here) */
188    jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
189 @@ -488,11 +532,9 @@
190    (void) jpeg_finish_decompress(&srcinfo);
191    jpeg_destroy_decompress(&srcinfo);
192  
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 */
199 +  if (fp != stdout)
200 +    fclose(fp);
201  
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
207 @@ -1,7 +1,7 @@
208  /*
209   * transupp.c
210   *
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.
215   *
216 @@ -20,6 +20,7 @@
217  #include "jinclude.h"
218  #include "jpeglib.h"
219  #include "transupp.h"          /* My own external interface */
220 +#include <ctype.h>             /* to declare isdigit() */
221  
222  
223  #if TRANSFORMS_SUPPORTED
224 @@ -28,7 +29,8 @@
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.
231   *
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
234 @@ -42,6 +44,13 @@
235   * arrays for most of the transforms.  That could result in much thrashing
236   * if the image is larger than main memory.
237   *
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.
244 + *
245   * Some notes about the operating environment of the individual transform
246   * routines:
247   * 1. Both the source and destination virtual arrays are allocated from the
248 @@ -54,20 +63,65 @@
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
258 + *    destination.)
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.
264   */
265  
266  
267  LOCAL(void)
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. */
276 +{
277 +  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
278 +  int ci, offset_y;
279 +  JBLOCKARRAY src_buffer, dst_buffer;
280 +  jpeg_component_info *compptr;
281 +
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.
284 +   */
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);
302 +      }
303 +    }
304 +  }
305 +}
306 +
307 +
308 +LOCAL(void)
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.
314 + */
315  {
316 -  JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
317 +  JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
318    int ci, k, offset_y;
319    JBLOCKARRAY buffer;
320    JCOEFPTR ptr1, ptr2;
321 @@ -79,17 +133,19 @@
322     * mirroring by changing the signs of odd-numbered columns.
323     * Partial iMCUs at the right edge are left untouched.
324     */
325 -  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
326 +  MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
327  
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];
342 @@ -105,6 +161,79 @@
343             *ptr2++ = -temp1;
344           }
345         }
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.
351 +          */
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,
355 +                           (JDIMENSION) 1);
356 +         }
357 +       }
358 +      }
359 +    }
360 +  }
361 +}
362 +
363 +
364 +LOCAL(void)
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 */
370 +{
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;
378 +
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.
382 +   */
383 +  MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
384 +
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 */
411 +           }
412 +         } else {
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,
416 +                           (JDIMENSION) 1);
417 +         }
418 +       }
419        }
420      }
421    }
422 @@ -113,11 +242,13 @@
423  
424  LOCAL(void)
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)
429  /* Vertical flip */
430  {
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.
439     */
440 -  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
441 +  MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
442  
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);
462        } else {
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);
469        }
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;
478                dst_blk_x++) {
479             dst_ptr = dst_row_ptr[dst_blk_x];
480 @@ -173,7 +309,8 @@
481           }
482         } else {
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);
488         }
489        }
490 @@ -184,11 +321,12 @@
491  
492  LOCAL(void)
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 */
498  {
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;
504 @@ -201,6 +339,8 @@
505     */
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];
528 @@ -228,6 +369,7 @@
529  
530  LOCAL(void)
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
536 @@ -237,6 +379,7 @@
537   */
538  {
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
546     * not mirrored.
547     */
548 -  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
549 +  MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE);
550  
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);
573 +         } else {
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);
579 +         }
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];
593 @@ -277,7 +433,8 @@
594               }
595             } else {
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];
603 @@ -292,6 +449,7 @@
604  
605  LOCAL(void)
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
611 @@ -301,6 +459,7 @@
612   */
613  {
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
621     * not mirrored.
622     */
623 -  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
624 +  MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE);
625  
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];
653 @@ -341,7 +503,8 @@
654               }
655             } else {
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];
663 @@ -356,6 +519,7 @@
664  
665  LOCAL(void)
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 @@
672   */
673  {
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;
681  
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);
686  
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);
707        } else {
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);
714        }
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++;
740 +               }
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++;
745 +               }
746               }
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++;
751 +           } else {
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++;
759               }
760             }
761           }
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++;
771 -           }
772 -         }
773         } else {
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++;
792 +             }
793 +           } else {
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,
797 +                             (JDIMENSION) 1);
798             }
799           }
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++;
806 -         }
807         }
808        }
809      }
810 @@ -457,6 +625,7 @@
811  
812  LOCAL(void)
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 @@
819   */
820  {
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;
827  
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);
832  
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);
856 +         } else {
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);
861 +         }
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];
878 @@ -516,7 +697,8 @@
879                 }
880               } else {
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 @@
889                 }
890               }
891             } else {
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];
903 @@ -540,7 +721,8 @@
904                 }
905               } else {
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 @@
914  }
915  
916  
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.
920 + */
921 +
922 +LOCAL(boolean)
923 +jt_read_integer (const char ** strptr, JDIMENSION * result)
924 +{
925 +  const char * ptr = *strptr;
926 +  JDIMENSION val = 0;
927 +
928 +  for (; isdigit(*ptr); ptr++) {
929 +    val = val * 10 + (JDIMENSION) (*ptr - '0');
930 +  }
931 +  *result = val;
932 +  if (ptr == *strptr)
933 +    return FALSE;              /* oops, no digits */
934 +  *strptr = ptr;
935 +  return TRUE;
936 +}
937 +
938 +
939 +/* Parse a crop specification (written in X11 geometry style).
940 + * The routine returns TRUE if the spec string is valid, FALSE if not.
941 + *
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.)
948 + *
949 + * This code is loosely based on XParseGeometry from the X11 distribution.
950 + */
951 +
952 +GLOBAL(boolean)
953 +jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
954 +{
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;
960 +
961 +  if (isdigit(*spec)) {
962 +    /* fetch width */
963 +    if (! jt_read_integer(&spec, &info->crop_width))
964 +      return FALSE;
965 +    info->crop_width_set = JCROP_POS;
966 +  }
967 +  if (*spec == 'x' || *spec == 'X') {  
968 +    /* fetch height */
969 +    spec++;
970 +    if (! jt_read_integer(&spec, &info->crop_height))
971 +      return FALSE;
972 +    info->crop_height_set = JCROP_POS;
973 +  }
974 +  if (*spec == '+' || *spec == '-') {
975 +    /* fetch xoffset */
976 +    info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
977 +    spec++;
978 +    if (! jt_read_integer(&spec, &info->crop_xoffset))
979 +      return FALSE;
980 +  }
981 +  if (*spec == '+' || *spec == '-') {
982 +    /* fetch yoffset */
983 +    info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
984 +    spec++;
985 +    if (! jt_read_integer(&spec, &info->crop_yoffset))
986 +      return FALSE;
987 +  }
988 +  /* We had better have gotten to the end of the string. */
989 +  if (*spec != '\0')
990 +    return FALSE;
991 +  info->crop = TRUE;
992 +  return TRUE;
993 +}
994 +
995 +
996 +/* Trim off any partial iMCUs on the indicated destination edge */
997 +
998 +LOCAL(void)
999 +trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
1000 +{
1001 +  JDIMENSION MCU_cols;
1002 +
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);
1007 +}
1008 +
1009 +LOCAL(void)
1010 +trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
1011 +{
1012 +  JDIMENSION MCU_rows;
1013 +
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);
1018 +}
1019 +
1020 +
1021  /* Request any required workspace.
1022   *
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
1025 + * it is called).
1026 + *
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)
1032  {
1033    jvirt_barray_ptr *coef_arrays = NULL;
1034 +  boolean need_workspace, transpose_it;
1035    jpeg_component_info *compptr;
1036 -  int ci;
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;
1040  
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;
1048    }
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.)
1053 +   */
1054 +
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;
1065 +    } else {
1066 +      info->max_h_samp_factor = srcinfo->max_v_samp_factor;
1067 +      info->max_v_samp_factor = srcinfo->max_h_samp_factor;
1068 +    }
1069 +    break;
1070 +  default:
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;
1076 +    } else {
1077 +      info->max_h_samp_factor = srcinfo->max_h_samp_factor;
1078 +      info->max_v_samp_factor = srcinfo->max_v_samp_factor;
1079 +    }
1080 +    break;
1081 +  }
1082 +
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.
1085 +   */
1086 +  if (info->crop) {
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;
1108 +    else
1109 +      xoffset = info->crop_xoffset;
1110 +    if (info->crop_yoffset_set == JCROP_NEG)
1111 +      yoffset = info->output_height - info->crop_height - info->crop_yoffset;
1112 +    else
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);
1122 +  } else {
1123 +    info->x_crop_offset = 0;
1124 +    info->y_crop_offset = 0;
1125 +  }
1126  
1127 +  /* Figure out whether we need workspace arrays,
1128 +   * and if so whether they are transposed relative to the source.
1129 +   */
1130 +  need_workspace = FALSE;
1131 +  transpose_it = FALSE;
1132    switch (info->transform) {
1133    case JXFORM_NONE:
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 */
1137 +    break;
1138    case JXFORM_FLIP_H:
1139 -    /* Don't need a workspace array */
1140 +    if (info->trim)
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 */
1145      break;
1146    case JXFORM_FLIP_V:
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.
1151 -     */
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);
1164 -    }
1165 +    if (info->trim)
1166 +      trim_bottom_edge(info, srcinfo->image_height);
1167 +    /* Need workspace arrays having same dimensions as source image. */
1168 +    need_workspace = TRUE;
1169      break;
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;
1175 +    break;
1176    case JXFORM_TRANSVERSE:
1177 +    if (info->trim) {
1178 +      trim_right_edge(info, srcinfo->image_height);
1179 +      trim_bottom_edge(info, srcinfo->image_width);
1180 +    }
1181 +    /* Need workspace arrays having transposed dimensions. */
1182 +    need_workspace = TRUE;
1183 +    transpose_it = TRUE;
1184 +    break;
1185    case JXFORM_ROT_90:
1186 +    if (info->trim)
1187 +      trim_right_edge(info, srcinfo->image_height);
1188 +    /* Need workspace arrays having transposed dimensions. */
1189 +    need_workspace = TRUE;
1190 +    transpose_it = TRUE;
1191 +    break;
1192 +  case JXFORM_ROT_180:
1193 +    if (info->trim) {
1194 +      trim_right_edge(info, srcinfo->image_width);
1195 +      trim_bottom_edge(info, srcinfo->image_height);
1196 +    }
1197 +    /* Need workspace arrays having same dimensions as source image. */
1198 +    need_workspace = TRUE;
1199 +    break;
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.
1204 -     */
1205 +    if (info->trim)
1206 +      trim_bottom_edge(info, srcinfo->image_width);
1207 +    /* Need workspace arrays having transposed dimensions. */
1208 +    need_workspace = TRUE;
1209 +    transpose_it = TRUE;
1210 +    break;
1211 +  }
1212 +
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.
1216 +   */
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;
1236 +      } else {
1237 +       h_samp_factor = compptr->h_samp_factor;
1238 +       v_samp_factor = compptr->v_samp_factor;
1239 +      }
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);
1250      }
1251 -    break;
1252    }
1253 +
1254    info->workspace_coef_arrays = coef_arrays;
1255  }
1256  
1257 @@ -642,14 +1062,8 @@
1258    int tblno, i, j, ci, itemp;
1259    jpeg_component_info *compptr;
1260    JQUANT_TBL *qtblptr;
1261 -  JDIMENSION dtemp;
1262    UINT16 qtemp;
1263  
1264 -  /* Transpose basic image dimensions */
1265 -  dtemp = dstinfo->image_width;
1266 -  dstinfo->image_width = dstinfo->image_height;
1267 -  dstinfo->image_height = dtemp;
1268 -
1269    /* Transpose sampling factors */
1270    for (ci = 0; ci < dstinfo->num_components; ci++) {
1271      compptr = dstinfo->comp_info + ci;
1272 @@ -674,46 +1088,159 @@
1273  }
1274  
1275  
1276 -/* Trim off any partial iMCUs on the indicated destination edge */
1277 +/* Adjust Exif image parameters.
1278 + *
1279 + * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1280 + */
1281  
1282  LOCAL(void)
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)
1286  {
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;
1293 +
1294 +  if (length < 12) return; /* Length of an IFD entry */
1295 +
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;
1301 +  else
1302 +    return;
1303 +
1304 +  /* Check Tag Mark */
1305 +  if (is_motorola) {
1306 +    if (GETJOCTET(data[2]) != 0) return;
1307 +    if (GETJOCTET(data[3]) != 0x2A) return;
1308 +  } else {
1309 +    if (GETJOCTET(data[3]) != 0) return;
1310 +    if (GETJOCTET(data[2]) != 0x2A) return;
1311 +  }
1312  
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).
1316 -   */
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]);
1328 +  } else {
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]);
1334    }
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);
1338 -}
1339 +  if (firstoffset > length - 2) return; /* check end of data segment */
1340  
1341 -LOCAL(void)
1342 -trim_bottom_edge (j_compress_ptr dstinfo)
1343 -{
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]);
1351 +  } else {
1352 +    number_of_tags = GETJOCTET(data[firstoffset+1]);
1353 +    number_of_tags <<= 8;
1354 +    number_of_tags += GETJOCTET(data[firstoffset]);
1355 +  }
1356 +  if (number_of_tags == 0) return;
1357 +  firstoffset += 2;
1358  
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).
1362 -   */
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 */
1368 +  for (;;) {
1369 +    if (firstoffset > length - 12) return; /* check end of data segment */
1370 +    /* Get Tag number */
1371 +    if (is_motorola) {
1372 +      tagnum = GETJOCTET(data[firstoffset]);
1373 +      tagnum <<= 8;
1374 +      tagnum += GETJOCTET(data[firstoffset+1]);
1375 +    } else {
1376 +      tagnum = GETJOCTET(data[firstoffset+1]);
1377 +      tagnum <<= 8;
1378 +      tagnum += GETJOCTET(data[firstoffset]);
1379 +    }
1380 +    if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1381 +    if (--number_of_tags == 0) return;
1382 +    firstoffset += 12;
1383    }
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);
1387 +
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]);
1393 +    offset <<= 8;
1394 +    offset += GETJOCTET(data[firstoffset+11]);
1395 +  } else {
1396 +    if (GETJOCTET(data[firstoffset+11]) != 0) return;
1397 +    if (GETJOCTET(data[firstoffset+10]) != 0) return;
1398 +    offset = GETJOCTET(data[firstoffset+9]);
1399 +    offset <<= 8;
1400 +    offset += GETJOCTET(data[firstoffset+8]);
1401 +  }
1402 +  if (offset > length - 2) return; /* check end of data segment */
1403 +
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]);
1409 +  } else {
1410 +    number_of_tags = GETJOCTET(data[offset+1]);
1411 +    number_of_tags <<= 8;
1412 +    number_of_tags += GETJOCTET(data[offset]);
1413 +  }
1414 +  if (number_of_tags < 2) return;
1415 +  offset += 2;
1416 +
1417 +  /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1418 +  do {
1419 +    if (offset > length - 12) return; /* check end of data segment */
1420 +    /* Get Tag number */
1421 +    if (is_motorola) {
1422 +      tagnum = GETJOCTET(data[offset]);
1423 +      tagnum <<= 8;
1424 +      tagnum += GETJOCTET(data[offset+1]);
1425 +    } else {
1426 +      tagnum = GETJOCTET(data[offset+1]);
1427 +      tagnum <<= 8;
1428 +      tagnum += GETJOCTET(data[offset]);
1429 +    }
1430 +    if (tagnum == 0xA002 || tagnum == 0xA003) {
1431 +      if (tagnum == 0xA002)
1432 +       new_value = new_width; /* ExifImageWidth Tag */
1433 +      else
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);
1446 +      } else {
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;
1457 +      }
1458 +    }
1459 +    offset += 12;
1460 +  } while (--number_of_tags);
1461  }
1462  
1463  
1464 @@ -736,18 +1263,22 @@
1465  {
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.)
1478       */
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.
1494 +       */
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);
1501      }
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.
1506 +     */
1507 +    dstinfo->comp_info[0].h_samp_factor = 1;
1508 +    dstinfo->comp_info[0].v_samp_factor = 1;
1509    }
1510  
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.
1514 +   */
1515 +  dstinfo->image_width = info->output_width;
1516 +  dstinfo->image_height = info->output_height;
1517 +
1518 +  /* Transpose destination image parameters */
1519    switch (info->transform) {
1520 -  case JXFORM_NONE:
1521 -    /* Nothing to do */
1522 -    break;
1523 -  case JXFORM_FLIP_H:
1524 -    if (info->trim)
1525 -      trim_right_edge(dstinfo);
1526 -    break;
1527 -  case JXFORM_FLIP_V:
1528 -    if (info->trim)
1529 -      trim_bottom_edge(dstinfo);
1530 -    break;
1531    case JXFORM_TRANSPOSE:
1532 -    transpose_critical_parameters(dstinfo);
1533 -    /* transpose does NOT have to trim anything */
1534 -    break;
1535    case JXFORM_TRANSVERSE:
1536 -    transpose_critical_parameters(dstinfo);
1537 -    if (info->trim) {
1538 -      trim_right_edge(dstinfo);
1539 -      trim_bottom_edge(dstinfo);
1540 -    }
1541 -    break;
1542    case JXFORM_ROT_90:
1543 -    transpose_critical_parameters(dstinfo);
1544 -    if (info->trim)
1545 -      trim_right_edge(dstinfo);
1546 -    break;
1547 -  case JXFORM_ROT_180:
1548 -    if (info->trim) {
1549 -      trim_right_edge(dstinfo);
1550 -      trim_bottom_edge(dstinfo);
1551 -    }
1552 -    break;
1553    case JXFORM_ROT_270:
1554      transpose_critical_parameters(dstinfo);
1555 -    if (info->trim)
1556 -      trim_bottom_edge(dstinfo);
1557      break;
1558    }
1559  
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);
1579 +  }
1580 +
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 @@
1585   */
1586  
1587  GLOBAL(void)
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)
1596  {
1597    jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
1598  
1599 +  /* Note: conditions tested here should match those in switch statement
1600 +   * in jtransform_request_workspace()
1601 +   */
1602    switch (info->transform) {
1603    case JXFORM_NONE:
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);
1607      break;
1608    case JXFORM_FLIP_H:
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);
1613 +    else
1614 +      do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
1615 +                       src_coef_arrays);
1616      break;
1617    case JXFORM_FLIP_V:
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);
1621      break;
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);
1626      break;
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);
1631      break;
1632    case JXFORM_ROT_90:
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);
1636      break;
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);
1641      break;
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);
1646      break;
1647    }
1648  }
1649  
1650 +/* jtransform_perfect_transform
1651 + *
1652 + * Determine whether lossless transformation is perfectly
1653 + * possible for a specified image and transformation.
1654 + *
1655 + * Inputs:
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
1665 + * Result:
1666 + *   TRUE = perfect transformation possible
1667 + *   FALSE = perfect transformation not possible
1668 + *           (may use custom action then)
1669 + */
1670 +
1671 +GLOBAL(boolean)
1672 +jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
1673 +                            int MCU_width, int MCU_height,
1674 +                            JXFORM_CODE transform)
1675 +{
1676 +  boolean result = TRUE; /* initialize TRUE */
1677 +
1678 +  switch (transform) {
1679 +  case JXFORM_FLIP_H:
1680 +  case JXFORM_ROT_270:
1681 +    if (image_width % (JDIMENSION) MCU_width)
1682 +      result = FALSE;
1683 +    break;
1684 +  case JXFORM_FLIP_V:
1685 +  case JXFORM_ROT_90:
1686 +    if (image_height % (JDIMENSION) MCU_height)
1687 +      result = FALSE;
1688 +    break;
1689 +  case JXFORM_TRANSVERSE:
1690 +  case JXFORM_ROT_180:
1691 +    if (image_width % (JDIMENSION) MCU_width)
1692 +      result = FALSE;
1693 +    if (image_height % (JDIMENSION) MCU_height)
1694 +      result = FALSE;
1695 +    break;
1696 +  }
1697 +
1698 +  return result;
1699 +}
1700 +
1701  #endif /* TRANSFORMS_SUPPORTED */
1702  
1703  
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
1707 @@ -1,7 +1,7 @@
1708  /*
1709   * transupp.h
1710   *
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.
1715   *
1716 @@ -22,32 +22,6 @@
1717  #define TRANSFORMS_SUPPORTED 1         /* 0 disables transform code */
1718  #endif
1719  
1720 -/* Short forms of external names for systems with brain-damaged linkers. */
1721 -
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 */
1729 -
1730 -
1731 -/*
1732 - * Codes for supported types of image transformations.
1733 - */
1734 -
1735 -typedef enum {
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) */
1744 -} JXFORM_CODE;
1745 -
1746  /*
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
1749 @@ -75,6 +49,19 @@
1750   * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
1751   * followed by -rot 180 -trim trims both edges.)
1752   *
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.)
1761 + *
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
1764 + * image.
1765 + *
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
1769 @@ -83,20 +70,89 @@
1770   * be aware of the option to know how many components to work on.
1771   */
1772  
1773 +
1774 +/* Short forms of external names for systems with brain-damaged linkers. */
1775 +
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 */
1785 +
1786 +
1787 +/*
1788 + * Codes for supported types of image transformations.
1789 + */
1790 +
1791 +typedef enum {
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) */
1800 +} JXFORM_CODE;
1801 +
1802 +/*
1803 + * Codes for crop parameters, which can individually be unspecified,
1804 + * positive, or negative.  (Negative width or height makes no sense, though.)
1805 + */
1806 +
1807 +typedef enum {
1808 +       JCROP_UNSET,
1809 +       JCROP_POS,
1810 +       JCROP_NEG
1811 +} JCROP_CODE;
1812 +
1813 +/*
1814 + * Transform parameters struct.
1815 + * NB: application must not change any elements of this struct after
1816 + * calling jtransform_request_workspace.
1817 + */
1818 +
1819  typedef struct {
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 */
1826 +
1827 +  /* Crop parameters: application need not set these unless crop is TRUE.
1828 +   * These can be filled in by jtransform_parse_crop_spec().
1829 +   */
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) */
1838  
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;
1849  
1850  
1851  #if TRANSFORMS_SUPPORTED
1852  
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.
1870 + */
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));
1875 +
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...
1880 + */
1881 +#define jtransform_execute_transformation      jtransform_execute_transform
1882  
1883  #endif /* TRANSFORMS_SUPPORTED */
1884  
This page took 0.178302 seconds and 4 git commands to generate.