blob: 6e860778908f7597ae0ce0d1d912a3868fa5df4b [file] [log] [blame]
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001/*
2 * transupp.c
3 *
noel@chromium.org3395bcc2014-04-14 06:56:00 +00004 * This file was part of the Independent JPEG Group's software:
Jonathan Wrightbbb82822020-11-25 13:36:43 +00005 * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
noel@chromium.org3395bcc2014-04-14 06:56:00 +00006 * libjpeg-turbo Modifications:
Chris Blumecca8c4d2019-03-01 01:09:50 -08007 * Copyright (C) 2010, 2017, D. R. Commander.
Tom Hudson0d47d2d2016-05-04 13:22:56 -04008 * For conditions of distribution and use, see the accompanying README.ijg
9 * file.
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000010 *
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"
Tom Hudson0d47d2d2016-05-04 13:22:56 -040025#include "transupp.h" /* My own external interface */
hbono@chromium.org98626972011-08-03 03:13:08 +000026#include "jpegcomp.h"
Tom Hudson0d47d2d2016-05-04 13:22:56 -040027#include <ctype.h> /* to declare isdigit() */
hbono@chromium.org98626972011-08-03 03:13:08 +000028
29
30#if JPEG_LIB_VERSION >= 70
Chris Blumecca8c4d2019-03-01 01:09:50 -080031#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
hbono@chromium.org98626972011-08-03 03:13:08 +000033#else
Chris Blumecca8c4d2019-03-01 01:09:50 -080034#define dstinfo_min_DCT_h_scaled_size DCTSIZE
35#define dstinfo_min_DCT_v_scaled_size DCTSIZE
hbono@chromium.org98626972011-08-03 03:13:08 +000036#endif
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000037
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.
hbono@chromium.org98626972011-08-03 03:13:08 +000045 * Thanks to Guido Vollbeding for the initial design and code of this feature,
46 * and to Ben Jackson for introducing the cropping feature.
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000047 *
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 *
hbono@chromium.org98626972011-08-03 03:13:08 +000060 * 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 *
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000067 * 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.
hbono@chromium.org98626972011-08-03 03:13:08 +000079 * 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
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000086 * padded out to a full iMCU boundary. This is true, although for the
87 * source buffer it is an undocumented property of jdcoefct.c.
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000088 */
89
90
91LOCAL(void)
Jonathan Wrightbbb82822020-11-25 13:36:43 +000092dequant_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
121LOCAL(void)
122requant_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 */
175LOCAL(JCOEF)
176largest_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
190LOCAL(void)
191adjust_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
226LOCAL(void)
227do_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
274LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800275do_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)
hbono@chromium.org98626972011-08-03 03:13:08 +0000279/* Crop. This is only used when no rotate/flip is requested with the crop. */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000280{
hbono@chromium.org98626972011-08-03 03:13:08 +0000281 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;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400294 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.org98626972011-08-03 03:13:08 +0000295 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800296 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
297 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +0000298 src_buffer = (*srcinfo->mem->access_virt_barray)
Jonathan Wrightbbb82822020-11-25 13:36:43 +0000299 ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -0800300 (JDIMENSION)compptr->v_samp_factor, FALSE);
hbono@chromium.org98626972011-08-03 03:13:08 +0000301 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400302 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
Jonathan Wrightbbb82822020-11-25 13:36:43 +0000303 dst_buffer[offset_y], compptr->width_in_blocks);
304 }
305 }
306 }
307}
308
309
310LOCAL(void)
311do_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
385LOCAL(void)
386do_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
465LOCAL(void)
466do_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
567LOCAL(void)
568do_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
601LOCAL(void)
602do_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
650LOCAL(void)
651do_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 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000715 }
716 }
717 }
718}
719
720
721LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800722do_flip_h_no_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
723 JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays)
hbono@chromium.org98626972011-08-03 03:13:08 +0000724/* 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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000729 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 */
hbono@chromium.org98626972011-08-03 03:13:08 +0000740 MCU_cols = srcinfo->output_width /
Chris Blumecca8c4d2019-03-01 01:09:50 -0800741 (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000742
743 for (ci = 0; ci < dstinfo->num_components; ci++) {
744 compptr = dstinfo->comp_info + ci;
745 comp_width = MCU_cols * compptr->h_samp_factor;
hbono@chromium.org98626972011-08-03 03:13:08 +0000746 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000747 for (blk_y = 0; blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400748 blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000749 buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800750 ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y,
751 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000752 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400753 /* 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,
Chris Blumecca8c4d2019-03-01 01:09:50 -0800777 buffer[offset_y] + blk_x, (JDIMENSION)1);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400778 }
779 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000780 }
781 }
782 }
783}
784
785
786LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800787do_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)
hbono@chromium.org98626972011-08-03 03:13:08 +0000791/* 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 /
Chris Blumecca8c4d2019-03-01 01:09:50 -0800806 (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
hbono@chromium.org98626972011-08-03 03:13:08 +0000807
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;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400814 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.org98626972011-08-03 03:13:08 +0000815 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800816 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
817 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +0000818 src_buffer = (*srcinfo->mem->access_virt_barray)
Jonathan Wrightbbb82822020-11-25 13:36:43 +0000819 ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -0800820 (JDIMENSION)compptr->v_samp_factor, FALSE);
hbono@chromium.org98626972011-08-03 03:13:08 +0000821 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400822 dst_row_ptr = dst_buffer[offset_y];
823 src_row_ptr = src_buffer[offset_y];
Chris Blumecca8c4d2019-03-01 01:09:50 -0800824 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
825 dst_blk_x++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400826 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) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +0000832 *dst_ptr++ = *src_ptr++; /* copy even column */
833 *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
834 change */
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400835 }
836 } else {
837 /* Copy last partial block(s) verbatim */
838 jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -0800839 dst_row_ptr + dst_blk_x, (JDIMENSION)1);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400840 }
841 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000842 }
843 }
844 }
845}
846
847
848LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800849do_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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000853/* Vertical flip */
854{
855 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
hbono@chromium.org98626972011-08-03 03:13:08 +0000856 JDIMENSION x_crop_blocks, y_crop_blocks;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000857 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 */
hbono@chromium.org98626972011-08-03 03:13:08 +0000870 MCU_rows = srcinfo->output_height /
Chris Blumecca8c4d2019-03-01 01:09:50 -0800871 (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000872
873 for (ci = 0; ci < dstinfo->num_components; ci++) {
874 compptr = dstinfo->comp_info + ci;
875 comp_height = MCU_rows * compptr->v_samp_factor;
hbono@chromium.org98626972011-08-03 03:13:08 +0000876 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
877 y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000878 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400879 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000880 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800881 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
882 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +0000883 if (y_crop_blocks + dst_blk_y < comp_height) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400884 /* Row is within the mirrorable area. */
885 src_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800886 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400887 comp_height - y_crop_blocks - dst_blk_y -
Chris Blumecca8c4d2019-03-01 01:09:50 -0800888 (JDIMENSION)compptr->v_samp_factor,
889 (JDIMENSION)compptr->v_samp_factor, FALSE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000890 } else {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400891 /* Bottom-edge blocks will be copied verbatim. */
892 src_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800893 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400894 dst_blk_y + y_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -0800895 (JDIMENSION)compptr->v_samp_factor, FALSE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000896 }
897 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400898 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++)
Jonathan Wrightbbb82822020-11-25 13:36:43 +0000913 *dst_ptr++ = -(*src_ptr++);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400914 }
915 }
916 } else {
917 /* Just copy row verbatim. */
918 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
Jonathan Wrightbbb82822020-11-25 13:36:43 +0000919 dst_buffer[offset_y], compptr->width_in_blocks);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400920 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000921 }
922 }
923 }
924}
925
926
927LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800928do_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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000932/* Transpose source into destination */
933{
hbono@chromium.org98626972011-08-03 03:13:08 +0000934 JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000935 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;
hbono@chromium.org98626972011-08-03 03:13:08 +0000947 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
948 y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000949 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400950 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000951 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800952 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
953 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000954 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400955 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)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800958 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400959 dst_blk_x + x_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -0800960 (JDIMENSION)compptr->h_samp_factor, FALSE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400961 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
962 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
Chris Blumecca8c4d2019-03-01 01:09:50 -0800963 src_ptr =
964 src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400965 for (i = 0; i < DCTSIZE; i++)
966 for (j = 0; j < DCTSIZE; j++)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800967 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400968 }
969 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000970 }
971 }
972 }
973}
974
975
976LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800977do_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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000981/* 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;
hbono@chromium.org98626972011-08-03 03:13:08 +0000988 JDIMENSION x_crop_blocks, y_crop_blocks;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000989 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 */
hbono@chromium.org98626972011-08-03 03:13:08 +0000998 MCU_cols = srcinfo->output_height /
Chris Blumecca8c4d2019-03-01 01:09:50 -0800999 (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001000
1001 for (ci = 0; ci < dstinfo->num_components; ci++) {
1002 compptr = dstinfo->comp_info + ci;
1003 comp_width = MCU_cols * compptr->h_samp_factor;
hbono@chromium.org98626972011-08-03 03:13:08 +00001004 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1005 y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001006 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001007 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001008 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001009 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1010 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001011 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001012 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)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001017 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001018 comp_width - x_crop_blocks - dst_blk_x -
Chris Blumecca8c4d2019-03-01 01:09:50 -08001019 (JDIMENSION)compptr->h_samp_factor,
1020 (JDIMENSION)compptr->h_samp_factor, FALSE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001021 } else {
1022 /* Edge blocks are transposed but not mirrored. */
1023 src_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001024 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001025 dst_blk_x + x_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -08001026 (JDIMENSION)compptr->h_samp_factor, FALSE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001027 }
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++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001036 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001037 i++;
1038 for (j = 0; j < DCTSIZE; j++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001039 dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001040 }
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++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001047 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001048 }
1049 }
1050 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001051 }
1052 }
1053 }
1054}
1055
1056
1057LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001058do_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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001062/* 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001069 JDIMENSION x_crop_blocks, y_crop_blocks;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001070 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 */
hbono@chromium.org98626972011-08-03 03:13:08 +00001079 MCU_rows = srcinfo->output_width /
Chris Blumecca8c4d2019-03-01 01:09:50 -08001080 (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001081
1082 for (ci = 0; ci < dstinfo->num_components; ci++) {
1083 compptr = dstinfo->comp_info + ci;
1084 comp_height = MCU_rows * compptr->v_samp_factor;
hbono@chromium.org98626972011-08-03 03:13:08 +00001085 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1086 y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001087 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001088 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001089 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001090 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1091 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001092 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001093 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)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001096 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001097 dst_blk_x + x_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -08001098 (JDIMENSION)compptr->h_samp_factor, FALSE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001099 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++) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001107 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001108 j++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001109 dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001110 }
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++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001118 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001119 }
1120 }
1121 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001122 }
1123 }
1124 }
1125}
1126
1127
1128LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001129do_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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001133/* 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001140 JDIMENSION x_crop_blocks, y_crop_blocks;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001141 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
hbono@chromium.org98626972011-08-03 03:13:08 +00001147 MCU_cols = srcinfo->output_width /
Chris Blumecca8c4d2019-03-01 01:09:50 -08001148 (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
hbono@chromium.org98626972011-08-03 03:13:08 +00001149 MCU_rows = srcinfo->output_height /
Chris Blumecca8c4d2019-03-01 01:09:50 -08001150 (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001151
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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001156 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1157 y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001158 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001159 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001160 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001161 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1162 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.org98626972011-08-03 03:13:08 +00001163 if (y_crop_blocks + dst_blk_y < comp_height) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001164 /* Row is within the vertically mirrorable area. */
1165 src_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001166 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001167 comp_height - y_crop_blocks - dst_blk_y -
Chris Blumecca8c4d2019-03-01 01:09:50 -08001168 (JDIMENSION)compptr->v_samp_factor,
1169 (JDIMENSION)compptr->v_samp_factor, FALSE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001170 } else {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001171 /* Bottom-edge rows are only mirrored horizontally. */
1172 src_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001173 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001174 dst_blk_y + y_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -08001175 (JDIMENSION)compptr->v_samp_factor, FALSE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001176 }
1177 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001178 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];
Chris Blumecca8c4d2019-03-01 01:09:50 -08001182 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1183 dst_blk_x++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001184 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. */
Chris Blumecca8c4d2019-03-01 01:09:50 -08001187 src_ptr =
1188 src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001189 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++;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001193 *dst_ptr++ = -(*src_ptr++);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001194 }
1195 /* For odd row, negate every even column. */
1196 for (j = 0; j < DCTSIZE; j += 2) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001197 *dst_ptr++ = -(*src_ptr++);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001198 *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++)
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001208 *dst_ptr++ = -(*src_ptr++);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001209 }
1210 }
1211 }
1212 } else {
1213 /* Remaining rows are just mirrored horizontally. */
1214 src_row_ptr = src_buffer[offset_y];
Chris Blumecca8c4d2019-03-01 01:09:50 -08001215 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
1216 dst_blk_x++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001217 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];
Chris Blumecca8c4d2019-03-01 01:09:50 -08001220 src_ptr =
1221 src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001222 for (i = 0; i < DCTSIZE2; i += 2) {
1223 *dst_ptr++ = *src_ptr++;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001224 *dst_ptr++ = -(*src_ptr++);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001225 }
1226 } else {
1227 /* Any remaining right-edge blocks are only copied. */
1228 jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -08001229 dst_row_ptr + dst_blk_x, (JDIMENSION)1);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001230 }
1231 }
1232 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001233 }
1234 }
1235 }
1236}
1237
1238
1239LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001240do_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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001244/* 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001255 JDIMENSION x_crop_blocks, y_crop_blocks;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001256 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
hbono@chromium.org98626972011-08-03 03:13:08 +00001261 MCU_cols = srcinfo->output_height /
Chris Blumecca8c4d2019-03-01 01:09:50 -08001262 (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
hbono@chromium.org98626972011-08-03 03:13:08 +00001263 MCU_rows = srcinfo->output_width /
Chris Blumecca8c4d2019-03-01 01:09:50 -08001264 (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001265
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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001270 x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
1271 y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001272 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001273 dst_blk_y += compptr->v_samp_factor) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001274 dst_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001275 ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
1276 (JDIMENSION)compptr->v_samp_factor, TRUE);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001277 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001278 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)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001283 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001284 comp_width - x_crop_blocks - dst_blk_x -
Chris Blumecca8c4d2019-03-01 01:09:50 -08001285 (JDIMENSION)compptr->h_samp_factor,
1286 (JDIMENSION)compptr->h_samp_factor, FALSE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001287 } else {
1288 src_buffer = (*srcinfo->mem->access_virt_barray)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001289 ((j_common_ptr)srcinfo, src_coef_arrays[ci],
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001290 dst_blk_x + x_crop_blocks,
Chris Blumecca8c4d2019-03-01 01:09:50 -08001291 (JDIMENSION)compptr->h_samp_factor, FALSE);
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001292 }
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++) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001302 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001303 j++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001304 dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001305 }
1306 i++;
1307 for (j = 0; j < DCTSIZE; j++) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001308 dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001309 j++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001310 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001311 }
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++) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001319 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001320 j++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001321 dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001322 }
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++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001332 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001333 i++;
1334 for (j = 0; j < DCTSIZE; j++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001335 dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001336 }
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++)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001343 dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001344 }
1345 }
1346 }
1347 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001348 }
1349 }
1350 }
1351}
1352
1353
hbono@chromium.org98626972011-08-03 03:13:08 +00001354/* 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
1359LOCAL(boolean)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001360jt_read_integer(const char **strptr, JDIMENSION *result)
hbono@chromium.org98626972011-08-03 03:13:08 +00001361{
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001362 const char *ptr = *strptr;
hbono@chromium.org98626972011-08-03 03:13:08 +00001363 JDIMENSION val = 0;
1364
1365 for (; isdigit(*ptr); ptr++) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001366 val = val * 10 + (JDIMENSION)(*ptr - '0');
hbono@chromium.org98626972011-08-03 03:13:08 +00001367 }
1368 *result = val;
1369 if (ptr == *strptr)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001370 return FALSE; /* oops, no digits */
hbono@chromium.org98626972011-08-03 03:13:08 +00001371 *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
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001380 * <width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset>
hbono@chromium.org98626972011-08-03 03:13:08 +00001381 * 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
1389GLOBAL(boolean)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001390jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
hbono@chromium.org98626972011-08-03 03:13:08 +00001391{
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 */
Chris Blumecca8c4d2019-03-01 01:09:50 -08001400 if (!jt_read_integer(&spec, &info->crop_width))
hbono@chromium.org98626972011-08-03 03:13:08 +00001401 return FALSE;
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001402 if (*spec == 'f' || *spec == 'F') {
1403 spec++;
1404 info->crop_width_set = JCROP_FORCE;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001405 } else if (*spec == 'r' || *spec == 'R') {
1406 spec++;
1407 info->crop_width_set = JCROP_REFLECT;
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001408 } else
1409 info->crop_width_set = JCROP_POS;
hbono@chromium.org98626972011-08-03 03:13:08 +00001410 }
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001411 if (*spec == 'x' || *spec == 'X') {
hbono@chromium.org98626972011-08-03 03:13:08 +00001412 /* fetch height */
1413 spec++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001414 if (!jt_read_integer(&spec, &info->crop_height))
hbono@chromium.org98626972011-08-03 03:13:08 +00001415 return FALSE;
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001416 if (*spec == 'f' || *spec == 'F') {
1417 spec++;
1418 info->crop_height_set = JCROP_FORCE;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001419 } else if (*spec == 'r' || *spec == 'R') {
1420 spec++;
1421 info->crop_height_set = JCROP_REFLECT;
noel@chromium.org3395bcc2014-04-14 06:56:00 +00001422 } else
1423 info->crop_height_set = JCROP_POS;
hbono@chromium.org98626972011-08-03 03:13:08 +00001424 }
1425 if (*spec == '+' || *spec == '-') {
1426 /* fetch xoffset */
1427 info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
1428 spec++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001429 if (!jt_read_integer(&spec, &info->crop_xoffset))
hbono@chromium.org98626972011-08-03 03:13:08 +00001430 return FALSE;
1431 }
1432 if (*spec == '+' || *spec == '-') {
1433 /* fetch yoffset */
1434 info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
1435 spec++;
Chris Blumecca8c4d2019-03-01 01:09:50 -08001436 if (!jt_read_integer(&spec, &info->crop_yoffset))
hbono@chromium.org98626972011-08-03 03:13:08 +00001437 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
1449LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001450trim_right_edge(jpeg_transform_info *info, JDIMENSION full_width)
hbono@chromium.org98626972011-08-03 03:13:08 +00001451{
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
1460LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001461trim_bottom_edge(jpeg_transform_info *info, JDIMENSION full_height)
hbono@chromium.org98626972011-08-03 03:13:08 +00001462{
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
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001472/* Request any required workspace.
1473 *
hbono@chromium.org98626972011-08-03 03:13:08 +00001474 * 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 *
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001478 * 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).
hbono@chromium.org98626972011-08-03 03:13:08 +00001484 *
1485 * This function returns FALSE right away if -perfect is given
1486 * and transformation is not perfect. Otherwise returns TRUE.
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001487 */
1488
hbono@chromium.org98626972011-08-03 03:13:08 +00001489GLOBAL(boolean)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001490jtransform_request_workspace(j_decompress_ptr srcinfo,
1491 jpeg_transform_info *info)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001492{
hbono@chromium.org98626972011-08-03 03:13:08 +00001493 jvirt_barray_ptr *coef_arrays;
1494 boolean need_workspace, transpose_it;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001495 jpeg_component_info *compptr;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001496 JDIMENSION xoffset, yoffset, dtemp;
hbono@chromium.org98626972011-08-03 03:13:08 +00001497 JDIMENSION width_in_iMCUs, height_in_iMCUs;
1498 JDIMENSION width_in_blocks, height_in_blocks;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001499 int itemp, ci, h_samp_factor, v_samp_factor;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001500
hbono@chromium.org98626972011-08-03 03:13:08 +00001501 /* Determine number of components in output image */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001502 if (info->force_grayscale &&
1503 srcinfo->jpeg_color_space == JCS_YCbCr &&
hbono@chromium.org98626972011-08-03 03:13:08 +00001504 srcinfo->num_components == 3)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001505 /* We'll only process the first component */
1506 info->num_components = 1;
hbono@chromium.org98626972011-08-03 03:13:08 +00001507 else
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001508 /* Process all the components */
1509 info->num_components = srcinfo->num_components;
hbono@chromium.org98626972011-08-03 03:13:08 +00001510
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,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001524 srcinfo->output_height,
1525 srcinfo->_min_DCT_h_scaled_size,
1526 srcinfo->_min_DCT_v_scaled_size,
1527 info->transform))
1528 return FALSE;
hbono@chromium.org98626972011-08-03 03:13:08 +00001529 } else {
1530 if (!jtransform_perfect_transform(srcinfo->output_width,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001531 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001536 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001537 }
1538
hbono@chromium.org98626972011-08-03 03:13:08 +00001539 /* 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 */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001544 switch (info->transform) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001545 case JXFORM_TRANSPOSE:
1546 case JXFORM_TRANSVERSE:
1547 case JXFORM_ROT_90:
1548 case JXFORM_ROT_270:
hbono@chromium.org98626972011-08-03 03:13:08 +00001549 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 =
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001556 srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
hbono@chromium.org98626972011-08-03 03:13:08 +00001557 info->iMCU_sample_height =
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001558 srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
hbono@chromium.org98626972011-08-03 03:13:08 +00001559 }
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 =
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001569 srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
hbono@chromium.org98626972011-08-03 03:13:08 +00001570 info->iMCU_sample_height =
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001571 srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001572 }
1573 break;
1574 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001575
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)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001582 info->crop_xoffset = 0; /* default to +0 */
hbono@chromium.org98626972011-08-03 03:13:08 +00001583 if (info->crop_yoffset_set == JCROP_UNSET)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001584 info->crop_yoffset = 0; /* default to +0 */
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001585 if (info->crop_width_set == JCROP_UNSET) {
1586 if (info->crop_xoffset >= info->output_width)
1587 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
hbono@chromium.org98626972011-08-03 03:13:08 +00001588 info->crop_width = info->output_width - info->crop_xoffset;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001589 } 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);
hbono@chromium.org98626972011-08-03 03:13:08 +00001607 info->crop_height = info->output_height - info->crop_yoffset;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001608 } 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 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001623 /* Convert negative crop offsets into regular offsets */
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001624 if (info->crop_xoffset_set != JCROP_NEG)
hbono@chromium.org98626972011-08-03 03:13:08 +00001625 xoffset = info->crop_xoffset;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001626 else if (info->crop_width > info->output_width) /* crop extension */
1627 xoffset = info->crop_width - info->output_width - info->crop_xoffset;
hbono@chromium.org98626972011-08-03 03:13:08 +00001628 else
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001629 xoffset = info->output_width - info->crop_width - info->crop_xoffset;
1630 if (info->crop_yoffset_set != JCROP_NEG)
hbono@chromium.org98626972011-08-03 03:13:08 +00001631 yoffset = info->crop_yoffset;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001632 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00001636 /* Now adjust so that upper left corner falls at an iMCU boundary */
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001637 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 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001708 /* 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:
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001723 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)
hbono@chromium.org98626972011-08-03 03:13:08 +00001726 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;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001779 case JXFORM_WIPE:
1780 break;
1781 case JXFORM_DROP:
1782 break;
hbono@chromium.org98626972011-08-03 03:13:08 +00001783 }
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 *)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001791 (*srcinfo->mem->alloc_small) ((j_common_ptr)srcinfo, JPOOL_IMAGE,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001792 sizeof(jvirt_barray_ptr) * info->num_components);
hbono@chromium.org98626972011-08-03 03:13:08 +00001793 width_in_iMCUs = (JDIMENSION)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001794 jdiv_round_up((long)info->output_width, (long)info->iMCU_sample_width);
hbono@chromium.org98626972011-08-03 03:13:08 +00001795 height_in_iMCUs = (JDIMENSION)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001796 jdiv_round_up((long)info->output_height, (long)info->iMCU_sample_height);
hbono@chromium.org98626972011-08-03 03:13:08 +00001797 for (ci = 0; ci < info->num_components; ci++) {
1798 compptr = srcinfo->comp_info + ci;
1799 if (info->num_components == 1) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001800 /* we're going to force samp factors to 1x1 in this case */
1801 h_samp_factor = v_samp_factor = 1;
hbono@chromium.org98626972011-08-03 03:13:08 +00001802 } else if (transpose_it) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001803 h_samp_factor = compptr->v_samp_factor;
1804 v_samp_factor = compptr->h_samp_factor;
hbono@chromium.org98626972011-08-03 03:13:08 +00001805 } else {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001806 h_samp_factor = compptr->h_samp_factor;
1807 v_samp_factor = compptr->v_samp_factor;
hbono@chromium.org98626972011-08-03 03:13:08 +00001808 }
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)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001812 ((j_common_ptr)srcinfo, JPOOL_IMAGE, FALSE,
1813 width_in_blocks, height_in_blocks, (JDIMENSION)v_samp_factor);
hbono@chromium.org98626972011-08-03 03:13:08 +00001814 }
1815 info->workspace_coef_arrays = coef_arrays;
1816 } else
1817 info->workspace_coef_arrays = NULL;
1818
1819 return TRUE;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001820}
1821
1822
1823/* Transpose destination image parameters */
1824
1825LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001826transpose_critical_parameters(j_compress_ptr dstinfo)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001827{
1828 int tblno, i, j, ci, itemp;
1829 jpeg_component_info *compptr;
1830 JQUANT_TBL *qtblptr;
hbono@chromium.org98626972011-08-03 03:13:08 +00001831 JDIMENSION jtemp;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001832 UINT16 qtemp;
1833
hbono@chromium.org98626972011-08-03 03:13:08 +00001834 /* Transpose image dimensions */
1835 jtemp = dstinfo->image_width;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001836 dstinfo->image_width = dstinfo->image_height;
hbono@chromium.org98626972011-08-03 03:13:08 +00001837 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
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001843
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++) {
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001857 for (j = 0; j < i; j++) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001858 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;
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001862 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001863 }
1864 }
1865 }
1866}
1867
1868
hbono@chromium.org98626972011-08-03 03:13:08 +00001869/* Adjust Exif image parameters.
1870 *
1871 * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1872 */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001873
1874LOCAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08001875adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
1876 JDIMENSION new_height)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001877{
hbono@chromium.org98626972011-08-03 03:13:08 +00001878 boolean is_motorola; /* Flag for byte order */
1879 unsigned int number_of_tags, tagnum;
1880 unsigned int firstoffset, offset;
1881 JDIMENSION new_value;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001882
hbono@chromium.org98626972011-08-03 03:13:08 +00001883 if (length < 12) return; /* Length of an IFD entry */
1884
1885 /* Discover byte order */
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001886 if (data[0] == 0x49 && data[1] == 0x49)
hbono@chromium.org98626972011-08-03 03:13:08 +00001887 is_motorola = FALSE;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001888 else if (data[0] == 0x4D && data[1] == 0x4D)
hbono@chromium.org98626972011-08-03 03:13:08 +00001889 is_motorola = TRUE;
1890 else
1891 return;
1892
1893 /* Check Tag Mark */
1894 if (is_motorola) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001895 if (data[2] != 0) return;
1896 if (data[3] != 0x2A) return;
hbono@chromium.org98626972011-08-03 03:13:08 +00001897 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001898 if (data[3] != 0) return;
1899 if (data[2] != 0x2A) return;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001900 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001901
hbono@chromium.org98626972011-08-03 03:13:08 +00001902 /* Get first IFD offset (offset to IFD0) */
1903 if (is_motorola) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001904 if (data[4] != 0) return;
1905 if (data[5] != 0) return;
1906 firstoffset = data[6];
hbono@chromium.org98626972011-08-03 03:13:08 +00001907 firstoffset <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001908 firstoffset += data[7];
hbono@chromium.org98626972011-08-03 03:13:08 +00001909 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001910 if (data[7] != 0) return;
1911 if (data[6] != 0) return;
1912 firstoffset = data[5];
hbono@chromium.org98626972011-08-03 03:13:08 +00001913 firstoffset <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001914 firstoffset += data[4];
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00001915 }
hbono@chromium.org98626972011-08-03 03:13:08 +00001916 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) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001920 number_of_tags = data[firstoffset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001921 number_of_tags <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001922 number_of_tags += data[firstoffset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001923 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001924 number_of_tags = data[firstoffset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001925 number_of_tags <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001926 number_of_tags += data[firstoffset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001927 }
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) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001936 tagnum = data[firstoffset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001937 tagnum <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001938 tagnum += data[firstoffset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001939 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001940 tagnum = data[firstoffset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001941 tagnum <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001942 tagnum += data[firstoffset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001943 }
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) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001951 if (data[firstoffset + 8] != 0) return;
1952 if (data[firstoffset + 9] != 0) return;
1953 offset = data[firstoffset + 10];
hbono@chromium.org98626972011-08-03 03:13:08 +00001954 offset <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001955 offset += data[firstoffset + 11];
hbono@chromium.org98626972011-08-03 03:13:08 +00001956 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001957 if (data[firstoffset + 11] != 0) return;
1958 if (data[firstoffset + 10] != 0) return;
1959 offset = data[firstoffset + 9];
hbono@chromium.org98626972011-08-03 03:13:08 +00001960 offset <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001961 offset += data[firstoffset + 8];
hbono@chromium.org98626972011-08-03 03:13:08 +00001962 }
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) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001967 number_of_tags = data[offset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001968 number_of_tags <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001969 number_of_tags += data[offset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001970 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001971 number_of_tags = data[offset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001972 number_of_tags <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001973 number_of_tags += data[offset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001974 }
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) {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001983 tagnum = data[offset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001984 tagnum <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001985 tagnum += data[offset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001986 } else {
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001987 tagnum = data[offset + 1];
hbono@chromium.org98626972011-08-03 03:13:08 +00001988 tagnum <<= 8;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00001989 tagnum += data[offset];
hbono@chromium.org98626972011-08-03 03:13:08 +00001990 }
1991 if (tagnum == 0xA002 || tagnum == 0xA003) {
1992 if (tagnum == 0xA002)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001993 new_value = new_width; /* ExifImageWidth Tag */
hbono@chromium.org98626972011-08-03 03:13:08 +00001994 else
Tom Hudson0d47d2d2016-05-04 13:22:56 -04001995 new_value = new_height; /* ExifImageHeight Tag */
hbono@chromium.org98626972011-08-03 03:13:08 +00001996 if (is_motorola) {
Chris Blumecca8c4d2019-03-01 01:09:50 -08001997 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);
hbono@chromium.org98626972011-08-03 03:13:08 +00002007 } else {
Chris Blumecca8c4d2019-03-01 01:09:50 -08002008 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00002018 }
2019 }
2020 offset += 12;
2021 } while (--number_of_tags);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002022}
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
2036GLOBAL(jvirt_barray_ptr *)
Chris Blumecca8c4d2019-03-01 01:09:50 -08002037jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2038 jvirt_barray_ptr *src_coef_arrays,
2039 jpeg_transform_info *info)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002040{
2041 /* If force-to-grayscale is requested, adjust destination parameters */
2042 if (info->force_grayscale) {
hbono@chromium.org98626972011-08-03 03:13:08 +00002043 /* 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.)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002047 */
hbono@chromium.org98626972011-08-03 03:13:08 +00002048 if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002049 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) {
hbono@chromium.org98626972011-08-03 03:13:08 +00002054 /* 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 */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002059 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 }
hbono@chromium.org98626972011-08-03 03:13:08 +00002066 } 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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002073 }
2074
hbono@chromium.org98626972011-08-03 03:13:08 +00002075 /* Correct the destination's image dimensions as necessary
2076 * for rotate/flip, resize, and crop operations.
2077 */
Chris Blumecca8c4d2019-03-01 01:09:50 -08002078#if JPEG_LIB_VERSION >= 80
hbono@chromium.org98626972011-08-03 03:13:08 +00002079 dstinfo->jpeg_width = info->output_width;
2080 dstinfo->jpeg_height = info->output_height;
2081#endif
2082
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002083 /* Transpose destination image parameters, adjust quantization */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002084 switch (info->transform) {
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002085 case JXFORM_TRANSPOSE:
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002086 case JXFORM_TRANSVERSE:
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002087 case JXFORM_ROT_90:
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002088 case JXFORM_ROT_270:
Chris Blumecca8c4d2019-03-01 01:09:50 -08002089#if JPEG_LIB_VERSION < 80
hbono@chromium.org98626972011-08-03 03:13:08 +00002090 dstinfo->image_width = info->output_height;
2091 dstinfo->image_height = info->output_width;
2092#endif
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002093 transpose_critical_parameters(dstinfo);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002094 break;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002095 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;
hbono@chromium.org98626972011-08-03 03:13:08 +00002101 default:
Chris Blumecca8c4d2019-03-01 01:09:50 -08002102#if JPEG_LIB_VERSION < 80
hbono@chromium.org98626972011-08-03 03:13:08 +00002103 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 &&
Chris Blumecca8c4d2019-03-01 01:09:50 -08002111 srcinfo->marker_list->marker == JPEG_APP0 + 1 &&
hbono@chromium.org98626972011-08-03 03:13:08 +00002112 srcinfo->marker_list->data_length >= 6 &&
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002113 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) {
hbono@chromium.org98626972011-08-03 03:13:08 +00002119 /* Suppress output of JFIF marker */
2120 dstinfo->write_JFIF_header = FALSE;
hbono@chromium.org98626972011-08-03 03:13:08 +00002121 /* Adjust Exif image parameters */
Chris Blumecca8c4d2019-03-01 01:09:50 -08002122#if JPEG_LIB_VERSION >= 80
hbono@chromium.org98626972011-08-03 03:13:08 +00002123 if (dstinfo->jpeg_width != srcinfo->image_width ||
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002124 dstinfo->jpeg_height != srcinfo->image_height)
hbono@chromium.org98626972011-08-03 03:13:08 +00002125 /* Align data segment to start of TIFF structure for parsing */
2126 adjust_exif_parameters(srcinfo->marker_list->data + 6,
Chris Blumecca8c4d2019-03-01 01:09:50 -08002127 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);
hbono@chromium.org98626972011-08-03 03:13:08 +00002136#endif
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002137 }
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
2155GLOBAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08002156jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2157 jvirt_barray_ptr *src_coef_arrays,
2158 jpeg_transform_info *info)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002159{
2160 jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
2161
hbono@chromium.org98626972011-08-03 03:13:08 +00002162 /* Note: conditions tested here should match those in switch statement
2163 * in jtransform_request_workspace()
2164 */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002165 switch (info->transform) {
2166 case JXFORM_NONE:
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002167 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)
hbono@chromium.org98626972011-08-03 03:13:08 +00002184 do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002185 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002186 break;
2187 case JXFORM_FLIP_H:
hbono@chromium.org98626972011-08-03 03:13:08 +00002188 if (info->y_crop_offset != 0 || info->slow_hflip)
2189 do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002190 src_coef_arrays, dst_coef_arrays);
hbono@chromium.org98626972011-08-03 03:13:08 +00002191 else
2192 do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002193 src_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002194 break;
2195 case JXFORM_FLIP_V:
hbono@chromium.org98626972011-08-03 03:13:08 +00002196 do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002197 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002198 break;
2199 case JXFORM_TRANSPOSE:
hbono@chromium.org98626972011-08-03 03:13:08 +00002200 do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002201 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002202 break;
2203 case JXFORM_TRANSVERSE:
hbono@chromium.org98626972011-08-03 03:13:08 +00002204 do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002205 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002206 break;
2207 case JXFORM_ROT_90:
hbono@chromium.org98626972011-08-03 03:13:08 +00002208 do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002209 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002210 break;
2211 case JXFORM_ROT_180:
hbono@chromium.org98626972011-08-03 03:13:08 +00002212 do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002213 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002214 break;
2215 case JXFORM_ROT_270:
hbono@chromium.org98626972011-08-03 03:13:08 +00002216 do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002217 src_coef_arrays, dst_coef_arrays);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002218 break;
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002219 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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002243 }
2244}
2245
hbono@chromium.org98626972011-08-03 03:13:08 +00002246/* 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
2267GLOBAL(boolean)
2268jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002269 int MCU_width, int MCU_height,
2270 JXFORM_CODE transform)
hbono@chromium.org98626972011-08-03 03:13:08 +00002271{
2272 boolean result = TRUE; /* initialize TRUE */
2273
2274 switch (transform) {
2275 case JXFORM_FLIP_H:
2276 case JXFORM_ROT_270:
Chris Blumecca8c4d2019-03-01 01:09:50 -08002277 if (image_width % (JDIMENSION)MCU_width)
hbono@chromium.org98626972011-08-03 03:13:08 +00002278 result = FALSE;
2279 break;
2280 case JXFORM_FLIP_V:
2281 case JXFORM_ROT_90:
Chris Blumecca8c4d2019-03-01 01:09:50 -08002282 if (image_height % (JDIMENSION)MCU_height)
hbono@chromium.org98626972011-08-03 03:13:08 +00002283 result = FALSE;
2284 break;
2285 case JXFORM_TRANSVERSE:
2286 case JXFORM_ROT_180:
Chris Blumecca8c4d2019-03-01 01:09:50 -08002287 if (image_width % (JDIMENSION)MCU_width)
hbono@chromium.org98626972011-08-03 03:13:08 +00002288 result = FALSE;
Chris Blumecca8c4d2019-03-01 01:09:50 -08002289 if (image_height % (JDIMENSION)MCU_height)
hbono@chromium.org98626972011-08-03 03:13:08 +00002290 result = FALSE;
2291 break;
2292 default:
2293 break;
2294 }
2295
2296 return result;
2297}
2298
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002299#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
2306GLOBAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08002307jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002308{
2309#ifdef SAVE_MARKERS_SUPPORTED
2310 int m;
2311
2312 /* Save comments except under NONE option */
2313 if (option != JCOPYOPT_NONE) {
2314 jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
2315 }
2316 /* Save all types of APPn markers iff ALL option */
Chris Blumecca8c4d2019-03-01 01:09:50 -08002317 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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002321 jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
Chris Blumecca8c4d2019-03-01 01:09:50 -08002322 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002323 }
2324#endif /* SAVE_MARKERS_SUPPORTED */
2325}
2326
2327/* Copy markers saved in the given source object to the destination object.
2328 * This should be called just after jpeg_start_compress() or
2329 * jpeg_write_coefficients().
2330 * Note that those routines will have written the SOI, and also the
2331 * JFIF APP0 or Adobe APP14 markers if selected.
2332 */
2333
2334GLOBAL(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -08002335jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
2336 JCOPY_OPTION option)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002337{
2338 jpeg_saved_marker_ptr marker;
2339
2340 /* In the current implementation, we don't actually need to examine the
2341 * option flag here; we just copy everything that got saved.
2342 * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
2343 * if the encoder library already wrote one.
2344 */
2345 for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
2346 if (dstinfo->write_JFIF_header &&
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002347 marker->marker == JPEG_APP0 &&
2348 marker->data_length >= 5 &&
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002349 marker->data[0] == 0x4A &&
2350 marker->data[1] == 0x46 &&
2351 marker->data[2] == 0x49 &&
2352 marker->data[3] == 0x46 &&
2353 marker->data[4] == 0)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002354 continue; /* reject duplicate JFIF */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002355 if (dstinfo->write_Adobe_marker &&
Chris Blumecca8c4d2019-03-01 01:09:50 -08002356 marker->marker == JPEG_APP0 + 14 &&
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002357 marker->data_length >= 5 &&
Jonathan Wrightbbb82822020-11-25 13:36:43 +00002358 marker->data[0] == 0x41 &&
2359 marker->data[1] == 0x64 &&
2360 marker->data[2] == 0x6F &&
2361 marker->data[3] == 0x62 &&
2362 marker->data[4] == 0x65)
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002363 continue; /* reject duplicate Adobe */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002364 jpeg_write_marker(dstinfo, marker->marker,
Tom Hudson0d47d2d2016-05-04 13:22:56 -04002365 marker->data, marker->data_length);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00002366 }
2367}