Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/libjpeg/transupp.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * transupp.c | |
| 3 * | |
| 4 * Copyright (C) 1997-2023, Thomas G. Lane, Guido Vollbeding. | |
| 5 * This file is part of the Independent JPEG Group's software. | |
| 6 * For conditions of distribution and use, see the accompanying README file. | |
| 7 * | |
| 8 * This file contains image transformation routines and other utility code | |
| 9 * used by the jpegtran sample application. These are NOT part of the core | |
| 10 * JPEG library. But we keep these routines separate from jpegtran.c to | |
| 11 * ease the task of maintaining jpegtran-like programs that have other user | |
| 12 * interfaces. | |
| 13 */ | |
| 14 | |
| 15 /* Although this file really shouldn't have access to the library internals, | |
| 16 * it's helpful to let it call jround_up() and jcopy_block_row(). | |
| 17 * Also, the (switchable) virtual memory adaptation code for | |
| 18 * the drop feature has dependencies on library internals. | |
| 19 */ | |
| 20 #define JPEG_INTERNALS | |
| 21 | |
| 22 #include "jinclude.h" | |
| 23 #include "jpeglib.h" | |
| 24 #include "transupp.h" /* My own external interface */ | |
| 25 #include <ctype.h> /* to declare isdigit() */ | |
| 26 | |
| 27 | |
| 28 #if TRANSFORMS_SUPPORTED | |
| 29 | |
| 30 /* | |
| 31 * Lossless image transformation routines. These routines work on DCT | |
| 32 * coefficient arrays and thus do not require any lossy decompression | |
| 33 * or recompression of the image. | |
| 34 * Thanks to Guido Vollbeding for the initial design and code of this feature, | |
| 35 * and to Ben Jackson for introducing the cropping feature. | |
| 36 * | |
| 37 * Horizontal flipping is done in-place, using a single top-to-bottom | |
| 38 * pass through the virtual source array. It will thus be much the | |
| 39 * fastest option for images larger than main memory. | |
| 40 * | |
| 41 * The other routines require a set of destination virtual arrays, so they | |
| 42 * need twice as much memory as jpegtran normally does. The destination | |
| 43 * arrays are always written in normal scan order (top to bottom) because | |
| 44 * the virtual array manager expects this. The source arrays will be scanned | |
| 45 * in the corresponding order, which means multiple passes through the source | |
| 46 * arrays for most of the transforms. That could result in much thrashing | |
| 47 * if the image is larger than main memory. | |
| 48 * | |
| 49 * If cropping or trimming is involved, the destination arrays may be smaller | |
| 50 * than the source arrays. Note it is not possible to do horizontal flip | |
| 51 * in-place when a nonzero Y crop offset is specified, since we'd have to move | |
| 52 * data from one block row to another but the virtual array manager doesn't | |
| 53 * guarantee we can touch more than one row at a time. So in that case, | |
| 54 * we have to use a separate destination array. | |
| 55 * | |
| 56 * Some notes about the operating environment of the individual transform | |
| 57 * routines: | |
| 58 * 1. Both the source and destination virtual arrays are allocated from the | |
| 59 * source JPEG object, and therefore should be manipulated by calling the | |
| 60 * source's memory manager. | |
| 61 * 2. The destination's component count should be used. It may be smaller | |
| 62 * than the source's when forcing to grayscale. | |
| 63 * 3. Likewise the destination's sampling factors should be used. When | |
| 64 * forcing to grayscale the destination's sampling factors will be all 1, | |
| 65 * and we may as well take that as the effective iMCU size. | |
| 66 * 4. When "trim" is in effect, the destination's dimensions will be the | |
| 67 * trimmed values but the source's will be untrimmed. | |
| 68 * 5. When "crop" is in effect, the destination's dimensions will be the | |
| 69 * cropped values but the source's will be uncropped. Each transform | |
| 70 * routine is responsible for picking up source data starting at the | |
| 71 * correct X and Y offset for the crop region. (The X and Y offsets | |
| 72 * passed to the transform routines are measured in iMCU blocks of the | |
| 73 * destination.) | |
| 74 * 6. All the routines assume that the source and destination buffers are | |
| 75 * padded out to a full iMCU boundary. This is true, although for the | |
| 76 * source buffer it is an undocumented property of jdcoefct.c. | |
| 77 */ | |
| 78 | |
| 79 | |
| 80 /* Drop code may be used with or without virtual memory adaptation code. | |
| 81 * This code has some dependencies on internal library behavior, so you | |
| 82 * may choose to disable it. For example, it doesn't make a difference | |
| 83 * if you only use jmemnobs anyway. | |
| 84 */ | |
| 85 #ifndef DROP_REQUEST_FROM_SRC | |
| 86 #define DROP_REQUEST_FROM_SRC 1 /* 0 disables adaptation */ | |
| 87 #endif | |
| 88 | |
| 89 | |
| 90 #if DROP_REQUEST_FROM_SRC | |
| 91 /* Force jpeg_read_coefficients to request | |
| 92 * the virtual coefficient arrays from | |
| 93 * the source decompression object. | |
| 94 */ | |
| 95 METHODDEF(jvirt_barray_ptr) | |
| 96 drop_request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, | |
| 97 JDIMENSION blocksperrow, JDIMENSION numrows, | |
| 98 JDIMENSION maxaccess) | |
| 99 { | |
| 100 j_common_ptr srcinfo = (j_common_ptr) cinfo->client_data; | |
| 101 | |
| 102 return (*srcinfo->mem->request_virt_barray) | |
| 103 (srcinfo, pool_id, pre_zero, | |
| 104 blocksperrow, numrows, maxaccess); | |
| 105 } | |
| 106 | |
| 107 | |
| 108 /* Force jpeg_read_coefficients to return | |
| 109 * after requesting and before accessing | |
| 110 * the virtual coefficient arrays. | |
| 111 */ | |
| 112 METHODDEF(int) | |
| 113 drop_consume_input (j_decompress_ptr cinfo) | |
| 114 { | |
| 115 return JPEG_SUSPENDED; | |
| 116 } | |
| 117 | |
| 118 | |
| 119 METHODDEF(void) | |
| 120 drop_start_input_pass (j_decompress_ptr cinfo) | |
| 121 { | |
| 122 cinfo->inputctl->consume_input = drop_consume_input; | |
| 123 } | |
| 124 | |
| 125 | |
| 126 LOCAL(void) | |
| 127 drop_request_from_src (j_decompress_ptr dropinfo, j_decompress_ptr srcinfo) | |
| 128 { | |
| 129 void *save_client_data; | |
| 130 JMETHOD(jvirt_barray_ptr, save_request_virt_barray, | |
| 131 (j_common_ptr cinfo, int pool_id, boolean pre_zero, | |
| 132 JDIMENSION blocksperrow, JDIMENSION numrows, JDIMENSION maxaccess)); | |
| 133 JMETHOD(void, save_start_input_pass, (j_decompress_ptr cinfo)); | |
| 134 | |
| 135 /* Set custom method pointers, save original pointers */ | |
| 136 save_client_data = dropinfo->client_data; | |
| 137 dropinfo->client_data = (void *) srcinfo; | |
| 138 save_request_virt_barray = dropinfo->mem->request_virt_barray; | |
| 139 dropinfo->mem->request_virt_barray = drop_request_virt_barray; | |
| 140 save_start_input_pass = dropinfo->inputctl->start_input_pass; | |
| 141 dropinfo->inputctl->start_input_pass = drop_start_input_pass; | |
| 142 | |
| 143 /* Execute only initialization part. | |
| 144 * Requested coefficient arrays will be realized later by the srcinfo object. | |
| 145 * Next call to the same function will then do the actual data reading. | |
| 146 * NB: since we request the coefficient arrays from another object, | |
| 147 * the inherent realization call is effectively a no-op. | |
| 148 */ | |
| 149 (void) jpeg_read_coefficients(dropinfo); | |
| 150 | |
| 151 /* Reset method pointers */ | |
| 152 dropinfo->client_data = save_client_data; | |
| 153 dropinfo->mem->request_virt_barray = save_request_virt_barray; | |
| 154 dropinfo->inputctl->start_input_pass = save_start_input_pass; | |
| 155 /* Do input initialization for first scan now, | |
| 156 * which also resets the consume_input method. | |
| 157 */ | |
| 158 (*save_start_input_pass)(dropinfo); | |
| 159 } | |
| 160 #endif /* DROP_REQUEST_FROM_SRC */ | |
| 161 | |
| 162 | |
| 163 LOCAL(void) | |
| 164 dequant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr, | |
| 165 jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) | |
| 166 { | |
| 167 JDIMENSION blk_x, blk_y; | |
| 168 int offset_y, k; | |
| 169 JQUANT_TBL *qtblptr; | |
| 170 JBLOCKARRAY buffer; | |
| 171 JBLOCKROW block; | |
| 172 JCOEFPTR ptr; | |
| 173 | |
| 174 qtblptr = compptr->quant_table; | |
| 175 for (blk_y = 0; blk_y < compptr->height_in_blocks; | |
| 176 blk_y += compptr->v_samp_factor) { | |
| 177 buffer = (*cinfo->mem->access_virt_barray) | |
| 178 ((j_common_ptr) cinfo, coef_array, blk_y, | |
| 179 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 180 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 181 block = buffer[offset_y]; | |
| 182 for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { | |
| 183 ptr = block[blk_x]; | |
| 184 for (k = 0; k < DCTSIZE2; k++) | |
| 185 if (qtblptr->quantval[k] != qtblptr1->quantval[k]) | |
| 186 ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k]; | |
| 187 } | |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 | |
| 193 LOCAL(void) | |
| 194 requant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr, | |
| 195 jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) | |
| 196 { | |
| 197 JDIMENSION blk_x, blk_y; | |
| 198 int offset_y, k, temp, qval; | |
| 199 JQUANT_TBL *qtblptr; | |
| 200 JBLOCKARRAY buffer; | |
| 201 JBLOCKROW block; | |
| 202 JCOEFPTR ptr; | |
| 203 | |
| 204 qtblptr = compptr->quant_table; | |
| 205 for (blk_y = 0; blk_y < compptr->height_in_blocks; | |
| 206 blk_y += compptr->v_samp_factor) { | |
| 207 buffer = (*cinfo->mem->access_virt_barray) | |
| 208 ((j_common_ptr) cinfo, coef_array, blk_y, | |
| 209 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 210 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 211 block = buffer[offset_y]; | |
| 212 for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { | |
| 213 ptr = block[blk_x]; | |
| 214 for (k = 0; k < DCTSIZE2; k++) { | |
| 215 qval = qtblptr1->quantval[k]; | |
| 216 if (qval == 0) continue; | |
| 217 temp = qtblptr->quantval[k]; | |
| 218 if (temp == qval) continue; | |
| 219 temp *= ptr[k]; | |
| 220 /* The following quantization code is a copy from jcdctmgr.c */ | |
| 221 #ifdef FAST_DIVIDE | |
| 222 #define DIVIDE_BY(a,b) a /= b | |
| 223 #else | |
| 224 #define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 | |
| 225 #endif | |
| 226 if (temp < 0) { | |
| 227 temp = -temp; | |
| 228 temp += qval>>1; /* for rounding */ | |
| 229 DIVIDE_BY(temp, qval); | |
| 230 temp = -temp; | |
| 231 } else { | |
| 232 temp += qval>>1; /* for rounding */ | |
| 233 DIVIDE_BY(temp, qval); | |
| 234 } | |
| 235 ptr[k] = (JCOEF) temp; | |
| 236 } | |
| 237 } | |
| 238 } | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 | |
| 243 /* Calculate largest common denominator with Euclid's algorithm. | |
| 244 */ | |
| 245 LOCAL(JCOEF) | |
| 246 largest_common_denominator(JCOEF a, JCOEF b) | |
| 247 { | |
| 248 JCOEF c; | |
| 249 | |
| 250 while (b) { | |
| 251 c = a % b; | |
| 252 a = b; | |
| 253 b = c; | |
| 254 } | |
| 255 | |
| 256 return a; | |
| 257 } | |
| 258 | |
| 259 | |
| 260 LOCAL(void) | |
| 261 adjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays, | |
| 262 j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays, | |
| 263 boolean trim, j_compress_ptr dstinfo) | |
| 264 { | |
| 265 jpeg_component_info *compptr1, *compptr2; | |
| 266 JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3; | |
| 267 int ci, k; | |
| 268 | |
| 269 for (ci = 0; ci < dstinfo->num_components && | |
| 270 ci < dropinfo->num_components; ci++) { | |
| 271 compptr1 = srcinfo->comp_info + ci; | |
| 272 compptr2 = dropinfo->comp_info + ci; | |
| 273 qtblptr1 = compptr1->quant_table; | |
| 274 qtblptr2 = compptr2->quant_table; | |
| 275 for (k = 0; k < DCTSIZE2; k++) { | |
| 276 if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) { | |
| 277 if (trim) | |
| 278 requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1); | |
| 279 else { | |
| 280 qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no]; | |
| 281 for (k = 0; k < DCTSIZE2; k++) | |
| 282 if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) | |
| 283 qtblptr3->quantval[k] = largest_common_denominator | |
| 284 (qtblptr1->quantval[k], qtblptr2->quantval[k]); | |
| 285 dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3); | |
| 286 dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3); | |
| 287 } | |
| 288 break; | |
| 289 } | |
| 290 } | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 | |
| 295 LOCAL(void) | |
| 296 do_drop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 297 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 298 jvirt_barray_ptr *src_coef_arrays, | |
| 299 j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays, | |
| 300 JDIMENSION drop_width, JDIMENSION drop_height) | |
| 301 /* Drop. If the dropinfo component number is smaller than the destination's, | |
| 302 * we fill in the remaining components with zero. This provides the feature | |
| 303 * of dropping grayscale into (arbitrarily sampled) color images. | |
| 304 */ | |
| 305 { | |
| 306 JDIMENSION comp_width, comp_height; | |
| 307 JDIMENSION blk_y, x_drop_blocks, y_drop_blocks; | |
| 308 int ci, offset_y; | |
| 309 JBLOCKARRAY src_buffer, dst_buffer; | |
| 310 jpeg_component_info *compptr; | |
| 311 | |
| 312 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 313 compptr = dstinfo->comp_info + ci; | |
| 314 comp_width = drop_width * compptr->h_samp_factor; | |
| 315 comp_height = drop_height * compptr->v_samp_factor; | |
| 316 x_drop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 317 y_drop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 318 for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) { | |
| 319 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 320 ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks, | |
| 321 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 322 if (ci < dropinfo->num_components) { | |
| 323 #if DROP_REQUEST_FROM_SRC | |
| 324 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 325 ((j_common_ptr) srcinfo, drop_coef_arrays[ci], blk_y, | |
| 326 #else | |
| 327 src_buffer = (*dropinfo->mem->access_virt_barray) | |
| 328 ((j_common_ptr) dropinfo, drop_coef_arrays[ci], blk_y, | |
| 329 #endif | |
| 330 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 331 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 332 jcopy_block_row(src_buffer[offset_y], | |
| 333 dst_buffer[offset_y] + x_drop_blocks, | |
| 334 comp_width); | |
| 335 } | |
| 336 } else { | |
| 337 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 338 FMEMZERO(dst_buffer[offset_y] + x_drop_blocks, | |
| 339 comp_width * SIZEOF(JBLOCK)); | |
| 340 } | |
| 341 } | |
| 342 } | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 | |
| 347 LOCAL(void) | |
| 348 do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 349 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 350 jvirt_barray_ptr *src_coef_arrays, | |
| 351 jvirt_barray_ptr *dst_coef_arrays) | |
| 352 /* Crop. This is only used when no rotate/flip is requested with the crop. */ | |
| 353 { | |
| 354 JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; | |
| 355 int ci, offset_y; | |
| 356 JBLOCKARRAY src_buffer, dst_buffer; | |
| 357 jpeg_component_info *compptr; | |
| 358 | |
| 359 /* We simply have to copy the right amount of data (the destination's | |
| 360 * image size) starting at the given X and Y offsets in the source. | |
| 361 */ | |
| 362 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 363 compptr = dstinfo->comp_info + ci; | |
| 364 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 365 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 366 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 367 dst_blk_y += compptr->v_samp_factor) { | |
| 368 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 369 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 370 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 371 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 372 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 373 dst_blk_y + y_crop_blocks, | |
| 374 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 375 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 376 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, | |
| 377 dst_buffer[offset_y], | |
| 378 compptr->width_in_blocks); | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 | |
| 385 LOCAL(void) | |
| 386 do_crop_ext_zero (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 387 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 388 jvirt_barray_ptr *src_coef_arrays, | |
| 389 jvirt_barray_ptr *dst_coef_arrays) | |
| 390 /* Crop. This is only used when no rotate/flip is requested with the crop. | |
| 391 * Extension: If the destination size is larger than the source, we fill in | |
| 392 * the extra area with zero (neutral gray). Note we also have to zero partial | |
| 393 * iMCUs at the right and bottom edge of the source image area in this case. | |
| 394 */ | |
| 395 { | |
| 396 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height; | |
| 397 JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; | |
| 398 int ci, offset_y; | |
| 399 JBLOCKARRAY src_buffer, dst_buffer; | |
| 400 jpeg_component_info *compptr; | |
| 401 | |
| 402 MCU_cols = srcinfo->output_width / | |
| 403 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 404 MCU_rows = srcinfo->output_height / | |
| 405 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 406 | |
| 407 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 408 compptr = dstinfo->comp_info + ci; | |
| 409 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 410 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 411 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 412 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 413 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 414 dst_blk_y += compptr->v_samp_factor) { | |
| 415 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 416 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 417 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 418 if (dstinfo->jpeg_height > srcinfo->output_height) { | |
| 419 if (dst_blk_y < y_crop_blocks || | |
| 420 dst_blk_y >= y_crop_blocks + comp_height) { | |
| 421 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 422 FMEMZERO(dst_buffer[offset_y], | |
| 423 compptr->width_in_blocks * SIZEOF(JBLOCK)); | |
| 424 } | |
| 425 continue; | |
| 426 } | |
| 427 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 428 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 429 dst_blk_y - y_crop_blocks, | |
| 430 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 431 } else { | |
| 432 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 433 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 434 dst_blk_y + y_crop_blocks, | |
| 435 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 436 } | |
| 437 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 438 if (dstinfo->jpeg_width > srcinfo->output_width) { | |
| 439 if (x_crop_blocks > 0) { | |
| 440 FMEMZERO(dst_buffer[offset_y], | |
| 441 x_crop_blocks * SIZEOF(JBLOCK)); | |
| 442 } | |
| 443 jcopy_block_row(src_buffer[offset_y], | |
| 444 dst_buffer[offset_y] + x_crop_blocks, | |
| 445 comp_width); | |
| 446 if (compptr->width_in_blocks > x_crop_blocks + comp_width) { | |
| 447 FMEMZERO(dst_buffer[offset_y] + | |
| 448 x_crop_blocks + comp_width, | |
| 449 (compptr->width_in_blocks - | |
| 450 x_crop_blocks - comp_width) * SIZEOF(JBLOCK)); | |
| 451 } | |
| 452 } else { | |
| 453 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, | |
| 454 dst_buffer[offset_y], | |
| 455 compptr->width_in_blocks); | |
| 456 } | |
| 457 } | |
| 458 } | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 | |
| 463 LOCAL(void) | |
| 464 do_crop_ext_flat (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 465 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 466 jvirt_barray_ptr *src_coef_arrays, | |
| 467 jvirt_barray_ptr *dst_coef_arrays) | |
| 468 /* Crop. This is only used when no rotate/flip is requested with the crop. | |
| 469 * Extension: The destination width is larger than the source and we fill in | |
| 470 * the extra area with the DC of the adjacent block. Note we also have to | |
| 471 * fill partial iMCUs at the right and bottom edge of the source image area | |
| 472 * in this case. | |
| 473 */ | |
| 474 { | |
| 475 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height; | |
| 476 JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; | |
| 477 int ci, offset_y; | |
| 478 JCOEF dc; | |
| 479 JBLOCKARRAY src_buffer, dst_buffer; | |
| 480 jpeg_component_info *compptr; | |
| 481 | |
| 482 MCU_cols = srcinfo->output_width / | |
| 483 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 484 MCU_rows = srcinfo->output_height / | |
| 485 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 486 | |
| 487 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 488 compptr = dstinfo->comp_info + ci; | |
| 489 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 490 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 491 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 492 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 493 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 494 dst_blk_y += compptr->v_samp_factor) { | |
| 495 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 496 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 497 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 498 if (dstinfo->jpeg_height > srcinfo->output_height) { | |
| 499 if (dst_blk_y < y_crop_blocks || | |
| 500 dst_blk_y >= y_crop_blocks + comp_height) { | |
| 501 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 502 FMEMZERO(dst_buffer[offset_y], | |
| 503 compptr->width_in_blocks * SIZEOF(JBLOCK)); | |
| 504 } | |
| 505 continue; | |
| 506 } | |
| 507 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 508 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 509 dst_blk_y - y_crop_blocks, | |
| 510 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 511 } else { | |
| 512 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 513 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 514 dst_blk_y + y_crop_blocks, | |
| 515 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 516 } | |
| 517 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 518 if (x_crop_blocks > 0) { | |
| 519 FMEMZERO(dst_buffer[offset_y], | |
| 520 x_crop_blocks * SIZEOF(JBLOCK)); | |
| 521 dc = src_buffer[offset_y][0][0]; | |
| 522 for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) { | |
| 523 dst_buffer[offset_y][dst_blk_x][0] = dc; | |
| 524 } | |
| 525 } | |
| 526 jcopy_block_row(src_buffer[offset_y], | |
| 527 dst_buffer[offset_y] + x_crop_blocks, | |
| 528 comp_width); | |
| 529 if (compptr->width_in_blocks > x_crop_blocks + comp_width) { | |
| 530 FMEMZERO(dst_buffer[offset_y] + | |
| 531 x_crop_blocks + comp_width, | |
| 532 (compptr->width_in_blocks - | |
| 533 x_crop_blocks - comp_width) * SIZEOF(JBLOCK)); | |
| 534 dc = src_buffer[offset_y][comp_width - 1][0]; | |
| 535 for (dst_blk_x = x_crop_blocks + comp_width; | |
| 536 dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | |
| 537 dst_buffer[offset_y][dst_blk_x][0] = dc; | |
| 538 } | |
| 539 } | |
| 540 } | |
| 541 } | |
| 542 } | |
| 543 } | |
| 544 | |
| 545 | |
| 546 LOCAL(void) | |
| 547 do_crop_ext_reflect (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 548 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 549 jvirt_barray_ptr *src_coef_arrays, | |
| 550 jvirt_barray_ptr *dst_coef_arrays) | |
| 551 /* Crop. This is only used when no rotate/flip is requested with the crop. | |
| 552 * Extension: The destination width is larger than the source and we fill in | |
| 553 * the extra area with repeated reflections of the source region. Note we | |
| 554 * also have to fill partial iMCUs at the right and bottom edge of the source | |
| 555 * image area in this case. | |
| 556 */ | |
| 557 { | |
| 558 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x; | |
| 559 JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; | |
| 560 int ci, k, offset_y; | |
| 561 JBLOCKARRAY src_buffer, dst_buffer; | |
| 562 JBLOCKROW src_row_ptr, dst_row_ptr; | |
| 563 JCOEFPTR src_ptr, dst_ptr; | |
| 564 jpeg_component_info *compptr; | |
| 565 | |
| 566 MCU_cols = srcinfo->output_width / | |
| 567 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 568 MCU_rows = srcinfo->output_height / | |
| 569 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 570 | |
| 571 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 572 compptr = dstinfo->comp_info + ci; | |
| 573 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 574 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 575 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 576 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 577 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 578 dst_blk_y += compptr->v_samp_factor) { | |
| 579 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 580 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 581 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 582 if (dstinfo->jpeg_height > srcinfo->output_height) { | |
| 583 if (dst_blk_y < y_crop_blocks || | |
| 584 dst_blk_y >= y_crop_blocks + comp_height) { | |
| 585 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 586 FMEMZERO(dst_buffer[offset_y], | |
| 587 compptr->width_in_blocks * SIZEOF(JBLOCK)); | |
| 588 } | |
| 589 continue; | |
| 590 } | |
| 591 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 592 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 593 dst_blk_y - y_crop_blocks, | |
| 594 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 595 } else { | |
| 596 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 597 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 598 dst_blk_y + y_crop_blocks, | |
| 599 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 600 } | |
| 601 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 602 /* Copy source region */ | |
| 603 jcopy_block_row(src_buffer[offset_y], | |
| 604 dst_buffer[offset_y] + x_crop_blocks, | |
| 605 comp_width); | |
| 606 if (x_crop_blocks > 0) { | |
| 607 /* Reflect to left */ | |
| 608 dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks; | |
| 609 for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) { | |
| 610 src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ | |
| 611 for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0; | |
| 612 src_blk_x--, dst_blk_x--) { | |
| 613 dst_ptr = *--dst_row_ptr; /* destination goes left */ | |
| 614 src_ptr = *src_row_ptr++; /* source goes right */ | |
| 615 /* this unrolled loop doesn't need to know which row it's on... */ | |
| 616 for (k = 0; k < DCTSIZE2; k += 2) { | |
| 617 *dst_ptr++ = *src_ptr++; /* copy even column */ | |
| 618 *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ | |
| 619 } | |
| 620 } | |
| 621 } | |
| 622 } | |
| 623 if (compptr->width_in_blocks > x_crop_blocks + comp_width) { | |
| 624 /* Reflect to right */ | |
| 625 dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width; | |
| 626 for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width; | |
| 627 dst_blk_x > 0;) { | |
| 628 src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ | |
| 629 for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0; | |
| 630 src_blk_x--, dst_blk_x--) { | |
| 631 dst_ptr = *dst_row_ptr++; /* destination goes right */ | |
| 632 src_ptr = *--src_row_ptr; /* source goes left */ | |
| 633 /* this unrolled loop doesn't need to know which row it's on... */ | |
| 634 for (k = 0; k < DCTSIZE2; k += 2) { | |
| 635 *dst_ptr++ = *src_ptr++; /* copy even column */ | |
| 636 *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ | |
| 637 } | |
| 638 } | |
| 639 } | |
| 640 } | |
| 641 } | |
| 642 } | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 | |
| 647 LOCAL(void) | |
| 648 do_wipe (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 649 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 650 jvirt_barray_ptr *src_coef_arrays, | |
| 651 JDIMENSION drop_width, JDIMENSION drop_height) | |
| 652 /* Wipe - drop content of specified area, fill with zero (neutral gray) */ | |
| 653 { | |
| 654 JDIMENSION x_wipe_blocks, wipe_width; | |
| 655 JDIMENSION y_wipe_blocks, wipe_bottom; | |
| 656 int ci, offset_y; | |
| 657 JBLOCKARRAY buffer; | |
| 658 jpeg_component_info *compptr; | |
| 659 | |
| 660 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 661 compptr = dstinfo->comp_info + ci; | |
| 662 x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 663 wipe_width = drop_width * compptr->h_samp_factor; | |
| 664 y_wipe_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 665 wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks; | |
| 666 for (; y_wipe_blocks < wipe_bottom; | |
| 667 y_wipe_blocks += compptr->v_samp_factor) { | |
| 668 buffer = (*srcinfo->mem->access_virt_barray) | |
| 669 ((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks, | |
| 670 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 671 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 672 FMEMZERO(buffer[offset_y] + x_wipe_blocks, | |
| 673 wipe_width * SIZEOF(JBLOCK)); | |
| 674 } | |
| 675 } | |
| 676 } | |
| 677 } | |
| 678 | |
| 679 | |
| 680 LOCAL(void) | |
| 681 do_flatten (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 682 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 683 jvirt_barray_ptr *src_coef_arrays, | |
| 684 JDIMENSION drop_width, JDIMENSION drop_height) | |
| 685 /* Flatten - drop content of specified area, similar to wipe, | |
| 686 * but fill with average of adjacent blocks, instead of zero. | |
| 687 */ | |
| 688 { | |
| 689 JDIMENSION x_wipe_blocks, wipe_width, wipe_right; | |
| 690 JDIMENSION y_wipe_blocks, wipe_bottom, blk_x; | |
| 691 int ci, offset_y, dc_left_value, dc_right_value, average; | |
| 692 JBLOCKARRAY buffer; | |
| 693 jpeg_component_info *compptr; | |
| 694 | |
| 695 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 696 compptr = dstinfo->comp_info + ci; | |
| 697 x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 698 wipe_width = drop_width * compptr->h_samp_factor; | |
| 699 wipe_right = wipe_width + x_wipe_blocks; | |
| 700 y_wipe_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 701 wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks; | |
| 702 for (; y_wipe_blocks < wipe_bottom; | |
| 703 y_wipe_blocks += compptr->v_samp_factor) { | |
| 704 buffer = (*srcinfo->mem->access_virt_barray) | |
| 705 ((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks, | |
| 706 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 707 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 708 FMEMZERO(buffer[offset_y] + x_wipe_blocks, | |
| 709 wipe_width * SIZEOF(JBLOCK)); | |
| 710 if (x_wipe_blocks > 0) { | |
| 711 dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0]; | |
| 712 if (wipe_right < compptr->width_in_blocks) { | |
| 713 dc_right_value = buffer[offset_y][wipe_right][0]; | |
| 714 average = (dc_left_value + dc_right_value) >> 1; | |
| 715 } else { | |
| 716 average = dc_left_value; | |
| 717 } | |
| 718 } else if (wipe_right < compptr->width_in_blocks) { | |
| 719 average = buffer[offset_y][wipe_right][0]; | |
| 720 } else continue; | |
| 721 for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) { | |
| 722 buffer[offset_y][blk_x][0] = (JCOEF) average; | |
| 723 } | |
| 724 } | |
| 725 } | |
| 726 } | |
| 727 } | |
| 728 | |
| 729 | |
| 730 LOCAL(void) | |
| 731 do_reflect (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 732 JDIMENSION x_crop_offset, | |
| 733 jvirt_barray_ptr *src_coef_arrays, | |
| 734 JDIMENSION drop_width, JDIMENSION drop_height) | |
| 735 /* Reflect - drop content of specified area, similar to wipe, but | |
| 736 * fill with repeated reflections of the outside area, instead of zero. | |
| 737 * NB: y_crop_offset is assumed to be zero. | |
| 738 */ | |
| 739 { | |
| 740 JDIMENSION x_wipe_blocks, wipe_width; | |
| 741 JDIMENSION y_wipe_blocks, wipe_bottom; | |
| 742 JDIMENSION src_blk_x, dst_blk_x; | |
| 743 int ci, k, offset_y; | |
| 744 JBLOCKARRAY buffer; | |
| 745 JBLOCKROW src_row_ptr, dst_row_ptr; | |
| 746 JCOEFPTR src_ptr, dst_ptr; | |
| 747 jpeg_component_info *compptr; | |
| 748 | |
| 749 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 750 compptr = dstinfo->comp_info + ci; | |
| 751 x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 752 wipe_width = drop_width * compptr->h_samp_factor; | |
| 753 wipe_bottom = drop_height * compptr->v_samp_factor; | |
| 754 for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom; | |
| 755 y_wipe_blocks += compptr->v_samp_factor) { | |
| 756 buffer = (*srcinfo->mem->access_virt_barray) | |
| 757 ((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks, | |
| 758 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 759 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 760 if (x_wipe_blocks > 0) { | |
| 761 /* Reflect from left */ | |
| 762 dst_row_ptr = buffer[offset_y] + x_wipe_blocks; | |
| 763 for (dst_blk_x = wipe_width; dst_blk_x > 0;) { | |
| 764 src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ | |
| 765 for (src_blk_x = x_wipe_blocks; | |
| 766 src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) { | |
| 767 dst_ptr = *dst_row_ptr++; /* destination goes right */ | |
| 768 src_ptr = *--src_row_ptr; /* source goes left */ | |
| 769 /* this unrolled loop doesn't need to know which row it's on... */ | |
| 770 for (k = 0; k < DCTSIZE2; k += 2) { | |
| 771 *dst_ptr++ = *src_ptr++; /* copy even column */ | |
| 772 *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ | |
| 773 } | |
| 774 } | |
| 775 } | |
| 776 } else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) { | |
| 777 /* Reflect from right */ | |
| 778 dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width; | |
| 779 for (dst_blk_x = wipe_width; dst_blk_x > 0;) { | |
| 780 src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */ | |
| 781 src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width; | |
| 782 for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) { | |
| 783 dst_ptr = *--dst_row_ptr; /* destination goes left */ | |
| 784 src_ptr = *src_row_ptr++; /* source goes right */ | |
| 785 /* this unrolled loop doesn't need to know which row it's on... */ | |
| 786 for (k = 0; k < DCTSIZE2; k += 2) { | |
| 787 *dst_ptr++ = *src_ptr++; /* copy even column */ | |
| 788 *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ | |
| 789 } | |
| 790 } | |
| 791 } | |
| 792 } else { | |
| 793 FMEMZERO(buffer[offset_y] + x_wipe_blocks, | |
| 794 wipe_width * SIZEOF(JBLOCK)); | |
| 795 } | |
| 796 } | |
| 797 } | |
| 798 } | |
| 799 } | |
| 800 | |
| 801 | |
| 802 LOCAL(void) | |
| 803 do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 804 JDIMENSION x_crop_offset, | |
| 805 jvirt_barray_ptr *src_coef_arrays) | |
| 806 /* Horizontal flip; done in-place, so no separate dest array is required. | |
| 807 * NB: this only works when y_crop_offset is zero. | |
| 808 */ | |
| 809 { | |
| 810 JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; | |
| 811 int ci, k, offset_y; | |
| 812 JBLOCKARRAY buffer; | |
| 813 JCOEFPTR ptr1, ptr2; | |
| 814 JCOEF temp1, temp2; | |
| 815 jpeg_component_info *compptr; | |
| 816 | |
| 817 /* Horizontal mirroring of DCT blocks is accomplished by swapping | |
| 818 * pairs of blocks in-place. Within a DCT block, we perform horizontal | |
| 819 * mirroring by changing the signs of odd-numbered columns. | |
| 820 * Partial iMCUs at the right edge are left untouched. | |
| 821 */ | |
| 822 MCU_cols = srcinfo->output_width / | |
| 823 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 824 | |
| 825 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 826 compptr = dstinfo->comp_info + ci; | |
| 827 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 828 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 829 for (blk_y = 0; blk_y < compptr->height_in_blocks; | |
| 830 blk_y += compptr->v_samp_factor) { | |
| 831 buffer = (*srcinfo->mem->access_virt_barray) | |
| 832 ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, | |
| 833 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 834 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 835 /* Do the mirroring */ | |
| 836 for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { | |
| 837 ptr1 = buffer[offset_y][blk_x]; | |
| 838 ptr2 = buffer[offset_y][comp_width - blk_x - 1]; | |
| 839 /* this unrolled loop doesn't need to know which row it's on... */ | |
| 840 for (k = 0; k < DCTSIZE2; k += 2) { | |
| 841 temp1 = *ptr1; /* swap even column */ | |
| 842 temp2 = *ptr2; | |
| 843 *ptr1++ = temp2; | |
| 844 *ptr2++ = temp1; | |
| 845 temp1 = *ptr1; /* swap odd column with sign change */ | |
| 846 temp2 = *ptr2; | |
| 847 *ptr1++ = -temp2; | |
| 848 *ptr2++ = -temp1; | |
| 849 } | |
| 850 } | |
| 851 if (x_crop_blocks > 0) { | |
| 852 /* Now left-justify the portion of the data to be kept. | |
| 853 * We can't use a single jcopy_block_row() call because that routine | |
| 854 * depends on memcpy(), whose behavior is unspecified for overlapping | |
| 855 * source and destination areas. Sigh. | |
| 856 */ | |
| 857 for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { | |
| 858 jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, | |
| 859 buffer[offset_y] + blk_x, | |
| 860 (JDIMENSION) 1); | |
| 861 } | |
| 862 } | |
| 863 } | |
| 864 } | |
| 865 } | |
| 866 } | |
| 867 | |
| 868 | |
| 869 LOCAL(void) | |
| 870 do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 871 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 872 jvirt_barray_ptr *src_coef_arrays, | |
| 873 jvirt_barray_ptr *dst_coef_arrays) | |
| 874 /* Horizontal flip in general cropping case */ | |
| 875 { | |
| 876 JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; | |
| 877 JDIMENSION x_crop_blocks, y_crop_blocks; | |
| 878 int ci, k, offset_y; | |
| 879 JBLOCKARRAY src_buffer, dst_buffer; | |
| 880 JBLOCKROW src_row_ptr, dst_row_ptr; | |
| 881 JCOEFPTR src_ptr, dst_ptr; | |
| 882 jpeg_component_info *compptr; | |
| 883 | |
| 884 /* Here we must output into a separate array because we can't touch | |
| 885 * different rows of a single virtual array simultaneously. Otherwise, | |
| 886 * this is essentially the same as the routine above. | |
| 887 */ | |
| 888 MCU_cols = srcinfo->output_width / | |
| 889 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 890 | |
| 891 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 892 compptr = dstinfo->comp_info + ci; | |
| 893 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 894 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 895 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 896 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 897 dst_blk_y += compptr->v_samp_factor) { | |
| 898 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 899 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 900 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 901 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 902 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 903 dst_blk_y + y_crop_blocks, | |
| 904 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 905 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 906 dst_row_ptr = dst_buffer[offset_y]; | |
| 907 src_row_ptr = src_buffer[offset_y]; | |
| 908 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | |
| 909 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 910 /* Do the mirrorable blocks */ | |
| 911 dst_ptr = dst_row_ptr[dst_blk_x]; | |
| 912 src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; | |
| 913 /* this unrolled loop doesn't need to know which row it's on... */ | |
| 914 for (k = 0; k < DCTSIZE2; k += 2) { | |
| 915 *dst_ptr++ = *src_ptr++; /* copy even column */ | |
| 916 *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ | |
| 917 } | |
| 918 } else { | |
| 919 /* Copy last partial block(s) verbatim */ | |
| 920 jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, | |
| 921 dst_row_ptr + dst_blk_x, | |
| 922 (JDIMENSION) 1); | |
| 923 } | |
| 924 } | |
| 925 } | |
| 926 } | |
| 927 } | |
| 928 } | |
| 929 | |
| 930 | |
| 931 LOCAL(void) | |
| 932 do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 933 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 934 jvirt_barray_ptr *src_coef_arrays, | |
| 935 jvirt_barray_ptr *dst_coef_arrays) | |
| 936 /* Vertical flip */ | |
| 937 { | |
| 938 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; | |
| 939 JDIMENSION x_crop_blocks, y_crop_blocks; | |
| 940 int ci, i, j, offset_y; | |
| 941 JBLOCKARRAY src_buffer, dst_buffer; | |
| 942 JBLOCKROW src_row_ptr, dst_row_ptr; | |
| 943 JCOEFPTR src_ptr, dst_ptr; | |
| 944 jpeg_component_info *compptr; | |
| 945 | |
| 946 /* We output into a separate array because we can't touch different | |
| 947 * rows of the source virtual array simultaneously. Otherwise, this | |
| 948 * is a pretty straightforward analog of horizontal flip. | |
| 949 * Within a DCT block, vertical mirroring is done by changing the signs | |
| 950 * of odd-numbered rows. | |
| 951 * Partial iMCUs at the bottom edge are copied verbatim. | |
| 952 */ | |
| 953 MCU_rows = srcinfo->output_height / | |
| 954 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 955 | |
| 956 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 957 compptr = dstinfo->comp_info + ci; | |
| 958 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 959 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 960 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 961 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 962 dst_blk_y += compptr->v_samp_factor) { | |
| 963 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 964 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 965 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 966 if (y_crop_blocks + dst_blk_y < comp_height) { | |
| 967 /* Row is within the mirrorable area. */ | |
| 968 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 969 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 970 comp_height - y_crop_blocks - dst_blk_y - | |
| 971 (JDIMENSION) compptr->v_samp_factor, | |
| 972 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 973 } else { | |
| 974 /* Bottom-edge blocks will be copied verbatim. */ | |
| 975 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 976 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 977 dst_blk_y + y_crop_blocks, | |
| 978 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 979 } | |
| 980 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 981 if (y_crop_blocks + dst_blk_y < comp_height) { | |
| 982 /* Row is within the mirrorable area. */ | |
| 983 dst_row_ptr = dst_buffer[offset_y]; | |
| 984 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; | |
| 985 src_row_ptr += x_crop_blocks; | |
| 986 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | |
| 987 dst_blk_x++) { | |
| 988 dst_ptr = dst_row_ptr[dst_blk_x]; | |
| 989 src_ptr = src_row_ptr[dst_blk_x]; | |
| 990 for (i = 0; i < DCTSIZE; i += 2) { | |
| 991 /* copy even row */ | |
| 992 for (j = 0; j < DCTSIZE; j++) | |
| 993 *dst_ptr++ = *src_ptr++; | |
| 994 /* copy odd row with sign change */ | |
| 995 for (j = 0; j < DCTSIZE; j++) | |
| 996 *dst_ptr++ = - *src_ptr++; | |
| 997 } | |
| 998 } | |
| 999 } else { | |
| 1000 /* Just copy row verbatim. */ | |
| 1001 jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, | |
| 1002 dst_buffer[offset_y], | |
| 1003 compptr->width_in_blocks); | |
| 1004 } | |
| 1005 } | |
| 1006 } | |
| 1007 } | |
| 1008 } | |
| 1009 | |
| 1010 | |
| 1011 LOCAL(void) | |
| 1012 do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 1013 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 1014 jvirt_barray_ptr *src_coef_arrays, | |
| 1015 jvirt_barray_ptr *dst_coef_arrays) | |
| 1016 /* Transpose source into destination */ | |
| 1017 { | |
| 1018 JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; | |
| 1019 int ci, i, j, offset_x, offset_y; | |
| 1020 JBLOCKARRAY src_buffer, dst_buffer; | |
| 1021 JCOEFPTR src_ptr, dst_ptr; | |
| 1022 jpeg_component_info *compptr; | |
| 1023 | |
| 1024 /* Transposing pixels within a block just requires transposing the | |
| 1025 * DCT coefficients. | |
| 1026 * Partial iMCUs at the edges require no special treatment; we simply | |
| 1027 * process all the available DCT blocks for every component. | |
| 1028 */ | |
| 1029 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 1030 compptr = dstinfo->comp_info + ci; | |
| 1031 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 1032 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 1033 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 1034 dst_blk_y += compptr->v_samp_factor) { | |
| 1035 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1036 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 1037 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 1038 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 1039 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | |
| 1040 dst_blk_x += compptr->h_samp_factor) { | |
| 1041 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1042 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1043 dst_blk_x + x_crop_blocks, | |
| 1044 (JDIMENSION) compptr->h_samp_factor, FALSE); | |
| 1045 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | |
| 1046 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | |
| 1047 src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; | |
| 1048 for (i = 0; i < DCTSIZE; i++) | |
| 1049 for (j = 0; j < DCTSIZE; j++) | |
| 1050 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1051 } | |
| 1052 } | |
| 1053 } | |
| 1054 } | |
| 1055 } | |
| 1056 } | |
| 1057 | |
| 1058 | |
| 1059 LOCAL(void) | |
| 1060 do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 1061 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 1062 jvirt_barray_ptr *src_coef_arrays, | |
| 1063 jvirt_barray_ptr *dst_coef_arrays) | |
| 1064 /* 90 degree rotation is equivalent to | |
| 1065 * 1. Transposing the image; | |
| 1066 * 2. Horizontal mirroring. | |
| 1067 * These two steps are merged into a single processing routine. | |
| 1068 */ | |
| 1069 { | |
| 1070 JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; | |
| 1071 JDIMENSION x_crop_blocks, y_crop_blocks; | |
| 1072 int ci, i, j, offset_x, offset_y; | |
| 1073 JBLOCKARRAY src_buffer, dst_buffer; | |
| 1074 JCOEFPTR src_ptr, dst_ptr; | |
| 1075 jpeg_component_info *compptr; | |
| 1076 | |
| 1077 /* Because of the horizontal mirror step, we can't process partial iMCUs | |
| 1078 * at the (output) right edge properly. They just get transposed and | |
| 1079 * not mirrored. | |
| 1080 */ | |
| 1081 MCU_cols = srcinfo->output_height / | |
| 1082 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 1083 | |
| 1084 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 1085 compptr = dstinfo->comp_info + ci; | |
| 1086 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 1087 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 1088 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 1089 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 1090 dst_blk_y += compptr->v_samp_factor) { | |
| 1091 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1092 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 1093 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 1094 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 1095 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | |
| 1096 dst_blk_x += compptr->h_samp_factor) { | |
| 1097 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1098 /* Block is within the mirrorable area. */ | |
| 1099 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1100 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1101 comp_width - x_crop_blocks - dst_blk_x - | |
| 1102 (JDIMENSION) compptr->h_samp_factor, | |
| 1103 (JDIMENSION) compptr->h_samp_factor, FALSE); | |
| 1104 } else { | |
| 1105 /* Edge blocks are transposed but not mirrored. */ | |
| 1106 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1107 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1108 dst_blk_x + x_crop_blocks, | |
| 1109 (JDIMENSION) compptr->h_samp_factor, FALSE); | |
| 1110 } | |
| 1111 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | |
| 1112 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | |
| 1113 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1114 /* Block is within the mirrorable area. */ | |
| 1115 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] | |
| 1116 [dst_blk_y + offset_y + y_crop_blocks]; | |
| 1117 for (i = 0; i < DCTSIZE; i++) { | |
| 1118 for (j = 0; j < DCTSIZE; j++) | |
| 1119 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1120 i++; | |
| 1121 for (j = 0; j < DCTSIZE; j++) | |
| 1122 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; | |
| 1123 } | |
| 1124 } else { | |
| 1125 /* Edge blocks are transposed but not mirrored. */ | |
| 1126 src_ptr = src_buffer[offset_x] | |
| 1127 [dst_blk_y + offset_y + y_crop_blocks]; | |
| 1128 for (i = 0; i < DCTSIZE; i++) | |
| 1129 for (j = 0; j < DCTSIZE; j++) | |
| 1130 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1131 } | |
| 1132 } | |
| 1133 } | |
| 1134 } | |
| 1135 } | |
| 1136 } | |
| 1137 } | |
| 1138 | |
| 1139 | |
| 1140 LOCAL(void) | |
| 1141 do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 1142 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 1143 jvirt_barray_ptr *src_coef_arrays, | |
| 1144 jvirt_barray_ptr *dst_coef_arrays) | |
| 1145 /* 270 degree rotation is equivalent to | |
| 1146 * 1. Horizontal mirroring; | |
| 1147 * 2. Transposing the image. | |
| 1148 * These two steps are merged into a single processing routine. | |
| 1149 */ | |
| 1150 { | |
| 1151 JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; | |
| 1152 JDIMENSION x_crop_blocks, y_crop_blocks; | |
| 1153 int ci, i, j, offset_x, offset_y; | |
| 1154 JBLOCKARRAY src_buffer, dst_buffer; | |
| 1155 JCOEFPTR src_ptr, dst_ptr; | |
| 1156 jpeg_component_info *compptr; | |
| 1157 | |
| 1158 /* Because of the horizontal mirror step, we can't process partial iMCUs | |
| 1159 * at the (output) bottom edge properly. They just get transposed and | |
| 1160 * not mirrored. | |
| 1161 */ | |
| 1162 MCU_rows = srcinfo->output_width / | |
| 1163 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 1164 | |
| 1165 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 1166 compptr = dstinfo->comp_info + ci; | |
| 1167 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 1168 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 1169 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 1170 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 1171 dst_blk_y += compptr->v_samp_factor) { | |
| 1172 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1173 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 1174 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 1175 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 1176 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | |
| 1177 dst_blk_x += compptr->h_samp_factor) { | |
| 1178 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1179 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1180 dst_blk_x + x_crop_blocks, | |
| 1181 (JDIMENSION) compptr->h_samp_factor, FALSE); | |
| 1182 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | |
| 1183 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | |
| 1184 if (y_crop_blocks + dst_blk_y < comp_height) { | |
| 1185 /* Block is within the mirrorable area. */ | |
| 1186 src_ptr = src_buffer[offset_x] | |
| 1187 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; | |
| 1188 for (i = 0; i < DCTSIZE; i++) { | |
| 1189 for (j = 0; j < DCTSIZE; j++) { | |
| 1190 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1191 j++; | |
| 1192 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; | |
| 1193 } | |
| 1194 } | |
| 1195 } else { | |
| 1196 /* Edge blocks are transposed but not mirrored. */ | |
| 1197 src_ptr = src_buffer[offset_x] | |
| 1198 [dst_blk_y + offset_y + y_crop_blocks]; | |
| 1199 for (i = 0; i < DCTSIZE; i++) | |
| 1200 for (j = 0; j < DCTSIZE; j++) | |
| 1201 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1202 } | |
| 1203 } | |
| 1204 } | |
| 1205 } | |
| 1206 } | |
| 1207 } | |
| 1208 } | |
| 1209 | |
| 1210 | |
| 1211 LOCAL(void) | |
| 1212 do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 1213 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 1214 jvirt_barray_ptr *src_coef_arrays, | |
| 1215 jvirt_barray_ptr *dst_coef_arrays) | |
| 1216 /* 180 degree rotation is equivalent to | |
| 1217 * 1. Vertical mirroring; | |
| 1218 * 2. Horizontal mirroring. | |
| 1219 * These two steps are merged into a single processing routine. | |
| 1220 */ | |
| 1221 { | |
| 1222 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; | |
| 1223 JDIMENSION x_crop_blocks, y_crop_blocks; | |
| 1224 int ci, i, j, offset_y; | |
| 1225 JBLOCKARRAY src_buffer, dst_buffer; | |
| 1226 JBLOCKROW src_row_ptr, dst_row_ptr; | |
| 1227 JCOEFPTR src_ptr, dst_ptr; | |
| 1228 jpeg_component_info *compptr; | |
| 1229 | |
| 1230 MCU_cols = srcinfo->output_width / | |
| 1231 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 1232 MCU_rows = srcinfo->output_height / | |
| 1233 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 1234 | |
| 1235 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 1236 compptr = dstinfo->comp_info + ci; | |
| 1237 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 1238 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 1239 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 1240 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 1241 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 1242 dst_blk_y += compptr->v_samp_factor) { | |
| 1243 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1244 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 1245 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 1246 if (y_crop_blocks + dst_blk_y < comp_height) { | |
| 1247 /* Row is within the vertically mirrorable area. */ | |
| 1248 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1249 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1250 comp_height - y_crop_blocks - dst_blk_y - | |
| 1251 (JDIMENSION) compptr->v_samp_factor, | |
| 1252 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 1253 } else { | |
| 1254 /* Bottom-edge rows are only mirrored horizontally. */ | |
| 1255 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1256 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1257 dst_blk_y + y_crop_blocks, | |
| 1258 (JDIMENSION) compptr->v_samp_factor, FALSE); | |
| 1259 } | |
| 1260 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 1261 dst_row_ptr = dst_buffer[offset_y]; | |
| 1262 if (y_crop_blocks + dst_blk_y < comp_height) { | |
| 1263 /* Row is within the mirrorable area. */ | |
| 1264 src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; | |
| 1265 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | |
| 1266 dst_ptr = dst_row_ptr[dst_blk_x]; | |
| 1267 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1268 /* Process the blocks that can be mirrored both ways. */ | |
| 1269 src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; | |
| 1270 for (i = 0; i < DCTSIZE; i += 2) { | |
| 1271 /* For even row, negate every odd column. */ | |
| 1272 for (j = 0; j < DCTSIZE; j += 2) { | |
| 1273 *dst_ptr++ = *src_ptr++; | |
| 1274 *dst_ptr++ = - *src_ptr++; | |
| 1275 } | |
| 1276 /* For odd row, negate every even column. */ | |
| 1277 for (j = 0; j < DCTSIZE; j += 2) { | |
| 1278 *dst_ptr++ = - *src_ptr++; | |
| 1279 *dst_ptr++ = *src_ptr++; | |
| 1280 } | |
| 1281 } | |
| 1282 } else { | |
| 1283 /* Any remaining right-edge blocks are only mirrored vertically. */ | |
| 1284 src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; | |
| 1285 for (i = 0; i < DCTSIZE; i += 2) { | |
| 1286 for (j = 0; j < DCTSIZE; j++) | |
| 1287 *dst_ptr++ = *src_ptr++; | |
| 1288 for (j = 0; j < DCTSIZE; j++) | |
| 1289 *dst_ptr++ = - *src_ptr++; | |
| 1290 } | |
| 1291 } | |
| 1292 } | |
| 1293 } else { | |
| 1294 /* Remaining rows are just mirrored horizontally. */ | |
| 1295 src_row_ptr = src_buffer[offset_y]; | |
| 1296 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { | |
| 1297 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1298 /* Process the blocks that can be mirrored. */ | |
| 1299 dst_ptr = dst_row_ptr[dst_blk_x]; | |
| 1300 src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; | |
| 1301 for (i = 0; i < DCTSIZE2; i += 2) { | |
| 1302 *dst_ptr++ = *src_ptr++; | |
| 1303 *dst_ptr++ = - *src_ptr++; | |
| 1304 } | |
| 1305 } else { | |
| 1306 /* Any remaining right-edge blocks are only copied. */ | |
| 1307 jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, | |
| 1308 dst_row_ptr + dst_blk_x, | |
| 1309 (JDIMENSION) 1); | |
| 1310 } | |
| 1311 } | |
| 1312 } | |
| 1313 } | |
| 1314 } | |
| 1315 } | |
| 1316 } | |
| 1317 | |
| 1318 | |
| 1319 LOCAL(void) | |
| 1320 do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 1321 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, | |
| 1322 jvirt_barray_ptr *src_coef_arrays, | |
| 1323 jvirt_barray_ptr *dst_coef_arrays) | |
| 1324 /* Transverse transpose is equivalent to | |
| 1325 * 1. 180 degree rotation; | |
| 1326 * 2. Transposition; | |
| 1327 * or | |
| 1328 * 1. Horizontal mirroring; | |
| 1329 * 2. Transposition; | |
| 1330 * 3. Horizontal mirroring. | |
| 1331 * These steps are merged into a single processing routine. | |
| 1332 */ | |
| 1333 { | |
| 1334 JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; | |
| 1335 JDIMENSION x_crop_blocks, y_crop_blocks; | |
| 1336 int ci, i, j, offset_x, offset_y; | |
| 1337 JBLOCKARRAY src_buffer, dst_buffer; | |
| 1338 JCOEFPTR src_ptr, dst_ptr; | |
| 1339 jpeg_component_info *compptr; | |
| 1340 | |
| 1341 MCU_cols = srcinfo->output_height / | |
| 1342 (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); | |
| 1343 MCU_rows = srcinfo->output_width / | |
| 1344 (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); | |
| 1345 | |
| 1346 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 1347 compptr = dstinfo->comp_info + ci; | |
| 1348 comp_width = MCU_cols * compptr->h_samp_factor; | |
| 1349 comp_height = MCU_rows * compptr->v_samp_factor; | |
| 1350 x_crop_blocks = x_crop_offset * compptr->h_samp_factor; | |
| 1351 y_crop_blocks = y_crop_offset * compptr->v_samp_factor; | |
| 1352 for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; | |
| 1353 dst_blk_y += compptr->v_samp_factor) { | |
| 1354 dst_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1355 ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, | |
| 1356 (JDIMENSION) compptr->v_samp_factor, TRUE); | |
| 1357 for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { | |
| 1358 for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; | |
| 1359 dst_blk_x += compptr->h_samp_factor) { | |
| 1360 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1361 /* Block is within the mirrorable area. */ | |
| 1362 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1363 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1364 comp_width - x_crop_blocks - dst_blk_x - | |
| 1365 (JDIMENSION) compptr->h_samp_factor, | |
| 1366 (JDIMENSION) compptr->h_samp_factor, FALSE); | |
| 1367 } else { | |
| 1368 src_buffer = (*srcinfo->mem->access_virt_barray) | |
| 1369 ((j_common_ptr) srcinfo, src_coef_arrays[ci], | |
| 1370 dst_blk_x + x_crop_blocks, | |
| 1371 (JDIMENSION) compptr->h_samp_factor, FALSE); | |
| 1372 } | |
| 1373 for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { | |
| 1374 dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; | |
| 1375 if (y_crop_blocks + dst_blk_y < comp_height) { | |
| 1376 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1377 /* Block is within the mirrorable area. */ | |
| 1378 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] | |
| 1379 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; | |
| 1380 for (i = 0; i < DCTSIZE; i++) { | |
| 1381 for (j = 0; j < DCTSIZE; j++) { | |
| 1382 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1383 j++; | |
| 1384 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; | |
| 1385 } | |
| 1386 i++; | |
| 1387 for (j = 0; j < DCTSIZE; j++) { | |
| 1388 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; | |
| 1389 j++; | |
| 1390 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1391 } | |
| 1392 } | |
| 1393 } else { | |
| 1394 /* Right-edge blocks are mirrored in y only */ | |
| 1395 src_ptr = src_buffer[offset_x] | |
| 1396 [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; | |
| 1397 for (i = 0; i < DCTSIZE; i++) { | |
| 1398 for (j = 0; j < DCTSIZE; j++) { | |
| 1399 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1400 j++; | |
| 1401 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; | |
| 1402 } | |
| 1403 } | |
| 1404 } | |
| 1405 } else { | |
| 1406 if (x_crop_blocks + dst_blk_x < comp_width) { | |
| 1407 /* Bottom-edge blocks are mirrored in x only */ | |
| 1408 src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] | |
| 1409 [dst_blk_y + offset_y + y_crop_blocks]; | |
| 1410 for (i = 0; i < DCTSIZE; i++) { | |
| 1411 for (j = 0; j < DCTSIZE; j++) | |
| 1412 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1413 i++; | |
| 1414 for (j = 0; j < DCTSIZE; j++) | |
| 1415 dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; | |
| 1416 } | |
| 1417 } else { | |
| 1418 /* At lower right corner, just transpose, no mirroring */ | |
| 1419 src_ptr = src_buffer[offset_x] | |
| 1420 [dst_blk_y + offset_y + y_crop_blocks]; | |
| 1421 for (i = 0; i < DCTSIZE; i++) | |
| 1422 for (j = 0; j < DCTSIZE; j++) | |
| 1423 dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; | |
| 1424 } | |
| 1425 } | |
| 1426 } | |
| 1427 } | |
| 1428 } | |
| 1429 } | |
| 1430 } | |
| 1431 } | |
| 1432 | |
| 1433 | |
| 1434 /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. | |
| 1435 * Returns TRUE if valid integer found, FALSE if not. | |
| 1436 * *strptr is advanced over the digit string, and *result is set to its value. | |
| 1437 */ | |
| 1438 | |
| 1439 LOCAL(boolean) | |
| 1440 jt_read_integer (const char ** strptr, JDIMENSION * result) | |
| 1441 { | |
| 1442 const char * ptr = *strptr; | |
| 1443 JDIMENSION val = 0; | |
| 1444 | |
| 1445 for (; isdigit(*ptr); ptr++) { | |
| 1446 val = val * 10 + (JDIMENSION) (*ptr - '0'); | |
| 1447 } | |
| 1448 *result = val; | |
| 1449 if (ptr == *strptr) | |
| 1450 return FALSE; /* oops, no digits */ | |
| 1451 *strptr = ptr; | |
| 1452 return TRUE; | |
| 1453 } | |
| 1454 | |
| 1455 | |
| 1456 /* Parse a crop specification (written in X11 geometry style). | |
| 1457 * The routine returns TRUE if the spec string is valid, FALSE if not. | |
| 1458 * | |
| 1459 * The crop spec string should have the format | |
| 1460 * <width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset> | |
| 1461 * where width, height, xoffset, and yoffset are unsigned integers. | |
| 1462 * Each of the elements can be omitted to indicate a default value. | |
| 1463 * (A weakness of this style is that it is not possible to omit xoffset | |
| 1464 * while specifying yoffset, since they look alike.) | |
| 1465 * | |
| 1466 * This code is loosely based on XParseGeometry from the X11 distribution. | |
| 1467 */ | |
| 1468 | |
| 1469 GLOBAL(boolean) | |
| 1470 jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) | |
| 1471 { | |
| 1472 info->crop = FALSE; | |
| 1473 info->crop_width_set = JCROP_UNSET; | |
| 1474 info->crop_height_set = JCROP_UNSET; | |
| 1475 info->crop_xoffset_set = JCROP_UNSET; | |
| 1476 info->crop_yoffset_set = JCROP_UNSET; | |
| 1477 | |
| 1478 if (isdigit(*spec)) { | |
| 1479 /* fetch width */ | |
| 1480 if (! jt_read_integer(&spec, &info->crop_width)) | |
| 1481 return FALSE; | |
| 1482 if (*spec == 'f' || *spec == 'F') { | |
| 1483 spec++; | |
| 1484 info->crop_width_set = JCROP_FORCE; | |
| 1485 } else if (*spec == 'r' || *spec == 'R') { | |
| 1486 spec++; | |
| 1487 info->crop_width_set = JCROP_REFLECT; | |
| 1488 } else | |
| 1489 info->crop_width_set = JCROP_POS; | |
| 1490 } | |
| 1491 if (*spec == 'x' || *spec == 'X') { | |
| 1492 /* fetch height */ | |
| 1493 spec++; | |
| 1494 if (! jt_read_integer(&spec, &info->crop_height)) | |
| 1495 return FALSE; | |
| 1496 if (*spec == 'f' || *spec == 'F') { | |
| 1497 spec++; | |
| 1498 info->crop_height_set = JCROP_FORCE; | |
| 1499 } else if (*spec == 'r' || *spec == 'R') { | |
| 1500 spec++; | |
| 1501 info->crop_height_set = JCROP_REFLECT; | |
| 1502 } else | |
| 1503 info->crop_height_set = JCROP_POS; | |
| 1504 } | |
| 1505 if (*spec == '+' || *spec == '-') { | |
| 1506 /* fetch xoffset */ | |
| 1507 info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; | |
| 1508 spec++; | |
| 1509 if (! jt_read_integer(&spec, &info->crop_xoffset)) | |
| 1510 return FALSE; | |
| 1511 } | |
| 1512 if (*spec == '+' || *spec == '-') { | |
| 1513 /* fetch yoffset */ | |
| 1514 info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; | |
| 1515 spec++; | |
| 1516 if (! jt_read_integer(&spec, &info->crop_yoffset)) | |
| 1517 return FALSE; | |
| 1518 } | |
| 1519 /* We had better have gotten to the end of the string. */ | |
| 1520 if (*spec != '\0') | |
| 1521 return FALSE; | |
| 1522 info->crop = TRUE; | |
| 1523 return TRUE; | |
| 1524 } | |
| 1525 | |
| 1526 | |
| 1527 /* Trim off any partial iMCUs on the indicated destination edge */ | |
| 1528 | |
| 1529 LOCAL(void) | |
| 1530 trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) | |
| 1531 { | |
| 1532 JDIMENSION MCU_cols; | |
| 1533 | |
| 1534 MCU_cols = info->output_width / info->iMCU_sample_width; | |
| 1535 if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == | |
| 1536 full_width / info->iMCU_sample_width) | |
| 1537 info->output_width = MCU_cols * info->iMCU_sample_width; | |
| 1538 } | |
| 1539 | |
| 1540 LOCAL(void) | |
| 1541 trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) | |
| 1542 { | |
| 1543 JDIMENSION MCU_rows; | |
| 1544 | |
| 1545 MCU_rows = info->output_height / info->iMCU_sample_height; | |
| 1546 if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == | |
| 1547 full_height / info->iMCU_sample_height) | |
| 1548 info->output_height = MCU_rows * info->iMCU_sample_height; | |
| 1549 } | |
| 1550 | |
| 1551 | |
| 1552 /* Request any required workspace. | |
| 1553 * | |
| 1554 * This routine figures out the size that the output image will be | |
| 1555 * (which implies that all the transform parameters must be set before | |
| 1556 * it is called). | |
| 1557 * | |
| 1558 * We allocate the workspace virtual arrays from the source decompression | |
| 1559 * object, so that all the arrays (both the original data and the workspace) | |
| 1560 * will be taken into account while making memory management decisions. | |
| 1561 * Hence, this routine must be called after jpeg_read_header (which reads | |
| 1562 * the image dimensions) and before jpeg_read_coefficients (which realizes | |
| 1563 * the source's virtual arrays). | |
| 1564 * | |
| 1565 * This function returns FALSE right away if -perfect is given | |
| 1566 * and transformation is not perfect. Otherwise returns TRUE. | |
| 1567 */ | |
| 1568 | |
| 1569 GLOBAL(boolean) | |
| 1570 jtransform_request_workspace (j_decompress_ptr srcinfo, | |
| 1571 jpeg_transform_info *info) | |
| 1572 { | |
| 1573 jvirt_barray_ptr *coef_arrays; | |
| 1574 boolean need_workspace, transpose_it; | |
| 1575 jpeg_component_info *compptr; | |
| 1576 JDIMENSION xoffset, yoffset, dtemp; | |
| 1577 JDIMENSION width_in_iMCUs, height_in_iMCUs; | |
| 1578 JDIMENSION width_in_blocks, height_in_blocks; | |
| 1579 int itemp, ci, h_samp_factor, v_samp_factor; | |
| 1580 | |
| 1581 /* Determine number of components in output image */ | |
| 1582 if (info->force_grayscale && | |
| 1583 (srcinfo->jpeg_color_space == JCS_YCbCr || | |
| 1584 srcinfo->jpeg_color_space == JCS_BG_YCC) && | |
| 1585 srcinfo->num_components == 3) | |
| 1586 /* We'll only process the first component */ | |
| 1587 info->num_components = 1; | |
| 1588 else | |
| 1589 /* Process all the components */ | |
| 1590 info->num_components = srcinfo->num_components; | |
| 1591 | |
| 1592 /* Compute output image dimensions and related values. */ | |
| 1593 jpeg_core_output_dimensions(srcinfo); | |
| 1594 | |
| 1595 /* Return right away if -perfect is given and transformation is not perfect. | |
| 1596 */ | |
| 1597 if (info->perfect) { | |
| 1598 if (info->num_components == 1) { | |
| 1599 if (!jtransform_perfect_transform(srcinfo->output_width, | |
| 1600 srcinfo->output_height, | |
| 1601 srcinfo->min_DCT_h_scaled_size, | |
| 1602 srcinfo->min_DCT_v_scaled_size, | |
| 1603 info->transform)) | |
| 1604 return FALSE; | |
| 1605 } else { | |
| 1606 if (!jtransform_perfect_transform(srcinfo->output_width, | |
| 1607 srcinfo->output_height, | |
| 1608 srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size, | |
| 1609 srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size, | |
| 1610 info->transform)) | |
| 1611 return FALSE; | |
| 1612 } | |
| 1613 } | |
| 1614 | |
| 1615 /* If there is only one output component, force the iMCU size to be 1; | |
| 1616 * else use the source iMCU size. (This allows us to do the right thing | |
| 1617 * when reducing color to grayscale, and also provides a handy way of | |
| 1618 * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) | |
| 1619 */ | |
| 1620 switch (info->transform) { | |
| 1621 case JXFORM_TRANSPOSE: | |
| 1622 case JXFORM_TRANSVERSE: | |
| 1623 case JXFORM_ROT_90: | |
| 1624 case JXFORM_ROT_270: | |
| 1625 info->output_width = srcinfo->output_height; | |
| 1626 info->output_height = srcinfo->output_width; | |
| 1627 if (info->num_components == 1) { | |
| 1628 info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size; | |
| 1629 info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size; | |
| 1630 } else { | |
| 1631 info->iMCU_sample_width = | |
| 1632 srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; | |
| 1633 info->iMCU_sample_height = | |
| 1634 srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; | |
| 1635 } | |
| 1636 break; | |
| 1637 default: | |
| 1638 info->output_width = srcinfo->output_width; | |
| 1639 info->output_height = srcinfo->output_height; | |
| 1640 if (info->num_components == 1) { | |
| 1641 info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size; | |
| 1642 info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size; | |
| 1643 } else { | |
| 1644 info->iMCU_sample_width = | |
| 1645 srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; | |
| 1646 info->iMCU_sample_height = | |
| 1647 srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; | |
| 1648 } | |
| 1649 } | |
| 1650 | |
| 1651 /* If cropping has been requested, compute the crop area's position and | |
| 1652 * dimensions, ensuring that its upper left corner falls at an iMCU boundary. | |
| 1653 */ | |
| 1654 if (info->crop) { | |
| 1655 /* Insert default values for unset crop parameters */ | |
| 1656 if (info->crop_xoffset_set == JCROP_UNSET) | |
| 1657 info->crop_xoffset = 0; /* default to +0 */ | |
| 1658 if (info->crop_yoffset_set == JCROP_UNSET) | |
| 1659 info->crop_yoffset = 0; /* default to +0 */ | |
| 1660 if (info->crop_width_set == JCROP_UNSET) { | |
| 1661 if (info->crop_xoffset >= info->output_width) | |
| 1662 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | |
| 1663 info->crop_width = info->output_width - info->crop_xoffset; | |
| 1664 } else { | |
| 1665 /* Check for crop extension */ | |
| 1666 if (info->crop_width > info->output_width) { | |
| 1667 /* Crop extension does not work when transforming! */ | |
| 1668 if (info->transform != JXFORM_NONE || | |
| 1669 info->crop_xoffset >= info->crop_width || | |
| 1670 info->crop_xoffset > info->crop_width - info->output_width) | |
| 1671 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | |
| 1672 } else { | |
| 1673 if (info->crop_xoffset >= info->output_width || | |
| 1674 info->crop_width <= 0 || | |
| 1675 info->crop_xoffset > info->output_width - info->crop_width) | |
| 1676 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | |
| 1677 } | |
| 1678 } | |
| 1679 if (info->crop_height_set == JCROP_UNSET) { | |
| 1680 if (info->crop_yoffset >= info->output_height) | |
| 1681 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | |
| 1682 info->crop_height = info->output_height - info->crop_yoffset; | |
| 1683 } else { | |
| 1684 /* Check for crop extension */ | |
| 1685 if (info->crop_height > info->output_height) { | |
| 1686 /* Crop extension does not work when transforming! */ | |
| 1687 if (info->transform != JXFORM_NONE || | |
| 1688 info->crop_yoffset >= info->crop_height || | |
| 1689 info->crop_yoffset > info->crop_height - info->output_height) | |
| 1690 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | |
| 1691 } else { | |
| 1692 if (info->crop_yoffset >= info->output_height || | |
| 1693 info->crop_height <= 0 || | |
| 1694 info->crop_yoffset > info->output_height - info->crop_height) | |
| 1695 ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); | |
| 1696 } | |
| 1697 } | |
| 1698 /* Convert negative crop offsets into regular offsets */ | |
| 1699 if (info->crop_xoffset_set != JCROP_NEG) | |
| 1700 xoffset = info->crop_xoffset; | |
| 1701 else if (info->crop_width > info->output_width) /* crop extension */ | |
| 1702 xoffset = info->crop_width - info->output_width - info->crop_xoffset; | |
| 1703 else | |
| 1704 xoffset = info->output_width - info->crop_width - info->crop_xoffset; | |
| 1705 if (info->crop_yoffset_set != JCROP_NEG) | |
| 1706 yoffset = info->crop_yoffset; | |
| 1707 else if (info->crop_height > info->output_height) /* crop extension */ | |
| 1708 yoffset = info->crop_height - info->output_height - info->crop_yoffset; | |
| 1709 else | |
| 1710 yoffset = info->output_height - info->crop_height - info->crop_yoffset; | |
| 1711 /* Now adjust so that upper left corner falls at an iMCU boundary */ | |
| 1712 switch (info->transform) { | |
| 1713 case JXFORM_DROP: | |
| 1714 /* Ensure the effective drop region will not exceed the requested */ | |
| 1715 itemp = info->iMCU_sample_width; | |
| 1716 dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp); | |
| 1717 xoffset += dtemp; | |
| 1718 if (info->crop_width <= dtemp) | |
| 1719 info->drop_width = 0; | |
| 1720 else if (xoffset + info->crop_width - dtemp == info->output_width) | |
| 1721 /* Matching right edge: include partial iMCU */ | |
| 1722 info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp; | |
| 1723 else | |
| 1724 info->drop_width = (info->crop_width - dtemp) / itemp; | |
| 1725 itemp = info->iMCU_sample_height; | |
| 1726 dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp); | |
| 1727 yoffset += dtemp; | |
| 1728 if (info->crop_height <= dtemp) | |
| 1729 info->drop_height = 0; | |
| 1730 else if (yoffset + info->crop_height - dtemp == info->output_height) | |
| 1731 /* Matching bottom edge: include partial iMCU */ | |
| 1732 info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp; | |
| 1733 else | |
| 1734 info->drop_height = (info->crop_height - dtemp) / itemp; | |
| 1735 /* Check if sampling factors match for dropping */ | |
| 1736 if (info->drop_width != 0 && info->drop_height != 0) | |
| 1737 for (ci = 0; ci < info->num_components && | |
| 1738 ci < info->drop_ptr->num_components; ci++) { | |
| 1739 if (info->drop_ptr->comp_info[ci].h_samp_factor * | |
| 1740 srcinfo->max_h_samp_factor != | |
| 1741 srcinfo->comp_info[ci].h_samp_factor * | |
| 1742 info->drop_ptr->max_h_samp_factor) | |
| 1743 ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci, | |
| 1744 info->drop_ptr->comp_info[ci].h_samp_factor, | |
| 1745 info->drop_ptr->max_h_samp_factor, | |
| 1746 srcinfo->comp_info[ci].h_samp_factor, | |
| 1747 srcinfo->max_h_samp_factor, 'h'); | |
| 1748 if (info->drop_ptr->comp_info[ci].v_samp_factor * | |
| 1749 srcinfo->max_v_samp_factor != | |
| 1750 srcinfo->comp_info[ci].v_samp_factor * | |
| 1751 info->drop_ptr->max_v_samp_factor) | |
| 1752 ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci, | |
| 1753 info->drop_ptr->comp_info[ci].v_samp_factor, | |
| 1754 info->drop_ptr->max_v_samp_factor, | |
| 1755 srcinfo->comp_info[ci].v_samp_factor, | |
| 1756 srcinfo->max_v_samp_factor, 'v'); | |
| 1757 } | |
| 1758 break; | |
| 1759 case JXFORM_WIPE: | |
| 1760 /* Ensure the effective wipe region will cover the requested */ | |
| 1761 info->drop_width = (JDIMENSION) jdiv_round_up | |
| 1762 ((long) (info->crop_width + (xoffset % info->iMCU_sample_width)), | |
| 1763 (long) info->iMCU_sample_width); | |
| 1764 info->drop_height = (JDIMENSION) jdiv_round_up | |
| 1765 ((long) (info->crop_height + (yoffset % info->iMCU_sample_height)), | |
| 1766 (long) info->iMCU_sample_height); | |
| 1767 break; | |
| 1768 default: | |
| 1769 /* Ensure the effective crop region will cover the requested */ | |
| 1770 if (info->crop_width_set == JCROP_FORCE || | |
| 1771 info->crop_width > info->output_width) | |
| 1772 info->output_width = info->crop_width; | |
| 1773 else | |
| 1774 info->output_width = | |
| 1775 info->crop_width + (xoffset % info->iMCU_sample_width); | |
| 1776 if (info->crop_height_set == JCROP_FORCE || | |
| 1777 info->crop_height > info->output_height) | |
| 1778 info->output_height = info->crop_height; | |
| 1779 else | |
| 1780 info->output_height = | |
| 1781 info->crop_height + (yoffset % info->iMCU_sample_height); | |
| 1782 } | |
| 1783 /* Save x/y offsets measured in iMCUs */ | |
| 1784 info->x_crop_offset = xoffset / info->iMCU_sample_width; | |
| 1785 info->y_crop_offset = yoffset / info->iMCU_sample_height; | |
| 1786 } else { | |
| 1787 info->x_crop_offset = 0; | |
| 1788 info->y_crop_offset = 0; | |
| 1789 } | |
| 1790 | |
| 1791 /* Figure out whether we need workspace arrays, | |
| 1792 * and if so whether they are transposed relative to the source. | |
| 1793 */ | |
| 1794 need_workspace = FALSE; | |
| 1795 transpose_it = FALSE; | |
| 1796 switch (info->transform) { | |
| 1797 case JXFORM_NONE: | |
| 1798 if (info->x_crop_offset != 0 || info->y_crop_offset != 0 || | |
| 1799 info->output_width > srcinfo->output_width || | |
| 1800 info->output_height > srcinfo->output_height) | |
| 1801 need_workspace = TRUE; | |
| 1802 /* No workspace needed if neither cropping nor transforming */ | |
| 1803 break; | |
| 1804 case JXFORM_FLIP_H: | |
| 1805 if (info->trim) | |
| 1806 trim_right_edge(info, srcinfo->output_width); | |
| 1807 if (info->y_crop_offset != 0) | |
| 1808 need_workspace = TRUE; | |
| 1809 /* do_flip_h_no_crop doesn't need a workspace array */ | |
| 1810 break; | |
| 1811 case JXFORM_FLIP_V: | |
| 1812 if (info->trim) | |
| 1813 trim_bottom_edge(info, srcinfo->output_height); | |
| 1814 /* Need workspace arrays having same dimensions as source image. */ | |
| 1815 need_workspace = TRUE; | |
| 1816 break; | |
| 1817 case JXFORM_TRANSPOSE: | |
| 1818 /* transpose does NOT have to trim anything */ | |
| 1819 /* Need workspace arrays having transposed dimensions. */ | |
| 1820 need_workspace = TRUE; | |
| 1821 transpose_it = TRUE; | |
| 1822 break; | |
| 1823 case JXFORM_TRANSVERSE: | |
| 1824 if (info->trim) { | |
| 1825 trim_right_edge(info, srcinfo->output_height); | |
| 1826 trim_bottom_edge(info, srcinfo->output_width); | |
| 1827 } | |
| 1828 /* Need workspace arrays having transposed dimensions. */ | |
| 1829 need_workspace = TRUE; | |
| 1830 transpose_it = TRUE; | |
| 1831 break; | |
| 1832 case JXFORM_ROT_90: | |
| 1833 if (info->trim) | |
| 1834 trim_right_edge(info, srcinfo->output_height); | |
| 1835 /* Need workspace arrays having transposed dimensions. */ | |
| 1836 need_workspace = TRUE; | |
| 1837 transpose_it = TRUE; | |
| 1838 break; | |
| 1839 case JXFORM_ROT_180: | |
| 1840 if (info->trim) { | |
| 1841 trim_right_edge(info, srcinfo->output_width); | |
| 1842 trim_bottom_edge(info, srcinfo->output_height); | |
| 1843 } | |
| 1844 /* Need workspace arrays having same dimensions as source image. */ | |
| 1845 need_workspace = TRUE; | |
| 1846 break; | |
| 1847 case JXFORM_ROT_270: | |
| 1848 if (info->trim) | |
| 1849 trim_bottom_edge(info, srcinfo->output_width); | |
| 1850 /* Need workspace arrays having transposed dimensions. */ | |
| 1851 need_workspace = TRUE; | |
| 1852 transpose_it = TRUE; | |
| 1853 break; | |
| 1854 case JXFORM_WIPE: | |
| 1855 break; | |
| 1856 case JXFORM_DROP: | |
| 1857 #if DROP_REQUEST_FROM_SRC | |
| 1858 drop_request_from_src(info->drop_ptr, srcinfo); | |
| 1859 #endif | |
| 1860 break; | |
| 1861 } | |
| 1862 | |
| 1863 /* Allocate workspace if needed. | |
| 1864 * Note that we allocate arrays padded out to the next iMCU boundary, | |
| 1865 * so that transform routines need not worry about missing edge blocks. | |
| 1866 */ | |
| 1867 if (need_workspace) { | |
| 1868 coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) | |
| 1869 ((j_common_ptr) srcinfo, JPOOL_IMAGE, | |
| 1870 SIZEOF(jvirt_barray_ptr) * info->num_components); | |
| 1871 width_in_iMCUs = (JDIMENSION) jdiv_round_up | |
| 1872 ((long) info->output_width, (long) info->iMCU_sample_width); | |
| 1873 height_in_iMCUs = (JDIMENSION) jdiv_round_up | |
| 1874 ((long) info->output_height, (long) info->iMCU_sample_height); | |
| 1875 for (ci = 0; ci < info->num_components; ci++) { | |
| 1876 compptr = srcinfo->comp_info + ci; | |
| 1877 if (info->num_components == 1) { | |
| 1878 /* we're going to force samp factors to 1x1 in this case */ | |
| 1879 h_samp_factor = v_samp_factor = 1; | |
| 1880 } else if (transpose_it) { | |
| 1881 h_samp_factor = compptr->v_samp_factor; | |
| 1882 v_samp_factor = compptr->h_samp_factor; | |
| 1883 } else { | |
| 1884 h_samp_factor = compptr->h_samp_factor; | |
| 1885 v_samp_factor = compptr->v_samp_factor; | |
| 1886 } | |
| 1887 width_in_blocks = width_in_iMCUs * h_samp_factor; | |
| 1888 height_in_blocks = height_in_iMCUs * v_samp_factor; | |
| 1889 coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) | |
| 1890 ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, | |
| 1891 width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); | |
| 1892 } | |
| 1893 info->workspace_coef_arrays = coef_arrays; | |
| 1894 } else | |
| 1895 info->workspace_coef_arrays = NULL; | |
| 1896 | |
| 1897 return TRUE; | |
| 1898 } | |
| 1899 | |
| 1900 | |
| 1901 /* Transpose destination image parameters */ | |
| 1902 | |
| 1903 LOCAL(void) | |
| 1904 transpose_critical_parameters (j_compress_ptr dstinfo) | |
| 1905 { | |
| 1906 int tblno, i, j, ci, itemp; | |
| 1907 jpeg_component_info *compptr; | |
| 1908 JQUANT_TBL *qtblptr; | |
| 1909 JDIMENSION jtemp; | |
| 1910 UINT16 qtemp; | |
| 1911 | |
| 1912 /* Transpose image dimensions */ | |
| 1913 jtemp = dstinfo->image_width; | |
| 1914 dstinfo->image_width = dstinfo->image_height; | |
| 1915 dstinfo->image_height = jtemp; | |
| 1916 itemp = dstinfo->min_DCT_h_scaled_size; | |
| 1917 dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; | |
| 1918 dstinfo->min_DCT_v_scaled_size = itemp; | |
| 1919 | |
| 1920 /* Transpose sampling factors */ | |
| 1921 for (ci = 0; ci < dstinfo->num_components; ci++) { | |
| 1922 compptr = dstinfo->comp_info + ci; | |
| 1923 itemp = compptr->h_samp_factor; | |
| 1924 compptr->h_samp_factor = compptr->v_samp_factor; | |
| 1925 compptr->v_samp_factor = itemp; | |
| 1926 } | |
| 1927 | |
| 1928 /* Transpose quantization tables */ | |
| 1929 for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { | |
| 1930 qtblptr = dstinfo->quant_tbl_ptrs[tblno]; | |
| 1931 if (qtblptr != NULL) { | |
| 1932 for (i = 0; i < DCTSIZE; i++) { | |
| 1933 for (j = 0; j < i; j++) { | |
| 1934 qtemp = qtblptr->quantval[i*DCTSIZE+j]; | |
| 1935 qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; | |
| 1936 qtblptr->quantval[j*DCTSIZE+i] = qtemp; | |
| 1937 } | |
| 1938 } | |
| 1939 } | |
| 1940 } | |
| 1941 } | |
| 1942 | |
| 1943 | |
| 1944 /* Adjust Exif image parameters. | |
| 1945 * | |
| 1946 * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. | |
| 1947 */ | |
| 1948 | |
| 1949 LOCAL(void) | |
| 1950 adjust_exif_parameters (JOCTET FAR * data, unsigned int length, | |
| 1951 JDIMENSION new_width, JDIMENSION new_height) | |
| 1952 { | |
| 1953 boolean is_motorola; /* Flag for byte order */ | |
| 1954 unsigned int number_of_tags, tagnum; | |
| 1955 unsigned int firstoffset, offset; | |
| 1956 JDIMENSION new_value; | |
| 1957 | |
| 1958 if (length < 12) return; /* Length of an IFD entry */ | |
| 1959 | |
| 1960 /* Discover byte order */ | |
| 1961 if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) | |
| 1962 is_motorola = FALSE; | |
| 1963 else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) | |
| 1964 is_motorola = TRUE; | |
| 1965 else | |
| 1966 return; | |
| 1967 | |
| 1968 /* Check Tag Mark */ | |
| 1969 if (is_motorola) { | |
| 1970 if (GETJOCTET(data[2]) != 0) return; | |
| 1971 if (GETJOCTET(data[3]) != 0x2A) return; | |
| 1972 } else { | |
| 1973 if (GETJOCTET(data[3]) != 0) return; | |
| 1974 if (GETJOCTET(data[2]) != 0x2A) return; | |
| 1975 } | |
| 1976 | |
| 1977 /* Get first IFD offset (offset to IFD0) */ | |
| 1978 if (is_motorola) { | |
| 1979 if (GETJOCTET(data[4]) != 0) return; | |
| 1980 if (GETJOCTET(data[5]) != 0) return; | |
| 1981 firstoffset = GETJOCTET(data[6]); | |
| 1982 firstoffset <<= 8; | |
| 1983 firstoffset += GETJOCTET(data[7]); | |
| 1984 } else { | |
| 1985 if (GETJOCTET(data[7]) != 0) return; | |
| 1986 if (GETJOCTET(data[6]) != 0) return; | |
| 1987 firstoffset = GETJOCTET(data[5]); | |
| 1988 firstoffset <<= 8; | |
| 1989 firstoffset += GETJOCTET(data[4]); | |
| 1990 } | |
| 1991 if (firstoffset > length - 2) return; /* check end of data segment */ | |
| 1992 | |
| 1993 /* Get the number of directory entries contained in this IFD */ | |
| 1994 if (is_motorola) { | |
| 1995 number_of_tags = GETJOCTET(data[firstoffset]); | |
| 1996 number_of_tags <<= 8; | |
| 1997 number_of_tags += GETJOCTET(data[firstoffset+1]); | |
| 1998 } else { | |
| 1999 number_of_tags = GETJOCTET(data[firstoffset+1]); | |
| 2000 number_of_tags <<= 8; | |
| 2001 number_of_tags += GETJOCTET(data[firstoffset]); | |
| 2002 } | |
| 2003 if (number_of_tags == 0) return; | |
| 2004 firstoffset += 2; | |
| 2005 | |
| 2006 /* Search for ExifSubIFD offset Tag in IFD0 */ | |
| 2007 for (;;) { | |
| 2008 if (firstoffset > length - 12) return; /* check end of data segment */ | |
| 2009 /* Get Tag number */ | |
| 2010 if (is_motorola) { | |
| 2011 tagnum = GETJOCTET(data[firstoffset]); | |
| 2012 tagnum <<= 8; | |
| 2013 tagnum += GETJOCTET(data[firstoffset+1]); | |
| 2014 } else { | |
| 2015 tagnum = GETJOCTET(data[firstoffset+1]); | |
| 2016 tagnum <<= 8; | |
| 2017 tagnum += GETJOCTET(data[firstoffset]); | |
| 2018 } | |
| 2019 if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ | |
| 2020 if (--number_of_tags == 0) return; | |
| 2021 firstoffset += 12; | |
| 2022 } | |
| 2023 | |
| 2024 /* Get the ExifSubIFD offset */ | |
| 2025 if (is_motorola) { | |
| 2026 if (GETJOCTET(data[firstoffset+8]) != 0) return; | |
| 2027 if (GETJOCTET(data[firstoffset+9]) != 0) return; | |
| 2028 offset = GETJOCTET(data[firstoffset+10]); | |
| 2029 offset <<= 8; | |
| 2030 offset += GETJOCTET(data[firstoffset+11]); | |
| 2031 } else { | |
| 2032 if (GETJOCTET(data[firstoffset+11]) != 0) return; | |
| 2033 if (GETJOCTET(data[firstoffset+10]) != 0) return; | |
| 2034 offset = GETJOCTET(data[firstoffset+9]); | |
| 2035 offset <<= 8; | |
| 2036 offset += GETJOCTET(data[firstoffset+8]); | |
| 2037 } | |
| 2038 if (offset > length - 2) return; /* check end of data segment */ | |
| 2039 | |
| 2040 /* Get the number of directory entries contained in this SubIFD */ | |
| 2041 if (is_motorola) { | |
| 2042 number_of_tags = GETJOCTET(data[offset]); | |
| 2043 number_of_tags <<= 8; | |
| 2044 number_of_tags += GETJOCTET(data[offset+1]); | |
| 2045 } else { | |
| 2046 number_of_tags = GETJOCTET(data[offset+1]); | |
| 2047 number_of_tags <<= 8; | |
| 2048 number_of_tags += GETJOCTET(data[offset]); | |
| 2049 } | |
| 2050 if (number_of_tags < 2) return; | |
| 2051 offset += 2; | |
| 2052 | |
| 2053 /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ | |
| 2054 do { | |
| 2055 if (offset > length - 12) return; /* check end of data segment */ | |
| 2056 /* Get Tag number */ | |
| 2057 if (is_motorola) { | |
| 2058 tagnum = GETJOCTET(data[offset]); | |
| 2059 tagnum <<= 8; | |
| 2060 tagnum += GETJOCTET(data[offset+1]); | |
| 2061 } else { | |
| 2062 tagnum = GETJOCTET(data[offset+1]); | |
| 2063 tagnum <<= 8; | |
| 2064 tagnum += GETJOCTET(data[offset]); | |
| 2065 } | |
| 2066 if (tagnum == 0xA002 || tagnum == 0xA003) { | |
| 2067 if (tagnum == 0xA002) | |
| 2068 new_value = new_width; /* ExifImageWidth Tag */ | |
| 2069 else | |
| 2070 new_value = new_height; /* ExifImageHeight Tag */ | |
| 2071 if (is_motorola) { | |
| 2072 data[offset+2] = 0; /* Format = unsigned long (4 octets) */ | |
| 2073 data[offset+3] = 4; | |
| 2074 data[offset+4] = 0; /* Number Of Components = 1 */ | |
| 2075 data[offset+5] = 0; | |
| 2076 data[offset+6] = 0; | |
| 2077 data[offset+7] = 1; | |
| 2078 data[offset+8] = 0; | |
| 2079 data[offset+9] = 0; | |
| 2080 data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); | |
| 2081 data[offset+11] = (JOCTET)(new_value & 0xFF); | |
| 2082 } else { | |
| 2083 data[offset+2] = 4; /* Format = unsigned long (4 octets) */ | |
| 2084 data[offset+3] = 0; | |
| 2085 data[offset+4] = 1; /* Number Of Components = 1 */ | |
| 2086 data[offset+5] = 0; | |
| 2087 data[offset+6] = 0; | |
| 2088 data[offset+7] = 0; | |
| 2089 data[offset+8] = (JOCTET)(new_value & 0xFF); | |
| 2090 data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); | |
| 2091 data[offset+10] = 0; | |
| 2092 data[offset+11] = 0; | |
| 2093 } | |
| 2094 } | |
| 2095 offset += 12; | |
| 2096 } while (--number_of_tags); | |
| 2097 } | |
| 2098 | |
| 2099 | |
| 2100 /* Adjust output image parameters as needed. | |
| 2101 * | |
| 2102 * This must be called after jpeg_copy_critical_parameters() | |
| 2103 * and before jpeg_write_coefficients(). | |
| 2104 * | |
| 2105 * The return value is the set of virtual coefficient arrays to be written | |
| 2106 * (either the ones allocated by jtransform_request_workspace, or the | |
| 2107 * original source data arrays). The caller will need to pass this value | |
| 2108 * to jpeg_write_coefficients(). | |
| 2109 */ | |
| 2110 | |
| 2111 GLOBAL(jvirt_barray_ptr *) | |
| 2112 jtransform_adjust_parameters (j_decompress_ptr srcinfo, | |
| 2113 j_compress_ptr dstinfo, | |
| 2114 jvirt_barray_ptr *src_coef_arrays, | |
| 2115 jpeg_transform_info *info) | |
| 2116 { | |
| 2117 /* If force-to-grayscale is requested, adjust destination parameters */ | |
| 2118 if (info->force_grayscale) { | |
| 2119 /* First, ensure we have YCC or grayscale data, and that the source's | |
| 2120 * Y channel is full resolution. (No reasonable person would make Y | |
| 2121 * be less than full resolution, so actually coping with that case | |
| 2122 * isn't worth extra code space. But we check it to avoid crashing.) | |
| 2123 */ | |
| 2124 if ((((dstinfo->jpeg_color_space == JCS_YCbCr || | |
| 2125 dstinfo->jpeg_color_space == JCS_BG_YCC) && | |
| 2126 dstinfo->num_components == 3) || | |
| 2127 (dstinfo->jpeg_color_space == JCS_GRAYSCALE && | |
| 2128 dstinfo->num_components == 1)) && | |
| 2129 srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && | |
| 2130 srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { | |
| 2131 /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed | |
| 2132 * properly. Among other things, it sets the target h_samp_factor & | |
| 2133 * v_samp_factor to 1, which typically won't match the source. | |
| 2134 * We have to preserve the source's quantization table number, however. | |
| 2135 */ | |
| 2136 int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; | |
| 2137 jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); | |
| 2138 dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; | |
| 2139 } else { | |
| 2140 /* Sorry, can't do it */ | |
| 2141 ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); | |
| 2142 } | |
| 2143 } else if (info->num_components == 1) { | |
| 2144 /* For a single-component source, we force the destination sampling factors | |
| 2145 * to 1x1, with or without force_grayscale. This is useful because some | |
| 2146 * decoders choke on grayscale images with other sampling factors. | |
| 2147 */ | |
| 2148 dstinfo->comp_info[0].h_samp_factor = 1; | |
| 2149 dstinfo->comp_info[0].v_samp_factor = 1; | |
| 2150 } | |
| 2151 | |
| 2152 /* Correct the destination's image dimensions as necessary | |
| 2153 * for rotate/flip, resize, and crop operations. | |
| 2154 */ | |
| 2155 dstinfo->jpeg_width = info->output_width; | |
| 2156 dstinfo->jpeg_height = info->output_height; | |
| 2157 | |
| 2158 /* Transpose destination image parameters, adjust quantization */ | |
| 2159 switch (info->transform) { | |
| 2160 case JXFORM_TRANSPOSE: | |
| 2161 case JXFORM_TRANSVERSE: | |
| 2162 case JXFORM_ROT_90: | |
| 2163 case JXFORM_ROT_270: | |
| 2164 transpose_critical_parameters(dstinfo); | |
| 2165 break; | |
| 2166 case JXFORM_DROP: | |
| 2167 if (info->drop_width != 0 && info->drop_height != 0) | |
| 2168 adjust_quant(srcinfo, src_coef_arrays, | |
| 2169 info->drop_ptr, info->drop_coef_arrays, | |
| 2170 info->trim, dstinfo); | |
| 2171 break; | |
| 2172 default: | |
| 2173 break; | |
| 2174 } | |
| 2175 | |
| 2176 /* Adjust Exif properties */ | |
| 2177 if (srcinfo->marker_list != NULL && | |
| 2178 srcinfo->marker_list->marker == JPEG_APP0+1 && | |
| 2179 srcinfo->marker_list->data_length >= 6 && | |
| 2180 GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && | |
| 2181 GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && | |
| 2182 GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && | |
| 2183 GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && | |
| 2184 GETJOCTET(srcinfo->marker_list->data[4]) == 0 && | |
| 2185 GETJOCTET(srcinfo->marker_list->data[5]) == 0) { | |
| 2186 /* Suppress output of JFIF marker */ | |
| 2187 dstinfo->write_JFIF_header = FALSE; | |
| 2188 /* Adjust Exif image parameters */ | |
| 2189 if (dstinfo->jpeg_width != srcinfo->image_width || | |
| 2190 dstinfo->jpeg_height != srcinfo->image_height) | |
| 2191 /* Align data segment to start of TIFF structure for parsing */ | |
| 2192 adjust_exif_parameters(srcinfo->marker_list->data + 6, | |
| 2193 srcinfo->marker_list->data_length - 6, | |
| 2194 dstinfo->jpeg_width, dstinfo->jpeg_height); | |
| 2195 } | |
| 2196 | |
| 2197 /* Return the appropriate output data set */ | |
| 2198 if (info->workspace_coef_arrays != NULL) | |
| 2199 return info->workspace_coef_arrays; | |
| 2200 return src_coef_arrays; | |
| 2201 } | |
| 2202 | |
| 2203 | |
| 2204 /* Execute the actual transformation, if any. | |
| 2205 * | |
| 2206 * This must be called *after* jpeg_write_coefficients, because it depends | |
| 2207 * on jpeg_write_coefficients to have computed subsidiary values such as | |
| 2208 * the per-component width and height fields in the destination object. | |
| 2209 * | |
| 2210 * Note that some transformations will modify the source data arrays! | |
| 2211 */ | |
| 2212 | |
| 2213 GLOBAL(void) | |
| 2214 jtransform_execute_transform (j_decompress_ptr srcinfo, | |
| 2215 j_compress_ptr dstinfo, | |
| 2216 jvirt_barray_ptr *src_coef_arrays, | |
| 2217 jpeg_transform_info *info) | |
| 2218 { | |
| 2219 jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; | |
| 2220 | |
| 2221 /* Note: conditions tested here should match those in switch statement | |
| 2222 * in jtransform_request_workspace() | |
| 2223 */ | |
| 2224 switch (info->transform) { | |
| 2225 case JXFORM_NONE: | |
| 2226 if (info->output_width > srcinfo->output_width || | |
| 2227 info->output_height > srcinfo->output_height) { | |
| 2228 if (info->output_width > srcinfo->output_width && | |
| 2229 info->crop_width_set == JCROP_REFLECT) | |
| 2230 do_crop_ext_reflect(srcinfo, dstinfo, | |
| 2231 info->x_crop_offset, info->y_crop_offset, | |
| 2232 src_coef_arrays, dst_coef_arrays); | |
| 2233 else if (info->output_width > srcinfo->output_width && | |
| 2234 info->crop_width_set == JCROP_FORCE) | |
| 2235 do_crop_ext_flat(srcinfo, dstinfo, | |
| 2236 info->x_crop_offset, info->y_crop_offset, | |
| 2237 src_coef_arrays, dst_coef_arrays); | |
| 2238 else | |
| 2239 do_crop_ext_zero(srcinfo, dstinfo, | |
| 2240 info->x_crop_offset, info->y_crop_offset, | |
| 2241 src_coef_arrays, dst_coef_arrays); | |
| 2242 } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0) | |
| 2243 do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2244 src_coef_arrays, dst_coef_arrays); | |
| 2245 break; | |
| 2246 case JXFORM_FLIP_H: | |
| 2247 if (info->y_crop_offset != 0) | |
| 2248 do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2249 src_coef_arrays, dst_coef_arrays); | |
| 2250 else | |
| 2251 do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, | |
| 2252 src_coef_arrays); | |
| 2253 break; | |
| 2254 case JXFORM_FLIP_V: | |
| 2255 do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2256 src_coef_arrays, dst_coef_arrays); | |
| 2257 break; | |
| 2258 case JXFORM_TRANSPOSE: | |
| 2259 do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2260 src_coef_arrays, dst_coef_arrays); | |
| 2261 break; | |
| 2262 case JXFORM_TRANSVERSE: | |
| 2263 do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2264 src_coef_arrays, dst_coef_arrays); | |
| 2265 break; | |
| 2266 case JXFORM_ROT_90: | |
| 2267 do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2268 src_coef_arrays, dst_coef_arrays); | |
| 2269 break; | |
| 2270 case JXFORM_ROT_180: | |
| 2271 do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2272 src_coef_arrays, dst_coef_arrays); | |
| 2273 break; | |
| 2274 case JXFORM_ROT_270: | |
| 2275 do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2276 src_coef_arrays, dst_coef_arrays); | |
| 2277 break; | |
| 2278 case JXFORM_WIPE: | |
| 2279 if (info->crop_width_set == JCROP_REFLECT && | |
| 2280 info->y_crop_offset == 0 && info->drop_height == | |
| 2281 (JDIMENSION) jdiv_round_up | |
| 2282 ((long) info->output_height, (long) info->iMCU_sample_height) && | |
| 2283 (info->x_crop_offset == 0 || | |
| 2284 info->x_crop_offset + info->drop_width == | |
| 2285 (JDIMENSION) jdiv_round_up | |
| 2286 ((long) info->output_width, (long) info->iMCU_sample_width))) | |
| 2287 do_reflect(srcinfo, dstinfo, info->x_crop_offset, | |
| 2288 src_coef_arrays, info->drop_width, info->drop_height); | |
| 2289 else if (info->crop_width_set == JCROP_FORCE) | |
| 2290 do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2291 src_coef_arrays, info->drop_width, info->drop_height); | |
| 2292 else | |
| 2293 do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2294 src_coef_arrays, info->drop_width, info->drop_height); | |
| 2295 break; | |
| 2296 case JXFORM_DROP: | |
| 2297 if (info->drop_width != 0 && info->drop_height != 0) | |
| 2298 do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, | |
| 2299 src_coef_arrays, info->drop_ptr, info->drop_coef_arrays, | |
| 2300 info->drop_width, info->drop_height); | |
| 2301 break; | |
| 2302 } | |
| 2303 } | |
| 2304 | |
| 2305 /* jtransform_perfect_transform | |
| 2306 * | |
| 2307 * Determine whether lossless transformation is perfectly | |
| 2308 * possible for a specified image and transformation. | |
| 2309 * | |
| 2310 * Inputs: | |
| 2311 * image_width, image_height: source image dimensions. | |
| 2312 * MCU_width, MCU_height: pixel dimensions of MCU. | |
| 2313 * transform: transformation identifier. | |
| 2314 * Parameter sources from initialized jpeg_struct | |
| 2315 * (after reading source header): | |
| 2316 * image_width = cinfo.image_width | |
| 2317 * image_height = cinfo.image_height | |
| 2318 * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size | |
| 2319 * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size | |
| 2320 * Result: | |
| 2321 * TRUE = perfect transformation possible | |
| 2322 * FALSE = perfect transformation not possible | |
| 2323 * (may use custom action then) | |
| 2324 */ | |
| 2325 | |
| 2326 GLOBAL(boolean) | |
| 2327 jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, | |
| 2328 int MCU_width, int MCU_height, | |
| 2329 JXFORM_CODE transform) | |
| 2330 { | |
| 2331 boolean result = TRUE; /* initialize TRUE */ | |
| 2332 | |
| 2333 switch (transform) { | |
| 2334 case JXFORM_FLIP_H: | |
| 2335 case JXFORM_ROT_270: | |
| 2336 if (image_width % (JDIMENSION) MCU_width) | |
| 2337 result = FALSE; | |
| 2338 break; | |
| 2339 case JXFORM_FLIP_V: | |
| 2340 case JXFORM_ROT_90: | |
| 2341 if (image_height % (JDIMENSION) MCU_height) | |
| 2342 result = FALSE; | |
| 2343 break; | |
| 2344 case JXFORM_TRANSVERSE: | |
| 2345 case JXFORM_ROT_180: | |
| 2346 if (image_width % (JDIMENSION) MCU_width) | |
| 2347 result = FALSE; | |
| 2348 if (image_height % (JDIMENSION) MCU_height) | |
| 2349 result = FALSE; | |
| 2350 break; | |
| 2351 default: | |
| 2352 break; | |
| 2353 } | |
| 2354 | |
| 2355 return result; | |
| 2356 } | |
| 2357 | |
| 2358 #endif /* TRANSFORMS_SUPPORTED */ | |
| 2359 | |
| 2360 | |
| 2361 /* Setup decompression object to save desired markers in memory. | |
| 2362 * This must be called before jpeg_read_header() to have the desired effect. | |
| 2363 */ | |
| 2364 | |
| 2365 GLOBAL(void) | |
| 2366 jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) | |
| 2367 { | |
| 2368 #ifdef SAVE_MARKERS_SUPPORTED | |
| 2369 int m; | |
| 2370 | |
| 2371 /* Save comments except under NONE option */ | |
| 2372 if (option != JCOPYOPT_NONE) { | |
| 2373 jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); | |
| 2374 } | |
| 2375 /* Save all types of APPn markers iff ALL option */ | |
| 2376 if (option == JCOPYOPT_ALL) { | |
| 2377 for (m = 0; m < 16; m++) | |
| 2378 jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); | |
| 2379 } | |
| 2380 #endif /* SAVE_MARKERS_SUPPORTED */ | |
| 2381 } | |
| 2382 | |
| 2383 /* Copy markers saved in the given source object to the destination object. | |
| 2384 * This should be called just after jpeg_start_compress() or | |
| 2385 * jpeg_write_coefficients(). | |
| 2386 * Note that those routines will have written the SOI, and also the | |
| 2387 * JFIF APP0 or Adobe APP14 markers if selected. | |
| 2388 */ | |
| 2389 | |
| 2390 GLOBAL(void) | |
| 2391 jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, | |
| 2392 JCOPY_OPTION option) | |
| 2393 { | |
| 2394 jpeg_saved_marker_ptr marker; | |
| 2395 | |
| 2396 /* In the current implementation, we don't actually need to examine the | |
| 2397 * option flag here; we just copy everything that got saved. | |
| 2398 * But to avoid confusion, we do not output JFIF and Adobe APP14 markers | |
| 2399 * if the encoder library already wrote one. | |
| 2400 */ | |
| 2401 for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { | |
| 2402 if (dstinfo->write_JFIF_header && | |
| 2403 marker->marker == JPEG_APP0 && | |
| 2404 marker->data_length >= 5 && | |
| 2405 GETJOCTET(marker->data[0]) == 0x4A && | |
| 2406 GETJOCTET(marker->data[1]) == 0x46 && | |
| 2407 GETJOCTET(marker->data[2]) == 0x49 && | |
| 2408 GETJOCTET(marker->data[3]) == 0x46 && | |
| 2409 GETJOCTET(marker->data[4]) == 0) | |
| 2410 continue; /* reject duplicate JFIF */ | |
| 2411 if (dstinfo->write_Adobe_marker && | |
| 2412 marker->marker == JPEG_APP0+14 && | |
| 2413 marker->data_length >= 5 && | |
| 2414 GETJOCTET(marker->data[0]) == 0x41 && | |
| 2415 GETJOCTET(marker->data[1]) == 0x64 && | |
| 2416 GETJOCTET(marker->data[2]) == 0x6F && | |
| 2417 GETJOCTET(marker->data[3]) == 0x62 && | |
| 2418 GETJOCTET(marker->data[4]) == 0x65) | |
| 2419 continue; /* reject duplicate Adobe */ | |
| 2420 #ifdef NEED_FAR_POINTERS | |
| 2421 /* We could use jpeg_write_marker if the data weren't FAR... */ | |
| 2422 { | |
| 2423 unsigned int i; | |
| 2424 jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); | |
| 2425 for (i = 0; i < marker->data_length; i++) | |
| 2426 jpeg_write_m_byte(dstinfo, marker->data[i]); | |
| 2427 } | |
| 2428 #else | |
| 2429 jpeg_write_marker(dstinfo, marker->marker, | |
| 2430 marker->data, marker->data_length); | |
| 2431 #endif | |
| 2432 } | |
| 2433 } |
