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