source: rtems-graphics-toolkit/jpeg-8d/transupp.c @ 86b99f7

Last change on this file since 86b99f7 was 86b99f7, checked in by Alexandru-Sever Horin <alex.sever.h@…>, on 08/01/12 at 22:40:32

Added jpeg-8d version. Made modifications to compile for RTEMS, without man or binaries

  • Property mode set to 100644
File size: 55.9 KB
Line 
1/*
2 * transupp.c
3 *
4 * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
5 * This file is part of the Independent JPEG Group's software.
6 * For conditions of distribution and use, see the accompanying README file.
7 *
8 * This file contains image transformation routines and other utility code
9 * used by the jpegtran sample application.  These are NOT part of the core
10 * JPEG library.  But we keep these routines separate from jpegtran.c to
11 * ease the task of maintaining jpegtran-like programs that have other user
12 * interfaces.
13 */
14
15/* Although this file really shouldn't have access to the library internals,
16 * it's helpful to let it call jround_up() and jcopy_block_row().
17 */
18#define JPEG_INTERNALS
19
20#include "jinclude.h"
21#include "jpeglib.h"
22#include "transupp.h"           /* My own external interface */
23#include <ctype.h>              /* to declare isdigit() */
24
25
26#if TRANSFORMS_SUPPORTED
27
28/*
29 * Lossless image transformation routines.  These routines work on DCT
30 * coefficient arrays and thus do not require any lossy decompression
31 * or recompression of the image.
32 * Thanks to Guido Vollbeding for the initial design and code of this feature,
33 * and to Ben Jackson for introducing the cropping feature.
34 *
35 * Horizontal flipping is done in-place, using a single top-to-bottom
36 * pass through the virtual source array.  It will thus be much the
37 * fastest option for images larger than main memory.
38 *
39 * The other routines require a set of destination virtual arrays, so they
40 * need twice as much memory as jpegtran normally does.  The destination
41 * arrays are always written in normal scan order (top to bottom) because
42 * the virtual array manager expects this.  The source arrays will be scanned
43 * in the corresponding order, which means multiple passes through the source
44 * arrays for most of the transforms.  That could result in much thrashing
45 * if the image is larger than main memory.
46 *
47 * If cropping or trimming is involved, the destination arrays may be smaller
48 * than the source arrays.  Note it is not possible to do horizontal flip
49 * in-place when a nonzero Y crop offset is specified, since we'd have to move
50 * data from one block row to another but the virtual array manager doesn't
51 * guarantee we can touch more than one row at a time.  So in that case,
52 * we have to use a separate destination array.
53 *
54 * Some notes about the operating environment of the individual transform
55 * routines:
56 * 1. Both the source and destination virtual arrays are allocated from the
57 *    source JPEG object, and therefore should be manipulated by calling the
58 *    source's memory manager.
59 * 2. The destination's component count should be used.  It may be smaller
60 *    than the source's when forcing to grayscale.
61 * 3. Likewise the destination's sampling factors should be used.  When
62 *    forcing to grayscale the destination's sampling factors will be all 1,
63 *    and we may as well take that as the effective iMCU size.
64 * 4. When "trim" is in effect, the destination's dimensions will be the
65 *    trimmed values but the source's will be untrimmed.
66 * 5. When "crop" is in effect, the destination's dimensions will be the
67 *    cropped values but the source's will be uncropped.  Each transform
68 *    routine is responsible for picking up source data starting at the
69 *    correct X and Y offset for the crop region.  (The X and Y offsets
70 *    passed to the transform routines are measured in iMCU blocks of the
71 *    destination.)
72 * 6. All the routines assume that the source and destination buffers are
73 *    padded out to a full iMCU boundary.  This is true, although for the
74 *    source buffer it is an undocumented property of jdcoefct.c.
75 */
76
77
78LOCAL(void)
79do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
80         JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
81         jvirt_barray_ptr *src_coef_arrays,
82         jvirt_barray_ptr *dst_coef_arrays)
83/* Crop.  This is only used when no rotate/flip is requested with the crop. */
84{
85  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
86  int ci, offset_y;
87  JBLOCKARRAY src_buffer, dst_buffer;
88  jpeg_component_info *compptr;
89
90  /* We simply have to copy the right amount of data (the destination's
91   * image size) starting at the given X and Y offsets in the source.
92   */
93  for (ci = 0; ci < dstinfo->num_components; ci++) {
94    compptr = dstinfo->comp_info + ci;
95    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
96    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
97    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
98         dst_blk_y += compptr->v_samp_factor) {
99      dst_buffer = (*srcinfo->mem->access_virt_barray)
100        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
101         (JDIMENSION) compptr->v_samp_factor, TRUE);
102      src_buffer = (*srcinfo->mem->access_virt_barray)
103        ((j_common_ptr) srcinfo, src_coef_arrays[ci],
104         dst_blk_y + y_crop_blocks,
105         (JDIMENSION) compptr->v_samp_factor, FALSE);
106      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
107        jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
108                        dst_buffer[offset_y],
109                        compptr->width_in_blocks);
110      }
111    }
112  }
113}
114
115
116LOCAL(void)
117do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
118                   JDIMENSION x_crop_offset,
119                   jvirt_barray_ptr *src_coef_arrays)
120/* Horizontal flip; done in-place, so no separate dest array is required.
121 * NB: this only works when y_crop_offset is zero.
122 */
123{
124  JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
125  int ci, k, offset_y;
126  JBLOCKARRAY buffer;
127  JCOEFPTR ptr1, ptr2;
128  JCOEF temp1, temp2;
129  jpeg_component_info *compptr;
130
131  /* Horizontal mirroring of DCT blocks is accomplished by swapping
132   * pairs of blocks in-place.  Within a DCT block, we perform horizontal
133   * mirroring by changing the signs of odd-numbered columns.
134   * Partial iMCUs at the right edge are left untouched.
135   */
136  MCU_cols = srcinfo->output_width /
137    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
138
139  for (ci = 0; ci < dstinfo->num_components; ci++) {
140    compptr = dstinfo->comp_info + ci;
141    comp_width = MCU_cols * compptr->h_samp_factor;
142    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
143    for (blk_y = 0; blk_y < compptr->height_in_blocks;
144         blk_y += compptr->v_samp_factor) {
145      buffer = (*srcinfo->mem->access_virt_barray)
146        ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
147         (JDIMENSION) compptr->v_samp_factor, TRUE);
148      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
149        /* Do the mirroring */
150        for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
151          ptr1 = buffer[offset_y][blk_x];
152          ptr2 = buffer[offset_y][comp_width - blk_x - 1];
153          /* this unrolled loop doesn't need to know which row it's on... */
154          for (k = 0; k < DCTSIZE2; k += 2) {
155            temp1 = *ptr1;      /* swap even column */
156            temp2 = *ptr2;
157            *ptr1++ = temp2;
158            *ptr2++ = temp1;
159            temp1 = *ptr1;      /* swap odd column with sign change */
160            temp2 = *ptr2;
161            *ptr1++ = -temp2;
162            *ptr2++ = -temp1;
163          }
164        }
165        if (x_crop_blocks > 0) {
166          /* Now left-justify the portion of the data to be kept.
167           * We can't use a single jcopy_block_row() call because that routine
168           * depends on memcpy(), whose behavior is unspecified for overlapping
169           * source and destination areas.  Sigh.
170           */
171          for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
172            jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
173                            buffer[offset_y] + blk_x,
174                            (JDIMENSION) 1);
175          }
176        }
177      }
178    }
179  }
180}
181
182
183LOCAL(void)
184do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
185           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
186           jvirt_barray_ptr *src_coef_arrays,
187           jvirt_barray_ptr *dst_coef_arrays)
188/* Horizontal flip in general cropping case */
189{
190  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
191  JDIMENSION x_crop_blocks, y_crop_blocks;
192  int ci, k, offset_y;
193  JBLOCKARRAY src_buffer, dst_buffer;
194  JBLOCKROW src_row_ptr, dst_row_ptr;
195  JCOEFPTR src_ptr, dst_ptr;
196  jpeg_component_info *compptr;
197
198  /* Here we must output into a separate array because we can't touch
199   * different rows of a single virtual array simultaneously.  Otherwise,
200   * this is essentially the same as the routine above.
201   */
202  MCU_cols = srcinfo->output_width /
203    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
204
205  for (ci = 0; ci < dstinfo->num_components; ci++) {
206    compptr = dstinfo->comp_info + ci;
207    comp_width = MCU_cols * compptr->h_samp_factor;
208    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
209    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
210    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
211         dst_blk_y += compptr->v_samp_factor) {
212      dst_buffer = (*srcinfo->mem->access_virt_barray)
213        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
214         (JDIMENSION) compptr->v_samp_factor, TRUE);
215      src_buffer = (*srcinfo->mem->access_virt_barray)
216        ((j_common_ptr) srcinfo, src_coef_arrays[ci],
217         dst_blk_y + y_crop_blocks,
218         (JDIMENSION) compptr->v_samp_factor, FALSE);
219      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
220        dst_row_ptr = dst_buffer[offset_y];
221        src_row_ptr = src_buffer[offset_y];
222        for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
223          if (x_crop_blocks + dst_blk_x < comp_width) {
224            /* Do the mirrorable blocks */
225            dst_ptr = dst_row_ptr[dst_blk_x];
226            src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
227            /* this unrolled loop doesn't need to know which row it's on... */
228            for (k = 0; k < DCTSIZE2; k += 2) {
229              *dst_ptr++ = *src_ptr++;   /* copy even column */
230              *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
231            }
232          } else {
233            /* Copy last partial block(s) verbatim */
234            jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
235                            dst_row_ptr + dst_blk_x,
236                            (JDIMENSION) 1);
237          }
238        }
239      }
240    }
241  }
242}
243
244
245LOCAL(void)
246do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
247           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
248           jvirt_barray_ptr *src_coef_arrays,
249           jvirt_barray_ptr *dst_coef_arrays)
250/* Vertical flip */
251{
252  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
253  JDIMENSION x_crop_blocks, y_crop_blocks;
254  int ci, i, j, offset_y;
255  JBLOCKARRAY src_buffer, dst_buffer;
256  JBLOCKROW src_row_ptr, dst_row_ptr;
257  JCOEFPTR src_ptr, dst_ptr;
258  jpeg_component_info *compptr;
259
260  /* We output into a separate array because we can't touch different
261   * rows of the source virtual array simultaneously.  Otherwise, this
262   * is a pretty straightforward analog of horizontal flip.
263   * Within a DCT block, vertical mirroring is done by changing the signs
264   * of odd-numbered rows.
265   * Partial iMCUs at the bottom edge are copied verbatim.
266   */
267  MCU_rows = srcinfo->output_height /
268    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
269
270  for (ci = 0; ci < dstinfo->num_components; ci++) {
271    compptr = dstinfo->comp_info + ci;
272    comp_height = MCU_rows * compptr->v_samp_factor;
273    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
274    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
275    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
276         dst_blk_y += compptr->v_samp_factor) {
277      dst_buffer = (*srcinfo->mem->access_virt_barray)
278        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
279         (JDIMENSION) compptr->v_samp_factor, TRUE);
280      if (y_crop_blocks + dst_blk_y < comp_height) {
281        /* Row is within the mirrorable area. */
282        src_buffer = (*srcinfo->mem->access_virt_barray)
283          ((j_common_ptr) srcinfo, src_coef_arrays[ci],
284           comp_height - y_crop_blocks - dst_blk_y -
285           (JDIMENSION) compptr->v_samp_factor,
286           (JDIMENSION) compptr->v_samp_factor, FALSE);
287      } else {
288        /* Bottom-edge blocks will be copied verbatim. */
289        src_buffer = (*srcinfo->mem->access_virt_barray)
290          ((j_common_ptr) srcinfo, src_coef_arrays[ci],
291           dst_blk_y + y_crop_blocks,
292           (JDIMENSION) compptr->v_samp_factor, FALSE);
293      }
294      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
295        if (y_crop_blocks + dst_blk_y < comp_height) {
296          /* Row is within the mirrorable area. */
297          dst_row_ptr = dst_buffer[offset_y];
298          src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
299          src_row_ptr += x_crop_blocks;
300          for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
301               dst_blk_x++) {
302            dst_ptr = dst_row_ptr[dst_blk_x];
303            src_ptr = src_row_ptr[dst_blk_x];
304            for (i = 0; i < DCTSIZE; i += 2) {
305              /* copy even row */
306              for (j = 0; j < DCTSIZE; j++)
307                *dst_ptr++ = *src_ptr++;
308              /* copy odd row with sign change */
309              for (j = 0; j < DCTSIZE; j++)
310                *dst_ptr++ = - *src_ptr++;
311            }
312          }
313        } else {
314          /* Just copy row verbatim. */
315          jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
316                          dst_buffer[offset_y],
317                          compptr->width_in_blocks);
318        }
319      }
320    }
321  }
322}
323
324
325LOCAL(void)
326do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
327              JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
328              jvirt_barray_ptr *src_coef_arrays,
329              jvirt_barray_ptr *dst_coef_arrays)
330/* Transpose source into destination */
331{
332  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
333  int ci, i, j, offset_x, offset_y;
334  JBLOCKARRAY src_buffer, dst_buffer;
335  JCOEFPTR src_ptr, dst_ptr;
336  jpeg_component_info *compptr;
337
338  /* Transposing pixels within a block just requires transposing the
339   * DCT coefficients.
340   * Partial iMCUs at the edges require no special treatment; we simply
341   * process all the available DCT blocks for every component.
342   */
343  for (ci = 0; ci < dstinfo->num_components; ci++) {
344    compptr = dstinfo->comp_info + ci;
345    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
346    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
347    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
348         dst_blk_y += compptr->v_samp_factor) {
349      dst_buffer = (*srcinfo->mem->access_virt_barray)
350        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
351         (JDIMENSION) compptr->v_samp_factor, TRUE);
352      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
353        for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
354             dst_blk_x += compptr->h_samp_factor) {
355          src_buffer = (*srcinfo->mem->access_virt_barray)
356            ((j_common_ptr) srcinfo, src_coef_arrays[ci],
357             dst_blk_x + x_crop_blocks,
358             (JDIMENSION) compptr->h_samp_factor, FALSE);
359          for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
360            dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
361            src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
362            for (i = 0; i < DCTSIZE; i++)
363              for (j = 0; j < DCTSIZE; j++)
364                dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
365          }
366        }
367      }
368    }
369  }
370}
371
372
373LOCAL(void)
374do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
375           JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
376           jvirt_barray_ptr *src_coef_arrays,
377           jvirt_barray_ptr *dst_coef_arrays)
378/* 90 degree rotation is equivalent to
379 *   1. Transposing the image;
380 *   2. Horizontal mirroring.
381 * These two steps are merged into a single processing routine.
382 */
383{
384  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
385  JDIMENSION x_crop_blocks, y_crop_blocks;
386  int ci, i, j, offset_x, offset_y;
387  JBLOCKARRAY src_buffer, dst_buffer;
388  JCOEFPTR src_ptr, dst_ptr;
389  jpeg_component_info *compptr;
390
391  /* Because of the horizontal mirror step, we can't process partial iMCUs
392   * at the (output) right edge properly.  They just get transposed and
393   * not mirrored.
394   */
395  MCU_cols = srcinfo->output_height /
396    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
397
398  for (ci = 0; ci < dstinfo->num_components; ci++) {
399    compptr = dstinfo->comp_info + ci;
400    comp_width = MCU_cols * compptr->h_samp_factor;
401    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
402    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
403    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
404         dst_blk_y += compptr->v_samp_factor) {
405      dst_buffer = (*srcinfo->mem->access_virt_barray)
406        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
407         (JDIMENSION) compptr->v_samp_factor, TRUE);
408      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
409        for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
410             dst_blk_x += compptr->h_samp_factor) {
411          if (x_crop_blocks + dst_blk_x < comp_width) {
412            /* Block is within the mirrorable area. */
413            src_buffer = (*srcinfo->mem->access_virt_barray)
414              ((j_common_ptr) srcinfo, src_coef_arrays[ci],
415               comp_width - x_crop_blocks - dst_blk_x -
416               (JDIMENSION) compptr->h_samp_factor,
417               (JDIMENSION) compptr->h_samp_factor, FALSE);
418          } else {
419            /* Edge blocks are transposed but not mirrored. */
420            src_buffer = (*srcinfo->mem->access_virt_barray)
421              ((j_common_ptr) srcinfo, src_coef_arrays[ci],
422               dst_blk_x + x_crop_blocks,
423               (JDIMENSION) compptr->h_samp_factor, FALSE);
424          }
425          for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
426            dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
427            if (x_crop_blocks + dst_blk_x < comp_width) {
428              /* Block is within the mirrorable area. */
429              src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
430                [dst_blk_y + offset_y + y_crop_blocks];
431              for (i = 0; i < DCTSIZE; i++) {
432                for (j = 0; j < DCTSIZE; j++)
433                  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
434                i++;
435                for (j = 0; j < DCTSIZE; j++)
436                  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
437              }
438            } else {
439              /* Edge blocks are transposed but not mirrored. */
440              src_ptr = src_buffer[offset_x]
441                [dst_blk_y + offset_y + y_crop_blocks];
442              for (i = 0; i < DCTSIZE; i++)
443                for (j = 0; j < DCTSIZE; j++)
444                  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
445            }
446          }
447        }
448      }
449    }
450  }
451}
452
453
454LOCAL(void)
455do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
456            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
457            jvirt_barray_ptr *src_coef_arrays,
458            jvirt_barray_ptr *dst_coef_arrays)
459/* 270 degree rotation is equivalent to
460 *   1. Horizontal mirroring;
461 *   2. Transposing the image.
462 * These two steps are merged into a single processing routine.
463 */
464{
465  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
466  JDIMENSION x_crop_blocks, y_crop_blocks;
467  int ci, i, j, offset_x, offset_y;
468  JBLOCKARRAY src_buffer, dst_buffer;
469  JCOEFPTR src_ptr, dst_ptr;
470  jpeg_component_info *compptr;
471
472  /* Because of the horizontal mirror step, we can't process partial iMCUs
473   * at the (output) bottom edge properly.  They just get transposed and
474   * not mirrored.
475   */
476  MCU_rows = srcinfo->output_width /
477    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
478
479  for (ci = 0; ci < dstinfo->num_components; ci++) {
480    compptr = dstinfo->comp_info + ci;
481    comp_height = MCU_rows * compptr->v_samp_factor;
482    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
483    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
484    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
485         dst_blk_y += compptr->v_samp_factor) {
486      dst_buffer = (*srcinfo->mem->access_virt_barray)
487        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
488         (JDIMENSION) compptr->v_samp_factor, TRUE);
489      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
490        for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
491             dst_blk_x += compptr->h_samp_factor) {
492          src_buffer = (*srcinfo->mem->access_virt_barray)
493            ((j_common_ptr) srcinfo, src_coef_arrays[ci],
494             dst_blk_x + x_crop_blocks,
495             (JDIMENSION) compptr->h_samp_factor, FALSE);
496          for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
497            dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
498            if (y_crop_blocks + dst_blk_y < comp_height) {
499              /* Block is within the mirrorable area. */
500              src_ptr = src_buffer[offset_x]
501                [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
502              for (i = 0; i < DCTSIZE; i++) {
503                for (j = 0; j < DCTSIZE; j++) {
504                  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
505                  j++;
506                  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
507                }
508              }
509            } else {
510              /* Edge blocks are transposed but not mirrored. */
511              src_ptr = src_buffer[offset_x]
512                [dst_blk_y + offset_y + y_crop_blocks];
513              for (i = 0; i < DCTSIZE; i++)
514                for (j = 0; j < DCTSIZE; j++)
515                  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
516            }
517          }
518        }
519      }
520    }
521  }
522}
523
524
525LOCAL(void)
526do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
527            JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
528            jvirt_barray_ptr *src_coef_arrays,
529            jvirt_barray_ptr *dst_coef_arrays)
530/* 180 degree rotation is equivalent to
531 *   1. Vertical mirroring;
532 *   2. Horizontal mirroring.
533 * These two steps are merged into a single processing routine.
534 */
535{
536  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
537  JDIMENSION x_crop_blocks, y_crop_blocks;
538  int ci, i, j, offset_y;
539  JBLOCKARRAY src_buffer, dst_buffer;
540  JBLOCKROW src_row_ptr, dst_row_ptr;
541  JCOEFPTR src_ptr, dst_ptr;
542  jpeg_component_info *compptr;
543
544  MCU_cols = srcinfo->output_width /
545    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
546  MCU_rows = srcinfo->output_height /
547    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
548
549  for (ci = 0; ci < dstinfo->num_components; ci++) {
550    compptr = dstinfo->comp_info + ci;
551    comp_width = MCU_cols * compptr->h_samp_factor;
552    comp_height = MCU_rows * compptr->v_samp_factor;
553    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
554    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
555    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
556         dst_blk_y += compptr->v_samp_factor) {
557      dst_buffer = (*srcinfo->mem->access_virt_barray)
558        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
559         (JDIMENSION) compptr->v_samp_factor, TRUE);
560      if (y_crop_blocks + dst_blk_y < comp_height) {
561        /* Row is within the vertically mirrorable area. */
562        src_buffer = (*srcinfo->mem->access_virt_barray)
563          ((j_common_ptr) srcinfo, src_coef_arrays[ci],
564           comp_height - y_crop_blocks - dst_blk_y -
565           (JDIMENSION) compptr->v_samp_factor,
566           (JDIMENSION) compptr->v_samp_factor, FALSE);
567      } else {
568        /* Bottom-edge rows are only mirrored horizontally. */
569        src_buffer = (*srcinfo->mem->access_virt_barray)
570          ((j_common_ptr) srcinfo, src_coef_arrays[ci],
571           dst_blk_y + y_crop_blocks,
572           (JDIMENSION) compptr->v_samp_factor, FALSE);
573      }
574      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
575        dst_row_ptr = dst_buffer[offset_y];
576        if (y_crop_blocks + dst_blk_y < comp_height) {
577          /* Row is within the mirrorable area. */
578          src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
579          for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
580            dst_ptr = dst_row_ptr[dst_blk_x];
581            if (x_crop_blocks + dst_blk_x < comp_width) {
582              /* Process the blocks that can be mirrored both ways. */
583              src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
584              for (i = 0; i < DCTSIZE; i += 2) {
585                /* For even row, negate every odd column. */
586                for (j = 0; j < DCTSIZE; j += 2) {
587                  *dst_ptr++ = *src_ptr++;
588                  *dst_ptr++ = - *src_ptr++;
589                }
590                /* For odd row, negate every even column. */
591                for (j = 0; j < DCTSIZE; j += 2) {
592                  *dst_ptr++ = - *src_ptr++;
593                  *dst_ptr++ = *src_ptr++;
594                }
595              }
596            } else {
597              /* Any remaining right-edge blocks are only mirrored vertically. */
598              src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
599              for (i = 0; i < DCTSIZE; i += 2) {
600                for (j = 0; j < DCTSIZE; j++)
601                  *dst_ptr++ = *src_ptr++;
602                for (j = 0; j < DCTSIZE; j++)
603                  *dst_ptr++ = - *src_ptr++;
604              }
605            }
606          }
607        } else {
608          /* Remaining rows are just mirrored horizontally. */
609          src_row_ptr = src_buffer[offset_y];
610          for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
611            if (x_crop_blocks + dst_blk_x < comp_width) {
612              /* Process the blocks that can be mirrored. */
613              dst_ptr = dst_row_ptr[dst_blk_x];
614              src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
615              for (i = 0; i < DCTSIZE2; i += 2) {
616                *dst_ptr++ = *src_ptr++;
617                *dst_ptr++ = - *src_ptr++;
618              }
619            } else {
620              /* Any remaining right-edge blocks are only copied. */
621              jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
622                              dst_row_ptr + dst_blk_x,
623                              (JDIMENSION) 1);
624            }
625          }
626        }
627      }
628    }
629  }
630}
631
632
633LOCAL(void)
634do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
635               JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
636               jvirt_barray_ptr *src_coef_arrays,
637               jvirt_barray_ptr *dst_coef_arrays)
638/* Transverse transpose is equivalent to
639 *   1. 180 degree rotation;
640 *   2. Transposition;
641 * or
642 *   1. Horizontal mirroring;
643 *   2. Transposition;
644 *   3. Horizontal mirroring.
645 * These steps are merged into a single processing routine.
646 */
647{
648  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
649  JDIMENSION x_crop_blocks, y_crop_blocks;
650  int ci, i, j, offset_x, offset_y;
651  JBLOCKARRAY src_buffer, dst_buffer;
652  JCOEFPTR src_ptr, dst_ptr;
653  jpeg_component_info *compptr;
654
655  MCU_cols = srcinfo->output_height /
656    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
657  MCU_rows = srcinfo->output_width /
658    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
659
660  for (ci = 0; ci < dstinfo->num_components; ci++) {
661    compptr = dstinfo->comp_info + ci;
662    comp_width = MCU_cols * compptr->h_samp_factor;
663    comp_height = MCU_rows * compptr->v_samp_factor;
664    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
665    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
666    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
667         dst_blk_y += compptr->v_samp_factor) {
668      dst_buffer = (*srcinfo->mem->access_virt_barray)
669        ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
670         (JDIMENSION) compptr->v_samp_factor, TRUE);
671      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
672        for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
673             dst_blk_x += compptr->h_samp_factor) {
674          if (x_crop_blocks + dst_blk_x < comp_width) {
675            /* Block is within the mirrorable area. */
676            src_buffer = (*srcinfo->mem->access_virt_barray)
677              ((j_common_ptr) srcinfo, src_coef_arrays[ci],
678               comp_width - x_crop_blocks - dst_blk_x -
679               (JDIMENSION) compptr->h_samp_factor,
680               (JDIMENSION) compptr->h_samp_factor, FALSE);
681          } else {
682            src_buffer = (*srcinfo->mem->access_virt_barray)
683              ((j_common_ptr) srcinfo, src_coef_arrays[ci],
684               dst_blk_x + x_crop_blocks,
685               (JDIMENSION) compptr->h_samp_factor, FALSE);
686          }
687          for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
688            dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
689            if (y_crop_blocks + dst_blk_y < comp_height) {
690              if (x_crop_blocks + dst_blk_x < comp_width) {
691                /* Block is within the mirrorable area. */
692                src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
693                  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
694                for (i = 0; i < DCTSIZE; i++) {
695                  for (j = 0; j < DCTSIZE; j++) {
696                    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
697                    j++;
698                    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
699                  }
700                  i++;
701                  for (j = 0; j < DCTSIZE; j++) {
702                    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
703                    j++;
704                    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
705                  }
706                }
707              } else {
708                /* Right-edge blocks are mirrored in y only */
709                src_ptr = src_buffer[offset_x]
710                  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
711                for (i = 0; i < DCTSIZE; i++) {
712                  for (j = 0; j < DCTSIZE; j++) {
713                    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
714                    j++;
715                    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
716                  }
717                }
718              }
719            } else {
720              if (x_crop_blocks + dst_blk_x < comp_width) {
721                /* Bottom-edge blocks are mirrored in x only */
722                src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
723                  [dst_blk_y + offset_y + y_crop_blocks];
724                for (i = 0; i < DCTSIZE; i++) {
725                  for (j = 0; j < DCTSIZE; j++)
726                    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
727                  i++;
728                  for (j = 0; j < DCTSIZE; j++)
729                    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
730                }
731              } else {
732                /* At lower right corner, just transpose, no mirroring */
733                src_ptr = src_buffer[offset_x]
734                  [dst_blk_y + offset_y + y_crop_blocks];
735                for (i = 0; i < DCTSIZE; i++)
736                  for (j = 0; j < DCTSIZE; j++)
737                    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
738              }
739            }
740          }
741        }
742      }
743    }
744  }
745}
746
747
748/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
749 * Returns TRUE if valid integer found, FALSE if not.
750 * *strptr is advanced over the digit string, and *result is set to its value.
751 */
752
753LOCAL(boolean)
754jt_read_integer (const char ** strptr, JDIMENSION * result)
755{
756  const char * ptr = *strptr;
757  JDIMENSION val = 0;
758
759  for (; isdigit(*ptr); ptr++) {
760    val = val * 10 + (JDIMENSION) (*ptr - '0');
761  }
762  *result = val;
763  if (ptr == *strptr)
764    return FALSE;               /* oops, no digits */
765  *strptr = ptr;
766  return TRUE;
767}
768
769
770/* Parse a crop specification (written in X11 geometry style).
771 * The routine returns TRUE if the spec string is valid, FALSE if not.
772 *
773 * The crop spec string should have the format
774 *      <width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset>
775 * where width, height, xoffset, and yoffset are unsigned integers.
776 * Each of the elements can be omitted to indicate a default value.
777 * (A weakness of this style is that it is not possible to omit xoffset
778 * while specifying yoffset, since they look alike.)
779 *
780 * This code is loosely based on XParseGeometry from the X11 distribution.
781 */
782
783GLOBAL(boolean)
784jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
785{
786  info->crop = FALSE;
787  info->crop_width_set = JCROP_UNSET;
788  info->crop_height_set = JCROP_UNSET;
789  info->crop_xoffset_set = JCROP_UNSET;
790  info->crop_yoffset_set = JCROP_UNSET;
791
792  if (isdigit(*spec)) {
793    /* fetch width */
794    if (! jt_read_integer(&spec, &info->crop_width))
795      return FALSE;
796    if (*spec == 'f' || *spec == 'F') {
797      spec++;
798      info->crop_width_set = JCROP_FORCE;
799    } else
800      info->crop_width_set = JCROP_POS;
801  }
802  if (*spec == 'x' || *spec == 'X') {
803    /* fetch height */
804    spec++;
805    if (! jt_read_integer(&spec, &info->crop_height))
806      return FALSE;
807    if (*spec == 'f' || *spec == 'F') {
808      spec++;
809      info->crop_height_set = JCROP_FORCE;
810    } else
811      info->crop_height_set = JCROP_POS;
812  }
813  if (*spec == '+' || *spec == '-') {
814    /* fetch xoffset */
815    info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
816    spec++;
817    if (! jt_read_integer(&spec, &info->crop_xoffset))
818      return FALSE;
819  }
820  if (*spec == '+' || *spec == '-') {
821    /* fetch yoffset */
822    info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
823    spec++;
824    if (! jt_read_integer(&spec, &info->crop_yoffset))
825      return FALSE;
826  }
827  /* We had better have gotten to the end of the string. */
828  if (*spec != '\0')
829    return FALSE;
830  info->crop = TRUE;
831  return TRUE;
832}
833
834
835/* Trim off any partial iMCUs on the indicated destination edge */
836
837LOCAL(void)
838trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
839{
840  JDIMENSION MCU_cols;
841
842  MCU_cols = info->output_width / info->iMCU_sample_width;
843  if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
844      full_width / info->iMCU_sample_width)
845    info->output_width = MCU_cols * info->iMCU_sample_width;
846}
847
848LOCAL(void)
849trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
850{
851  JDIMENSION MCU_rows;
852
853  MCU_rows = info->output_height / info->iMCU_sample_height;
854  if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
855      full_height / info->iMCU_sample_height)
856    info->output_height = MCU_rows * info->iMCU_sample_height;
857}
858
859
860/* Request any required workspace.
861 *
862 * This routine figures out the size that the output image will be
863 * (which implies that all the transform parameters must be set before
864 * it is called).
865 *
866 * We allocate the workspace virtual arrays from the source decompression
867 * object, so that all the arrays (both the original data and the workspace)
868 * will be taken into account while making memory management decisions.
869 * Hence, this routine must be called after jpeg_read_header (which reads
870 * the image dimensions) and before jpeg_read_coefficients (which realizes
871 * the source's virtual arrays).
872 *
873 * This function returns FALSE right away if -perfect is given
874 * and transformation is not perfect.  Otherwise returns TRUE.
875 */
876
877GLOBAL(boolean)
878jtransform_request_workspace (j_decompress_ptr srcinfo,
879                              jpeg_transform_info *info)
880{
881  jvirt_barray_ptr *coef_arrays;
882  boolean need_workspace, transpose_it;
883  jpeg_component_info *compptr;
884  JDIMENSION xoffset, yoffset;
885  JDIMENSION width_in_iMCUs, height_in_iMCUs;
886  JDIMENSION width_in_blocks, height_in_blocks;
887  int ci, h_samp_factor, v_samp_factor;
888
889  /* Determine number of components in output image */
890  if (info->force_grayscale &&
891      srcinfo->jpeg_color_space == JCS_YCbCr &&
892      srcinfo->num_components == 3)
893    /* We'll only process the first component */
894    info->num_components = 1;
895  else
896    /* Process all the components */
897    info->num_components = srcinfo->num_components;
898
899  /* Compute output image dimensions and related values. */
900  jpeg_core_output_dimensions(srcinfo);
901
902  /* Return right away if -perfect is given and transformation is not perfect.
903   */
904  if (info->perfect) {
905    if (info->num_components == 1) {
906      if (!jtransform_perfect_transform(srcinfo->output_width,
907          srcinfo->output_height,
908          srcinfo->min_DCT_h_scaled_size,
909          srcinfo->min_DCT_v_scaled_size,
910          info->transform))
911        return FALSE;
912    } else {
913      if (!jtransform_perfect_transform(srcinfo->output_width,
914          srcinfo->output_height,
915          srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size,
916          srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size,
917          info->transform))
918        return FALSE;
919    }
920  }
921
922  /* If there is only one output component, force the iMCU size to be 1;
923   * else use the source iMCU size.  (This allows us to do the right thing
924   * when reducing color to grayscale, and also provides a handy way of
925   * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
926   */
927  switch (info->transform) {
928  case JXFORM_TRANSPOSE:
929  case JXFORM_TRANSVERSE:
930  case JXFORM_ROT_90:
931  case JXFORM_ROT_270:
932    info->output_width = srcinfo->output_height;
933    info->output_height = srcinfo->output_width;
934    if (info->num_components == 1) {
935      info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;
936      info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;
937    } else {
938      info->iMCU_sample_width =
939        srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
940      info->iMCU_sample_height =
941        srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
942    }
943    break;
944  default:
945    info->output_width = srcinfo->output_width;
946    info->output_height = srcinfo->output_height;
947    if (info->num_components == 1) {
948      info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;
949      info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;
950    } else {
951      info->iMCU_sample_width =
952        srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
953      info->iMCU_sample_height =
954        srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
955    }
956    break;
957  }
958
959  /* If cropping has been requested, compute the crop area's position and
960   * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
961   */
962  if (info->crop) {
963    /* Insert default values for unset crop parameters */
964    if (info->crop_xoffset_set == JCROP_UNSET)
965      info->crop_xoffset = 0;   /* default to +0 */
966    if (info->crop_yoffset_set == JCROP_UNSET)
967      info->crop_yoffset = 0;   /* default to +0 */
968    if (info->crop_xoffset >= info->output_width ||
969        info->crop_yoffset >= info->output_height)
970      ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
971    if (info->crop_width_set == JCROP_UNSET)
972      info->crop_width = info->output_width - info->crop_xoffset;
973    if (info->crop_height_set == JCROP_UNSET)
974      info->crop_height = info->output_height - info->crop_yoffset;
975    /* Ensure parameters are valid */
976    if (info->crop_width <= 0 || info->crop_width > info->output_width ||
977        info->crop_height <= 0 || info->crop_height > info->output_height ||
978        info->crop_xoffset > info->output_width - info->crop_width ||
979        info->crop_yoffset > info->output_height - info->crop_height)
980      ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
981    /* Convert negative crop offsets into regular offsets */
982    if (info->crop_xoffset_set == JCROP_NEG)
983      xoffset = info->output_width - info->crop_width - info->crop_xoffset;
984    else
985      xoffset = info->crop_xoffset;
986    if (info->crop_yoffset_set == JCROP_NEG)
987      yoffset = info->output_height - info->crop_height - info->crop_yoffset;
988    else
989      yoffset = info->crop_yoffset;
990    /* Now adjust so that upper left corner falls at an iMCU boundary */
991    if (info->crop_width_set == JCROP_FORCE)
992      info->output_width = info->crop_width;
993    else
994      info->output_width =
995        info->crop_width + (xoffset % info->iMCU_sample_width);
996    if (info->crop_height_set == JCROP_FORCE)
997      info->output_height = info->crop_height;
998    else
999      info->output_height =
1000        info->crop_height + (yoffset % info->iMCU_sample_height);
1001    /* Save x/y offsets measured in iMCUs */
1002    info->x_crop_offset = xoffset / info->iMCU_sample_width;
1003    info->y_crop_offset = yoffset / info->iMCU_sample_height;
1004  } else {
1005    info->x_crop_offset = 0;
1006    info->y_crop_offset = 0;
1007  }
1008
1009  /* Figure out whether we need workspace arrays,
1010   * and if so whether they are transposed relative to the source.
1011   */
1012  need_workspace = FALSE;
1013  transpose_it = FALSE;
1014  switch (info->transform) {
1015  case JXFORM_NONE:
1016    if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1017      need_workspace = TRUE;
1018    /* No workspace needed if neither cropping nor transforming */
1019    break;
1020  case JXFORM_FLIP_H:
1021    if (info->trim)
1022      trim_right_edge(info, srcinfo->output_width);
1023    if (info->y_crop_offset != 0)
1024      need_workspace = TRUE;
1025    /* do_flip_h_no_crop doesn't need a workspace array */
1026    break;
1027  case JXFORM_FLIP_V:
1028    if (info->trim)
1029      trim_bottom_edge(info, srcinfo->output_height);
1030    /* Need workspace arrays having same dimensions as source image. */
1031    need_workspace = TRUE;
1032    break;
1033  case JXFORM_TRANSPOSE:
1034    /* transpose does NOT have to trim anything */
1035    /* Need workspace arrays having transposed dimensions. */
1036    need_workspace = TRUE;
1037    transpose_it = TRUE;
1038    break;
1039  case JXFORM_TRANSVERSE:
1040    if (info->trim) {
1041      trim_right_edge(info, srcinfo->output_height);
1042      trim_bottom_edge(info, srcinfo->output_width);
1043    }
1044    /* Need workspace arrays having transposed dimensions. */
1045    need_workspace = TRUE;
1046    transpose_it = TRUE;
1047    break;
1048  case JXFORM_ROT_90:
1049    if (info->trim)
1050      trim_right_edge(info, srcinfo->output_height);
1051    /* Need workspace arrays having transposed dimensions. */
1052    need_workspace = TRUE;
1053    transpose_it = TRUE;
1054    break;
1055  case JXFORM_ROT_180:
1056    if (info->trim) {
1057      trim_right_edge(info, srcinfo->output_width);
1058      trim_bottom_edge(info, srcinfo->output_height);
1059    }
1060    /* Need workspace arrays having same dimensions as source image. */
1061    need_workspace = TRUE;
1062    break;
1063  case JXFORM_ROT_270:
1064    if (info->trim)
1065      trim_bottom_edge(info, srcinfo->output_width);
1066    /* Need workspace arrays having transposed dimensions. */
1067    need_workspace = TRUE;
1068    transpose_it = TRUE;
1069    break;
1070  }
1071
1072  /* Allocate workspace if needed.
1073   * Note that we allocate arrays padded out to the next iMCU boundary,
1074   * so that transform routines need not worry about missing edge blocks.
1075   */
1076  if (need_workspace) {
1077    coef_arrays = (jvirt_barray_ptr *)
1078      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
1079                SIZEOF(jvirt_barray_ptr) * info->num_components);
1080    width_in_iMCUs = (JDIMENSION)
1081      jdiv_round_up((long) info->output_width,
1082                    (long) info->iMCU_sample_width);
1083    height_in_iMCUs = (JDIMENSION)
1084      jdiv_round_up((long) info->output_height,
1085                    (long) info->iMCU_sample_height);
1086    for (ci = 0; ci < info->num_components; ci++) {
1087      compptr = srcinfo->comp_info + ci;
1088      if (info->num_components == 1) {
1089        /* we're going to force samp factors to 1x1 in this case */
1090        h_samp_factor = v_samp_factor = 1;
1091      } else if (transpose_it) {
1092        h_samp_factor = compptr->v_samp_factor;
1093        v_samp_factor = compptr->h_samp_factor;
1094      } else {
1095        h_samp_factor = compptr->h_samp_factor;
1096        v_samp_factor = compptr->v_samp_factor;
1097      }
1098      width_in_blocks = width_in_iMCUs * h_samp_factor;
1099      height_in_blocks = height_in_iMCUs * v_samp_factor;
1100      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
1101        ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
1102         width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
1103    }
1104    info->workspace_coef_arrays = coef_arrays;
1105  } else
1106    info->workspace_coef_arrays = NULL;
1107
1108  return TRUE;
1109}
1110
1111
1112/* Transpose destination image parameters */
1113
1114LOCAL(void)
1115transpose_critical_parameters (j_compress_ptr dstinfo)
1116{
1117  int tblno, i, j, ci, itemp;
1118  jpeg_component_info *compptr;
1119  JQUANT_TBL *qtblptr;
1120  JDIMENSION jtemp;
1121  UINT16 qtemp;
1122
1123  /* Transpose image dimensions */
1124  jtemp = dstinfo->image_width;
1125  dstinfo->image_width = dstinfo->image_height;
1126  dstinfo->image_height = jtemp;
1127  itemp = dstinfo->min_DCT_h_scaled_size;
1128  dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
1129  dstinfo->min_DCT_v_scaled_size = itemp;
1130
1131  /* Transpose sampling factors */
1132  for (ci = 0; ci < dstinfo->num_components; ci++) {
1133    compptr = dstinfo->comp_info + ci;
1134    itemp = compptr->h_samp_factor;
1135    compptr->h_samp_factor = compptr->v_samp_factor;
1136    compptr->v_samp_factor = itemp;
1137  }
1138
1139  /* Transpose quantization tables */
1140  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
1141    qtblptr = dstinfo->quant_tbl_ptrs[tblno];
1142    if (qtblptr != NULL) {
1143      for (i = 0; i < DCTSIZE; i++) {
1144        for (j = 0; j < i; j++) {
1145          qtemp = qtblptr->quantval[i*DCTSIZE+j];
1146          qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];
1147          qtblptr->quantval[j*DCTSIZE+i] = qtemp;
1148        }
1149      }
1150    }
1151  }
1152}
1153
1154
1155/* Adjust Exif image parameters.
1156 *
1157 * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
1158 */
1159
1160LOCAL(void)
1161adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
1162                        JDIMENSION new_width, JDIMENSION new_height)
1163{
1164  boolean is_motorola; /* Flag for byte order */
1165  unsigned int number_of_tags, tagnum;
1166  unsigned int firstoffset, offset;
1167  JDIMENSION new_value;
1168
1169  if (length < 12) return; /* Length of an IFD entry */
1170
1171  /* Discover byte order */
1172  if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
1173    is_motorola = FALSE;
1174  else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
1175    is_motorola = TRUE;
1176  else
1177    return;
1178
1179  /* Check Tag Mark */
1180  if (is_motorola) {
1181    if (GETJOCTET(data[2]) != 0) return;
1182    if (GETJOCTET(data[3]) != 0x2A) return;
1183  } else {
1184    if (GETJOCTET(data[3]) != 0) return;
1185    if (GETJOCTET(data[2]) != 0x2A) return;
1186  }
1187
1188  /* Get first IFD offset (offset to IFD0) */
1189  if (is_motorola) {
1190    if (GETJOCTET(data[4]) != 0) return;
1191    if (GETJOCTET(data[5]) != 0) return;
1192    firstoffset = GETJOCTET(data[6]);
1193    firstoffset <<= 8;
1194    firstoffset += GETJOCTET(data[7]);
1195  } else {
1196    if (GETJOCTET(data[7]) != 0) return;
1197    if (GETJOCTET(data[6]) != 0) return;
1198    firstoffset = GETJOCTET(data[5]);
1199    firstoffset <<= 8;
1200    firstoffset += GETJOCTET(data[4]);
1201  }
1202  if (firstoffset > length - 2) return; /* check end of data segment */
1203
1204  /* Get the number of directory entries contained in this IFD */
1205  if (is_motorola) {
1206    number_of_tags = GETJOCTET(data[firstoffset]);
1207    number_of_tags <<= 8;
1208    number_of_tags += GETJOCTET(data[firstoffset+1]);
1209  } else {
1210    number_of_tags = GETJOCTET(data[firstoffset+1]);
1211    number_of_tags <<= 8;
1212    number_of_tags += GETJOCTET(data[firstoffset]);
1213  }
1214  if (number_of_tags == 0) return;
1215  firstoffset += 2;
1216
1217  /* Search for ExifSubIFD offset Tag in IFD0 */
1218  for (;;) {
1219    if (firstoffset > length - 12) return; /* check end of data segment */
1220    /* Get Tag number */
1221    if (is_motorola) {
1222      tagnum = GETJOCTET(data[firstoffset]);
1223      tagnum <<= 8;
1224      tagnum += GETJOCTET(data[firstoffset+1]);
1225    } else {
1226      tagnum = GETJOCTET(data[firstoffset+1]);
1227      tagnum <<= 8;
1228      tagnum += GETJOCTET(data[firstoffset]);
1229    }
1230    if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
1231    if (--number_of_tags == 0) return;
1232    firstoffset += 12;
1233  }
1234
1235  /* Get the ExifSubIFD offset */
1236  if (is_motorola) {
1237    if (GETJOCTET(data[firstoffset+8]) != 0) return;
1238    if (GETJOCTET(data[firstoffset+9]) != 0) return;
1239    offset = GETJOCTET(data[firstoffset+10]);
1240    offset <<= 8;
1241    offset += GETJOCTET(data[firstoffset+11]);
1242  } else {
1243    if (GETJOCTET(data[firstoffset+11]) != 0) return;
1244    if (GETJOCTET(data[firstoffset+10]) != 0) return;
1245    offset = GETJOCTET(data[firstoffset+9]);
1246    offset <<= 8;
1247    offset += GETJOCTET(data[firstoffset+8]);
1248  }
1249  if (offset > length - 2) return; /* check end of data segment */
1250
1251  /* Get the number of directory entries contained in this SubIFD */
1252  if (is_motorola) {
1253    number_of_tags = GETJOCTET(data[offset]);
1254    number_of_tags <<= 8;
1255    number_of_tags += GETJOCTET(data[offset+1]);
1256  } else {
1257    number_of_tags = GETJOCTET(data[offset+1]);
1258    number_of_tags <<= 8;
1259    number_of_tags += GETJOCTET(data[offset]);
1260  }
1261  if (number_of_tags < 2) return;
1262  offset += 2;
1263
1264  /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
1265  do {
1266    if (offset > length - 12) return; /* check end of data segment */
1267    /* Get Tag number */
1268    if (is_motorola) {
1269      tagnum = GETJOCTET(data[offset]);
1270      tagnum <<= 8;
1271      tagnum += GETJOCTET(data[offset+1]);
1272    } else {
1273      tagnum = GETJOCTET(data[offset+1]);
1274      tagnum <<= 8;
1275      tagnum += GETJOCTET(data[offset]);
1276    }
1277    if (tagnum == 0xA002 || tagnum == 0xA003) {
1278      if (tagnum == 0xA002)
1279        new_value = new_width; /* ExifImageWidth Tag */
1280      else
1281        new_value = new_height; /* ExifImageHeight Tag */
1282      if (is_motorola) {
1283        data[offset+2] = 0; /* Format = unsigned long (4 octets) */
1284        data[offset+3] = 4;
1285        data[offset+4] = 0; /* Number Of Components = 1 */
1286        data[offset+5] = 0;
1287        data[offset+6] = 0;
1288        data[offset+7] = 1;
1289        data[offset+8] = 0;
1290        data[offset+9] = 0;
1291        data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
1292        data[offset+11] = (JOCTET)(new_value & 0xFF);
1293      } else {
1294        data[offset+2] = 4; /* Format = unsigned long (4 octets) */
1295        data[offset+3] = 0;
1296        data[offset+4] = 1; /* Number Of Components = 1 */
1297        data[offset+5] = 0;
1298        data[offset+6] = 0;
1299        data[offset+7] = 0;
1300        data[offset+8] = (JOCTET)(new_value & 0xFF);
1301        data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
1302        data[offset+10] = 0;
1303        data[offset+11] = 0;
1304      }
1305    }
1306    offset += 12;
1307  } while (--number_of_tags);
1308}
1309
1310
1311/* Adjust output image parameters as needed.
1312 *
1313 * This must be called after jpeg_copy_critical_parameters()
1314 * and before jpeg_write_coefficients().
1315 *
1316 * The return value is the set of virtual coefficient arrays to be written
1317 * (either the ones allocated by jtransform_request_workspace, or the
1318 * original source data arrays).  The caller will need to pass this value
1319 * to jpeg_write_coefficients().
1320 */
1321
1322GLOBAL(jvirt_barray_ptr *)
1323jtransform_adjust_parameters (j_decompress_ptr srcinfo,
1324                              j_compress_ptr dstinfo,
1325                              jvirt_barray_ptr *src_coef_arrays,
1326                              jpeg_transform_info *info)
1327{
1328  /* If force-to-grayscale is requested, adjust destination parameters */
1329  if (info->force_grayscale) {
1330    /* First, ensure we have YCbCr or grayscale data, and that the source's
1331     * Y channel is full resolution.  (No reasonable person would make Y
1332     * be less than full resolution, so actually coping with that case
1333     * isn't worth extra code space.  But we check it to avoid crashing.)
1334     */
1335    if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
1336          dstinfo->num_components == 3) ||
1337         (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
1338          dstinfo->num_components == 1)) &&
1339        srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
1340        srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
1341      /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
1342       * properly.  Among other things, it sets the target h_samp_factor &
1343       * v_samp_factor to 1, which typically won't match the source.
1344       * We have to preserve the source's quantization table number, however.
1345       */
1346      int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
1347      jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
1348      dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
1349    } else {
1350      /* Sorry, can't do it */
1351      ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
1352    }
1353  } else if (info->num_components == 1) {
1354    /* For a single-component source, we force the destination sampling factors
1355     * to 1x1, with or without force_grayscale.  This is useful because some
1356     * decoders choke on grayscale images with other sampling factors.
1357     */
1358    dstinfo->comp_info[0].h_samp_factor = 1;
1359    dstinfo->comp_info[0].v_samp_factor = 1;
1360  }
1361
1362  /* Correct the destination's image dimensions as necessary
1363   * for rotate/flip, resize, and crop operations.
1364   */
1365  dstinfo->jpeg_width = info->output_width;
1366  dstinfo->jpeg_height = info->output_height;
1367
1368  /* Transpose destination image parameters */
1369  switch (info->transform) {
1370  case JXFORM_TRANSPOSE:
1371  case JXFORM_TRANSVERSE:
1372  case JXFORM_ROT_90:
1373  case JXFORM_ROT_270:
1374    transpose_critical_parameters(dstinfo);
1375    break;
1376  default:
1377    break;
1378  }
1379
1380  /* Adjust Exif properties */
1381  if (srcinfo->marker_list != NULL &&
1382      srcinfo->marker_list->marker == JPEG_APP0+1 &&
1383      srcinfo->marker_list->data_length >= 6 &&
1384      GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
1385      GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
1386      GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
1387      GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
1388      GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
1389      GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
1390    /* Suppress output of JFIF marker */
1391    dstinfo->write_JFIF_header = FALSE;
1392    /* Adjust Exif image parameters */
1393    if (dstinfo->jpeg_width != srcinfo->image_width ||
1394        dstinfo->jpeg_height != srcinfo->image_height)
1395      /* Align data segment to start of TIFF structure for parsing */
1396      adjust_exif_parameters(srcinfo->marker_list->data + 6,
1397        srcinfo->marker_list->data_length - 6,
1398        dstinfo->jpeg_width, dstinfo->jpeg_height);
1399  }
1400
1401  /* Return the appropriate output data set */
1402  if (info->workspace_coef_arrays != NULL)
1403    return info->workspace_coef_arrays;
1404  return src_coef_arrays;
1405}
1406
1407
1408/* Execute the actual transformation, if any.
1409 *
1410 * This must be called *after* jpeg_write_coefficients, because it depends
1411 * on jpeg_write_coefficients to have computed subsidiary values such as
1412 * the per-component width and height fields in the destination object.
1413 *
1414 * Note that some transformations will modify the source data arrays!
1415 */
1416
1417GLOBAL(void)
1418jtransform_execute_transform (j_decompress_ptr srcinfo,
1419                              j_compress_ptr dstinfo,
1420                              jvirt_barray_ptr *src_coef_arrays,
1421                              jpeg_transform_info *info)
1422{
1423  jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
1424
1425  /* Note: conditions tested here should match those in switch statement
1426   * in jtransform_request_workspace()
1427   */
1428  switch (info->transform) {
1429  case JXFORM_NONE:
1430    if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
1431      do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1432              src_coef_arrays, dst_coef_arrays);
1433    break;
1434  case JXFORM_FLIP_H:
1435    if (info->y_crop_offset != 0)
1436      do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1437                src_coef_arrays, dst_coef_arrays);
1438    else
1439      do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
1440                        src_coef_arrays);
1441    break;
1442  case JXFORM_FLIP_V:
1443    do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1444              src_coef_arrays, dst_coef_arrays);
1445    break;
1446  case JXFORM_TRANSPOSE:
1447    do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1448                 src_coef_arrays, dst_coef_arrays);
1449    break;
1450  case JXFORM_TRANSVERSE:
1451    do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1452                  src_coef_arrays, dst_coef_arrays);
1453    break;
1454  case JXFORM_ROT_90:
1455    do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1456              src_coef_arrays, dst_coef_arrays);
1457    break;
1458  case JXFORM_ROT_180:
1459    do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1460               src_coef_arrays, dst_coef_arrays);
1461    break;
1462  case JXFORM_ROT_270:
1463    do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
1464               src_coef_arrays, dst_coef_arrays);
1465    break;
1466  }
1467}
1468
1469/* jtransform_perfect_transform
1470 *
1471 * Determine whether lossless transformation is perfectly
1472 * possible for a specified image and transformation.
1473 *
1474 * Inputs:
1475 *   image_width, image_height: source image dimensions.
1476 *   MCU_width, MCU_height: pixel dimensions of MCU.
1477 *   transform: transformation identifier.
1478 * Parameter sources from initialized jpeg_struct
1479 * (after reading source header):
1480 *   image_width = cinfo.image_width
1481 *   image_height = cinfo.image_height
1482 *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
1483 *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
1484 * Result:
1485 *   TRUE = perfect transformation possible
1486 *   FALSE = perfect transformation not possible
1487 *           (may use custom action then)
1488 */
1489
1490GLOBAL(boolean)
1491jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
1492                             int MCU_width, int MCU_height,
1493                             JXFORM_CODE transform)
1494{
1495  boolean result = TRUE; /* initialize TRUE */
1496
1497  switch (transform) {
1498  case JXFORM_FLIP_H:
1499  case JXFORM_ROT_270:
1500    if (image_width % (JDIMENSION) MCU_width)
1501      result = FALSE;
1502    break;
1503  case JXFORM_FLIP_V:
1504  case JXFORM_ROT_90:
1505    if (image_height % (JDIMENSION) MCU_height)
1506      result = FALSE;
1507    break;
1508  case JXFORM_TRANSVERSE:
1509  case JXFORM_ROT_180:
1510    if (image_width % (JDIMENSION) MCU_width)
1511      result = FALSE;
1512    if (image_height % (JDIMENSION) MCU_height)
1513      result = FALSE;
1514    break;
1515  default:
1516    break;
1517  }
1518
1519  return result;
1520}
1521
1522#endif /* TRANSFORMS_SUPPORTED */
1523
1524
1525/* Setup decompression object to save desired markers in memory.
1526 * This must be called before jpeg_read_header() to have the desired effect.
1527 */
1528
1529GLOBAL(void)
1530jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)
1531{
1532#ifdef SAVE_MARKERS_SUPPORTED
1533  int m;
1534
1535  /* Save comments except under NONE option */
1536  if (option != JCOPYOPT_NONE) {
1537    jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
1538  }
1539  /* Save all types of APPn markers iff ALL option */
1540  if (option == JCOPYOPT_ALL) {
1541    for (m = 0; m < 16; m++)
1542      jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
1543  }
1544#endif /* SAVE_MARKERS_SUPPORTED */
1545}
1546
1547/* Copy markers saved in the given source object to the destination object.
1548 * This should be called just after jpeg_start_compress() or
1549 * jpeg_write_coefficients().
1550 * Note that those routines will have written the SOI, and also the
1551 * JFIF APP0 or Adobe APP14 markers if selected.
1552 */
1553
1554GLOBAL(void)
1555jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
1556                       JCOPY_OPTION option)
1557{
1558  jpeg_saved_marker_ptr marker;
1559
1560  /* In the current implementation, we don't actually need to examine the
1561   * option flag here; we just copy everything that got saved.
1562   * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
1563   * if the encoder library already wrote one.
1564   */
1565  for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
1566    if (dstinfo->write_JFIF_header &&
1567        marker->marker == JPEG_APP0 &&
1568        marker->data_length >= 5 &&
1569        GETJOCTET(marker->data[0]) == 0x4A &&
1570        GETJOCTET(marker->data[1]) == 0x46 &&
1571        GETJOCTET(marker->data[2]) == 0x49 &&
1572        GETJOCTET(marker->data[3]) == 0x46 &&
1573        GETJOCTET(marker->data[4]) == 0)
1574      continue;                 /* reject duplicate JFIF */
1575    if (dstinfo->write_Adobe_marker &&
1576        marker->marker == JPEG_APP0+14 &&
1577        marker->data_length >= 5 &&
1578        GETJOCTET(marker->data[0]) == 0x41 &&
1579        GETJOCTET(marker->data[1]) == 0x64 &&
1580        GETJOCTET(marker->data[2]) == 0x6F &&
1581        GETJOCTET(marker->data[3]) == 0x62 &&
1582        GETJOCTET(marker->data[4]) == 0x65)
1583      continue;                 /* reject duplicate Adobe */
1584#ifdef NEED_FAR_POINTERS
1585    /* We could use jpeg_write_marker if the data weren't FAR... */
1586    {
1587      unsigned int i;
1588      jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);
1589      for (i = 0; i < marker->data_length; i++)
1590        jpeg_write_m_byte(dstinfo, marker->data[i]);
1591    }
1592#else
1593    jpeg_write_marker(dstinfo, marker->marker,
1594                      marker->data, marker->data_length);
1595#endif
1596  }
1597}
Note: See TracBrowser for help on using the repository browser.