Annotation of /trunk/libjpeg/patches/libjpeg-6b-crop.patch
Parent Directory | Revision Log
Revision 144 -
(hide annotations)
(download)
Tue May 8 20:06:05 2007 UTC (17 years, 4 months ago) by niro
File size: 72760 byte(s)
Tue May 8 20:06:05 2007 UTC (17 years, 4 months ago) by niro
File size: 72760 byte(s)
-import
1 | niro | 144 | # DP: Lossless-crop patch from <http://sylvana.net/jpegcrop/croppatch.tar.gz> |
2 | # DP: by <guido@jpegclub.org>. | ||
3 | |||
4 | diff -urNad /home/bill/debian/libjpeg/libjpeg6b-6b/jerror.h libjpeg6b-6b/jerror.h | ||
5 | --- /home/bill/debian/libjpeg/libjpeg6b-6b/jerror.h 2003-09-22 18:15:48.000000000 +0200 | ||
6 | +++ libjpeg6b-6b/jerror.h 2003-09-22 18:16:12.000000000 +0200 | ||
7 | @@ -45,6 +45,7 @@ | ||
8 | JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") | ||
9 | JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") | ||
10 | JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") | ||
11 | +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") | ||
12 | JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") | ||
13 | JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") | ||
14 | JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") | ||
15 | diff -urNad /home/bill/debian/libjpeg/libjpeg6b-6b/jpegtran.c libjpeg6b-6b/jpegtran.c | ||
16 | --- /home/bill/debian/libjpeg/libjpeg6b-6b/jpegtran.c 2003-09-22 18:15:48.000000000 +0200 | ||
17 | +++ libjpeg6b-6b/jpegtran.c 2003-09-22 18:16:22.000000000 +0200 | ||
18 | @@ -1,7 +1,7 @@ | ||
19 | /* | ||
20 | * jpegtran.c | ||
21 | * | ||
22 | - * Copyright (C) 1995-1997, Thomas G. Lane. | ||
23 | + * Copyright (C) 1995-2001, Thomas G. Lane. | ||
24 | * This file is part of the Independent JPEG Group's software. | ||
25 | * For conditions of distribution and use, see the accompanying README file. | ||
26 | * | ||
27 | @@ -64,8 +64,10 @@ | ||
28 | #endif | ||
29 | #if TRANSFORMS_SUPPORTED | ||
30 | fprintf(stderr, "Switches for modifying the image:\n"); | ||
31 | + fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n"); | ||
32 | fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n"); | ||
33 | fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n"); | ||
34 | + fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n"); | ||
35 | fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n"); | ||
36 | fprintf(stderr, " -transpose Transpose image\n"); | ||
37 | fprintf(stderr, " -transverse Transverse transpose image\n"); | ||
38 | @@ -133,7 +135,9 @@ | ||
39 | copyoption = JCOPYOPT_DEFAULT; | ||
40 | transformoption.transform = JXFORM_NONE; | ||
41 | transformoption.trim = FALSE; | ||
42 | + transformoption.perfect = FALSE; | ||
43 | transformoption.force_grayscale = FALSE; | ||
44 | + transformoption.crop = FALSE; | ||
45 | cinfo->err->trace_level = 0; | ||
46 | |||
47 | /* Scan command line options, adjust parameters */ | ||
48 | @@ -160,7 +164,7 @@ | ||
49 | exit(EXIT_FAILURE); | ||
50 | #endif | ||
51 | |||
52 | - } else if (keymatch(arg, "copy", 1)) { | ||
53 | + } else if (keymatch(arg, "copy", 2)) { | ||
54 | /* Select which extra markers to copy. */ | ||
55 | if (++argn >= argc) /* advance to next argument */ | ||
56 | usage(); | ||
57 | @@ -173,6 +177,20 @@ | ||
58 | } else | ||
59 | usage(); | ||
60 | |||
61 | + } else if (keymatch(arg, "crop", 2)) { | ||
62 | + /* Perform lossless cropping. */ | ||
63 | +#if TRANSFORMS_SUPPORTED | ||
64 | + if (++argn >= argc) /* advance to next argument */ | ||
65 | + usage(); | ||
66 | + if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) { | ||
67 | + fprintf(stderr, "%s: bogus -crop argument '%s'\n", | ||
68 | + progname, argv[argn]); | ||
69 | + exit(EXIT_FAILURE); | ||
70 | + } | ||
71 | +#else | ||
72 | + select_transform(JXFORM_NONE); /* force an error */ | ||
73 | +#endif | ||
74 | + | ||
75 | } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { | ||
76 | /* Enable debug printouts. */ | ||
77 | /* On first -d, print version identification */ | ||
78 | @@ -233,7 +251,12 @@ | ||
79 | usage(); | ||
80 | outfilename = argv[argn]; /* save it away for later use */ | ||
81 | |||
82 | - } else if (keymatch(arg, "progressive", 1)) { | ||
83 | + } else if (keymatch(arg, "perfect", 2)) { | ||
84 | + /* Fail if there is any partial edge MCUs that the transform can't | ||
85 | + * handle. */ | ||
86 | + transformoption.perfect = TRUE; | ||
87 | + | ||
88 | + } else if (keymatch(arg, "progressive", 2)) { | ||
89 | /* Select simple progressive mode. */ | ||
90 | #ifdef C_PROGRESSIVE_SUPPORTED | ||
91 | simple_progressive = TRUE; | ||
92 | @@ -342,8 +365,10 @@ | ||
93 | jvirt_barray_ptr * src_coef_arrays; | ||
94 | jvirt_barray_ptr * dst_coef_arrays; | ||
95 | int file_index; | ||
96 | - FILE * input_file; | ||
97 | - FILE * output_file; | ||
98 | + /* We assume all-in-memory processing and can therefore use only a | ||
99 | + * single file pointer for sequential input and output operation. | ||
100 | + */ | ||
101 | + FILE * fp; | ||
102 | |||
103 | /* On Mac, fetch a command line. */ | ||
104 | #ifdef USE_CCOMMAND | ||
105 | @@ -406,24 +431,13 @@ | ||
106 | |||
107 | /* Open the input file. */ | ||
108 | if (file_index < argc) { | ||
109 | - if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { | ||
110 | - fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); | ||
111 | + if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { | ||
112 | + fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]); | ||
113 | exit(EXIT_FAILURE); | ||
114 | } | ||
115 | } else { | ||
116 | /* default input file is stdin */ | ||
117 | - input_file = read_stdin(); | ||
118 | - } | ||
119 | - | ||
120 | - /* Open the output file. */ | ||
121 | - if (outfilename != NULL) { | ||
122 | - if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { | ||
123 | - fprintf(stderr, "%s: can't open %s\n", progname, outfilename); | ||
124 | - exit(EXIT_FAILURE); | ||
125 | - } | ||
126 | - } else { | ||
127 | - /* default output file is stdout */ | ||
128 | - output_file = write_stdout(); | ||
129 | + fp = read_stdin(); | ||
130 | } | ||
131 | |||
132 | #ifdef PROGRESS_REPORT | ||
133 | @@ -431,7 +445,7 @@ | ||
134 | #endif | ||
135 | |||
136 | /* Specify data source for decompression */ | ||
137 | - jpeg_stdio_src(&srcinfo, input_file); | ||
138 | + jpeg_stdio_src(&srcinfo, fp); | ||
139 | |||
140 | /* Enable saving of extra markers that we want to copy */ | ||
141 | jcopy_markers_setup(&srcinfo, copyoption); | ||
142 | @@ -443,6 +457,15 @@ | ||
143 | * jpeg_read_coefficients so that memory allocation will be done right. | ||
144 | */ | ||
145 | #if TRANSFORMS_SUPPORTED | ||
146 | + /* Fails right away if -perfect is given and transformation is not perfect. | ||
147 | + */ | ||
148 | + if (transformoption.perfect && | ||
149 | + !jtransform_perfect_transform(srcinfo.image_width, srcinfo.image_height, | ||
150 | + srcinfo.max_h_samp_factor * DCTSIZE, srcinfo.max_v_samp_factor * DCTSIZE, | ||
151 | + transformoption.transform)) { | ||
152 | + fprintf(stderr, "%s: transformation is not perfect\n", progname); | ||
153 | + exit(EXIT_FAILURE); | ||
154 | + } | ||
155 | jtransform_request_workspace(&srcinfo, &transformoption); | ||
156 | #endif | ||
157 | |||
158 | @@ -463,11 +486,32 @@ | ||
159 | dst_coef_arrays = src_coef_arrays; | ||
160 | #endif | ||
161 | |||
162 | + /* Close input file, if we opened it. | ||
163 | + * Note: we assume that jpeg_read_coefficients consumed all input | ||
164 | + * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will | ||
165 | + * only consume more while (! cinfo->inputctl->eoi_reached). | ||
166 | + * We cannot call jpeg_finish_decompress here since we still need the | ||
167 | + * virtual arrays allocated from the source object for processing. | ||
168 | + */ | ||
169 | + if (fp != stdin) | ||
170 | + fclose(fp); | ||
171 | + | ||
172 | + /* Open the output file. */ | ||
173 | + if (outfilename != NULL) { | ||
174 | + if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { | ||
175 | + fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename); | ||
176 | + exit(EXIT_FAILURE); | ||
177 | + } | ||
178 | + } else { | ||
179 | + /* default output file is stdout */ | ||
180 | + fp = write_stdout(); | ||
181 | + } | ||
182 | + | ||
183 | /* Adjust default compression parameters by re-parsing the options */ | ||
184 | file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); | ||
185 | |||
186 | /* Specify data destination for compression */ | ||
187 | - jpeg_stdio_dest(&dstinfo, output_file); | ||
188 | + jpeg_stdio_dest(&dstinfo, fp); | ||
189 | |||
190 | /* Start compressor (note no image data is actually written here) */ | ||
191 | jpeg_write_coefficients(&dstinfo, dst_coef_arrays); | ||
192 | @@ -488,11 +532,9 @@ | ||
193 | (void) jpeg_finish_decompress(&srcinfo); | ||
194 | jpeg_destroy_decompress(&srcinfo); | ||
195 | |||
196 | - /* Close files, if we opened them */ | ||
197 | - if (input_file != stdin) | ||
198 | - fclose(input_file); | ||
199 | - if (output_file != stdout) | ||
200 | - fclose(output_file); | ||
201 | + /* Close output file, if we opened it */ | ||
202 | + if (fp != stdout) | ||
203 | + fclose(fp); | ||
204 | |||
205 | #ifdef PROGRESS_REPORT | ||
206 | end_progress_monitor((j_common_ptr) &dstinfo); | ||
207 | diff -urNad /home/bill/debian/libjpeg/libjpeg6b-6b/transupp.c libjpeg6b-6b/transupp.c | ||
208 | --- /home/bill/debian/libjpeg/libjpeg6b-6b/transupp.c 2003-09-22 18:15:49.000000000 +0200 | ||
209 | +++ libjpeg6b-6b/transupp.c 2003-09-22 18:16:28.000000000 +0200 | ||
210 | @@ -1,7 +1,7 @@ | ||
211 | /* | ||
212 | * transupp.c | ||
213 | * | ||
214 | - * Copyright (C) 1997, Thomas G. Lane. | ||
215 | + * Copyright (C) 1997-2001, Thomas G. Lane. | ||
216 | * This file is part of the Independent JPEG Group's software. | ||
217 | * For conditions of distribution and use, see the accompanying README file. | ||
218 | * | ||
219 | @@ -20,6 +20,7 @@ | ||
220 | #include "jinclude.h" | ||
221 | #include "jpeglib.h" | ||
222 | #include "transupp.h" /* My own external interface */ | ||
223 | +#include <ctype.h> /* to declare isdigit() */ | ||
224 | |||
225 | |||
226 | #if TRANSFORMS_SUPPORTED | ||
227 | @@ -28,7 +29,8 @@ | ||
228 | * Lossless image transformation routines. These routines work on DCT | ||
229 | * coefficient arrays and thus do not require any lossy decompression | ||
230 | * or recompression of the image. | ||
231 | - * Thanks to Guido Vollbeding for the initial design and code of this feature. | ||
232 | + * Thanks to Guido Vollbeding for the initial design and code of this feature, | ||
233 | + * and to Ben Jackson for introducing the cropping feature. | ||
234 | * | ||
235 | * Horizontal flipping is done in-place, using a single top-to-bottom | ||
236 | * pass through the virtual source array. It will thus be much the | ||
237 | @@ -42,6 +44,13 @@ | ||
238 | * arrays for most of the transforms. That could result in much thrashing | ||
239 | * if the image is larger than main memory. | ||
240 | * | ||
241 | + * If cropping or trimming is involved, the destination arrays may be smaller | ||
242 | + * than the source arrays. Note it is not possible to do horizontal flip | ||
243 | + * in-place when a nonzero Y crop offset is specified, since we'd have to move | ||
244 | + * data from one block row to another but the virtual array manager doesn't | ||
245 | + * guarantee we can touch more than one row at a time. So in that case, | ||
246 | + * we have to use a separate destination array. | ||
247 | + * | ||
248 | * Some notes about the operating environment of the individual transform | ||
249 | * routines: | ||
250 | * 1. Both the source and destination virtual arrays are allocated from the | ||
251 | @@ -54,20 +63,65 @@ | ||
252 | * and we may as well take that as the effective iMCU size. | ||
253 | * 4. When "trim" is in effect, the destination's dimensions will be the | ||
254 | * trimmed values but the source's will be untrimmed. | ||
255 | - * 5. All the routines assume that the source and destination buffers are | ||
256 | + * 5. When "crop" is in effect, the destination's dimensions will be the | ||
257 | + * cropped values but the source's will be uncropped. Each transform | ||
258 | + * routine is responsible for picking up source data starting at the | ||
259 | + * correct X and Y offset for the crop region. (The X and Y offsets | ||
260 | + * passed to the transform routines are measured in iMCU blocks of the | ||
261 | + * destination.) | ||
262 | + * 6. All the routines assume that the source and destination buffers are | ||
263 | * padded out to a full iMCU boundary. This is true, although for the | ||
264 | * source buffer it is an undocumented property of jdcoefct.c. | ||
265 | - * Notes 2,3,4 boil down to this: generally we should use the destination's | ||
266 | - * dimensions and ignore the source's. | ||
267 | */ | ||
268 | |||
269 | |||
270 | LOCAL(void) | ||
271 | -do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
272 | - jvirt_barray_ptr *src_coef_arrays) | ||
273 | -/* Horizontal flip; done in-place, so no separate dest array is required */ | ||
274 | +do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
275 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
276 | + jvirt_barray_ptr *src_coef_arrays, | ||
277 | + jvirt_barray_ptr *dst_coef_arrays) | ||
278 | +/* Crop. This is only used when no rotate/flip is requested with the crop. */ | ||
279 | { | ||
280 | - JDIMENSION MCU_cols, comp_width, blk_x, blk_y; | ||
281 | + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; | ||
282 | + int ci, offset_y; | ||
283 | + JBLOCKARRAY src_buffer, dst_buffer; | ||
284 | + jpeg_component_info *compptr; | ||
285 | + | ||
286 | + /* We simply have to copy the right amount of data (the destination's | ||
287 | + * image size) starting at the given X and Y offsets in the source. | ||
288 | + */ | ||
289 | + for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
290 | + compptr = dstinfo->comp_info + ci; | ||
291 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
292 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
293 | + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
294 | + dst_blk_y += compptr->v_samp_factor) { | ||
295 | + dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
296 | + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | ||
297 | + (JDIMENSION) compptr->v_samp_factor, TRUE); | ||
298 | + src_buffer = (*srcinfo->mem->access_virt_barray) | ||
299 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
300 | + dst_blk_y + y_crop_blocks, | ||
301 | + (JDIMENSION) compptr->v_samp_factor, FALSE); | ||
302 | + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
303 | + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, | ||
304 | + dst_buffer[offset_y], | ||
305 | + compptr->width_in_blocks); | ||
306 | + } | ||
307 | + } | ||
308 | + } | ||
309 | +} | ||
310 | + | ||
311 | + | ||
312 | +LOCAL(void) | ||
313 | +do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
314 | + JDIMENSION x_crop_offset, | ||
315 | + jvirt_barray_ptr *src_coef_arrays) | ||
316 | +/* Horizontal flip; done in-place, so no separate dest array is required. | ||
317 | + * NB: this only works when y_crop_offset is zero. | ||
318 | + */ | ||
319 | +{ | ||
320 | + JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; | ||
321 | int ci, k, offset_y; | ||
322 | JBLOCKARRAY buffer; | ||
323 | JCOEFPTR ptr1, ptr2; | ||
324 | @@ -79,17 +133,19 @@ | ||
325 | * mirroring by changing the signs of odd-numbered columns. | ||
326 | * Partial iMCUs at the right edge are left untouched. | ||
327 | */ | ||
328 | - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
329 | + MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
330 | |||
331 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
332 | compptr = dstinfo->comp_info + ci; | ||
333 | comp_width = MCU_cols * compptr->h_samp_factor; | ||
334 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
335 | for (blk_y = 0; blk_y < compptr->height_in_blocks; | ||
336 | blk_y += compptr->v_samp_factor) { | ||
337 | buffer = (*srcinfo->mem->access_virt_barray) | ||
338 | ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, | ||
339 | (JDIMENSION) compptr->v_samp_factor, TRUE); | ||
340 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
341 | + /* Do the mirroring */ | ||
342 | for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { | ||
343 | ptr1 = buffer[offset_y][blk_x]; | ||
344 | ptr2 = buffer[offset_y][comp_width - blk_x - 1]; | ||
345 | @@ -105,6 +161,79 @@ | ||
346 | *ptr2++ = -temp1; | ||
347 | } | ||
348 | } | ||
349 | + if (x_crop_blocks > 0) { | ||
350 | + /* Now left-justify the portion of the data to be kept. | ||
351 | + * We can't use a single jcopy_block_row() call because that routine | ||
352 | + * depends on memcpy(), whose behavior is unspecified for overlapping | ||
353 | + * source and destination areas. Sigh. | ||
354 | + */ | ||
355 | + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { | ||
356 | + jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, | ||
357 | + buffer[offset_y] + blk_x, | ||
358 | + (JDIMENSION) 1); | ||
359 | + } | ||
360 | + } | ||
361 | + } | ||
362 | + } | ||
363 | + } | ||
364 | +} | ||
365 | + | ||
366 | + | ||
367 | +LOCAL(void) | ||
368 | +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
369 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
370 | + jvirt_barray_ptr *src_coef_arrays, | ||
371 | + jvirt_barray_ptr *dst_coef_arrays) | ||
372 | +/* Horizontal flip in general cropping case */ | ||
373 | +{ | ||
374 | + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; | ||
375 | + JDIMENSION x_crop_blocks, y_crop_blocks; | ||
376 | + int ci, k, offset_y; | ||
377 | + JBLOCKARRAY src_buffer, dst_buffer; | ||
378 | + JBLOCKROW src_row_ptr, dst_row_ptr; | ||
379 | + JCOEFPTR src_ptr, dst_ptr; | ||
380 | + jpeg_component_info *compptr; | ||
381 | + | ||
382 | + /* Here we must output into a separate array because we can't touch | ||
383 | + * different rows of a single virtual array simultaneously. Otherwise, | ||
384 | + * this is essentially the same as the routine above. | ||
385 | + */ | ||
386 | + MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
387 | + | ||
388 | + for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
389 | + compptr = dstinfo->comp_info + ci; | ||
390 | + comp_width = MCU_cols * compptr->h_samp_factor; | ||
391 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
392 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
393 | + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
394 | + dst_blk_y += compptr->v_samp_factor) { | ||
395 | + dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
396 | + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | ||
397 | + (JDIMENSION) compptr->v_samp_factor, TRUE); | ||
398 | + src_buffer = (*srcinfo->mem->access_virt_barray) | ||
399 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
400 | + dst_blk_y + y_crop_blocks, | ||
401 | + (JDIMENSION) compptr->v_samp_factor, FALSE); | ||
402 | + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
403 | + dst_row_ptr = dst_buffer[offset_y]; | ||
404 | + src_row_ptr = src_buffer[offset_y]; | ||
405 | + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | ||
406 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
407 | + /* Do the mirrorable blocks */ | ||
408 | + dst_ptr = dst_row_ptr[dst_blk_x]; | ||
409 | + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; | ||
410 | + /* this unrolled loop doesn't need to know which row it's on... */ | ||
411 | + for (k = 0; k < DCTSIZE2; k += 2) { | ||
412 | + *dst_ptr++ = *src_ptr++; /* copy even column */ | ||
413 | + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ | ||
414 | + } | ||
415 | + } else { | ||
416 | + /* Copy last partial block(s) verbatim */ | ||
417 | + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, | ||
418 | + dst_row_ptr + dst_blk_x, | ||
419 | + (JDIMENSION) 1); | ||
420 | + } | ||
421 | + } | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | @@ -113,11 +242,13 @@ | ||
426 | |||
427 | LOCAL(void) | ||
428 | do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
429 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
430 | jvirt_barray_ptr *src_coef_arrays, | ||
431 | jvirt_barray_ptr *dst_coef_arrays) | ||
432 | /* Vertical flip */ | ||
433 | { | ||
434 | JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; | ||
435 | + JDIMENSION x_crop_blocks, y_crop_blocks; | ||
436 | int ci, i, j, offset_y; | ||
437 | JBLOCKARRAY src_buffer, dst_buffer; | ||
438 | JBLOCKROW src_row_ptr, dst_row_ptr; | ||
439 | @@ -131,33 +262,38 @@ | ||
440 | * of odd-numbered rows. | ||
441 | * Partial iMCUs at the bottom edge are copied verbatim. | ||
442 | */ | ||
443 | - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
444 | + MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
445 | |||
446 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
447 | compptr = dstinfo->comp_info + ci; | ||
448 | comp_height = MCU_rows * compptr->v_samp_factor; | ||
449 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
450 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
451 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
452 | dst_blk_y += compptr->v_samp_factor) { | ||
453 | dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
454 | ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | ||
455 | (JDIMENSION) compptr->v_samp_factor, TRUE); | ||
456 | - if (dst_blk_y < comp_height) { | ||
457 | + if (y_crop_blocks + dst_blk_y < comp_height) { | ||
458 | /* Row is within the mirrorable area. */ | ||
459 | src_buffer = (*srcinfo->mem->access_virt_barray) | ||
460 | ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
461 | - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, | ||
462 | + comp_height - y_crop_blocks - dst_blk_y - | ||
463 | + (JDIMENSION) compptr->v_samp_factor, | ||
464 | (JDIMENSION) compptr->v_samp_factor, FALSE); | ||
465 | } else { | ||
466 | /* Bottom-edge blocks will be copied verbatim. */ | ||
467 | src_buffer = (*srcinfo->mem->access_virt_barray) | ||
468 | - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, | ||
469 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
470 | + dst_blk_y + y_crop_blocks, | ||
471 | (JDIMENSION) compptr->v_samp_factor, FALSE); | ||
472 | } | ||
473 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
474 | - if (dst_blk_y < comp_height) { | ||
475 | + if (y_crop_blocks + dst_blk_y < comp_height) { | ||
476 | /* Row is within the mirrorable area. */ | ||
477 | dst_row_ptr = dst_buffer[offset_y]; | ||
478 | src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; | ||
479 | + src_row_ptr += x_crop_blocks; | ||
480 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | ||
481 | dst_blk_x++) { | ||
482 | dst_ptr = dst_row_ptr[dst_blk_x]; | ||
483 | @@ -173,7 +309,8 @@ | ||
484 | } | ||
485 | } else { | ||
486 | /* Just copy row verbatim. */ | ||
487 | - jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], | ||
488 | + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, | ||
489 | + dst_buffer[offset_y], | ||
490 | compptr->width_in_blocks); | ||
491 | } | ||
492 | } | ||
493 | @@ -184,11 +321,12 @@ | ||
494 | |||
495 | LOCAL(void) | ||
496 | do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
497 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
498 | jvirt_barray_ptr *src_coef_arrays, | ||
499 | jvirt_barray_ptr *dst_coef_arrays) | ||
500 | /* Transpose source into destination */ | ||
501 | { | ||
502 | - JDIMENSION dst_blk_x, dst_blk_y; | ||
503 | + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; | ||
504 | int ci, i, j, offset_x, offset_y; | ||
505 | JBLOCKARRAY src_buffer, dst_buffer; | ||
506 | JCOEFPTR src_ptr, dst_ptr; | ||
507 | @@ -201,6 +339,8 @@ | ||
508 | */ | ||
509 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
510 | compptr = dstinfo->comp_info + ci; | ||
511 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
512 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
513 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
514 | dst_blk_y += compptr->v_samp_factor) { | ||
515 | dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
516 | @@ -210,11 +350,12 @@ | ||
517 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | ||
518 | dst_blk_x += compptr->h_samp_factor) { | ||
519 | src_buffer = (*srcinfo->mem->access_virt_barray) | ||
520 | - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, | ||
521 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
522 | + dst_blk_x + x_crop_blocks, | ||
523 | (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
524 | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | ||
525 | - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; | ||
526 | dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
527 | + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; | ||
528 | for (i = 0; i < DCTSIZE; i++) | ||
529 | for (j = 0; j < DCTSIZE; j++) | ||
530 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
531 | @@ -228,6 +369,7 @@ | ||
532 | |||
533 | LOCAL(void) | ||
534 | do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
535 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
536 | jvirt_barray_ptr *src_coef_arrays, | ||
537 | jvirt_barray_ptr *dst_coef_arrays) | ||
538 | /* 90 degree rotation is equivalent to | ||
539 | @@ -237,6 +379,7 @@ | ||
540 | */ | ||
541 | { | ||
542 | JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; | ||
543 | + JDIMENSION x_crop_blocks, y_crop_blocks; | ||
544 | int ci, i, j, offset_x, offset_y; | ||
545 | JBLOCKARRAY src_buffer, dst_buffer; | ||
546 | JCOEFPTR src_ptr, dst_ptr; | ||
547 | @@ -246,11 +389,13 @@ | ||
548 | * at the (output) right edge properly. They just get transposed and | ||
549 | * not mirrored. | ||
550 | */ | ||
551 | - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
552 | + MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
553 | |||
554 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
555 | compptr = dstinfo->comp_info + ci; | ||
556 | comp_width = MCU_cols * compptr->h_samp_factor; | ||
557 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
558 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
559 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
560 | dst_blk_y += compptr->v_samp_factor) { | ||
561 | dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
562 | @@ -259,15 +404,26 @@ | ||
563 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
564 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | ||
565 | dst_blk_x += compptr->h_samp_factor) { | ||
566 | - src_buffer = (*srcinfo->mem->access_virt_barray) | ||
567 | - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, | ||
568 | - (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
569 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
570 | + /* Block is within the mirrorable area. */ | ||
571 | + src_buffer = (*srcinfo->mem->access_virt_barray) | ||
572 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
573 | + comp_width - x_crop_blocks - dst_blk_x - | ||
574 | + (JDIMENSION) compptr->h_samp_factor, | ||
575 | + (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
576 | + } else { | ||
577 | + /* Edge blocks are transposed but not mirrored. */ | ||
578 | + src_buffer = (*srcinfo->mem->access_virt_barray) | ||
579 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
580 | + dst_blk_x + x_crop_blocks, | ||
581 | + (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
582 | + } | ||
583 | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | ||
584 | - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; | ||
585 | - if (dst_blk_x < comp_width) { | ||
586 | + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
587 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
588 | /* Block is within the mirrorable area. */ | ||
589 | - dst_ptr = dst_buffer[offset_y] | ||
590 | - [comp_width - dst_blk_x - offset_x - 1]; | ||
591 | + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] | ||
592 | + [dst_blk_y + offset_y + y_crop_blocks]; | ||
593 | for (i = 0; i < DCTSIZE; i++) { | ||
594 | for (j = 0; j < DCTSIZE; j++) | ||
595 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
596 | @@ -277,7 +433,8 @@ | ||
597 | } | ||
598 | } else { | ||
599 | /* Edge blocks are transposed but not mirrored. */ | ||
600 | - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
601 | + src_ptr = src_buffer[offset_x] | ||
602 | + [dst_blk_y + offset_y + y_crop_blocks]; | ||
603 | for (i = 0; i < DCTSIZE; i++) | ||
604 | for (j = 0; j < DCTSIZE; j++) | ||
605 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
606 | @@ -292,6 +449,7 @@ | ||
607 | |||
608 | LOCAL(void) | ||
609 | do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
610 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
611 | jvirt_barray_ptr *src_coef_arrays, | ||
612 | jvirt_barray_ptr *dst_coef_arrays) | ||
613 | /* 270 degree rotation is equivalent to | ||
614 | @@ -301,6 +459,7 @@ | ||
615 | */ | ||
616 | { | ||
617 | JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; | ||
618 | + JDIMENSION x_crop_blocks, y_crop_blocks; | ||
619 | int ci, i, j, offset_x, offset_y; | ||
620 | JBLOCKARRAY src_buffer, dst_buffer; | ||
621 | JCOEFPTR src_ptr, dst_ptr; | ||
622 | @@ -310,11 +469,13 @@ | ||
623 | * at the (output) bottom edge properly. They just get transposed and | ||
624 | * not mirrored. | ||
625 | */ | ||
626 | - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
627 | + MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
628 | |||
629 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
630 | compptr = dstinfo->comp_info + ci; | ||
631 | comp_height = MCU_rows * compptr->v_samp_factor; | ||
632 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
633 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
634 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
635 | dst_blk_y += compptr->v_samp_factor) { | ||
636 | dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
637 | @@ -324,14 +485,15 @@ | ||
638 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | ||
639 | dst_blk_x += compptr->h_samp_factor) { | ||
640 | src_buffer = (*srcinfo->mem->access_virt_barray) | ||
641 | - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, | ||
642 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
643 | + dst_blk_x + x_crop_blocks, | ||
644 | (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
645 | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | ||
646 | dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
647 | - if (dst_blk_y < comp_height) { | ||
648 | + if (y_crop_blocks + dst_blk_y < comp_height) { | ||
649 | /* Block is within the mirrorable area. */ | ||
650 | src_ptr = src_buffer[offset_x] | ||
651 | - [comp_height - dst_blk_y - offset_y - 1]; | ||
652 | + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; | ||
653 | for (i = 0; i < DCTSIZE; i++) { | ||
654 | for (j = 0; j < DCTSIZE; j++) { | ||
655 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
656 | @@ -341,7 +503,8 @@ | ||
657 | } | ||
658 | } else { | ||
659 | /* Edge blocks are transposed but not mirrored. */ | ||
660 | - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; | ||
661 | + src_ptr = src_buffer[offset_x] | ||
662 | + [dst_blk_y + offset_y + y_crop_blocks]; | ||
663 | for (i = 0; i < DCTSIZE; i++) | ||
664 | for (j = 0; j < DCTSIZE; j++) | ||
665 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
666 | @@ -356,6 +519,7 @@ | ||
667 | |||
668 | LOCAL(void) | ||
669 | do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
670 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
671 | jvirt_barray_ptr *src_coef_arrays, | ||
672 | jvirt_barray_ptr *dst_coef_arrays) | ||
673 | /* 180 degree rotation is equivalent to | ||
674 | @@ -365,89 +529,93 @@ | ||
675 | */ | ||
676 | { | ||
677 | JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; | ||
678 | + JDIMENSION x_crop_blocks, y_crop_blocks; | ||
679 | int ci, i, j, offset_y; | ||
680 | JBLOCKARRAY src_buffer, dst_buffer; | ||
681 | JBLOCKROW src_row_ptr, dst_row_ptr; | ||
682 | JCOEFPTR src_ptr, dst_ptr; | ||
683 | jpeg_component_info *compptr; | ||
684 | |||
685 | - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
686 | - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
687 | + MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
688 | + MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
689 | |||
690 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
691 | compptr = dstinfo->comp_info + ci; | ||
692 | comp_width = MCU_cols * compptr->h_samp_factor; | ||
693 | comp_height = MCU_rows * compptr->v_samp_factor; | ||
694 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
695 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
696 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
697 | dst_blk_y += compptr->v_samp_factor) { | ||
698 | dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
699 | ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | ||
700 | (JDIMENSION) compptr->v_samp_factor, TRUE); | ||
701 | - if (dst_blk_y < comp_height) { | ||
702 | + if (y_crop_blocks + dst_blk_y < comp_height) { | ||
703 | /* Row is within the vertically mirrorable area. */ | ||
704 | src_buffer = (*srcinfo->mem->access_virt_barray) | ||
705 | ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
706 | - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, | ||
707 | + comp_height - y_crop_blocks - dst_blk_y - | ||
708 | + (JDIMENSION) compptr->v_samp_factor, | ||
709 | (JDIMENSION) compptr->v_samp_factor, FALSE); | ||
710 | } else { | ||
711 | /* Bottom-edge rows are only mirrored horizontally. */ | ||
712 | src_buffer = (*srcinfo->mem->access_virt_barray) | ||
713 | - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, | ||
714 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
715 | + dst_blk_y + y_crop_blocks, | ||
716 | (JDIMENSION) compptr->v_samp_factor, FALSE); | ||
717 | } | ||
718 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
719 | - if (dst_blk_y < comp_height) { | ||
720 | + dst_row_ptr = dst_buffer[offset_y]; | ||
721 | + if (y_crop_blocks + dst_blk_y < comp_height) { | ||
722 | /* Row is within the mirrorable area. */ | ||
723 | - dst_row_ptr = dst_buffer[offset_y]; | ||
724 | src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; | ||
725 | - /* Process the blocks that can be mirrored both ways. */ | ||
726 | - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { | ||
727 | + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | ||
728 | dst_ptr = dst_row_ptr[dst_blk_x]; | ||
729 | - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; | ||
730 | - for (i = 0; i < DCTSIZE; i += 2) { | ||
731 | - /* For even row, negate every odd column. */ | ||
732 | - for (j = 0; j < DCTSIZE; j += 2) { | ||
733 | - *dst_ptr++ = *src_ptr++; | ||
734 | - *dst_ptr++ = - *src_ptr++; | ||
735 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
736 | + /* Process the blocks that can be mirrored both ways. */ | ||
737 | + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; | ||
738 | + for (i = 0; i < DCTSIZE; i += 2) { | ||
739 | + /* For even row, negate every odd column. */ | ||
740 | + for (j = 0; j < DCTSIZE; j += 2) { | ||
741 | + *dst_ptr++ = *src_ptr++; | ||
742 | + *dst_ptr++ = - *src_ptr++; | ||
743 | + } | ||
744 | + /* For odd row, negate every even column. */ | ||
745 | + for (j = 0; j < DCTSIZE; j += 2) { | ||
746 | + *dst_ptr++ = - *src_ptr++; | ||
747 | + *dst_ptr++ = *src_ptr++; | ||
748 | + } | ||
749 | } | ||
750 | - /* For odd row, negate every even column. */ | ||
751 | - for (j = 0; j < DCTSIZE; j += 2) { | ||
752 | - *dst_ptr++ = - *src_ptr++; | ||
753 | - *dst_ptr++ = *src_ptr++; | ||
754 | + } else { | ||
755 | + /* Any remaining right-edge blocks are only mirrored vertically. */ | ||
756 | + src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; | ||
757 | + for (i = 0; i < DCTSIZE; i += 2) { | ||
758 | + for (j = 0; j < DCTSIZE; j++) | ||
759 | + *dst_ptr++ = *src_ptr++; | ||
760 | + for (j = 0; j < DCTSIZE; j++) | ||
761 | + *dst_ptr++ = - *src_ptr++; | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | - /* Any remaining right-edge blocks are only mirrored vertically. */ | ||
766 | - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | ||
767 | - dst_ptr = dst_row_ptr[dst_blk_x]; | ||
768 | - src_ptr = src_row_ptr[dst_blk_x]; | ||
769 | - for (i = 0; i < DCTSIZE; i += 2) { | ||
770 | - for (j = 0; j < DCTSIZE; j++) | ||
771 | - *dst_ptr++ = *src_ptr++; | ||
772 | - for (j = 0; j < DCTSIZE; j++) | ||
773 | - *dst_ptr++ = - *src_ptr++; | ||
774 | - } | ||
775 | - } | ||
776 | } else { | ||
777 | /* Remaining rows are just mirrored horizontally. */ | ||
778 | - dst_row_ptr = dst_buffer[offset_y]; | ||
779 | src_row_ptr = src_buffer[offset_y]; | ||
780 | - /* Process the blocks that can be mirrored. */ | ||
781 | - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { | ||
782 | - dst_ptr = dst_row_ptr[dst_blk_x]; | ||
783 | - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; | ||
784 | - for (i = 0; i < DCTSIZE2; i += 2) { | ||
785 | - *dst_ptr++ = *src_ptr++; | ||
786 | - *dst_ptr++ = - *src_ptr++; | ||
787 | + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | ||
788 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
789 | + /* Process the blocks that can be mirrored. */ | ||
790 | + dst_ptr = dst_row_ptr[dst_blk_x]; | ||
791 | + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; | ||
792 | + for (i = 0; i < DCTSIZE2; i += 2) { | ||
793 | + *dst_ptr++ = *src_ptr++; | ||
794 | + *dst_ptr++ = - *src_ptr++; | ||
795 | + } | ||
796 | + } else { | ||
797 | + /* Any remaining right-edge blocks are only copied. */ | ||
798 | + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, | ||
799 | + dst_row_ptr + dst_blk_x, | ||
800 | + (JDIMENSION) 1); | ||
801 | } | ||
802 | } | ||
803 | - /* Any remaining right-edge blocks are only copied. */ | ||
804 | - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | ||
805 | - dst_ptr = dst_row_ptr[dst_blk_x]; | ||
806 | - src_ptr = src_row_ptr[dst_blk_x]; | ||
807 | - for (i = 0; i < DCTSIZE2; i++) | ||
808 | - *dst_ptr++ = *src_ptr++; | ||
809 | - } | ||
810 | } | ||
811 | } | ||
812 | } | ||
813 | @@ -457,6 +625,7 @@ | ||
814 | |||
815 | LOCAL(void) | ||
816 | do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
817 | + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | ||
818 | jvirt_barray_ptr *src_coef_arrays, | ||
819 | jvirt_barray_ptr *dst_coef_arrays) | ||
820 | /* Transverse transpose is equivalent to | ||
821 | @@ -470,18 +639,21 @@ | ||
822 | */ | ||
823 | { | ||
824 | JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; | ||
825 | + JDIMENSION x_crop_blocks, y_crop_blocks; | ||
826 | int ci, i, j, offset_x, offset_y; | ||
827 | JBLOCKARRAY src_buffer, dst_buffer; | ||
828 | JCOEFPTR src_ptr, dst_ptr; | ||
829 | jpeg_component_info *compptr; | ||
830 | |||
831 | - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
832 | - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
833 | + MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); | ||
834 | + MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); | ||
835 | |||
836 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
837 | compptr = dstinfo->comp_info + ci; | ||
838 | comp_width = MCU_cols * compptr->h_samp_factor; | ||
839 | comp_height = MCU_rows * compptr->v_samp_factor; | ||
840 | + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | ||
841 | + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | ||
842 | for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | ||
843 | dst_blk_y += compptr->v_samp_factor) { | ||
844 | dst_buffer = (*srcinfo->mem->access_virt_barray) | ||
845 | @@ -490,17 +662,26 @@ | ||
846 | for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | ||
847 | for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | ||
848 | dst_blk_x += compptr->h_samp_factor) { | ||
849 | - src_buffer = (*srcinfo->mem->access_virt_barray) | ||
850 | - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, | ||
851 | - (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
852 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
853 | + /* Block is within the mirrorable area. */ | ||
854 | + src_buffer = (*srcinfo->mem->access_virt_barray) | ||
855 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
856 | + comp_width - x_crop_blocks - dst_blk_x - | ||
857 | + (JDIMENSION) compptr->h_samp_factor, | ||
858 | + (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
859 | + } else { | ||
860 | + src_buffer = (*srcinfo->mem->access_virt_barray) | ||
861 | + ((j_common_ptr) srcinfo, src_coef_arrays[ci], | ||
862 | + dst_blk_x + x_crop_blocks, | ||
863 | + (JDIMENSION) compptr->h_samp_factor, FALSE); | ||
864 | + } | ||
865 | for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | ||
866 | - if (dst_blk_y < comp_height) { | ||
867 | - src_ptr = src_buffer[offset_x] | ||
868 | - [comp_height - dst_blk_y - offset_y - 1]; | ||
869 | - if (dst_blk_x < comp_width) { | ||
870 | + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
871 | + if (y_crop_blocks + dst_blk_y < comp_height) { | ||
872 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
873 | /* Block is within the mirrorable area. */ | ||
874 | - dst_ptr = dst_buffer[offset_y] | ||
875 | - [comp_width - dst_blk_x - offset_x - 1]; | ||
876 | + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] | ||
877 | + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; | ||
878 | for (i = 0; i < DCTSIZE; i++) { | ||
879 | for (j = 0; j < DCTSIZE; j++) { | ||
880 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
881 | @@ -516,7 +697,8 @@ | ||
882 | } | ||
883 | } else { | ||
884 | /* Right-edge blocks are mirrored in y only */ | ||
885 | - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
886 | + src_ptr = src_buffer[offset_x] | ||
887 | + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; | ||
888 | for (i = 0; i < DCTSIZE; i++) { | ||
889 | for (j = 0; j < DCTSIZE; j++) { | ||
890 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
891 | @@ -526,11 +708,10 @@ | ||
892 | } | ||
893 | } | ||
894 | } else { | ||
895 | - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; | ||
896 | - if (dst_blk_x < comp_width) { | ||
897 | + if (x_crop_blocks + dst_blk_x < comp_width) { | ||
898 | /* Bottom-edge blocks are mirrored in x only */ | ||
899 | - dst_ptr = dst_buffer[offset_y] | ||
900 | - [comp_width - dst_blk_x - offset_x - 1]; | ||
901 | + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] | ||
902 | + [dst_blk_y + offset_y + y_crop_blocks]; | ||
903 | for (i = 0; i < DCTSIZE; i++) { | ||
904 | for (j = 0; j < DCTSIZE; j++) | ||
905 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
906 | @@ -540,7 +721,8 @@ | ||
907 | } | ||
908 | } else { | ||
909 | /* At lower right corner, just transpose, no mirroring */ | ||
910 | - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | ||
911 | + src_ptr = src_buffer[offset_x] | ||
912 | + [dst_blk_y + offset_y + y_crop_blocks]; | ||
913 | for (i = 0; i < DCTSIZE; i++) | ||
914 | for (j = 0; j < DCTSIZE; j++) | ||
915 | dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | ||
916 | @@ -554,8 +736,116 @@ | ||
917 | } | ||
918 | |||
919 | |||
920 | +/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. | ||
921 | + * Returns TRUE if valid integer found, FALSE if not. | ||
922 | + * *strptr is advanced over the digit string, and *result is set to its value. | ||
923 | + */ | ||
924 | + | ||
925 | +LOCAL(boolean) | ||
926 | +jt_read_integer (const char ** strptr, JDIMENSION * result) | ||
927 | +{ | ||
928 | + const char * ptr = *strptr; | ||
929 | + JDIMENSION val = 0; | ||
930 | + | ||
931 | + for (; isdigit(*ptr); ptr++) { | ||
932 | + val = val * 10 + (JDIMENSION) (*ptr - '0'); | ||
933 | + } | ||
934 | + *result = val; | ||
935 | + if (ptr == *strptr) | ||
936 | + return FALSE; /* oops, no digits */ | ||
937 | + *strptr = ptr; | ||
938 | + return TRUE; | ||
939 | +} | ||
940 | + | ||
941 | + | ||
942 | +/* Parse a crop specification (written in X11 geometry style). | ||
943 | + * The routine returns TRUE if the spec string is valid, FALSE if not. | ||
944 | + * | ||
945 | + * The crop spec string should have the format | ||
946 | + * <width>x<height>{+-}<xoffset>{+-}<yoffset> | ||
947 | + * where width, height, xoffset, and yoffset are unsigned integers. | ||
948 | + * Each of the elements can be omitted to indicate a default value. | ||
949 | + * (A weakness of this style is that it is not possible to omit xoffset | ||
950 | + * while specifying yoffset, since they look alike.) | ||
951 | + * | ||
952 | + * This code is loosely based on XParseGeometry from the X11 distribution. | ||
953 | + */ | ||
954 | + | ||
955 | +GLOBAL(boolean) | ||
956 | +jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) | ||
957 | +{ | ||
958 | + info->crop = FALSE; | ||
959 | + info->crop_width_set = JCROP_UNSET; | ||
960 | + info->crop_height_set = JCROP_UNSET; | ||
961 | + info->crop_xoffset_set = JCROP_UNSET; | ||
962 | + info->crop_yoffset_set = JCROP_UNSET; | ||
963 | + | ||
964 | + if (isdigit(*spec)) { | ||
965 | + /* fetch width */ | ||
966 | + if (! jt_read_integer(&spec, &info->crop_width)) | ||
967 | + return FALSE; | ||
968 | + info->crop_width_set = JCROP_POS; | ||
969 | + } | ||
970 | + if (*spec == 'x' || *spec == 'X') { | ||
971 | + /* fetch height */ | ||
972 | + spec++; | ||
973 | + if (! jt_read_integer(&spec, &info->crop_height)) | ||
974 | + return FALSE; | ||
975 | + info->crop_height_set = JCROP_POS; | ||
976 | + } | ||
977 | + if (*spec == '+' || *spec == '-') { | ||
978 | + /* fetch xoffset */ | ||
979 | + info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; | ||
980 | + spec++; | ||
981 | + if (! jt_read_integer(&spec, &info->crop_xoffset)) | ||
982 | + return FALSE; | ||
983 | + } | ||
984 | + if (*spec == '+' || *spec == '-') { | ||
985 | + /* fetch yoffset */ | ||
986 | + info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; | ||
987 | + spec++; | ||
988 | + if (! jt_read_integer(&spec, &info->crop_yoffset)) | ||
989 | + return FALSE; | ||
990 | + } | ||
991 | + /* We had better have gotten to the end of the string. */ | ||
992 | + if (*spec != '\0') | ||
993 | + return FALSE; | ||
994 | + info->crop = TRUE; | ||
995 | + return TRUE; | ||
996 | +} | ||
997 | + | ||
998 | + | ||
999 | +/* Trim off any partial iMCUs on the indicated destination edge */ | ||
1000 | + | ||
1001 | +LOCAL(void) | ||
1002 | +trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) | ||
1003 | +{ | ||
1004 | + JDIMENSION MCU_cols; | ||
1005 | + | ||
1006 | + MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE); | ||
1007 | + if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == | ||
1008 | + full_width / (info->max_h_samp_factor * DCTSIZE)) | ||
1009 | + info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE); | ||
1010 | +} | ||
1011 | + | ||
1012 | +LOCAL(void) | ||
1013 | +trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) | ||
1014 | +{ | ||
1015 | + JDIMENSION MCU_rows; | ||
1016 | + | ||
1017 | + MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE); | ||
1018 | + if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == | ||
1019 | + full_height / (info->max_v_samp_factor * DCTSIZE)) | ||
1020 | + info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE); | ||
1021 | +} | ||
1022 | + | ||
1023 | + | ||
1024 | /* Request any required workspace. | ||
1025 | * | ||
1026 | + * This routine figures out the size that the output image will be | ||
1027 | + * (which implies that all the transform parameters must be set before | ||
1028 | + * it is called). | ||
1029 | + * | ||
1030 | * We allocate the workspace virtual arrays from the source decompression | ||
1031 | * object, so that all the arrays (both the original data and the workspace) | ||
1032 | * will be taken into account while making memory management decisions. | ||
1033 | @@ -569,9 +859,13 @@ | ||
1034 | jpeg_transform_info *info) | ||
1035 | { | ||
1036 | jvirt_barray_ptr *coef_arrays = NULL; | ||
1037 | + boolean need_workspace, transpose_it; | ||
1038 | jpeg_component_info *compptr; | ||
1039 | - int ci; | ||
1040 | + JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs; | ||
1041 | + JDIMENSION width_in_blocks, height_in_blocks; | ||
1042 | + int ci, h_samp_factor, v_samp_factor; | ||
1043 | |||
1044 | + /* Determine number of components in output image */ | ||
1045 | if (info->force_grayscale && | ||
1046 | srcinfo->jpeg_color_space == JCS_YCbCr && | ||
1047 | srcinfo->num_components == 3) { | ||
1048 | @@ -581,55 +875,181 @@ | ||
1049 | /* Process all the components */ | ||
1050 | info->num_components = srcinfo->num_components; | ||
1051 | } | ||
1052 | + /* If there is only one output component, force the iMCU size to be 1; | ||
1053 | + * else use the source iMCU size. (This allows us to do the right thing | ||
1054 | + * when reducing color to grayscale, and also provides a handy way of | ||
1055 | + * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) | ||
1056 | + */ | ||
1057 | |||
1058 | switch (info->transform) { | ||
1059 | + case JXFORM_TRANSPOSE: | ||
1060 | + case JXFORM_TRANSVERSE: | ||
1061 | + case JXFORM_ROT_90: | ||
1062 | + case JXFORM_ROT_270: | ||
1063 | + info->output_width = srcinfo->image_height; | ||
1064 | + info->output_height = srcinfo->image_width; | ||
1065 | + if (info->num_components == 1) { | ||
1066 | + info->max_h_samp_factor = 1; | ||
1067 | + info->max_v_samp_factor = 1; | ||
1068 | + } else { | ||
1069 | + info->max_h_samp_factor = srcinfo->max_v_samp_factor; | ||
1070 | + info->max_v_samp_factor = srcinfo->max_h_samp_factor; | ||
1071 | + } | ||
1072 | + break; | ||
1073 | + default: | ||
1074 | + info->output_width = srcinfo->image_width; | ||
1075 | + info->output_height = srcinfo->image_height; | ||
1076 | + if (info->num_components == 1) { | ||
1077 | + info->max_h_samp_factor = 1; | ||
1078 | + info->max_v_samp_factor = 1; | ||
1079 | + } else { | ||
1080 | + info->max_h_samp_factor = srcinfo->max_h_samp_factor; | ||
1081 | + info->max_v_samp_factor = srcinfo->max_v_samp_factor; | ||
1082 | + } | ||
1083 | + break; | ||
1084 | + } | ||
1085 | + | ||
1086 | + /* If cropping has been requested, compute the crop area's position and | ||
1087 | + * dimensions, ensuring that its upper left corner falls at an iMCU boundary. | ||
1088 | + */ | ||
1089 | + if (info->crop) { | ||
1090 | + /* Insert default values for unset crop parameters */ | ||
1091 | + if (info->crop_xoffset_set == JCROP_UNSET) | ||
1092 | + info->crop_xoffset = 0; /* default to +0 */ | ||
1093 | + if (info->crop_yoffset_set == JCROP_UNSET) | ||
1094 | + info->crop_yoffset = 0; /* default to +0 */ | ||
1095 | + if (info->crop_xoffset >= info->output_width || | ||
1096 | + info->crop_yoffset >= info->output_height) | ||
1097 | + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | ||
1098 | + if (info->crop_width_set == JCROP_UNSET) | ||
1099 | + info->crop_width = info->output_width - info->crop_xoffset; | ||
1100 | + if (info->crop_height_set == JCROP_UNSET) | ||
1101 | + info->crop_height = info->output_height - info->crop_yoffset; | ||
1102 | + /* Ensure parameters are valid */ | ||
1103 | + if (info->crop_width <= 0 || info->crop_width > info->output_width || | ||
1104 | + info->crop_height <= 0 || info->crop_height > info->output_height || | ||
1105 | + info->crop_xoffset > info->output_width - info->crop_width || | ||
1106 | + info->crop_yoffset > info->output_height - info->crop_height) | ||
1107 | + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | ||
1108 | + /* Convert negative crop offsets into regular offsets */ | ||
1109 | + if (info->crop_xoffset_set == JCROP_NEG) | ||
1110 | + xoffset = info->output_width - info->crop_width - info->crop_xoffset; | ||
1111 | + else | ||
1112 | + xoffset = info->crop_xoffset; | ||
1113 | + if (info->crop_yoffset_set == JCROP_NEG) | ||
1114 | + yoffset = info->output_height - info->crop_height - info->crop_yoffset; | ||
1115 | + else | ||
1116 | + yoffset = info->crop_yoffset; | ||
1117 | + /* Now adjust so that upper left corner falls at an iMCU boundary */ | ||
1118 | + info->output_width = | ||
1119 | + info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE)); | ||
1120 | + info->output_height = | ||
1121 | + info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE)); | ||
1122 | + /* Save x/y offsets measured in iMCUs */ | ||
1123 | + info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE); | ||
1124 | + info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE); | ||
1125 | + } else { | ||
1126 | + info->x_crop_offset = 0; | ||
1127 | + info->y_crop_offset = 0; | ||
1128 | + } | ||
1129 | + | ||
1130 | + /* Figure out whether we need workspace arrays, | ||
1131 | + * and if so whether they are transposed relative to the source. | ||
1132 | + */ | ||
1133 | + need_workspace = FALSE; | ||
1134 | + transpose_it = FALSE; | ||
1135 | + switch (info->transform) { | ||
1136 | case JXFORM_NONE: | ||
1137 | + if (info->x_crop_offset != 0 || info->y_crop_offset != 0) | ||
1138 | + need_workspace = TRUE; | ||
1139 | + /* No workspace needed if neither cropping nor transforming */ | ||
1140 | + break; | ||
1141 | case JXFORM_FLIP_H: | ||
1142 | - /* Don't need a workspace array */ | ||
1143 | + if (info->trim) | ||
1144 | + trim_right_edge(info, srcinfo->image_width); | ||
1145 | + if (info->y_crop_offset != 0) | ||
1146 | + need_workspace = TRUE; | ||
1147 | + /* do_flip_h_no_crop doesn't need a workspace array */ | ||
1148 | break; | ||
1149 | case JXFORM_FLIP_V: | ||
1150 | - case JXFORM_ROT_180: | ||
1151 | - /* Need workspace arrays having same dimensions as source image. | ||
1152 | - * Note that we allocate arrays padded out to the next iMCU boundary, | ||
1153 | - * so that transform routines need not worry about missing edge blocks. | ||
1154 | - */ | ||
1155 | - coef_arrays = (jvirt_barray_ptr *) | ||
1156 | - (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, | ||
1157 | - SIZEOF(jvirt_barray_ptr) * info->num_components); | ||
1158 | - for (ci = 0; ci < info->num_components; ci++) { | ||
1159 | - compptr = srcinfo->comp_info + ci; | ||
1160 | - coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) | ||
1161 | - ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, | ||
1162 | - (JDIMENSION) jround_up((long) compptr->width_in_blocks, | ||
1163 | - (long) compptr->h_samp_factor), | ||
1164 | - (JDIMENSION) jround_up((long) compptr->height_in_blocks, | ||
1165 | - (long) compptr->v_samp_factor), | ||
1166 | - (JDIMENSION) compptr->v_samp_factor); | ||
1167 | - } | ||
1168 | + if (info->trim) | ||
1169 | + trim_bottom_edge(info, srcinfo->image_height); | ||
1170 | + /* Need workspace arrays having same dimensions as source image. */ | ||
1171 | + need_workspace = TRUE; | ||
1172 | break; | ||
1173 | case JXFORM_TRANSPOSE: | ||
1174 | + /* transpose does NOT have to trim anything */ | ||
1175 | + /* Need workspace arrays having transposed dimensions. */ | ||
1176 | + need_workspace = TRUE; | ||
1177 | + transpose_it = TRUE; | ||
1178 | + break; | ||
1179 | case JXFORM_TRANSVERSE: | ||
1180 | + if (info->trim) { | ||
1181 | + trim_right_edge(info, srcinfo->image_height); | ||
1182 | + trim_bottom_edge(info, srcinfo->image_width); | ||
1183 | + } | ||
1184 | + /* Need workspace arrays having transposed dimensions. */ | ||
1185 | + need_workspace = TRUE; | ||
1186 | + transpose_it = TRUE; | ||
1187 | + break; | ||
1188 | case JXFORM_ROT_90: | ||
1189 | + if (info->trim) | ||
1190 | + trim_right_edge(info, srcinfo->image_height); | ||
1191 | + /* Need workspace arrays having transposed dimensions. */ | ||
1192 | + need_workspace = TRUE; | ||
1193 | + transpose_it = TRUE; | ||
1194 | + break; | ||
1195 | + case JXFORM_ROT_180: | ||
1196 | + if (info->trim) { | ||
1197 | + trim_right_edge(info, srcinfo->image_width); | ||
1198 | + trim_bottom_edge(info, srcinfo->image_height); | ||
1199 | + } | ||
1200 | + /* Need workspace arrays having same dimensions as source image. */ | ||
1201 | + need_workspace = TRUE; | ||
1202 | + break; | ||
1203 | case JXFORM_ROT_270: | ||
1204 | - /* Need workspace arrays having transposed dimensions. | ||
1205 | - * Note that we allocate arrays padded out to the next iMCU boundary, | ||
1206 | - * so that transform routines need not worry about missing edge blocks. | ||
1207 | - */ | ||
1208 | + if (info->trim) | ||
1209 | + trim_bottom_edge(info, srcinfo->image_width); | ||
1210 | + /* Need workspace arrays having transposed dimensions. */ | ||
1211 | + need_workspace = TRUE; | ||
1212 | + transpose_it = TRUE; | ||
1213 | + break; | ||
1214 | + } | ||
1215 | + | ||
1216 | + /* Allocate workspace if needed. | ||
1217 | + * Note that we allocate arrays padded out to the next iMCU boundary, | ||
1218 | + * so that transform routines need not worry about missing edge blocks. | ||
1219 | + */ | ||
1220 | + if (need_workspace) { | ||
1221 | coef_arrays = (jvirt_barray_ptr *) | ||
1222 | (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, | ||
1223 | - SIZEOF(jvirt_barray_ptr) * info->num_components); | ||
1224 | + SIZEOF(jvirt_barray_ptr) * info->num_components); | ||
1225 | + width_in_iMCUs = (JDIMENSION) | ||
1226 | + jdiv_round_up((long) info->output_width, | ||
1227 | + (long) (info->max_h_samp_factor * DCTSIZE)); | ||
1228 | + height_in_iMCUs = (JDIMENSION) | ||
1229 | + jdiv_round_up((long) info->output_height, | ||
1230 | + (long) (info->max_v_samp_factor * DCTSIZE)); | ||
1231 | for (ci = 0; ci < info->num_components; ci++) { | ||
1232 | compptr = srcinfo->comp_info + ci; | ||
1233 | + if (info->num_components == 1) { | ||
1234 | + /* we're going to force samp factors to 1x1 in this case */ | ||
1235 | + h_samp_factor = v_samp_factor = 1; | ||
1236 | + } else if (transpose_it) { | ||
1237 | + h_samp_factor = compptr->v_samp_factor; | ||
1238 | + v_samp_factor = compptr->h_samp_factor; | ||
1239 | + } else { | ||
1240 | + h_samp_factor = compptr->h_samp_factor; | ||
1241 | + v_samp_factor = compptr->v_samp_factor; | ||
1242 | + } | ||
1243 | + width_in_blocks = width_in_iMCUs * h_samp_factor; | ||
1244 | + height_in_blocks = height_in_iMCUs * v_samp_factor; | ||
1245 | coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) | ||
1246 | ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, | ||
1247 | - (JDIMENSION) jround_up((long) compptr->height_in_blocks, | ||
1248 | - (long) compptr->v_samp_factor), | ||
1249 | - (JDIMENSION) jround_up((long) compptr->width_in_blocks, | ||
1250 | - (long) compptr->h_samp_factor), | ||
1251 | - (JDIMENSION) compptr->h_samp_factor); | ||
1252 | + width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); | ||
1253 | } | ||
1254 | - break; | ||
1255 | } | ||
1256 | + | ||
1257 | info->workspace_coef_arrays = coef_arrays; | ||
1258 | } | ||
1259 | |||
1260 | @@ -642,14 +1062,8 @@ | ||
1261 | int tblno, i, j, ci, itemp; | ||
1262 | jpeg_component_info *compptr; | ||
1263 | JQUANT_TBL *qtblptr; | ||
1264 | - JDIMENSION dtemp; | ||
1265 | UINT16 qtemp; | ||
1266 | |||
1267 | - /* Transpose basic image dimensions */ | ||
1268 | - dtemp = dstinfo->image_width; | ||
1269 | - dstinfo->image_width = dstinfo->image_height; | ||
1270 | - dstinfo->image_height = dtemp; | ||
1271 | - | ||
1272 | /* Transpose sampling factors */ | ||
1273 | for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
1274 | compptr = dstinfo->comp_info + ci; | ||
1275 | @@ -674,46 +1088,159 @@ | ||
1276 | } | ||
1277 | |||
1278 | |||
1279 | -/* Trim off any partial iMCUs on the indicated destination edge */ | ||
1280 | +/* Adjust Exif image parameters. | ||
1281 | + * | ||
1282 | + * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. | ||
1283 | + */ | ||
1284 | |||
1285 | LOCAL(void) | ||
1286 | -trim_right_edge (j_compress_ptr dstinfo) | ||
1287 | +adjust_exif_parameters (JOCTET FAR * data, unsigned int length, | ||
1288 | + JDIMENSION new_width, JDIMENSION new_height) | ||
1289 | { | ||
1290 | - int ci, max_h_samp_factor; | ||
1291 | - JDIMENSION MCU_cols; | ||
1292 | + boolean is_motorola; /* Flag for byte order */ | ||
1293 | + unsigned int number_of_tags, tagnum; | ||
1294 | + unsigned int firstoffset, offset; | ||
1295 | + JDIMENSION new_value; | ||
1296 | |||
1297 | - /* We have to compute max_h_samp_factor ourselves, | ||
1298 | - * because it hasn't been set yet in the destination | ||
1299 | - * (and we don't want to use the source's value). | ||
1300 | - */ | ||
1301 | - max_h_samp_factor = 1; | ||
1302 | - for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
1303 | - int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; | ||
1304 | - max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); | ||
1305 | + if (length < 12) return; /* Length of an IFD entry */ | ||
1306 | + | ||
1307 | + /* Discover byte order */ | ||
1308 | + if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) | ||
1309 | + is_motorola = FALSE; | ||
1310 | + else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) | ||
1311 | + is_motorola = TRUE; | ||
1312 | + else | ||
1313 | + return; | ||
1314 | + | ||
1315 | + /* Check Tag Mark */ | ||
1316 | + if (is_motorola) { | ||
1317 | + if (GETJOCTET(data[2]) != 0) return; | ||
1318 | + if (GETJOCTET(data[3]) != 0x2A) return; | ||
1319 | + } else { | ||
1320 | + if (GETJOCTET(data[3]) != 0) return; | ||
1321 | + if (GETJOCTET(data[2]) != 0x2A) return; | ||
1322 | } | ||
1323 | - MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); | ||
1324 | - if (MCU_cols > 0) /* can't trim to 0 pixels */ | ||
1325 | - dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); | ||
1326 | -} | ||
1327 | |||
1328 | -LOCAL(void) | ||
1329 | -trim_bottom_edge (j_compress_ptr dstinfo) | ||
1330 | -{ | ||
1331 | - int ci, max_v_samp_factor; | ||
1332 | - JDIMENSION MCU_rows; | ||
1333 | + /* Get first IFD offset (offset to IFD0) */ | ||
1334 | + if (is_motorola) { | ||
1335 | + if (GETJOCTET(data[4]) != 0) return; | ||
1336 | + if (GETJOCTET(data[5]) != 0) return; | ||
1337 | + firstoffset = GETJOCTET(data[6]); | ||
1338 | + firstoffset <<= 8; | ||
1339 | + firstoffset += GETJOCTET(data[7]); | ||
1340 | + } else { | ||
1341 | + if (GETJOCTET(data[7]) != 0) return; | ||
1342 | + if (GETJOCTET(data[6]) != 0) return; | ||
1343 | + firstoffset = GETJOCTET(data[5]); | ||
1344 | + firstoffset <<= 8; | ||
1345 | + firstoffset += GETJOCTET(data[4]); | ||
1346 | + } | ||
1347 | + if (firstoffset > length - 2) return; /* check end of data segment */ | ||
1348 | |||
1349 | - /* We have to compute max_v_samp_factor ourselves, | ||
1350 | - * because it hasn't been set yet in the destination | ||
1351 | - * (and we don't want to use the source's value). | ||
1352 | - */ | ||
1353 | - max_v_samp_factor = 1; | ||
1354 | - for (ci = 0; ci < dstinfo->num_components; ci++) { | ||
1355 | - int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; | ||
1356 | - max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); | ||
1357 | + /* Get the number of directory entries contained in this IFD */ | ||
1358 | + if (is_motorola) { | ||
1359 | + number_of_tags = GETJOCTET(data[firstoffset]); | ||
1360 | + number_of_tags <<= 8; | ||
1361 | + number_of_tags += GETJOCTET(data[firstoffset+1]); | ||
1362 | + } else { | ||
1363 | + number_of_tags = GETJOCTET(data[firstoffset+1]); | ||
1364 | + number_of_tags <<= 8; | ||
1365 | + number_of_tags += GETJOCTET(data[firstoffset]); | ||
1366 | } | ||
1367 | - MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); | ||
1368 | - if (MCU_rows > 0) /* can't trim to 0 pixels */ | ||
1369 | - dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); | ||
1370 | + if (number_of_tags == 0) return; | ||
1371 | + firstoffset += 2; | ||
1372 | + | ||
1373 | + /* Search for ExifSubIFD offset Tag in IFD0 */ | ||
1374 | + for (;;) { | ||
1375 | + if (firstoffset > length - 12) return; /* check end of data segment */ | ||
1376 | + /* Get Tag number */ | ||
1377 | + if (is_motorola) { | ||
1378 | + tagnum = GETJOCTET(data[firstoffset]); | ||
1379 | + tagnum <<= 8; | ||
1380 | + tagnum += GETJOCTET(data[firstoffset+1]); | ||
1381 | + } else { | ||
1382 | + tagnum = GETJOCTET(data[firstoffset+1]); | ||
1383 | + tagnum <<= 8; | ||
1384 | + tagnum += GETJOCTET(data[firstoffset]); | ||
1385 | + } | ||
1386 | + if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ | ||
1387 | + if (--number_of_tags == 0) return; | ||
1388 | + firstoffset += 12; | ||
1389 | + } | ||
1390 | + | ||
1391 | + /* Get the ExifSubIFD offset */ | ||
1392 | + if (is_motorola) { | ||
1393 | + if (GETJOCTET(data[firstoffset+8]) != 0) return; | ||
1394 | + if (GETJOCTET(data[firstoffset+9]) != 0) return; | ||
1395 | + offset = GETJOCTET(data[firstoffset+10]); | ||
1396 | + offset <<= 8; | ||
1397 | + offset += GETJOCTET(data[firstoffset+11]); | ||
1398 | + } else { | ||
1399 | + if (GETJOCTET(data[firstoffset+11]) != 0) return; | ||
1400 | + if (GETJOCTET(data[firstoffset+10]) != 0) return; | ||
1401 | + offset = GETJOCTET(data[firstoffset+9]); | ||
1402 | + offset <<= 8; | ||
1403 | + offset += GETJOCTET(data[firstoffset+8]); | ||
1404 | + } | ||
1405 | + if (offset > length - 2) return; /* check end of data segment */ | ||
1406 | + | ||
1407 | + /* Get the number of directory entries contained in this SubIFD */ | ||
1408 | + if (is_motorola) { | ||
1409 | + number_of_tags = GETJOCTET(data[offset]); | ||
1410 | + number_of_tags <<= 8; | ||
1411 | + number_of_tags += GETJOCTET(data[offset+1]); | ||
1412 | + } else { | ||
1413 | + number_of_tags = GETJOCTET(data[offset+1]); | ||
1414 | + number_of_tags <<= 8; | ||
1415 | + number_of_tags += GETJOCTET(data[offset]); | ||
1416 | + } | ||
1417 | + if (number_of_tags < 2) return; | ||
1418 | + offset += 2; | ||
1419 | + | ||
1420 | + /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ | ||
1421 | + do { | ||
1422 | + if (offset > length - 12) return; /* check end of data segment */ | ||
1423 | + /* Get Tag number */ | ||
1424 | + if (is_motorola) { | ||
1425 | + tagnum = GETJOCTET(data[offset]); | ||
1426 | + tagnum <<= 8; | ||
1427 | + tagnum += GETJOCTET(data[offset+1]); | ||
1428 | + } else { | ||
1429 | + tagnum = GETJOCTET(data[offset+1]); | ||
1430 | + tagnum <<= 8; | ||
1431 | + tagnum += GETJOCTET(data[offset]); | ||
1432 | + } | ||
1433 | + if (tagnum == 0xA002 || tagnum == 0xA003) { | ||
1434 | + if (tagnum == 0xA002) | ||
1435 | + new_value = new_width; /* ExifImageWidth Tag */ | ||
1436 | + else | ||
1437 | + new_value = new_height; /* ExifImageHeight Tag */ | ||
1438 | + if (is_motorola) { | ||
1439 | + data[offset+2] = 0; /* Format = unsigned long (4 octets) */ | ||
1440 | + data[offset+3] = 4; | ||
1441 | + data[offset+4] = 0; /* Number Of Components = 1 */ | ||
1442 | + data[offset+5] = 0; | ||
1443 | + data[offset+6] = 0; | ||
1444 | + data[offset+7] = 1; | ||
1445 | + data[offset+8] = 0; | ||
1446 | + data[offset+9] = 0; | ||
1447 | + data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); | ||
1448 | + data[offset+11] = (JOCTET)(new_value & 0xFF); | ||
1449 | + } else { | ||
1450 | + data[offset+2] = 4; /* Format = unsigned long (4 octets) */ | ||
1451 | + data[offset+3] = 0; | ||
1452 | + data[offset+4] = 1; /* Number Of Components = 1 */ | ||
1453 | + data[offset+5] = 0; | ||
1454 | + data[offset+6] = 0; | ||
1455 | + data[offset+7] = 0; | ||
1456 | + data[offset+8] = (JOCTET)(new_value & 0xFF); | ||
1457 | + data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); | ||
1458 | + data[offset+10] = 0; | ||
1459 | + data[offset+11] = 0; | ||
1460 | + } | ||
1461 | + } | ||
1462 | + offset += 12; | ||
1463 | + } while (--number_of_tags); | ||
1464 | } | ||
1465 | |||
1466 | |||
1467 | @@ -736,18 +1263,22 @@ | ||
1468 | { | ||
1469 | /* If force-to-grayscale is requested, adjust destination parameters */ | ||
1470 | if (info->force_grayscale) { | ||
1471 | - /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed | ||
1472 | - * properly. Among other things, the target h_samp_factor & v_samp_factor | ||
1473 | - * will get set to 1, which typically won't match the source. | ||
1474 | - * In fact we do this even if the source is already grayscale; that | ||
1475 | - * provides an easy way of coercing a grayscale JPEG with funny sampling | ||
1476 | - * factors to the customary 1,1. (Some decoders fail on other factors.) | ||
1477 | + /* First, ensure we have YCbCr or grayscale data, and that the source's | ||
1478 | + * Y channel is full resolution. (No reasonable person would make Y | ||
1479 | + * be less than full resolution, so actually coping with that case | ||
1480 | + * isn't worth extra code space. But we check it to avoid crashing.) | ||
1481 | */ | ||
1482 | - if ((dstinfo->jpeg_color_space == JCS_YCbCr && | ||
1483 | - dstinfo->num_components == 3) || | ||
1484 | - (dstinfo->jpeg_color_space == JCS_GRAYSCALE && | ||
1485 | - dstinfo->num_components == 1)) { | ||
1486 | - /* We have to preserve the source's quantization table number. */ | ||
1487 | + if (((dstinfo->jpeg_color_space == JCS_YCbCr && | ||
1488 | + dstinfo->num_components == 3) || | ||
1489 | + (dstinfo->jpeg_color_space == JCS_GRAYSCALE && | ||
1490 | + dstinfo->num_components == 1)) && | ||
1491 | + srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && | ||
1492 | + srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { | ||
1493 | + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed | ||
1494 | + * properly. Among other things, it sets the target h_samp_factor & | ||
1495 | + * v_samp_factor to 1, which typically won't match the source. | ||
1496 | + * We have to preserve the source's quantization table number, however. | ||
1497 | + */ | ||
1498 | int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; | ||
1499 | jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); | ||
1500 | dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; | ||
1501 | @@ -755,50 +1286,52 @@ | ||
1502 | /* Sorry, can't do it */ | ||
1503 | ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); | ||
1504 | } | ||
1505 | + } else if (info->num_components == 1) { | ||
1506 | + /* For a single-component source, we force the destination sampling factors | ||
1507 | + * to 1x1, with or without force_grayscale. This is useful because some | ||
1508 | + * decoders choke on grayscale images with other sampling factors. | ||
1509 | + */ | ||
1510 | + dstinfo->comp_info[0].h_samp_factor = 1; | ||
1511 | + dstinfo->comp_info[0].v_samp_factor = 1; | ||
1512 | } | ||
1513 | |||
1514 | - /* Correct the destination's image dimensions etc if necessary */ | ||
1515 | + /* Correct the destination's image dimensions as necessary | ||
1516 | + * for crop and rotate/flip operations. | ||
1517 | + */ | ||
1518 | + dstinfo->image_width = info->output_width; | ||
1519 | + dstinfo->image_height = info->output_height; | ||
1520 | + | ||
1521 | + /* Transpose destination image parameters */ | ||
1522 | switch (info->transform) { | ||
1523 | - case JXFORM_NONE: | ||
1524 | - /* Nothing to do */ | ||
1525 | - break; | ||
1526 | - case JXFORM_FLIP_H: | ||
1527 | - if (info->trim) | ||
1528 | - trim_right_edge(dstinfo); | ||
1529 | - break; | ||
1530 | - case JXFORM_FLIP_V: | ||
1531 | - if (info->trim) | ||
1532 | - trim_bottom_edge(dstinfo); | ||
1533 | - break; | ||
1534 | case JXFORM_TRANSPOSE: | ||
1535 | - transpose_critical_parameters(dstinfo); | ||
1536 | - /* transpose does NOT have to trim anything */ | ||
1537 | - break; | ||
1538 | case JXFORM_TRANSVERSE: | ||
1539 | - transpose_critical_parameters(dstinfo); | ||
1540 | - if (info->trim) { | ||
1541 | - trim_right_edge(dstinfo); | ||
1542 | - trim_bottom_edge(dstinfo); | ||
1543 | - } | ||
1544 | - break; | ||
1545 | case JXFORM_ROT_90: | ||
1546 | - transpose_critical_parameters(dstinfo); | ||
1547 | - if (info->trim) | ||
1548 | - trim_right_edge(dstinfo); | ||
1549 | - break; | ||
1550 | - case JXFORM_ROT_180: | ||
1551 | - if (info->trim) { | ||
1552 | - trim_right_edge(dstinfo); | ||
1553 | - trim_bottom_edge(dstinfo); | ||
1554 | - } | ||
1555 | - break; | ||
1556 | case JXFORM_ROT_270: | ||
1557 | transpose_critical_parameters(dstinfo); | ||
1558 | - if (info->trim) | ||
1559 | - trim_bottom_edge(dstinfo); | ||
1560 | break; | ||
1561 | } | ||
1562 | |||
1563 | + /* Adjust Exif properties */ | ||
1564 | + if (srcinfo->marker_list != NULL && | ||
1565 | + srcinfo->marker_list->marker == JPEG_APP0+1 && | ||
1566 | + srcinfo->marker_list->data_length >= 6 && | ||
1567 | + GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && | ||
1568 | + GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && | ||
1569 | + GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && | ||
1570 | + GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && | ||
1571 | + GETJOCTET(srcinfo->marker_list->data[4]) == 0 && | ||
1572 | + GETJOCTET(srcinfo->marker_list->data[5]) == 0) { | ||
1573 | + /* Suppress output of JFIF marker */ | ||
1574 | + dstinfo->write_JFIF_header = FALSE; | ||
1575 | + /* Adjust Exif image parameters */ | ||
1576 | + if (dstinfo->image_width != srcinfo->image_width || | ||
1577 | + dstinfo->image_height != srcinfo->image_height) | ||
1578 | + /* Align data segment to start of TIFF structure for parsing */ | ||
1579 | + adjust_exif_parameters(srcinfo->marker_list->data + 6, | ||
1580 | + srcinfo->marker_list->data_length - 6, | ||
1581 | + dstinfo->image_width, dstinfo->image_height); | ||
1582 | + } | ||
1583 | + | ||
1584 | /* Return the appropriate output data set */ | ||
1585 | if (info->workspace_coef_arrays != NULL) | ||
1586 | return info->workspace_coef_arrays; | ||
1587 | @@ -816,38 +1349,106 @@ | ||
1588 | */ | ||
1589 | |||
1590 | GLOBAL(void) | ||
1591 | -jtransform_execute_transformation (j_decompress_ptr srcinfo, | ||
1592 | - j_compress_ptr dstinfo, | ||
1593 | - jvirt_barray_ptr *src_coef_arrays, | ||
1594 | - jpeg_transform_info *info) | ||
1595 | +jtransform_execute_transform (j_decompress_ptr srcinfo, | ||
1596 | + j_compress_ptr dstinfo, | ||
1597 | + jvirt_barray_ptr *src_coef_arrays, | ||
1598 | + jpeg_transform_info *info) | ||
1599 | { | ||
1600 | jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; | ||
1601 | |||
1602 | + /* Note: conditions tested here should match those in switch statement | ||
1603 | + * in jtransform_request_workspace() | ||
1604 | + */ | ||
1605 | switch (info->transform) { | ||
1606 | case JXFORM_NONE: | ||
1607 | + if (info->x_crop_offset != 0 || info->y_crop_offset != 0) | ||
1608 | + do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1609 | + src_coef_arrays, dst_coef_arrays); | ||
1610 | break; | ||
1611 | case JXFORM_FLIP_H: | ||
1612 | - do_flip_h(srcinfo, dstinfo, src_coef_arrays); | ||
1613 | + if (info->y_crop_offset != 0) | ||
1614 | + do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1615 | + src_coef_arrays, dst_coef_arrays); | ||
1616 | + else | ||
1617 | + do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, | ||
1618 | + src_coef_arrays); | ||
1619 | break; | ||
1620 | case JXFORM_FLIP_V: | ||
1621 | - do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); | ||
1622 | + do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1623 | + src_coef_arrays, dst_coef_arrays); | ||
1624 | break; | ||
1625 | case JXFORM_TRANSPOSE: | ||
1626 | - do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); | ||
1627 | + do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1628 | + src_coef_arrays, dst_coef_arrays); | ||
1629 | break; | ||
1630 | case JXFORM_TRANSVERSE: | ||
1631 | - do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); | ||
1632 | + do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1633 | + src_coef_arrays, dst_coef_arrays); | ||
1634 | break; | ||
1635 | case JXFORM_ROT_90: | ||
1636 | - do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); | ||
1637 | + do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1638 | + src_coef_arrays, dst_coef_arrays); | ||
1639 | break; | ||
1640 | case JXFORM_ROT_180: | ||
1641 | - do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); | ||
1642 | + do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1643 | + src_coef_arrays, dst_coef_arrays); | ||
1644 | break; | ||
1645 | case JXFORM_ROT_270: | ||
1646 | - do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); | ||
1647 | + do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | ||
1648 | + src_coef_arrays, dst_coef_arrays); | ||
1649 | + break; | ||
1650 | + } | ||
1651 | +} | ||
1652 | + | ||
1653 | +/* jtransform_perfect_transform | ||
1654 | + * | ||
1655 | + * Determine whether lossless transformation is perfectly | ||
1656 | + * possible for a specified image and transformation. | ||
1657 | + * | ||
1658 | + * Inputs: | ||
1659 | + * image_width, image_height: source image dimensions. | ||
1660 | + * MCU_width, MCU_height: pixel dimensions of MCU. | ||
1661 | + * transform: transformation identifier. | ||
1662 | + * Parameter sources from initialized jpeg_struct | ||
1663 | + * (after reading source header): | ||
1664 | + * image_width = cinfo.image_width | ||
1665 | + * image_height = cinfo.image_height | ||
1666 | + * MCU_width = cinfo.max_h_samp_factor * DCTSIZE | ||
1667 | + * MCU_height = cinfo.max_v_samp_factor * DCTSIZE | ||
1668 | + * Result: | ||
1669 | + * TRUE = perfect transformation possible | ||
1670 | + * FALSE = perfect transformation not possible | ||
1671 | + * (may use custom action then) | ||
1672 | + */ | ||
1673 | + | ||
1674 | +GLOBAL(boolean) | ||
1675 | +jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, | ||
1676 | + int MCU_width, int MCU_height, | ||
1677 | + JXFORM_CODE transform) | ||
1678 | +{ | ||
1679 | + boolean result = TRUE; /* initialize TRUE */ | ||
1680 | + | ||
1681 | + switch (transform) { | ||
1682 | + case JXFORM_FLIP_H: | ||
1683 | + case JXFORM_ROT_270: | ||
1684 | + if (image_width % (JDIMENSION) MCU_width) | ||
1685 | + result = FALSE; | ||
1686 | + break; | ||
1687 | + case JXFORM_FLIP_V: | ||
1688 | + case JXFORM_ROT_90: | ||
1689 | + if (image_height % (JDIMENSION) MCU_height) | ||
1690 | + result = FALSE; | ||
1691 | + break; | ||
1692 | + case JXFORM_TRANSVERSE: | ||
1693 | + case JXFORM_ROT_180: | ||
1694 | + if (image_width % (JDIMENSION) MCU_width) | ||
1695 | + result = FALSE; | ||
1696 | + if (image_height % (JDIMENSION) MCU_height) | ||
1697 | + result = FALSE; | ||
1698 | break; | ||
1699 | } | ||
1700 | + | ||
1701 | + return result; | ||
1702 | } | ||
1703 | |||
1704 | #endif /* TRANSFORMS_SUPPORTED */ | ||
1705 | diff -urNad /home/bill/debian/libjpeg/libjpeg6b-6b/transupp.h libjpeg6b-6b/transupp.h | ||
1706 | --- /home/bill/debian/libjpeg/libjpeg6b-6b/transupp.h 2003-09-22 18:15:49.000000000 +0200 | ||
1707 | +++ libjpeg6b-6b/transupp.h 2003-09-22 18:16:16.000000000 +0200 | ||
1708 | @@ -1,7 +1,7 @@ | ||
1709 | /* | ||
1710 | * transupp.h | ||
1711 | * | ||
1712 | - * Copyright (C) 1997, Thomas G. Lane. | ||
1713 | + * Copyright (C) 1997-2001, Thomas G. Lane. | ||
1714 | * This file is part of the Independent JPEG Group's software. | ||
1715 | * For conditions of distribution and use, see the accompanying README file. | ||
1716 | * | ||
1717 | @@ -22,32 +22,6 @@ | ||
1718 | #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ | ||
1719 | #endif | ||
1720 | |||
1721 | -/* Short forms of external names for systems with brain-damaged linkers. */ | ||
1722 | - | ||
1723 | -#ifdef NEED_SHORT_EXTERNAL_NAMES | ||
1724 | -#define jtransform_request_workspace jTrRequest | ||
1725 | -#define jtransform_adjust_parameters jTrAdjust | ||
1726 | -#define jtransform_execute_transformation jTrExec | ||
1727 | -#define jcopy_markers_setup jCMrkSetup | ||
1728 | -#define jcopy_markers_execute jCMrkExec | ||
1729 | -#endif /* NEED_SHORT_EXTERNAL_NAMES */ | ||
1730 | - | ||
1731 | - | ||
1732 | -/* | ||
1733 | - * Codes for supported types of image transformations. | ||
1734 | - */ | ||
1735 | - | ||
1736 | -typedef enum { | ||
1737 | - JXFORM_NONE, /* no transformation */ | ||
1738 | - JXFORM_FLIP_H, /* horizontal flip */ | ||
1739 | - JXFORM_FLIP_V, /* vertical flip */ | ||
1740 | - JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ | ||
1741 | - JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ | ||
1742 | - JXFORM_ROT_90, /* 90-degree clockwise rotation */ | ||
1743 | - JXFORM_ROT_180, /* 180-degree rotation */ | ||
1744 | - JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ | ||
1745 | -} JXFORM_CODE; | ||
1746 | - | ||
1747 | /* | ||
1748 | * Although rotating and flipping data expressed as DCT coefficients is not | ||
1749 | * hard, there is an asymmetry in the JPEG format specification for images | ||
1750 | @@ -75,6 +49,19 @@ | ||
1751 | * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim | ||
1752 | * followed by -rot 180 -trim trims both edges.) | ||
1753 | * | ||
1754 | + * We also offer a lossless-crop option, which discards data outside a given | ||
1755 | + * image region but losslessly preserves what is inside. Like the rotate and | ||
1756 | + * flip transforms, lossless crop is restricted by the JPEG format: the upper | ||
1757 | + * left corner of the selected region must fall on an iMCU boundary. If this | ||
1758 | + * does not hold for the given crop parameters, we silently move the upper left | ||
1759 | + * corner up and/or left to make it so, simultaneously increasing the region | ||
1760 | + * dimensions to keep the lower right crop corner unchanged. (Thus, the | ||
1761 | + * output image covers at least the requested region, but may cover more.) | ||
1762 | + * | ||
1763 | + * If both crop and a rotate/flip transform are requested, the crop is applied | ||
1764 | + * last --- that is, the crop region is specified in terms of the destination | ||
1765 | + * image. | ||
1766 | + * | ||
1767 | * We also offer a "force to grayscale" option, which simply discards the | ||
1768 | * chrominance channels of a YCbCr image. This is lossless in the sense that | ||
1769 | * the luminance channel is preserved exactly. It's not the same kind of | ||
1770 | @@ -83,20 +70,89 @@ | ||
1771 | * be aware of the option to know how many components to work on. | ||
1772 | */ | ||
1773 | |||
1774 | + | ||
1775 | +/* Short forms of external names for systems with brain-damaged linkers. */ | ||
1776 | + | ||
1777 | +#ifdef NEED_SHORT_EXTERNAL_NAMES | ||
1778 | +#define jtransform_parse_crop_spec jTrParCrop | ||
1779 | +#define jtransform_request_workspace jTrRequest | ||
1780 | +#define jtransform_adjust_parameters jTrAdjust | ||
1781 | +#define jtransform_execute_transform jTrExec | ||
1782 | +#define jtransform_perfect_transform jTrPerfect | ||
1783 | +#define jcopy_markers_setup jCMrkSetup | ||
1784 | +#define jcopy_markers_execute jCMrkExec | ||
1785 | +#endif /* NEED_SHORT_EXTERNAL_NAMES */ | ||
1786 | + | ||
1787 | + | ||
1788 | +/* | ||
1789 | + * Codes for supported types of image transformations. | ||
1790 | + */ | ||
1791 | + | ||
1792 | +typedef enum { | ||
1793 | + JXFORM_NONE, /* no transformation */ | ||
1794 | + JXFORM_FLIP_H, /* horizontal flip */ | ||
1795 | + JXFORM_FLIP_V, /* vertical flip */ | ||
1796 | + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ | ||
1797 | + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ | ||
1798 | + JXFORM_ROT_90, /* 90-degree clockwise rotation */ | ||
1799 | + JXFORM_ROT_180, /* 180-degree rotation */ | ||
1800 | + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ | ||
1801 | +} JXFORM_CODE; | ||
1802 | + | ||
1803 | +/* | ||
1804 | + * Codes for crop parameters, which can individually be unspecified, | ||
1805 | + * positive, or negative. (Negative width or height makes no sense, though.) | ||
1806 | + */ | ||
1807 | + | ||
1808 | +typedef enum { | ||
1809 | + JCROP_UNSET, | ||
1810 | + JCROP_POS, | ||
1811 | + JCROP_NEG | ||
1812 | +} JCROP_CODE; | ||
1813 | + | ||
1814 | +/* | ||
1815 | + * Transform parameters struct. | ||
1816 | + * NB: application must not change any elements of this struct after | ||
1817 | + * calling jtransform_request_workspace. | ||
1818 | + */ | ||
1819 | + | ||
1820 | typedef struct { | ||
1821 | /* Options: set by caller */ | ||
1822 | JXFORM_CODE transform; /* image transform operator */ | ||
1823 | + boolean perfect; /* if TRUE, fail if partial MCUs are requested */ | ||
1824 | boolean trim; /* if TRUE, trim partial MCUs as needed */ | ||
1825 | boolean force_grayscale; /* if TRUE, convert color image to grayscale */ | ||
1826 | + boolean crop; /* if TRUE, crop source image */ | ||
1827 | + | ||
1828 | + /* Crop parameters: application need not set these unless crop is TRUE. | ||
1829 | + * These can be filled in by jtransform_parse_crop_spec(). | ||
1830 | + */ | ||
1831 | + JDIMENSION crop_width; /* Width of selected region */ | ||
1832 | + JCROP_CODE crop_width_set; | ||
1833 | + JDIMENSION crop_height; /* Height of selected region */ | ||
1834 | + JCROP_CODE crop_height_set; | ||
1835 | + JDIMENSION crop_xoffset; /* X offset of selected region */ | ||
1836 | + JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ | ||
1837 | + JDIMENSION crop_yoffset; /* Y offset of selected region */ | ||
1838 | + JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ | ||
1839 | |||
1840 | /* Internal workspace: caller should not touch these */ | ||
1841 | int num_components; /* # of components in workspace */ | ||
1842 | jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ | ||
1843 | + JDIMENSION output_width; /* cropped destination dimensions */ | ||
1844 | + JDIMENSION output_height; | ||
1845 | + JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ | ||
1846 | + JDIMENSION y_crop_offset; | ||
1847 | + int max_h_samp_factor; /* destination iMCU size */ | ||
1848 | + int max_v_samp_factor; | ||
1849 | } jpeg_transform_info; | ||
1850 | |||
1851 | |||
1852 | #if TRANSFORMS_SUPPORTED | ||
1853 | |||
1854 | +/* Parse a crop specification (written in X11 geometry style) */ | ||
1855 | +EXTERN(boolean) jtransform_parse_crop_spec | ||
1856 | + JPP((jpeg_transform_info *info, const char *spec)); | ||
1857 | /* Request any required workspace */ | ||
1858 | EXTERN(void) jtransform_request_workspace | ||
1859 | JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); | ||
1860 | @@ -106,10 +162,24 @@ | ||
1861 | jvirt_barray_ptr *src_coef_arrays, | ||
1862 | jpeg_transform_info *info)); | ||
1863 | /* Execute the actual transformation, if any */ | ||
1864 | -EXTERN(void) jtransform_execute_transformation | ||
1865 | +EXTERN(void) jtransform_execute_transform | ||
1866 | JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | ||
1867 | jvirt_barray_ptr *src_coef_arrays, | ||
1868 | jpeg_transform_info *info)); | ||
1869 | +/* Determine whether lossless transformation is perfectly | ||
1870 | + * possible for a specified image and transformation. | ||
1871 | + */ | ||
1872 | +EXTERN(boolean) jtransform_perfect_transform | ||
1873 | + JPP((JDIMENSION image_width, JDIMENSION image_height, | ||
1874 | + int MCU_width, int MCU_height, | ||
1875 | + JXFORM_CODE transform)); | ||
1876 | + | ||
1877 | +/* jtransform_execute_transform used to be called | ||
1878 | + * jtransform_execute_transformation, but some compilers complain about | ||
1879 | + * routine names that long. This macro is here to avoid breaking any | ||
1880 | + * old source code that uses the original name... | ||
1881 | + */ | ||
1882 | +#define jtransform_execute_transformation jtransform_execute_transform | ||
1883 | |||
1884 | #endif /* TRANSFORMS_SUPPORTED */ | ||
1885 |