a3d878cc735bec1644f0c778587784d09e260ba7
[platform/upstream/libjpeg-turbo.git] / transupp.c
1 /*
2  * transupp.c
3  *
4  * This file was part of the Independent JPEG Group's software:
5  * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
6  * libjpeg-turbo Modifications:
7  * Copyright (C) 2010, 2017, 2021-2022, D. R. Commander.
8  * For conditions of distribution and use, see the accompanying README.ijg
9  * file.
10  *
11  * This file contains image transformation routines and other utility code
12  * used by the jpegtran sample application.  These are NOT part of the core
13  * JPEG library.  But we keep these routines separate from jpegtran.c to
14  * ease the task of maintaining jpegtran-like programs that have other user
15  * interfaces.
16  */
17
18 /* Although this file really shouldn't have access to the library internals,
19  * it's helpful to let it call jround_up() and jcopy_block_row().
20  */
21 #define JPEG_INTERNALS
22
23 #include "jinclude.h"
24 #include "jpeglib.h"
25 #include "transupp.h"           /* My own external interface */
26 #include "jpegcomp.h"
27 #include <ctype.h>              /* to declare isdigit() */
28
29
30 #if JPEG_LIB_VERSION >= 70
31 #define dstinfo_min_DCT_h_scaled_size  dstinfo->min_DCT_h_scaled_size
32 #define dstinfo_min_DCT_v_scaled_size  dstinfo->min_DCT_v_scaled_size
33 #else
34 #define dstinfo_min_DCT_h_scaled_size  DCTSIZE
35 #define dstinfo_min_DCT_v_scaled_size  DCTSIZE
36 #endif
37
38
39 #if TRANSFORMS_SUPPORTED
40
41 /*
42  * Lossless image transformation routines.  These routines work on DCT
43  * coefficient arrays and thus do not require any lossy decompression
44  * or recompression of the image.
45  * Thanks to Guido Vollbeding for the initial design and code of this feature,
46  * and to Ben Jackson for introducing the cropping feature.
47  *
48  * Horizontal flipping is done in-place, using a single top-to-bottom
49  * pass through the virtual source array.  It will thus be much the
50  * fastest option for images larger than main memory.
51  *
52  * The other routines require a set of destination virtual arrays, so they
53  * need twice as much memory as jpegtran normally does.  The destination
54  * arrays are always written in normal scan order (top to bottom) because
55  * the virtual array manager expects this.  The source arrays will be scanned
56  * in the corresponding order, which means multiple passes through the source
57  * arrays for most of the transforms.  That could result in much thrashing
58  * if the image is larger than main memory.
59  *
60  * If cropping or trimming is involved, the destination arrays may be smaller
61  * than the source arrays.  Note it is not possible to do horizontal flip
62  * in-place when a nonzero Y crop offset is specified, since we'd have to move
63  * data from one block row to another but the virtual array manager doesn't
64  * guarantee we can touch more than one row at a time.  So in that case,
65  * we have to use a separate destination array.
66  *
67  * Some notes about the operating environment of the individual transform
68  * routines:
69  * 1. Both the source and destination virtual arrays are allocated from the
70  *    source JPEG object, and therefore should be manipulated by calling the
71  *    source's memory manager.
72  * 2. The destination's component count should be used.  It may be smaller
73  *    than the source's when forcing to grayscale.
74  * 3. Likewise the destination's sampling factors should be used.  When
75  *    forcing to grayscale the destination's sampling factors will be all 1,
76  *    and we may as well take that as the effective iMCU size.
77  * 4. When "trim" is in effect, the destination's dimensions will be the
78  *    trimmed values but the source's will be untrimmed.
79  * 5. When "crop" is in effect, the destination's dimensions will be the
80  *    cropped values but the source's will be uncropped.  Each transform
81  *    routine is responsible for picking up source data starting at the
82  *    correct X and Y offset for the crop region.  (The X and Y offsets
83  *    passed to the transform routines are measured in iMCU blocks of the
84  *    destination.)
85  * 6. All the routines assume that the source and destination buffers are
86  *    padded out to a full iMCU boundary.  This is true, although for the
87  *    source buffer it is an undocumented property of jdcoefct.c.
88  */
89
90
91 LOCAL(void)
92 dequant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
93              jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
94 {
95   JDIMENSION blk_x, blk_y;
96   int offset_y, k;
97   JQUANT_TBL *qtblptr;
98   JBLOCKARRAY buffer;
99   JBLOCKROW block;
100   JCOEFPTR ptr;
101
102   qtblptr = compptr->quant_table;
103   for (blk_y = 0; blk_y < compptr->height_in_blocks;
104        blk_y += compptr->v_samp_factor) {
105     buffer = (*cinfo->mem->access_virt_barray)
106       ((j_common_ptr)cinfo, coef_array, blk_y,
107        (JDIMENSION)compptr->v_samp_factor, TRUE);
108     for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
109       block = buffer[offset_y];
110       for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
111         ptr = block[blk_x];
112         for (k = 0; k < DCTSIZE2; k++)
113           if (qtblptr->quantval[k] != qtblptr1->quantval[k])
114             ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k];
115       }
116     }
117   }
118 }
119
120
121 LOCAL(void)
122 requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
123              jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
124 {
125   JDIMENSION blk_x, blk_y;
126   int offset_y, k;
127   JQUANT_TBL *qtblptr;
128   JBLOCKARRAY buffer;
129   JBLOCKROW block;
130   JCOEFPTR ptr;
131   JCOEF temp, qval;
132
133   qtblptr = compptr->quant_table;
134   for (blk_y = 0; blk_y < compptr->height_in_blocks;
135        blk_y += compptr->v_samp_factor) {
136     buffer = (*cinfo->mem->access_virt_barray)
137       ((j_common_ptr)cinfo, coef_array, blk_y,
138        (JDIMENSION)compptr->v_samp_factor, TRUE);
139     for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
140       block = buffer[offset_y];
141       for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
142         ptr = block[blk_x];
143         for (k = 0; k < DCTSIZE2; k++) {
144           temp = qtblptr->quantval[k];
145           qval = qtblptr1->quantval[k];
146           if (temp != qval) {
147             temp *= ptr[k];
148             /* The following quantization code is copied from jcdctmgr.c */
149 #ifdef FAST_DIVIDE
150 #define DIVIDE_BY(a, b)  a /= b
151 #else
152 #define DIVIDE_BY(a, b)  if (a >= b) a /= b;  else a = 0
153 #endif
154             if (temp < 0) {
155               temp = -temp;
156               temp += qval >> 1; /* for rounding */
157               DIVIDE_BY(temp, qval);
158               temp = -temp;
159             } else {
160               temp += qval >> 1; /* for rounding */
161               DIVIDE_BY(temp, qval);
162             }
163             ptr[k] = temp;
164           }
165         }
166       }
167     }
168   }
169 }
170
171
172 /*
173  * Calculate largest common denominator using Euclid's algorithm.
174  */
175 LOCAL(JCOEF)
176 largest_common_denominator(JCOEF a, JCOEF b)
177 {
178   JCOEF c;
179
180   do {
181     c = a % b;
182     a = b;
183     b = c;
184   } while (c);
185
186   return a;
187 }
188
189
190 LOCAL(void)
191 adjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays,
192              j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,
193              boolean trim, j_compress_ptr dstinfo)
194 {
195   jpeg_component_info *compptr1, *compptr2;
196   JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3;
197   int ci, k;
198
199   for (ci = 0; ci < dstinfo->num_components && ci < dropinfo->num_components;
200        ci++) {
201     compptr1 = srcinfo->comp_info + ci;
202     compptr2 = dropinfo->comp_info + ci;
203     qtblptr1 = compptr1->quant_table;
204     qtblptr2 = compptr2->quant_table;
205     for (k = 0; k < DCTSIZE2; k++) {
206       if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) {
207         if (trim)
208           requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1);
209         else {
210           qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no];
211           for (k = 0; k < DCTSIZE2; k++)
212             if (qtblptr1->quantval[k] != qtblptr2->quantval[k])
213               qtblptr3->quantval[k] =
214                 largest_common_denominator(qtblptr1->quantval[k],
215                                            qtblptr2->quantval[k]);
216           dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3);
217           dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3);
218         }
219         break;
220       }
221     }
222   }
223 }
224
225
226 LOCAL(void)
227 do_drop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
228         JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
229         jvirt_barray_ptr *src_coef_arrays,
230         j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,
231         JDIMENSION drop_width, JDIMENSION drop_height)
232 /* Drop (insert) the contents of another image into the source image.  If the
233  * number of components in the drop image is smaller than the number of
234  * components in the destination image, then we fill in the remaining
235  * components with zero.  This allows for dropping the contents of grayscale
236  * images into (arbitrarily sampled) color images.
237  */
238 {
239   JDIMENSION comp_width, comp_height;
240   JDIMENSION blk_y, x_drop_blocks, y_drop_blocks;
241   int ci, offset_y;
242   JBLOCKARRAY src_buffer, dst_buffer;
243   jpeg_component_info *compptr;
244
245   for (ci = 0; ci < dstinfo->num_components; ci++) {
246     compptr = dstinfo->comp_info + ci;
247     comp_width = drop_width * compptr->h_samp_factor;
248     comp_height = drop_height * compptr->v_samp_factor;
249     x_drop_blocks = x_crop_offset * compptr->h_samp_factor;
250     y_drop_blocks = y_crop_offset * compptr->v_samp_factor;
251     for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) {
252       dst_buffer = (*srcinfo->mem->access_virt_barray)
253         ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks,
254          (JDIMENSION)compptr->v_samp_factor, TRUE);
255       if (ci < dropinfo->num_components) {
256         src_buffer = (*dropinfo->mem->access_virt_barray)
257           ((j_common_ptr)dropinfo, drop_coef_arrays[ci], blk_y,
258            (JDIMENSION)compptr->v_samp_factor, FALSE);
259         for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
260           jcopy_block_row(src_buffer[offset_y],
261                           dst_buffer[offset_y] + x_drop_blocks, comp_width);
262         }
263       } else {
264         for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
265           memset(dst_buffer[offset_y] + x_drop_blocks, 0,
266                  comp_width * sizeof(JBLOCK));
267         }
268       }
269     }
270   }
271 }
272
273
274 LOCAL(void)
275 do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
276         JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
277         jvirt_barray_ptr *src_coef_arrays,
278         jvirt_barray_ptr *dst_coef_arrays)
279 /* Crop.  This is only used when no rotate/flip is requested with the crop. */
280 {
281   JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
282   int ci, offset_y;
283   JBLOCKARRAY src_buffer, dst_buffer;
284   jpeg_component_info *compptr;
285
286   /* We simply have to copy the right amount of data (the destination's
287    * image size) starting at the given X and Y offsets in the source.
288    */
289   for (ci = 0; ci < dstinfo->num_components; ci++) {
290     compptr = dstinfo->comp_info + ci;
291     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
292     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
293     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
294          dst_blk_y += compptr->v_samp_factor) {
295       dst_buffer = (*srcinfo->mem->access_virt_barray)
296         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
297          (JDIMENSION)compptr->v_samp_factor, TRUE);
298       src_buffer = (*srcinfo->mem->access_virt_barray)
299         ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
300          (JDIMENSION)compptr->v_samp_factor, FALSE);
301       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
302         jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
303                         dst_buffer[offset_y], compptr->width_in_blocks);
304       }
305     }
306   }
307 }
308
309
310 LOCAL(void)
311 do_crop_ext_zero(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
312                  JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
313                  jvirt_barray_ptr *src_coef_arrays,
314                  jvirt_barray_ptr *dst_coef_arrays)
315 /* Crop.  This is only used when no rotate/flip is requested with the crop.
316  * Extension: If the destination size is larger than the source, we fill in the
317  * expanded region with zero (neutral gray).  Note that we also have to zero
318  * partial iMCUs at the right and bottom edge of the source image area in this
319  * case.
320  */
321 {
322   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
323   JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
324   int ci, offset_y;
325   JBLOCKARRAY src_buffer, dst_buffer;
326   jpeg_component_info *compptr;
327
328   MCU_cols = srcinfo->output_width /
329              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
330   MCU_rows = srcinfo->output_height /
331              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
332
333   for (ci = 0; ci < dstinfo->num_components; ci++) {
334     compptr = dstinfo->comp_info + ci;
335     comp_width = MCU_cols * compptr->h_samp_factor;
336     comp_height = MCU_rows * compptr->v_samp_factor;
337     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
338     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
339     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
340          dst_blk_y += compptr->v_samp_factor) {
341       dst_buffer = (*srcinfo->mem->access_virt_barray)
342         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
343          (JDIMENSION)compptr->v_samp_factor, TRUE);
344       if (dstinfo->_jpeg_height > srcinfo->output_height) {
345         if (dst_blk_y < y_crop_blocks ||
346             dst_blk_y >= y_crop_blocks + comp_height) {
347           for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
348             memset(dst_buffer[offset_y], 0,
349                    compptr->width_in_blocks * sizeof(JBLOCK));
350           }
351           continue;
352         }
353         src_buffer = (*srcinfo->mem->access_virt_barray)
354           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
355            dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
356            FALSE);
357       } else {
358         src_buffer = (*srcinfo->mem->access_virt_barray)
359           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
360            dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
361            FALSE);
362       }
363       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
364         if (dstinfo->_jpeg_width > srcinfo->output_width) {
365           if (x_crop_blocks > 0) {
366             memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK));
367           }
368           jcopy_block_row(src_buffer[offset_y],
369                           dst_buffer[offset_y] + x_crop_blocks, comp_width);
370           if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
371             memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0,
372                    (compptr->width_in_blocks - x_crop_blocks - comp_width) *
373                    sizeof(JBLOCK));
374           }
375         } else {
376           jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
377                           dst_buffer[offset_y], compptr->width_in_blocks);
378         }
379       }
380     }
381   }
382 }
383
384
385 LOCAL(void)
386 do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
387                  JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
388                  jvirt_barray_ptr *src_coef_arrays,
389                  jvirt_barray_ptr *dst_coef_arrays)
390 /* Crop.  This is only used when no rotate/flip is requested with the crop.
391  * Extension: The destination width is larger than the source, and we fill in
392  * the expanded region with the DC coefficient of the adjacent block.  Note
393  * that we also have to fill partial iMCUs at the right and bottom edge of the
394  * source image area in this case.
395  */
396 {
397   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
398   JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
399   int ci, offset_y;
400   JCOEF dc;
401   JBLOCKARRAY src_buffer, dst_buffer;
402   jpeg_component_info *compptr;
403
404   MCU_cols = srcinfo->output_width /
405              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
406   MCU_rows = srcinfo->output_height /
407              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
408
409   for (ci = 0; ci < dstinfo->num_components; ci++) {
410     compptr = dstinfo->comp_info + ci;
411     comp_width = MCU_cols * compptr->h_samp_factor;
412     comp_height = MCU_rows * compptr->v_samp_factor;
413     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
414     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
415     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
416          dst_blk_y += compptr->v_samp_factor) {
417       dst_buffer = (*srcinfo->mem->access_virt_barray)
418         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
419          (JDIMENSION)compptr->v_samp_factor, TRUE);
420       if (dstinfo->_jpeg_height > srcinfo->output_height) {
421         if (dst_blk_y < y_crop_blocks ||
422             dst_blk_y >= y_crop_blocks + comp_height) {
423           for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
424             memset(dst_buffer[offset_y], 0,
425                    compptr->width_in_blocks * sizeof(JBLOCK));
426           }
427           continue;
428         }
429         src_buffer = (*srcinfo->mem->access_virt_barray)
430           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
431            dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
432            FALSE);
433       } else {
434         src_buffer = (*srcinfo->mem->access_virt_barray)
435           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
436            dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
437           FALSE);
438       }
439       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
440         if (x_crop_blocks > 0) {
441           memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK));
442           dc = src_buffer[offset_y][0][0];
443           for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) {
444             dst_buffer[offset_y][dst_blk_x][0] = dc;
445           }
446         }
447         jcopy_block_row(src_buffer[offset_y],
448                         dst_buffer[offset_y] + x_crop_blocks, comp_width);
449         if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
450           memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0,
451                  (compptr->width_in_blocks - x_crop_blocks - comp_width) *
452                  sizeof(JBLOCK));
453           dc = src_buffer[offset_y][comp_width - 1][0];
454           for (dst_blk_x = x_crop_blocks + comp_width;
455                dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
456             dst_buffer[offset_y][dst_blk_x][0] = dc;
457           }
458         }
459       }
460     }
461   }
462 }
463
464
465 LOCAL(void)
466 do_crop_ext_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
467                     JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
468                     jvirt_barray_ptr *src_coef_arrays,
469                     jvirt_barray_ptr *dst_coef_arrays)
470 /* Crop.  This is only used when no rotate/flip is requested with the crop.
471  * Extension: The destination width is larger than the source, and we fill in
472  * the expanded region with repeated reflections of the source image.  Note
473  * that we also have to fill partial iMCUs at the right and bottom edge of the
474  * source image area in this case.
475  */
476 {
477   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x;
478   JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
479   int ci, k, offset_y;
480   JBLOCKARRAY src_buffer, dst_buffer;
481   JBLOCKROW src_row_ptr, dst_row_ptr;
482   JCOEFPTR src_ptr, dst_ptr;
483   jpeg_component_info *compptr;
484
485   MCU_cols = srcinfo->output_width /
486              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
487   MCU_rows = srcinfo->output_height /
488              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
489
490   for (ci = 0; ci < dstinfo->num_components; ci++) {
491     compptr = dstinfo->comp_info + ci;
492     comp_width = MCU_cols * compptr->h_samp_factor;
493     comp_height = MCU_rows * compptr->v_samp_factor;
494     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
495     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
496     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
497          dst_blk_y += compptr->v_samp_factor) {
498       dst_buffer = (*srcinfo->mem->access_virt_barray)
499         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
500          (JDIMENSION)compptr->v_samp_factor, TRUE);
501       if (dstinfo->_jpeg_height > srcinfo->output_height) {
502         if (dst_blk_y < y_crop_blocks ||
503             dst_blk_y >= y_crop_blocks + comp_height) {
504           for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
505             memset(dst_buffer[offset_y], 0,
506                    compptr->width_in_blocks * sizeof(JBLOCK));
507           }
508           continue;
509         }
510         src_buffer = (*srcinfo->mem->access_virt_barray)
511           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
512            dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
513            FALSE);
514       } else {
515         src_buffer = (*srcinfo->mem->access_virt_barray)
516           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
517            dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
518            FALSE);
519       }
520       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
521         /* Copy source region */
522         jcopy_block_row(src_buffer[offset_y],
523                         dst_buffer[offset_y] + x_crop_blocks, comp_width);
524         if (x_crop_blocks > 0) {
525           /* Reflect to left */
526           dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks;
527           for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) {
528             src_row_ptr = dst_row_ptr;      /* (re)set axis of reflection */
529             for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
530                  src_blk_x--, dst_blk_x--) {
531               dst_ptr = *(--dst_row_ptr);   /* destination goes left */
532               src_ptr = *src_row_ptr++;     /* source goes right */
533               /* This unrolled loop doesn't need to know which row it's on. */
534               for (k = 0; k < DCTSIZE2; k += 2) {
535                 *dst_ptr++ = *src_ptr++;    /* copy even column */
536                 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
537                                                change */
538               }
539             }
540           }
541         }
542         if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
543           /* Reflect to right */
544           dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width;
545           for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width;
546                dst_blk_x > 0;) {
547             src_row_ptr = dst_row_ptr;      /* (re)set axis of reflection */
548             for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
549                  src_blk_x--, dst_blk_x--) {
550               dst_ptr = *dst_row_ptr++;     /* destination goes right */
551               src_ptr = *(--src_row_ptr);   /* source goes left */
552               /* This unrolled loop doesn't need to know which row it's on. */
553               for (k = 0; k < DCTSIZE2; k += 2) {
554                 *dst_ptr++ = *src_ptr++;    /* copy even column */
555                 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
556                                                change */
557               }
558             }
559           }
560         }
561       }
562     }
563   }
564 }
565
566
567 LOCAL(void)
568 do_wipe(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
569         JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
570         jvirt_barray_ptr *src_coef_arrays,
571         JDIMENSION drop_width, JDIMENSION drop_height)
572 /* Wipe - discard image contents of specified region and fill with zero
573  * (neutral gray)
574  */
575 {
576   JDIMENSION x_wipe_blocks, wipe_width;
577   JDIMENSION y_wipe_blocks, wipe_bottom;
578   int ci, offset_y;
579   JBLOCKARRAY buffer;
580   jpeg_component_info *compptr;
581
582   for (ci = 0; ci < dstinfo->num_components; ci++) {
583     compptr = dstinfo->comp_info + ci;
584     x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
585     wipe_width = drop_width * compptr->h_samp_factor;
586     y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
587     wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
588     for (; y_wipe_blocks < wipe_bottom;
589          y_wipe_blocks += compptr->v_samp_factor) {
590       buffer = (*srcinfo->mem->access_virt_barray)
591         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
592          (JDIMENSION)compptr->v_samp_factor, TRUE);
593       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
594         memset(buffer[offset_y] + x_wipe_blocks, 0,
595                wipe_width * sizeof(JBLOCK));
596       }
597     }
598   }
599 }
600
601
602 LOCAL(void)
603 do_flatten(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
604            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
605            jvirt_barray_ptr *src_coef_arrays,
606            JDIMENSION drop_width, JDIMENSION drop_height)
607 /* Flatten - discard image contents of specified region, similarly to wipe,
608  * but fill with the average of adjacent blocks instead of zero.
609  */
610 {
611   JDIMENSION x_wipe_blocks, wipe_width, wipe_right;
612   JDIMENSION y_wipe_blocks, wipe_bottom, blk_x;
613   int ci, offset_y, dc_left_value, dc_right_value, average;
614   JBLOCKARRAY buffer;
615   jpeg_component_info *compptr;
616
617   for (ci = 0; ci < dstinfo->num_components; ci++) {
618     compptr = dstinfo->comp_info + ci;
619     x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
620     wipe_width = drop_width * compptr->h_samp_factor;
621     wipe_right = wipe_width + x_wipe_blocks;
622     y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
623     wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
624     for (; y_wipe_blocks < wipe_bottom;
625          y_wipe_blocks += compptr->v_samp_factor) {
626       buffer = (*srcinfo->mem->access_virt_barray)
627         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
628          (JDIMENSION)compptr->v_samp_factor, TRUE);
629       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
630         memset(buffer[offset_y] + x_wipe_blocks, 0,
631                wipe_width * sizeof(JBLOCK));
632         if (x_wipe_blocks > 0) {
633           dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];
634           if (wipe_right < compptr->width_in_blocks) {
635             dc_right_value = buffer[offset_y][wipe_right][0];
636             average = (dc_left_value + dc_right_value) >> 1;
637           } else {
638             average = dc_left_value;
639           }
640         } else if (wipe_right < compptr->width_in_blocks) {
641           average = buffer[offset_y][wipe_right][0];
642         } else continue;
643         for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) {
644           buffer[offset_y][blk_x][0] = (JCOEF)average;
645         }
646       }
647     }
648   }
649 }
650
651
652 LOCAL(void)
653 do_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
654            JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays,
655            JDIMENSION drop_width, JDIMENSION drop_height)
656 /* Reflect - discard image contents of specified region, similarly to wipe,
657  * but fill with repeated reflections of the outside region instead of zero.
658  * NB: y_crop_offset is assumed to be zero.
659  */
660 {
661   JDIMENSION x_wipe_blocks, wipe_width;
662   JDIMENSION y_wipe_blocks, wipe_bottom;
663   JDIMENSION src_blk_x, dst_blk_x;
664   int ci, k, offset_y;
665   JBLOCKARRAY buffer;
666   JBLOCKROW src_row_ptr, dst_row_ptr;
667   JCOEFPTR src_ptr, dst_ptr;
668   jpeg_component_info *compptr;
669
670   for (ci = 0; ci < dstinfo->num_components; ci++) {
671     compptr = dstinfo->comp_info + ci;
672     x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
673     wipe_width = drop_width * compptr->h_samp_factor;
674     wipe_bottom = drop_height * compptr->v_samp_factor;
675     for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom;
676          y_wipe_blocks += compptr->v_samp_factor) {
677       buffer = (*srcinfo->mem->access_virt_barray)
678         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
679          (JDIMENSION)compptr->v_samp_factor, TRUE);
680       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
681         if (x_wipe_blocks > 0) {
682           /* Reflect from left */
683           dst_row_ptr = buffer[offset_y] + x_wipe_blocks;
684           for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
685             src_row_ptr = dst_row_ptr;     /* (re)set axis of reflection */
686             for (src_blk_x = x_wipe_blocks;
687                  src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
688               dst_ptr = *dst_row_ptr++;    /* destination goes right */
689               src_ptr = *(--src_row_ptr);  /* source goes left */
690               /* this unrolled loop doesn't need to know which row it's on... */
691               for (k = 0; k < DCTSIZE2; k += 2) {
692                 *dst_ptr++ = *src_ptr++;   /* copy even column */
693                 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
694               }
695             }
696           }
697         } else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) {
698           /* Reflect from right */
699           dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width;
700           for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
701             src_row_ptr = dst_row_ptr;     /* (re)set axis of reflection */
702             src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width;
703             for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
704               dst_ptr = *(--dst_row_ptr);  /* destination goes left */
705               src_ptr = *src_row_ptr++;    /* source goes right */
706               /* this unrolled loop doesn't need to know which row it's on... */
707               for (k = 0; k < DCTSIZE2; k += 2) {
708                 *dst_ptr++ = *src_ptr++;   /* copy even column */
709                 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
710               }
711             }
712           }
713         } else {
714           memset(buffer[offset_y] + x_wipe_blocks, 0,
715                  wipe_width * sizeof(JBLOCK));
716         }
717       }
718     }
719   }
720 }
721
722
723 LOCAL(void)
724 do_flip_h_no_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
725                   JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays)
726 /* Horizontal flip; done in-place, so no separate dest array is required.
727  * NB: this only works when y_crop_offset is zero.
728  */
729 {
730   JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
731   int ci, k, offset_y;
732   JBLOCKARRAY buffer;
733   JCOEFPTR ptr1, ptr2;
734   JCOEF temp1, temp2;
735   jpeg_component_info *compptr;
736
737   /* Horizontal mirroring of DCT blocks is accomplished by swapping
738    * pairs of blocks in-place.  Within a DCT block, we perform horizontal
739    * mirroring by changing the signs of odd-numbered columns.
740    * Partial iMCUs at the right edge are left untouched.
741    */
742   MCU_cols = srcinfo->output_width /
743              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
744
745   for (ci = 0; ci < dstinfo->num_components; ci++) {
746     compptr = dstinfo->comp_info + ci;
747     comp_width = MCU_cols * compptr->h_samp_factor;
748     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
749     for (blk_y = 0; blk_y < compptr->height_in_blocks;
750          blk_y += compptr->v_samp_factor) {
751       buffer = (*srcinfo->mem->access_virt_barray)
752         ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y,
753          (JDIMENSION)compptr->v_samp_factor, TRUE);
754       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
755         /* Do the mirroring */
756         for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
757           ptr1 = buffer[offset_y][blk_x];
758           ptr2 = buffer[offset_y][comp_width - blk_x - 1];
759           /* this unrolled loop doesn't need to know which row it's on... */
760           for (k = 0; k < DCTSIZE2; k += 2) {
761             temp1 = *ptr1;      /* swap even column */
762             temp2 = *ptr2;
763             *ptr1++ = temp2;
764             *ptr2++ = temp1;
765             temp1 = *ptr1;      /* swap odd column with sign change */
766             temp2 = *ptr2;
767             *ptr1++ = -temp2;
768             *ptr2++ = -temp1;
769           }
770         }
771         if (x_crop_blocks > 0) {
772           /* Now left-justify the portion of the data to be kept.
773            * We can't use a single jcopy_block_row() call because that routine
774            * depends on memcpy(), whose behavior is unspecified for overlapping
775            * source and destination areas.  Sigh.
776            */
777           for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
778             jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
779                             buffer[offset_y] + blk_x, (JDIMENSION)1);
780           }
781         }
782       }
783     }
784   }
785 }
786
787
788 LOCAL(void)
789 do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
790           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
791           jvirt_barray_ptr *src_coef_arrays,
792           jvirt_barray_ptr *dst_coef_arrays)
793 /* Horizontal flip in general cropping case */
794 {
795   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
796   JDIMENSION x_crop_blocks, y_crop_blocks;
797   int ci, k, offset_y;
798   JBLOCKARRAY src_buffer, dst_buffer;
799   JBLOCKROW src_row_ptr, dst_row_ptr;
800   JCOEFPTR src_ptr, dst_ptr;
801   jpeg_component_info *compptr;
802
803   /* Here we must output into a separate array because we can't touch
804    * different rows of a single virtual array simultaneously.  Otherwise,
805    * this is essentially the same as the routine above.
806    */
807   MCU_cols = srcinfo->output_width /
808              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
809
810   for (ci = 0; ci < dstinfo->num_components; ci++) {
811     compptr = dstinfo->comp_info + ci;
812     comp_width = MCU_cols * compptr->h_samp_factor;
813     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
814     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
815     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
816          dst_blk_y += compptr->v_samp_factor) {
817       dst_buffer = (*srcinfo->mem->access_virt_barray)
818         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
819          (JDIMENSION)compptr->v_samp_factor, TRUE);
820       src_buffer = (*srcinfo->mem->access_virt_barray)
821         ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
822          (JDIMENSION)compptr->v_samp_factor, FALSE);
823       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
824         dst_row_ptr = dst_buffer[offset_y];
825         src_row_ptr = src_buffer[offset_y];
826         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
827              dst_blk_x++) {
828           if (x_crop_blocks + dst_blk_x < comp_width) {
829             /* Do the mirrorable blocks */
830             dst_ptr = dst_row_ptr[dst_blk_x];
831             src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
832             /* this unrolled loop doesn't need to know which row it's on... */
833             for (k = 0; k < DCTSIZE2; k += 2) {
834               *dst_ptr++ = *src_ptr++;    /* copy even column */
835               *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
836                                              change */
837             }
838           } else {
839             /* Copy last partial block(s) verbatim */
840             jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
841                             dst_row_ptr + dst_blk_x, (JDIMENSION)1);
842           }
843         }
844       }
845     }
846   }
847 }
848
849
850 LOCAL(void)
851 do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
852           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
853           jvirt_barray_ptr *src_coef_arrays,
854           jvirt_barray_ptr *dst_coef_arrays)
855 /* Vertical flip */
856 {
857   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
858   JDIMENSION x_crop_blocks, y_crop_blocks;
859   int ci, i, j, offset_y;
860   JBLOCKARRAY src_buffer, dst_buffer;
861   JBLOCKROW src_row_ptr, dst_row_ptr;
862   JCOEFPTR src_ptr, dst_ptr;
863   jpeg_component_info *compptr;
864
865   /* We output into a separate array because we can't touch different
866    * rows of the source virtual array simultaneously.  Otherwise, this
867    * is a pretty straightforward analog of horizontal flip.
868    * Within a DCT block, vertical mirroring is done by changing the signs
869    * of odd-numbered rows.
870    * Partial iMCUs at the bottom edge are copied verbatim.
871    */
872   MCU_rows = srcinfo->output_height /
873              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
874
875   for (ci = 0; ci < dstinfo->num_components; ci++) {
876     compptr = dstinfo->comp_info + ci;
877     comp_height = MCU_rows * compptr->v_samp_factor;
878     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
879     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
880     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
881          dst_blk_y += compptr->v_samp_factor) {
882       dst_buffer = (*srcinfo->mem->access_virt_barray)
883         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
884          (JDIMENSION)compptr->v_samp_factor, TRUE);
885       if (y_crop_blocks + dst_blk_y < comp_height) {
886         /* Row is within the mirrorable area. */
887         src_buffer = (*srcinfo->mem->access_virt_barray)
888           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
889            comp_height - y_crop_blocks - dst_blk_y -
890            (JDIMENSION)compptr->v_samp_factor,
891            (JDIMENSION)compptr->v_samp_factor, FALSE);
892       } else {
893         /* Bottom-edge blocks will be copied verbatim. */
894         src_buffer = (*srcinfo->mem->access_virt_barray)
895           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
896            dst_blk_y + y_crop_blocks,
897            (JDIMENSION)compptr->v_samp_factor, FALSE);
898       }
899       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
900         if (y_crop_blocks + dst_blk_y < comp_height) {
901           /* Row is within the mirrorable area. */
902           dst_row_ptr = dst_buffer[offset_y];
903           src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
904           src_row_ptr += x_crop_blocks;
905           for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
906                dst_blk_x++) {
907             dst_ptr = dst_row_ptr[dst_blk_x];
908             src_ptr = src_row_ptr[dst_blk_x];
909             for (i = 0; i < DCTSIZE; i += 2) {
910               /* copy even row */
911               for (j = 0; j < DCTSIZE; j++)
912                 *dst_ptr++ = *src_ptr++;
913               /* copy odd row with sign change */
914               for (j = 0; j < DCTSIZE; j++)
915                 *dst_ptr++ = -(*src_ptr++);
916             }
917           }
918         } else {
919           /* Just copy row verbatim. */
920           jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
921                           dst_buffer[offset_y], compptr->width_in_blocks);
922         }
923       }
924     }
925   }
926 }
927
928
929 LOCAL(void)
930 do_transpose(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
931              JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
932              jvirt_barray_ptr *src_coef_arrays,
933              jvirt_barray_ptr *dst_coef_arrays)
934 /* Transpose source into destination */
935 {
936   JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
937   int ci, i, j, offset_x, offset_y;
938   JBLOCKARRAY src_buffer, dst_buffer;
939   JCOEFPTR src_ptr, dst_ptr;
940   jpeg_component_info *compptr;
941
942   /* Transposing pixels within a block just requires transposing the
943    * DCT coefficients.
944    * Partial iMCUs at the edges require no special treatment; we simply
945    * process all the available DCT blocks for every component.
946    */
947   for (ci = 0; ci < dstinfo->num_components; ci++) {
948     compptr = dstinfo->comp_info + ci;
949     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
950     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
951     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
952          dst_blk_y += compptr->v_samp_factor) {
953       dst_buffer = (*srcinfo->mem->access_virt_barray)
954         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
955          (JDIMENSION)compptr->v_samp_factor, TRUE);
956       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
957         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
958              dst_blk_x += compptr->h_samp_factor) {
959           src_buffer = (*srcinfo->mem->access_virt_barray)
960             ((j_common_ptr)srcinfo, src_coef_arrays[ci],
961              dst_blk_x + x_crop_blocks,
962              (JDIMENSION)compptr->h_samp_factor, FALSE);
963           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
964             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
965             src_ptr =
966               src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
967             for (i = 0; i < DCTSIZE; i++)
968               for (j = 0; j < DCTSIZE; j++)
969                 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
970           }
971         }
972       }
973     }
974   }
975 }
976
977
978 LOCAL(void)
979 do_rot_90(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
980           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
981           jvirt_barray_ptr *src_coef_arrays,
982           jvirt_barray_ptr *dst_coef_arrays)
983 /* 90 degree rotation is equivalent to
984  *   1. Transposing the image;
985  *   2. Horizontal mirroring.
986  * These two steps are merged into a single processing routine.
987  */
988 {
989   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
990   JDIMENSION x_crop_blocks, y_crop_blocks;
991   int ci, i, j, offset_x, offset_y;
992   JBLOCKARRAY src_buffer, dst_buffer;
993   JCOEFPTR src_ptr, dst_ptr;
994   jpeg_component_info *compptr;
995
996   /* Because of the horizontal mirror step, we can't process partial iMCUs
997    * at the (output) right edge properly.  They just get transposed and
998    * not mirrored.
999    */
1000   MCU_cols = srcinfo->output_height /
1001              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
1002
1003   for (ci = 0; ci < dstinfo->num_components; ci++) {
1004     compptr = dstinfo->comp_info + ci;
1005     comp_width = MCU_cols * compptr->h_samp_factor;
1006     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1007     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1008     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1009          dst_blk_y += compptr->v_samp_factor) {
1010       dst_buffer = (*srcinfo->mem->access_virt_barray)
1011         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1012          (JDIMENSION)compptr->v_samp_factor, TRUE);
1013       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1014         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1015              dst_blk_x += compptr->h_samp_factor) {
1016           if (x_crop_blocks + dst_blk_x < comp_width) {
1017             /* Block is within the mirrorable area. */
1018             src_buffer = (*srcinfo->mem->access_virt_barray)
1019               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1020                comp_width - x_crop_blocks - dst_blk_x -
1021                (JDIMENSION)compptr->h_samp_factor,
1022                (JDIMENSION)compptr->h_samp_factor, FALSE);
1023           } else {
1024             /* Edge blocks are transposed but not mirrored. */
1025             src_buffer = (*srcinfo->mem->access_virt_barray)
1026               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1027                dst_blk_x + x_crop_blocks,
1028                (JDIMENSION)compptr->h_samp_factor, FALSE);
1029           }
1030           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
1031             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
1032             if (x_crop_blocks + dst_blk_x < comp_width) {
1033               /* Block is within the mirrorable area. */
1034               src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
1035                 [dst_blk_y + offset_y + y_crop_blocks];
1036               for (i = 0; i < DCTSIZE; i++) {
1037                 for (j = 0; j < DCTSIZE; j++)
1038                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1039                 i++;
1040                 for (j = 0; j < DCTSIZE; j++)
1041                   dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1042               }
1043             } else {
1044               /* Edge blocks are transposed but not mirrored. */
1045               src_ptr = src_buffer[offset_x]
1046                 [dst_blk_y + offset_y + y_crop_blocks];
1047               for (i = 0; i < DCTSIZE; i++)
1048                 for (j = 0; j < DCTSIZE; j++)
1049                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1050             }
1051           }
1052         }
1053       }
1054     }
1055   }
1056 }
1057
1058
1059 LOCAL(void)
1060 do_rot_270(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1061            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
1062            jvirt_barray_ptr *src_coef_arrays,
1063            jvirt_barray_ptr *dst_coef_arrays)
1064 /* 270 degree rotation is equivalent to
1065  *   1. Horizontal mirroring;
1066  *   2. Transposing the image.
1067  * These two steps are merged into a single processing routine.
1068  */
1069 {
1070   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
1071   JDIMENSION x_crop_blocks, y_crop_blocks;
1072   int ci, i, j, offset_x, offset_y;
1073   JBLOCKARRAY src_buffer, dst_buffer;
1074   JCOEFPTR src_ptr, dst_ptr;
1075   jpeg_component_info *compptr;
1076
1077   /* Because of the horizontal mirror step, we can't process partial iMCUs
1078    * at the (output) bottom edge properly.  They just get transposed and
1079    * not mirrored.
1080    */
1081   MCU_rows = srcinfo->output_width /
1082              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
1083
1084   for (ci = 0; ci < dstinfo->num_components; ci++) {
1085     compptr = dstinfo->comp_info + ci;
1086     comp_height = MCU_rows * compptr->v_samp_factor;
1087     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1088     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1089     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1090          dst_blk_y += compptr->v_samp_factor) {
1091       dst_buffer = (*srcinfo->mem->access_virt_barray)
1092         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1093          (JDIMENSION)compptr->v_samp_factor, TRUE);
1094       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1095         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1096              dst_blk_x += compptr->h_samp_factor) {
1097           src_buffer = (*srcinfo->mem->access_virt_barray)
1098             ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1099              dst_blk_x + x_crop_blocks,
1100              (JDIMENSION)compptr->h_samp_factor, FALSE);
1101           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
1102             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
1103             if (y_crop_blocks + dst_blk_y < comp_height) {
1104               /* Block is within the mirrorable area. */
1105               src_ptr = src_buffer[offset_x]
1106                 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
1107               for (i = 0; i < DCTSIZE; i++) {
1108                 for (j = 0; j < DCTSIZE; j++) {
1109                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1110                   j++;
1111                   dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1112                 }
1113               }
1114             } else {
1115               /* Edge blocks are transposed but not mirrored. */
1116               src_ptr = src_buffer[offset_x]
1117                 [dst_blk_y + offset_y + y_crop_blocks];
1118               for (i = 0; i < DCTSIZE; i++)
1119                 for (j = 0; j < DCTSIZE; j++)
1120                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1121             }
1122           }
1123         }
1124       }
1125     }
1126   }
1127 }
1128
1129
1130 LOCAL(void)
1131 do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1132            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
1133            jvirt_barray_ptr *src_coef_arrays,
1134            jvirt_barray_ptr *dst_coef_arrays)
1135 /* 180 degree rotation is equivalent to
1136  *   1. Vertical mirroring;
1137  *   2. Horizontal mirroring.
1138  * These two steps are merged into a single processing routine.
1139  */
1140 {
1141   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
1142   JDIMENSION x_crop_blocks, y_crop_blocks;
1143   int ci, i, j, offset_y;
1144   JBLOCKARRAY src_buffer, dst_buffer;
1145   JBLOCKROW src_row_ptr, dst_row_ptr;
1146   JCOEFPTR src_ptr, dst_ptr;
1147   jpeg_component_info *compptr;
1148
1149   MCU_cols = srcinfo->output_width /
1150              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
1151   MCU_rows = srcinfo->output_height /
1152              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
1153
1154   for (ci = 0; ci < dstinfo->num_components; ci++) {
1155     compptr = dstinfo->comp_info + ci;
1156     comp_width = MCU_cols * compptr->h_samp_factor;
1157     comp_height = MCU_rows * compptr->v_samp_factor;
1158     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1159     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1160     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1161          dst_blk_y += compptr->v_samp_factor) {
1162       dst_buffer = (*srcinfo->mem->access_virt_barray)
1163         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1164          (JDIMENSION)compptr->v_samp_factor, TRUE);
1165       if (y_crop_blocks + dst_blk_y < comp_height) {
1166         /* Row is within the vertically mirrorable area. */
1167         src_buffer = (*srcinfo->mem->access_virt_barray)
1168           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1169            comp_height - y_crop_blocks - dst_blk_y -
1170            (JDIMENSION)compptr->v_samp_factor,
1171            (JDIMENSION)compptr->v_samp_factor, FALSE);
1172       } else {
1173         /* Bottom-edge rows are only mirrored horizontally. */
1174         src_buffer = (*srcinfo->mem->access_virt_barray)
1175           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1176            dst_blk_y + y_crop_blocks,
1177            (JDIMENSION)compptr->v_samp_factor, FALSE);
1178       }
1179       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1180         dst_row_ptr = dst_buffer[offset_y];
1181         if (y_crop_blocks + dst_blk_y < comp_height) {
1182           /* Row is within the mirrorable area. */
1183           src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
1184           for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1185                dst_blk_x++) {
1186             dst_ptr = dst_row_ptr[dst_blk_x];
1187             if (x_crop_blocks + dst_blk_x < comp_width) {
1188               /* Process the blocks that can be mirrored both ways. */
1189               src_ptr =
1190                 src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
1191               for (i = 0; i < DCTSIZE; i += 2) {
1192                 /* For even row, negate every odd column. */
1193                 for (j = 0; j < DCTSIZE; j += 2) {
1194                   *dst_ptr++ = *src_ptr++;
1195                   *dst_ptr++ = -(*src_ptr++);
1196                 }
1197                 /* For odd row, negate every even column. */
1198                 for (j = 0; j < DCTSIZE; j += 2) {
1199                   *dst_ptr++ = -(*src_ptr++);
1200                   *dst_ptr++ = *src_ptr++;
1201                 }
1202               }
1203             } else {
1204               /* Any remaining right-edge blocks are only mirrored vertically. */
1205               src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
1206               for (i = 0; i < DCTSIZE; i += 2) {
1207                 for (j = 0; j < DCTSIZE; j++)
1208                   *dst_ptr++ = *src_ptr++;
1209                 for (j = 0; j < DCTSIZE; j++)
1210                   *dst_ptr++ = -(*src_ptr++);
1211               }
1212             }
1213           }
1214         } else {
1215           /* Remaining rows are just mirrored horizontally. */
1216           src_row_ptr = src_buffer[offset_y];
1217           for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1218                dst_blk_x++) {
1219             if (x_crop_blocks + dst_blk_x < comp_width) {
1220               /* Process the blocks that can be mirrored. */
1221               dst_ptr = dst_row_ptr[dst_blk_x];
1222               src_ptr =
1223                 src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
1224               for (i = 0; i < DCTSIZE2; i += 2) {
1225                 *dst_ptr++ = *src_ptr++;
1226                 *dst_ptr++ = -(*src_ptr++);
1227               }
1228             } else {
1229               /* Any remaining right-edge blocks are only copied. */
1230               jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
1231                               dst_row_ptr + dst_blk_x, (JDIMENSION)1);
1232             }
1233           }
1234         }
1235       }
1236     }
1237   }
1238 }
1239
1240
1241 LOCAL(void)
1242 do_transverse(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1243               JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
1244               jvirt_barray_ptr *src_coef_arrays,
1245               jvirt_barray_ptr *dst_coef_arrays)
1246 /* Transverse transpose is equivalent to
1247  *   1. 180 degree rotation;
1248  *   2. Transposition;
1249  * or
1250  *   1. Horizontal mirroring;
1251  *   2. Transposition;
1252  *   3. Horizontal mirroring.
1253  * These steps are merged into a single processing routine.
1254  */
1255 {
1256   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
1257   JDIMENSION x_crop_blocks, y_crop_blocks;
1258   int ci, i, j, offset_x, offset_y;
1259   JBLOCKARRAY src_buffer, dst_buffer;
1260   JCOEFPTR src_ptr, dst_ptr;
1261   jpeg_component_info *compptr;
1262
1263   MCU_cols = srcinfo->output_height /
1264              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
1265   MCU_rows = srcinfo->output_width /
1266              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
1267
1268   for (ci = 0; ci < dstinfo->num_components; ci++) {
1269     compptr = dstinfo->comp_info + ci;
1270     comp_width = MCU_cols * compptr->h_samp_factor;
1271     comp_height = MCU_rows * compptr->v_samp_factor;
1272     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1273     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1274     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1275          dst_blk_y += compptr->v_samp_factor) {
1276       dst_buffer = (*srcinfo->mem->access_virt_barray)
1277         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1278          (JDIMENSION)compptr->v_samp_factor, TRUE);
1279       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1280         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1281              dst_blk_x += compptr->h_samp_factor) {
1282           if (x_crop_blocks + dst_blk_x < comp_width) {
1283             /* Block is within the mirrorable area. */
1284             src_buffer = (*srcinfo->mem->access_virt_barray)
1285               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1286                comp_width - x_crop_blocks - dst_blk_x -
1287                (JDIMENSION)compptr->h_samp_factor,
1288                (JDIMENSION)compptr->h_samp_factor, FALSE);
1289           } else {
1290             src_buffer = (*srcinfo->mem->access_virt_barray)
1291               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1292                dst_blk_x + x_crop_blocks,
1293                (JDIMENSION)compptr->h_samp_factor, FALSE);
1294           }
1295           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
1296             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
1297             if (y_crop_blocks + dst_blk_y < comp_height) {
1298               if (x_crop_blocks + dst_blk_x < comp_width) {
1299                 /* Block is within the mirrorable area. */
1300                 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
1301                   [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
1302                 for (i = 0; i < DCTSIZE; i++) {
1303                   for (j = 0; j < DCTSIZE; j++) {
1304                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1305                     j++;
1306                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1307                   }
1308                   i++;
1309                   for (j = 0; j < DCTSIZE; j++) {
1310                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1311                     j++;
1312                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1313                   }
1314                 }
1315               } else {
1316                 /* Right-edge blocks are mirrored in y only */
1317                 src_ptr = src_buffer[offset_x]
1318                   [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
1319                 for (i = 0; i < DCTSIZE; i++) {
1320                   for (j = 0; j < DCTSIZE; j++) {
1321                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1322                     j++;
1323                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1324                   }
1325                 }
1326               }
1327             } else {
1328               if (x_crop_blocks + dst_blk_x < comp_width) {
1329                 /* Bottom-edge blocks are mirrored in x only */
1330                 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
1331                   [dst_blk_y + offset_y + y_crop_blocks];
1332                 for (i = 0; i < DCTSIZE; i++) {
1333                   for (j = 0; j < DCTSIZE; j++)
1334                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1335                   i++;
1336                   for (j = 0; j < DCTSIZE; j++)
1337                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1338                 }
1339               } else {
1340                 /* At lower right corner, just transpose, no mirroring */
1341                 src_ptr = src_buffer[offset_x]
1342                   [dst_blk_y + offset_y + y_crop_blocks];
1343                 for (i = 0; i < DCTSIZE; i++)
1344                   for (j = 0; j < DCTSIZE; j++)
1345                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1346               }
1347             }
1348           }
1349         }
1350       }
1351     }
1352   }
1353 }
1354
1355
1356 /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
1357  * Returns TRUE if valid integer found, FALSE if not.
1358  * *strptr is advanced over the digit string, and *result is set to its value.
1359  */
1360
1361 LOCAL(boolean)
1362 jt_read_integer(const char **strptr, JDIMENSION *result)
1363 {
1364   const char *ptr = *strptr;
1365   JDIMENSION val = 0;
1366
1367   for (; isdigit(*ptr); ptr++) {
1368     val = val * 10 + (JDIMENSION)(*ptr - '0');
1369   }
1370   *result = val;
1371   if (ptr == *strptr)
1372     return FALSE;               /* oops, no digits */
1373   *strptr = ptr;
1374   return TRUE;
1375 }
1376
1377
1378 /* Parse a crop specification (written in X11 geometry style).
1379  * The routine returns TRUE if the spec string is valid, FALSE if not.
1380  *
1381  * The crop spec string should have the format
1382  *      <width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset>
1383  * where width, height, xoffset, and yoffset are unsigned integers.
1384  * Each of the elements can be omitted to indicate a default value.
1385  * (A weakness of this style is that it is not possible to omit xoffset
1386  * while specifying yoffset, since they look alike.)
1387  *
1388  * This code is loosely based on XParseGeometry from the X11 distribution.
1389  */
1390
1391 GLOBAL(boolean)
1392 jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
1393 {
1394   info->crop = FALSE;
1395   info->crop_width_set = JCROP_UNSET;
1396   info->crop_height_set = JCROP_UNSET;
1397   info->crop_xoffset_set = JCROP_UNSET;
1398   info->crop_yoffset_set = JCROP_UNSET;
1399
1400   if (isdigit(*spec)) {
1401     /* fetch width */
1402     if (!jt_read_integer(&spec, &info->crop_width))
1403       return FALSE;
1404     if (*spec == 'f' || *spec == 'F') {
1405       spec++;
1406       info->crop_width_set = JCROP_FORCE;
1407     } else if (*spec == 'r' || *spec == 'R') {
1408       spec++;
1409       info->crop_width_set = JCROP_REFLECT;
1410     } else
1411       info->crop_width_set = JCROP_POS;
1412   }
1413   if (*spec == 'x' || *spec == 'X') {
1414     /* fetch height */
1415     spec++;
1416     if (!jt_read_integer(&spec, &info->crop_height))
1417       return FALSE;
1418     if (*spec == 'f' || *spec == 'F') {
1419       spec++;
1420       info->crop_height_set = JCROP_FORCE;
1421     } else if (*spec == 'r' || *spec == 'R') {
1422       spec++;
1423       info->crop_height_set = JCROP_REFLECT;
1424     } else
1425       info->crop_height_set = JCROP_POS;
1426   }
1427   if (*spec == '+' || *spec == '-') {
1428     /* fetch xoffset */
1429     info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
1430     spec++;
1431     if (!jt_read_integer(&spec, &info->crop_xoffset))
1432       return FALSE;
1433   }
1434   if (*spec == '+' || *spec == '-') {
1435     /* fetch yoffset */
1436     info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
1437     spec++;
1438     if (!jt_read_integer(&spec, &info->crop_yoffset))
1439       return FALSE;
1440   }
1441   /* We had better have gotten to the end of the string. */
1442   if (*spec != '\0')
1443     return FALSE;
1444   info->crop = TRUE;
1445   return TRUE;
1446 }
1447
1448
1449 /* Trim off any partial iMCUs on the indicated destination edge */
1450
1451 LOCAL(void)
1452 trim_right_edge(jpeg_transform_info *info, JDIMENSION full_width)
1453 {
1454   JDIMENSION MCU_cols;
1455
1456   MCU_cols = info->output_width / info->iMCU_sample_width;
1457   if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
1458       full_width / info->iMCU_sample_width)
1459     info->output_width = MCU_cols * info->iMCU_sample_width;
1460 }
1461
1462 LOCAL(void)
1463 trim_bottom_edge(jpeg_transform_info *info, JDIMENSION full_height)
1464 {
1465   JDIMENSION MCU_rows;
1466
1467   MCU_rows = info->output_height / info->iMCU_sample_height;
1468   if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
1469       full_height / info->iMCU_sample_height)
1470     info->output_height = MCU_rows * info->iMCU_sample_height;
1471 }
1472
1473
1474 /* Request any required workspace.
1475  *
1476  * This routine figures out the size that the output image will be
1477  * (which implies that all the transform parameters must be set before
1478  * it is called).
1479  *
1480  * We allocate the workspace virtual arrays from the source decompression
1481  * object, so that all the arrays (both the original data and the workspace)
1482  * will be taken into account while making memory management decisions.
1483  * Hence, this routine must be called after jpeg_read_header (which reads
1484  * the image dimensions) and before jpeg_read_coefficients (which realizes
1485  * the source's virtual arrays).
1486  *
1487  * This function returns FALSE right away if -perfect is given
1488  * and transformation is not perfect.  Otherwise returns TRUE.
1489  */
1490
1491 GLOBAL(boolean)
1492 jtransform_request_workspace(j_decompress_ptr srcinfo,
1493                              jpeg_transform_info *info)
1494 {
1495   jvirt_barray_ptr *coef_arrays;
1496   boolean need_workspace, transpose_it;
1497   jpeg_component_info *compptr;
1498   JDIMENSION xoffset, yoffset, dtemp;
1499   JDIMENSION width_in_iMCUs, height_in_iMCUs;
1500   JDIMENSION width_in_blocks, height_in_blocks;
1501   int itemp, ci, h_samp_factor, v_samp_factor;
1502
1503   /* Determine number of components in output image */
1504   if (info->force_grayscale &&
1505       srcinfo->jpeg_color_space == JCS_YCbCr &&
1506       srcinfo->num_components == 3)
1507     /* We'll only process the first component */
1508     info->num_components = 1;
1509   else
1510     /* Process all the components */
1511     info->num_components = srcinfo->num_components;
1512
1513   /* Compute output image dimensions and related values. */
1514 #if JPEG_LIB_VERSION >= 80
1515   jpeg_core_output_dimensions(srcinfo);
1516 #else
1517   srcinfo->output_width = srcinfo->image_width;
1518   srcinfo->output_height = srcinfo->image_height;
1519 #endif
1520
1521   /* Return right away if -perfect is given and transformation is not perfect.
1522    */
1523   if (info->perfect) {
1524     if (info->num_components == 1) {
1525       if (!jtransform_perfect_transform(srcinfo->output_width,
1526           srcinfo->output_height,
1527           srcinfo->_min_DCT_h_scaled_size,
1528           srcinfo->_min_DCT_v_scaled_size,
1529           info->transform))
1530         return FALSE;
1531     } else {
1532       if (!jtransform_perfect_transform(srcinfo->output_width,
1533           srcinfo->output_height,
1534           srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size,
1535           srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size,
1536           info->transform))
1537         return FALSE;
1538     }
1539   }
1540
1541   /* If there is only one output component, force the iMCU size to be 1;
1542    * else use the source iMCU size.  (This allows us to do the right thing
1543    * when reducing color to grayscale, and also provides a handy way of
1544    * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
1545    */
1546   switch (info->transform) {
1547   case JXFORM_TRANSPOSE:
1548   case JXFORM_TRANSVERSE:
1549   case JXFORM_ROT_90:
1550   case JXFORM_ROT_270:
1551     info->output_width = srcinfo->output_height;
1552     info->output_height = srcinfo->output_width;
1553     if (info->num_components == 1) {
1554       info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size;
1555       info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size;
1556     } else {
1557       info->iMCU_sample_width =
1558         srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
1559       info->iMCU_sample_height =
1560         srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
1561     }
1562     break;
1563   default:
1564     info->output_width = srcinfo->output_width;
1565     info->output_height = srcinfo->output_height;
1566     if (info->num_components == 1) {
1567       info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size;
1568       info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size;
1569     } else {
1570       info->iMCU_sample_width =
1571         srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
1572       info->iMCU_sample_height =
1573         srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
1574     }
1575     break;
1576   }
1577
1578   /* If cropping has been requested, compute the crop area's position and
1579    * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
1580    */
1581   if (info->crop) {
1582     /* Insert default values for unset crop parameters */
1583     if (info->crop_xoffset_set == JCROP_UNSET)
1584       info->crop_xoffset = 0;   /* default to +0 */
1585     if (info->crop_yoffset_set == JCROP_UNSET)
1586       info->crop_yoffset = 0;   /* default to +0 */
1587     if (info->crop_width_set == JCROP_UNSET) {
1588       if (info->crop_xoffset >= info->output_width)
1589         ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1590       info->crop_width = info->output_width - info->crop_xoffset;
1591     } else {
1592       /* Check for crop extension */
1593       if (info->crop_width > info->output_width) {
1594         /* Crop extension does not work when transforming! */
1595         if (info->transform != JXFORM_NONE ||
1596             info->crop_xoffset >= info->crop_width ||
1597             info->crop_xoffset > info->crop_width - info->output_width)
1598           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1599       } else {
1600         if (info->crop_xoffset >= info->output_width ||
1601             info->crop_width <= 0 ||
1602             info->crop_xoffset > info->output_width - info->crop_width)
1603           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1604       }
1605     }
1606     if (info->crop_height_set == JCROP_UNSET) {
1607       if (info->crop_yoffset >= info->output_height)
1608         ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1609       info->crop_height = info->output_height - info->crop_yoffset;
1610     } else {
1611       /* Check for crop extension */
1612       if (info->crop_height > info->output_height) {
1613         /* Crop extension does not work when transforming! */
1614         if (info->transform != JXFORM_NONE ||
1615             info->crop_yoffset >= info->crop_height ||
1616             info->crop_yoffset > info->crop_height - info->output_height)
1617           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1618       } else {
1619         if (info->crop_yoffset >= info->output_height ||
1620             info->crop_height <= 0 ||
1621             info->crop_yoffset > info->output_height - info->crop_height)
1622           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1623       }
1624     }
1625     /* Convert negative crop offsets into regular offsets */
1626     if (info->crop_xoffset_set != JCROP_NEG)
1627       xoffset = info->crop_xoffset;
1628     else if (info->crop_width > info->output_width) /* crop extension */
1629       xoffset = info->crop_width - info->output_width - info->crop_xoffset;
1630     else
1631       xoffset = info->output_width - info->crop_width - info->crop_xoffset;
1632     if (info->crop_yoffset_set != JCROP_NEG)
1633       yoffset = info->crop_yoffset;
1634     else if (info->crop_height > info->output_height) /* crop extension */
1635       yoffset = info->crop_height - info->output_height - info->crop_yoffset;
1636     else
1637       yoffset = info->output_height - info->crop_height - info->crop_yoffset;
1638     /* Now adjust so that upper left corner falls at an iMCU boundary */
1639     switch (info->transform) {
1640     case JXFORM_DROP:
1641       /* Ensure the effective drop region will not exceed the requested */
1642       itemp = info->iMCU_sample_width;
1643       dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp);
1644       xoffset += dtemp;
1645       if (info->crop_width <= dtemp)
1646         info->drop_width = 0;
1647       else if (xoffset + info->crop_width - dtemp == info->output_width)
1648         /* Matching right edge: include partial iMCU */
1649         info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp;
1650       else
1651         info->drop_width = (info->crop_width - dtemp) / itemp;
1652       itemp = info->iMCU_sample_height;
1653       dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp);
1654       yoffset += dtemp;
1655       if (info->crop_height <= dtemp)
1656         info->drop_height = 0;
1657       else if (yoffset + info->crop_height - dtemp == info->output_height)
1658         /* Matching bottom edge: include partial iMCU */
1659         info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp;
1660       else
1661         info->drop_height = (info->crop_height - dtemp) / itemp;
1662       /* Check if sampling factors match for dropping */
1663       if (info->drop_width != 0 && info->drop_height != 0)
1664         for (ci = 0; ci < info->num_components &&
1665                      ci < info->drop_ptr->num_components; ci++) {
1666           if (info->drop_ptr->comp_info[ci].h_samp_factor *
1667               srcinfo->max_h_samp_factor !=
1668               srcinfo->comp_info[ci].h_samp_factor *
1669               info->drop_ptr->max_h_samp_factor)
1670             ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
1671               info->drop_ptr->comp_info[ci].h_samp_factor,
1672               info->drop_ptr->max_h_samp_factor,
1673               srcinfo->comp_info[ci].h_samp_factor,
1674               srcinfo->max_h_samp_factor, 'h');
1675           if (info->drop_ptr->comp_info[ci].v_samp_factor *
1676               srcinfo->max_v_samp_factor !=
1677               srcinfo->comp_info[ci].v_samp_factor *
1678               info->drop_ptr->max_v_samp_factor)
1679             ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
1680               info->drop_ptr->comp_info[ci].v_samp_factor,
1681               info->drop_ptr->max_v_samp_factor,
1682               srcinfo->comp_info[ci].v_samp_factor,
1683               srcinfo->max_v_samp_factor, 'v');
1684         }
1685       break;
1686     case JXFORM_WIPE:
1687       /* Ensure the effective wipe region will cover the requested */
1688       info->drop_width = (JDIMENSION)jdiv_round_up
1689         ((long)(info->crop_width + (xoffset % info->iMCU_sample_width)),
1690          (long)info->iMCU_sample_width);
1691       info->drop_height = (JDIMENSION)jdiv_round_up
1692         ((long)(info->crop_height + (yoffset % info->iMCU_sample_height)),
1693          (long)info->iMCU_sample_height);
1694       break;
1695     default:
1696       /* Ensure the effective crop region will cover the requested */
1697       if (info->crop_width_set == JCROP_FORCE ||
1698           info->crop_width > info->output_width)
1699         info->output_width = info->crop_width;
1700       else
1701         info->output_width =
1702           info->crop_width + (xoffset % info->iMCU_sample_width);
1703       if (info->crop_height_set == JCROP_FORCE ||
1704           info->crop_height > info->output_height)
1705         info->output_height = info->crop_height;
1706       else
1707         info->output_height =
1708           info->crop_height + (yoffset % info->iMCU_sample_height);
1709     }
1710     /* Save x/y offsets measured in iMCUs */
1711     info->x_crop_offset = xoffset / info->iMCU_sample_width;
1712     info->y_crop_offset = yoffset / info->iMCU_sample_height;
1713   } else {
1714     info->x_crop_offset = 0;
1715     info->y_crop_offset = 0;
1716   }
1717
1718   /* Figure out whether we need workspace arrays,
1719    * and if so whether they are transposed relative to the source.
1720    */
1721   need_workspace = FALSE;
1722   transpose_it = FALSE;
1723   switch (info->transform) {
1724   case JXFORM_NONE:
1725     if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||
1726         info->output_width > srcinfo->output_width ||
1727         info->output_height > srcinfo->output_height)
1728       need_workspace = TRUE;
1729     /* No workspace needed if neither cropping nor transforming */
1730     break;
1731   case JXFORM_FLIP_H:
1732     if (info->trim)
1733       trim_right_edge(info, srcinfo->output_width);
1734     if (info->y_crop_offset != 0 || info->slow_hflip)
1735       need_workspace = TRUE;
1736     /* do_flip_h_no_crop doesn't need a workspace array */
1737     break;
1738   case JXFORM_FLIP_V:
1739     if (info->trim)
1740       trim_bottom_edge(info, srcinfo->output_height);
1741     /* Need workspace arrays having same dimensions as source image. */
1742     need_workspace = TRUE;
1743     break;
1744   case JXFORM_TRANSPOSE:
1745     /* transpose does NOT have to trim anything */
1746     /* Need workspace arrays having transposed dimensions. */
1747     need_workspace = TRUE;
1748     transpose_it = TRUE;
1749     break;
1750   case JXFORM_TRANSVERSE:
1751     if (info->trim) {
1752       trim_right_edge(info, srcinfo->output_height);
1753       trim_bottom_edge(info, srcinfo->output_width);
1754     }
1755     /* Need workspace arrays having transposed dimensions. */
1756     need_workspace = TRUE;
1757     transpose_it = TRUE;
1758     break;
1759   case JXFORM_ROT_90:
1760     if (info->trim)
1761       trim_right_edge(info, srcinfo->output_height);
1762     /* Need workspace arrays having transposed dimensions. */
1763     need_workspace = TRUE;
1764     transpose_it = TRUE;
1765     break;
1766   case JXFORM_ROT_180:
1767     if (info->trim) {
1768       trim_right_edge(info, srcinfo->output_width);
1769       trim_bottom_edge(info, srcinfo->output_height);
1770     }
1771     /* Need workspace arrays having same dimensions as source image. */
1772     need_workspace = TRUE;
1773     break;
1774   case JXFORM_ROT_270:
1775     if (info->trim)
1776       trim_bottom_edge(info, srcinfo->output_width);
1777     /* Need workspace arrays having transposed dimensions. */
1778     need_workspace = TRUE;
1779     transpose_it = TRUE;
1780     break;
1781   case JXFORM_WIPE:
1782     break;
1783   case JXFORM_DROP:
1784     break;
1785   }
1786
1787   /* Allocate workspace if needed.
1788    * Note that we allocate arrays padded out to the next iMCU boundary,
1789    * so that transform routines need not worry about missing edge blocks.
1790    */
1791   if (need_workspace) {
1792     coef_arrays = (jvirt_barray_ptr *)
1793       (*srcinfo->mem->alloc_small) ((j_common_ptr)srcinfo, JPOOL_IMAGE,
1794                 sizeof(jvirt_barray_ptr) * info->num_components);
1795     width_in_iMCUs = (JDIMENSION)
1796       jdiv_round_up((long)info->output_width, (long)info->iMCU_sample_width);
1797     height_in_iMCUs = (JDIMENSION)
1798       jdiv_round_up((long)info->output_height, (long)info->iMCU_sample_height);
1799     for (ci = 0; ci < info->num_components; ci++) {
1800       compptr = srcinfo->comp_info + ci;
1801       if (info->num_components == 1) {
1802         /* we're going to force samp factors to 1x1 in this case */
1803         h_samp_factor = v_samp_factor = 1;
1804       } else if (transpose_it) {
1805         h_samp_factor = compptr->v_samp_factor;
1806         v_samp_factor = compptr->h_samp_factor;
1807       } else {
1808         h_samp_factor = compptr->h_samp_factor;
1809         v_samp_factor = compptr->v_samp_factor;
1810       }
1811       width_in_blocks = width_in_iMCUs * h_samp_factor;
1812       height_in_blocks = height_in_iMCUs * v_samp_factor;
1813       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1814         ((j_common_ptr)srcinfo, JPOOL_IMAGE, FALSE,
1815          width_in_blocks, height_in_blocks, (JDIMENSION)v_samp_factor);
1816     }
1817     info->workspace_coef_arrays = coef_arrays;
1818   } else
1819     info->workspace_coef_arrays = NULL;
1820
1821   return TRUE;
1822 }
1823
1824
1825 /* Transpose destination image parameters */
1826
1827 LOCAL(void)
1828 transpose_critical_parameters(j_compress_ptr dstinfo)
1829 {
1830   int tblno, i, j, ci, itemp;
1831   jpeg_component_info *compptr;
1832   JQUANT_TBL *qtblptr;
1833   JDIMENSION jtemp;
1834   UINT16 qtemp;
1835
1836   /* Transpose image dimensions */
1837   jtemp = dstinfo->image_width;
1838   dstinfo->image_width = dstinfo->image_height;
1839   dstinfo->image_height = jtemp;
1840 #if JPEG_LIB_VERSION >= 70
1841   itemp = dstinfo->min_DCT_h_scaled_size;
1842   dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
1843   dstinfo->min_DCT_v_scaled_size = itemp;
1844 #endif
1845
1846   /* Transpose sampling factors */
1847   for (ci = 0; ci < dstinfo->num_components; ci++) {
1848     compptr = dstinfo->comp_info + ci;
1849     itemp = compptr->h_samp_factor;
1850     compptr->h_samp_factor = compptr->v_samp_factor;
1851     compptr->v_samp_factor = itemp;
1852   }
1853
1854   /* Transpose quantization tables */
1855   for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
1856     qtblptr = dstinfo->quant_tbl_ptrs[tblno];
1857     if (qtblptr != NULL) {
1858       for (i = 0; i < DCTSIZE; i++) {
1859         for (j = 0; j < i; j++) {
1860           qtemp = qtblptr->quantval[i * DCTSIZE + j];
1861           qtblptr->quantval[i * DCTSIZE + j] =
1862             qtblptr->quantval[j * DCTSIZE + i];
1863           qtblptr->quantval[j * DCTSIZE + i] = qtemp;
1864         }
1865       }
1866     }
1867   }
1868 }
1869
1870
1871 /* Adjust Exif image parameters.
1872  *
1873  * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1874  */
1875
1876 LOCAL(void)
1877 adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
1878                        JDIMENSION new_height)
1879 {
1880   boolean is_motorola; /* Flag for byte order */
1881   unsigned int number_of_tags, tagnum;
1882   unsigned int firstoffset, offset;
1883   JDIMENSION new_value;
1884
1885   if (length < 12) return; /* Length of an IFD entry */
1886
1887   /* Discover byte order */
1888   if (data[0] == 0x49 && data[1] == 0x49)
1889     is_motorola = FALSE;
1890   else if (data[0] == 0x4D && data[1] == 0x4D)
1891     is_motorola = TRUE;
1892   else
1893     return;
1894
1895   /* Check Tag Mark */
1896   if (is_motorola) {
1897     if (data[2] != 0) return;
1898     if (data[3] != 0x2A) return;
1899   } else {
1900     if (data[3] != 0) return;
1901     if (data[2] != 0x2A) return;
1902   }
1903
1904   /* Get first IFD offset (offset to IFD0) */
1905   if (is_motorola) {
1906     if (data[4] != 0) return;
1907     if (data[5] != 0) return;
1908     firstoffset = data[6];
1909     firstoffset <<= 8;
1910     firstoffset += data[7];
1911   } else {
1912     if (data[7] != 0) return;
1913     if (data[6] != 0) return;
1914     firstoffset = data[5];
1915     firstoffset <<= 8;
1916     firstoffset += data[4];
1917   }
1918   if (firstoffset > length - 2) return; /* check end of data segment */
1919
1920   /* Get the number of directory entries contained in this IFD */
1921   if (is_motorola) {
1922     number_of_tags = data[firstoffset];
1923     number_of_tags <<= 8;
1924     number_of_tags += data[firstoffset + 1];
1925   } else {
1926     number_of_tags = data[firstoffset + 1];
1927     number_of_tags <<= 8;
1928     number_of_tags += data[firstoffset];
1929   }
1930   if (number_of_tags == 0) return;
1931   firstoffset += 2;
1932
1933   /* Search for ExifSubIFD offset Tag in IFD0 */
1934   for (;;) {
1935     if (firstoffset > length - 12) return; /* check end of data segment */
1936     /* Get Tag number */
1937     if (is_motorola) {
1938       tagnum = data[firstoffset];
1939       tagnum <<= 8;
1940       tagnum += data[firstoffset + 1];
1941     } else {
1942       tagnum = data[firstoffset + 1];
1943       tagnum <<= 8;
1944       tagnum += data[firstoffset];
1945     }
1946     if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1947     if (--number_of_tags == 0) return;
1948     firstoffset += 12;
1949   }
1950
1951   /* Get the ExifSubIFD offset */
1952   if (is_motorola) {
1953     if (data[firstoffset + 8] != 0) return;
1954     if (data[firstoffset + 9] != 0) return;
1955     offset = data[firstoffset + 10];
1956     offset <<= 8;
1957     offset += data[firstoffset + 11];
1958   } else {
1959     if (data[firstoffset + 11] != 0) return;
1960     if (data[firstoffset + 10] != 0) return;
1961     offset = data[firstoffset + 9];
1962     offset <<= 8;
1963     offset += data[firstoffset + 8];
1964   }
1965   if (offset > length - 2) return; /* check end of data segment */
1966
1967   /* Get the number of directory entries contained in this SubIFD */
1968   if (is_motorola) {
1969     number_of_tags = data[offset];
1970     number_of_tags <<= 8;
1971     number_of_tags += data[offset + 1];
1972   } else {
1973     number_of_tags = data[offset + 1];
1974     number_of_tags <<= 8;
1975     number_of_tags += data[offset];
1976   }
1977   if (number_of_tags < 2) return;
1978   offset += 2;
1979
1980   /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1981   do {
1982     if (offset > length - 12) return; /* check end of data segment */
1983     /* Get Tag number */
1984     if (is_motorola) {
1985       tagnum = data[offset];
1986       tagnum <<= 8;
1987       tagnum += data[offset + 1];
1988     } else {
1989       tagnum = data[offset + 1];
1990       tagnum <<= 8;
1991       tagnum += data[offset];
1992     }
1993     if (tagnum == 0xA002 || tagnum == 0xA003) {
1994       if (tagnum == 0xA002)
1995         new_value = new_width; /* ExifImageWidth Tag */
1996       else
1997         new_value = new_height; /* ExifImageHeight Tag */
1998       if (is_motorola) {
1999         data[offset + 2] = 0; /* Format = unsigned long (4 octets) */
2000         data[offset + 3] = 4;
2001         data[offset + 4] = 0; /* Number Of Components = 1 */
2002         data[offset + 5] = 0;
2003         data[offset + 6] = 0;
2004         data[offset + 7] = 1;
2005         data[offset + 8] = 0;
2006         data[offset + 9] = 0;
2007         data[offset + 10] = (JOCTET)((new_value >> 8) & 0xFF);
2008         data[offset + 11] = (JOCTET)(new_value & 0xFF);
2009       } else {
2010         data[offset + 2] = 4; /* Format = unsigned long (4 octets) */
2011         data[offset + 3] = 0;
2012         data[offset + 4] = 1; /* Number Of Components = 1 */
2013         data[offset + 5] = 0;
2014         data[offset + 6] = 0;
2015         data[offset + 7] = 0;
2016         data[offset + 8] = (JOCTET)(new_value & 0xFF);
2017         data[offset + 9] = (JOCTET)((new_value >> 8) & 0xFF);
2018         data[offset + 10] = 0;
2019         data[offset + 11] = 0;
2020       }
2021     }
2022     offset += 12;
2023   } while (--number_of_tags);
2024 }
2025
2026
2027 /* Adjust output image parameters as needed.
2028  *
2029  * This must be called after jpeg_copy_critical_parameters()
2030  * and before jpeg_write_coefficients().
2031  *
2032  * The return value is the set of virtual coefficient arrays to be written
2033  * (either the ones allocated by jtransform_request_workspace, or the
2034  * original source data arrays).  The caller will need to pass this value
2035  * to jpeg_write_coefficients().
2036  */
2037
2038 GLOBAL(jvirt_barray_ptr *)
2039 jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2040                              jvirt_barray_ptr *src_coef_arrays,
2041                              jpeg_transform_info *info)
2042 {
2043   /* If force-to-grayscale is requested, adjust destination parameters */
2044   if (info->force_grayscale) {
2045     /* First, ensure we have YCbCr or grayscale data, and that the source's
2046      * Y channel is full resolution.  (No reasonable person would make Y
2047      * be less than full resolution, so actually coping with that case
2048      * isn't worth extra code space.  But we check it to avoid crashing.)
2049      */
2050     if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
2051           dstinfo->num_components == 3) ||
2052          (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
2053           dstinfo->num_components == 1)) &&
2054         srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
2055         srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
2056       /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
2057        * properly.  Among other things, it sets the target h_samp_factor &
2058        * v_samp_factor to 1, which typically won't match the source.
2059        * We have to preserve the source's quantization table number, however.
2060        */
2061       int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
2062       jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
2063       dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
2064     } else {
2065       /* Sorry, can't do it */
2066       ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
2067     }
2068   } else if (info->num_components == 1) {
2069     /* For a single-component source, we force the destination sampling factors
2070      * to 1x1, with or without force_grayscale.  This is useful because some
2071      * decoders choke on grayscale images with other sampling factors.
2072      */
2073     dstinfo->comp_info[0].h_samp_factor = 1;
2074     dstinfo->comp_info[0].v_samp_factor = 1;
2075   }
2076
2077   /* Correct the destination's image dimensions as necessary
2078    * for rotate/flip, resize, and crop operations.
2079    */
2080 #if JPEG_LIB_VERSION >= 80
2081   dstinfo->jpeg_width = info->output_width;
2082   dstinfo->jpeg_height = info->output_height;
2083 #endif
2084
2085   /* Transpose destination image parameters, adjust quantization */
2086   switch (info->transform) {
2087   case JXFORM_TRANSPOSE:
2088   case JXFORM_TRANSVERSE:
2089   case JXFORM_ROT_90:
2090   case JXFORM_ROT_270:
2091 #if JPEG_LIB_VERSION < 80
2092     dstinfo->image_width = info->output_height;
2093     dstinfo->image_height = info->output_width;
2094 #endif
2095     transpose_critical_parameters(dstinfo);
2096     break;
2097   case JXFORM_DROP:
2098     if (info->drop_width != 0 && info->drop_height != 0)
2099       adjust_quant(srcinfo, src_coef_arrays,
2100                    info->drop_ptr, info->drop_coef_arrays,
2101                    info->trim, dstinfo);
2102     break;
2103   default:
2104 #if JPEG_LIB_VERSION < 80
2105     dstinfo->image_width = info->output_width;
2106     dstinfo->image_height = info->output_height;
2107 #endif
2108     break;
2109   }
2110
2111   /* Adjust Exif properties */
2112   if (srcinfo->marker_list != NULL &&
2113       srcinfo->marker_list->marker == JPEG_APP0 + 1 &&
2114       srcinfo->marker_list->data_length >= 6 &&
2115       srcinfo->marker_list->data[0] == 0x45 &&
2116       srcinfo->marker_list->data[1] == 0x78 &&
2117       srcinfo->marker_list->data[2] == 0x69 &&
2118       srcinfo->marker_list->data[3] == 0x66 &&
2119       srcinfo->marker_list->data[4] == 0 &&
2120       srcinfo->marker_list->data[5] == 0) {
2121     /* Suppress output of JFIF marker */
2122     dstinfo->write_JFIF_header = FALSE;
2123     /* Adjust Exif image parameters */
2124 #if JPEG_LIB_VERSION >= 80
2125     if (dstinfo->jpeg_width != srcinfo->image_width ||
2126         dstinfo->jpeg_height != srcinfo->image_height)
2127       /* Align data segment to start of TIFF structure for parsing */
2128       adjust_exif_parameters(srcinfo->marker_list->data + 6,
2129                              srcinfo->marker_list->data_length - 6,
2130                              dstinfo->jpeg_width, dstinfo->jpeg_height);
2131 #else
2132     if (dstinfo->image_width != srcinfo->image_width ||
2133         dstinfo->image_height != srcinfo->image_height)
2134       /* Align data segment to start of TIFF structure for parsing */
2135       adjust_exif_parameters(srcinfo->marker_list->data + 6,
2136                              srcinfo->marker_list->data_length - 6,
2137                              dstinfo->image_width, dstinfo->image_height);
2138 #endif
2139   }
2140
2141   /* Return the appropriate output data set */
2142   if (info->workspace_coef_arrays != NULL)
2143     return info->workspace_coef_arrays;
2144   return src_coef_arrays;
2145 }
2146
2147
2148 /* Execute the actual transformation, if any.
2149  *
2150  * This must be called *after* jpeg_write_coefficients, because it depends
2151  * on jpeg_write_coefficients to have computed subsidiary values such as
2152  * the per-component width and height fields in the destination object.
2153  *
2154  * Note that some transformations will modify the source data arrays!
2155  */
2156
2157 GLOBAL(void)
2158 jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2159                              jvirt_barray_ptr *src_coef_arrays,
2160                              jpeg_transform_info *info)
2161 {
2162   jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
2163
2164   /* Note: conditions tested here should match those in switch statement
2165    * in jtransform_request_workspace()
2166    */
2167   switch (info->transform) {
2168   case JXFORM_NONE:
2169     if (info->output_width > srcinfo->output_width ||
2170         info->output_height > srcinfo->output_height) {
2171       if (info->output_width > srcinfo->output_width &&
2172           info->crop_width_set == JCROP_REFLECT)
2173         do_crop_ext_reflect(srcinfo, dstinfo,
2174                             info->x_crop_offset, info->y_crop_offset,
2175                             src_coef_arrays, dst_coef_arrays);
2176       else if (info->output_width > srcinfo->output_width &&
2177                info->crop_width_set == JCROP_FORCE)
2178         do_crop_ext_flat(srcinfo, dstinfo,
2179                          info->x_crop_offset, info->y_crop_offset,
2180                          src_coef_arrays, dst_coef_arrays);
2181       else
2182         do_crop_ext_zero(srcinfo, dstinfo,
2183                          info->x_crop_offset, info->y_crop_offset,
2184                          src_coef_arrays, dst_coef_arrays);
2185     } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
2186       do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2187               src_coef_arrays, dst_coef_arrays);
2188     break;
2189   case JXFORM_FLIP_H:
2190     if (info->y_crop_offset != 0 || info->slow_hflip)
2191       do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2192                 src_coef_arrays, dst_coef_arrays);
2193     else
2194       do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
2195                         src_coef_arrays);
2196     break;
2197   case JXFORM_FLIP_V:
2198     do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2199               src_coef_arrays, dst_coef_arrays);
2200     break;
2201   case JXFORM_TRANSPOSE:
2202     do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2203                  src_coef_arrays, dst_coef_arrays);
2204     break;
2205   case JXFORM_TRANSVERSE:
2206     do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2207                   src_coef_arrays, dst_coef_arrays);
2208     break;
2209   case JXFORM_ROT_90:
2210     do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2211               src_coef_arrays, dst_coef_arrays);
2212     break;
2213   case JXFORM_ROT_180:
2214     do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2215                src_coef_arrays, dst_coef_arrays);
2216     break;
2217   case JXFORM_ROT_270:
2218     do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2219                src_coef_arrays, dst_coef_arrays);
2220     break;
2221   case JXFORM_WIPE:
2222     if (info->crop_width_set == JCROP_REFLECT &&
2223         info->y_crop_offset == 0 && info->drop_height ==
2224         (JDIMENSION)jdiv_round_up
2225           ((long)info->output_height, (long)info->iMCU_sample_height) &&
2226         (info->x_crop_offset == 0 ||
2227          info->x_crop_offset + info->drop_width ==
2228          (JDIMENSION)jdiv_round_up
2229            ((long)info->output_width, (long)info->iMCU_sample_width)))
2230       do_reflect(srcinfo, dstinfo, info->x_crop_offset,
2231                  src_coef_arrays, info->drop_width, info->drop_height);
2232     else if (info->crop_width_set == JCROP_FORCE)
2233       do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2234                  src_coef_arrays, info->drop_width, info->drop_height);
2235     else
2236       do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2237               src_coef_arrays, info->drop_width, info->drop_height);
2238     break;
2239   case JXFORM_DROP:
2240     if (info->drop_width != 0 && info->drop_height != 0)
2241       do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2242               src_coef_arrays, info->drop_ptr, info->drop_coef_arrays,
2243               info->drop_width, info->drop_height);
2244     break;
2245   }
2246 }
2247
2248 /* jtransform_perfect_transform
2249  *
2250  * Determine whether lossless transformation is perfectly
2251  * possible for a specified image and transformation.
2252  *
2253  * Inputs:
2254  *   image_width, image_height: source image dimensions.
2255  *   MCU_width, MCU_height: pixel dimensions of MCU.
2256  *   transform: transformation identifier.
2257  * Parameter sources from initialized jpeg_struct
2258  * (after reading source header):
2259  *   image_width = cinfo.image_width
2260  *   image_height = cinfo.image_height
2261  *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
2262  *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
2263  * Result:
2264  *   TRUE = perfect transformation possible
2265  *   FALSE = perfect transformation not possible
2266  *           (may use custom action then)
2267  */
2268
2269 GLOBAL(boolean)
2270 jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
2271                              int MCU_width, int MCU_height,
2272                              JXFORM_CODE transform)
2273 {
2274   boolean result = TRUE; /* initialize TRUE */
2275
2276   switch (transform) {
2277   case JXFORM_FLIP_H:
2278   case JXFORM_ROT_270:
2279     if (image_width % (JDIMENSION)MCU_width)
2280       result = FALSE;
2281     break;
2282   case JXFORM_FLIP_V:
2283   case JXFORM_ROT_90:
2284     if (image_height % (JDIMENSION)MCU_height)
2285       result = FALSE;
2286     break;
2287   case JXFORM_TRANSVERSE:
2288   case JXFORM_ROT_180:
2289     if (image_width % (JDIMENSION)MCU_width)
2290       result = FALSE;
2291     if (image_height % (JDIMENSION)MCU_height)
2292       result = FALSE;
2293     break;
2294   default:
2295     break;
2296   }
2297
2298   return result;
2299 }
2300
2301 #endif /* TRANSFORMS_SUPPORTED */
2302
2303
2304 /* Setup decompression object to save desired markers in memory.
2305  * This must be called before jpeg_read_header() to have the desired effect.
2306  */
2307
2308 GLOBAL(void)
2309 jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option)
2310 {
2311 #ifdef SAVE_MARKERS_SUPPORTED
2312   int m;
2313
2314   /* Save comments except under NONE option */
2315   if (option != JCOPYOPT_NONE && option != JCOPYOPT_ICC) {
2316     jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
2317   }
2318   /* Save all types of APPn markers iff ALL option */
2319   if (option == JCOPYOPT_ALL || option == JCOPYOPT_ALL_EXCEPT_ICC) {
2320     for (m = 0; m < 16; m++) {
2321       if (option == JCOPYOPT_ALL_EXCEPT_ICC && m == 2)
2322         continue;
2323       jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
2324     }
2325   }
2326   /* Save only APP2 markers if ICC option selected */
2327   if (option == JCOPYOPT_ICC) {
2328     jpeg_save_markers(srcinfo, JPEG_APP0 + 2, 0xFFFF);
2329   }
2330 #endif /* SAVE_MARKERS_SUPPORTED */
2331 }
2332
2333 /* Copy markers saved in the given source object to the destination object.
2334  * This should be called just after jpeg_start_compress() or
2335  * jpeg_write_coefficients().
2336  * Note that those routines will have written the SOI, and also the
2337  * JFIF APP0 or Adobe APP14 markers if selected.
2338  */
2339
2340 GLOBAL(void)
2341 jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2342                       JCOPY_OPTION option)
2343 {
2344   jpeg_saved_marker_ptr marker;
2345
2346   /* In the current implementation, we don't actually need to examine the
2347    * option flag here; we just copy everything that got saved.
2348    * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
2349    * if the encoder library already wrote one.
2350    */
2351   for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
2352     if (dstinfo->write_JFIF_header &&
2353         marker->marker == JPEG_APP0 &&
2354         marker->data_length >= 5 &&
2355         marker->data[0] == 0x4A &&
2356         marker->data[1] == 0x46 &&
2357         marker->data[2] == 0x49 &&
2358         marker->data[3] == 0x46 &&
2359         marker->data[4] == 0)
2360       continue;                 /* reject duplicate JFIF */
2361     if (dstinfo->write_Adobe_marker &&
2362         marker->marker == JPEG_APP0 + 14 &&
2363         marker->data_length >= 5 &&
2364         marker->data[0] == 0x41 &&
2365         marker->data[1] == 0x64 &&
2366         marker->data[2] == 0x6F &&
2367         marker->data[3] == 0x62 &&
2368         marker->data[4] == 0x65)
2369       continue;                 /* reject duplicate Adobe */
2370     jpeg_write_marker(dstinfo, marker->marker,
2371                       marker->data, marker->data_length);
2372   }
2373 }