File indexing completed on 2024-05-12 04:19:46

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