File indexing completed on 2025-01-19 03:55:53
0001 /* 0002 * transupp.c 0003 * 0004 * SPDX-FileCopyrightText: 1997-2009, Thomas G. Lane, Guido Vollbeding. 0005 * This file is part of the Independent JPEG Group's software. 0006 * For conditions of distribution and use, see the accompanying README file. 0007 * 0008 * This file contains image transformation routines and other utility code 0009 * used by the jpegtran sample application. These are NOT part of the core 0010 * JPEG library. But we keep these routines separate from jpegtran.c to 0011 * ease the task of maintaining jpegtran-like programs that have other user 0012 * interfaces. 0013 */ 0014 0015 /* Although this file really shouldn't have access to the library internals, 0016 * it's helpful to let it call jround_up() and jcopy_block_row(). 0017 */ 0018 #define JPEG_INTERNALS 0019 0020 #include "jinclude.h" 0021 #include "jpeglib.h" 0022 #include "transupp.h" /* My own external interface */ 0023 #include <ctype.h> /* to declare isdigit() */ 0024 0025 0026 #if TRANSFORMS_SUPPORTED 0027 0028 /* 0029 * Lossless image transformation routines. These routines work on DCT 0030 * coefficient arrays and thus do not require any lossy decompression 0031 * or recompression of the image. 0032 * Thanks to Guido Vollbeding for the initial design and code of this feature, 0033 * and to Ben Jackson for introducing the cropping feature. 0034 * 0035 * Horizontal flipping is done in-place, using a single top-to-bottom 0036 * pass through the virtual source array. It will thus be much the 0037 * fastest option for images larger than main memory. 0038 * 0039 * The other routines require a set of destination virtual arrays, so they 0040 * need twice as much memory as jpegtran normally does. The destination 0041 * arrays are always written in normal scan order (top to bottom) because 0042 * the virtual array manager expects this. The source arrays will be scanned 0043 * in the corresponding order, which means multiple passes through the source 0044 * arrays for most of the transforms. That could result in much thrashing 0045 * if the image is larger than main memory. 0046 * 0047 * If cropping or trimming is involved, the destination arrays may be smaller 0048 * than the source arrays. Note it is not possible to do horizontal flip 0049 * in-place when a nonzero Y crop offset is specified, since we'd have to move 0050 * data from one block row to another but the virtual array manager doesn't 0051 * guarantee we can touch more than one row at a time. So in that case, 0052 * we have to use a separate destination array. 0053 * 0054 * Some notes about the operating environment of the individual transform 0055 * routines: 0056 * 1. Both the source and destination virtual arrays are allocated from the 0057 * source JPEG object, and therefore should be manipulated by calling the 0058 * source's memory manager. 0059 * 2. The destination's component count should be used. It may be smaller 0060 * than the source's when forcing to grayscale. 0061 * 3. Likewise the destination's sampling factors should be used. When 0062 * forcing to grayscale the destination's sampling factors will be all 1, 0063 * and we may as well take that as the effective iMCU size. 0064 * 4. When "trim" is in effect, the destination's dimensions will be the 0065 * trimmed values but the source's will be untrimmed. 0066 * 5. When "crop" is in effect, the destination's dimensions will be the 0067 * cropped values but the source's will be uncropped. Each transform 0068 * routine is responsible for picking up source data starting at the 0069 * correct X and Y offset for the crop region. (The X and Y offsets 0070 * passed to the transform routines are measured in iMCU blocks of the 0071 * destination.) 0072 * 6. All the routines assume that the source and destination buffers are 0073 * padded out to a full iMCU boundary. This is true, although for the 0074 * source buffer it is an undocumented property of jdcoefct.c. 0075 */ 0076 0077 0078 LOCAL(void) 0079 do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0080 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0081 jvirt_barray_ptr *src_coef_arrays, 0082 jvirt_barray_ptr *dst_coef_arrays) 0083 /* Crop. This is only used when no rotate/flip is requested with the crop. */ 0084 { 0085 JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; 0086 int ci, offset_y; 0087 JBLOCKARRAY src_buffer, dst_buffer; 0088 jpeg_component_info *compptr; 0089 0090 /* We simply have to copy the right amount of data (the destination's 0091 * image size) starting at the given X and Y offsets in the source. 0092 */ 0093 for (ci = 0; ci < dstinfo->num_components; ci++) { 0094 compptr = dstinfo->comp_info + ci; 0095 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0096 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0097 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0098 dst_blk_y += compptr->v_samp_factor) { 0099 dst_buffer = (*srcinfo->mem->access_virt_barray) 0100 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0101 (JDIMENSION) compptr->v_samp_factor, TRUE); 0102 src_buffer = (*srcinfo->mem->access_virt_barray) 0103 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0104 dst_blk_y + y_crop_blocks, 0105 (JDIMENSION) compptr->v_samp_factor, FALSE); 0106 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0107 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, 0108 dst_buffer[offset_y], 0109 compptr->width_in_blocks); 0110 } 0111 } 0112 } 0113 } 0114 0115 0116 LOCAL(void) 0117 do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0118 JDIMENSION x_crop_offset, 0119 jvirt_barray_ptr *src_coef_arrays) 0120 /* Horizontal flip; done in-place, so no separate dest array is required. 0121 * NB: this only works when y_crop_offset is zero. 0122 */ 0123 { 0124 JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; 0125 int ci, k, offset_y; 0126 JBLOCKARRAY buffer; 0127 JCOEFPTR ptr1, ptr2; 0128 JCOEF temp1, temp2; 0129 jpeg_component_info *compptr; 0130 0131 /* Horizontal mirroring of DCT blocks is accomplished by swapping 0132 * pairs of blocks in-place. Within a DCT block, we perform horizontal 0133 * mirroring by changing the signs of odd-numbered columns. 0134 * Partial iMCUs at the right edge are left untouched. 0135 */ 0136 MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); 0137 0138 for (ci = 0; ci < dstinfo->num_components; ci++) { 0139 compptr = dstinfo->comp_info + ci; 0140 comp_width = MCU_cols * compptr->h_samp_factor; 0141 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0142 for (blk_y = 0; blk_y < compptr->height_in_blocks; 0143 blk_y += compptr->v_samp_factor) { 0144 buffer = (*srcinfo->mem->access_virt_barray) 0145 ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, 0146 (JDIMENSION) compptr->v_samp_factor, TRUE); 0147 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0148 /* Do the mirroring */ 0149 for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { 0150 ptr1 = buffer[offset_y][blk_x]; 0151 ptr2 = buffer[offset_y][comp_width - blk_x - 1]; 0152 /* this unrolled loop doesn't need to know which row it's on... */ 0153 for (k = 0; k < DCTSIZE2; k += 2) { 0154 temp1 = *ptr1; /* swap even column */ 0155 temp2 = *ptr2; 0156 *ptr1++ = temp2; 0157 *ptr2++ = temp1; 0158 temp1 = *ptr1; /* swap odd column with sign change */ 0159 temp2 = *ptr2; 0160 *ptr1++ = -temp2; 0161 *ptr2++ = -temp1; 0162 } 0163 } 0164 if (x_crop_blocks > 0) { 0165 /* Now left-justify the portion of the data to be kept. 0166 * We can't use a single jcopy_block_row() call because that routine 0167 * depends on memcpy(), whose behavior is unspecified for overlapping 0168 * source and destination areas. Sigh. 0169 */ 0170 for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { 0171 jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, 0172 buffer[offset_y] + blk_x, 0173 (JDIMENSION) 1); 0174 } 0175 } 0176 } 0177 } 0178 } 0179 } 0180 0181 0182 LOCAL(void) 0183 do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0184 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0185 jvirt_barray_ptr *src_coef_arrays, 0186 jvirt_barray_ptr *dst_coef_arrays) 0187 /* Horizontal flip in general cropping case */ 0188 { 0189 JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; 0190 JDIMENSION x_crop_blocks, y_crop_blocks; 0191 int ci, k, offset_y; 0192 JBLOCKARRAY src_buffer, dst_buffer; 0193 JBLOCKROW src_row_ptr, dst_row_ptr; 0194 JCOEFPTR src_ptr, dst_ptr; 0195 jpeg_component_info *compptr; 0196 0197 /* Here we must output into a separate array because we can't touch 0198 * different rows of a single virtual array simultaneously. Otherwise, 0199 * this is essentially the same as the routine above. 0200 */ 0201 MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); 0202 0203 for (ci = 0; ci < dstinfo->num_components; ci++) { 0204 compptr = dstinfo->comp_info + ci; 0205 comp_width = MCU_cols * compptr->h_samp_factor; 0206 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0207 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0208 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0209 dst_blk_y += compptr->v_samp_factor) { 0210 dst_buffer = (*srcinfo->mem->access_virt_barray) 0211 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0212 (JDIMENSION) compptr->v_samp_factor, TRUE); 0213 src_buffer = (*srcinfo->mem->access_virt_barray) 0214 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0215 dst_blk_y + y_crop_blocks, 0216 (JDIMENSION) compptr->v_samp_factor, FALSE); 0217 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0218 dst_row_ptr = dst_buffer[offset_y]; 0219 src_row_ptr = src_buffer[offset_y]; 0220 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { 0221 if (x_crop_blocks + dst_blk_x < comp_width) { 0222 /* Do the mirrorable blocks */ 0223 dst_ptr = dst_row_ptr[dst_blk_x]; 0224 src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; 0225 /* this unrolled loop doesn't need to know which row it's on... */ 0226 for (k = 0; k < DCTSIZE2; k += 2) { 0227 *dst_ptr++ = *src_ptr++; /* copy even column */ 0228 *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ 0229 } 0230 } else { 0231 /* Copy last partial block(s) verbatim */ 0232 jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, 0233 dst_row_ptr + dst_blk_x, 0234 (JDIMENSION) 1); 0235 } 0236 } 0237 } 0238 } 0239 } 0240 } 0241 0242 0243 LOCAL(void) 0244 do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0245 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0246 jvirt_barray_ptr *src_coef_arrays, 0247 jvirt_barray_ptr *dst_coef_arrays) 0248 /* Vertical flip */ 0249 { 0250 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; 0251 JDIMENSION x_crop_blocks, y_crop_blocks; 0252 int ci, i, j, offset_y; 0253 JBLOCKARRAY src_buffer, dst_buffer; 0254 JBLOCKROW src_row_ptr, dst_row_ptr; 0255 JCOEFPTR src_ptr, dst_ptr; 0256 jpeg_component_info *compptr; 0257 0258 /* We output into a separate array because we can't touch different 0259 * rows of the source virtual array simultaneously. Otherwise, this 0260 * is a pretty straightforward analog of horizontal flip. 0261 * Within a DCT block, vertical mirroring is done by changing the signs 0262 * of odd-numbered rows. 0263 * Partial iMCUs at the bottom edge are copied verbatim. 0264 */ 0265 MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); 0266 0267 for (ci = 0; ci < dstinfo->num_components; ci++) { 0268 compptr = dstinfo->comp_info + ci; 0269 comp_height = MCU_rows * compptr->v_samp_factor; 0270 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0271 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0272 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0273 dst_blk_y += compptr->v_samp_factor) { 0274 dst_buffer = (*srcinfo->mem->access_virt_barray) 0275 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0276 (JDIMENSION) compptr->v_samp_factor, TRUE); 0277 if (y_crop_blocks + dst_blk_y < comp_height) { 0278 /* Row is within the mirrorable area. */ 0279 src_buffer = (*srcinfo->mem->access_virt_barray) 0280 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0281 comp_height - y_crop_blocks - dst_blk_y - 0282 (JDIMENSION) compptr->v_samp_factor, 0283 (JDIMENSION) compptr->v_samp_factor, FALSE); 0284 } else { 0285 /* Bottom-edge blocks will be copied verbatim. */ 0286 src_buffer = (*srcinfo->mem->access_virt_barray) 0287 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0288 dst_blk_y + y_crop_blocks, 0289 (JDIMENSION) compptr->v_samp_factor, FALSE); 0290 } 0291 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0292 if (y_crop_blocks + dst_blk_y < comp_height) { 0293 /* Row is within the mirrorable area. */ 0294 dst_row_ptr = dst_buffer[offset_y]; 0295 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; 0296 src_row_ptr += x_crop_blocks; 0297 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; 0298 dst_blk_x++) { 0299 dst_ptr = dst_row_ptr[dst_blk_x]; 0300 src_ptr = src_row_ptr[dst_blk_x]; 0301 for (i = 0; i < DCTSIZE; i += 2) { 0302 /* copy even row */ 0303 for (j = 0; j < DCTSIZE; j++) 0304 *dst_ptr++ = *src_ptr++; 0305 /* copy odd row with sign change */ 0306 for (j = 0; j < DCTSIZE; j++) 0307 *dst_ptr++ = - *src_ptr++; 0308 } 0309 } 0310 } else { 0311 /* Just copy row verbatim. */ 0312 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, 0313 dst_buffer[offset_y], 0314 compptr->width_in_blocks); 0315 } 0316 } 0317 } 0318 } 0319 } 0320 0321 0322 LOCAL(void) 0323 do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0324 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0325 jvirt_barray_ptr *src_coef_arrays, 0326 jvirt_barray_ptr *dst_coef_arrays) 0327 /* Transpose source into destination */ 0328 { 0329 JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; 0330 int ci, i, j, offset_x, offset_y; 0331 JBLOCKARRAY src_buffer, dst_buffer; 0332 JCOEFPTR src_ptr, dst_ptr; 0333 jpeg_component_info *compptr; 0334 0335 /* Transposing pixels within a block just requires transposing the 0336 * DCT coefficients. 0337 * Partial iMCUs at the edges require no special treatment; we simply 0338 * process all the available DCT blocks for every component. 0339 */ 0340 for (ci = 0; ci < dstinfo->num_components; ci++) { 0341 compptr = dstinfo->comp_info + ci; 0342 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0343 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0344 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0345 dst_blk_y += compptr->v_samp_factor) { 0346 dst_buffer = (*srcinfo->mem->access_virt_barray) 0347 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0348 (JDIMENSION) compptr->v_samp_factor, TRUE); 0349 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0350 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; 0351 dst_blk_x += compptr->h_samp_factor) { 0352 src_buffer = (*srcinfo->mem->access_virt_barray) 0353 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0354 dst_blk_x + x_crop_blocks, 0355 (JDIMENSION) compptr->h_samp_factor, FALSE); 0356 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { 0357 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; 0358 src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; 0359 for (i = 0; i < DCTSIZE; i++) 0360 for (j = 0; j < DCTSIZE; j++) 0361 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0362 } 0363 } 0364 } 0365 } 0366 } 0367 } 0368 0369 0370 LOCAL(void) 0371 do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0372 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0373 jvirt_barray_ptr *src_coef_arrays, 0374 jvirt_barray_ptr *dst_coef_arrays) 0375 /* 90 degree rotation is equivalent to 0376 * 1. Transposing the image; 0377 * 2. Horizontal mirroring. 0378 * These two steps are merged into a single processing routine. 0379 */ 0380 { 0381 JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; 0382 JDIMENSION x_crop_blocks, y_crop_blocks; 0383 int ci, i, j, offset_x, offset_y; 0384 JBLOCKARRAY src_buffer, dst_buffer; 0385 JCOEFPTR src_ptr, dst_ptr; 0386 jpeg_component_info *compptr; 0387 0388 /* Because of the horizontal mirror step, we can't process partial iMCUs 0389 * at the (output) right edge properly. They just get transposed and 0390 * not mirrored. 0391 */ 0392 MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); 0393 0394 for (ci = 0; ci < dstinfo->num_components; ci++) { 0395 compptr = dstinfo->comp_info + ci; 0396 comp_width = MCU_cols * compptr->h_samp_factor; 0397 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0398 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0399 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0400 dst_blk_y += compptr->v_samp_factor) { 0401 dst_buffer = (*srcinfo->mem->access_virt_barray) 0402 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0403 (JDIMENSION) compptr->v_samp_factor, TRUE); 0404 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0405 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; 0406 dst_blk_x += compptr->h_samp_factor) { 0407 if (x_crop_blocks + dst_blk_x < comp_width) { 0408 /* Block is within the mirrorable area. */ 0409 src_buffer = (*srcinfo->mem->access_virt_barray) 0410 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0411 comp_width - x_crop_blocks - dst_blk_x - 0412 (JDIMENSION) compptr->h_samp_factor, 0413 (JDIMENSION) compptr->h_samp_factor, FALSE); 0414 } else { 0415 /* Edge blocks are transposed but not mirrored. */ 0416 src_buffer = (*srcinfo->mem->access_virt_barray) 0417 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0418 dst_blk_x + x_crop_blocks, 0419 (JDIMENSION) compptr->h_samp_factor, FALSE); 0420 } 0421 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { 0422 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; 0423 if (x_crop_blocks + dst_blk_x < comp_width) { 0424 /* Block is within the mirrorable area. */ 0425 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] 0426 [dst_blk_y + offset_y + y_crop_blocks]; 0427 for (i = 0; i < DCTSIZE; i++) { 0428 for (j = 0; j < DCTSIZE; j++) 0429 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0430 i++; 0431 for (j = 0; j < DCTSIZE; j++) 0432 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; 0433 } 0434 } else { 0435 /* Edge blocks are transposed but not mirrored. */ 0436 src_ptr = src_buffer[offset_x] 0437 [dst_blk_y + offset_y + y_crop_blocks]; 0438 for (i = 0; i < DCTSIZE; i++) 0439 for (j = 0; j < DCTSIZE; j++) 0440 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0441 } 0442 } 0443 } 0444 } 0445 } 0446 } 0447 } 0448 0449 0450 LOCAL(void) 0451 do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0452 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0453 jvirt_barray_ptr *src_coef_arrays, 0454 jvirt_barray_ptr *dst_coef_arrays) 0455 /* 270 degree rotation is equivalent to 0456 * 1. Horizontal mirroring; 0457 * 2. Transposing the image. 0458 * These two steps are merged into a single processing routine. 0459 */ 0460 { 0461 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; 0462 JDIMENSION x_crop_blocks, y_crop_blocks; 0463 int ci, i, j, offset_x, offset_y; 0464 JBLOCKARRAY src_buffer, dst_buffer; 0465 JCOEFPTR src_ptr, dst_ptr; 0466 jpeg_component_info *compptr; 0467 0468 /* Because of the horizontal mirror step, we can't process partial iMCUs 0469 * at the (output) bottom edge properly. They just get transposed and 0470 * not mirrored. 0471 */ 0472 MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); 0473 0474 for (ci = 0; ci < dstinfo->num_components; ci++) { 0475 compptr = dstinfo->comp_info + ci; 0476 comp_height = MCU_rows * compptr->v_samp_factor; 0477 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0478 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0479 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0480 dst_blk_y += compptr->v_samp_factor) { 0481 dst_buffer = (*srcinfo->mem->access_virt_barray) 0482 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0483 (JDIMENSION) compptr->v_samp_factor, TRUE); 0484 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0485 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; 0486 dst_blk_x += compptr->h_samp_factor) { 0487 src_buffer = (*srcinfo->mem->access_virt_barray) 0488 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0489 dst_blk_x + x_crop_blocks, 0490 (JDIMENSION) compptr->h_samp_factor, FALSE); 0491 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { 0492 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; 0493 if (y_crop_blocks + dst_blk_y < comp_height) { 0494 /* Block is within the mirrorable area. */ 0495 src_ptr = src_buffer[offset_x] 0496 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; 0497 for (i = 0; i < DCTSIZE; i++) { 0498 for (j = 0; j < DCTSIZE; j++) { 0499 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0500 j++; 0501 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; 0502 } 0503 } 0504 } else { 0505 /* Edge blocks are transposed but not mirrored. */ 0506 src_ptr = src_buffer[offset_x] 0507 [dst_blk_y + offset_y + y_crop_blocks]; 0508 for (i = 0; i < DCTSIZE; i++) 0509 for (j = 0; j < DCTSIZE; j++) 0510 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0511 } 0512 } 0513 } 0514 } 0515 } 0516 } 0517 } 0518 0519 0520 LOCAL(void) 0521 do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0522 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0523 jvirt_barray_ptr *src_coef_arrays, 0524 jvirt_barray_ptr *dst_coef_arrays) 0525 /* 180 degree rotation is equivalent to 0526 * 1. Vertical mirroring; 0527 * 2. Horizontal mirroring. 0528 * These two steps are merged into a single processing routine. 0529 */ 0530 { 0531 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; 0532 JDIMENSION x_crop_blocks, y_crop_blocks; 0533 int ci, i, j, offset_y; 0534 JBLOCKARRAY src_buffer, dst_buffer; 0535 JBLOCKROW src_row_ptr, dst_row_ptr; 0536 JCOEFPTR src_ptr, dst_ptr; 0537 jpeg_component_info *compptr; 0538 0539 MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); 0540 MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); 0541 0542 for (ci = 0; ci < dstinfo->num_components; ci++) { 0543 compptr = dstinfo->comp_info + ci; 0544 comp_width = MCU_cols * compptr->h_samp_factor; 0545 comp_height = MCU_rows * compptr->v_samp_factor; 0546 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0547 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0548 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0549 dst_blk_y += compptr->v_samp_factor) { 0550 dst_buffer = (*srcinfo->mem->access_virt_barray) 0551 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0552 (JDIMENSION) compptr->v_samp_factor, TRUE); 0553 if (y_crop_blocks + dst_blk_y < comp_height) { 0554 /* Row is within the vertically mirrorable area. */ 0555 src_buffer = (*srcinfo->mem->access_virt_barray) 0556 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0557 comp_height - y_crop_blocks - dst_blk_y - 0558 (JDIMENSION) compptr->v_samp_factor, 0559 (JDIMENSION) compptr->v_samp_factor, FALSE); 0560 } else { 0561 /* Bottom-edge rows are only mirrored horizontally. */ 0562 src_buffer = (*srcinfo->mem->access_virt_barray) 0563 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0564 dst_blk_y + y_crop_blocks, 0565 (JDIMENSION) compptr->v_samp_factor, FALSE); 0566 } 0567 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0568 dst_row_ptr = dst_buffer[offset_y]; 0569 if (y_crop_blocks + dst_blk_y < comp_height) { 0570 /* Row is within the mirrorable area. */ 0571 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; 0572 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { 0573 dst_ptr = dst_row_ptr[dst_blk_x]; 0574 if (x_crop_blocks + dst_blk_x < comp_width) { 0575 /* Process the blocks that can be mirrored both ways. */ 0576 src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; 0577 for (i = 0; i < DCTSIZE; i += 2) { 0578 /* For even row, negate every odd column. */ 0579 for (j = 0; j < DCTSIZE; j += 2) { 0580 *dst_ptr++ = *src_ptr++; 0581 *dst_ptr++ = - *src_ptr++; 0582 } 0583 /* For odd row, negate every even column. */ 0584 for (j = 0; j < DCTSIZE; j += 2) { 0585 *dst_ptr++ = - *src_ptr++; 0586 *dst_ptr++ = *src_ptr++; 0587 } 0588 } 0589 } else { 0590 /* Any remaining right-edge blocks are only mirrored vertically. */ 0591 src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; 0592 for (i = 0; i < DCTSIZE; i += 2) { 0593 for (j = 0; j < DCTSIZE; j++) 0594 *dst_ptr++ = *src_ptr++; 0595 for (j = 0; j < DCTSIZE; j++) 0596 *dst_ptr++ = - *src_ptr++; 0597 } 0598 } 0599 } 0600 } else { 0601 /* Remaining rows are just mirrored horizontally. */ 0602 src_row_ptr = src_buffer[offset_y]; 0603 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { 0604 if (x_crop_blocks + dst_blk_x < comp_width) { 0605 /* Process the blocks that can be mirrored. */ 0606 dst_ptr = dst_row_ptr[dst_blk_x]; 0607 src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; 0608 for (i = 0; i < DCTSIZE2; i += 2) { 0609 *dst_ptr++ = *src_ptr++; 0610 *dst_ptr++ = - *src_ptr++; 0611 } 0612 } else { 0613 /* Any remaining right-edge blocks are only copied. */ 0614 jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, 0615 dst_row_ptr + dst_blk_x, 0616 (JDIMENSION) 1); 0617 } 0618 } 0619 } 0620 } 0621 } 0622 } 0623 } 0624 0625 0626 LOCAL(void) 0627 do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 0628 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, 0629 jvirt_barray_ptr *src_coef_arrays, 0630 jvirt_barray_ptr *dst_coef_arrays) 0631 /* Transverse transpose is equivalent to 0632 * 1. 180 degree rotation; 0633 * 2. Transposition; 0634 * or 0635 * 1. Horizontal mirroring; 0636 * 2. Transposition; 0637 * 3. Horizontal mirroring. 0638 * These steps are merged into a single processing routine. 0639 */ 0640 { 0641 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; 0642 JDIMENSION x_crop_blocks, y_crop_blocks; 0643 int ci, i, j, offset_x, offset_y; 0644 JBLOCKARRAY src_buffer, dst_buffer; 0645 JCOEFPTR src_ptr, dst_ptr; 0646 jpeg_component_info *compptr; 0647 0648 MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); 0649 MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); 0650 0651 for (ci = 0; ci < dstinfo->num_components; ci++) { 0652 compptr = dstinfo->comp_info + ci; 0653 comp_width = MCU_cols * compptr->h_samp_factor; 0654 comp_height = MCU_rows * compptr->v_samp_factor; 0655 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; 0656 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; 0657 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; 0658 dst_blk_y += compptr->v_samp_factor) { 0659 dst_buffer = (*srcinfo->mem->access_virt_barray) 0660 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 0661 (JDIMENSION) compptr->v_samp_factor, TRUE); 0662 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { 0663 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; 0664 dst_blk_x += compptr->h_samp_factor) { 0665 if (x_crop_blocks + dst_blk_x < comp_width) { 0666 /* Block is within the mirrorable area. */ 0667 src_buffer = (*srcinfo->mem->access_virt_barray) 0668 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0669 comp_width - x_crop_blocks - dst_blk_x - 0670 (JDIMENSION) compptr->h_samp_factor, 0671 (JDIMENSION) compptr->h_samp_factor, FALSE); 0672 } else { 0673 src_buffer = (*srcinfo->mem->access_virt_barray) 0674 ((j_common_ptr) srcinfo, src_coef_arrays[ci], 0675 dst_blk_x + x_crop_blocks, 0676 (JDIMENSION) compptr->h_samp_factor, FALSE); 0677 } 0678 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { 0679 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; 0680 if (y_crop_blocks + dst_blk_y < comp_height) { 0681 if (x_crop_blocks + dst_blk_x < comp_width) { 0682 /* Block is within the mirrorable area. */ 0683 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] 0684 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; 0685 for (i = 0; i < DCTSIZE; i++) { 0686 for (j = 0; j < DCTSIZE; j++) { 0687 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0688 j++; 0689 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; 0690 } 0691 i++; 0692 for (j = 0; j < DCTSIZE; j++) { 0693 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; 0694 j++; 0695 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0696 } 0697 } 0698 } else { 0699 /* Right-edge blocks are mirrored in y only */ 0700 src_ptr = src_buffer[offset_x] 0701 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; 0702 for (i = 0; i < DCTSIZE; i++) { 0703 for (j = 0; j < DCTSIZE; j++) { 0704 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0705 j++; 0706 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; 0707 } 0708 } 0709 } 0710 } else { 0711 if (x_crop_blocks + dst_blk_x < comp_width) { 0712 /* Bottom-edge blocks are mirrored in x only */ 0713 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] 0714 [dst_blk_y + offset_y + y_crop_blocks]; 0715 for (i = 0; i < DCTSIZE; i++) { 0716 for (j = 0; j < DCTSIZE; j++) 0717 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0718 i++; 0719 for (j = 0; j < DCTSIZE; j++) 0720 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; 0721 } 0722 } else { 0723 /* At lower right corner, just transpose, no mirroring */ 0724 src_ptr = src_buffer[offset_x] 0725 [dst_blk_y + offset_y + y_crop_blocks]; 0726 for (i = 0; i < DCTSIZE; i++) 0727 for (j = 0; j < DCTSIZE; j++) 0728 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; 0729 } 0730 } 0731 } 0732 } 0733 } 0734 } 0735 } 0736 } 0737 0738 0739 /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. 0740 * Returns TRUE if valid integer found, FALSE if not. 0741 * *strptr is advanced over the digit string, and *result is set to its value. 0742 */ 0743 0744 LOCAL(boolean) 0745 jt_read_integer (const char ** strptr, JDIMENSION * result) 0746 { 0747 const char * ptr = *strptr; 0748 JDIMENSION val = 0; 0749 0750 for (; isdigit(*ptr); ptr++) { 0751 val = val * 10 + (JDIMENSION) (*ptr - '0'); 0752 } 0753 *result = val; 0754 if (ptr == *strptr) 0755 return FALSE; /* oops, no digits */ 0756 *strptr = ptr; 0757 return TRUE; 0758 } 0759 0760 0761 /* Parse a crop specification (written in X11 geometry style). 0762 * The routine returns TRUE if the spec string is valid, FALSE if not. 0763 * 0764 * The crop spec string should have the format 0765 * <width>x<height>{+-}<xoffset>{+-}<yoffset> 0766 * where width, height, xoffset, and yoffset are unsigned integers. 0767 * Each of the elements can be omitted to indicate a default value. 0768 * (A weakness of this style is that it is not possible to omit xoffset 0769 * while specifying yoffset, since they look alike.) 0770 * 0771 * This code is loosely based on XParseGeometry from the X11 distribution. 0772 */ 0773 0774 GLOBAL(boolean) 0775 jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) 0776 { 0777 info->crop = FALSE; 0778 info->crop_width_set = JCROP_UNSET; 0779 info->crop_height_set = JCROP_UNSET; 0780 info->crop_xoffset_set = JCROP_UNSET; 0781 info->crop_yoffset_set = JCROP_UNSET; 0782 0783 if (isdigit(*spec)) { 0784 /* fetch width */ 0785 if (! jt_read_integer(&spec, &info->crop_width)) 0786 return FALSE; 0787 info->crop_width_set = JCROP_POS; 0788 } 0789 if (*spec == 'x' || *spec == 'X') { 0790 /* fetch height */ 0791 spec++; 0792 if (! jt_read_integer(&spec, &info->crop_height)) 0793 return FALSE; 0794 info->crop_height_set = JCROP_POS; 0795 } 0796 if (*spec == '+' || *spec == '-') { 0797 /* fetch xoffset */ 0798 info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; 0799 spec++; 0800 if (! jt_read_integer(&spec, &info->crop_xoffset)) 0801 return FALSE; 0802 } 0803 if (*spec == '+' || *spec == '-') { 0804 /* fetch yoffset */ 0805 info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; 0806 spec++; 0807 if (! jt_read_integer(&spec, &info->crop_yoffset)) 0808 return FALSE; 0809 } 0810 /* We had better have gotten to the end of the string. */ 0811 if (*spec != '\0') 0812 return FALSE; 0813 info->crop = TRUE; 0814 return TRUE; 0815 } 0816 0817 0818 /* Trim off any partial iMCUs on the indicated destination edge */ 0819 0820 LOCAL(void) 0821 trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) 0822 { 0823 JDIMENSION MCU_cols; 0824 0825 MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE); 0826 if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == 0827 full_width / (info->max_h_samp_factor * DCTSIZE)) 0828 info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE); 0829 } 0830 0831 LOCAL(void) 0832 trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) 0833 { 0834 JDIMENSION MCU_rows; 0835 0836 MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE); 0837 if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == 0838 full_height / (info->max_v_samp_factor * DCTSIZE)) 0839 info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE); 0840 } 0841 0842 0843 /* Request any required workspace. 0844 * 0845 * This routine figures out the size that the output image will be 0846 * (which implies that all the transform parameters must be set before 0847 * it is called). 0848 * 0849 * We allocate the workspace virtual arrays from the source decompression 0850 * object, so that all the arrays (both the original data and the workspace) 0851 * will be taken into account while making memory management decisions. 0852 * Hence, this routine must be called after jpeg_read_header (which reads 0853 * the image dimensions) and before jpeg_read_coefficients (which realizes 0854 * the source's virtual arrays). 0855 */ 0856 0857 GLOBAL(void) 0858 jtransform_request_workspace (j_decompress_ptr srcinfo, 0859 jpeg_transform_info *info) 0860 { 0861 jvirt_barray_ptr *coef_arrays = NULL; 0862 boolean need_workspace, transpose_it; 0863 jpeg_component_info *compptr; 0864 JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs; 0865 JDIMENSION width_in_blocks, height_in_blocks; 0866 int ci, h_samp_factor, v_samp_factor; 0867 0868 /* Determine number of components in output image */ 0869 if (info->force_grayscale && 0870 srcinfo->jpeg_color_space == JCS_YCbCr && 0871 srcinfo->num_components == 3) { 0872 /* We'll only process the first component */ 0873 info->num_components = 1; 0874 } else { 0875 /* Process all the components */ 0876 info->num_components = srcinfo->num_components; 0877 } 0878 /* If there is only one output component, force the iMCU size to be 1; 0879 * else use the source iMCU size. (This allows us to do the right thing 0880 * when reducing color to grayscale, and also provides a handy way of 0881 * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) 0882 */ 0883 0884 switch (info->transform) { 0885 case JXFORM_TRANSPOSE: 0886 case JXFORM_TRANSVERSE: 0887 case JXFORM_ROT_90: 0888 case JXFORM_ROT_270: 0889 info->output_width = srcinfo->image_height; 0890 info->output_height = srcinfo->image_width; 0891 if (info->num_components == 1) { 0892 info->max_h_samp_factor = 1; 0893 info->max_v_samp_factor = 1; 0894 } else { 0895 info->max_h_samp_factor = srcinfo->max_v_samp_factor; 0896 info->max_v_samp_factor = srcinfo->max_h_samp_factor; 0897 } 0898 break; 0899 default: 0900 info->output_width = srcinfo->image_width; 0901 info->output_height = srcinfo->image_height; 0902 if (info->num_components == 1) { 0903 info->max_h_samp_factor = 1; 0904 info->max_v_samp_factor = 1; 0905 } else { 0906 info->max_h_samp_factor = srcinfo->max_h_samp_factor; 0907 info->max_v_samp_factor = srcinfo->max_v_samp_factor; 0908 } 0909 break; 0910 } 0911 0912 /* If cropping has been requested, compute the crop area's position and 0913 * dimensions, ensuring that its upper left corner falls at an iMCU boundary. 0914 */ 0915 if (info->crop) { 0916 /* Insert default values for unset crop parameters */ 0917 if (info->crop_xoffset_set == JCROP_UNSET) 0918 info->crop_xoffset = 0; /* default to +0 */ 0919 if (info->crop_yoffset_set == JCROP_UNSET) 0920 info->crop_yoffset = 0; /* default to +0 */ 0921 if (info->crop_xoffset >= info->output_width || 0922 info->crop_yoffset >= info->output_height) 0923 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); 0924 if (info->crop_width_set == JCROP_UNSET) 0925 info->crop_width = info->output_width - info->crop_xoffset; 0926 if (info->crop_height_set == JCROP_UNSET) 0927 info->crop_height = info->output_height - info->crop_yoffset; 0928 /* Ensure parameters are valid */ 0929 if (info->crop_width <= 0 || info->crop_width > info->output_width || 0930 info->crop_height <= 0 || info->crop_height > info->output_height || 0931 info->crop_xoffset > info->output_width - info->crop_width || 0932 info->crop_yoffset > info->output_height - info->crop_height) 0933 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); 0934 /* Convert negative crop offsets into regular offsets */ 0935 if (info->crop_xoffset_set == JCROP_NEG) 0936 xoffset = info->output_width - info->crop_width - info->crop_xoffset; 0937 else 0938 xoffset = info->crop_xoffset; 0939 if (info->crop_yoffset_set == JCROP_NEG) 0940 yoffset = info->output_height - info->crop_height - info->crop_yoffset; 0941 else 0942 yoffset = info->crop_yoffset; 0943 /* Now adjust so that upper left corner falls at an iMCU boundary */ 0944 info->output_width = 0945 info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE)); 0946 info->output_height = 0947 info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE)); 0948 /* Save x/y offsets measured in iMCUs */ 0949 info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE); 0950 info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE); 0951 } else { 0952 info->x_crop_offset = 0; 0953 info->y_crop_offset = 0; 0954 } 0955 0956 /* Figure out whether we need workspace arrays, 0957 * and if so whether they are transposed relative to the source. 0958 */ 0959 need_workspace = FALSE; 0960 transpose_it = FALSE; 0961 switch (info->transform) { 0962 case JXFORM_NONE: 0963 if (info->x_crop_offset != 0 || info->y_crop_offset != 0) 0964 need_workspace = TRUE; 0965 /* No workspace needed if neither cropping nor transforming */ 0966 break; 0967 case JXFORM_FLIP_H: 0968 if (info->trim) 0969 trim_right_edge(info, srcinfo->image_width); 0970 if (info->y_crop_offset != 0) 0971 need_workspace = TRUE; 0972 /* do_flip_h_no_crop doesn't need a workspace array */ 0973 break; 0974 case JXFORM_FLIP_V: 0975 if (info->trim) 0976 trim_bottom_edge(info, srcinfo->image_height); 0977 /* Need workspace arrays having same dimensions as source image. */ 0978 need_workspace = TRUE; 0979 break; 0980 case JXFORM_TRANSPOSE: 0981 /* transpose does NOT have to trim anything */ 0982 /* Need workspace arrays having transposed dimensions. */ 0983 need_workspace = TRUE; 0984 transpose_it = TRUE; 0985 break; 0986 case JXFORM_TRANSVERSE: 0987 if (info->trim) { 0988 trim_right_edge(info, srcinfo->image_height); 0989 trim_bottom_edge(info, srcinfo->image_width); 0990 } 0991 /* Need workspace arrays having transposed dimensions. */ 0992 need_workspace = TRUE; 0993 transpose_it = TRUE; 0994 break; 0995 case JXFORM_ROT_90: 0996 if (info->trim) 0997 trim_right_edge(info, srcinfo->image_height); 0998 /* Need workspace arrays having transposed dimensions. */ 0999 need_workspace = TRUE; 1000 transpose_it = TRUE; 1001 break; 1002 case JXFORM_ROT_180: 1003 if (info->trim) { 1004 trim_right_edge(info, srcinfo->image_width); 1005 trim_bottom_edge(info, srcinfo->image_height); 1006 } 1007 /* Need workspace arrays having same dimensions as source image. */ 1008 need_workspace = TRUE; 1009 break; 1010 case JXFORM_ROT_270: 1011 if (info->trim) 1012 trim_bottom_edge(info, srcinfo->image_width); 1013 /* Need workspace arrays having transposed dimensions. */ 1014 need_workspace = TRUE; 1015 transpose_it = TRUE; 1016 break; 1017 } 1018 1019 /* Allocate workspace if needed. 1020 * Note that we allocate arrays padded out to the next iMCU boundary, 1021 * so that transform routines need not worry about missing edge blocks. 1022 */ 1023 if (need_workspace) { 1024 coef_arrays = (jvirt_barray_ptr *) 1025 (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, 1026 SIZEOF(jvirt_barray_ptr) * info->num_components); 1027 width_in_iMCUs = (JDIMENSION) 1028 jdiv_round_up((long) info->output_width, 1029 (long) (info->max_h_samp_factor * DCTSIZE)); 1030 height_in_iMCUs = (JDIMENSION) 1031 jdiv_round_up((long) info->output_height, 1032 (long) (info->max_v_samp_factor * DCTSIZE)); 1033 for (ci = 0; ci < info->num_components; ci++) { 1034 compptr = srcinfo->comp_info + ci; 1035 if (info->num_components == 1) { 1036 /* we're going to force samp factors to 1x1 in this case */ 1037 h_samp_factor = v_samp_factor = 1; 1038 } else if (transpose_it) { 1039 h_samp_factor = compptr->v_samp_factor; 1040 v_samp_factor = compptr->h_samp_factor; 1041 } else { 1042 h_samp_factor = compptr->h_samp_factor; 1043 v_samp_factor = compptr->v_samp_factor; 1044 } 1045 width_in_blocks = width_in_iMCUs * h_samp_factor; 1046 height_in_blocks = height_in_iMCUs * v_samp_factor; 1047 coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) 1048 ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, 1049 width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); 1050 } 1051 } 1052 1053 info->workspace_coef_arrays = coef_arrays; 1054 } 1055 1056 1057 /* Transpose destination image parameters */ 1058 1059 LOCAL(void) 1060 transpose_critical_parameters (j_compress_ptr dstinfo) 1061 { 1062 int tblno, i, j, ci, itemp; 1063 jpeg_component_info *compptr; 1064 JQUANT_TBL *qtblptr; 1065 UINT16 qtemp; 1066 1067 /* Transpose sampling factors */ 1068 for (ci = 0; ci < dstinfo->num_components; ci++) { 1069 compptr = dstinfo->comp_info + ci; 1070 itemp = compptr->h_samp_factor; 1071 compptr->h_samp_factor = compptr->v_samp_factor; 1072 compptr->v_samp_factor = itemp; 1073 } 1074 1075 /* Transpose quantization tables */ 1076 for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { 1077 qtblptr = dstinfo->quant_tbl_ptrs[tblno]; 1078 if (qtblptr != NULL) { 1079 for (i = 0; i < DCTSIZE; i++) { 1080 for (j = 0; j < i; j++) { 1081 qtemp = qtblptr->quantval[i*DCTSIZE+j]; 1082 qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; 1083 qtblptr->quantval[j*DCTSIZE+i] = qtemp; 1084 } 1085 } 1086 } 1087 } 1088 } 1089 1090 1091 /* Adjust Exif image parameters. 1092 * 1093 * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. 1094 */ 1095 1096 LOCAL(void) 1097 adjust_exif_parameters (JOCTET FAR * data, unsigned int length, 1098 JDIMENSION new_width, JDIMENSION new_height) 1099 { 1100 boolean is_motorola; /* Flag for byte order */ 1101 unsigned int number_of_tags, tagnum; 1102 unsigned int firstoffset, offset; 1103 JDIMENSION new_value; 1104 1105 if (length < 12) return; /* Length of an IFD entry */ 1106 1107 /* Discover byte order */ 1108 if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) 1109 is_motorola = FALSE; 1110 else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) 1111 is_motorola = TRUE; 1112 else 1113 return; 1114 1115 /* Check Tag Mark */ 1116 if (is_motorola) { 1117 if (GETJOCTET(data[2]) != 0) return; 1118 if (GETJOCTET(data[3]) != 0x2A) return; 1119 } else { 1120 if (GETJOCTET(data[3]) != 0) return; 1121 if (GETJOCTET(data[2]) != 0x2A) return; 1122 } 1123 1124 /* Get first IFD offset (offset to IFD0) */ 1125 if (is_motorola) { 1126 if (GETJOCTET(data[4]) != 0) return; 1127 if (GETJOCTET(data[5]) != 0) return; 1128 firstoffset = GETJOCTET(data[6]); 1129 firstoffset <<= 8; 1130 firstoffset += GETJOCTET(data[7]); 1131 } else { 1132 if (GETJOCTET(data[7]) != 0) return; 1133 if (GETJOCTET(data[6]) != 0) return; 1134 firstoffset = GETJOCTET(data[5]); 1135 firstoffset <<= 8; 1136 firstoffset += GETJOCTET(data[4]); 1137 } 1138 if (firstoffset > length - 2) return; /* check end of data segment */ 1139 1140 /* Get the number of directory entries contained in this IFD */ 1141 if (is_motorola) { 1142 number_of_tags = GETJOCTET(data[firstoffset]); 1143 number_of_tags <<= 8; 1144 number_of_tags += GETJOCTET(data[firstoffset+1]); 1145 } else { 1146 number_of_tags = GETJOCTET(data[firstoffset+1]); 1147 number_of_tags <<= 8; 1148 number_of_tags += GETJOCTET(data[firstoffset]); 1149 } 1150 if (number_of_tags == 0) return; 1151 firstoffset += 2; 1152 1153 /* Search for ExifSubIFD offset Tag in IFD0 */ 1154 for (;;) { 1155 if (firstoffset > length - 12) return; /* check end of data segment */ 1156 /* Get Tag number */ 1157 if (is_motorola) { 1158 tagnum = GETJOCTET(data[firstoffset]); 1159 tagnum <<= 8; 1160 tagnum += GETJOCTET(data[firstoffset+1]); 1161 } else { 1162 tagnum = GETJOCTET(data[firstoffset+1]); 1163 tagnum <<= 8; 1164 tagnum += GETJOCTET(data[firstoffset]); 1165 } 1166 if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ 1167 if (--number_of_tags == 0) return; 1168 firstoffset += 12; 1169 } 1170 1171 /* Get the ExifSubIFD offset */ 1172 if (is_motorola) { 1173 if (GETJOCTET(data[firstoffset+8]) != 0) return; 1174 if (GETJOCTET(data[firstoffset+9]) != 0) return; 1175 offset = GETJOCTET(data[firstoffset+10]); 1176 offset <<= 8; 1177 offset += GETJOCTET(data[firstoffset+11]); 1178 } else { 1179 if (GETJOCTET(data[firstoffset+11]) != 0) return; 1180 if (GETJOCTET(data[firstoffset+10]) != 0) return; 1181 offset = GETJOCTET(data[firstoffset+9]); 1182 offset <<= 8; 1183 offset += GETJOCTET(data[firstoffset+8]); 1184 } 1185 if (offset > length - 2) return; /* check end of data segment */ 1186 1187 /* Get the number of directory entries contained in this SubIFD */ 1188 if (is_motorola) { 1189 number_of_tags = GETJOCTET(data[offset]); 1190 number_of_tags <<= 8; 1191 number_of_tags += GETJOCTET(data[offset+1]); 1192 } else { 1193 number_of_tags = GETJOCTET(data[offset+1]); 1194 number_of_tags <<= 8; 1195 number_of_tags += GETJOCTET(data[offset]); 1196 } 1197 if (number_of_tags < 2) return; 1198 offset += 2; 1199 1200 /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ 1201 do { 1202 if (offset > length - 12) return; /* check end of data segment */ 1203 /* Get Tag number */ 1204 if (is_motorola) { 1205 tagnum = GETJOCTET(data[offset]); 1206 tagnum <<= 8; 1207 tagnum += GETJOCTET(data[offset+1]); 1208 } else { 1209 tagnum = GETJOCTET(data[offset+1]); 1210 tagnum <<= 8; 1211 tagnum += GETJOCTET(data[offset]); 1212 } 1213 if (tagnum == 0xA002 || tagnum == 0xA003) { 1214 if (tagnum == 0xA002) 1215 new_value = new_width; /* ExifImageWidth Tag */ 1216 else 1217 new_value = new_height; /* ExifImageHeight Tag */ 1218 if (is_motorola) { 1219 data[offset+2] = 0; /* Format = unsigned long (4 octets) */ 1220 data[offset+3] = 4; 1221 data[offset+4] = 0; /* Number Of Components = 1 */ 1222 data[offset+5] = 0; 1223 data[offset+6] = 0; 1224 data[offset+7] = 1; 1225 data[offset+8] = 0; 1226 data[offset+9] = 0; 1227 data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); 1228 data[offset+11] = (JOCTET)(new_value & 0xFF); 1229 } else { 1230 data[offset+2] = 4; /* Format = unsigned long (4 octets) */ 1231 data[offset+3] = 0; 1232 data[offset+4] = 1; /* Number Of Components = 1 */ 1233 data[offset+5] = 0; 1234 data[offset+6] = 0; 1235 data[offset+7] = 0; 1236 data[offset+8] = (JOCTET)(new_value & 0xFF); 1237 data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); 1238 data[offset+10] = 0; 1239 data[offset+11] = 0; 1240 } 1241 } 1242 offset += 12; 1243 } while (--number_of_tags); 1244 } 1245 1246 1247 /* Adjust output image parameters as needed. 1248 * 1249 * This must be called after jpeg_copy_critical_parameters() 1250 * and before jpeg_write_coefficients(). 1251 * 1252 * The return value is the set of virtual coefficient arrays to be written 1253 * (either the ones allocated by jtransform_request_workspace, or the 1254 * original source data arrays). The caller will need to pass this value 1255 * to jpeg_write_coefficients(). 1256 */ 1257 1258 GLOBAL(jvirt_barray_ptr *) 1259 jtransform_adjust_parameters (j_decompress_ptr srcinfo, 1260 j_compress_ptr dstinfo, 1261 jvirt_barray_ptr *src_coef_arrays, 1262 jpeg_transform_info *info) 1263 { 1264 /* If force-to-grayscale is requested, adjust destination parameters */ 1265 if (info->force_grayscale) { 1266 /* First, ensure we have YCbCr or grayscale data, and that the source's 1267 * Y channel is full resolution. (No reasonable person would make Y 1268 * be less than full resolution, so actually coping with that case 1269 * isn't worth extra code space. But we check it to avoid crashing.) 1270 */ 1271 if (((dstinfo->jpeg_color_space == JCS_YCbCr && 1272 dstinfo->num_components == 3) || 1273 (dstinfo->jpeg_color_space == JCS_GRAYSCALE && 1274 dstinfo->num_components == 1)) && 1275 srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && 1276 srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { 1277 /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed 1278 * properly. Among other things, it sets the target h_samp_factor & 1279 * v_samp_factor to 1, which typically won't match the source. 1280 * We have to preserve the source's quantization table number, however. 1281 */ 1282 int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; 1283 jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); 1284 dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; 1285 } else { 1286 /* Sorry, can't do it */ 1287 ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); 1288 } 1289 } else if (info->num_components == 1) { 1290 /* For a single-component source, we force the destination sampling factors 1291 * to 1x1, with or without force_grayscale. This is useful because some 1292 * decoders choke on grayscale images with other sampling factors. 1293 */ 1294 dstinfo->comp_info[0].h_samp_factor = 1; 1295 dstinfo->comp_info[0].v_samp_factor = 1; 1296 } 1297 1298 /* Correct the destination's image dimensions as necessary 1299 * for crop and rotate/flip operations. 1300 */ 1301 dstinfo->image_width = info->output_width; 1302 dstinfo->image_height = info->output_height; 1303 1304 /* Transpose destination image parameters */ 1305 switch (info->transform) { 1306 case JXFORM_TRANSPOSE: 1307 case JXFORM_TRANSVERSE: 1308 case JXFORM_ROT_90: 1309 case JXFORM_ROT_270: 1310 transpose_critical_parameters(dstinfo); 1311 break; 1312 default: 1313 break; 1314 } 1315 1316 /* Adjust Exif properties */ 1317 if (srcinfo->marker_list != NULL && 1318 srcinfo->marker_list->marker == JPEG_APP0+1 && 1319 srcinfo->marker_list->data_length >= 6 && 1320 GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && 1321 GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && 1322 GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && 1323 GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && 1324 GETJOCTET(srcinfo->marker_list->data[4]) == 0 && 1325 GETJOCTET(srcinfo->marker_list->data[5]) == 0) { 1326 /* Suppress output of JFIF marker */ 1327 dstinfo->write_JFIF_header = FALSE; 1328 /* Adjust Exif image parameters */ 1329 if (dstinfo->image_width != srcinfo->image_width || 1330 dstinfo->image_height != srcinfo->image_height) 1331 /* Align data segment to start of TIFF structure for parsing */ 1332 adjust_exif_parameters(srcinfo->marker_list->data + 6, 1333 srcinfo->marker_list->data_length - 6, 1334 dstinfo->image_width, dstinfo->image_height); 1335 } 1336 1337 /* Return the appropriate output data set */ 1338 if (info->workspace_coef_arrays != NULL) 1339 return info->workspace_coef_arrays; 1340 return src_coef_arrays; 1341 } 1342 1343 1344 /* Execute the actual transformation, if any. 1345 * 1346 * This must be called *after* jpeg_write_coefficients, because it depends 1347 * on jpeg_write_coefficients to have computed subsidiary values such as 1348 * the per-component width and height fields in the destination object. 1349 * 1350 * Note that some transformations will modify the source data arrays! 1351 */ 1352 1353 GLOBAL(void) 1354 jtransform_execute_transform (j_decompress_ptr srcinfo, 1355 j_compress_ptr dstinfo, 1356 jvirt_barray_ptr *src_coef_arrays, 1357 jpeg_transform_info *info) 1358 { 1359 jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; 1360 1361 /* Note: conditions tested here should match those in switch statement 1362 * in jtransform_request_workspace() 1363 */ 1364 switch (info->transform) { 1365 case JXFORM_NONE: 1366 if (info->x_crop_offset != 0 || info->y_crop_offset != 0) 1367 do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1368 src_coef_arrays, dst_coef_arrays); 1369 break; 1370 case JXFORM_FLIP_H: 1371 if (info->y_crop_offset != 0) 1372 do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1373 src_coef_arrays, dst_coef_arrays); 1374 else 1375 do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, 1376 src_coef_arrays); 1377 break; 1378 case JXFORM_FLIP_V: 1379 do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1380 src_coef_arrays, dst_coef_arrays); 1381 break; 1382 case JXFORM_TRANSPOSE: 1383 do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1384 src_coef_arrays, dst_coef_arrays); 1385 break; 1386 case JXFORM_TRANSVERSE: 1387 do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1388 src_coef_arrays, dst_coef_arrays); 1389 break; 1390 case JXFORM_ROT_90: 1391 do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1392 src_coef_arrays, dst_coef_arrays); 1393 break; 1394 case JXFORM_ROT_180: 1395 do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1396 src_coef_arrays, dst_coef_arrays); 1397 break; 1398 case JXFORM_ROT_270: 1399 do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, 1400 src_coef_arrays, dst_coef_arrays); 1401 break; 1402 } 1403 } 1404 1405 /* jtransform_perfect_transform 1406 * 1407 * Determine whether lossless transformation is perfectly 1408 * possible for a specified image and transformation. 1409 * 1410 * Inputs: 1411 * image_width, image_height: source image dimensions. 1412 * MCU_width, MCU_height: pixel dimensions of MCU. 1413 * transform: transformation identifier. 1414 * Parameter sources from initialized jpeg_struct 1415 * (after reading source header): 1416 * image_width = cinfo.image_width 1417 * image_height = cinfo.image_height 1418 * MCU_width = cinfo.max_h_samp_factor * DCTSIZE 1419 * MCU_height = cinfo.max_v_samp_factor * DCTSIZE 1420 * Result: 1421 * TRUE = perfect transformation possible 1422 * FALSE = perfect transformation not possible 1423 * (may use custom action then) 1424 */ 1425 1426 GLOBAL(boolean) 1427 jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, 1428 int MCU_width, int MCU_height, 1429 JXFORM_CODE transform) 1430 { 1431 boolean result = TRUE; /* initialize TRUE */ 1432 1433 switch (transform) { 1434 case JXFORM_FLIP_H: 1435 case JXFORM_ROT_270: 1436 if (image_width % (JDIMENSION) MCU_width) 1437 result = FALSE; 1438 break; 1439 case JXFORM_FLIP_V: 1440 case JXFORM_ROT_90: 1441 if (image_height % (JDIMENSION) MCU_height) 1442 result = FALSE; 1443 break; 1444 case JXFORM_TRANSVERSE: 1445 case JXFORM_ROT_180: 1446 if (image_width % (JDIMENSION) MCU_width) 1447 result = FALSE; 1448 if (image_height % (JDIMENSION) MCU_height) 1449 result = FALSE; 1450 break; 1451 default: 1452 break; 1453 } 1454 1455 return result; 1456 } 1457 1458 #endif /* TRANSFORMS_SUPPORTED */ 1459 1460 1461 /* Setup decompression object to save desired markers in memory. 1462 * This must be called before jpeg_read_header() to have the desired effect. 1463 */ 1464 1465 GLOBAL(void) 1466 jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) 1467 { 1468 #ifdef SAVE_MARKERS_SUPPORTED 1469 int m; 1470 1471 /* Save comments except under NONE option */ 1472 if (option != JCOPYOPT_NONE) { 1473 jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); 1474 } 1475 /* Save all types of APPn markers iff ALL option */ 1476 if (option == JCOPYOPT_ALL) { 1477 for (m = 0; m < 16; m++) 1478 jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); 1479 } 1480 #endif /* SAVE_MARKERS_SUPPORTED */ 1481 } 1482 1483 /* Copy markers saved in the given source object to the destination object. 1484 * This should be called just after jpeg_start_compress() or 1485 * jpeg_write_coefficients(). 1486 * Note that those routines will have written the SOI, and also the 1487 * JFIF APP0 or Adobe APP14 markers if selected. 1488 */ 1489 1490 GLOBAL(void) 1491 jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, 1492 JCOPY_OPTION option) 1493 { 1494 jpeg_saved_marker_ptr marker; 1495 1496 /* In the current implementation, we don't actually need to examine the 1497 * option flag here; we just copy everything that got saved. 1498 * But to avoid confusion, we do not output JFIF and Adobe APP14 markers 1499 * if the encoder library already wrote one. 1500 */ 1501 for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { 1502 if (dstinfo->write_JFIF_header && 1503 marker->marker == JPEG_APP0 && 1504 marker->data_length >= 5 && 1505 GETJOCTET(marker->data[0]) == 0x4A && 1506 GETJOCTET(marker->data[1]) == 0x46 && 1507 GETJOCTET(marker->data[2]) == 0x49 && 1508 GETJOCTET(marker->data[3]) == 0x46 && 1509 GETJOCTET(marker->data[4]) == 0) 1510 continue; /* reject duplicate JFIF */ 1511 if (dstinfo->write_Adobe_marker && 1512 marker->marker == JPEG_APP0+14 && 1513 marker->data_length >= 5 && 1514 GETJOCTET(marker->data[0]) == 0x41 && 1515 GETJOCTET(marker->data[1]) == 0x64 && 1516 GETJOCTET(marker->data[2]) == 0x6F && 1517 GETJOCTET(marker->data[3]) == 0x62 && 1518 GETJOCTET(marker->data[4]) == 0x65) 1519 continue; /* reject duplicate Adobe */ 1520 #ifdef NEED_FAR_POINTERS 1521 /* We could use jpeg_write_marker if the data weren't FAR... */ 1522 { 1523 unsigned int i; 1524 jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); 1525 for (i = 0; i < marker->data_length; i++) 1526 jpeg_write_m_byte(dstinfo, marker->data[i]); 1527 } 1528 #else 1529 jpeg_write_marker(dstinfo, marker->marker, 1530 marker->data, marker->data_length); 1531 #endif 1532 } 1533 }