/src/libjpeg-turbo.2.0.x/transupp.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * transupp.c |
3 | | * |
4 | | * This file was part of the Independent JPEG Group's software: |
5 | | * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding. |
6 | | * libjpeg-turbo Modifications: |
7 | | * Copyright (C) 2010, 2017, D. R. Commander. |
8 | | * For conditions of distribution and use, see the accompanying README.ijg |
9 | | * file. |
10 | | * |
11 | | * This file contains image transformation routines and other utility code |
12 | | * used by the jpegtran sample application. These are NOT part of the core |
13 | | * JPEG library. But we keep these routines separate from jpegtran.c to |
14 | | * ease the task of maintaining jpegtran-like programs that have other user |
15 | | * interfaces. |
16 | | */ |
17 | | |
18 | | /* Although this file really shouldn't have access to the library internals, |
19 | | * it's helpful to let it call jround_up() and jcopy_block_row(). |
20 | | */ |
21 | | #define JPEG_INTERNALS |
22 | | |
23 | | #include "jinclude.h" |
24 | | #include "jpeglib.h" |
25 | | #include "transupp.h" /* My own external interface */ |
26 | | #include "jpegcomp.h" |
27 | | #include <ctype.h> /* to declare isdigit() */ |
28 | | |
29 | | |
30 | | #if JPEG_LIB_VERSION >= 70 |
31 | | #define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size |
32 | | #define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size |
33 | | #else |
34 | 2.75k | #define dstinfo_min_DCT_h_scaled_size DCTSIZE |
35 | 0 | #define dstinfo_min_DCT_v_scaled_size DCTSIZE |
36 | | #endif |
37 | | |
38 | | |
39 | | #if TRANSFORMS_SUPPORTED |
40 | | |
41 | | /* |
42 | | * Lossless image transformation routines. These routines work on DCT |
43 | | * coefficient arrays and thus do not require any lossy decompression |
44 | | * or recompression of the image. |
45 | | * Thanks to Guido Vollbeding for the initial design and code of this feature, |
46 | | * and to Ben Jackson for introducing the cropping feature. |
47 | | * |
48 | | * Horizontal flipping is done in-place, using a single top-to-bottom |
49 | | * pass through the virtual source array. It will thus be much the |
50 | | * fastest option for images larger than main memory. |
51 | | * |
52 | | * The other routines require a set of destination virtual arrays, so they |
53 | | * need twice as much memory as jpegtran normally does. The destination |
54 | | * arrays are always written in normal scan order (top to bottom) because |
55 | | * the virtual array manager expects this. The source arrays will be scanned |
56 | | * in the corresponding order, which means multiple passes through the source |
57 | | * arrays for most of the transforms. That could result in much thrashing |
58 | | * if the image is larger than main memory. |
59 | | * |
60 | | * If cropping or trimming is involved, the destination arrays may be smaller |
61 | | * than the source arrays. Note it is not possible to do horizontal flip |
62 | | * in-place when a nonzero Y crop offset is specified, since we'd have to move |
63 | | * data from one block row to another but the virtual array manager doesn't |
64 | | * guarantee we can touch more than one row at a time. So in that case, |
65 | | * we have to use a separate destination array. |
66 | | * |
67 | | * Some notes about the operating environment of the individual transform |
68 | | * routines: |
69 | | * 1. Both the source and destination virtual arrays are allocated from the |
70 | | * source JPEG object, and therefore should be manipulated by calling the |
71 | | * source's memory manager. |
72 | | * 2. The destination's component count should be used. It may be smaller |
73 | | * than the source's when forcing to grayscale. |
74 | | * 3. Likewise the destination's sampling factors should be used. When |
75 | | * forcing to grayscale the destination's sampling factors will be all 1, |
76 | | * and we may as well take that as the effective iMCU size. |
77 | | * 4. When "trim" is in effect, the destination's dimensions will be the |
78 | | * trimmed values but the source's will be untrimmed. |
79 | | * 5. When "crop" is in effect, the destination's dimensions will be the |
80 | | * cropped values but the source's will be uncropped. Each transform |
81 | | * routine is responsible for picking up source data starting at the |
82 | | * correct X and Y offset for the crop region. (The X and Y offsets |
83 | | * passed to the transform routines are measured in iMCU blocks of the |
84 | | * destination.) |
85 | | * 6. All the routines assume that the source and destination buffers are |
86 | | * padded out to a full iMCU boundary. This is true, although for the |
87 | | * source buffer it is an undocumented property of jdcoefct.c. |
88 | | */ |
89 | | |
90 | | |
91 | | LOCAL(void) |
92 | | do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
93 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
94 | | jvirt_barray_ptr *src_coef_arrays, |
95 | | jvirt_barray_ptr *dst_coef_arrays) |
96 | | /* Crop. This is only used when no rotate/flip is requested with the crop. */ |
97 | 0 | { |
98 | 0 | JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; |
99 | 0 | int ci, offset_y; |
100 | 0 | JBLOCKARRAY src_buffer, dst_buffer; |
101 | 0 | jpeg_component_info *compptr; |
102 | | |
103 | | /* We simply have to copy the right amount of data (the destination's |
104 | | * image size) starting at the given X and Y offsets in the source. |
105 | | */ |
106 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
107 | 0 | compptr = dstinfo->comp_info + ci; |
108 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
109 | 0 | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
110 | 0 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
111 | 0 | dst_blk_y += compptr->v_samp_factor) { |
112 | 0 | dst_buffer = (*srcinfo->mem->access_virt_barray) |
113 | 0 | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
114 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
115 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
116 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, |
117 | 0 | (JDIMENSION)compptr->v_samp_factor, FALSE); |
118 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
119 | 0 | jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, |
120 | 0 | dst_buffer[offset_y], compptr->width_in_blocks); |
121 | 0 | } |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | |
127 | | LOCAL(void) |
128 | | do_flip_h_no_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
129 | | JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays) |
130 | | /* Horizontal flip; done in-place, so no separate dest array is required. |
131 | | * NB: this only works when y_crop_offset is zero. |
132 | | */ |
133 | 0 | { |
134 | 0 | JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; |
135 | 0 | int ci, k, offset_y; |
136 | 0 | JBLOCKARRAY buffer; |
137 | 0 | JCOEFPTR ptr1, ptr2; |
138 | 0 | JCOEF temp1, temp2; |
139 | 0 | jpeg_component_info *compptr; |
140 | | |
141 | | /* Horizontal mirroring of DCT blocks is accomplished by swapping |
142 | | * pairs of blocks in-place. Within a DCT block, we perform horizontal |
143 | | * mirroring by changing the signs of odd-numbered columns. |
144 | | * Partial iMCUs at the right edge are left untouched. |
145 | | */ |
146 | 0 | MCU_cols = srcinfo->output_width / |
147 | 0 | (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size); |
148 | |
|
149 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
150 | 0 | compptr = dstinfo->comp_info + ci; |
151 | 0 | comp_width = MCU_cols * compptr->h_samp_factor; |
152 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
153 | 0 | for (blk_y = 0; blk_y < compptr->height_in_blocks; |
154 | 0 | blk_y += compptr->v_samp_factor) { |
155 | 0 | buffer = (*srcinfo->mem->access_virt_barray) |
156 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y, |
157 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
158 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
159 | | /* Do the mirroring */ |
160 | 0 | for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { |
161 | 0 | ptr1 = buffer[offset_y][blk_x]; |
162 | 0 | ptr2 = buffer[offset_y][comp_width - blk_x - 1]; |
163 | | /* this unrolled loop doesn't need to know which row it's on... */ |
164 | 0 | for (k = 0; k < DCTSIZE2; k += 2) { |
165 | 0 | temp1 = *ptr1; /* swap even column */ |
166 | 0 | temp2 = *ptr2; |
167 | 0 | *ptr1++ = temp2; |
168 | 0 | *ptr2++ = temp1; |
169 | 0 | temp1 = *ptr1; /* swap odd column with sign change */ |
170 | 0 | temp2 = *ptr2; |
171 | 0 | *ptr1++ = -temp2; |
172 | 0 | *ptr2++ = -temp1; |
173 | 0 | } |
174 | 0 | } |
175 | 0 | if (x_crop_blocks > 0) { |
176 | | /* Now left-justify the portion of the data to be kept. |
177 | | * We can't use a single jcopy_block_row() call because that routine |
178 | | * depends on memcpy(), whose behavior is unspecified for overlapping |
179 | | * source and destination areas. Sigh. |
180 | | */ |
181 | 0 | for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { |
182 | 0 | jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, |
183 | 0 | buffer[offset_y] + blk_x, (JDIMENSION)1); |
184 | 0 | } |
185 | 0 | } |
186 | 0 | } |
187 | 0 | } |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | |
192 | | LOCAL(void) |
193 | | do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
194 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
195 | | jvirt_barray_ptr *src_coef_arrays, |
196 | | jvirt_barray_ptr *dst_coef_arrays) |
197 | | /* Horizontal flip in general cropping case */ |
198 | 0 | { |
199 | 0 | JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; |
200 | 0 | JDIMENSION x_crop_blocks, y_crop_blocks; |
201 | 0 | int ci, k, offset_y; |
202 | 0 | JBLOCKARRAY src_buffer, dst_buffer; |
203 | 0 | JBLOCKROW src_row_ptr, dst_row_ptr; |
204 | 0 | JCOEFPTR src_ptr, dst_ptr; |
205 | 0 | jpeg_component_info *compptr; |
206 | | |
207 | | /* Here we must output into a separate array because we can't touch |
208 | | * different rows of a single virtual array simultaneously. Otherwise, |
209 | | * this is essentially the same as the routine above. |
210 | | */ |
211 | 0 | MCU_cols = srcinfo->output_width / |
212 | 0 | (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size); |
213 | |
|
214 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
215 | 0 | compptr = dstinfo->comp_info + ci; |
216 | 0 | comp_width = MCU_cols * compptr->h_samp_factor; |
217 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
218 | 0 | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
219 | 0 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
220 | 0 | dst_blk_y += compptr->v_samp_factor) { |
221 | 0 | dst_buffer = (*srcinfo->mem->access_virt_barray) |
222 | 0 | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
223 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
224 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
225 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, |
226 | 0 | (JDIMENSION)compptr->v_samp_factor, FALSE); |
227 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
228 | 0 | dst_row_ptr = dst_buffer[offset_y]; |
229 | 0 | src_row_ptr = src_buffer[offset_y]; |
230 | 0 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
231 | 0 | dst_blk_x++) { |
232 | 0 | if (x_crop_blocks + dst_blk_x < comp_width) { |
233 | | /* Do the mirrorable blocks */ |
234 | 0 | dst_ptr = dst_row_ptr[dst_blk_x]; |
235 | 0 | src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; |
236 | | /* this unrolled loop doesn't need to know which row it's on... */ |
237 | 0 | for (k = 0; k < DCTSIZE2; k += 2) { |
238 | 0 | *dst_ptr++ = *src_ptr++; /* copy even column */ |
239 | 0 | *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign |
240 | | change */ |
241 | 0 | } |
242 | 0 | } else { |
243 | | /* Copy last partial block(s) verbatim */ |
244 | 0 | jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, |
245 | 0 | dst_row_ptr + dst_blk_x, (JDIMENSION)1); |
246 | 0 | } |
247 | 0 | } |
248 | 0 | } |
249 | 0 | } |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | |
254 | | LOCAL(void) |
255 | | do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
256 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
257 | | jvirt_barray_ptr *src_coef_arrays, |
258 | | jvirt_barray_ptr *dst_coef_arrays) |
259 | | /* Vertical flip */ |
260 | 0 | { |
261 | 0 | JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; |
262 | 0 | JDIMENSION x_crop_blocks, y_crop_blocks; |
263 | 0 | int ci, i, j, offset_y; |
264 | 0 | JBLOCKARRAY src_buffer, dst_buffer; |
265 | 0 | JBLOCKROW src_row_ptr, dst_row_ptr; |
266 | 0 | JCOEFPTR src_ptr, dst_ptr; |
267 | 0 | jpeg_component_info *compptr; |
268 | | |
269 | | /* We output into a separate array because we can't touch different |
270 | | * rows of the source virtual array simultaneously. Otherwise, this |
271 | | * is a pretty straightforward analog of horizontal flip. |
272 | | * Within a DCT block, vertical mirroring is done by changing the signs |
273 | | * of odd-numbered rows. |
274 | | * Partial iMCUs at the bottom edge are copied verbatim. |
275 | | */ |
276 | 0 | MCU_rows = srcinfo->output_height / |
277 | 0 | (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size); |
278 | |
|
279 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
280 | 0 | compptr = dstinfo->comp_info + ci; |
281 | 0 | comp_height = MCU_rows * compptr->v_samp_factor; |
282 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
283 | 0 | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
284 | 0 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
285 | 0 | dst_blk_y += compptr->v_samp_factor) { |
286 | 0 | dst_buffer = (*srcinfo->mem->access_virt_barray) |
287 | 0 | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
288 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
289 | 0 | if (y_crop_blocks + dst_blk_y < comp_height) { |
290 | | /* Row is within the mirrorable area. */ |
291 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
292 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
293 | 0 | comp_height - y_crop_blocks - dst_blk_y - |
294 | 0 | (JDIMENSION)compptr->v_samp_factor, |
295 | 0 | (JDIMENSION)compptr->v_samp_factor, FALSE); |
296 | 0 | } else { |
297 | | /* Bottom-edge blocks will be copied verbatim. */ |
298 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
299 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
300 | 0 | dst_blk_y + y_crop_blocks, |
301 | 0 | (JDIMENSION)compptr->v_samp_factor, FALSE); |
302 | 0 | } |
303 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
304 | 0 | if (y_crop_blocks + dst_blk_y < comp_height) { |
305 | | /* Row is within the mirrorable area. */ |
306 | 0 | dst_row_ptr = dst_buffer[offset_y]; |
307 | 0 | src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; |
308 | 0 | src_row_ptr += x_crop_blocks; |
309 | 0 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
310 | 0 | dst_blk_x++) { |
311 | 0 | dst_ptr = dst_row_ptr[dst_blk_x]; |
312 | 0 | src_ptr = src_row_ptr[dst_blk_x]; |
313 | 0 | for (i = 0; i < DCTSIZE; i += 2) { |
314 | | /* copy even row */ |
315 | 0 | for (j = 0; j < DCTSIZE; j++) |
316 | 0 | *dst_ptr++ = *src_ptr++; |
317 | | /* copy odd row with sign change */ |
318 | 0 | for (j = 0; j < DCTSIZE; j++) |
319 | 0 | *dst_ptr++ = -(*src_ptr++); |
320 | 0 | } |
321 | 0 | } |
322 | 0 | } else { |
323 | | /* Just copy row verbatim. */ |
324 | 0 | jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, |
325 | 0 | dst_buffer[offset_y], compptr->width_in_blocks); |
326 | 0 | } |
327 | 0 | } |
328 | 0 | } |
329 | 0 | } |
330 | 0 | } |
331 | | |
332 | | |
333 | | LOCAL(void) |
334 | | do_transpose(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
335 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
336 | | jvirt_barray_ptr *src_coef_arrays, |
337 | | jvirt_barray_ptr *dst_coef_arrays) |
338 | | /* Transpose source into destination */ |
339 | 2.77k | { |
340 | 2.77k | JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; |
341 | 2.77k | int ci, i, j, offset_x, offset_y; |
342 | 2.77k | JBLOCKARRAY src_buffer, dst_buffer; |
343 | 2.77k | JCOEFPTR src_ptr, dst_ptr; |
344 | 2.77k | jpeg_component_info *compptr; |
345 | | |
346 | | /* Transposing pixels within a block just requires transposing the |
347 | | * DCT coefficients. |
348 | | * Partial iMCUs at the edges require no special treatment; we simply |
349 | | * process all the available DCT blocks for every component. |
350 | | */ |
351 | 5.54k | for (ci = 0; ci < dstinfo->num_components; ci++) { |
352 | 2.77k | compptr = dstinfo->comp_info + ci; |
353 | 2.77k | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
354 | 2.77k | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
355 | 74.0k | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
356 | 71.3k | dst_blk_y += compptr->v_samp_factor) { |
357 | 71.3k | dst_buffer = (*srcinfo->mem->access_virt_barray) |
358 | 71.3k | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
359 | 71.3k | (JDIMENSION)compptr->v_samp_factor, TRUE); |
360 | 142k | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
361 | 3.53M | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
362 | 3.46M | dst_blk_x += compptr->h_samp_factor) { |
363 | 3.46M | src_buffer = (*srcinfo->mem->access_virt_barray) |
364 | 3.46M | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
365 | 3.46M | dst_blk_x + x_crop_blocks, |
366 | 3.46M | (JDIMENSION)compptr->h_samp_factor, FALSE); |
367 | 6.92M | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
368 | 3.46M | dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
369 | 3.46M | src_ptr = |
370 | 3.46M | src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; |
371 | 31.1M | for (i = 0; i < DCTSIZE; i++) |
372 | 249M | for (j = 0; j < DCTSIZE; j++) |
373 | 221M | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
374 | 3.46M | } |
375 | 3.46M | } |
376 | 71.3k | } |
377 | 71.3k | } |
378 | 2.77k | } |
379 | 2.77k | } |
380 | | |
381 | | |
382 | | LOCAL(void) |
383 | | do_rot_90(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
384 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
385 | | jvirt_barray_ptr *src_coef_arrays, |
386 | | jvirt_barray_ptr *dst_coef_arrays) |
387 | | /* 90 degree rotation is equivalent to |
388 | | * 1. Transposing the image; |
389 | | * 2. Horizontal mirroring. |
390 | | * These two steps are merged into a single processing routine. |
391 | | */ |
392 | 2.75k | { |
393 | 2.75k | JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; |
394 | 2.75k | JDIMENSION x_crop_blocks, y_crop_blocks; |
395 | 2.75k | int ci, i, j, offset_x, offset_y; |
396 | 2.75k | JBLOCKARRAY src_buffer, dst_buffer; |
397 | 2.75k | JCOEFPTR src_ptr, dst_ptr; |
398 | 2.75k | jpeg_component_info *compptr; |
399 | | |
400 | | /* Because of the horizontal mirror step, we can't process partial iMCUs |
401 | | * at the (output) right edge properly. They just get transposed and |
402 | | * not mirrored. |
403 | | */ |
404 | 2.75k | MCU_cols = srcinfo->output_height / |
405 | 2.75k | (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size); |
406 | | |
407 | 6.81k | for (ci = 0; ci < dstinfo->num_components; ci++) { |
408 | 4.05k | compptr = dstinfo->comp_info + ci; |
409 | 4.05k | comp_width = MCU_cols * compptr->h_samp_factor; |
410 | 4.05k | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
411 | 4.05k | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
412 | 182k | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
413 | 178k | dst_blk_y += compptr->v_samp_factor) { |
414 | 178k | dst_buffer = (*srcinfo->mem->access_virt_barray) |
415 | 178k | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
416 | 178k | (JDIMENSION)compptr->v_samp_factor, TRUE); |
417 | 377k | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
418 | 16.1M | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
419 | 15.9M | dst_blk_x += compptr->h_samp_factor) { |
420 | 15.9M | if (x_crop_blocks + dst_blk_x < comp_width) { |
421 | | /* Block is within the mirrorable area. */ |
422 | 15.9M | src_buffer = (*srcinfo->mem->access_virt_barray) |
423 | 15.9M | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
424 | 15.9M | comp_width - x_crop_blocks - dst_blk_x - |
425 | 15.9M | (JDIMENSION)compptr->h_samp_factor, |
426 | 15.9M | (JDIMENSION)compptr->h_samp_factor, FALSE); |
427 | 15.9M | } else { |
428 | | /* Edge blocks are transposed but not mirrored. */ |
429 | 179 | src_buffer = (*srcinfo->mem->access_virt_barray) |
430 | 179 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
431 | 179 | dst_blk_x + x_crop_blocks, |
432 | 179 | (JDIMENSION)compptr->h_samp_factor, FALSE); |
433 | 179 | } |
434 | 32.5M | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
435 | 16.6M | dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
436 | 16.6M | if (x_crop_blocks + dst_blk_x < comp_width) { |
437 | | /* Block is within the mirrorable area. */ |
438 | 16.6M | src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] |
439 | 16.6M | [dst_blk_y + offset_y + y_crop_blocks]; |
440 | 83.3M | for (i = 0; i < DCTSIZE; i++) { |
441 | 600M | for (j = 0; j < DCTSIZE; j++) |
442 | 533M | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
443 | 66.6M | i++; |
444 | 600M | for (j = 0; j < DCTSIZE; j++) |
445 | 533M | dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j]; |
446 | 66.6M | } |
447 | 16.6M | } else { |
448 | | /* Edge blocks are transposed but not mirrored. */ |
449 | 258 | src_ptr = src_buffer[offset_x] |
450 | 258 | [dst_blk_y + offset_y + y_crop_blocks]; |
451 | 2.32k | for (i = 0; i < DCTSIZE; i++) |
452 | 18.5k | for (j = 0; j < DCTSIZE; j++) |
453 | 16.5k | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
454 | 258 | } |
455 | 16.6M | } |
456 | 15.9M | } |
457 | 198k | } |
458 | 178k | } |
459 | 4.05k | } |
460 | 2.75k | } |
461 | | |
462 | | |
463 | | LOCAL(void) |
464 | | do_rot_270(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
465 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
466 | | jvirt_barray_ptr *src_coef_arrays, |
467 | | jvirt_barray_ptr *dst_coef_arrays) |
468 | | /* 270 degree rotation is equivalent to |
469 | | * 1. Horizontal mirroring; |
470 | | * 2. Transposing the image. |
471 | | * These two steps are merged into a single processing routine. |
472 | | */ |
473 | 0 | { |
474 | 0 | JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; |
475 | 0 | JDIMENSION x_crop_blocks, y_crop_blocks; |
476 | 0 | int ci, i, j, offset_x, offset_y; |
477 | 0 | JBLOCKARRAY src_buffer, dst_buffer; |
478 | 0 | JCOEFPTR src_ptr, dst_ptr; |
479 | 0 | jpeg_component_info *compptr; |
480 | | |
481 | | /* Because of the horizontal mirror step, we can't process partial iMCUs |
482 | | * at the (output) bottom edge properly. They just get transposed and |
483 | | * not mirrored. |
484 | | */ |
485 | 0 | MCU_rows = srcinfo->output_width / |
486 | 0 | (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size); |
487 | |
|
488 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
489 | 0 | compptr = dstinfo->comp_info + ci; |
490 | 0 | comp_height = MCU_rows * compptr->v_samp_factor; |
491 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
492 | 0 | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
493 | 0 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
494 | 0 | dst_blk_y += compptr->v_samp_factor) { |
495 | 0 | dst_buffer = (*srcinfo->mem->access_virt_barray) |
496 | 0 | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
497 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
498 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
499 | 0 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
500 | 0 | dst_blk_x += compptr->h_samp_factor) { |
501 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
502 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
503 | 0 | dst_blk_x + x_crop_blocks, |
504 | 0 | (JDIMENSION)compptr->h_samp_factor, FALSE); |
505 | 0 | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
506 | 0 | dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
507 | 0 | if (y_crop_blocks + dst_blk_y < comp_height) { |
508 | | /* Block is within the mirrorable area. */ |
509 | 0 | src_ptr = src_buffer[offset_x] |
510 | 0 | [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; |
511 | 0 | for (i = 0; i < DCTSIZE; i++) { |
512 | 0 | for (j = 0; j < DCTSIZE; j++) { |
513 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
514 | 0 | j++; |
515 | 0 | dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j]; |
516 | 0 | } |
517 | 0 | } |
518 | 0 | } else { |
519 | | /* Edge blocks are transposed but not mirrored. */ |
520 | 0 | src_ptr = src_buffer[offset_x] |
521 | 0 | [dst_blk_y + offset_y + y_crop_blocks]; |
522 | 0 | for (i = 0; i < DCTSIZE; i++) |
523 | 0 | for (j = 0; j < DCTSIZE; j++) |
524 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
525 | 0 | } |
526 | 0 | } |
527 | 0 | } |
528 | 0 | } |
529 | 0 | } |
530 | 0 | } |
531 | 0 | } |
532 | | |
533 | | |
534 | | LOCAL(void) |
535 | | do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
536 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
537 | | jvirt_barray_ptr *src_coef_arrays, |
538 | | jvirt_barray_ptr *dst_coef_arrays) |
539 | | /* 180 degree rotation is equivalent to |
540 | | * 1. Vertical mirroring; |
541 | | * 2. Horizontal mirroring. |
542 | | * These two steps are merged into a single processing routine. |
543 | | */ |
544 | 0 | { |
545 | 0 | JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; |
546 | 0 | JDIMENSION x_crop_blocks, y_crop_blocks; |
547 | 0 | int ci, i, j, offset_y; |
548 | 0 | JBLOCKARRAY src_buffer, dst_buffer; |
549 | 0 | JBLOCKROW src_row_ptr, dst_row_ptr; |
550 | 0 | JCOEFPTR src_ptr, dst_ptr; |
551 | 0 | jpeg_component_info *compptr; |
552 | |
|
553 | 0 | MCU_cols = srcinfo->output_width / |
554 | 0 | (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size); |
555 | 0 | MCU_rows = srcinfo->output_height / |
556 | 0 | (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size); |
557 | |
|
558 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
559 | 0 | compptr = dstinfo->comp_info + ci; |
560 | 0 | comp_width = MCU_cols * compptr->h_samp_factor; |
561 | 0 | comp_height = MCU_rows * compptr->v_samp_factor; |
562 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
563 | 0 | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
564 | 0 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
565 | 0 | dst_blk_y += compptr->v_samp_factor) { |
566 | 0 | dst_buffer = (*srcinfo->mem->access_virt_barray) |
567 | 0 | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
568 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
569 | 0 | if (y_crop_blocks + dst_blk_y < comp_height) { |
570 | | /* Row is within the vertically mirrorable area. */ |
571 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
572 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
573 | 0 | comp_height - y_crop_blocks - dst_blk_y - |
574 | 0 | (JDIMENSION)compptr->v_samp_factor, |
575 | 0 | (JDIMENSION)compptr->v_samp_factor, FALSE); |
576 | 0 | } else { |
577 | | /* Bottom-edge rows are only mirrored horizontally. */ |
578 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
579 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
580 | 0 | dst_blk_y + y_crop_blocks, |
581 | 0 | (JDIMENSION)compptr->v_samp_factor, FALSE); |
582 | 0 | } |
583 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
584 | 0 | dst_row_ptr = dst_buffer[offset_y]; |
585 | 0 | if (y_crop_blocks + dst_blk_y < comp_height) { |
586 | | /* Row is within the mirrorable area. */ |
587 | 0 | src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; |
588 | 0 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
589 | 0 | dst_blk_x++) { |
590 | 0 | dst_ptr = dst_row_ptr[dst_blk_x]; |
591 | 0 | if (x_crop_blocks + dst_blk_x < comp_width) { |
592 | | /* Process the blocks that can be mirrored both ways. */ |
593 | 0 | src_ptr = |
594 | 0 | src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; |
595 | 0 | for (i = 0; i < DCTSIZE; i += 2) { |
596 | | /* For even row, negate every odd column. */ |
597 | 0 | for (j = 0; j < DCTSIZE; j += 2) { |
598 | 0 | *dst_ptr++ = *src_ptr++; |
599 | 0 | *dst_ptr++ = -(*src_ptr++); |
600 | 0 | } |
601 | | /* For odd row, negate every even column. */ |
602 | 0 | for (j = 0; j < DCTSIZE; j += 2) { |
603 | 0 | *dst_ptr++ = -(*src_ptr++); |
604 | 0 | *dst_ptr++ = *src_ptr++; |
605 | 0 | } |
606 | 0 | } |
607 | 0 | } else { |
608 | | /* Any remaining right-edge blocks are only mirrored vertically. */ |
609 | 0 | src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; |
610 | 0 | for (i = 0; i < DCTSIZE; i += 2) { |
611 | 0 | for (j = 0; j < DCTSIZE; j++) |
612 | 0 | *dst_ptr++ = *src_ptr++; |
613 | 0 | for (j = 0; j < DCTSIZE; j++) |
614 | 0 | *dst_ptr++ = -(*src_ptr++); |
615 | 0 | } |
616 | 0 | } |
617 | 0 | } |
618 | 0 | } else { |
619 | | /* Remaining rows are just mirrored horizontally. */ |
620 | 0 | src_row_ptr = src_buffer[offset_y]; |
621 | 0 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
622 | 0 | dst_blk_x++) { |
623 | 0 | if (x_crop_blocks + dst_blk_x < comp_width) { |
624 | | /* Process the blocks that can be mirrored. */ |
625 | 0 | dst_ptr = dst_row_ptr[dst_blk_x]; |
626 | 0 | src_ptr = |
627 | 0 | src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; |
628 | 0 | for (i = 0; i < DCTSIZE2; i += 2) { |
629 | 0 | *dst_ptr++ = *src_ptr++; |
630 | 0 | *dst_ptr++ = -(*src_ptr++); |
631 | 0 | } |
632 | 0 | } else { |
633 | | /* Any remaining right-edge blocks are only copied. */ |
634 | 0 | jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, |
635 | 0 | dst_row_ptr + dst_blk_x, (JDIMENSION)1); |
636 | 0 | } |
637 | 0 | } |
638 | 0 | } |
639 | 0 | } |
640 | 0 | } |
641 | 0 | } |
642 | 0 | } |
643 | | |
644 | | |
645 | | LOCAL(void) |
646 | | do_transverse(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
647 | | JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, |
648 | | jvirt_barray_ptr *src_coef_arrays, |
649 | | jvirt_barray_ptr *dst_coef_arrays) |
650 | | /* Transverse transpose is equivalent to |
651 | | * 1. 180 degree rotation; |
652 | | * 2. Transposition; |
653 | | * or |
654 | | * 1. Horizontal mirroring; |
655 | | * 2. Transposition; |
656 | | * 3. Horizontal mirroring. |
657 | | * These steps are merged into a single processing routine. |
658 | | */ |
659 | 0 | { |
660 | 0 | JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; |
661 | 0 | JDIMENSION x_crop_blocks, y_crop_blocks; |
662 | 0 | int ci, i, j, offset_x, offset_y; |
663 | 0 | JBLOCKARRAY src_buffer, dst_buffer; |
664 | 0 | JCOEFPTR src_ptr, dst_ptr; |
665 | 0 | jpeg_component_info *compptr; |
666 | |
|
667 | 0 | MCU_cols = srcinfo->output_height / |
668 | 0 | (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size); |
669 | 0 | MCU_rows = srcinfo->output_width / |
670 | 0 | (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size); |
671 | |
|
672 | 0 | for (ci = 0; ci < dstinfo->num_components; ci++) { |
673 | 0 | compptr = dstinfo->comp_info + ci; |
674 | 0 | comp_width = MCU_cols * compptr->h_samp_factor; |
675 | 0 | comp_height = MCU_rows * compptr->v_samp_factor; |
676 | 0 | x_crop_blocks = x_crop_offset * compptr->h_samp_factor; |
677 | 0 | y_crop_blocks = y_crop_offset * compptr->v_samp_factor; |
678 | 0 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; |
679 | 0 | dst_blk_y += compptr->v_samp_factor) { |
680 | 0 | dst_buffer = (*srcinfo->mem->access_virt_barray) |
681 | 0 | ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y, |
682 | 0 | (JDIMENSION)compptr->v_samp_factor, TRUE); |
683 | 0 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { |
684 | 0 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; |
685 | 0 | dst_blk_x += compptr->h_samp_factor) { |
686 | 0 | if (x_crop_blocks + dst_blk_x < comp_width) { |
687 | | /* Block is within the mirrorable area. */ |
688 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
689 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
690 | 0 | comp_width - x_crop_blocks - dst_blk_x - |
691 | 0 | (JDIMENSION)compptr->h_samp_factor, |
692 | 0 | (JDIMENSION)compptr->h_samp_factor, FALSE); |
693 | 0 | } else { |
694 | 0 | src_buffer = (*srcinfo->mem->access_virt_barray) |
695 | 0 | ((j_common_ptr)srcinfo, src_coef_arrays[ci], |
696 | 0 | dst_blk_x + x_crop_blocks, |
697 | 0 | (JDIMENSION)compptr->h_samp_factor, FALSE); |
698 | 0 | } |
699 | 0 | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { |
700 | 0 | dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; |
701 | 0 | if (y_crop_blocks + dst_blk_y < comp_height) { |
702 | 0 | if (x_crop_blocks + dst_blk_x < comp_width) { |
703 | | /* Block is within the mirrorable area. */ |
704 | 0 | src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] |
705 | 0 | [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; |
706 | 0 | for (i = 0; i < DCTSIZE; i++) { |
707 | 0 | for (j = 0; j < DCTSIZE; j++) { |
708 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
709 | 0 | j++; |
710 | 0 | dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j]; |
711 | 0 | } |
712 | 0 | i++; |
713 | 0 | for (j = 0; j < DCTSIZE; j++) { |
714 | 0 | dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j]; |
715 | 0 | j++; |
716 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
717 | 0 | } |
718 | 0 | } |
719 | 0 | } else { |
720 | | /* Right-edge blocks are mirrored in y only */ |
721 | 0 | src_ptr = src_buffer[offset_x] |
722 | 0 | [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; |
723 | 0 | for (i = 0; i < DCTSIZE; i++) { |
724 | 0 | for (j = 0; j < DCTSIZE; j++) { |
725 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
726 | 0 | j++; |
727 | 0 | dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j]; |
728 | 0 | } |
729 | 0 | } |
730 | 0 | } |
731 | 0 | } else { |
732 | 0 | if (x_crop_blocks + dst_blk_x < comp_width) { |
733 | | /* Bottom-edge blocks are mirrored in x only */ |
734 | 0 | src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] |
735 | 0 | [dst_blk_y + offset_y + y_crop_blocks]; |
736 | 0 | for (i = 0; i < DCTSIZE; i++) { |
737 | 0 | for (j = 0; j < DCTSIZE; j++) |
738 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
739 | 0 | i++; |
740 | 0 | for (j = 0; j < DCTSIZE; j++) |
741 | 0 | dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j]; |
742 | 0 | } |
743 | 0 | } else { |
744 | | /* At lower right corner, just transpose, no mirroring */ |
745 | 0 | src_ptr = src_buffer[offset_x] |
746 | 0 | [dst_blk_y + offset_y + y_crop_blocks]; |
747 | 0 | for (i = 0; i < DCTSIZE; i++) |
748 | 0 | for (j = 0; j < DCTSIZE; j++) |
749 | 0 | dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j]; |
750 | 0 | } |
751 | 0 | } |
752 | 0 | } |
753 | 0 | } |
754 | 0 | } |
755 | 0 | } |
756 | 0 | } |
757 | 0 | } |
758 | | |
759 | | |
760 | | /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. |
761 | | * Returns TRUE if valid integer found, FALSE if not. |
762 | | * *strptr is advanced over the digit string, and *result is set to its value. |
763 | | */ |
764 | | |
765 | | LOCAL(boolean) |
766 | | jt_read_integer(const char **strptr, JDIMENSION *result) |
767 | 0 | { |
768 | 0 | const char *ptr = *strptr; |
769 | 0 | JDIMENSION val = 0; |
770 | |
|
771 | 0 | for (; isdigit(*ptr); ptr++) { |
772 | 0 | val = val * 10 + (JDIMENSION)(*ptr - '0'); |
773 | 0 | } |
774 | 0 | *result = val; |
775 | 0 | if (ptr == *strptr) |
776 | 0 | return FALSE; /* oops, no digits */ |
777 | 0 | *strptr = ptr; |
778 | 0 | return TRUE; |
779 | 0 | } |
780 | | |
781 | | |
782 | | /* Parse a crop specification (written in X11 geometry style). |
783 | | * The routine returns TRUE if the spec string is valid, FALSE if not. |
784 | | * |
785 | | * The crop spec string should have the format |
786 | | * <width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset> |
787 | | * where width, height, xoffset, and yoffset are unsigned integers. |
788 | | * Each of the elements can be omitted to indicate a default value. |
789 | | * (A weakness of this style is that it is not possible to omit xoffset |
790 | | * while specifying yoffset, since they look alike.) |
791 | | * |
792 | | * This code is loosely based on XParseGeometry from the X11 distribution. |
793 | | */ |
794 | | |
795 | | GLOBAL(boolean) |
796 | | jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec) |
797 | 0 | { |
798 | 0 | info->crop = FALSE; |
799 | 0 | info->crop_width_set = JCROP_UNSET; |
800 | 0 | info->crop_height_set = JCROP_UNSET; |
801 | 0 | info->crop_xoffset_set = JCROP_UNSET; |
802 | 0 | info->crop_yoffset_set = JCROP_UNSET; |
803 | |
|
804 | 0 | if (isdigit(*spec)) { |
805 | | /* fetch width */ |
806 | 0 | if (!jt_read_integer(&spec, &info->crop_width)) |
807 | 0 | return FALSE; |
808 | 0 | if (*spec == 'f' || *spec == 'F') { |
809 | 0 | spec++; |
810 | 0 | info->crop_width_set = JCROP_FORCE; |
811 | 0 | } else |
812 | 0 | info->crop_width_set = JCROP_POS; |
813 | 0 | } |
814 | 0 | if (*spec == 'x' || *spec == 'X') { |
815 | | /* fetch height */ |
816 | 0 | spec++; |
817 | 0 | if (!jt_read_integer(&spec, &info->crop_height)) |
818 | 0 | return FALSE; |
819 | 0 | if (*spec == 'f' || *spec == 'F') { |
820 | 0 | spec++; |
821 | 0 | info->crop_height_set = JCROP_FORCE; |
822 | 0 | } else |
823 | 0 | info->crop_height_set = JCROP_POS; |
824 | 0 | } |
825 | 0 | if (*spec == '+' || *spec == '-') { |
826 | | /* fetch xoffset */ |
827 | 0 | info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; |
828 | 0 | spec++; |
829 | 0 | if (!jt_read_integer(&spec, &info->crop_xoffset)) |
830 | 0 | return FALSE; |
831 | 0 | } |
832 | 0 | if (*spec == '+' || *spec == '-') { |
833 | | /* fetch yoffset */ |
834 | 0 | info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; |
835 | 0 | spec++; |
836 | 0 | if (!jt_read_integer(&spec, &info->crop_yoffset)) |
837 | 0 | return FALSE; |
838 | 0 | } |
839 | | /* We had better have gotten to the end of the string. */ |
840 | 0 | if (*spec != '\0') |
841 | 0 | return FALSE; |
842 | 0 | info->crop = TRUE; |
843 | 0 | return TRUE; |
844 | 0 | } |
845 | | |
846 | | |
847 | | /* Trim off any partial iMCUs on the indicated destination edge */ |
848 | | |
849 | | LOCAL(void) |
850 | | trim_right_edge(jpeg_transform_info *info, JDIMENSION full_width) |
851 | 6.36k | { |
852 | 6.36k | JDIMENSION MCU_cols; |
853 | | |
854 | 6.36k | MCU_cols = info->output_width / info->iMCU_sample_width; |
855 | 6.36k | if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == |
856 | 6.27k | full_width / info->iMCU_sample_width) |
857 | 6.27k | info->output_width = MCU_cols * info->iMCU_sample_width; |
858 | 6.36k | } |
859 | | |
860 | | LOCAL(void) |
861 | | trim_bottom_edge(jpeg_transform_info *info, JDIMENSION full_height) |
862 | 0 | { |
863 | 0 | JDIMENSION MCU_rows; |
864 | |
|
865 | 0 | MCU_rows = info->output_height / info->iMCU_sample_height; |
866 | 0 | if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == |
867 | 0 | full_height / info->iMCU_sample_height) |
868 | 0 | info->output_height = MCU_rows * info->iMCU_sample_height; |
869 | 0 | } |
870 | | |
871 | | |
872 | | /* Request any required workspace. |
873 | | * |
874 | | * This routine figures out the size that the output image will be |
875 | | * (which implies that all the transform parameters must be set before |
876 | | * it is called). |
877 | | * |
878 | | * We allocate the workspace virtual arrays from the source decompression |
879 | | * object, so that all the arrays (both the original data and the workspace) |
880 | | * will be taken into account while making memory management decisions. |
881 | | * Hence, this routine must be called after jpeg_read_header (which reads |
882 | | * the image dimensions) and before jpeg_read_coefficients (which realizes |
883 | | * the source's virtual arrays). |
884 | | * |
885 | | * This function returns FALSE right away if -perfect is given |
886 | | * and transformation is not perfect. Otherwise returns TRUE. |
887 | | */ |
888 | | |
889 | | GLOBAL(boolean) |
890 | | jtransform_request_workspace(j_decompress_ptr srcinfo, |
891 | | jpeg_transform_info *info) |
892 | 14.1k | { |
893 | 14.1k | jvirt_barray_ptr *coef_arrays; |
894 | 14.1k | boolean need_workspace, transpose_it; |
895 | 14.1k | jpeg_component_info *compptr; |
896 | 14.1k | JDIMENSION xoffset, yoffset; |
897 | 14.1k | JDIMENSION width_in_iMCUs, height_in_iMCUs; |
898 | 14.1k | JDIMENSION width_in_blocks, height_in_blocks; |
899 | 14.1k | int ci, h_samp_factor, v_samp_factor; |
900 | | |
901 | | /* Determine number of components in output image */ |
902 | 14.1k | if (info->force_grayscale && |
903 | 14.1k | srcinfo->jpeg_color_space == JCS_YCbCr && |
904 | 14.1k | srcinfo->num_components == 3) |
905 | | /* We'll only process the first component */ |
906 | 1.79k | info->num_components = 1; |
907 | 12.3k | else |
908 | | /* Process all the components */ |
909 | 12.3k | info->num_components = srcinfo->num_components; |
910 | | |
911 | | /* Compute output image dimensions and related values. */ |
912 | | #if JPEG_LIB_VERSION >= 80 |
913 | | jpeg_core_output_dimensions(srcinfo); |
914 | | #else |
915 | 14.1k | srcinfo->output_width = srcinfo->image_width; |
916 | 14.1k | srcinfo->output_height = srcinfo->image_height; |
917 | 14.1k | #endif |
918 | | |
919 | | /* Return right away if -perfect is given and transformation is not perfect. |
920 | | */ |
921 | 14.1k | if (info->perfect) { |
922 | 0 | if (info->num_components == 1) { |
923 | 0 | if (!jtransform_perfect_transform(srcinfo->output_width, |
924 | 0 | srcinfo->output_height, |
925 | 0 | srcinfo->_min_DCT_h_scaled_size, |
926 | 0 | srcinfo->_min_DCT_v_scaled_size, |
927 | 0 | info->transform)) |
928 | 0 | return FALSE; |
929 | 0 | } else { |
930 | 0 | if (!jtransform_perfect_transform(srcinfo->output_width, |
931 | 0 | srcinfo->output_height, |
932 | 0 | srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size, |
933 | 0 | srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size, |
934 | 0 | info->transform)) |
935 | 0 | return FALSE; |
936 | 0 | } |
937 | 0 | } |
938 | | |
939 | | /* If there is only one output component, force the iMCU size to be 1; |
940 | | * else use the source iMCU size. (This allows us to do the right thing |
941 | | * when reducing color to grayscale, and also provides a handy way of |
942 | | * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) |
943 | | */ |
944 | 14.1k | switch (info->transform) { |
945 | 4.03k | case JXFORM_TRANSPOSE: |
946 | 4.03k | case JXFORM_TRANSVERSE: |
947 | 6.10k | case JXFORM_ROT_90: |
948 | 6.10k | case JXFORM_ROT_270: |
949 | 6.10k | info->output_width = srcinfo->output_height; |
950 | 6.10k | info->output_height = srcinfo->output_width; |
951 | 6.10k | if (info->num_components == 1) { |
952 | 4.67k | info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size; |
953 | 4.67k | info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size; |
954 | 4.67k | } else { |
955 | 1.42k | info->iMCU_sample_width = |
956 | 1.42k | srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size; |
957 | 1.42k | info->iMCU_sample_height = |
958 | 1.42k | srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size; |
959 | 1.42k | } |
960 | 6.10k | break; |
961 | 8.06k | default: |
962 | 8.06k | info->output_width = srcinfo->output_width; |
963 | 8.06k | info->output_height = srcinfo->output_height; |
964 | 8.06k | if (info->num_components == 1) { |
965 | 4.15k | info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size; |
966 | 4.15k | info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size; |
967 | 4.15k | } else { |
968 | 3.91k | info->iMCU_sample_width = |
969 | 3.91k | srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size; |
970 | 3.91k | info->iMCU_sample_height = |
971 | 3.91k | srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size; |
972 | 3.91k | } |
973 | 8.06k | break; |
974 | 14.1k | } |
975 | | |
976 | | /* If cropping has been requested, compute the crop area's position and |
977 | | * dimensions, ensuring that its upper left corner falls at an iMCU boundary. |
978 | | */ |
979 | 14.1k | if (info->crop) { |
980 | | /* Insert default values for unset crop parameters */ |
981 | 4.03k | if (info->crop_xoffset_set == JCROP_UNSET) |
982 | 0 | info->crop_xoffset = 0; /* default to +0 */ |
983 | 4.03k | if (info->crop_yoffset_set == JCROP_UNSET) |
984 | 0 | info->crop_yoffset = 0; /* default to +0 */ |
985 | 4.03k | if (info->crop_xoffset >= info->output_width || |
986 | 4.03k | info->crop_yoffset >= info->output_height) |
987 | 0 | ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); |
988 | 4.03k | if (info->crop_width_set == JCROP_UNSET) |
989 | 0 | info->crop_width = info->output_width - info->crop_xoffset; |
990 | 4.03k | if (info->crop_height_set == JCROP_UNSET) |
991 | 0 | info->crop_height = info->output_height - info->crop_yoffset; |
992 | | /* Ensure parameters are valid */ |
993 | 4.03k | if (info->crop_width <= 0 || info->crop_width > info->output_width || |
994 | 4.03k | info->crop_height <= 0 || info->crop_height > info->output_height || |
995 | 4.03k | info->crop_xoffset > info->output_width - info->crop_width || |
996 | 4.03k | info->crop_yoffset > info->output_height - info->crop_height) |
997 | 1.95k | ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); |
998 | | /* Convert negative crop offsets into regular offsets */ |
999 | 4.03k | if (info->crop_xoffset_set == JCROP_NEG) |
1000 | 0 | xoffset = info->output_width - info->crop_width - info->crop_xoffset; |
1001 | 4.03k | else |
1002 | 4.03k | xoffset = info->crop_xoffset; |
1003 | 4.03k | if (info->crop_yoffset_set == JCROP_NEG) |
1004 | 0 | yoffset = info->output_height - info->crop_height - info->crop_yoffset; |
1005 | 4.03k | else |
1006 | 4.03k | yoffset = info->crop_yoffset; |
1007 | | /* Now adjust so that upper left corner falls at an iMCU boundary */ |
1008 | 4.03k | if (info->crop_width_set == JCROP_FORCE) |
1009 | 0 | info->output_width = info->crop_width; |
1010 | 4.03k | else |
1011 | 4.03k | info->output_width = |
1012 | 4.03k | info->crop_width + (xoffset % info->iMCU_sample_width); |
1013 | 4.03k | if (info->crop_height_set == JCROP_FORCE) |
1014 | 0 | info->output_height = info->crop_height; |
1015 | 4.03k | else |
1016 | 4.03k | info->output_height = |
1017 | 4.03k | info->crop_height + (yoffset % info->iMCU_sample_height); |
1018 | | /* Save x/y offsets measured in iMCUs */ |
1019 | 4.03k | info->x_crop_offset = xoffset / info->iMCU_sample_width; |
1020 | 4.03k | info->y_crop_offset = yoffset / info->iMCU_sample_height; |
1021 | 10.1k | } else { |
1022 | 10.1k | info->x_crop_offset = 0; |
1023 | 10.1k | info->y_crop_offset = 0; |
1024 | 10.1k | } |
1025 | | |
1026 | | /* Figure out whether we need workspace arrays, |
1027 | | * and if so whether they are transposed relative to the source. |
1028 | | */ |
1029 | 14.1k | need_workspace = FALSE; |
1030 | 14.1k | transpose_it = FALSE; |
1031 | 14.1k | switch (info->transform) { |
1032 | 8.06k | case JXFORM_NONE: |
1033 | 8.06k | if (info->x_crop_offset != 0 || info->y_crop_offset != 0) |
1034 | 0 | need_workspace = TRUE; |
1035 | | /* No workspace needed if neither cropping nor transforming */ |
1036 | 8.06k | break; |
1037 | 0 | case JXFORM_FLIP_H: |
1038 | 0 | if (info->trim) |
1039 | 0 | trim_right_edge(info, srcinfo->output_width); |
1040 | 0 | if (info->y_crop_offset != 0 || info->slow_hflip) |
1041 | 0 | need_workspace = TRUE; |
1042 | | /* do_flip_h_no_crop doesn't need a workspace array */ |
1043 | 0 | break; |
1044 | 0 | case JXFORM_FLIP_V: |
1045 | 0 | if (info->trim) |
1046 | 0 | trim_bottom_edge(info, srcinfo->output_height); |
1047 | | /* Need workspace arrays having same dimensions as source image. */ |
1048 | 0 | need_workspace = TRUE; |
1049 | 0 | break; |
1050 | 2.07k | case JXFORM_TRANSPOSE: |
1051 | | /* transpose does NOT have to trim anything */ |
1052 | | /* Need workspace arrays having transposed dimensions. */ |
1053 | 2.07k | need_workspace = TRUE; |
1054 | 2.07k | transpose_it = TRUE; |
1055 | 2.07k | break; |
1056 | 0 | case JXFORM_TRANSVERSE: |
1057 | 0 | if (info->trim) { |
1058 | 0 | trim_right_edge(info, srcinfo->output_height); |
1059 | 0 | trim_bottom_edge(info, srcinfo->output_width); |
1060 | 0 | } |
1061 | | /* Need workspace arrays having transposed dimensions. */ |
1062 | 0 | need_workspace = TRUE; |
1063 | 0 | transpose_it = TRUE; |
1064 | 0 | break; |
1065 | 2.07k | case JXFORM_ROT_90: |
1066 | 2.07k | if (info->trim) |
1067 | 2.07k | trim_right_edge(info, srcinfo->output_height); |
1068 | | /* Need workspace arrays having transposed dimensions. */ |
1069 | 2.07k | need_workspace = TRUE; |
1070 | 2.07k | transpose_it = TRUE; |
1071 | 2.07k | break; |
1072 | 0 | case JXFORM_ROT_180: |
1073 | 0 | if (info->trim) { |
1074 | 0 | trim_right_edge(info, srcinfo->output_width); |
1075 | 0 | trim_bottom_edge(info, srcinfo->output_height); |
1076 | 0 | } |
1077 | | /* Need workspace arrays having same dimensions as source image. */ |
1078 | 0 | need_workspace = TRUE; |
1079 | 0 | break; |
1080 | 0 | case JXFORM_ROT_270: |
1081 | 0 | if (info->trim) |
1082 | 0 | trim_bottom_edge(info, srcinfo->output_width); |
1083 | | /* Need workspace arrays having transposed dimensions. */ |
1084 | 0 | need_workspace = TRUE; |
1085 | 0 | transpose_it = TRUE; |
1086 | 0 | break; |
1087 | 14.1k | } |
1088 | | |
1089 | | /* Allocate workspace if needed. |
1090 | | * Note that we allocate arrays padded out to the next iMCU boundary, |
1091 | | * so that transform routines need not worry about missing edge blocks. |
1092 | | */ |
1093 | 12.2k | if (need_workspace) { |
1094 | 4.14k | coef_arrays = (jvirt_barray_ptr *) |
1095 | 4.14k | (*srcinfo->mem->alloc_small) ((j_common_ptr)srcinfo, JPOOL_IMAGE, |
1096 | 4.14k | sizeof(jvirt_barray_ptr) * info->num_components); |
1097 | 4.14k | width_in_iMCUs = (JDIMENSION) |
1098 | 4.14k | jdiv_round_up((long)info->output_width, (long)info->iMCU_sample_width); |
1099 | 4.14k | height_in_iMCUs = (JDIMENSION) |
1100 | 4.14k | jdiv_round_up((long)info->output_height, (long)info->iMCU_sample_height); |
1101 | 11.0k | for (ci = 0; ci < info->num_components; ci++) { |
1102 | 6.95k | compptr = srcinfo->comp_info + ci; |
1103 | 6.95k | if (info->num_components == 1) { |
1104 | | /* we're going to force samp factors to 1x1 in this case */ |
1105 | 2.79k | h_samp_factor = v_samp_factor = 1; |
1106 | 4.15k | } else if (transpose_it) { |
1107 | 4.15k | h_samp_factor = compptr->v_samp_factor; |
1108 | 4.15k | v_samp_factor = compptr->h_samp_factor; |
1109 | 4.15k | } else { |
1110 | 0 | h_samp_factor = compptr->h_samp_factor; |
1111 | 0 | v_samp_factor = compptr->v_samp_factor; |
1112 | 0 | } |
1113 | 6.95k | width_in_blocks = width_in_iMCUs * h_samp_factor; |
1114 | 6.95k | height_in_blocks = height_in_iMCUs * v_samp_factor; |
1115 | 6.95k | coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) |
1116 | 6.95k | ((j_common_ptr)srcinfo, JPOOL_IMAGE, FALSE, |
1117 | 6.95k | width_in_blocks, height_in_blocks, (JDIMENSION)v_samp_factor); |
1118 | 6.95k | } |
1119 | 4.14k | info->workspace_coef_arrays = coef_arrays; |
1120 | 4.14k | } else |
1121 | 8.06k | info->workspace_coef_arrays = NULL; |
1122 | | |
1123 | 12.2k | return TRUE; |
1124 | 14.1k | } |
1125 | | |
1126 | | |
1127 | | /* Transpose destination image parameters */ |
1128 | | |
1129 | | LOCAL(void) |
1130 | | transpose_critical_parameters(j_compress_ptr dstinfo) |
1131 | 5.52k | { |
1132 | 5.52k | int tblno, i, j, ci, itemp; |
1133 | 5.52k | jpeg_component_info *compptr; |
1134 | 5.52k | JQUANT_TBL *qtblptr; |
1135 | 5.52k | JDIMENSION jtemp; |
1136 | 5.52k | UINT16 qtemp; |
1137 | | |
1138 | | /* Transpose image dimensions */ |
1139 | 5.52k | jtemp = dstinfo->image_width; |
1140 | 5.52k | dstinfo->image_width = dstinfo->image_height; |
1141 | 5.52k | dstinfo->image_height = jtemp; |
1142 | | #if JPEG_LIB_VERSION >= 70 |
1143 | | itemp = dstinfo->min_DCT_h_scaled_size; |
1144 | | dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; |
1145 | | dstinfo->min_DCT_v_scaled_size = itemp; |
1146 | | #endif |
1147 | | |
1148 | | /* Transpose sampling factors */ |
1149 | 12.3k | for (ci = 0; ci < dstinfo->num_components; ci++) { |
1150 | 6.82k | compptr = dstinfo->comp_info + ci; |
1151 | 6.82k | itemp = compptr->h_samp_factor; |
1152 | 6.82k | compptr->h_samp_factor = compptr->v_samp_factor; |
1153 | 6.82k | compptr->v_samp_factor = itemp; |
1154 | 6.82k | } |
1155 | | |
1156 | | /* Transpose quantization tables */ |
1157 | 27.6k | for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { |
1158 | 22.1k | qtblptr = dstinfo->quant_tbl_ptrs[tblno]; |
1159 | 22.1k | if (qtblptr != NULL) { |
1160 | 99.8k | for (i = 0; i < DCTSIZE; i++) { |
1161 | 399k | for (j = 0; j < i; j++) { |
1162 | 310k | qtemp = qtblptr->quantval[i * DCTSIZE + j]; |
1163 | 310k | qtblptr->quantval[i * DCTSIZE + j] = |
1164 | 310k | qtblptr->quantval[j * DCTSIZE + i]; |
1165 | 310k | qtblptr->quantval[j * DCTSIZE + i] = qtemp; |
1166 | 310k | } |
1167 | 88.7k | } |
1168 | 11.0k | } |
1169 | 22.1k | } |
1170 | 5.52k | } |
1171 | | |
1172 | | |
1173 | | /* Adjust Exif image parameters. |
1174 | | * |
1175 | | * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. |
1176 | | */ |
1177 | | |
1178 | | LOCAL(void) |
1179 | | adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width, |
1180 | | JDIMENSION new_height) |
1181 | 0 | { |
1182 | 0 | boolean is_motorola; /* Flag for byte order */ |
1183 | 0 | unsigned int number_of_tags, tagnum; |
1184 | 0 | unsigned int firstoffset, offset; |
1185 | 0 | JDIMENSION new_value; |
1186 | |
|
1187 | 0 | if (length < 12) return; /* Length of an IFD entry */ |
1188 | | |
1189 | | /* Discover byte order */ |
1190 | 0 | if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) |
1191 | 0 | is_motorola = FALSE; |
1192 | 0 | else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) |
1193 | 0 | is_motorola = TRUE; |
1194 | 0 | else |
1195 | 0 | return; |
1196 | | |
1197 | | /* Check Tag Mark */ |
1198 | 0 | if (is_motorola) { |
1199 | 0 | if (GETJOCTET(data[2]) != 0) return; |
1200 | 0 | if (GETJOCTET(data[3]) != 0x2A) return; |
1201 | 0 | } else { |
1202 | 0 | if (GETJOCTET(data[3]) != 0) return; |
1203 | 0 | if (GETJOCTET(data[2]) != 0x2A) return; |
1204 | 0 | } |
1205 | | |
1206 | | /* Get first IFD offset (offset to IFD0) */ |
1207 | 0 | if (is_motorola) { |
1208 | 0 | if (GETJOCTET(data[4]) != 0) return; |
1209 | 0 | if (GETJOCTET(data[5]) != 0) return; |
1210 | 0 | firstoffset = GETJOCTET(data[6]); |
1211 | 0 | firstoffset <<= 8; |
1212 | 0 | firstoffset += GETJOCTET(data[7]); |
1213 | 0 | } else { |
1214 | 0 | if (GETJOCTET(data[7]) != 0) return; |
1215 | 0 | if (GETJOCTET(data[6]) != 0) return; |
1216 | 0 | firstoffset = GETJOCTET(data[5]); |
1217 | 0 | firstoffset <<= 8; |
1218 | 0 | firstoffset += GETJOCTET(data[4]); |
1219 | 0 | } |
1220 | 0 | if (firstoffset > length - 2) return; /* check end of data segment */ |
1221 | | |
1222 | | /* Get the number of directory entries contained in this IFD */ |
1223 | 0 | if (is_motorola) { |
1224 | 0 | number_of_tags = GETJOCTET(data[firstoffset]); |
1225 | 0 | number_of_tags <<= 8; |
1226 | 0 | number_of_tags += GETJOCTET(data[firstoffset + 1]); |
1227 | 0 | } else { |
1228 | 0 | number_of_tags = GETJOCTET(data[firstoffset + 1]); |
1229 | 0 | number_of_tags <<= 8; |
1230 | 0 | number_of_tags += GETJOCTET(data[firstoffset]); |
1231 | 0 | } |
1232 | 0 | if (number_of_tags == 0) return; |
1233 | 0 | firstoffset += 2; |
1234 | | |
1235 | | /* Search for ExifSubIFD offset Tag in IFD0 */ |
1236 | 0 | for (;;) { |
1237 | 0 | if (firstoffset > length - 12) return; /* check end of data segment */ |
1238 | | /* Get Tag number */ |
1239 | 0 | if (is_motorola) { |
1240 | 0 | tagnum = GETJOCTET(data[firstoffset]); |
1241 | 0 | tagnum <<= 8; |
1242 | 0 | tagnum += GETJOCTET(data[firstoffset + 1]); |
1243 | 0 | } else { |
1244 | 0 | tagnum = GETJOCTET(data[firstoffset + 1]); |
1245 | 0 | tagnum <<= 8; |
1246 | 0 | tagnum += GETJOCTET(data[firstoffset]); |
1247 | 0 | } |
1248 | 0 | if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ |
1249 | 0 | if (--number_of_tags == 0) return; |
1250 | 0 | firstoffset += 12; |
1251 | 0 | } |
1252 | | |
1253 | | /* Get the ExifSubIFD offset */ |
1254 | 0 | if (is_motorola) { |
1255 | 0 | if (GETJOCTET(data[firstoffset + 8]) != 0) return; |
1256 | 0 | if (GETJOCTET(data[firstoffset + 9]) != 0) return; |
1257 | 0 | offset = GETJOCTET(data[firstoffset + 10]); |
1258 | 0 | offset <<= 8; |
1259 | 0 | offset += GETJOCTET(data[firstoffset + 11]); |
1260 | 0 | } else { |
1261 | 0 | if (GETJOCTET(data[firstoffset + 11]) != 0) return; |
1262 | 0 | if (GETJOCTET(data[firstoffset + 10]) != 0) return; |
1263 | 0 | offset = GETJOCTET(data[firstoffset + 9]); |
1264 | 0 | offset <<= 8; |
1265 | 0 | offset += GETJOCTET(data[firstoffset + 8]); |
1266 | 0 | } |
1267 | 0 | if (offset > length - 2) return; /* check end of data segment */ |
1268 | | |
1269 | | /* Get the number of directory entries contained in this SubIFD */ |
1270 | 0 | if (is_motorola) { |
1271 | 0 | number_of_tags = GETJOCTET(data[offset]); |
1272 | 0 | number_of_tags <<= 8; |
1273 | 0 | number_of_tags += GETJOCTET(data[offset + 1]); |
1274 | 0 | } else { |
1275 | 0 | number_of_tags = GETJOCTET(data[offset + 1]); |
1276 | 0 | number_of_tags <<= 8; |
1277 | 0 | number_of_tags += GETJOCTET(data[offset]); |
1278 | 0 | } |
1279 | 0 | if (number_of_tags < 2) return; |
1280 | 0 | offset += 2; |
1281 | | |
1282 | | /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ |
1283 | 0 | do { |
1284 | 0 | if (offset > length - 12) return; /* check end of data segment */ |
1285 | | /* Get Tag number */ |
1286 | 0 | if (is_motorola) { |
1287 | 0 | tagnum = GETJOCTET(data[offset]); |
1288 | 0 | tagnum <<= 8; |
1289 | 0 | tagnum += GETJOCTET(data[offset + 1]); |
1290 | 0 | } else { |
1291 | 0 | tagnum = GETJOCTET(data[offset + 1]); |
1292 | 0 | tagnum <<= 8; |
1293 | 0 | tagnum += GETJOCTET(data[offset]); |
1294 | 0 | } |
1295 | 0 | if (tagnum == 0xA002 || tagnum == 0xA003) { |
1296 | 0 | if (tagnum == 0xA002) |
1297 | 0 | new_value = new_width; /* ExifImageWidth Tag */ |
1298 | 0 | else |
1299 | 0 | new_value = new_height; /* ExifImageHeight Tag */ |
1300 | 0 | if (is_motorola) { |
1301 | 0 | data[offset + 2] = 0; /* Format = unsigned long (4 octets) */ |
1302 | 0 | data[offset + 3] = 4; |
1303 | 0 | data[offset + 4] = 0; /* Number Of Components = 1 */ |
1304 | 0 | data[offset + 5] = 0; |
1305 | 0 | data[offset + 6] = 0; |
1306 | 0 | data[offset + 7] = 1; |
1307 | 0 | data[offset + 8] = 0; |
1308 | 0 | data[offset + 9] = 0; |
1309 | 0 | data[offset + 10] = (JOCTET)((new_value >> 8) & 0xFF); |
1310 | 0 | data[offset + 11] = (JOCTET)(new_value & 0xFF); |
1311 | 0 | } else { |
1312 | 0 | data[offset + 2] = 4; /* Format = unsigned long (4 octets) */ |
1313 | 0 | data[offset + 3] = 0; |
1314 | 0 | data[offset + 4] = 1; /* Number Of Components = 1 */ |
1315 | 0 | data[offset + 5] = 0; |
1316 | 0 | data[offset + 6] = 0; |
1317 | 0 | data[offset + 7] = 0; |
1318 | 0 | data[offset + 8] = (JOCTET)(new_value & 0xFF); |
1319 | 0 | data[offset + 9] = (JOCTET)((new_value >> 8) & 0xFF); |
1320 | 0 | data[offset + 10] = 0; |
1321 | 0 | data[offset + 11] = 0; |
1322 | 0 | } |
1323 | 0 | } |
1324 | 0 | offset += 12; |
1325 | 0 | } while (--number_of_tags); |
1326 | 0 | } |
1327 | | |
1328 | | |
1329 | | /* Adjust output image parameters as needed. |
1330 | | * |
1331 | | * This must be called after jpeg_copy_critical_parameters() |
1332 | | * and before jpeg_write_coefficients(). |
1333 | | * |
1334 | | * The return value is the set of virtual coefficient arrays to be written |
1335 | | * (either the ones allocated by jtransform_request_workspace, or the |
1336 | | * original source data arrays). The caller will need to pass this value |
1337 | | * to jpeg_write_coefficients(). |
1338 | | */ |
1339 | | |
1340 | | GLOBAL(jvirt_barray_ptr *) |
1341 | | jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
1342 | | jvirt_barray_ptr *src_coef_arrays, |
1343 | | jpeg_transform_info *info) |
1344 | 4.30k | { |
1345 | | /* If force-to-grayscale is requested, adjust destination parameters */ |
1346 | 4.30k | if (info->force_grayscale) { |
1347 | | /* First, ensure we have YCbCr or grayscale data, and that the source's |
1348 | | * Y channel is full resolution. (No reasonable person would make Y |
1349 | | * be less than full resolution, so actually coping with that case |
1350 | | * isn't worth extra code space. But we check it to avoid crashing.) |
1351 | | */ |
1352 | 779 | if (((dstinfo->jpeg_color_space == JCS_YCbCr && |
1353 | 779 | dstinfo->num_components == 3) || |
1354 | 779 | (dstinfo->jpeg_color_space == JCS_GRAYSCALE && |
1355 | 501 | dstinfo->num_components == 1)) && |
1356 | 779 | srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && |
1357 | 779 | srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { |
1358 | | /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed |
1359 | | * properly. Among other things, it sets the target h_samp_factor & |
1360 | | * v_samp_factor to 1, which typically won't match the source. |
1361 | | * We have to preserve the source's quantization table number, however. |
1362 | | */ |
1363 | 733 | int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; |
1364 | 733 | jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); |
1365 | 733 | dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; |
1366 | 733 | } else { |
1367 | | /* Sorry, can't do it */ |
1368 | 46 | ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); |
1369 | 46 | } |
1370 | 3.52k | } else if (info->num_components == 1) { |
1371 | | /* For a single-component source, we force the destination sampling factors |
1372 | | * to 1x1, with or without force_grayscale. This is useful because some |
1373 | | * decoders choke on grayscale images with other sampling factors. |
1374 | | */ |
1375 | 2.27k | dstinfo->comp_info[0].h_samp_factor = 1; |
1376 | 2.27k | dstinfo->comp_info[0].v_samp_factor = 1; |
1377 | 2.27k | } |
1378 | | |
1379 | | /* Correct the destination's image dimensions as necessary |
1380 | | * for rotate/flip, resize, and crop operations. |
1381 | | */ |
1382 | | #if JPEG_LIB_VERSION >= 80 |
1383 | | dstinfo->jpeg_width = info->output_width; |
1384 | | dstinfo->jpeg_height = info->output_height; |
1385 | | #endif |
1386 | | |
1387 | | /* Transpose destination image parameters */ |
1388 | 4.30k | switch (info->transform) { |
1389 | 733 | case JXFORM_TRANSPOSE: |
1390 | 733 | case JXFORM_TRANSVERSE: |
1391 | 1.46k | case JXFORM_ROT_90: |
1392 | 1.46k | case JXFORM_ROT_270: |
1393 | 1.46k | #if JPEG_LIB_VERSION < 80 |
1394 | 1.46k | dstinfo->image_width = info->output_height; |
1395 | 1.46k | dstinfo->image_height = info->output_width; |
1396 | 1.46k | #endif |
1397 | 1.46k | transpose_critical_parameters(dstinfo); |
1398 | 1.46k | break; |
1399 | 2.79k | default: |
1400 | 2.79k | #if JPEG_LIB_VERSION < 80 |
1401 | 2.79k | dstinfo->image_width = info->output_width; |
1402 | 2.79k | dstinfo->image_height = info->output_height; |
1403 | 2.79k | #endif |
1404 | 2.79k | break; |
1405 | 4.30k | } |
1406 | | |
1407 | | /* Adjust Exif properties */ |
1408 | 4.25k | if (srcinfo->marker_list != NULL && |
1409 | 4.25k | srcinfo->marker_list->marker == JPEG_APP0 + 1 && |
1410 | 4.25k | srcinfo->marker_list->data_length >= 6 && |
1411 | 4.25k | GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && |
1412 | 4.25k | GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && |
1413 | 4.25k | GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && |
1414 | 4.25k | GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && |
1415 | 4.25k | GETJOCTET(srcinfo->marker_list->data[4]) == 0 && |
1416 | 4.25k | GETJOCTET(srcinfo->marker_list->data[5]) == 0) { |
1417 | | /* Suppress output of JFIF marker */ |
1418 | 3 | dstinfo->write_JFIF_header = FALSE; |
1419 | | /* Adjust Exif image parameters */ |
1420 | | #if JPEG_LIB_VERSION >= 80 |
1421 | | if (dstinfo->jpeg_width != srcinfo->image_width || |
1422 | | dstinfo->jpeg_height != srcinfo->image_height) |
1423 | | /* Align data segment to start of TIFF structure for parsing */ |
1424 | | adjust_exif_parameters(srcinfo->marker_list->data + 6, |
1425 | | srcinfo->marker_list->data_length - 6, |
1426 | | dstinfo->jpeg_width, dstinfo->jpeg_height); |
1427 | | #else |
1428 | 3 | if (dstinfo->image_width != srcinfo->image_width || |
1429 | 3 | dstinfo->image_height != srcinfo->image_height) |
1430 | | /* Align data segment to start of TIFF structure for parsing */ |
1431 | 0 | adjust_exif_parameters(srcinfo->marker_list->data + 6, |
1432 | 0 | srcinfo->marker_list->data_length - 6, |
1433 | 0 | dstinfo->image_width, dstinfo->image_height); |
1434 | 3 | #endif |
1435 | 3 | } |
1436 | | |
1437 | | /* Return the appropriate output data set */ |
1438 | 4.25k | if (info->workspace_coef_arrays != NULL) |
1439 | 1.46k | return info->workspace_coef_arrays; |
1440 | 2.79k | return src_coef_arrays; |
1441 | 4.25k | } |
1442 | | |
1443 | | |
1444 | | /* Execute the actual transformation, if any. |
1445 | | * |
1446 | | * This must be called *after* jpeg_write_coefficients, because it depends |
1447 | | * on jpeg_write_coefficients to have computed subsidiary values such as |
1448 | | * the per-component width and height fields in the destination object. |
1449 | | * |
1450 | | * Note that some transformations will modify the source data arrays! |
1451 | | */ |
1452 | | |
1453 | | GLOBAL(void) |
1454 | | jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
1455 | | jvirt_barray_ptr *src_coef_arrays, |
1456 | | jpeg_transform_info *info) |
1457 | 4.25k | { |
1458 | 4.25k | jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; |
1459 | | |
1460 | | /* Note: conditions tested here should match those in switch statement |
1461 | | * in jtransform_request_workspace() |
1462 | | */ |
1463 | 4.25k | switch (info->transform) { |
1464 | 2.79k | case JXFORM_NONE: |
1465 | 2.79k | if (info->x_crop_offset != 0 || info->y_crop_offset != 0) |
1466 | 0 | do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1467 | 0 | src_coef_arrays, dst_coef_arrays); |
1468 | 2.79k | break; |
1469 | 0 | case JXFORM_FLIP_H: |
1470 | 0 | if (info->y_crop_offset != 0 || info->slow_hflip) |
1471 | 0 | do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1472 | 0 | src_coef_arrays, dst_coef_arrays); |
1473 | 0 | else |
1474 | 0 | do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, |
1475 | 0 | src_coef_arrays); |
1476 | 0 | break; |
1477 | 0 | case JXFORM_FLIP_V: |
1478 | 0 | do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1479 | 0 | src_coef_arrays, dst_coef_arrays); |
1480 | 0 | break; |
1481 | 733 | case JXFORM_TRANSPOSE: |
1482 | 733 | do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1483 | 733 | src_coef_arrays, dst_coef_arrays); |
1484 | 733 | break; |
1485 | 0 | case JXFORM_TRANSVERSE: |
1486 | 0 | do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1487 | 0 | src_coef_arrays, dst_coef_arrays); |
1488 | 0 | break; |
1489 | 733 | case JXFORM_ROT_90: |
1490 | 733 | do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1491 | 733 | src_coef_arrays, dst_coef_arrays); |
1492 | 733 | break; |
1493 | 0 | case JXFORM_ROT_180: |
1494 | 0 | do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1495 | 0 | src_coef_arrays, dst_coef_arrays); |
1496 | 0 | break; |
1497 | 0 | case JXFORM_ROT_270: |
1498 | 0 | do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, |
1499 | 0 | src_coef_arrays, dst_coef_arrays); |
1500 | 0 | break; |
1501 | 4.25k | } |
1502 | 4.25k | } |
1503 | | |
1504 | | /* jtransform_perfect_transform |
1505 | | * |
1506 | | * Determine whether lossless transformation is perfectly |
1507 | | * possible for a specified image and transformation. |
1508 | | * |
1509 | | * Inputs: |
1510 | | * image_width, image_height: source image dimensions. |
1511 | | * MCU_width, MCU_height: pixel dimensions of MCU. |
1512 | | * transform: transformation identifier. |
1513 | | * Parameter sources from initialized jpeg_struct |
1514 | | * (after reading source header): |
1515 | | * image_width = cinfo.image_width |
1516 | | * image_height = cinfo.image_height |
1517 | | * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size |
1518 | | * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size |
1519 | | * Result: |
1520 | | * TRUE = perfect transformation possible |
1521 | | * FALSE = perfect transformation not possible |
1522 | | * (may use custom action then) |
1523 | | */ |
1524 | | |
1525 | | GLOBAL(boolean) |
1526 | | jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, |
1527 | | int MCU_width, int MCU_height, |
1528 | | JXFORM_CODE transform) |
1529 | 0 | { |
1530 | 0 | boolean result = TRUE; /* initialize TRUE */ |
1531 | |
|
1532 | 0 | switch (transform) { |
1533 | 0 | case JXFORM_FLIP_H: |
1534 | 0 | case JXFORM_ROT_270: |
1535 | 0 | if (image_width % (JDIMENSION)MCU_width) |
1536 | 0 | result = FALSE; |
1537 | 0 | break; |
1538 | 0 | case JXFORM_FLIP_V: |
1539 | 0 | case JXFORM_ROT_90: |
1540 | 0 | if (image_height % (JDIMENSION)MCU_height) |
1541 | 0 | result = FALSE; |
1542 | 0 | break; |
1543 | 0 | case JXFORM_TRANSVERSE: |
1544 | 0 | case JXFORM_ROT_180: |
1545 | 0 | if (image_width % (JDIMENSION)MCU_width) |
1546 | 0 | result = FALSE; |
1547 | 0 | if (image_height % (JDIMENSION)MCU_height) |
1548 | 0 | result = FALSE; |
1549 | 0 | break; |
1550 | 0 | default: |
1551 | 0 | break; |
1552 | 0 | } |
1553 | | |
1554 | 0 | return result; |
1555 | 0 | } |
1556 | | |
1557 | | #endif /* TRANSFORMS_SUPPORTED */ |
1558 | | |
1559 | | |
1560 | | /* Setup decompression object to save desired markers in memory. |
1561 | | * This must be called before jpeg_read_header() to have the desired effect. |
1562 | | */ |
1563 | | |
1564 | | GLOBAL(void) |
1565 | | jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option) |
1566 | 8.26k | { |
1567 | 8.26k | #ifdef SAVE_MARKERS_SUPPORTED |
1568 | 8.26k | int m; |
1569 | | |
1570 | | /* Save comments except under NONE option */ |
1571 | 8.26k | if (option != JCOPYOPT_NONE) { |
1572 | 4.13k | jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); |
1573 | 4.13k | } |
1574 | | /* Save all types of APPn markers iff ALL option */ |
1575 | 8.26k | if (option == JCOPYOPT_ALL || option == JCOPYOPT_ALL_EXCEPT_ICC) { |
1576 | 70.2k | for (m = 0; m < 16; m++) { |
1577 | 66.0k | if (option == JCOPYOPT_ALL_EXCEPT_ICC && m == 2) |
1578 | 0 | continue; |
1579 | 66.0k | jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); |
1580 | 66.0k | } |
1581 | 4.13k | } |
1582 | 8.26k | #endif /* SAVE_MARKERS_SUPPORTED */ |
1583 | 8.26k | } |
1584 | | |
1585 | | /* Copy markers saved in the given source object to the destination object. |
1586 | | * This should be called just after jpeg_start_compress() or |
1587 | | * jpeg_write_coefficients(). |
1588 | | * Note that those routines will have written the SOI, and also the |
1589 | | * JFIF APP0 or Adobe APP14 markers if selected. |
1590 | | */ |
1591 | | |
1592 | | GLOBAL(void) |
1593 | | jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, |
1594 | | JCOPY_OPTION option) |
1595 | 15.2k | { |
1596 | 15.2k | jpeg_saved_marker_ptr marker; |
1597 | | |
1598 | | /* In the current implementation, we don't actually need to examine the |
1599 | | * option flag here; we just copy everything that got saved. |
1600 | | * But to avoid confusion, we do not output JFIF and Adobe APP14 markers |
1601 | | * if the encoder library already wrote one. |
1602 | | */ |
1603 | 614k | for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { |
1604 | 599k | if (dstinfo->write_JFIF_header && |
1605 | 599k | marker->marker == JPEG_APP0 && |
1606 | 599k | marker->data_length >= 5 && |
1607 | 599k | GETJOCTET(marker->data[0]) == 0x4A && |
1608 | 599k | GETJOCTET(marker->data[1]) == 0x46 && |
1609 | 599k | GETJOCTET(marker->data[2]) == 0x49 && |
1610 | 599k | GETJOCTET(marker->data[3]) == 0x46 && |
1611 | 599k | GETJOCTET(marker->data[4]) == 0) |
1612 | 1.26k | continue; /* reject duplicate JFIF */ |
1613 | 598k | if (dstinfo->write_Adobe_marker && |
1614 | 598k | marker->marker == JPEG_APP0 + 14 && |
1615 | 598k | marker->data_length >= 5 && |
1616 | 598k | GETJOCTET(marker->data[0]) == 0x41 && |
1617 | 598k | GETJOCTET(marker->data[1]) == 0x64 && |
1618 | 598k | GETJOCTET(marker->data[2]) == 0x6F && |
1619 | 598k | GETJOCTET(marker->data[3]) == 0x62 && |
1620 | 598k | GETJOCTET(marker->data[4]) == 0x65) |
1621 | 7.69k | continue; /* reject duplicate Adobe */ |
1622 | 590k | jpeg_write_marker(dstinfo, marker->marker, |
1623 | 590k | marker->data, marker->data_length); |
1624 | 590k | } |
1625 | 15.2k | } |