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, 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)
dequant_comp(j_decompress_ptr cinfo,jpeg_component_info * compptr,jvirt_barray_ptr coef_array,JQUANT_TBL * qtblptr1)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)
requant_comp(j_decompress_ptr cinfo,jpeg_component_info * compptr,jvirt_barray_ptr coef_array,JQUANT_TBL * qtblptr1)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)
largest_common_denominator(JCOEF a,JCOEF b)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)
adjust_quant(j_decompress_ptr srcinfo,jvirt_barray_ptr * src_coef_arrays,j_decompress_ptr dropinfo,jvirt_barray_ptr * drop_coef_arrays,boolean trim,j_compress_ptr dstinfo)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)
do_drop(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,j_decompress_ptr dropinfo,jvirt_barray_ptr * drop_coef_arrays,JDIMENSION drop_width,JDIMENSION drop_height)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           MEMZERO(dst_buffer[offset_y] + x_drop_blocks,
266                   comp_width * sizeof(JBLOCK));
267         }
268       }
269     }
270   }
271 }
272 
273 
274 LOCAL(void)
do_crop(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)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)
do_crop_ext_zero(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)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             MEMZERO(dst_buffer[offset_y],
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             MEMZERO(dst_buffer[offset_y], 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             MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
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)
do_crop_ext_flat(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)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             MEMZERO(dst_buffer[offset_y],
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           MEMZERO(dst_buffer[offset_y], 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           MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
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)
do_crop_ext_reflect(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)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             MEMZERO(dst_buffer[offset_y],
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)
do_wipe(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,JDIMENSION drop_width,JDIMENSION drop_height)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         MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
595       }
596     }
597   }
598 }
599 
600 
601 LOCAL(void)
do_flatten(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,JDIMENSION drop_width,JDIMENSION drop_height)602 do_flatten(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
603            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
604            jvirt_barray_ptr *src_coef_arrays,
605            JDIMENSION drop_width, JDIMENSION drop_height)
606 /* Flatten - discard image contents of specified region, similarly to wipe,
607  * but fill with the average of adjacent blocks instead of zero.
608  */
609 {
610   JDIMENSION x_wipe_blocks, wipe_width, wipe_right;
611   JDIMENSION y_wipe_blocks, wipe_bottom, blk_x;
612   int ci, offset_y, dc_left_value, dc_right_value, average;
613   JBLOCKARRAY buffer;
614   jpeg_component_info *compptr;
615 
616   for (ci = 0; ci < dstinfo->num_components; ci++) {
617     compptr = dstinfo->comp_info + ci;
618     x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
619     wipe_width = drop_width * compptr->h_samp_factor;
620     wipe_right = wipe_width + x_wipe_blocks;
621     y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
622     wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
623     for (; y_wipe_blocks < wipe_bottom;
624          y_wipe_blocks += compptr->v_samp_factor) {
625       buffer = (*srcinfo->mem->access_virt_barray)
626         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
627          (JDIMENSION)compptr->v_samp_factor, TRUE);
628       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
629         MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
630         if (x_wipe_blocks > 0) {
631           dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];
632           if (wipe_right < compptr->width_in_blocks) {
633             dc_right_value = buffer[offset_y][wipe_right][0];
634             average = (dc_left_value + dc_right_value) >> 1;
635           } else {
636             average = dc_left_value;
637           }
638         } else if (wipe_right < compptr->width_in_blocks) {
639           average = buffer[offset_y][wipe_right][0];
640         } else continue;
641         for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) {
642           buffer[offset_y][blk_x][0] = (JCOEF)average;
643         }
644       }
645     }
646   }
647 }
648 
649 
650 LOCAL(void)
do_reflect(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,jvirt_barray_ptr * src_coef_arrays,JDIMENSION drop_width,JDIMENSION drop_height)651 do_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
652            JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays,
653            JDIMENSION drop_width, JDIMENSION drop_height)
654 /* Reflect - discard image contents of specified region, similarly to wipe,
655  * but fill with repeated reflections of the outside region instead of zero.
656  * NB: y_crop_offset is assumed to be zero.
657  */
658 {
659   JDIMENSION x_wipe_blocks, wipe_width;
660   JDIMENSION y_wipe_blocks, wipe_bottom;
661   JDIMENSION src_blk_x, dst_blk_x;
662   int ci, k, offset_y;
663   JBLOCKARRAY buffer;
664   JBLOCKROW src_row_ptr, dst_row_ptr;
665   JCOEFPTR src_ptr, dst_ptr;
666   jpeg_component_info *compptr;
667 
668   for (ci = 0; ci < dstinfo->num_components; ci++) {
669     compptr = dstinfo->comp_info + ci;
670     x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
671     wipe_width = drop_width * compptr->h_samp_factor;
672     wipe_bottom = drop_height * compptr->v_samp_factor;
673     for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom;
674          y_wipe_blocks += compptr->v_samp_factor) {
675       buffer = (*srcinfo->mem->access_virt_barray)
676         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
677          (JDIMENSION)compptr->v_samp_factor, TRUE);
678       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
679         if (x_wipe_blocks > 0) {
680           /* Reflect from left */
681           dst_row_ptr = buffer[offset_y] + x_wipe_blocks;
682           for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
683             src_row_ptr = dst_row_ptr;     /* (re)set axis of reflection */
684             for (src_blk_x = x_wipe_blocks;
685                  src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
686               dst_ptr = *dst_row_ptr++;    /* destination goes right */
687               src_ptr = *(--src_row_ptr);  /* source goes left */
688               /* this unrolled loop doesn't need to know which row it's on... */
689               for (k = 0; k < DCTSIZE2; k += 2) {
690                 *dst_ptr++ = *src_ptr++;   /* copy even column */
691                 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
692               }
693             }
694           }
695         } else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) {
696           /* Reflect from right */
697           dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width;
698           for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
699             src_row_ptr = dst_row_ptr;     /* (re)set axis of reflection */
700             src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width;
701             for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
702               dst_ptr = *(--dst_row_ptr);  /* destination goes left */
703               src_ptr = *src_row_ptr++;    /* source goes right */
704               /* this unrolled loop doesn't need to know which row it's on... */
705               for (k = 0; k < DCTSIZE2; k += 2) {
706                 *dst_ptr++ = *src_ptr++;   /* copy even column */
707                 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
708               }
709             }
710           }
711         } else {
712           MEMZERO(buffer[offset_y] + x_wipe_blocks,
713                   wipe_width * sizeof(JBLOCK));
714         }
715       }
716     }
717   }
718 }
719 
720 
721 LOCAL(void)
do_flip_h_no_crop(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,jvirt_barray_ptr * src_coef_arrays)722 do_flip_h_no_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
723                   JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays)
724 /* Horizontal flip; done in-place, so no separate dest array is required.
725  * NB: this only works when y_crop_offset is zero.
726  */
727 {
728   JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
729   int ci, k, offset_y;
730   JBLOCKARRAY buffer;
731   JCOEFPTR ptr1, ptr2;
732   JCOEF temp1, temp2;
733   jpeg_component_info *compptr;
734 
735   /* Horizontal mirroring of DCT blocks is accomplished by swapping
736    * pairs of blocks in-place.  Within a DCT block, we perform horizontal
737    * mirroring by changing the signs of odd-numbered columns.
738    * Partial iMCUs at the right edge are left untouched.
739    */
740   MCU_cols = srcinfo->output_width /
741              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
742 
743   for (ci = 0; ci < dstinfo->num_components; ci++) {
744     compptr = dstinfo->comp_info + ci;
745     comp_width = MCU_cols * compptr->h_samp_factor;
746     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
747     for (blk_y = 0; blk_y < compptr->height_in_blocks;
748          blk_y += compptr->v_samp_factor) {
749       buffer = (*srcinfo->mem->access_virt_barray)
750         ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y,
751          (JDIMENSION)compptr->v_samp_factor, TRUE);
752       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
753         /* Do the mirroring */
754         for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
755           ptr1 = buffer[offset_y][blk_x];
756           ptr2 = buffer[offset_y][comp_width - blk_x - 1];
757           /* this unrolled loop doesn't need to know which row it's on... */
758           for (k = 0; k < DCTSIZE2; k += 2) {
759             temp1 = *ptr1;      /* swap even column */
760             temp2 = *ptr2;
761             *ptr1++ = temp2;
762             *ptr2++ = temp1;
763             temp1 = *ptr1;      /* swap odd column with sign change */
764             temp2 = *ptr2;
765             *ptr1++ = -temp2;
766             *ptr2++ = -temp1;
767           }
768         }
769         if (x_crop_blocks > 0) {
770           /* Now left-justify the portion of the data to be kept.
771            * We can't use a single jcopy_block_row() call because that routine
772            * depends on memcpy(), whose behavior is unspecified for overlapping
773            * source and destination areas.  Sigh.
774            */
775           for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
776             jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
777                             buffer[offset_y] + blk_x, (JDIMENSION)1);
778           }
779         }
780       }
781     }
782   }
783 }
784 
785 
786 LOCAL(void)
do_flip_h(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)787 do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
788           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
789           jvirt_barray_ptr *src_coef_arrays,
790           jvirt_barray_ptr *dst_coef_arrays)
791 /* Horizontal flip in general cropping case */
792 {
793   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
794   JDIMENSION x_crop_blocks, y_crop_blocks;
795   int ci, k, offset_y;
796   JBLOCKARRAY src_buffer, dst_buffer;
797   JBLOCKROW src_row_ptr, dst_row_ptr;
798   JCOEFPTR src_ptr, dst_ptr;
799   jpeg_component_info *compptr;
800 
801   /* Here we must output into a separate array because we can't touch
802    * different rows of a single virtual array simultaneously.  Otherwise,
803    * this is essentially the same as the routine above.
804    */
805   MCU_cols = srcinfo->output_width /
806              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
807 
808   for (ci = 0; ci < dstinfo->num_components; ci++) {
809     compptr = dstinfo->comp_info + ci;
810     comp_width = MCU_cols * compptr->h_samp_factor;
811     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
812     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
813     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
814          dst_blk_y += compptr->v_samp_factor) {
815       dst_buffer = (*srcinfo->mem->access_virt_barray)
816         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
817          (JDIMENSION)compptr->v_samp_factor, TRUE);
818       src_buffer = (*srcinfo->mem->access_virt_barray)
819         ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
820          (JDIMENSION)compptr->v_samp_factor, FALSE);
821       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
822         dst_row_ptr = dst_buffer[offset_y];
823         src_row_ptr = src_buffer[offset_y];
824         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
825              dst_blk_x++) {
826           if (x_crop_blocks + dst_blk_x < comp_width) {
827             /* Do the mirrorable blocks */
828             dst_ptr = dst_row_ptr[dst_blk_x];
829             src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
830             /* this unrolled loop doesn't need to know which row it's on... */
831             for (k = 0; k < DCTSIZE2; k += 2) {
832               *dst_ptr++ = *src_ptr++;    /* copy even column */
833               *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
834                                              change */
835             }
836           } else {
837             /* Copy last partial block(s) verbatim */
838             jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
839                             dst_row_ptr + dst_blk_x, (JDIMENSION)1);
840           }
841         }
842       }
843     }
844   }
845 }
846 
847 
848 LOCAL(void)
do_flip_v(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)849 do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
850           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
851           jvirt_barray_ptr *src_coef_arrays,
852           jvirt_barray_ptr *dst_coef_arrays)
853 /* Vertical flip */
854 {
855   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
856   JDIMENSION x_crop_blocks, y_crop_blocks;
857   int ci, i, j, offset_y;
858   JBLOCKARRAY src_buffer, dst_buffer;
859   JBLOCKROW src_row_ptr, dst_row_ptr;
860   JCOEFPTR src_ptr, dst_ptr;
861   jpeg_component_info *compptr;
862 
863   /* We output into a separate array because we can't touch different
864    * rows of the source virtual array simultaneously.  Otherwise, this
865    * is a pretty straightforward analog of horizontal flip.
866    * Within a DCT block, vertical mirroring is done by changing the signs
867    * of odd-numbered rows.
868    * Partial iMCUs at the bottom edge are copied verbatim.
869    */
870   MCU_rows = srcinfo->output_height /
871              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
872 
873   for (ci = 0; ci < dstinfo->num_components; ci++) {
874     compptr = dstinfo->comp_info + ci;
875     comp_height = MCU_rows * compptr->v_samp_factor;
876     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
877     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
878     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
879          dst_blk_y += compptr->v_samp_factor) {
880       dst_buffer = (*srcinfo->mem->access_virt_barray)
881         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
882          (JDIMENSION)compptr->v_samp_factor, TRUE);
883       if (y_crop_blocks + dst_blk_y < comp_height) {
884         /* Row is within the mirrorable area. */
885         src_buffer = (*srcinfo->mem->access_virt_barray)
886           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
887            comp_height - y_crop_blocks - dst_blk_y -
888            (JDIMENSION)compptr->v_samp_factor,
889            (JDIMENSION)compptr->v_samp_factor, FALSE);
890       } else {
891         /* Bottom-edge blocks will be copied verbatim. */
892         src_buffer = (*srcinfo->mem->access_virt_barray)
893           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
894            dst_blk_y + y_crop_blocks,
895            (JDIMENSION)compptr->v_samp_factor, FALSE);
896       }
897       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
898         if (y_crop_blocks + dst_blk_y < comp_height) {
899           /* Row is within the mirrorable area. */
900           dst_row_ptr = dst_buffer[offset_y];
901           src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
902           src_row_ptr += x_crop_blocks;
903           for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
904                dst_blk_x++) {
905             dst_ptr = dst_row_ptr[dst_blk_x];
906             src_ptr = src_row_ptr[dst_blk_x];
907             for (i = 0; i < DCTSIZE; i += 2) {
908               /* copy even row */
909               for (j = 0; j < DCTSIZE; j++)
910                 *dst_ptr++ = *src_ptr++;
911               /* copy odd row with sign change */
912               for (j = 0; j < DCTSIZE; j++)
913                 *dst_ptr++ = -(*src_ptr++);
914             }
915           }
916         } else {
917           /* Just copy row verbatim. */
918           jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
919                           dst_buffer[offset_y], compptr->width_in_blocks);
920         }
921       }
922     }
923   }
924 }
925 
926 
927 LOCAL(void)
do_transpose(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)928 do_transpose(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
929              JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
930              jvirt_barray_ptr *src_coef_arrays,
931              jvirt_barray_ptr *dst_coef_arrays)
932 /* Transpose source into destination */
933 {
934   JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
935   int ci, i, j, offset_x, offset_y;
936   JBLOCKARRAY src_buffer, dst_buffer;
937   JCOEFPTR src_ptr, dst_ptr;
938   jpeg_component_info *compptr;
939 
940   /* Transposing pixels within a block just requires transposing the
941    * DCT coefficients.
942    * Partial iMCUs at the edges require no special treatment; we simply
943    * process all the available DCT blocks for every component.
944    */
945   for (ci = 0; ci < dstinfo->num_components; ci++) {
946     compptr = dstinfo->comp_info + ci;
947     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
948     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
949     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
950          dst_blk_y += compptr->v_samp_factor) {
951       dst_buffer = (*srcinfo->mem->access_virt_barray)
952         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
953          (JDIMENSION)compptr->v_samp_factor, TRUE);
954       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
955         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
956              dst_blk_x += compptr->h_samp_factor) {
957           src_buffer = (*srcinfo->mem->access_virt_barray)
958             ((j_common_ptr)srcinfo, src_coef_arrays[ci],
959              dst_blk_x + x_crop_blocks,
960              (JDIMENSION)compptr->h_samp_factor, FALSE);
961           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
962             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
963             src_ptr =
964               src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
965             for (i = 0; i < DCTSIZE; i++)
966               for (j = 0; j < DCTSIZE; j++)
967                 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
968           }
969         }
970       }
971     }
972   }
973 }
974 
975 
976 LOCAL(void)
do_rot_90(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)977 do_rot_90(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
978           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
979           jvirt_barray_ptr *src_coef_arrays,
980           jvirt_barray_ptr *dst_coef_arrays)
981 /* 90 degree rotation is equivalent to
982  *   1. Transposing the image;
983  *   2. Horizontal mirroring.
984  * These two steps are merged into a single processing routine.
985  */
986 {
987   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
988   JDIMENSION x_crop_blocks, y_crop_blocks;
989   int ci, i, j, offset_x, offset_y;
990   JBLOCKARRAY src_buffer, dst_buffer;
991   JCOEFPTR src_ptr, dst_ptr;
992   jpeg_component_info *compptr;
993 
994   /* Because of the horizontal mirror step, we can't process partial iMCUs
995    * at the (output) right edge properly.  They just get transposed and
996    * not mirrored.
997    */
998   MCU_cols = srcinfo->output_height /
999              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
1000 
1001   for (ci = 0; ci < dstinfo->num_components; ci++) {
1002     compptr = dstinfo->comp_info + ci;
1003     comp_width = MCU_cols * compptr->h_samp_factor;
1004     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1005     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1006     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1007          dst_blk_y += compptr->v_samp_factor) {
1008       dst_buffer = (*srcinfo->mem->access_virt_barray)
1009         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1010          (JDIMENSION)compptr->v_samp_factor, TRUE);
1011       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1012         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1013              dst_blk_x += compptr->h_samp_factor) {
1014           if (x_crop_blocks + dst_blk_x < comp_width) {
1015             /* Block is within the mirrorable area. */
1016             src_buffer = (*srcinfo->mem->access_virt_barray)
1017               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1018                comp_width - x_crop_blocks - dst_blk_x -
1019                (JDIMENSION)compptr->h_samp_factor,
1020                (JDIMENSION)compptr->h_samp_factor, FALSE);
1021           } else {
1022             /* Edge blocks are transposed but not mirrored. */
1023             src_buffer = (*srcinfo->mem->access_virt_barray)
1024               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1025                dst_blk_x + x_crop_blocks,
1026                (JDIMENSION)compptr->h_samp_factor, FALSE);
1027           }
1028           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
1029             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
1030             if (x_crop_blocks + dst_blk_x < comp_width) {
1031               /* Block is within the mirrorable area. */
1032               src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
1033                 [dst_blk_y + offset_y + y_crop_blocks];
1034               for (i = 0; i < DCTSIZE; i++) {
1035                 for (j = 0; j < DCTSIZE; j++)
1036                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1037                 i++;
1038                 for (j = 0; j < DCTSIZE; j++)
1039                   dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1040               }
1041             } else {
1042               /* Edge blocks are transposed but not mirrored. */
1043               src_ptr = src_buffer[offset_x]
1044                 [dst_blk_y + offset_y + y_crop_blocks];
1045               for (i = 0; i < DCTSIZE; i++)
1046                 for (j = 0; j < DCTSIZE; j++)
1047                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1048             }
1049           }
1050         }
1051       }
1052     }
1053   }
1054 }
1055 
1056 
1057 LOCAL(void)
do_rot_270(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)1058 do_rot_270(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1059            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
1060            jvirt_barray_ptr *src_coef_arrays,
1061            jvirt_barray_ptr *dst_coef_arrays)
1062 /* 270 degree rotation is equivalent to
1063  *   1. Horizontal mirroring;
1064  *   2. Transposing the image.
1065  * These two steps are merged into a single processing routine.
1066  */
1067 {
1068   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
1069   JDIMENSION x_crop_blocks, y_crop_blocks;
1070   int ci, i, j, offset_x, offset_y;
1071   JBLOCKARRAY src_buffer, dst_buffer;
1072   JCOEFPTR src_ptr, dst_ptr;
1073   jpeg_component_info *compptr;
1074 
1075   /* Because of the horizontal mirror step, we can't process partial iMCUs
1076    * at the (output) bottom edge properly.  They just get transposed and
1077    * not mirrored.
1078    */
1079   MCU_rows = srcinfo->output_width /
1080              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
1081 
1082   for (ci = 0; ci < dstinfo->num_components; ci++) {
1083     compptr = dstinfo->comp_info + ci;
1084     comp_height = MCU_rows * compptr->v_samp_factor;
1085     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1086     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1087     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1088          dst_blk_y += compptr->v_samp_factor) {
1089       dst_buffer = (*srcinfo->mem->access_virt_barray)
1090         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1091          (JDIMENSION)compptr->v_samp_factor, TRUE);
1092       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1093         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1094              dst_blk_x += compptr->h_samp_factor) {
1095           src_buffer = (*srcinfo->mem->access_virt_barray)
1096             ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1097              dst_blk_x + x_crop_blocks,
1098              (JDIMENSION)compptr->h_samp_factor, FALSE);
1099           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
1100             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
1101             if (y_crop_blocks + dst_blk_y < comp_height) {
1102               /* Block is within the mirrorable area. */
1103               src_ptr = src_buffer[offset_x]
1104                 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
1105               for (i = 0; i < DCTSIZE; i++) {
1106                 for (j = 0; j < DCTSIZE; j++) {
1107                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1108                   j++;
1109                   dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1110                 }
1111               }
1112             } else {
1113               /* Edge blocks are transposed but not mirrored. */
1114               src_ptr = src_buffer[offset_x]
1115                 [dst_blk_y + offset_y + y_crop_blocks];
1116               for (i = 0; i < DCTSIZE; i++)
1117                 for (j = 0; j < DCTSIZE; j++)
1118                   dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1119             }
1120           }
1121         }
1122       }
1123     }
1124   }
1125 }
1126 
1127 
1128 LOCAL(void)
do_rot_180(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)1129 do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1130            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
1131            jvirt_barray_ptr *src_coef_arrays,
1132            jvirt_barray_ptr *dst_coef_arrays)
1133 /* 180 degree rotation is equivalent to
1134  *   1. Vertical mirroring;
1135  *   2. Horizontal mirroring.
1136  * These two steps are merged into a single processing routine.
1137  */
1138 {
1139   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
1140   JDIMENSION x_crop_blocks, y_crop_blocks;
1141   int ci, i, j, offset_y;
1142   JBLOCKARRAY src_buffer, dst_buffer;
1143   JBLOCKROW src_row_ptr, dst_row_ptr;
1144   JCOEFPTR src_ptr, dst_ptr;
1145   jpeg_component_info *compptr;
1146 
1147   MCU_cols = srcinfo->output_width /
1148              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
1149   MCU_rows = srcinfo->output_height /
1150              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
1151 
1152   for (ci = 0; ci < dstinfo->num_components; ci++) {
1153     compptr = dstinfo->comp_info + ci;
1154     comp_width = MCU_cols * compptr->h_samp_factor;
1155     comp_height = MCU_rows * compptr->v_samp_factor;
1156     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1157     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1158     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1159          dst_blk_y += compptr->v_samp_factor) {
1160       dst_buffer = (*srcinfo->mem->access_virt_barray)
1161         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1162          (JDIMENSION)compptr->v_samp_factor, TRUE);
1163       if (y_crop_blocks + dst_blk_y < comp_height) {
1164         /* Row is within the vertically mirrorable area. */
1165         src_buffer = (*srcinfo->mem->access_virt_barray)
1166           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1167            comp_height - y_crop_blocks - dst_blk_y -
1168            (JDIMENSION)compptr->v_samp_factor,
1169            (JDIMENSION)compptr->v_samp_factor, FALSE);
1170       } else {
1171         /* Bottom-edge rows are only mirrored horizontally. */
1172         src_buffer = (*srcinfo->mem->access_virt_barray)
1173           ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1174            dst_blk_y + y_crop_blocks,
1175            (JDIMENSION)compptr->v_samp_factor, FALSE);
1176       }
1177       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1178         dst_row_ptr = dst_buffer[offset_y];
1179         if (y_crop_blocks + dst_blk_y < comp_height) {
1180           /* Row is within the mirrorable area. */
1181           src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
1182           for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1183                dst_blk_x++) {
1184             dst_ptr = dst_row_ptr[dst_blk_x];
1185             if (x_crop_blocks + dst_blk_x < comp_width) {
1186               /* Process the blocks that can be mirrored both ways. */
1187               src_ptr =
1188                 src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
1189               for (i = 0; i < DCTSIZE; i += 2) {
1190                 /* For even row, negate every odd column. */
1191                 for (j = 0; j < DCTSIZE; j += 2) {
1192                   *dst_ptr++ = *src_ptr++;
1193                   *dst_ptr++ = -(*src_ptr++);
1194                 }
1195                 /* For odd row, negate every even column. */
1196                 for (j = 0; j < DCTSIZE; j += 2) {
1197                   *dst_ptr++ = -(*src_ptr++);
1198                   *dst_ptr++ = *src_ptr++;
1199                 }
1200               }
1201             } else {
1202               /* Any remaining right-edge blocks are only mirrored vertically. */
1203               src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
1204               for (i = 0; i < DCTSIZE; i += 2) {
1205                 for (j = 0; j < DCTSIZE; j++)
1206                   *dst_ptr++ = *src_ptr++;
1207                 for (j = 0; j < DCTSIZE; j++)
1208                   *dst_ptr++ = -(*src_ptr++);
1209               }
1210             }
1211           }
1212         } else {
1213           /* Remaining rows are just mirrored horizontally. */
1214           src_row_ptr = src_buffer[offset_y];
1215           for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1216                dst_blk_x++) {
1217             if (x_crop_blocks + dst_blk_x < comp_width) {
1218               /* Process the blocks that can be mirrored. */
1219               dst_ptr = dst_row_ptr[dst_blk_x];
1220               src_ptr =
1221                 src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
1222               for (i = 0; i < DCTSIZE2; i += 2) {
1223                 *dst_ptr++ = *src_ptr++;
1224                 *dst_ptr++ = -(*src_ptr++);
1225               }
1226             } else {
1227               /* Any remaining right-edge blocks are only copied. */
1228               jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
1229                               dst_row_ptr + dst_blk_x, (JDIMENSION)1);
1230             }
1231           }
1232         }
1233       }
1234     }
1235   }
1236 }
1237 
1238 
1239 LOCAL(void)
do_transverse(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JDIMENSION x_crop_offset,JDIMENSION y_crop_offset,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)1240 do_transverse(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1241               JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
1242               jvirt_barray_ptr *src_coef_arrays,
1243               jvirt_barray_ptr *dst_coef_arrays)
1244 /* Transverse transpose is equivalent to
1245  *   1. 180 degree rotation;
1246  *   2. Transposition;
1247  * or
1248  *   1. Horizontal mirroring;
1249  *   2. Transposition;
1250  *   3. Horizontal mirroring.
1251  * These steps are merged into a single processing routine.
1252  */
1253 {
1254   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
1255   JDIMENSION x_crop_blocks, y_crop_blocks;
1256   int ci, i, j, offset_x, offset_y;
1257   JBLOCKARRAY src_buffer, dst_buffer;
1258   JCOEFPTR src_ptr, dst_ptr;
1259   jpeg_component_info *compptr;
1260 
1261   MCU_cols = srcinfo->output_height /
1262              (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
1263   MCU_rows = srcinfo->output_width /
1264              (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
1265 
1266   for (ci = 0; ci < dstinfo->num_components; ci++) {
1267     compptr = dstinfo->comp_info + ci;
1268     comp_width = MCU_cols * compptr->h_samp_factor;
1269     comp_height = MCU_rows * compptr->v_samp_factor;
1270     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1271     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
1272     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
1273          dst_blk_y += compptr->v_samp_factor) {
1274       dst_buffer = (*srcinfo->mem->access_virt_barray)
1275         ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1276          (JDIMENSION)compptr->v_samp_factor, TRUE);
1277       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
1278         for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1279              dst_blk_x += compptr->h_samp_factor) {
1280           if (x_crop_blocks + dst_blk_x < comp_width) {
1281             /* Block is within the mirrorable area. */
1282             src_buffer = (*srcinfo->mem->access_virt_barray)
1283               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1284                comp_width - x_crop_blocks - dst_blk_x -
1285                (JDIMENSION)compptr->h_samp_factor,
1286                (JDIMENSION)compptr->h_samp_factor, FALSE);
1287           } else {
1288             src_buffer = (*srcinfo->mem->access_virt_barray)
1289               ((j_common_ptr)srcinfo, src_coef_arrays[ci],
1290                dst_blk_x + x_crop_blocks,
1291                (JDIMENSION)compptr->h_samp_factor, FALSE);
1292           }
1293           for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
1294             dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
1295             if (y_crop_blocks + dst_blk_y < comp_height) {
1296               if (x_crop_blocks + dst_blk_x < comp_width) {
1297                 /* Block is within the mirrorable area. */
1298                 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
1299                   [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
1300                 for (i = 0; i < DCTSIZE; i++) {
1301                   for (j = 0; j < DCTSIZE; j++) {
1302                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1303                     j++;
1304                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1305                   }
1306                   i++;
1307                   for (j = 0; j < DCTSIZE; j++) {
1308                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1309                     j++;
1310                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1311                   }
1312                 }
1313               } else {
1314                 /* Right-edge blocks are mirrored in y only */
1315                 src_ptr = src_buffer[offset_x]
1316                   [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
1317                 for (i = 0; i < DCTSIZE; i++) {
1318                   for (j = 0; j < DCTSIZE; j++) {
1319                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1320                     j++;
1321                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1322                   }
1323                 }
1324               }
1325             } else {
1326               if (x_crop_blocks + dst_blk_x < comp_width) {
1327                 /* Bottom-edge blocks are mirrored in x only */
1328                 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
1329                   [dst_blk_y + offset_y + y_crop_blocks];
1330                 for (i = 0; i < DCTSIZE; i++) {
1331                   for (j = 0; j < DCTSIZE; j++)
1332                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1333                   i++;
1334                   for (j = 0; j < DCTSIZE; j++)
1335                     dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
1336                 }
1337               } else {
1338                 /* At lower right corner, just transpose, no mirroring */
1339                 src_ptr = src_buffer[offset_x]
1340                   [dst_blk_y + offset_y + y_crop_blocks];
1341                 for (i = 0; i < DCTSIZE; i++)
1342                   for (j = 0; j < DCTSIZE; j++)
1343                     dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
1344               }
1345             }
1346           }
1347         }
1348       }
1349     }
1350   }
1351 }
1352 
1353 
1354 /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
1355  * Returns TRUE if valid integer found, FALSE if not.
1356  * *strptr is advanced over the digit string, and *result is set to its value.
1357  */
1358 
1359 LOCAL(boolean)
jt_read_integer(const char ** strptr,JDIMENSION * result)1360 jt_read_integer(const char **strptr, JDIMENSION *result)
1361 {
1362   const char *ptr = *strptr;
1363   JDIMENSION val = 0;
1364 
1365   for (; isdigit(*ptr); ptr++) {
1366     val = val * 10 + (JDIMENSION)(*ptr - '0');
1367   }
1368   *result = val;
1369   if (ptr == *strptr)
1370     return FALSE;               /* oops, no digits */
1371   *strptr = ptr;
1372   return TRUE;
1373 }
1374 
1375 
1376 /* Parse a crop specification (written in X11 geometry style).
1377  * The routine returns TRUE if the spec string is valid, FALSE if not.
1378  *
1379  * The crop spec string should have the format
1380  *      <width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset>
1381  * where width, height, xoffset, and yoffset are unsigned integers.
1382  * Each of the elements can be omitted to indicate a default value.
1383  * (A weakness of this style is that it is not possible to omit xoffset
1384  * while specifying yoffset, since they look alike.)
1385  *
1386  * This code is loosely based on XParseGeometry from the X11 distribution.
1387  */
1388 
1389 GLOBAL(boolean)
jtransform_parse_crop_spec(jpeg_transform_info * info,const char * spec)1390 jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
1391 {
1392   info->crop = FALSE;
1393   info->crop_width_set = JCROP_UNSET;
1394   info->crop_height_set = JCROP_UNSET;
1395   info->crop_xoffset_set = JCROP_UNSET;
1396   info->crop_yoffset_set = JCROP_UNSET;
1397 
1398   if (isdigit(*spec)) {
1399     /* fetch width */
1400     if (!jt_read_integer(&spec, &info->crop_width))
1401       return FALSE;
1402     if (*spec == 'f' || *spec == 'F') {
1403       spec++;
1404       info->crop_width_set = JCROP_FORCE;
1405     } else if (*spec == 'r' || *spec == 'R') {
1406       spec++;
1407       info->crop_width_set = JCROP_REFLECT;
1408     } else
1409       info->crop_width_set = JCROP_POS;
1410   }
1411   if (*spec == 'x' || *spec == 'X') {
1412     /* fetch height */
1413     spec++;
1414     if (!jt_read_integer(&spec, &info->crop_height))
1415       return FALSE;
1416     if (*spec == 'f' || *spec == 'F') {
1417       spec++;
1418       info->crop_height_set = JCROP_FORCE;
1419     } else if (*spec == 'r' || *spec == 'R') {
1420       spec++;
1421       info->crop_height_set = JCROP_REFLECT;
1422     } else
1423       info->crop_height_set = JCROP_POS;
1424   }
1425   if (*spec == '+' || *spec == '-') {
1426     /* fetch xoffset */
1427     info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
1428     spec++;
1429     if (!jt_read_integer(&spec, &info->crop_xoffset))
1430       return FALSE;
1431   }
1432   if (*spec == '+' || *spec == '-') {
1433     /* fetch yoffset */
1434     info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
1435     spec++;
1436     if (!jt_read_integer(&spec, &info->crop_yoffset))
1437       return FALSE;
1438   }
1439   /* We had better have gotten to the end of the string. */
1440   if (*spec != '\0')
1441     return FALSE;
1442   info->crop = TRUE;
1443   return TRUE;
1444 }
1445 
1446 
1447 /* Trim off any partial iMCUs on the indicated destination edge */
1448 
1449 LOCAL(void)
trim_right_edge(jpeg_transform_info * info,JDIMENSION full_width)1450 trim_right_edge(jpeg_transform_info *info, JDIMENSION full_width)
1451 {
1452   JDIMENSION MCU_cols;
1453 
1454   MCU_cols = info->output_width / info->iMCU_sample_width;
1455   if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
1456       full_width / info->iMCU_sample_width)
1457     info->output_width = MCU_cols * info->iMCU_sample_width;
1458 }
1459 
1460 LOCAL(void)
trim_bottom_edge(jpeg_transform_info * info,JDIMENSION full_height)1461 trim_bottom_edge(jpeg_transform_info *info, JDIMENSION full_height)
1462 {
1463   JDIMENSION MCU_rows;
1464 
1465   MCU_rows = info->output_height / info->iMCU_sample_height;
1466   if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
1467       full_height / info->iMCU_sample_height)
1468     info->output_height = MCU_rows * info->iMCU_sample_height;
1469 }
1470 
1471 
1472 /* Request any required workspace.
1473  *
1474  * This routine figures out the size that the output image will be
1475  * (which implies that all the transform parameters must be set before
1476  * it is called).
1477  *
1478  * We allocate the workspace virtual arrays from the source decompression
1479  * object, so that all the arrays (both the original data and the workspace)
1480  * will be taken into account while making memory management decisions.
1481  * Hence, this routine must be called after jpeg_read_header (which reads
1482  * the image dimensions) and before jpeg_read_coefficients (which realizes
1483  * the source's virtual arrays).
1484  *
1485  * This function returns FALSE right away if -perfect is given
1486  * and transformation is not perfect.  Otherwise returns TRUE.
1487  */
1488 
1489 GLOBAL(boolean)
jtransform_request_workspace(j_decompress_ptr srcinfo,jpeg_transform_info * info)1490 jtransform_request_workspace(j_decompress_ptr srcinfo,
1491                              jpeg_transform_info *info)
1492 {
1493   jvirt_barray_ptr *coef_arrays;
1494   boolean need_workspace, transpose_it;
1495   jpeg_component_info *compptr;
1496   JDIMENSION xoffset, yoffset, dtemp;
1497   JDIMENSION width_in_iMCUs, height_in_iMCUs;
1498   JDIMENSION width_in_blocks, height_in_blocks;
1499   int itemp, ci, h_samp_factor, v_samp_factor;
1500 
1501   /* Determine number of components in output image */
1502   if (info->force_grayscale &&
1503       srcinfo->jpeg_color_space == JCS_YCbCr &&
1504       srcinfo->num_components == 3)
1505     /* We'll only process the first component */
1506     info->num_components = 1;
1507   else
1508     /* Process all the components */
1509     info->num_components = srcinfo->num_components;
1510 
1511   /* Compute output image dimensions and related values. */
1512 #if JPEG_LIB_VERSION >= 80
1513   jpeg_core_output_dimensions(srcinfo);
1514 #else
1515   srcinfo->output_width = srcinfo->image_width;
1516   srcinfo->output_height = srcinfo->image_height;
1517 #endif
1518 
1519   /* Return right away if -perfect is given and transformation is not perfect.
1520    */
1521   if (info->perfect) {
1522     if (info->num_components == 1) {
1523       if (!jtransform_perfect_transform(srcinfo->output_width,
1524           srcinfo->output_height,
1525           srcinfo->_min_DCT_h_scaled_size,
1526           srcinfo->_min_DCT_v_scaled_size,
1527           info->transform))
1528         return FALSE;
1529     } else {
1530       if (!jtransform_perfect_transform(srcinfo->output_width,
1531           srcinfo->output_height,
1532           srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size,
1533           srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size,
1534           info->transform))
1535         return FALSE;
1536     }
1537   }
1538 
1539   /* If there is only one output component, force the iMCU size to be 1;
1540    * else use the source iMCU size.  (This allows us to do the right thing
1541    * when reducing color to grayscale, and also provides a handy way of
1542    * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
1543    */
1544   switch (info->transform) {
1545   case JXFORM_TRANSPOSE:
1546   case JXFORM_TRANSVERSE:
1547   case JXFORM_ROT_90:
1548   case JXFORM_ROT_270:
1549     info->output_width = srcinfo->output_height;
1550     info->output_height = srcinfo->output_width;
1551     if (info->num_components == 1) {
1552       info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size;
1553       info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size;
1554     } else {
1555       info->iMCU_sample_width =
1556         srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
1557       info->iMCU_sample_height =
1558         srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
1559     }
1560     break;
1561   default:
1562     info->output_width = srcinfo->output_width;
1563     info->output_height = srcinfo->output_height;
1564     if (info->num_components == 1) {
1565       info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size;
1566       info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size;
1567     } else {
1568       info->iMCU_sample_width =
1569         srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
1570       info->iMCU_sample_height =
1571         srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
1572     }
1573     break;
1574   }
1575 
1576   /* If cropping has been requested, compute the crop area's position and
1577    * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
1578    */
1579   if (info->crop) {
1580     /* Insert default values for unset crop parameters */
1581     if (info->crop_xoffset_set == JCROP_UNSET)
1582       info->crop_xoffset = 0;   /* default to +0 */
1583     if (info->crop_yoffset_set == JCROP_UNSET)
1584       info->crop_yoffset = 0;   /* default to +0 */
1585     if (info->crop_width_set == JCROP_UNSET) {
1586       if (info->crop_xoffset >= info->output_width)
1587         ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1588       info->crop_width = info->output_width - info->crop_xoffset;
1589     } else {
1590       /* Check for crop extension */
1591       if (info->crop_width > info->output_width) {
1592         /* Crop extension does not work when transforming! */
1593         if (info->transform != JXFORM_NONE ||
1594             info->crop_xoffset >= info->crop_width ||
1595             info->crop_xoffset > info->crop_width - info->output_width)
1596           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1597       } else {
1598         if (info->crop_xoffset >= info->output_width ||
1599             info->crop_width <= 0 ||
1600             info->crop_xoffset > info->output_width - info->crop_width)
1601           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1602       }
1603     }
1604     if (info->crop_height_set == JCROP_UNSET) {
1605       if (info->crop_yoffset >= info->output_height)
1606         ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1607       info->crop_height = info->output_height - info->crop_yoffset;
1608     } else {
1609       /* Check for crop extension */
1610       if (info->crop_height > info->output_height) {
1611         /* Crop extension does not work when transforming! */
1612         if (info->transform != JXFORM_NONE ||
1613             info->crop_yoffset >= info->crop_height ||
1614             info->crop_yoffset > info->crop_height - info->output_height)
1615           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1616       } else {
1617         if (info->crop_yoffset >= info->output_height ||
1618             info->crop_height <= 0 ||
1619             info->crop_yoffset > info->output_height - info->crop_height)
1620           ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
1621       }
1622     }
1623     /* Convert negative crop offsets into regular offsets */
1624     if (info->crop_xoffset_set != JCROP_NEG)
1625       xoffset = info->crop_xoffset;
1626     else if (info->crop_width > info->output_width) /* crop extension */
1627       xoffset = info->crop_width - info->output_width - info->crop_xoffset;
1628     else
1629       xoffset = info->output_width - info->crop_width - info->crop_xoffset;
1630     if (info->crop_yoffset_set != JCROP_NEG)
1631       yoffset = info->crop_yoffset;
1632     else if (info->crop_height > info->output_height) /* crop extension */
1633       yoffset = info->crop_height - info->output_height - info->crop_yoffset;
1634     else
1635       yoffset = info->output_height - info->crop_height - info->crop_yoffset;
1636     /* Now adjust so that upper left corner falls at an iMCU boundary */
1637     switch (info->transform) {
1638     case JXFORM_DROP:
1639       /* Ensure the effective drop region will not exceed the requested */
1640       itemp = info->iMCU_sample_width;
1641       dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp);
1642       xoffset += dtemp;
1643       if (info->crop_width <= dtemp)
1644         info->drop_width = 0;
1645       else if (xoffset + info->crop_width - dtemp == info->output_width)
1646         /* Matching right edge: include partial iMCU */
1647         info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp;
1648       else
1649         info->drop_width = (info->crop_width - dtemp) / itemp;
1650       itemp = info->iMCU_sample_height;
1651       dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp);
1652       yoffset += dtemp;
1653       if (info->crop_height <= dtemp)
1654         info->drop_height = 0;
1655       else if (yoffset + info->crop_height - dtemp == info->output_height)
1656         /* Matching bottom edge: include partial iMCU */
1657         info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp;
1658       else
1659         info->drop_height = (info->crop_height - dtemp) / itemp;
1660       /* Check if sampling factors match for dropping */
1661       if (info->drop_width != 0 && info->drop_height != 0)
1662         for (ci = 0; ci < info->num_components &&
1663                      ci < info->drop_ptr->num_components; ci++) {
1664           if (info->drop_ptr->comp_info[ci].h_samp_factor *
1665               srcinfo->max_h_samp_factor !=
1666               srcinfo->comp_info[ci].h_samp_factor *
1667               info->drop_ptr->max_h_samp_factor)
1668             ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
1669               info->drop_ptr->comp_info[ci].h_samp_factor,
1670               info->drop_ptr->max_h_samp_factor,
1671               srcinfo->comp_info[ci].h_samp_factor,
1672               srcinfo->max_h_samp_factor, 'h');
1673           if (info->drop_ptr->comp_info[ci].v_samp_factor *
1674               srcinfo->max_v_samp_factor !=
1675               srcinfo->comp_info[ci].v_samp_factor *
1676               info->drop_ptr->max_v_samp_factor)
1677             ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
1678               info->drop_ptr->comp_info[ci].v_samp_factor,
1679               info->drop_ptr->max_v_samp_factor,
1680               srcinfo->comp_info[ci].v_samp_factor,
1681               srcinfo->max_v_samp_factor, 'v');
1682         }
1683       break;
1684     case JXFORM_WIPE:
1685       /* Ensure the effective wipe region will cover the requested */
1686       info->drop_width = (JDIMENSION)jdiv_round_up
1687         ((long)(info->crop_width + (xoffset % info->iMCU_sample_width)),
1688          (long)info->iMCU_sample_width);
1689       info->drop_height = (JDIMENSION)jdiv_round_up
1690         ((long)(info->crop_height + (yoffset % info->iMCU_sample_height)),
1691          (long)info->iMCU_sample_height);
1692       break;
1693     default:
1694       /* Ensure the effective crop region will cover the requested */
1695       if (info->crop_width_set == JCROP_FORCE ||
1696           info->crop_width > info->output_width)
1697         info->output_width = info->crop_width;
1698       else
1699         info->output_width =
1700           info->crop_width + (xoffset % info->iMCU_sample_width);
1701       if (info->crop_height_set == JCROP_FORCE ||
1702           info->crop_height > info->output_height)
1703         info->output_height = info->crop_height;
1704       else
1705         info->output_height =
1706           info->crop_height + (yoffset % info->iMCU_sample_height);
1707     }
1708     /* Save x/y offsets measured in iMCUs */
1709     info->x_crop_offset = xoffset / info->iMCU_sample_width;
1710     info->y_crop_offset = yoffset / info->iMCU_sample_height;
1711   } else {
1712     info->x_crop_offset = 0;
1713     info->y_crop_offset = 0;
1714   }
1715 
1716   /* Figure out whether we need workspace arrays,
1717    * and if so whether they are transposed relative to the source.
1718    */
1719   need_workspace = FALSE;
1720   transpose_it = FALSE;
1721   switch (info->transform) {
1722   case JXFORM_NONE:
1723     if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||
1724         info->output_width > srcinfo->output_width ||
1725         info->output_height > srcinfo->output_height)
1726       need_workspace = TRUE;
1727     /* No workspace needed if neither cropping nor transforming */
1728     break;
1729   case JXFORM_FLIP_H:
1730     if (info->trim)
1731       trim_right_edge(info, srcinfo->output_width);
1732     if (info->y_crop_offset != 0 || info->slow_hflip)
1733       need_workspace = TRUE;
1734     /* do_flip_h_no_crop doesn't need a workspace array */
1735     break;
1736   case JXFORM_FLIP_V:
1737     if (info->trim)
1738       trim_bottom_edge(info, srcinfo->output_height);
1739     /* Need workspace arrays having same dimensions as source image. */
1740     need_workspace = TRUE;
1741     break;
1742   case JXFORM_TRANSPOSE:
1743     /* transpose does NOT have to trim anything */
1744     /* Need workspace arrays having transposed dimensions. */
1745     need_workspace = TRUE;
1746     transpose_it = TRUE;
1747     break;
1748   case JXFORM_TRANSVERSE:
1749     if (info->trim) {
1750       trim_right_edge(info, srcinfo->output_height);
1751       trim_bottom_edge(info, srcinfo->output_width);
1752     }
1753     /* Need workspace arrays having transposed dimensions. */
1754     need_workspace = TRUE;
1755     transpose_it = TRUE;
1756     break;
1757   case JXFORM_ROT_90:
1758     if (info->trim)
1759       trim_right_edge(info, srcinfo->output_height);
1760     /* Need workspace arrays having transposed dimensions. */
1761     need_workspace = TRUE;
1762     transpose_it = TRUE;
1763     break;
1764   case JXFORM_ROT_180:
1765     if (info->trim) {
1766       trim_right_edge(info, srcinfo->output_width);
1767       trim_bottom_edge(info, srcinfo->output_height);
1768     }
1769     /* Need workspace arrays having same dimensions as source image. */
1770     need_workspace = TRUE;
1771     break;
1772   case JXFORM_ROT_270:
1773     if (info->trim)
1774       trim_bottom_edge(info, srcinfo->output_width);
1775     /* Need workspace arrays having transposed dimensions. */
1776     need_workspace = TRUE;
1777     transpose_it = TRUE;
1778     break;
1779   case JXFORM_WIPE:
1780     break;
1781   case JXFORM_DROP:
1782     break;
1783   }
1784 
1785   /* Allocate workspace if needed.
1786    * Note that we allocate arrays padded out to the next iMCU boundary,
1787    * so that transform routines need not worry about missing edge blocks.
1788    */
1789   if (need_workspace) {
1790     coef_arrays = (jvirt_barray_ptr *)
1791       (*srcinfo->mem->alloc_small) ((j_common_ptr)srcinfo, JPOOL_IMAGE,
1792                 sizeof(jvirt_barray_ptr) * info->num_components);
1793     width_in_iMCUs = (JDIMENSION)
1794       jdiv_round_up((long)info->output_width, (long)info->iMCU_sample_width);
1795     height_in_iMCUs = (JDIMENSION)
1796       jdiv_round_up((long)info->output_height, (long)info->iMCU_sample_height);
1797     for (ci = 0; ci < info->num_components; ci++) {
1798       compptr = srcinfo->comp_info + ci;
1799       if (info->num_components == 1) {
1800         /* we're going to force samp factors to 1x1 in this case */
1801         h_samp_factor = v_samp_factor = 1;
1802       } else if (transpose_it) {
1803         h_samp_factor = compptr->v_samp_factor;
1804         v_samp_factor = compptr->h_samp_factor;
1805       } else {
1806         h_samp_factor = compptr->h_samp_factor;
1807         v_samp_factor = compptr->v_samp_factor;
1808       }
1809       width_in_blocks = width_in_iMCUs * h_samp_factor;
1810       height_in_blocks = height_in_iMCUs * v_samp_factor;
1811       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1812         ((j_common_ptr)srcinfo, JPOOL_IMAGE, FALSE,
1813          width_in_blocks, height_in_blocks, (JDIMENSION)v_samp_factor);
1814     }
1815     info->workspace_coef_arrays = coef_arrays;
1816   } else
1817     info->workspace_coef_arrays = NULL;
1818 
1819   return TRUE;
1820 }
1821 
1822 
1823 /* Transpose destination image parameters */
1824 
1825 LOCAL(void)
transpose_critical_parameters(j_compress_ptr dstinfo)1826 transpose_critical_parameters(j_compress_ptr dstinfo)
1827 {
1828   int tblno, i, j, ci, itemp;
1829   jpeg_component_info *compptr;
1830   JQUANT_TBL *qtblptr;
1831   JDIMENSION jtemp;
1832   UINT16 qtemp;
1833 
1834   /* Transpose image dimensions */
1835   jtemp = dstinfo->image_width;
1836   dstinfo->image_width = dstinfo->image_height;
1837   dstinfo->image_height = jtemp;
1838 #if JPEG_LIB_VERSION >= 70
1839   itemp = dstinfo->min_DCT_h_scaled_size;
1840   dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
1841   dstinfo->min_DCT_v_scaled_size = itemp;
1842 #endif
1843 
1844   /* Transpose sampling factors */
1845   for (ci = 0; ci < dstinfo->num_components; ci++) {
1846     compptr = dstinfo->comp_info + ci;
1847     itemp = compptr->h_samp_factor;
1848     compptr->h_samp_factor = compptr->v_samp_factor;
1849     compptr->v_samp_factor = itemp;
1850   }
1851 
1852   /* Transpose quantization tables */
1853   for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
1854     qtblptr = dstinfo->quant_tbl_ptrs[tblno];
1855     if (qtblptr != NULL) {
1856       for (i = 0; i < DCTSIZE; i++) {
1857         for (j = 0; j < i; j++) {
1858           qtemp = qtblptr->quantval[i * DCTSIZE + j];
1859           qtblptr->quantval[i * DCTSIZE + j] =
1860             qtblptr->quantval[j * DCTSIZE + i];
1861           qtblptr->quantval[j * DCTSIZE + i] = qtemp;
1862         }
1863       }
1864     }
1865   }
1866 }
1867 
1868 
1869 /* Adjust Exif image parameters.
1870  *
1871  * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1872  */
1873 
1874 LOCAL(void)
adjust_exif_parameters(JOCTET * data,unsigned int length,JDIMENSION new_width,JDIMENSION new_height)1875 adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
1876                        JDIMENSION new_height)
1877 {
1878   boolean is_motorola; /* Flag for byte order */
1879   unsigned int number_of_tags, tagnum;
1880   unsigned int firstoffset, offset;
1881   JDIMENSION new_value;
1882 
1883   if (length < 12) return; /* Length of an IFD entry */
1884 
1885   /* Discover byte order */
1886   if (data[0] == 0x49 && data[1] == 0x49)
1887     is_motorola = FALSE;
1888   else if (data[0] == 0x4D && data[1] == 0x4D)
1889     is_motorola = TRUE;
1890   else
1891     return;
1892 
1893   /* Check Tag Mark */
1894   if (is_motorola) {
1895     if (data[2] != 0) return;
1896     if (data[3] != 0x2A) return;
1897   } else {
1898     if (data[3] != 0) return;
1899     if (data[2] != 0x2A) return;
1900   }
1901 
1902   /* Get first IFD offset (offset to IFD0) */
1903   if (is_motorola) {
1904     if (data[4] != 0) return;
1905     if (data[5] != 0) return;
1906     firstoffset = data[6];
1907     firstoffset <<= 8;
1908     firstoffset += data[7];
1909   } else {
1910     if (data[7] != 0) return;
1911     if (data[6] != 0) return;
1912     firstoffset = data[5];
1913     firstoffset <<= 8;
1914     firstoffset += data[4];
1915   }
1916   if (firstoffset > length - 2) return; /* check end of data segment */
1917 
1918   /* Get the number of directory entries contained in this IFD */
1919   if (is_motorola) {
1920     number_of_tags = data[firstoffset];
1921     number_of_tags <<= 8;
1922     number_of_tags += data[firstoffset + 1];
1923   } else {
1924     number_of_tags = data[firstoffset + 1];
1925     number_of_tags <<= 8;
1926     number_of_tags += data[firstoffset];
1927   }
1928   if (number_of_tags == 0) return;
1929   firstoffset += 2;
1930 
1931   /* Search for ExifSubIFD offset Tag in IFD0 */
1932   for (;;) {
1933     if (firstoffset > length - 12) return; /* check end of data segment */
1934     /* Get Tag number */
1935     if (is_motorola) {
1936       tagnum = data[firstoffset];
1937       tagnum <<= 8;
1938       tagnum += data[firstoffset + 1];
1939     } else {
1940       tagnum = data[firstoffset + 1];
1941       tagnum <<= 8;
1942       tagnum += data[firstoffset];
1943     }
1944     if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1945     if (--number_of_tags == 0) return;
1946     firstoffset += 12;
1947   }
1948 
1949   /* Get the ExifSubIFD offset */
1950   if (is_motorola) {
1951     if (data[firstoffset + 8] != 0) return;
1952     if (data[firstoffset + 9] != 0) return;
1953     offset = data[firstoffset + 10];
1954     offset <<= 8;
1955     offset += data[firstoffset + 11];
1956   } else {
1957     if (data[firstoffset + 11] != 0) return;
1958     if (data[firstoffset + 10] != 0) return;
1959     offset = data[firstoffset + 9];
1960     offset <<= 8;
1961     offset += data[firstoffset + 8];
1962   }
1963   if (offset > length - 2) return; /* check end of data segment */
1964 
1965   /* Get the number of directory entries contained in this SubIFD */
1966   if (is_motorola) {
1967     number_of_tags = data[offset];
1968     number_of_tags <<= 8;
1969     number_of_tags += data[offset + 1];
1970   } else {
1971     number_of_tags = data[offset + 1];
1972     number_of_tags <<= 8;
1973     number_of_tags += data[offset];
1974   }
1975   if (number_of_tags < 2) return;
1976   offset += 2;
1977 
1978   /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1979   do {
1980     if (offset > length - 12) return; /* check end of data segment */
1981     /* Get Tag number */
1982     if (is_motorola) {
1983       tagnum = data[offset];
1984       tagnum <<= 8;
1985       tagnum += data[offset + 1];
1986     } else {
1987       tagnum = data[offset + 1];
1988       tagnum <<= 8;
1989       tagnum += data[offset];
1990     }
1991     if (tagnum == 0xA002 || tagnum == 0xA003) {
1992       if (tagnum == 0xA002)
1993         new_value = new_width; /* ExifImageWidth Tag */
1994       else
1995         new_value = new_height; /* ExifImageHeight Tag */
1996       if (is_motorola) {
1997         data[offset + 2] = 0; /* Format = unsigned long (4 octets) */
1998         data[offset + 3] = 4;
1999         data[offset + 4] = 0; /* Number Of Components = 1 */
2000         data[offset + 5] = 0;
2001         data[offset + 6] = 0;
2002         data[offset + 7] = 1;
2003         data[offset + 8] = 0;
2004         data[offset + 9] = 0;
2005         data[offset + 10] = (JOCTET)((new_value >> 8) & 0xFF);
2006         data[offset + 11] = (JOCTET)(new_value & 0xFF);
2007       } else {
2008         data[offset + 2] = 4; /* Format = unsigned long (4 octets) */
2009         data[offset + 3] = 0;
2010         data[offset + 4] = 1; /* Number Of Components = 1 */
2011         data[offset + 5] = 0;
2012         data[offset + 6] = 0;
2013         data[offset + 7] = 0;
2014         data[offset + 8] = (JOCTET)(new_value & 0xFF);
2015         data[offset + 9] = (JOCTET)((new_value >> 8) & 0xFF);
2016         data[offset + 10] = 0;
2017         data[offset + 11] = 0;
2018       }
2019     }
2020     offset += 12;
2021   } while (--number_of_tags);
2022 }
2023 
2024 
2025 /* Adjust output image parameters as needed.
2026  *
2027  * This must be called after jpeg_copy_critical_parameters()
2028  * and before jpeg_write_coefficients().
2029  *
2030  * The return value is the set of virtual coefficient arrays to be written
2031  * (either the ones allocated by jtransform_request_workspace, or the
2032  * original source data arrays).  The caller will need to pass this value
2033  * to jpeg_write_coefficients().
2034  */
2035 
2036 GLOBAL(jvirt_barray_ptr *)
jtransform_adjust_parameters(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jpeg_transform_info * info)2037 jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2038                              jvirt_barray_ptr *src_coef_arrays,
2039                              jpeg_transform_info *info)
2040 {
2041   /* If force-to-grayscale is requested, adjust destination parameters */
2042   if (info->force_grayscale) {
2043     /* First, ensure we have YCbCr or grayscale data, and that the source's
2044      * Y channel is full resolution.  (No reasonable person would make Y
2045      * be less than full resolution, so actually coping with that case
2046      * isn't worth extra code space.  But we check it to avoid crashing.)
2047      */
2048     if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
2049           dstinfo->num_components == 3) ||
2050          (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
2051           dstinfo->num_components == 1)) &&
2052         srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
2053         srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
2054       /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
2055        * properly.  Among other things, it sets the target h_samp_factor &
2056        * v_samp_factor to 1, which typically won't match the source.
2057        * We have to preserve the source's quantization table number, however.
2058        */
2059       int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
2060       jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
2061       dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
2062     } else {
2063       /* Sorry, can't do it */
2064       ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
2065     }
2066   } else if (info->num_components == 1) {
2067     /* For a single-component source, we force the destination sampling factors
2068      * to 1x1, with or without force_grayscale.  This is useful because some
2069      * decoders choke on grayscale images with other sampling factors.
2070      */
2071     dstinfo->comp_info[0].h_samp_factor = 1;
2072     dstinfo->comp_info[0].v_samp_factor = 1;
2073   }
2074 
2075   /* Correct the destination's image dimensions as necessary
2076    * for rotate/flip, resize, and crop operations.
2077    */
2078 #if JPEG_LIB_VERSION >= 80
2079   dstinfo->jpeg_width = info->output_width;
2080   dstinfo->jpeg_height = info->output_height;
2081 #endif
2082 
2083   /* Transpose destination image parameters, adjust quantization */
2084   switch (info->transform) {
2085   case JXFORM_TRANSPOSE:
2086   case JXFORM_TRANSVERSE:
2087   case JXFORM_ROT_90:
2088   case JXFORM_ROT_270:
2089 #if JPEG_LIB_VERSION < 80
2090     dstinfo->image_width = info->output_height;
2091     dstinfo->image_height = info->output_width;
2092 #endif
2093     transpose_critical_parameters(dstinfo);
2094     break;
2095   case JXFORM_DROP:
2096     if (info->drop_width != 0 && info->drop_height != 0)
2097       adjust_quant(srcinfo, src_coef_arrays,
2098                    info->drop_ptr, info->drop_coef_arrays,
2099                    info->trim, dstinfo);
2100     break;
2101   default:
2102 #if JPEG_LIB_VERSION < 80
2103     dstinfo->image_width = info->output_width;
2104     dstinfo->image_height = info->output_height;
2105 #endif
2106     break;
2107   }
2108 
2109   /* Adjust Exif properties */
2110   if (srcinfo->marker_list != NULL &&
2111       srcinfo->marker_list->marker == JPEG_APP0 + 1 &&
2112       srcinfo->marker_list->data_length >= 6 &&
2113       srcinfo->marker_list->data[0] == 0x45 &&
2114       srcinfo->marker_list->data[1] == 0x78 &&
2115       srcinfo->marker_list->data[2] == 0x69 &&
2116       srcinfo->marker_list->data[3] == 0x66 &&
2117       srcinfo->marker_list->data[4] == 0 &&
2118       srcinfo->marker_list->data[5] == 0) {
2119     /* Suppress output of JFIF marker */
2120     dstinfo->write_JFIF_header = FALSE;
2121     /* Adjust Exif image parameters */
2122 #if JPEG_LIB_VERSION >= 80
2123     if (dstinfo->jpeg_width != srcinfo->image_width ||
2124         dstinfo->jpeg_height != srcinfo->image_height)
2125       /* Align data segment to start of TIFF structure for parsing */
2126       adjust_exif_parameters(srcinfo->marker_list->data + 6,
2127                              srcinfo->marker_list->data_length - 6,
2128                              dstinfo->jpeg_width, dstinfo->jpeg_height);
2129 #else
2130     if (dstinfo->image_width != srcinfo->image_width ||
2131         dstinfo->image_height != srcinfo->image_height)
2132       /* Align data segment to start of TIFF structure for parsing */
2133       adjust_exif_parameters(srcinfo->marker_list->data + 6,
2134                              srcinfo->marker_list->data_length - 6,
2135                              dstinfo->image_width, dstinfo->image_height);
2136 #endif
2137   }
2138 
2139   /* Return the appropriate output data set */
2140   if (info->workspace_coef_arrays != NULL)
2141     return info->workspace_coef_arrays;
2142   return src_coef_arrays;
2143 }
2144 
2145 
2146 /* Execute the actual transformation, if any.
2147  *
2148  * This must be called *after* jpeg_write_coefficients, because it depends
2149  * on jpeg_write_coefficients to have computed subsidiary values such as
2150  * the per-component width and height fields in the destination object.
2151  *
2152  * Note that some transformations will modify the source data arrays!
2153  */
2154 
2155 GLOBAL(void)
jtransform_execute_transform(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jpeg_transform_info * info)2156 jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2157                              jvirt_barray_ptr *src_coef_arrays,
2158                              jpeg_transform_info *info)
2159 {
2160   jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
2161 
2162   /* Note: conditions tested here should match those in switch statement
2163    * in jtransform_request_workspace()
2164    */
2165   switch (info->transform) {
2166   case JXFORM_NONE:
2167     if (info->output_width > srcinfo->output_width ||
2168         info->output_height > srcinfo->output_height) {
2169       if (info->output_width > srcinfo->output_width &&
2170           info->crop_width_set == JCROP_REFLECT)
2171         do_crop_ext_reflect(srcinfo, dstinfo,
2172                             info->x_crop_offset, info->y_crop_offset,
2173                             src_coef_arrays, dst_coef_arrays);
2174       else if (info->output_width > srcinfo->output_width &&
2175                info->crop_width_set == JCROP_FORCE)
2176         do_crop_ext_flat(srcinfo, dstinfo,
2177                          info->x_crop_offset, info->y_crop_offset,
2178                          src_coef_arrays, dst_coef_arrays);
2179       else
2180         do_crop_ext_zero(srcinfo, dstinfo,
2181                          info->x_crop_offset, info->y_crop_offset,
2182                          src_coef_arrays, dst_coef_arrays);
2183     } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
2184       do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2185               src_coef_arrays, dst_coef_arrays);
2186     break;
2187   case JXFORM_FLIP_H:
2188     if (info->y_crop_offset != 0 || info->slow_hflip)
2189       do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2190                 src_coef_arrays, dst_coef_arrays);
2191     else
2192       do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
2193                         src_coef_arrays);
2194     break;
2195   case JXFORM_FLIP_V:
2196     do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2197               src_coef_arrays, dst_coef_arrays);
2198     break;
2199   case JXFORM_TRANSPOSE:
2200     do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2201                  src_coef_arrays, dst_coef_arrays);
2202     break;
2203   case JXFORM_TRANSVERSE:
2204     do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2205                   src_coef_arrays, dst_coef_arrays);
2206     break;
2207   case JXFORM_ROT_90:
2208     do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2209               src_coef_arrays, dst_coef_arrays);
2210     break;
2211   case JXFORM_ROT_180:
2212     do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2213                src_coef_arrays, dst_coef_arrays);
2214     break;
2215   case JXFORM_ROT_270:
2216     do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2217                src_coef_arrays, dst_coef_arrays);
2218     break;
2219   case JXFORM_WIPE:
2220     if (info->crop_width_set == JCROP_REFLECT &&
2221         info->y_crop_offset == 0 && info->drop_height ==
2222         (JDIMENSION)jdiv_round_up
2223           ((long)info->output_height, (long)info->iMCU_sample_height) &&
2224         (info->x_crop_offset == 0 ||
2225          info->x_crop_offset + info->drop_width ==
2226          (JDIMENSION)jdiv_round_up
2227            ((long)info->output_width, (long)info->iMCU_sample_width)))
2228       do_reflect(srcinfo, dstinfo, info->x_crop_offset,
2229                  src_coef_arrays, info->drop_width, info->drop_height);
2230     else if (info->crop_width_set == JCROP_FORCE)
2231       do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2232                  src_coef_arrays, info->drop_width, info->drop_height);
2233     else
2234       do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2235               src_coef_arrays, info->drop_width, info->drop_height);
2236     break;
2237   case JXFORM_DROP:
2238     if (info->drop_width != 0 && info->drop_height != 0)
2239       do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
2240               src_coef_arrays, info->drop_ptr, info->drop_coef_arrays,
2241               info->drop_width, info->drop_height);
2242     break;
2243   }
2244 }
2245 
2246 /* jtransform_perfect_transform
2247  *
2248  * Determine whether lossless transformation is perfectly
2249  * possible for a specified image and transformation.
2250  *
2251  * Inputs:
2252  *   image_width, image_height: source image dimensions.
2253  *   MCU_width, MCU_height: pixel dimensions of MCU.
2254  *   transform: transformation identifier.
2255  * Parameter sources from initialized jpeg_struct
2256  * (after reading source header):
2257  *   image_width = cinfo.image_width
2258  *   image_height = cinfo.image_height
2259  *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
2260  *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
2261  * Result:
2262  *   TRUE = perfect transformation possible
2263  *   FALSE = perfect transformation not possible
2264  *           (may use custom action then)
2265  */
2266 
2267 GLOBAL(boolean)
jtransform_perfect_transform(JDIMENSION image_width,JDIMENSION image_height,int MCU_width,int MCU_height,JXFORM_CODE transform)2268 jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
2269                              int MCU_width, int MCU_height,
2270                              JXFORM_CODE transform)
2271 {
2272   boolean result = TRUE; /* initialize TRUE */
2273 
2274   switch (transform) {
2275   case JXFORM_FLIP_H:
2276   case JXFORM_ROT_270:
2277     if (image_width % (JDIMENSION)MCU_width)
2278       result = FALSE;
2279     break;
2280   case JXFORM_FLIP_V:
2281   case JXFORM_ROT_90:
2282     if (image_height % (JDIMENSION)MCU_height)
2283       result = FALSE;
2284     break;
2285   case JXFORM_TRANSVERSE:
2286   case JXFORM_ROT_180:
2287     if (image_width % (JDIMENSION)MCU_width)
2288       result = FALSE;
2289     if (image_height % (JDIMENSION)MCU_height)
2290       result = FALSE;
2291     break;
2292   default:
2293     break;
2294   }
2295 
2296   return result;
2297 }
2298 
2299 #endif /* TRANSFORMS_SUPPORTED */
2300 
2301 
2302 /* Setup decompression object to save desired markers in memory.
2303  * This must be called before jpeg_read_header() to have the desired effect.
2304  */
2305 
2306 GLOBAL(void)
jcopy_markers_setup(j_decompress_ptr srcinfo,JCOPY_OPTION option)2307 jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option)
2308 {
2309 #ifdef SAVE_MARKERS_SUPPORTED
2310   int m;
2311 
2312   /* Save comments except under NONE option */
2313   if (option != JCOPYOPT_NONE && option != JCOPYOPT_ICC) {
2314     jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
2315   }
2316   /* Save all types of APPn markers iff ALL option */
2317   if (option == JCOPYOPT_ALL || option == JCOPYOPT_ALL_EXCEPT_ICC) {
2318     for (m = 0; m < 16; m++) {
2319       if (option == JCOPYOPT_ALL_EXCEPT_ICC && m == 2)
2320         continue;
2321       jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
2322     }
2323   }
2324   /* Save only APP2 markers if ICC option selected */
2325   if (option == JCOPYOPT_ICC) {
2326     jpeg_save_markers(srcinfo, JPEG_APP0 + 2, 0xFFFF);
2327   }
2328 #endif /* SAVE_MARKERS_SUPPORTED */
2329 }
2330 
2331 /* Copy markers saved in the given source object to the destination object.
2332  * This should be called just after jpeg_start_compress() or
2333  * jpeg_write_coefficients().
2334  * Note that those routines will have written the SOI, and also the
2335  * JFIF APP0 or Adobe APP14 markers if selected.
2336  */
2337 
2338 GLOBAL(void)
jcopy_markers_execute(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JCOPY_OPTION option)2339 jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2340                       JCOPY_OPTION option)
2341 {
2342   jpeg_saved_marker_ptr marker;
2343 
2344   /* In the current implementation, we don't actually need to examine the
2345    * option flag here; we just copy everything that got saved.
2346    * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
2347    * if the encoder library already wrote one.
2348    */
2349   for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
2350     if (dstinfo->write_JFIF_header &&
2351         marker->marker == JPEG_APP0 &&
2352         marker->data_length >= 5 &&
2353         marker->data[0] == 0x4A &&
2354         marker->data[1] == 0x46 &&
2355         marker->data[2] == 0x49 &&
2356         marker->data[3] == 0x46 &&
2357         marker->data[4] == 0)
2358       continue;                 /* reject duplicate JFIF */
2359     if (dstinfo->write_Adobe_marker &&
2360         marker->marker == JPEG_APP0 + 14 &&
2361         marker->data_length >= 5 &&
2362         marker->data[0] == 0x41 &&
2363         marker->data[1] == 0x64 &&
2364         marker->data[2] == 0x6F &&
2365         marker->data[3] == 0x62 &&
2366         marker->data[4] == 0x65)
2367       continue;                 /* reject duplicate Adobe */
2368     jpeg_write_marker(dstinfo, marker->marker,
2369                       marker->data, marker->data_length);
2370   }
2371 }
2372