Shoaib Ahmed / Mbed 2 deprecated uzairkhan

Dependencies:   uzair Camera_LS_Y201 F7_Ethernet LCD_DISCO_F746NG NetworkAPI SDFileSystem mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers transupp.c Source File

transupp.c

00001 /*
00002  * transupp.c
00003  *
00004  * Copyright (C) 1997-2013, Thomas G. Lane, Guido Vollbeding.
00005  * This file is part of the Independent JPEG Group's software.
00006  * For conditions of distribution and use, see the accompanying README file.
00007  *
00008  * This file contains image transformation routines and other utility code
00009  * used by the jpegtran sample application.  These are NOT part of the core
00010  * JPEG library.  But we keep these routines separate from jpegtran.c to
00011  * ease the task of maintaining jpegtran-like programs that have other user
00012  * interfaces.
00013  */
00014 
00015 /* Although this file really shouldn't have access to the library internals,
00016  * it's helpful to let it call jround_up() and jcopy_block_row().
00017  */
00018 #define JPEG_INTERNALS
00019 
00020 #include "jinclude.h"
00021 #include "jpeglib.h"
00022 #include "transupp.h"       /* My own external interface */
00023 #include <ctype.h>      /* to declare isdigit() */
00024 
00025 
00026 #if TRANSFORMS_SUPPORTED
00027 
00028 /*
00029  * Lossless image transformation routines.  These routines work on DCT
00030  * coefficient arrays and thus do not require any lossy decompression
00031  * or recompression of the image.
00032  * Thanks to Guido Vollbeding for the initial design and code of this feature,
00033  * and to Ben Jackson for introducing the cropping feature.
00034  *
00035  * Horizontal flipping is done in-place, using a single top-to-bottom
00036  * pass through the virtual source array.  It will thus be much the
00037  * fastest option for images larger than main memory.
00038  *
00039  * The other routines require a set of destination virtual arrays, so they
00040  * need twice as much memory as jpegtran normally does.  The destination
00041  * arrays are always written in normal scan order (top to bottom) because
00042  * the virtual array manager expects this.  The source arrays will be scanned
00043  * in the corresponding order, which means multiple passes through the source
00044  * arrays for most of the transforms.  That could result in much thrashing
00045  * if the image is larger than main memory.
00046  *
00047  * If cropping or trimming is involved, the destination arrays may be smaller
00048  * than the source arrays.  Note it is not possible to do horizontal flip
00049  * in-place when a nonzero Y crop offset is specified, since we'd have to move
00050  * data from one block row to another but the virtual array manager doesn't
00051  * guarantee we can touch more than one row at a time.  So in that case,
00052  * we have to use a separate destination array.
00053  *
00054  * Some notes about the operating environment of the individual transform
00055  * routines:
00056  * 1. Both the source and destination virtual arrays are allocated from the
00057  *    source JPEG object, and therefore should be manipulated by calling the
00058  *    source's memory manager.
00059  * 2. The destination's component count should be used.  It may be smaller
00060  *    than the source's when forcing to grayscale.
00061  * 3. Likewise the destination's sampling factors should be used.  When
00062  *    forcing to grayscale the destination's sampling factors will be all 1,
00063  *    and we may as well take that as the effective iMCU size.
00064  * 4. When "trim" is in effect, the destination's dimensions will be the
00065  *    trimmed values but the source's will be untrimmed.
00066  * 5. When "crop" is in effect, the destination's dimensions will be the
00067  *    cropped values but the source's will be uncropped.  Each transform
00068  *    routine is responsible for picking up source data starting at the
00069  *    correct X and Y offset for the crop region.  (The X and Y offsets
00070  *    passed to the transform routines are measured in iMCU blocks of the
00071  *    destination.)
00072  * 6. All the routines assume that the source and destination buffers are
00073  *    padded out to a full iMCU boundary.  This is true, although for the
00074  *    source buffer it is an undocumented property of jdcoefct.c.
00075  */
00076 
00077 
00078 LOCAL(void)
00079 do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00080      JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00081      jvirt_barray_ptr *src_coef_arrays,
00082      jvirt_barray_ptr *dst_coef_arrays)
00083 /* Crop.  This is only used when no rotate/flip is requested with the crop. */
00084 {
00085   JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
00086   int ci, offset_y;
00087   JBLOCKARRAY src_buffer, dst_buffer;
00088   jpeg_component_info *compptr;
00089 
00090   /* We simply have to copy the right amount of data (the destination's
00091    * image size) starting at the given X and Y offsets in the source.
00092    */
00093   for (ci = 0; ci < dstinfo->num_components; ci++) {
00094     compptr = dstinfo->comp_info + ci;
00095     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00096     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00097     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00098      dst_blk_y += compptr->v_samp_factor) {
00099       dst_buffer = (*srcinfo->mem->access_virt_barray)
00100     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00101      (JDIMENSION) compptr->v_samp_factor, TRUE);
00102       src_buffer = (*srcinfo->mem->access_virt_barray)
00103     ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00104      dst_blk_y + y_crop_blocks,
00105      (JDIMENSION) compptr->v_samp_factor, FALSE);
00106       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00107     jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
00108             dst_buffer[offset_y],
00109             compptr->width_in_blocks);
00110       }
00111     }
00112   }
00113 }
00114 
00115 
00116 LOCAL(void)
00117 do_crop_ext (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00118          JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00119          jvirt_barray_ptr *src_coef_arrays,
00120          jvirt_barray_ptr *dst_coef_arrays)
00121 /* Crop.  This is only used when no rotate/flip is requested with the crop.
00122  * Extension: If the destination size is larger than the source, we fill in
00123  * the extra area with zero (neutral gray).  Note we also have to zero partial
00124  * iMCUs at the right and bottom edge of the source image area in this case.
00125  */
00126 {
00127   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
00128   JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
00129   int ci, offset_y;
00130   JBLOCKARRAY src_buffer, dst_buffer;
00131   jpeg_component_info *compptr;
00132 
00133   MCU_cols = srcinfo->output_width /
00134     (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
00135   MCU_rows = srcinfo->output_height /
00136     (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
00137 
00138   for (ci = 0; ci < dstinfo->num_components; ci++) {
00139     compptr = dstinfo->comp_info + ci;
00140     comp_width = MCU_cols * compptr->h_samp_factor;
00141     comp_height = MCU_rows * compptr->v_samp_factor;
00142     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00143     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00144     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00145      dst_blk_y += compptr->v_samp_factor) {
00146       dst_buffer = (*srcinfo->mem->access_virt_barray)
00147     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00148      (JDIMENSION) compptr->v_samp_factor, TRUE);
00149       if (dstinfo->jpeg_height > srcinfo->output_height) {
00150     if (dst_blk_y < y_crop_blocks ||
00151         dst_blk_y >= comp_height + y_crop_blocks) {
00152       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00153         FMEMZERO(dst_buffer[offset_y],
00154              compptr->width_in_blocks * SIZEOF(JBLOCK));
00155       }
00156       continue;
00157     }
00158     src_buffer = (*srcinfo->mem->access_virt_barray)
00159       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00160        dst_blk_y - y_crop_blocks,
00161        (JDIMENSION) compptr->v_samp_factor, FALSE);
00162       } else {
00163     src_buffer = (*srcinfo->mem->access_virt_barray)
00164       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00165        dst_blk_y + y_crop_blocks,
00166        (JDIMENSION) compptr->v_samp_factor, FALSE);
00167       }
00168       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00169     if (dstinfo->jpeg_width > srcinfo->output_width) {
00170       if (x_crop_blocks > 0) {
00171         FMEMZERO(dst_buffer[offset_y],
00172              x_crop_blocks * SIZEOF(JBLOCK));
00173       }
00174       jcopy_block_row(src_buffer[offset_y],
00175               dst_buffer[offset_y] + x_crop_blocks,
00176               comp_width);
00177       if (compptr->width_in_blocks > comp_width + x_crop_blocks) {
00178         FMEMZERO(dst_buffer[offset_y] +
00179                comp_width + x_crop_blocks,
00180              (compptr->width_in_blocks -
00181                comp_width - x_crop_blocks) * SIZEOF(JBLOCK));
00182       }
00183     } else {
00184       jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
00185               dst_buffer[offset_y],
00186               compptr->width_in_blocks);
00187     }
00188       }
00189     }
00190   }
00191 }
00192 
00193 
00194 LOCAL(void)
00195 do_wipe (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00196      JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00197      jvirt_barray_ptr *src_coef_arrays,
00198      JDIMENSION drop_width, JDIMENSION drop_height)
00199 /* Wipe - drop content of specified area, fill with zero (neutral gray) */
00200 {
00201   JDIMENSION comp_width, comp_height;
00202   JDIMENSION blk_y, x_wipe_blocks, y_wipe_blocks;
00203   int ci, offset_y;
00204   JBLOCKARRAY buffer;
00205   jpeg_component_info *compptr;
00206 
00207   for (ci = 0; ci < dstinfo->num_components; ci++) {
00208     compptr = dstinfo->comp_info + ci;
00209     comp_width = drop_width * compptr->h_samp_factor;
00210     comp_height = drop_height * compptr->v_samp_factor;
00211     x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
00212     y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
00213     for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) {
00214       buffer = (*srcinfo->mem->access_virt_barray)
00215     ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y + y_wipe_blocks,
00216      (JDIMENSION) compptr->v_samp_factor, TRUE);
00217       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00218     FMEMZERO(buffer[offset_y] + x_wipe_blocks,
00219          comp_width * SIZEOF(JBLOCK));
00220       }
00221     }
00222   }
00223 }
00224 
00225 
00226 LOCAL(void)
00227 do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00228            JDIMENSION x_crop_offset,
00229            jvirt_barray_ptr *src_coef_arrays)
00230 /* Horizontal flip; done in-place, so no separate dest array is required.
00231  * NB: this only works when y_crop_offset is zero.
00232  */
00233 {
00234   JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
00235   int ci, k, offset_y;
00236   JBLOCKARRAY buffer;
00237   JCOEFPTR ptr1, ptr2;
00238   JCOEF temp1, temp2;
00239   jpeg_component_info *compptr;
00240 
00241   /* Horizontal mirroring of DCT blocks is accomplished by swapping
00242    * pairs of blocks in-place.  Within a DCT block, we perform horizontal
00243    * mirroring by changing the signs of odd-numbered columns.
00244    * Partial iMCUs at the right edge are left untouched.
00245    */
00246   MCU_cols = srcinfo->output_width /
00247     (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
00248 
00249   for (ci = 0; ci < dstinfo->num_components; ci++) {
00250     compptr = dstinfo->comp_info + ci;
00251     comp_width = MCU_cols * compptr->h_samp_factor;
00252     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00253     for (blk_y = 0; blk_y < compptr->height_in_blocks;
00254      blk_y += compptr->v_samp_factor) {
00255       buffer = (*srcinfo->mem->access_virt_barray)
00256     ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
00257      (JDIMENSION) compptr->v_samp_factor, TRUE);
00258       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00259     /* Do the mirroring */
00260     for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
00261       ptr1 = buffer[offset_y][blk_x];
00262       ptr2 = buffer[offset_y][comp_width - blk_x - 1];
00263       /* this unrolled loop doesn't need to know which row it's on... */
00264       for (k = 0; k < DCTSIZE2; k += 2) {
00265         temp1 = *ptr1;  /* swap even column */
00266         temp2 = *ptr2;
00267         *ptr1++ = temp2;
00268         *ptr2++ = temp1;
00269         temp1 = *ptr1;  /* swap odd column with sign change */
00270         temp2 = *ptr2;
00271         *ptr1++ = -temp2;
00272         *ptr2++ = -temp1;
00273       }
00274     }
00275     if (x_crop_blocks > 0) {
00276       /* Now left-justify the portion of the data to be kept.
00277        * We can't use a single jcopy_block_row() call because that routine
00278        * depends on memcpy(), whose behavior is unspecified for overlapping
00279        * source and destination areas.  Sigh.
00280        */
00281       for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
00282         jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
00283                 buffer[offset_y] + blk_x,
00284                 (JDIMENSION) 1);
00285       }
00286     }
00287       }
00288     }
00289   }
00290 }
00291 
00292 
00293 LOCAL(void)
00294 do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00295        JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00296        jvirt_barray_ptr *src_coef_arrays,
00297        jvirt_barray_ptr *dst_coef_arrays)
00298 /* Horizontal flip in general cropping case */
00299 {
00300   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
00301   JDIMENSION x_crop_blocks, y_crop_blocks;
00302   int ci, k, offset_y;
00303   JBLOCKARRAY src_buffer, dst_buffer;
00304   JBLOCKROW src_row_ptr, dst_row_ptr;
00305   JCOEFPTR src_ptr, dst_ptr;
00306   jpeg_component_info *compptr;
00307 
00308   /* Here we must output into a separate array because we can't touch
00309    * different rows of a single virtual array simultaneously.  Otherwise,
00310    * this is essentially the same as the routine above.
00311    */
00312   MCU_cols = srcinfo->output_width /
00313     (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
00314 
00315   for (ci = 0; ci < dstinfo->num_components; ci++) {
00316     compptr = dstinfo->comp_info + ci;
00317     comp_width = MCU_cols * compptr->h_samp_factor;
00318     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00319     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00320     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00321      dst_blk_y += compptr->v_samp_factor) {
00322       dst_buffer = (*srcinfo->mem->access_virt_barray)
00323     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00324      (JDIMENSION) compptr->v_samp_factor, TRUE);
00325       src_buffer = (*srcinfo->mem->access_virt_barray)
00326     ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00327      dst_blk_y + y_crop_blocks,
00328      (JDIMENSION) compptr->v_samp_factor, FALSE);
00329       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00330     dst_row_ptr = dst_buffer[offset_y];
00331     src_row_ptr = src_buffer[offset_y];
00332     for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
00333       if (x_crop_blocks + dst_blk_x < comp_width) {
00334         /* Do the mirrorable blocks */
00335         dst_ptr = dst_row_ptr[dst_blk_x];
00336         src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
00337         /* this unrolled loop doesn't need to know which row it's on... */
00338         for (k = 0; k < DCTSIZE2; k += 2) {
00339           *dst_ptr++ = *src_ptr++;   /* copy even column */
00340           *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
00341         }
00342       } else {
00343         /* Copy last partial block(s) verbatim */
00344         jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
00345                 dst_row_ptr + dst_blk_x,
00346                 (JDIMENSION) 1);
00347       }
00348     }
00349       }
00350     }
00351   }
00352 }
00353 
00354 
00355 LOCAL(void)
00356 do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00357        JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00358        jvirt_barray_ptr *src_coef_arrays,
00359        jvirt_barray_ptr *dst_coef_arrays)
00360 /* Vertical flip */
00361 {
00362   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
00363   JDIMENSION x_crop_blocks, y_crop_blocks;
00364   int ci, i, j, offset_y;
00365   JBLOCKARRAY src_buffer, dst_buffer;
00366   JBLOCKROW src_row_ptr, dst_row_ptr;
00367   JCOEFPTR src_ptr, dst_ptr;
00368   jpeg_component_info *compptr;
00369 
00370   /* We output into a separate array because we can't touch different
00371    * rows of the source virtual array simultaneously.  Otherwise, this
00372    * is a pretty straightforward analog of horizontal flip.
00373    * Within a DCT block, vertical mirroring is done by changing the signs
00374    * of odd-numbered rows.
00375    * Partial iMCUs at the bottom edge are copied verbatim.
00376    */
00377   MCU_rows = srcinfo->output_height /
00378     (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
00379 
00380   for (ci = 0; ci < dstinfo->num_components; ci++) {
00381     compptr = dstinfo->comp_info + ci;
00382     comp_height = MCU_rows * compptr->v_samp_factor;
00383     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00384     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00385     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00386      dst_blk_y += compptr->v_samp_factor) {
00387       dst_buffer = (*srcinfo->mem->access_virt_barray)
00388     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00389      (JDIMENSION) compptr->v_samp_factor, TRUE);
00390       if (y_crop_blocks + dst_blk_y < comp_height) {
00391     /* Row is within the mirrorable area. */
00392     src_buffer = (*srcinfo->mem->access_virt_barray)
00393       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00394        comp_height - y_crop_blocks - dst_blk_y -
00395        (JDIMENSION) compptr->v_samp_factor,
00396        (JDIMENSION) compptr->v_samp_factor, FALSE);
00397       } else {
00398     /* Bottom-edge blocks will be copied verbatim. */
00399     src_buffer = (*srcinfo->mem->access_virt_barray)
00400       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00401        dst_blk_y + y_crop_blocks,
00402        (JDIMENSION) compptr->v_samp_factor, FALSE);
00403       }
00404       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00405     if (y_crop_blocks + dst_blk_y < comp_height) {
00406       /* Row is within the mirrorable area. */
00407       dst_row_ptr = dst_buffer[offset_y];
00408       src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
00409       src_row_ptr += x_crop_blocks;
00410       for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
00411            dst_blk_x++) {
00412         dst_ptr = dst_row_ptr[dst_blk_x];
00413         src_ptr = src_row_ptr[dst_blk_x];
00414         for (i = 0; i < DCTSIZE; i += 2) {
00415           /* copy even row */
00416           for (j = 0; j < DCTSIZE; j++)
00417         *dst_ptr++ = *src_ptr++;
00418           /* copy odd row with sign change */
00419           for (j = 0; j < DCTSIZE; j++)
00420         *dst_ptr++ = - *src_ptr++;
00421         }
00422       }
00423     } else {
00424       /* Just copy row verbatim. */
00425       jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
00426               dst_buffer[offset_y],
00427               compptr->width_in_blocks);
00428     }
00429       }
00430     }
00431   }
00432 }
00433 
00434 
00435 LOCAL(void)
00436 do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00437           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00438           jvirt_barray_ptr *src_coef_arrays,
00439           jvirt_barray_ptr *dst_coef_arrays)
00440 /* Transpose source into destination */
00441 {
00442   JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
00443   int ci, i, j, offset_x, offset_y;
00444   JBLOCKARRAY src_buffer, dst_buffer;
00445   JCOEFPTR src_ptr, dst_ptr;
00446   jpeg_component_info *compptr;
00447 
00448   /* Transposing pixels within a block just requires transposing the
00449    * DCT coefficients.
00450    * Partial iMCUs at the edges require no special treatment; we simply
00451    * process all the available DCT blocks for every component.
00452    */
00453   for (ci = 0; ci < dstinfo->num_components; ci++) {
00454     compptr = dstinfo->comp_info + ci;
00455     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00456     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00457     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00458      dst_blk_y += compptr->v_samp_factor) {
00459       dst_buffer = (*srcinfo->mem->access_virt_barray)
00460     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00461      (JDIMENSION) compptr->v_samp_factor, TRUE);
00462       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00463     for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
00464          dst_blk_x += compptr->h_samp_factor) {
00465       src_buffer = (*srcinfo->mem->access_virt_barray)
00466         ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00467          dst_blk_x + x_crop_blocks,
00468          (JDIMENSION) compptr->h_samp_factor, FALSE);
00469       for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
00470         dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
00471         src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
00472         for (i = 0; i < DCTSIZE; i++)
00473           for (j = 0; j < DCTSIZE; j++)
00474         dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00475       }
00476     }
00477       }
00478     }
00479   }
00480 }
00481 
00482 
00483 LOCAL(void)
00484 do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00485        JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00486        jvirt_barray_ptr *src_coef_arrays,
00487        jvirt_barray_ptr *dst_coef_arrays)
00488 /* 90 degree rotation is equivalent to
00489  *   1. Transposing the image;
00490  *   2. Horizontal mirroring.
00491  * These two steps are merged into a single processing routine.
00492  */
00493 {
00494   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
00495   JDIMENSION x_crop_blocks, y_crop_blocks;
00496   int ci, i, j, offset_x, offset_y;
00497   JBLOCKARRAY src_buffer, dst_buffer;
00498   JCOEFPTR src_ptr, dst_ptr;
00499   jpeg_component_info *compptr;
00500 
00501   /* Because of the horizontal mirror step, we can't process partial iMCUs
00502    * at the (output) right edge properly.  They just get transposed and
00503    * not mirrored.
00504    */
00505   MCU_cols = srcinfo->output_height /
00506     (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
00507 
00508   for (ci = 0; ci < dstinfo->num_components; ci++) {
00509     compptr = dstinfo->comp_info + ci;
00510     comp_width = MCU_cols * compptr->h_samp_factor;
00511     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00512     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00513     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00514      dst_blk_y += compptr->v_samp_factor) {
00515       dst_buffer = (*srcinfo->mem->access_virt_barray)
00516     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00517      (JDIMENSION) compptr->v_samp_factor, TRUE);
00518       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00519     for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
00520          dst_blk_x += compptr->h_samp_factor) {
00521       if (x_crop_blocks + dst_blk_x < comp_width) {
00522         /* Block is within the mirrorable area. */
00523         src_buffer = (*srcinfo->mem->access_virt_barray)
00524           ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00525            comp_width - x_crop_blocks - dst_blk_x -
00526            (JDIMENSION) compptr->h_samp_factor,
00527            (JDIMENSION) compptr->h_samp_factor, FALSE);
00528       } else {
00529         /* Edge blocks are transposed but not mirrored. */
00530         src_buffer = (*srcinfo->mem->access_virt_barray)
00531           ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00532            dst_blk_x + x_crop_blocks,
00533            (JDIMENSION) compptr->h_samp_factor, FALSE);
00534       }
00535       for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
00536         dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
00537         if (x_crop_blocks + dst_blk_x < comp_width) {
00538           /* Block is within the mirrorable area. */
00539           src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
00540         [dst_blk_y + offset_y + y_crop_blocks];
00541           for (i = 0; i < DCTSIZE; i++) {
00542         for (j = 0; j < DCTSIZE; j++)
00543           dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00544         i++;
00545         for (j = 0; j < DCTSIZE; j++)
00546           dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
00547           }
00548         } else {
00549           /* Edge blocks are transposed but not mirrored. */
00550           src_ptr = src_buffer[offset_x]
00551         [dst_blk_y + offset_y + y_crop_blocks];
00552           for (i = 0; i < DCTSIZE; i++)
00553         for (j = 0; j < DCTSIZE; j++)
00554           dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00555         }
00556       }
00557     }
00558       }
00559     }
00560   }
00561 }
00562 
00563 
00564 LOCAL(void)
00565 do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00566         JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00567         jvirt_barray_ptr *src_coef_arrays,
00568         jvirt_barray_ptr *dst_coef_arrays)
00569 /* 270 degree rotation is equivalent to
00570  *   1. Horizontal mirroring;
00571  *   2. Transposing the image.
00572  * These two steps are merged into a single processing routine.
00573  */
00574 {
00575   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
00576   JDIMENSION x_crop_blocks, y_crop_blocks;
00577   int ci, i, j, offset_x, offset_y;
00578   JBLOCKARRAY src_buffer, dst_buffer;
00579   JCOEFPTR src_ptr, dst_ptr;
00580   jpeg_component_info *compptr;
00581 
00582   /* Because of the horizontal mirror step, we can't process partial iMCUs
00583    * at the (output) bottom edge properly.  They just get transposed and
00584    * not mirrored.
00585    */
00586   MCU_rows = srcinfo->output_width /
00587     (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
00588 
00589   for (ci = 0; ci < dstinfo->num_components; ci++) {
00590     compptr = dstinfo->comp_info + ci;
00591     comp_height = MCU_rows * compptr->v_samp_factor;
00592     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00593     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00594     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00595      dst_blk_y += compptr->v_samp_factor) {
00596       dst_buffer = (*srcinfo->mem->access_virt_barray)
00597     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00598      (JDIMENSION) compptr->v_samp_factor, TRUE);
00599       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00600     for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
00601          dst_blk_x += compptr->h_samp_factor) {
00602       src_buffer = (*srcinfo->mem->access_virt_barray)
00603         ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00604          dst_blk_x + x_crop_blocks,
00605          (JDIMENSION) compptr->h_samp_factor, FALSE);
00606       for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
00607         dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
00608         if (y_crop_blocks + dst_blk_y < comp_height) {
00609           /* Block is within the mirrorable area. */
00610           src_ptr = src_buffer[offset_x]
00611         [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
00612           for (i = 0; i < DCTSIZE; i++) {
00613         for (j = 0; j < DCTSIZE; j++) {
00614           dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00615           j++;
00616           dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
00617         }
00618           }
00619         } else {
00620           /* Edge blocks are transposed but not mirrored. */
00621           src_ptr = src_buffer[offset_x]
00622         [dst_blk_y + offset_y + y_crop_blocks];
00623           for (i = 0; i < DCTSIZE; i++)
00624         for (j = 0; j < DCTSIZE; j++)
00625           dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00626         }
00627       }
00628     }
00629       }
00630     }
00631   }
00632 }
00633 
00634 
00635 LOCAL(void)
00636 do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00637         JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00638         jvirt_barray_ptr *src_coef_arrays,
00639         jvirt_barray_ptr *dst_coef_arrays)
00640 /* 180 degree rotation is equivalent to
00641  *   1. Vertical mirroring;
00642  *   2. Horizontal mirroring.
00643  * These two steps are merged into a single processing routine.
00644  */
00645 {
00646   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
00647   JDIMENSION x_crop_blocks, y_crop_blocks;
00648   int ci, i, j, offset_y;
00649   JBLOCKARRAY src_buffer, dst_buffer;
00650   JBLOCKROW src_row_ptr, dst_row_ptr;
00651   JCOEFPTR src_ptr, dst_ptr;
00652   jpeg_component_info *compptr;
00653 
00654   MCU_cols = srcinfo->output_width /
00655     (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
00656   MCU_rows = srcinfo->output_height /
00657     (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
00658 
00659   for (ci = 0; ci < dstinfo->num_components; ci++) {
00660     compptr = dstinfo->comp_info + ci;
00661     comp_width = MCU_cols * compptr->h_samp_factor;
00662     comp_height = MCU_rows * compptr->v_samp_factor;
00663     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00664     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00665     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00666      dst_blk_y += compptr->v_samp_factor) {
00667       dst_buffer = (*srcinfo->mem->access_virt_barray)
00668     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00669      (JDIMENSION) compptr->v_samp_factor, TRUE);
00670       if (y_crop_blocks + dst_blk_y < comp_height) {
00671     /* Row is within the vertically mirrorable area. */
00672     src_buffer = (*srcinfo->mem->access_virt_barray)
00673       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00674        comp_height - y_crop_blocks - dst_blk_y -
00675        (JDIMENSION) compptr->v_samp_factor,
00676        (JDIMENSION) compptr->v_samp_factor, FALSE);
00677       } else {
00678     /* Bottom-edge rows are only mirrored horizontally. */
00679     src_buffer = (*srcinfo->mem->access_virt_barray)
00680       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00681        dst_blk_y + y_crop_blocks,
00682        (JDIMENSION) compptr->v_samp_factor, FALSE);
00683       }
00684       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00685     dst_row_ptr = dst_buffer[offset_y];
00686     if (y_crop_blocks + dst_blk_y < comp_height) {
00687       /* Row is within the mirrorable area. */
00688       src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
00689       for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
00690         dst_ptr = dst_row_ptr[dst_blk_x];
00691         if (x_crop_blocks + dst_blk_x < comp_width) {
00692           /* Process the blocks that can be mirrored both ways. */
00693           src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
00694           for (i = 0; i < DCTSIZE; i += 2) {
00695         /* For even row, negate every odd column. */
00696         for (j = 0; j < DCTSIZE; j += 2) {
00697           *dst_ptr++ = *src_ptr++;
00698           *dst_ptr++ = - *src_ptr++;
00699         }
00700         /* For odd row, negate every even column. */
00701         for (j = 0; j < DCTSIZE; j += 2) {
00702           *dst_ptr++ = - *src_ptr++;
00703           *dst_ptr++ = *src_ptr++;
00704         }
00705           }
00706         } else {
00707           /* Any remaining right-edge blocks are only mirrored vertically. */
00708           src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
00709           for (i = 0; i < DCTSIZE; i += 2) {
00710         for (j = 0; j < DCTSIZE; j++)
00711           *dst_ptr++ = *src_ptr++;
00712         for (j = 0; j < DCTSIZE; j++)
00713           *dst_ptr++ = - *src_ptr++;
00714           }
00715         }
00716       }
00717     } else {
00718       /* Remaining rows are just mirrored horizontally. */
00719       src_row_ptr = src_buffer[offset_y];
00720       for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
00721         if (x_crop_blocks + dst_blk_x < comp_width) {
00722           /* Process the blocks that can be mirrored. */
00723           dst_ptr = dst_row_ptr[dst_blk_x];
00724           src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
00725           for (i = 0; i < DCTSIZE2; i += 2) {
00726         *dst_ptr++ = *src_ptr++;
00727         *dst_ptr++ = - *src_ptr++;
00728           }
00729         } else {
00730           /* Any remaining right-edge blocks are only copied. */
00731           jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
00732                   dst_row_ptr + dst_blk_x,
00733                   (JDIMENSION) 1);
00734         }
00735       }
00736     }
00737       }
00738     }
00739   }
00740 }
00741 
00742 
00743 LOCAL(void)
00744 do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
00745            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
00746            jvirt_barray_ptr *src_coef_arrays,
00747            jvirt_barray_ptr *dst_coef_arrays)
00748 /* Transverse transpose is equivalent to
00749  *   1. 180 degree rotation;
00750  *   2. Transposition;
00751  * or
00752  *   1. Horizontal mirroring;
00753  *   2. Transposition;
00754  *   3. Horizontal mirroring.
00755  * These steps are merged into a single processing routine.
00756  */
00757 {
00758   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
00759   JDIMENSION x_crop_blocks, y_crop_blocks;
00760   int ci, i, j, offset_x, offset_y;
00761   JBLOCKARRAY src_buffer, dst_buffer;
00762   JCOEFPTR src_ptr, dst_ptr;
00763   jpeg_component_info *compptr;
00764 
00765   MCU_cols = srcinfo->output_height /
00766     (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
00767   MCU_rows = srcinfo->output_width /
00768     (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
00769 
00770   for (ci = 0; ci < dstinfo->num_components; ci++) {
00771     compptr = dstinfo->comp_info + ci;
00772     comp_width = MCU_cols * compptr->h_samp_factor;
00773     comp_height = MCU_rows * compptr->v_samp_factor;
00774     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
00775     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
00776     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
00777      dst_blk_y += compptr->v_samp_factor) {
00778       dst_buffer = (*srcinfo->mem->access_virt_barray)
00779     ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
00780      (JDIMENSION) compptr->v_samp_factor, TRUE);
00781       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
00782     for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
00783          dst_blk_x += compptr->h_samp_factor) {
00784       if (x_crop_blocks + dst_blk_x < comp_width) {
00785         /* Block is within the mirrorable area. */
00786         src_buffer = (*srcinfo->mem->access_virt_barray)
00787           ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00788            comp_width - x_crop_blocks - dst_blk_x -
00789            (JDIMENSION) compptr->h_samp_factor,
00790            (JDIMENSION) compptr->h_samp_factor, FALSE);
00791       } else {
00792         src_buffer = (*srcinfo->mem->access_virt_barray)
00793           ((j_common_ptr) srcinfo, src_coef_arrays[ci],
00794            dst_blk_x + x_crop_blocks,
00795            (JDIMENSION) compptr->h_samp_factor, FALSE);
00796       }
00797       for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
00798         dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
00799         if (y_crop_blocks + dst_blk_y < comp_height) {
00800           if (x_crop_blocks + dst_blk_x < comp_width) {
00801         /* Block is within the mirrorable area. */
00802         src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
00803           [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
00804         for (i = 0; i < DCTSIZE; i++) {
00805           for (j = 0; j < DCTSIZE; j++) {
00806             dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00807             j++;
00808             dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
00809           }
00810           i++;
00811           for (j = 0; j < DCTSIZE; j++) {
00812             dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
00813             j++;
00814             dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00815           }
00816         }
00817           } else {
00818         /* Right-edge blocks are mirrored in y only */
00819         src_ptr = src_buffer[offset_x]
00820           [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
00821         for (i = 0; i < DCTSIZE; i++) {
00822           for (j = 0; j < DCTSIZE; j++) {
00823             dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00824             j++;
00825             dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
00826           }
00827         }
00828           }
00829         } else {
00830           if (x_crop_blocks + dst_blk_x < comp_width) {
00831         /* Bottom-edge blocks are mirrored in x only */
00832         src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
00833           [dst_blk_y + offset_y + y_crop_blocks];
00834         for (i = 0; i < DCTSIZE; i++) {
00835           for (j = 0; j < DCTSIZE; j++)
00836             dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00837           i++;
00838           for (j = 0; j < DCTSIZE; j++)
00839             dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
00840         }
00841           } else {
00842         /* At lower right corner, just transpose, no mirroring */
00843         src_ptr = src_buffer[offset_x]
00844           [dst_blk_y + offset_y + y_crop_blocks];
00845         for (i = 0; i < DCTSIZE; i++)
00846           for (j = 0; j < DCTSIZE; j++)
00847             dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
00848           }
00849         }
00850       }
00851     }
00852       }
00853     }
00854   }
00855 }
00856 
00857 
00858 /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
00859  * Returns TRUE if valid integer found, FALSE if not.
00860  * *strptr is advanced over the digit string, and *result is set to its value.
00861  */
00862 
00863 LOCAL(boolean)
00864 jt_read_integer (const char ** strptr, JDIMENSION * result)
00865 {
00866   const char * ptr = *strptr;
00867   JDIMENSION val = 0;
00868 
00869   for (; isdigit(*ptr); ptr++) {
00870     val = val * 10 + (JDIMENSION) (*ptr - '0');
00871   }
00872   *result = val;
00873   if (ptr == *strptr)
00874     return FALSE;       /* oops, no digits */
00875   *strptr = ptr;
00876   return TRUE;
00877 }
00878 
00879 
00880 /* Parse a crop specification (written in X11 geometry style).
00881  * The routine returns TRUE if the spec string is valid, FALSE if not.
00882  *
00883  * The crop spec string should have the format
00884  *  <width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset>
00885  * where width, height, xoffset, and yoffset are unsigned integers.
00886  * Each of the elements can be omitted to indicate a default value.
00887  * (A weakness of this style is that it is not possible to omit xoffset
00888  * while specifying yoffset, since they look alike.)
00889  *
00890  * This code is loosely based on XParseGeometry from the X11 distribution.
00891  */
00892 
00893 GLOBAL(boolean)
00894 jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
00895 {
00896   info->crop = FALSE;
00897   info->crop_width_set = JCROP_UNSET;
00898   info->crop_height_set = JCROP_UNSET;
00899   info->crop_xoffset_set = JCROP_UNSET;
00900   info->crop_yoffset_set = JCROP_UNSET;
00901 
00902   if (isdigit(*spec)) {
00903     /* fetch width */
00904     if (! jt_read_integer(&spec, &info->crop_width))
00905       return FALSE;
00906     if (*spec == 'f' || *spec == 'F') {
00907       spec++;
00908       info->crop_width_set = JCROP_FORCE;
00909     } else
00910       info->crop_width_set = JCROP_POS;
00911   }
00912   if (*spec == 'x' || *spec == 'X') {
00913     /* fetch height */
00914     spec++;
00915     if (! jt_read_integer(&spec, &info->crop_height))
00916       return FALSE;
00917     if (*spec == 'f' || *spec == 'F') {
00918       spec++;
00919       info->crop_height_set = JCROP_FORCE;
00920     } else
00921       info->crop_height_set = JCROP_POS;
00922   }
00923   if (*spec == '+' || *spec == '-') {
00924     /* fetch xoffset */
00925     info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
00926     spec++;
00927     if (! jt_read_integer(&spec, &info->crop_xoffset))
00928       return FALSE;
00929   }
00930   if (*spec == '+' || *spec == '-') {
00931     /* fetch yoffset */
00932     info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
00933     spec++;
00934     if (! jt_read_integer(&spec, &info->crop_yoffset))
00935       return FALSE;
00936   }
00937   /* We had better have gotten to the end of the string. */
00938   if (*spec != '\0')
00939     return FALSE;
00940   info->crop = TRUE;
00941   return TRUE;
00942 }
00943 
00944 
00945 /* Trim off any partial iMCUs on the indicated destination edge */
00946 
00947 LOCAL(void)
00948 trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
00949 {
00950   JDIMENSION MCU_cols;
00951 
00952   MCU_cols = info->output_width / info->iMCU_sample_width;
00953   if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
00954       full_width / info->iMCU_sample_width)
00955     info->output_width = MCU_cols * info->iMCU_sample_width;
00956 }
00957 
00958 LOCAL(void)
00959 trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
00960 {
00961   JDIMENSION MCU_rows;
00962 
00963   MCU_rows = info->output_height / info->iMCU_sample_height;
00964   if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
00965       full_height / info->iMCU_sample_height)
00966     info->output_height = MCU_rows * info->iMCU_sample_height;
00967 }
00968 
00969 
00970 /* Request any required workspace.
00971  *
00972  * This routine figures out the size that the output image will be
00973  * (which implies that all the transform parameters must be set before
00974  * it is called).
00975  *
00976  * We allocate the workspace virtual arrays from the source decompression
00977  * object, so that all the arrays (both the original data and the workspace)
00978  * will be taken into account while making memory management decisions.
00979  * Hence, this routine must be called after jpeg_read_header (which reads
00980  * the image dimensions) and before jpeg_read_coefficients (which realizes
00981  * the source's virtual arrays).
00982  *
00983  * This function returns FALSE right away if -perfect is given
00984  * and transformation is not perfect.  Otherwise returns TRUE.
00985  */
00986 
00987 GLOBAL(boolean)
00988 jtransform_request_workspace (j_decompress_ptr srcinfo,
00989                   jpeg_transform_info *info)
00990 {
00991   jvirt_barray_ptr *coef_arrays;
00992   boolean need_workspace, transpose_it;
00993   jpeg_component_info *compptr;
00994   JDIMENSION xoffset, yoffset;
00995   JDIMENSION width_in_iMCUs, height_in_iMCUs;
00996   JDIMENSION width_in_blocks, height_in_blocks;
00997   int ci, h_samp_factor, v_samp_factor;
00998 
00999   /* Determine number of components in output image */
01000   if (info->force_grayscale &&
01001       (srcinfo->jpeg_color_space == JCS_YCbCr ||
01002        srcinfo->jpeg_color_space == JCS_BG_YCC) &&
01003       srcinfo->num_components == 3)
01004     /* We'll only process the first component */
01005     info->num_components = 1;
01006   else
01007     /* Process all the components */
01008     info->num_components = srcinfo->num_components;
01009 
01010   /* Compute output image dimensions and related values. */
01011   jpeg_core_output_dimensions(srcinfo);
01012 
01013   /* Return right away if -perfect is given and transformation is not perfect.
01014    */
01015   if (info->perfect) {
01016     if (info->num_components == 1) {
01017       if (!jtransform_perfect_transform(srcinfo->output_width,
01018       srcinfo->output_height,
01019       srcinfo->min_DCT_h_scaled_size,
01020       srcinfo->min_DCT_v_scaled_size,
01021       info->transform))
01022     return FALSE;
01023     } else {
01024       if (!jtransform_perfect_transform(srcinfo->output_width,
01025       srcinfo->output_height,
01026       srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size,
01027       srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size,
01028       info->transform))
01029     return FALSE;
01030     }
01031   }
01032 
01033   /* If there is only one output component, force the iMCU size to be 1;
01034    * else use the source iMCU size.  (This allows us to do the right thing
01035    * when reducing color to grayscale, and also provides a handy way of
01036    * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
01037    */
01038   switch (info->transform) {
01039   case JXFORM_TRANSPOSE:
01040   case JXFORM_TRANSVERSE:
01041   case JXFORM_ROT_90:
01042   case JXFORM_ROT_270:
01043     info->output_width = srcinfo->output_height;
01044     info->output_height = srcinfo->output_width;
01045     if (info->num_components == 1) {
01046       info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;
01047       info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;
01048     } else {
01049       info->iMCU_sample_width =
01050     srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
01051       info->iMCU_sample_height =
01052     srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
01053     }
01054     break;
01055   default:
01056     info->output_width = srcinfo->output_width;
01057     info->output_height = srcinfo->output_height;
01058     if (info->num_components == 1) {
01059       info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;
01060       info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;
01061     } else {
01062       info->iMCU_sample_width =
01063     srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
01064       info->iMCU_sample_height =
01065     srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
01066     }
01067     break;
01068   }
01069 
01070   /* If cropping has been requested, compute the crop area's position and
01071    * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
01072    */
01073   if (info->crop) {
01074     /* Insert default values for unset crop parameters */
01075     if (info->crop_xoffset_set == JCROP_UNSET)
01076       info->crop_xoffset = 0;   /* default to +0 */
01077     if (info->crop_yoffset_set == JCROP_UNSET)
01078       info->crop_yoffset = 0;   /* default to +0 */
01079     if (info->crop_width_set == JCROP_UNSET) {
01080       if (info->crop_xoffset >= info->output_width)
01081     ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
01082       info->crop_width = info->output_width - info->crop_xoffset;
01083     } else {
01084       /* Check for crop extension */
01085       if (info->crop_width > info->output_width) {
01086     /* Crop extension does not work when transforming! */
01087     if (info->transform != JXFORM_NONE ||
01088         info->crop_xoffset >= info->crop_width ||
01089         info->crop_xoffset > info->crop_width - info->output_width)
01090       ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
01091       } else {
01092     if (info->crop_xoffset >= info->output_width ||
01093         info->crop_width <= 0 ||
01094         info->crop_xoffset > info->output_width - info->crop_width)
01095       ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
01096       }
01097     }
01098     if (info->crop_height_set == JCROP_UNSET) {
01099       if (info->crop_yoffset >= info->output_height)
01100     ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
01101       info->crop_height = info->output_height - info->crop_yoffset;
01102     } else {
01103       /* Check for crop extension */
01104       if (info->crop_height > info->output_height) {
01105     /* Crop extension does not work when transforming! */
01106     if (info->transform != JXFORM_NONE ||
01107         info->crop_yoffset >= info->crop_height ||
01108         info->crop_yoffset > info->crop_height - info->output_height)
01109       ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
01110       } else {
01111     if (info->crop_yoffset >= info->output_height ||
01112         info->crop_height <= 0 ||
01113         info->crop_yoffset > info->output_height - info->crop_height)
01114       ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
01115       }
01116     }
01117     /* Convert negative crop offsets into regular offsets */
01118     if (info->crop_xoffset_set != JCROP_NEG)
01119       xoffset = info->crop_xoffset;
01120     else if (info->crop_width > info->output_width) /* crop extension */
01121       xoffset = info->crop_width - info->output_width - info->crop_xoffset;
01122     else
01123       xoffset = info->output_width - info->crop_width - info->crop_xoffset;
01124     if (info->crop_yoffset_set != JCROP_NEG)
01125       yoffset = info->crop_yoffset;
01126     else if (info->crop_height > info->output_height) /* crop extension */
01127       yoffset = info->crop_height - info->output_height - info->crop_yoffset;
01128     else
01129       yoffset = info->output_height - info->crop_height - info->crop_yoffset;
01130     /* Now adjust so that upper left corner falls at an iMCU boundary */
01131     if (info->transform == JXFORM_WIPE) {
01132       /* Ensure the effective wipe region will cover the requested */
01133       info->drop_width = (JDIMENSION) jdiv_round_up
01134     ((long) (info->crop_width + (xoffset % info->iMCU_sample_width)),
01135      (long) info->iMCU_sample_width);
01136       info->drop_height = (JDIMENSION) jdiv_round_up
01137     ((long) (info->crop_height + (yoffset % info->iMCU_sample_height)),
01138      (long) info->iMCU_sample_height);
01139     } else {
01140       /* Ensure the effective crop region will cover the requested */
01141       if (info->crop_width_set == JCROP_FORCE ||
01142       info->crop_width > info->output_width)
01143     info->output_width = info->crop_width;
01144       else
01145     info->output_width =
01146       info->crop_width + (xoffset % info->iMCU_sample_width);
01147       if (info->crop_height_set == JCROP_FORCE ||
01148       info->crop_height > info->output_height)
01149     info->output_height = info->crop_height;
01150       else
01151     info->output_height =
01152       info->crop_height + (yoffset % info->iMCU_sample_height);
01153     }
01154     /* Save x/y offsets measured in iMCUs */
01155     info->x_crop_offset = xoffset / info->iMCU_sample_width;
01156     info->y_crop_offset = yoffset / info->iMCU_sample_height;
01157   } else {
01158     info->x_crop_offset = 0;
01159     info->y_crop_offset = 0;
01160   }
01161 
01162   /* Figure out whether we need workspace arrays,
01163    * and if so whether they are transposed relative to the source.
01164    */
01165   need_workspace = FALSE;
01166   transpose_it = FALSE;
01167   switch (info->transform) {
01168   case JXFORM_NONE:
01169     if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||
01170     info->output_width > srcinfo->output_width ||
01171     info->output_height > srcinfo->output_height)
01172       need_workspace = TRUE;
01173     /* No workspace needed if neither cropping nor transforming */
01174     break;
01175   case JXFORM_FLIP_H:
01176     if (info->trim)
01177       trim_right_edge(info, srcinfo->output_width);
01178     if (info->y_crop_offset != 0)
01179       need_workspace = TRUE;
01180     /* do_flip_h_no_crop doesn't need a workspace array */
01181     break;
01182   case JXFORM_FLIP_V:
01183     if (info->trim)
01184       trim_bottom_edge(info, srcinfo->output_height);
01185     /* Need workspace arrays having same dimensions as source image. */
01186     need_workspace = TRUE;
01187     break;
01188   case JXFORM_TRANSPOSE:
01189     /* transpose does NOT have to trim anything */
01190     /* Need workspace arrays having transposed dimensions. */
01191     need_workspace = TRUE;
01192     transpose_it = TRUE;
01193     break;
01194   case JXFORM_TRANSVERSE:
01195     if (info->trim) {
01196       trim_right_edge(info, srcinfo->output_height);
01197       trim_bottom_edge(info, srcinfo->output_width);
01198     }
01199     /* Need workspace arrays having transposed dimensions. */
01200     need_workspace = TRUE;
01201     transpose_it = TRUE;
01202     break;
01203   case JXFORM_ROT_90:
01204     if (info->trim)
01205       trim_right_edge(info, srcinfo->output_height);
01206     /* Need workspace arrays having transposed dimensions. */
01207     need_workspace = TRUE;
01208     transpose_it = TRUE;
01209     break;
01210   case JXFORM_ROT_180:
01211     if (info->trim) {
01212       trim_right_edge(info, srcinfo->output_width);
01213       trim_bottom_edge(info, srcinfo->output_height);
01214     }
01215     /* Need workspace arrays having same dimensions as source image. */
01216     need_workspace = TRUE;
01217     break;
01218   case JXFORM_ROT_270:
01219     if (info->trim)
01220       trim_bottom_edge(info, srcinfo->output_width);
01221     /* Need workspace arrays having transposed dimensions. */
01222     need_workspace = TRUE;
01223     transpose_it = TRUE;
01224     break;
01225   case JXFORM_WIPE:
01226     break;
01227   }
01228 
01229   /* Allocate workspace if needed.
01230    * Note that we allocate arrays padded out to the next iMCU boundary,
01231    * so that transform routines need not worry about missing edge blocks.
01232    */
01233   if (need_workspace) {
01234     coef_arrays = (jvirt_barray_ptr *)
01235       (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
01236     SIZEOF(jvirt_barray_ptr) * info->num_components);
01237     width_in_iMCUs = (JDIMENSION)
01238       jdiv_round_up((long) info->output_width,
01239             (long) info->iMCU_sample_width);
01240     height_in_iMCUs = (JDIMENSION)
01241       jdiv_round_up((long) info->output_height,
01242             (long) info->iMCU_sample_height);
01243     for (ci = 0; ci < info->num_components; ci++) {
01244       compptr = srcinfo->comp_info + ci;
01245       if (info->num_components == 1) {
01246     /* we're going to force samp factors to 1x1 in this case */
01247     h_samp_factor = v_samp_factor = 1;
01248       } else if (transpose_it) {
01249     h_samp_factor = compptr->v_samp_factor;
01250     v_samp_factor = compptr->h_samp_factor;
01251       } else {
01252     h_samp_factor = compptr->h_samp_factor;
01253     v_samp_factor = compptr->v_samp_factor;
01254       }
01255       width_in_blocks = width_in_iMCUs * h_samp_factor;
01256       height_in_blocks = height_in_iMCUs * v_samp_factor;
01257       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
01258     ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
01259      width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
01260     }
01261     info->workspace_coef_arrays = coef_arrays;
01262   } else
01263     info->workspace_coef_arrays = NULL;
01264 
01265   return TRUE;
01266 }
01267 
01268 
01269 /* Transpose destination image parameters */
01270 
01271 LOCAL(void)
01272 transpose_critical_parameters (j_compress_ptr dstinfo)
01273 {
01274   int tblno, i, j, ci, itemp;
01275   jpeg_component_info *compptr;
01276   JQUANT_TBL *qtblptr;
01277   JDIMENSION jtemp;
01278   UINT16 qtemp;
01279 
01280   /* Transpose image dimensions */
01281   jtemp = dstinfo->image_width;
01282   dstinfo->image_width = dstinfo->image_height;
01283   dstinfo->image_height = jtemp;
01284   itemp = dstinfo->min_DCT_h_scaled_size;
01285   dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
01286   dstinfo->min_DCT_v_scaled_size = itemp;
01287 
01288   /* Transpose sampling factors */
01289   for (ci = 0; ci < dstinfo->num_components; ci++) {
01290     compptr = dstinfo->comp_info + ci;
01291     itemp = compptr->h_samp_factor;
01292     compptr->h_samp_factor = compptr->v_samp_factor;
01293     compptr->v_samp_factor = itemp;
01294   }
01295 
01296   /* Transpose quantization tables */
01297   for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
01298     qtblptr = dstinfo->quant_tbl_ptrs[tblno];
01299     if (qtblptr != NULL) {
01300       for (i = 0; i < DCTSIZE; i++) {
01301     for (j = 0; j < i; j++) {
01302       qtemp = qtblptr->quantval[i*DCTSIZE+j];
01303       qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];
01304       qtblptr->quantval[j*DCTSIZE+i] = qtemp;
01305     }
01306       }
01307     }
01308   }
01309 }
01310 
01311 
01312 /* Adjust Exif image parameters.
01313  *
01314  * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
01315  */
01316 
01317 LOCAL(void)
01318 adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
01319             JDIMENSION new_width, JDIMENSION new_height)
01320 {
01321   boolean is_motorola; /* Flag for byte order */
01322   unsigned int number_of_tags, tagnum;
01323   unsigned int firstoffset, offset;
01324   JDIMENSION new_value;
01325 
01326   if (length < 12) return; /* Length of an IFD entry */
01327 
01328   /* Discover byte order */
01329   if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
01330     is_motorola = FALSE;
01331   else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
01332     is_motorola = TRUE;
01333   else
01334     return;
01335 
01336   /* Check Tag Mark */
01337   if (is_motorola) {
01338     if (GETJOCTET(data[2]) != 0) return;
01339     if (GETJOCTET(data[3]) != 0x2A) return;
01340   } else {
01341     if (GETJOCTET(data[3]) != 0) return;
01342     if (GETJOCTET(data[2]) != 0x2A) return;
01343   }
01344 
01345   /* Get first IFD offset (offset to IFD0) */
01346   if (is_motorola) {
01347     if (GETJOCTET(data[4]) != 0) return;
01348     if (GETJOCTET(data[5]) != 0) return;
01349     firstoffset = GETJOCTET(data[6]);
01350     firstoffset <<= 8;
01351     firstoffset += GETJOCTET(data[7]);
01352   } else {
01353     if (GETJOCTET(data[7]) != 0) return;
01354     if (GETJOCTET(data[6]) != 0) return;
01355     firstoffset = GETJOCTET(data[5]);
01356     firstoffset <<= 8;
01357     firstoffset += GETJOCTET(data[4]);
01358   }
01359   if (firstoffset > length - 2) return; /* check end of data segment */
01360 
01361   /* Get the number of directory entries contained in this IFD */
01362   if (is_motorola) {
01363     number_of_tags = GETJOCTET(data[firstoffset]);
01364     number_of_tags <<= 8;
01365     number_of_tags += GETJOCTET(data[firstoffset+1]);
01366   } else {
01367     number_of_tags = GETJOCTET(data[firstoffset+1]);
01368     number_of_tags <<= 8;
01369     number_of_tags += GETJOCTET(data[firstoffset]);
01370   }
01371   if (number_of_tags == 0) return;
01372   firstoffset += 2;
01373 
01374   /* Search for ExifSubIFD offset Tag in IFD0 */
01375   for (;;) {
01376     if (firstoffset > length - 12) return; /* check end of data segment */
01377     /* Get Tag number */
01378     if (is_motorola) {
01379       tagnum = GETJOCTET(data[firstoffset]);
01380       tagnum <<= 8;
01381       tagnum += GETJOCTET(data[firstoffset+1]);
01382     } else {
01383       tagnum = GETJOCTET(data[firstoffset+1]);
01384       tagnum <<= 8;
01385       tagnum += GETJOCTET(data[firstoffset]);
01386     }
01387     if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
01388     if (--number_of_tags == 0) return;
01389     firstoffset += 12;
01390   }
01391 
01392   /* Get the ExifSubIFD offset */
01393   if (is_motorola) {
01394     if (GETJOCTET(data[firstoffset+8]) != 0) return;
01395     if (GETJOCTET(data[firstoffset+9]) != 0) return;
01396     offset = GETJOCTET(data[firstoffset+10]);
01397     offset <<= 8;
01398     offset += GETJOCTET(data[firstoffset+11]);
01399   } else {
01400     if (GETJOCTET(data[firstoffset+11]) != 0) return;
01401     if (GETJOCTET(data[firstoffset+10]) != 0) return;
01402     offset = GETJOCTET(data[firstoffset+9]);
01403     offset <<= 8;
01404     offset += GETJOCTET(data[firstoffset+8]);
01405   }
01406   if (offset > length - 2) return; /* check end of data segment */
01407 
01408   /* Get the number of directory entries contained in this SubIFD */
01409   if (is_motorola) {
01410     number_of_tags = GETJOCTET(data[offset]);
01411     number_of_tags <<= 8;
01412     number_of_tags += GETJOCTET(data[offset+1]);
01413   } else {
01414     number_of_tags = GETJOCTET(data[offset+1]);
01415     number_of_tags <<= 8;
01416     number_of_tags += GETJOCTET(data[offset]);
01417   }
01418   if (number_of_tags < 2) return;
01419   offset += 2;
01420 
01421   /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
01422   do {
01423     if (offset > length - 12) return; /* check end of data segment */
01424     /* Get Tag number */
01425     if (is_motorola) {
01426       tagnum = GETJOCTET(data[offset]);
01427       tagnum <<= 8;
01428       tagnum += GETJOCTET(data[offset+1]);
01429     } else {
01430       tagnum = GETJOCTET(data[offset+1]);
01431       tagnum <<= 8;
01432       tagnum += GETJOCTET(data[offset]);
01433     }
01434     if (tagnum == 0xA002 || tagnum == 0xA003) {
01435       if (tagnum == 0xA002)
01436     new_value = new_width; /* ExifImageWidth Tag */
01437       else
01438     new_value = new_height; /* ExifImageHeight Tag */
01439       if (is_motorola) {
01440     data[offset+2] = 0; /* Format = unsigned long (4 octets) */
01441     data[offset+3] = 4;
01442     data[offset+4] = 0; /* Number Of Components = 1 */
01443     data[offset+5] = 0;
01444     data[offset+6] = 0;
01445     data[offset+7] = 1;
01446     data[offset+8] = 0;
01447     data[offset+9] = 0;
01448     data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
01449     data[offset+11] = (JOCTET)(new_value & 0xFF);
01450       } else {
01451     data[offset+2] = 4; /* Format = unsigned long (4 octets) */
01452     data[offset+3] = 0;
01453     data[offset+4] = 1; /* Number Of Components = 1 */
01454     data[offset+5] = 0;
01455     data[offset+6] = 0;
01456     data[offset+7] = 0;
01457     data[offset+8] = (JOCTET)(new_value & 0xFF);
01458     data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
01459     data[offset+10] = 0;
01460     data[offset+11] = 0;
01461       }
01462     }
01463     offset += 12;
01464   } while (--number_of_tags);
01465 }
01466 
01467 
01468 /* Adjust output image parameters as needed.
01469  *
01470  * This must be called after jpeg_copy_critical_parameters()
01471  * and before jpeg_write_coefficients().
01472  *
01473  * The return value is the set of virtual coefficient arrays to be written
01474  * (either the ones allocated by jtransform_request_workspace, or the
01475  * original source data arrays).  The caller will need to pass this value
01476  * to jpeg_write_coefficients().
01477  */
01478 
01479 GLOBAL(jvirt_barray_ptr *)
01480 jtransform_adjust_parameters (j_decompress_ptr srcinfo,
01481                   j_compress_ptr dstinfo,
01482                   jvirt_barray_ptr *src_coef_arrays,
01483                   jpeg_transform_info *info)
01484 {
01485   /* If force-to-grayscale is requested, adjust destination parameters */
01486   if (info->force_grayscale) {
01487     /* First, ensure we have YCC or grayscale data, and that the source's
01488      * Y channel is full resolution.  (No reasonable person would make Y
01489      * be less than full resolution, so actually coping with that case
01490      * isn't worth extra code space.  But we check it to avoid crashing.)
01491      */
01492     if ((((dstinfo->jpeg_color_space == JCS_YCbCr ||
01493        dstinfo->jpeg_color_space == JCS_BG_YCC) &&
01494       dstinfo->num_components == 3) ||
01495      (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
01496       dstinfo->num_components == 1)) &&
01497     srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
01498     srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
01499       /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
01500        * properly.  Among other things, it sets the target h_samp_factor &
01501        * v_samp_factor to 1, which typically won't match the source.
01502        * We have to preserve the source's quantization table number, however.
01503        */
01504       int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
01505       jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
01506       dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
01507     } else {
01508       /* Sorry, can't do it */
01509       ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
01510     }
01511   } else if (info->num_components == 1) {
01512     /* For a single-component source, we force the destination sampling factors
01513      * to 1x1, with or without force_grayscale.  This is useful because some
01514      * decoders choke on grayscale images with other sampling factors.
01515      */
01516     dstinfo->comp_info[0].h_samp_factor = 1;
01517     dstinfo->comp_info[0].v_samp_factor = 1;
01518   }
01519 
01520   /* Correct the destination's image dimensions as necessary
01521    * for rotate/flip, resize, and crop operations.
01522    */
01523   dstinfo->jpeg_width = info->output_width;
01524   dstinfo->jpeg_height = info->output_height;
01525 
01526   /* Transpose destination image parameters */
01527   switch (info->transform) {
01528   case JXFORM_TRANSPOSE:
01529   case JXFORM_TRANSVERSE:
01530   case JXFORM_ROT_90:
01531   case JXFORM_ROT_270:
01532     transpose_critical_parameters(dstinfo);
01533     break;
01534   default:
01535     break;
01536   }
01537 
01538   /* Adjust Exif properties */
01539   if (srcinfo->marker_list != NULL &&
01540       srcinfo->marker_list->marker == JPEG_APP0+1 &&
01541       srcinfo->marker_list->data_length >= 6 &&
01542       GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
01543       GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
01544       GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
01545       GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
01546       GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
01547       GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
01548     /* Suppress output of JFIF marker */
01549     dstinfo->write_JFIF_header = FALSE;
01550     /* Adjust Exif image parameters */
01551     if (dstinfo->jpeg_width != srcinfo->image_width ||
01552     dstinfo->jpeg_height != srcinfo->image_height)
01553       /* Align data segment to start of TIFF structure for parsing */
01554       adjust_exif_parameters(srcinfo->marker_list->data + 6,
01555     srcinfo->marker_list->data_length - 6,
01556     dstinfo->jpeg_width, dstinfo->jpeg_height);
01557   }
01558 
01559   /* Return the appropriate output data set */
01560   if (info->workspace_coef_arrays != NULL)
01561     return info->workspace_coef_arrays;
01562   return src_coef_arrays;
01563 }
01564 
01565 
01566 /* Execute the actual transformation, if any.
01567  *
01568  * This must be called *after* jpeg_write_coefficients, because it depends
01569  * on jpeg_write_coefficients to have computed subsidiary values such as
01570  * the per-component width and height fields in the destination object.
01571  *
01572  * Note that some transformations will modify the source data arrays!
01573  */
01574 
01575 GLOBAL(void)
01576 jtransform_execute_transform (j_decompress_ptr srcinfo,
01577                   j_compress_ptr dstinfo,
01578                   jvirt_barray_ptr *src_coef_arrays,
01579                   jpeg_transform_info *info)
01580 {
01581   jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
01582 
01583   /* Note: conditions tested here should match those in switch statement
01584    * in jtransform_request_workspace()
01585    */
01586   switch (info->transform) {
01587   case JXFORM_NONE:
01588     if (info->output_width > srcinfo->output_width ||
01589     info->output_height > srcinfo->output_height)
01590       do_crop_ext(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01591           src_coef_arrays, dst_coef_arrays);
01592     else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
01593       do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01594           src_coef_arrays, dst_coef_arrays);
01595     break;
01596   case JXFORM_FLIP_H:
01597     if (info->y_crop_offset != 0)
01598       do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01599         src_coef_arrays, dst_coef_arrays);
01600     else
01601       do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
01602             src_coef_arrays);
01603     break;
01604   case JXFORM_FLIP_V:
01605     do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01606           src_coef_arrays, dst_coef_arrays);
01607     break;
01608   case JXFORM_TRANSPOSE:
01609     do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01610          src_coef_arrays, dst_coef_arrays);
01611     break;
01612   case JXFORM_TRANSVERSE:
01613     do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01614           src_coef_arrays, dst_coef_arrays);
01615     break;
01616   case JXFORM_ROT_90:
01617     do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01618           src_coef_arrays, dst_coef_arrays);
01619     break;
01620   case JXFORM_ROT_180:
01621     do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01622            src_coef_arrays, dst_coef_arrays);
01623     break;
01624   case JXFORM_ROT_270:
01625     do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01626            src_coef_arrays, dst_coef_arrays);
01627     break;
01628   case JXFORM_WIPE:
01629     do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
01630         src_coef_arrays, info->drop_width, info->drop_height);
01631     break;
01632   }
01633 }
01634 
01635 /* jtransform_perfect_transform
01636  *
01637  * Determine whether lossless transformation is perfectly
01638  * possible for a specified image and transformation.
01639  *
01640  * Inputs:
01641  *   image_width, image_height: source image dimensions.
01642  *   MCU_width, MCU_height: pixel dimensions of MCU.
01643  *   transform: transformation identifier.
01644  * Parameter sources from initialized jpeg_struct
01645  * (after reading source header):
01646  *   image_width = cinfo.image_width
01647  *   image_height = cinfo.image_height
01648  *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
01649  *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
01650  * Result:
01651  *   TRUE = perfect transformation possible
01652  *   FALSE = perfect transformation not possible
01653  *           (may use custom action then)
01654  */
01655 
01656 GLOBAL(boolean)
01657 jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
01658                  int MCU_width, int MCU_height,
01659                  JXFORM_CODE transform)
01660 {
01661   boolean result = TRUE; /* initialize TRUE */
01662 
01663   switch (transform) {
01664   case JXFORM_FLIP_H:
01665   case JXFORM_ROT_270:
01666     if (image_width % (JDIMENSION) MCU_width)
01667       result = FALSE;
01668     break;
01669   case JXFORM_FLIP_V:
01670   case JXFORM_ROT_90:
01671     if (image_height % (JDIMENSION) MCU_height)
01672       result = FALSE;
01673     break;
01674   case JXFORM_TRANSVERSE:
01675   case JXFORM_ROT_180:
01676     if (image_width % (JDIMENSION) MCU_width)
01677       result = FALSE;
01678     if (image_height % (JDIMENSION) MCU_height)
01679       result = FALSE;
01680     break;
01681   default:
01682     break;
01683   }
01684 
01685   return result;
01686 }
01687 
01688 #endif /* TRANSFORMS_SUPPORTED */
01689 
01690 
01691 /* Setup decompression object to save desired markers in memory.
01692  * This must be called before jpeg_read_header() to have the desired effect.
01693  */
01694 
01695 GLOBAL(void)
01696 jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)
01697 {
01698 #ifdef SAVE_MARKERS_SUPPORTED
01699   int m;
01700 
01701   /* Save comments except under NONE option */
01702   if (option != JCOPYOPT_NONE) {
01703     jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
01704   }
01705   /* Save all types of APPn markers iff ALL option */
01706   if (option == JCOPYOPT_ALL) {
01707     for (m = 0; m < 16; m++)
01708       jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
01709   }
01710 #endif /* SAVE_MARKERS_SUPPORTED */
01711 }
01712 
01713 /* Copy markers saved in the given source object to the destination object.
01714  * This should be called just after jpeg_start_compress() or
01715  * jpeg_write_coefficients().
01716  * Note that those routines will have written the SOI, and also the
01717  * JFIF APP0 or Adobe APP14 markers if selected.
01718  */
01719 
01720 GLOBAL(void)
01721 jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
01722                JCOPY_OPTION option)
01723 {
01724   jpeg_saved_marker_ptr marker;
01725 
01726   /* In the current implementation, we don't actually need to examine the
01727    * option flag here; we just copy everything that got saved.
01728    * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
01729    * if the encoder library already wrote one.
01730    */
01731   for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
01732     if (dstinfo->write_JFIF_header &&
01733     marker->marker == JPEG_APP0 &&
01734     marker->data_length >= 5 &&
01735     GETJOCTET(marker->data[0]) == 0x4A &&
01736     GETJOCTET(marker->data[1]) == 0x46 &&
01737     GETJOCTET(marker->data[2]) == 0x49 &&
01738     GETJOCTET(marker->data[3]) == 0x46 &&
01739     GETJOCTET(marker->data[4]) == 0)
01740       continue;         /* reject duplicate JFIF */
01741     if (dstinfo->write_Adobe_marker &&
01742     marker->marker == JPEG_APP0+14 &&
01743     marker->data_length >= 5 &&
01744     GETJOCTET(marker->data[0]) == 0x41 &&
01745     GETJOCTET(marker->data[1]) == 0x64 &&
01746     GETJOCTET(marker->data[2]) == 0x6F &&
01747     GETJOCTET(marker->data[3]) == 0x62 &&
01748     GETJOCTET(marker->data[4]) == 0x65)
01749       continue;         /* reject duplicate Adobe */
01750 #ifdef NEED_FAR_POINTERS
01751     /* We could use jpeg_write_marker if the data weren't FAR... */
01752     {
01753       unsigned int i;
01754       jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);
01755       for (i = 0; i < marker->data_length; i++)
01756     jpeg_write_m_byte(dstinfo, marker->data[i]);
01757     }
01758 #else
01759     jpeg_write_marker(dstinfo, marker->marker,
01760               marker->data, marker->data_length);
01761 #endif
01762   }
01763 }