xref: /plan9/sys/src/cmd/gs/jpeg/transupp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1*593dc095SDavid du Colombier /*
2*593dc095SDavid du Colombier  * transupp.c
3*593dc095SDavid du Colombier  *
4*593dc095SDavid du Colombier  * Copyright (C) 1997, Thomas G. Lane.
5*593dc095SDavid du Colombier  * This file is part of the Independent JPEG Group's software.
6*593dc095SDavid du Colombier  * For conditions of distribution and use, see the accompanying README file.
7*593dc095SDavid du Colombier  *
8*593dc095SDavid du Colombier  * This file contains image transformation routines and other utility code
9*593dc095SDavid du Colombier  * used by the jpegtran sample application.  These are NOT part of the core
10*593dc095SDavid du Colombier  * JPEG library.  But we keep these routines separate from jpegtran.c to
11*593dc095SDavid du Colombier  * ease the task of maintaining jpegtran-like programs that have other user
12*593dc095SDavid du Colombier  * interfaces.
13*593dc095SDavid du Colombier  */
14*593dc095SDavid du Colombier 
15*593dc095SDavid du Colombier /* Although this file really shouldn't have access to the library internals,
16*593dc095SDavid du Colombier  * it's helpful to let it call jround_up() and jcopy_block_row().
17*593dc095SDavid du Colombier  */
18*593dc095SDavid du Colombier #define JPEG_INTERNALS
19*593dc095SDavid du Colombier 
20*593dc095SDavid du Colombier #include "jinclude.h"
21*593dc095SDavid du Colombier #include "jpeglib.h"
22*593dc095SDavid du Colombier #include "transupp.h"		/* My own external interface */
23*593dc095SDavid du Colombier 
24*593dc095SDavid du Colombier 
25*593dc095SDavid du Colombier #if TRANSFORMS_SUPPORTED
26*593dc095SDavid du Colombier 
27*593dc095SDavid du Colombier /*
28*593dc095SDavid du Colombier  * Lossless image transformation routines.  These routines work on DCT
29*593dc095SDavid du Colombier  * coefficient arrays and thus do not require any lossy decompression
30*593dc095SDavid du Colombier  * or recompression of the image.
31*593dc095SDavid du Colombier  * Thanks to Guido Vollbeding for the initial design and code of this feature.
32*593dc095SDavid du Colombier  *
33*593dc095SDavid du Colombier  * Horizontal flipping is done in-place, using a single top-to-bottom
34*593dc095SDavid du Colombier  * pass through the virtual source array.  It will thus be much the
35*593dc095SDavid du Colombier  * fastest option for images larger than main memory.
36*593dc095SDavid du Colombier  *
37*593dc095SDavid du Colombier  * The other routines require a set of destination virtual arrays, so they
38*593dc095SDavid du Colombier  * need twice as much memory as jpegtran normally does.  The destination
39*593dc095SDavid du Colombier  * arrays are always written in normal scan order (top to bottom) because
40*593dc095SDavid du Colombier  * the virtual array manager expects this.  The source arrays will be scanned
41*593dc095SDavid du Colombier  * in the corresponding order, which means multiple passes through the source
42*593dc095SDavid du Colombier  * arrays for most of the transforms.  That could result in much thrashing
43*593dc095SDavid du Colombier  * if the image is larger than main memory.
44*593dc095SDavid du Colombier  *
45*593dc095SDavid du Colombier  * Some notes about the operating environment of the individual transform
46*593dc095SDavid du Colombier  * routines:
47*593dc095SDavid du Colombier  * 1. Both the source and destination virtual arrays are allocated from the
48*593dc095SDavid du Colombier  *    source JPEG object, and therefore should be manipulated by calling the
49*593dc095SDavid du Colombier  *    source's memory manager.
50*593dc095SDavid du Colombier  * 2. The destination's component count should be used.  It may be smaller
51*593dc095SDavid du Colombier  *    than the source's when forcing to grayscale.
52*593dc095SDavid du Colombier  * 3. Likewise the destination's sampling factors should be used.  When
53*593dc095SDavid du Colombier  *    forcing to grayscale the destination's sampling factors will be all 1,
54*593dc095SDavid du Colombier  *    and we may as well take that as the effective iMCU size.
55*593dc095SDavid du Colombier  * 4. When "trim" is in effect, the destination's dimensions will be the
56*593dc095SDavid du Colombier  *    trimmed values but the source's will be untrimmed.
57*593dc095SDavid du Colombier  * 5. All the routines assume that the source and destination buffers are
58*593dc095SDavid du Colombier  *    padded out to a full iMCU boundary.  This is true, although for the
59*593dc095SDavid du Colombier  *    source buffer it is an undocumented property of jdcoefct.c.
60*593dc095SDavid du Colombier  * Notes 2,3,4 boil down to this: generally we should use the destination's
61*593dc095SDavid du Colombier  * dimensions and ignore the source's.
62*593dc095SDavid du Colombier  */
63*593dc095SDavid du Colombier 
64*593dc095SDavid du Colombier 
65*593dc095SDavid du Colombier LOCAL(void)
do_flip_h(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays)66*593dc095SDavid du Colombier do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
67*593dc095SDavid du Colombier 	   jvirt_barray_ptr *src_coef_arrays)
68*593dc095SDavid du Colombier /* Horizontal flip; done in-place, so no separate dest array is required */
69*593dc095SDavid du Colombier {
70*593dc095SDavid du Colombier   JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
71*593dc095SDavid du Colombier   int ci, k, offset_y;
72*593dc095SDavid du Colombier   JBLOCKARRAY buffer;
73*593dc095SDavid du Colombier   JCOEFPTR ptr1, ptr2;
74*593dc095SDavid du Colombier   JCOEF temp1, temp2;
75*593dc095SDavid du Colombier   jpeg_component_info *compptr;
76*593dc095SDavid du Colombier 
77*593dc095SDavid du Colombier   /* Horizontal mirroring of DCT blocks is accomplished by swapping
78*593dc095SDavid du Colombier    * pairs of blocks in-place.  Within a DCT block, we perform horizontal
79*593dc095SDavid du Colombier    * mirroring by changing the signs of odd-numbered columns.
80*593dc095SDavid du Colombier    * Partial iMCUs at the right edge are left untouched.
81*593dc095SDavid du Colombier    */
82*593dc095SDavid du Colombier   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
83*593dc095SDavid du Colombier 
84*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
85*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
86*593dc095SDavid du Colombier     comp_width = MCU_cols * compptr->h_samp_factor;
87*593dc095SDavid du Colombier     for (blk_y = 0; blk_y < compptr->height_in_blocks;
88*593dc095SDavid du Colombier 	 blk_y += compptr->v_samp_factor) {
89*593dc095SDavid du Colombier       buffer = (*srcinfo->mem->access_virt_barray)
90*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
91*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
92*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
93*593dc095SDavid du Colombier 	for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
94*593dc095SDavid du Colombier 	  ptr1 = buffer[offset_y][blk_x];
95*593dc095SDavid du Colombier 	  ptr2 = buffer[offset_y][comp_width - blk_x - 1];
96*593dc095SDavid du Colombier 	  /* this unrolled loop doesn't need to know which row it's on... */
97*593dc095SDavid du Colombier 	  for (k = 0; k < DCTSIZE2; k += 2) {
98*593dc095SDavid du Colombier 	    temp1 = *ptr1;	/* swap even column */
99*593dc095SDavid du Colombier 	    temp2 = *ptr2;
100*593dc095SDavid du Colombier 	    *ptr1++ = temp2;
101*593dc095SDavid du Colombier 	    *ptr2++ = temp1;
102*593dc095SDavid du Colombier 	    temp1 = *ptr1;	/* swap odd column with sign change */
103*593dc095SDavid du Colombier 	    temp2 = *ptr2;
104*593dc095SDavid du Colombier 	    *ptr1++ = -temp2;
105*593dc095SDavid du Colombier 	    *ptr2++ = -temp1;
106*593dc095SDavid du Colombier 	  }
107*593dc095SDavid du Colombier 	}
108*593dc095SDavid du Colombier       }
109*593dc095SDavid du Colombier     }
110*593dc095SDavid du Colombier   }
111*593dc095SDavid du Colombier }
112*593dc095SDavid du Colombier 
113*593dc095SDavid du Colombier 
114*593dc095SDavid du Colombier LOCAL(void)
do_flip_v(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)115*593dc095SDavid du Colombier do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
116*593dc095SDavid du Colombier 	   jvirt_barray_ptr *src_coef_arrays,
117*593dc095SDavid du Colombier 	   jvirt_barray_ptr *dst_coef_arrays)
118*593dc095SDavid du Colombier /* Vertical flip */
119*593dc095SDavid du Colombier {
120*593dc095SDavid du Colombier   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
121*593dc095SDavid du Colombier   int ci, i, j, offset_y;
122*593dc095SDavid du Colombier   JBLOCKARRAY src_buffer, dst_buffer;
123*593dc095SDavid du Colombier   JBLOCKROW src_row_ptr, dst_row_ptr;
124*593dc095SDavid du Colombier   JCOEFPTR src_ptr, dst_ptr;
125*593dc095SDavid du Colombier   jpeg_component_info *compptr;
126*593dc095SDavid du Colombier 
127*593dc095SDavid du Colombier   /* We output into a separate array because we can't touch different
128*593dc095SDavid du Colombier    * rows of the source virtual array simultaneously.  Otherwise, this
129*593dc095SDavid du Colombier    * is a pretty straightforward analog of horizontal flip.
130*593dc095SDavid du Colombier    * Within a DCT block, vertical mirroring is done by changing the signs
131*593dc095SDavid du Colombier    * of odd-numbered rows.
132*593dc095SDavid du Colombier    * Partial iMCUs at the bottom edge are copied verbatim.
133*593dc095SDavid du Colombier    */
134*593dc095SDavid du Colombier   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
135*593dc095SDavid du Colombier 
136*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
137*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
138*593dc095SDavid du Colombier     comp_height = MCU_rows * compptr->v_samp_factor;
139*593dc095SDavid du Colombier     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
140*593dc095SDavid du Colombier 	 dst_blk_y += compptr->v_samp_factor) {
141*593dc095SDavid du Colombier       dst_buffer = (*srcinfo->mem->access_virt_barray)
142*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
143*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
144*593dc095SDavid du Colombier       if (dst_blk_y < comp_height) {
145*593dc095SDavid du Colombier 	/* Row is within the mirrorable area. */
146*593dc095SDavid du Colombier 	src_buffer = (*srcinfo->mem->access_virt_barray)
147*593dc095SDavid du Colombier 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
148*593dc095SDavid du Colombier 	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
149*593dc095SDavid du Colombier 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
150*593dc095SDavid du Colombier       } else {
151*593dc095SDavid du Colombier 	/* Bottom-edge blocks will be copied verbatim. */
152*593dc095SDavid du Colombier 	src_buffer = (*srcinfo->mem->access_virt_barray)
153*593dc095SDavid du Colombier 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
154*593dc095SDavid du Colombier 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
155*593dc095SDavid du Colombier       }
156*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
157*593dc095SDavid du Colombier 	if (dst_blk_y < comp_height) {
158*593dc095SDavid du Colombier 	  /* Row is within the mirrorable area. */
159*593dc095SDavid du Colombier 	  dst_row_ptr = dst_buffer[offset_y];
160*593dc095SDavid du Colombier 	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
161*593dc095SDavid du Colombier 	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
162*593dc095SDavid du Colombier 	       dst_blk_x++) {
163*593dc095SDavid du Colombier 	    dst_ptr = dst_row_ptr[dst_blk_x];
164*593dc095SDavid du Colombier 	    src_ptr = src_row_ptr[dst_blk_x];
165*593dc095SDavid du Colombier 	    for (i = 0; i < DCTSIZE; i += 2) {
166*593dc095SDavid du Colombier 	      /* copy even row */
167*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j++)
168*593dc095SDavid du Colombier 		*dst_ptr++ = *src_ptr++;
169*593dc095SDavid du Colombier 	      /* copy odd row with sign change */
170*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j++)
171*593dc095SDavid du Colombier 		*dst_ptr++ = - *src_ptr++;
172*593dc095SDavid du Colombier 	    }
173*593dc095SDavid du Colombier 	  }
174*593dc095SDavid du Colombier 	} else {
175*593dc095SDavid du Colombier 	  /* Just copy row verbatim. */
176*593dc095SDavid du Colombier 	  jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
177*593dc095SDavid du Colombier 			  compptr->width_in_blocks);
178*593dc095SDavid du Colombier 	}
179*593dc095SDavid du Colombier       }
180*593dc095SDavid du Colombier     }
181*593dc095SDavid du Colombier   }
182*593dc095SDavid du Colombier }
183*593dc095SDavid du Colombier 
184*593dc095SDavid du Colombier 
185*593dc095SDavid du Colombier LOCAL(void)
do_transpose(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)186*593dc095SDavid du Colombier do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
187*593dc095SDavid du Colombier 	      jvirt_barray_ptr *src_coef_arrays,
188*593dc095SDavid du Colombier 	      jvirt_barray_ptr *dst_coef_arrays)
189*593dc095SDavid du Colombier /* Transpose source into destination */
190*593dc095SDavid du Colombier {
191*593dc095SDavid du Colombier   JDIMENSION dst_blk_x, dst_blk_y;
192*593dc095SDavid du Colombier   int ci, i, j, offset_x, offset_y;
193*593dc095SDavid du Colombier   JBLOCKARRAY src_buffer, dst_buffer;
194*593dc095SDavid du Colombier   JCOEFPTR src_ptr, dst_ptr;
195*593dc095SDavid du Colombier   jpeg_component_info *compptr;
196*593dc095SDavid du Colombier 
197*593dc095SDavid du Colombier   /* Transposing pixels within a block just requires transposing the
198*593dc095SDavid du Colombier    * DCT coefficients.
199*593dc095SDavid du Colombier    * Partial iMCUs at the edges require no special treatment; we simply
200*593dc095SDavid du Colombier    * process all the available DCT blocks for every component.
201*593dc095SDavid du Colombier    */
202*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
203*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
204*593dc095SDavid du Colombier     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
205*593dc095SDavid du Colombier 	 dst_blk_y += compptr->v_samp_factor) {
206*593dc095SDavid du Colombier       dst_buffer = (*srcinfo->mem->access_virt_barray)
207*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
208*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
209*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
210*593dc095SDavid du Colombier 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
211*593dc095SDavid du Colombier 	     dst_blk_x += compptr->h_samp_factor) {
212*593dc095SDavid du Colombier 	  src_buffer = (*srcinfo->mem->access_virt_barray)
213*593dc095SDavid du Colombier 	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
214*593dc095SDavid du Colombier 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
215*593dc095SDavid du Colombier 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
216*593dc095SDavid du Colombier 	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
217*593dc095SDavid du Colombier 	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
218*593dc095SDavid du Colombier 	    for (i = 0; i < DCTSIZE; i++)
219*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j++)
220*593dc095SDavid du Colombier 		dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
221*593dc095SDavid du Colombier 	  }
222*593dc095SDavid du Colombier 	}
223*593dc095SDavid du Colombier       }
224*593dc095SDavid du Colombier     }
225*593dc095SDavid du Colombier   }
226*593dc095SDavid du Colombier }
227*593dc095SDavid du Colombier 
228*593dc095SDavid du Colombier 
229*593dc095SDavid du Colombier LOCAL(void)
do_rot_90(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)230*593dc095SDavid du Colombier do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
231*593dc095SDavid du Colombier 	   jvirt_barray_ptr *src_coef_arrays,
232*593dc095SDavid du Colombier 	   jvirt_barray_ptr *dst_coef_arrays)
233*593dc095SDavid du Colombier /* 90 degree rotation is equivalent to
234*593dc095SDavid du Colombier  *   1. Transposing the image;
235*593dc095SDavid du Colombier  *   2. Horizontal mirroring.
236*593dc095SDavid du Colombier  * These two steps are merged into a single processing routine.
237*593dc095SDavid du Colombier  */
238*593dc095SDavid du Colombier {
239*593dc095SDavid du Colombier   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
240*593dc095SDavid du Colombier   int ci, i, j, offset_x, offset_y;
241*593dc095SDavid du Colombier   JBLOCKARRAY src_buffer, dst_buffer;
242*593dc095SDavid du Colombier   JCOEFPTR src_ptr, dst_ptr;
243*593dc095SDavid du Colombier   jpeg_component_info *compptr;
244*593dc095SDavid du Colombier 
245*593dc095SDavid du Colombier   /* Because of the horizontal mirror step, we can't process partial iMCUs
246*593dc095SDavid du Colombier    * at the (output) right edge properly.  They just get transposed and
247*593dc095SDavid du Colombier    * not mirrored.
248*593dc095SDavid du Colombier    */
249*593dc095SDavid du Colombier   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
250*593dc095SDavid du Colombier 
251*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
252*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
253*593dc095SDavid du Colombier     comp_width = MCU_cols * compptr->h_samp_factor;
254*593dc095SDavid du Colombier     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
255*593dc095SDavid du Colombier 	 dst_blk_y += compptr->v_samp_factor) {
256*593dc095SDavid du Colombier       dst_buffer = (*srcinfo->mem->access_virt_barray)
257*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
258*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
259*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
260*593dc095SDavid du Colombier 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
261*593dc095SDavid du Colombier 	     dst_blk_x += compptr->h_samp_factor) {
262*593dc095SDavid du Colombier 	  src_buffer = (*srcinfo->mem->access_virt_barray)
263*593dc095SDavid du Colombier 	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
264*593dc095SDavid du Colombier 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
265*593dc095SDavid du Colombier 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
266*593dc095SDavid du Colombier 	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
267*593dc095SDavid du Colombier 	    if (dst_blk_x < comp_width) {
268*593dc095SDavid du Colombier 	      /* Block is within the mirrorable area. */
269*593dc095SDavid du Colombier 	      dst_ptr = dst_buffer[offset_y]
270*593dc095SDavid du Colombier 		[comp_width - dst_blk_x - offset_x - 1];
271*593dc095SDavid du Colombier 	      for (i = 0; i < DCTSIZE; i++) {
272*593dc095SDavid du Colombier 		for (j = 0; j < DCTSIZE; j++)
273*593dc095SDavid du Colombier 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
274*593dc095SDavid du Colombier 		i++;
275*593dc095SDavid du Colombier 		for (j = 0; j < DCTSIZE; j++)
276*593dc095SDavid du Colombier 		  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
277*593dc095SDavid du Colombier 	      }
278*593dc095SDavid du Colombier 	    } else {
279*593dc095SDavid du Colombier 	      /* Edge blocks are transposed but not mirrored. */
280*593dc095SDavid du Colombier 	      dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
281*593dc095SDavid du Colombier 	      for (i = 0; i < DCTSIZE; i++)
282*593dc095SDavid du Colombier 		for (j = 0; j < DCTSIZE; j++)
283*593dc095SDavid du Colombier 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
284*593dc095SDavid du Colombier 	    }
285*593dc095SDavid du Colombier 	  }
286*593dc095SDavid du Colombier 	}
287*593dc095SDavid du Colombier       }
288*593dc095SDavid du Colombier     }
289*593dc095SDavid du Colombier   }
290*593dc095SDavid du Colombier }
291*593dc095SDavid du Colombier 
292*593dc095SDavid du Colombier 
293*593dc095SDavid du Colombier LOCAL(void)
do_rot_270(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)294*593dc095SDavid du Colombier do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
295*593dc095SDavid du Colombier 	    jvirt_barray_ptr *src_coef_arrays,
296*593dc095SDavid du Colombier 	    jvirt_barray_ptr *dst_coef_arrays)
297*593dc095SDavid du Colombier /* 270 degree rotation is equivalent to
298*593dc095SDavid du Colombier  *   1. Horizontal mirroring;
299*593dc095SDavid du Colombier  *   2. Transposing the image.
300*593dc095SDavid du Colombier  * These two steps are merged into a single processing routine.
301*593dc095SDavid du Colombier  */
302*593dc095SDavid du Colombier {
303*593dc095SDavid du Colombier   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
304*593dc095SDavid du Colombier   int ci, i, j, offset_x, offset_y;
305*593dc095SDavid du Colombier   JBLOCKARRAY src_buffer, dst_buffer;
306*593dc095SDavid du Colombier   JCOEFPTR src_ptr, dst_ptr;
307*593dc095SDavid du Colombier   jpeg_component_info *compptr;
308*593dc095SDavid du Colombier 
309*593dc095SDavid du Colombier   /* Because of the horizontal mirror step, we can't process partial iMCUs
310*593dc095SDavid du Colombier    * at the (output) bottom edge properly.  They just get transposed and
311*593dc095SDavid du Colombier    * not mirrored.
312*593dc095SDavid du Colombier    */
313*593dc095SDavid du Colombier   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
314*593dc095SDavid du Colombier 
315*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
316*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
317*593dc095SDavid du Colombier     comp_height = MCU_rows * compptr->v_samp_factor;
318*593dc095SDavid du Colombier     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
319*593dc095SDavid du Colombier 	 dst_blk_y += compptr->v_samp_factor) {
320*593dc095SDavid du Colombier       dst_buffer = (*srcinfo->mem->access_virt_barray)
321*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
322*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
323*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
324*593dc095SDavid du Colombier 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
325*593dc095SDavid du Colombier 	     dst_blk_x += compptr->h_samp_factor) {
326*593dc095SDavid du Colombier 	  src_buffer = (*srcinfo->mem->access_virt_barray)
327*593dc095SDavid du Colombier 	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
328*593dc095SDavid du Colombier 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
329*593dc095SDavid du Colombier 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
330*593dc095SDavid du Colombier 	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
331*593dc095SDavid du Colombier 	    if (dst_blk_y < comp_height) {
332*593dc095SDavid du Colombier 	      /* Block is within the mirrorable area. */
333*593dc095SDavid du Colombier 	      src_ptr = src_buffer[offset_x]
334*593dc095SDavid du Colombier 		[comp_height - dst_blk_y - offset_y - 1];
335*593dc095SDavid du Colombier 	      for (i = 0; i < DCTSIZE; i++) {
336*593dc095SDavid du Colombier 		for (j = 0; j < DCTSIZE; j++) {
337*593dc095SDavid du Colombier 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
338*593dc095SDavid du Colombier 		  j++;
339*593dc095SDavid du Colombier 		  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
340*593dc095SDavid du Colombier 		}
341*593dc095SDavid du Colombier 	      }
342*593dc095SDavid du Colombier 	    } else {
343*593dc095SDavid du Colombier 	      /* Edge blocks are transposed but not mirrored. */
344*593dc095SDavid du Colombier 	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
345*593dc095SDavid du Colombier 	      for (i = 0; i < DCTSIZE; i++)
346*593dc095SDavid du Colombier 		for (j = 0; j < DCTSIZE; j++)
347*593dc095SDavid du Colombier 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
348*593dc095SDavid du Colombier 	    }
349*593dc095SDavid du Colombier 	  }
350*593dc095SDavid du Colombier 	}
351*593dc095SDavid du Colombier       }
352*593dc095SDavid du Colombier     }
353*593dc095SDavid du Colombier   }
354*593dc095SDavid du Colombier }
355*593dc095SDavid du Colombier 
356*593dc095SDavid du Colombier 
357*593dc095SDavid du Colombier LOCAL(void)
do_rot_180(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)358*593dc095SDavid du Colombier do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
359*593dc095SDavid du Colombier 	    jvirt_barray_ptr *src_coef_arrays,
360*593dc095SDavid du Colombier 	    jvirt_barray_ptr *dst_coef_arrays)
361*593dc095SDavid du Colombier /* 180 degree rotation is equivalent to
362*593dc095SDavid du Colombier  *   1. Vertical mirroring;
363*593dc095SDavid du Colombier  *   2. Horizontal mirroring.
364*593dc095SDavid du Colombier  * These two steps are merged into a single processing routine.
365*593dc095SDavid du Colombier  */
366*593dc095SDavid du Colombier {
367*593dc095SDavid du Colombier   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
368*593dc095SDavid du Colombier   int ci, i, j, offset_y;
369*593dc095SDavid du Colombier   JBLOCKARRAY src_buffer, dst_buffer;
370*593dc095SDavid du Colombier   JBLOCKROW src_row_ptr, dst_row_ptr;
371*593dc095SDavid du Colombier   JCOEFPTR src_ptr, dst_ptr;
372*593dc095SDavid du Colombier   jpeg_component_info *compptr;
373*593dc095SDavid du Colombier 
374*593dc095SDavid du Colombier   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
375*593dc095SDavid du Colombier   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
376*593dc095SDavid du Colombier 
377*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
378*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
379*593dc095SDavid du Colombier     comp_width = MCU_cols * compptr->h_samp_factor;
380*593dc095SDavid du Colombier     comp_height = MCU_rows * compptr->v_samp_factor;
381*593dc095SDavid du Colombier     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
382*593dc095SDavid du Colombier 	 dst_blk_y += compptr->v_samp_factor) {
383*593dc095SDavid du Colombier       dst_buffer = (*srcinfo->mem->access_virt_barray)
384*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
385*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
386*593dc095SDavid du Colombier       if (dst_blk_y < comp_height) {
387*593dc095SDavid du Colombier 	/* Row is within the vertically mirrorable area. */
388*593dc095SDavid du Colombier 	src_buffer = (*srcinfo->mem->access_virt_barray)
389*593dc095SDavid du Colombier 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
390*593dc095SDavid du Colombier 	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
391*593dc095SDavid du Colombier 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
392*593dc095SDavid du Colombier       } else {
393*593dc095SDavid du Colombier 	/* Bottom-edge rows are only mirrored horizontally. */
394*593dc095SDavid du Colombier 	src_buffer = (*srcinfo->mem->access_virt_barray)
395*593dc095SDavid du Colombier 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
396*593dc095SDavid du Colombier 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
397*593dc095SDavid du Colombier       }
398*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
399*593dc095SDavid du Colombier 	if (dst_blk_y < comp_height) {
400*593dc095SDavid du Colombier 	  /* Row is within the mirrorable area. */
401*593dc095SDavid du Colombier 	  dst_row_ptr = dst_buffer[offset_y];
402*593dc095SDavid du Colombier 	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
403*593dc095SDavid du Colombier 	  /* Process the blocks that can be mirrored both ways. */
404*593dc095SDavid du Colombier 	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
405*593dc095SDavid du Colombier 	    dst_ptr = dst_row_ptr[dst_blk_x];
406*593dc095SDavid du Colombier 	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
407*593dc095SDavid du Colombier 	    for (i = 0; i < DCTSIZE; i += 2) {
408*593dc095SDavid du Colombier 	      /* For even row, negate every odd column. */
409*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j += 2) {
410*593dc095SDavid du Colombier 		*dst_ptr++ = *src_ptr++;
411*593dc095SDavid du Colombier 		*dst_ptr++ = - *src_ptr++;
412*593dc095SDavid du Colombier 	      }
413*593dc095SDavid du Colombier 	      /* For odd row, negate every even column. */
414*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j += 2) {
415*593dc095SDavid du Colombier 		*dst_ptr++ = - *src_ptr++;
416*593dc095SDavid du Colombier 		*dst_ptr++ = *src_ptr++;
417*593dc095SDavid du Colombier 	      }
418*593dc095SDavid du Colombier 	    }
419*593dc095SDavid du Colombier 	  }
420*593dc095SDavid du Colombier 	  /* Any remaining right-edge blocks are only mirrored vertically. */
421*593dc095SDavid du Colombier 	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
422*593dc095SDavid du Colombier 	    dst_ptr = dst_row_ptr[dst_blk_x];
423*593dc095SDavid du Colombier 	    src_ptr = src_row_ptr[dst_blk_x];
424*593dc095SDavid du Colombier 	    for (i = 0; i < DCTSIZE; i += 2) {
425*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j++)
426*593dc095SDavid du Colombier 		*dst_ptr++ = *src_ptr++;
427*593dc095SDavid du Colombier 	      for (j = 0; j < DCTSIZE; j++)
428*593dc095SDavid du Colombier 		*dst_ptr++ = - *src_ptr++;
429*593dc095SDavid du Colombier 	    }
430*593dc095SDavid du Colombier 	  }
431*593dc095SDavid du Colombier 	} else {
432*593dc095SDavid du Colombier 	  /* Remaining rows are just mirrored horizontally. */
433*593dc095SDavid du Colombier 	  dst_row_ptr = dst_buffer[offset_y];
434*593dc095SDavid du Colombier 	  src_row_ptr = src_buffer[offset_y];
435*593dc095SDavid du Colombier 	  /* Process the blocks that can be mirrored. */
436*593dc095SDavid du Colombier 	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
437*593dc095SDavid du Colombier 	    dst_ptr = dst_row_ptr[dst_blk_x];
438*593dc095SDavid du Colombier 	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
439*593dc095SDavid du Colombier 	    for (i = 0; i < DCTSIZE2; i += 2) {
440*593dc095SDavid du Colombier 	      *dst_ptr++ = *src_ptr++;
441*593dc095SDavid du Colombier 	      *dst_ptr++ = - *src_ptr++;
442*593dc095SDavid du Colombier 	    }
443*593dc095SDavid du Colombier 	  }
444*593dc095SDavid du Colombier 	  /* Any remaining right-edge blocks are only copied. */
445*593dc095SDavid du Colombier 	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
446*593dc095SDavid du Colombier 	    dst_ptr = dst_row_ptr[dst_blk_x];
447*593dc095SDavid du Colombier 	    src_ptr = src_row_ptr[dst_blk_x];
448*593dc095SDavid du Colombier 	    for (i = 0; i < DCTSIZE2; i++)
449*593dc095SDavid du Colombier 	      *dst_ptr++ = *src_ptr++;
450*593dc095SDavid du Colombier 	  }
451*593dc095SDavid du Colombier 	}
452*593dc095SDavid du Colombier       }
453*593dc095SDavid du Colombier     }
454*593dc095SDavid du Colombier   }
455*593dc095SDavid du Colombier }
456*593dc095SDavid du Colombier 
457*593dc095SDavid du Colombier 
458*593dc095SDavid du Colombier LOCAL(void)
do_transverse(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jvirt_barray_ptr * dst_coef_arrays)459*593dc095SDavid du Colombier do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
460*593dc095SDavid du Colombier 	       jvirt_barray_ptr *src_coef_arrays,
461*593dc095SDavid du Colombier 	       jvirt_barray_ptr *dst_coef_arrays)
462*593dc095SDavid du Colombier /* Transverse transpose is equivalent to
463*593dc095SDavid du Colombier  *   1. 180 degree rotation;
464*593dc095SDavid du Colombier  *   2. Transposition;
465*593dc095SDavid du Colombier  * or
466*593dc095SDavid du Colombier  *   1. Horizontal mirroring;
467*593dc095SDavid du Colombier  *   2. Transposition;
468*593dc095SDavid du Colombier  *   3. Horizontal mirroring.
469*593dc095SDavid du Colombier  * These steps are merged into a single processing routine.
470*593dc095SDavid du Colombier  */
471*593dc095SDavid du Colombier {
472*593dc095SDavid du Colombier   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
473*593dc095SDavid du Colombier   int ci, i, j, offset_x, offset_y;
474*593dc095SDavid du Colombier   JBLOCKARRAY src_buffer, dst_buffer;
475*593dc095SDavid du Colombier   JCOEFPTR src_ptr, dst_ptr;
476*593dc095SDavid du Colombier   jpeg_component_info *compptr;
477*593dc095SDavid du Colombier 
478*593dc095SDavid du Colombier   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
479*593dc095SDavid du Colombier   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
480*593dc095SDavid du Colombier 
481*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
482*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
483*593dc095SDavid du Colombier     comp_width = MCU_cols * compptr->h_samp_factor;
484*593dc095SDavid du Colombier     comp_height = MCU_rows * compptr->v_samp_factor;
485*593dc095SDavid du Colombier     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
486*593dc095SDavid du Colombier 	 dst_blk_y += compptr->v_samp_factor) {
487*593dc095SDavid du Colombier       dst_buffer = (*srcinfo->mem->access_virt_barray)
488*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
489*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
490*593dc095SDavid du Colombier       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
491*593dc095SDavid du Colombier 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
492*593dc095SDavid du Colombier 	     dst_blk_x += compptr->h_samp_factor) {
493*593dc095SDavid du Colombier 	  src_buffer = (*srcinfo->mem->access_virt_barray)
494*593dc095SDavid du Colombier 	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
495*593dc095SDavid du Colombier 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
496*593dc095SDavid du Colombier 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
497*593dc095SDavid du Colombier 	    if (dst_blk_y < comp_height) {
498*593dc095SDavid du Colombier 	      src_ptr = src_buffer[offset_x]
499*593dc095SDavid du Colombier 		[comp_height - dst_blk_y - offset_y - 1];
500*593dc095SDavid du Colombier 	      if (dst_blk_x < comp_width) {
501*593dc095SDavid du Colombier 		/* Block is within the mirrorable area. */
502*593dc095SDavid du Colombier 		dst_ptr = dst_buffer[offset_y]
503*593dc095SDavid du Colombier 		  [comp_width - dst_blk_x - offset_x - 1];
504*593dc095SDavid du Colombier 		for (i = 0; i < DCTSIZE; i++) {
505*593dc095SDavid du Colombier 		  for (j = 0; j < DCTSIZE; j++) {
506*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
507*593dc095SDavid du Colombier 		    j++;
508*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
509*593dc095SDavid du Colombier 		  }
510*593dc095SDavid du Colombier 		  i++;
511*593dc095SDavid du Colombier 		  for (j = 0; j < DCTSIZE; j++) {
512*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
513*593dc095SDavid du Colombier 		    j++;
514*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
515*593dc095SDavid du Colombier 		  }
516*593dc095SDavid du Colombier 		}
517*593dc095SDavid du Colombier 	      } else {
518*593dc095SDavid du Colombier 		/* Right-edge blocks are mirrored in y only */
519*593dc095SDavid du Colombier 		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
520*593dc095SDavid du Colombier 		for (i = 0; i < DCTSIZE; i++) {
521*593dc095SDavid du Colombier 		  for (j = 0; j < DCTSIZE; j++) {
522*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
523*593dc095SDavid du Colombier 		    j++;
524*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
525*593dc095SDavid du Colombier 		  }
526*593dc095SDavid du Colombier 		}
527*593dc095SDavid du Colombier 	      }
528*593dc095SDavid du Colombier 	    } else {
529*593dc095SDavid du Colombier 	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
530*593dc095SDavid du Colombier 	      if (dst_blk_x < comp_width) {
531*593dc095SDavid du Colombier 		/* Bottom-edge blocks are mirrored in x only */
532*593dc095SDavid du Colombier 		dst_ptr = dst_buffer[offset_y]
533*593dc095SDavid du Colombier 		  [comp_width - dst_blk_x - offset_x - 1];
534*593dc095SDavid du Colombier 		for (i = 0; i < DCTSIZE; i++) {
535*593dc095SDavid du Colombier 		  for (j = 0; j < DCTSIZE; j++)
536*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
537*593dc095SDavid du Colombier 		  i++;
538*593dc095SDavid du Colombier 		  for (j = 0; j < DCTSIZE; j++)
539*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
540*593dc095SDavid du Colombier 		}
541*593dc095SDavid du Colombier 	      } else {
542*593dc095SDavid du Colombier 		/* At lower right corner, just transpose, no mirroring */
543*593dc095SDavid du Colombier 		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
544*593dc095SDavid du Colombier 		for (i = 0; i < DCTSIZE; i++)
545*593dc095SDavid du Colombier 		  for (j = 0; j < DCTSIZE; j++)
546*593dc095SDavid du Colombier 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
547*593dc095SDavid du Colombier 	      }
548*593dc095SDavid du Colombier 	    }
549*593dc095SDavid du Colombier 	  }
550*593dc095SDavid du Colombier 	}
551*593dc095SDavid du Colombier       }
552*593dc095SDavid du Colombier     }
553*593dc095SDavid du Colombier   }
554*593dc095SDavid du Colombier }
555*593dc095SDavid du Colombier 
556*593dc095SDavid du Colombier 
557*593dc095SDavid du Colombier /* Request any required workspace.
558*593dc095SDavid du Colombier  *
559*593dc095SDavid du Colombier  * We allocate the workspace virtual arrays from the source decompression
560*593dc095SDavid du Colombier  * object, so that all the arrays (both the original data and the workspace)
561*593dc095SDavid du Colombier  * will be taken into account while making memory management decisions.
562*593dc095SDavid du Colombier  * Hence, this routine must be called after jpeg_read_header (which reads
563*593dc095SDavid du Colombier  * the image dimensions) and before jpeg_read_coefficients (which realizes
564*593dc095SDavid du Colombier  * the source's virtual arrays).
565*593dc095SDavid du Colombier  */
566*593dc095SDavid du Colombier 
567*593dc095SDavid du Colombier GLOBAL(void)
jtransform_request_workspace(j_decompress_ptr srcinfo,jpeg_transform_info * info)568*593dc095SDavid du Colombier jtransform_request_workspace (j_decompress_ptr srcinfo,
569*593dc095SDavid du Colombier 			      jpeg_transform_info *info)
570*593dc095SDavid du Colombier {
571*593dc095SDavid du Colombier   jvirt_barray_ptr *coef_arrays = NULL;
572*593dc095SDavid du Colombier   jpeg_component_info *compptr;
573*593dc095SDavid du Colombier   int ci;
574*593dc095SDavid du Colombier 
575*593dc095SDavid du Colombier   if (info->force_grayscale &&
576*593dc095SDavid du Colombier       srcinfo->jpeg_color_space == JCS_YCbCr &&
577*593dc095SDavid du Colombier       srcinfo->num_components == 3) {
578*593dc095SDavid du Colombier     /* We'll only process the first component */
579*593dc095SDavid du Colombier     info->num_components = 1;
580*593dc095SDavid du Colombier   } else {
581*593dc095SDavid du Colombier     /* Process all the components */
582*593dc095SDavid du Colombier     info->num_components = srcinfo->num_components;
583*593dc095SDavid du Colombier   }
584*593dc095SDavid du Colombier 
585*593dc095SDavid du Colombier   switch (info->transform) {
586*593dc095SDavid du Colombier   case JXFORM_NONE:
587*593dc095SDavid du Colombier   case JXFORM_FLIP_H:
588*593dc095SDavid du Colombier     /* Don't need a workspace array */
589*593dc095SDavid du Colombier     break;
590*593dc095SDavid du Colombier   case JXFORM_FLIP_V:
591*593dc095SDavid du Colombier   case JXFORM_ROT_180:
592*593dc095SDavid du Colombier     /* Need workspace arrays having same dimensions as source image.
593*593dc095SDavid du Colombier      * Note that we allocate arrays padded out to the next iMCU boundary,
594*593dc095SDavid du Colombier      * so that transform routines need not worry about missing edge blocks.
595*593dc095SDavid du Colombier      */
596*593dc095SDavid du Colombier     coef_arrays = (jvirt_barray_ptr *)
597*593dc095SDavid du Colombier       (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
598*593dc095SDavid du Colombier 	SIZEOF(jvirt_barray_ptr) * info->num_components);
599*593dc095SDavid du Colombier     for (ci = 0; ci < info->num_components; ci++) {
600*593dc095SDavid du Colombier       compptr = srcinfo->comp_info + ci;
601*593dc095SDavid du Colombier       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
602*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
603*593dc095SDavid du Colombier 	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
604*593dc095SDavid du Colombier 				(long) compptr->h_samp_factor),
605*593dc095SDavid du Colombier 	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
606*593dc095SDavid du Colombier 				(long) compptr->v_samp_factor),
607*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->v_samp_factor);
608*593dc095SDavid du Colombier     }
609*593dc095SDavid du Colombier     break;
610*593dc095SDavid du Colombier   case JXFORM_TRANSPOSE:
611*593dc095SDavid du Colombier   case JXFORM_TRANSVERSE:
612*593dc095SDavid du Colombier   case JXFORM_ROT_90:
613*593dc095SDavid du Colombier   case JXFORM_ROT_270:
614*593dc095SDavid du Colombier     /* Need workspace arrays having transposed dimensions.
615*593dc095SDavid du Colombier      * Note that we allocate arrays padded out to the next iMCU boundary,
616*593dc095SDavid du Colombier      * so that transform routines need not worry about missing edge blocks.
617*593dc095SDavid du Colombier      */
618*593dc095SDavid du Colombier     coef_arrays = (jvirt_barray_ptr *)
619*593dc095SDavid du Colombier       (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
620*593dc095SDavid du Colombier 	SIZEOF(jvirt_barray_ptr) * info->num_components);
621*593dc095SDavid du Colombier     for (ci = 0; ci < info->num_components; ci++) {
622*593dc095SDavid du Colombier       compptr = srcinfo->comp_info + ci;
623*593dc095SDavid du Colombier       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
624*593dc095SDavid du Colombier 	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
625*593dc095SDavid du Colombier 	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
626*593dc095SDavid du Colombier 				(long) compptr->v_samp_factor),
627*593dc095SDavid du Colombier 	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
628*593dc095SDavid du Colombier 				(long) compptr->h_samp_factor),
629*593dc095SDavid du Colombier 	 (JDIMENSION) compptr->h_samp_factor);
630*593dc095SDavid du Colombier     }
631*593dc095SDavid du Colombier     break;
632*593dc095SDavid du Colombier   }
633*593dc095SDavid du Colombier   info->workspace_coef_arrays = coef_arrays;
634*593dc095SDavid du Colombier }
635*593dc095SDavid du Colombier 
636*593dc095SDavid du Colombier 
637*593dc095SDavid du Colombier /* Transpose destination image parameters */
638*593dc095SDavid du Colombier 
639*593dc095SDavid du Colombier LOCAL(void)
transpose_critical_parameters(j_compress_ptr dstinfo)640*593dc095SDavid du Colombier transpose_critical_parameters (j_compress_ptr dstinfo)
641*593dc095SDavid du Colombier {
642*593dc095SDavid du Colombier   int tblno, i, j, ci, itemp;
643*593dc095SDavid du Colombier   jpeg_component_info *compptr;
644*593dc095SDavid du Colombier   JQUANT_TBL *qtblptr;
645*593dc095SDavid du Colombier   JDIMENSION dtemp;
646*593dc095SDavid du Colombier   UINT16 qtemp;
647*593dc095SDavid du Colombier 
648*593dc095SDavid du Colombier   /* Transpose basic image dimensions */
649*593dc095SDavid du Colombier   dtemp = dstinfo->image_width;
650*593dc095SDavid du Colombier   dstinfo->image_width = dstinfo->image_height;
651*593dc095SDavid du Colombier   dstinfo->image_height = dtemp;
652*593dc095SDavid du Colombier 
653*593dc095SDavid du Colombier   /* Transpose sampling factors */
654*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
655*593dc095SDavid du Colombier     compptr = dstinfo->comp_info + ci;
656*593dc095SDavid du Colombier     itemp = compptr->h_samp_factor;
657*593dc095SDavid du Colombier     compptr->h_samp_factor = compptr->v_samp_factor;
658*593dc095SDavid du Colombier     compptr->v_samp_factor = itemp;
659*593dc095SDavid du Colombier   }
660*593dc095SDavid du Colombier 
661*593dc095SDavid du Colombier   /* Transpose quantization tables */
662*593dc095SDavid du Colombier   for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
663*593dc095SDavid du Colombier     qtblptr = dstinfo->quant_tbl_ptrs[tblno];
664*593dc095SDavid du Colombier     if (qtblptr != NULL) {
665*593dc095SDavid du Colombier       for (i = 0; i < DCTSIZE; i++) {
666*593dc095SDavid du Colombier 	for (j = 0; j < i; j++) {
667*593dc095SDavid du Colombier 	  qtemp = qtblptr->quantval[i*DCTSIZE+j];
668*593dc095SDavid du Colombier 	  qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];
669*593dc095SDavid du Colombier 	  qtblptr->quantval[j*DCTSIZE+i] = qtemp;
670*593dc095SDavid du Colombier 	}
671*593dc095SDavid du Colombier       }
672*593dc095SDavid du Colombier     }
673*593dc095SDavid du Colombier   }
674*593dc095SDavid du Colombier }
675*593dc095SDavid du Colombier 
676*593dc095SDavid du Colombier 
677*593dc095SDavid du Colombier /* Trim off any partial iMCUs on the indicated destination edge */
678*593dc095SDavid du Colombier 
679*593dc095SDavid du Colombier LOCAL(void)
trim_right_edge(j_compress_ptr dstinfo)680*593dc095SDavid du Colombier trim_right_edge (j_compress_ptr dstinfo)
681*593dc095SDavid du Colombier {
682*593dc095SDavid du Colombier   int ci, max_h_samp_factor;
683*593dc095SDavid du Colombier   JDIMENSION MCU_cols;
684*593dc095SDavid du Colombier 
685*593dc095SDavid du Colombier   /* We have to compute max_h_samp_factor ourselves,
686*593dc095SDavid du Colombier    * because it hasn't been set yet in the destination
687*593dc095SDavid du Colombier    * (and we don't want to use the source's value).
688*593dc095SDavid du Colombier    */
689*593dc095SDavid du Colombier   max_h_samp_factor = 1;
690*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
691*593dc095SDavid du Colombier     int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor;
692*593dc095SDavid du Colombier     max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor);
693*593dc095SDavid du Colombier   }
694*593dc095SDavid du Colombier   MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE);
695*593dc095SDavid du Colombier   if (MCU_cols > 0)		/* can't trim to 0 pixels */
696*593dc095SDavid du Colombier     dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE);
697*593dc095SDavid du Colombier }
698*593dc095SDavid du Colombier 
699*593dc095SDavid du Colombier LOCAL(void)
trim_bottom_edge(j_compress_ptr dstinfo)700*593dc095SDavid du Colombier trim_bottom_edge (j_compress_ptr dstinfo)
701*593dc095SDavid du Colombier {
702*593dc095SDavid du Colombier   int ci, max_v_samp_factor;
703*593dc095SDavid du Colombier   JDIMENSION MCU_rows;
704*593dc095SDavid du Colombier 
705*593dc095SDavid du Colombier   /* We have to compute max_v_samp_factor ourselves,
706*593dc095SDavid du Colombier    * because it hasn't been set yet in the destination
707*593dc095SDavid du Colombier    * (and we don't want to use the source's value).
708*593dc095SDavid du Colombier    */
709*593dc095SDavid du Colombier   max_v_samp_factor = 1;
710*593dc095SDavid du Colombier   for (ci = 0; ci < dstinfo->num_components; ci++) {
711*593dc095SDavid du Colombier     int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor;
712*593dc095SDavid du Colombier     max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor);
713*593dc095SDavid du Colombier   }
714*593dc095SDavid du Colombier   MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE);
715*593dc095SDavid du Colombier   if (MCU_rows > 0)		/* can't trim to 0 pixels */
716*593dc095SDavid du Colombier     dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE);
717*593dc095SDavid du Colombier }
718*593dc095SDavid du Colombier 
719*593dc095SDavid du Colombier 
720*593dc095SDavid du Colombier /* Adjust output image parameters as needed.
721*593dc095SDavid du Colombier  *
722*593dc095SDavid du Colombier  * This must be called after jpeg_copy_critical_parameters()
723*593dc095SDavid du Colombier  * and before jpeg_write_coefficients().
724*593dc095SDavid du Colombier  *
725*593dc095SDavid du Colombier  * The return value is the set of virtual coefficient arrays to be written
726*593dc095SDavid du Colombier  * (either the ones allocated by jtransform_request_workspace, or the
727*593dc095SDavid du Colombier  * original source data arrays).  The caller will need to pass this value
728*593dc095SDavid du Colombier  * to jpeg_write_coefficients().
729*593dc095SDavid du Colombier  */
730*593dc095SDavid du Colombier 
731*593dc095SDavid du Colombier GLOBAL(jvirt_barray_ptr *)
jtransform_adjust_parameters(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jpeg_transform_info * info)732*593dc095SDavid du Colombier jtransform_adjust_parameters (j_decompress_ptr srcinfo,
733*593dc095SDavid du Colombier 			      j_compress_ptr dstinfo,
734*593dc095SDavid du Colombier 			      jvirt_barray_ptr *src_coef_arrays,
735*593dc095SDavid du Colombier 			      jpeg_transform_info *info)
736*593dc095SDavid du Colombier {
737*593dc095SDavid du Colombier   /* If force-to-grayscale is requested, adjust destination parameters */
738*593dc095SDavid du Colombier   if (info->force_grayscale) {
739*593dc095SDavid du Colombier     /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
740*593dc095SDavid du Colombier      * properly.  Among other things, the target h_samp_factor & v_samp_factor
741*593dc095SDavid du Colombier      * will get set to 1, which typically won't match the source.
742*593dc095SDavid du Colombier      * In fact we do this even if the source is already grayscale; that
743*593dc095SDavid du Colombier      * provides an easy way of coercing a grayscale JPEG with funny sampling
744*593dc095SDavid du Colombier      * factors to the customary 1,1.  (Some decoders fail on other factors.)
745*593dc095SDavid du Colombier      */
746*593dc095SDavid du Colombier     if ((dstinfo->jpeg_color_space == JCS_YCbCr &&
747*593dc095SDavid du Colombier 	 dstinfo->num_components == 3) ||
748*593dc095SDavid du Colombier 	(dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
749*593dc095SDavid du Colombier 	 dstinfo->num_components == 1)) {
750*593dc095SDavid du Colombier       /* We have to preserve the source's quantization table number. */
751*593dc095SDavid du Colombier       int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
752*593dc095SDavid du Colombier       jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
753*593dc095SDavid du Colombier       dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
754*593dc095SDavid du Colombier     } else {
755*593dc095SDavid du Colombier       /* Sorry, can't do it */
756*593dc095SDavid du Colombier       ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
757*593dc095SDavid du Colombier     }
758*593dc095SDavid du Colombier   }
759*593dc095SDavid du Colombier 
760*593dc095SDavid du Colombier   /* Correct the destination's image dimensions etc if necessary */
761*593dc095SDavid du Colombier   switch (info->transform) {
762*593dc095SDavid du Colombier   case JXFORM_NONE:
763*593dc095SDavid du Colombier     /* Nothing to do */
764*593dc095SDavid du Colombier     break;
765*593dc095SDavid du Colombier   case JXFORM_FLIP_H:
766*593dc095SDavid du Colombier     if (info->trim)
767*593dc095SDavid du Colombier       trim_right_edge(dstinfo);
768*593dc095SDavid du Colombier     break;
769*593dc095SDavid du Colombier   case JXFORM_FLIP_V:
770*593dc095SDavid du Colombier     if (info->trim)
771*593dc095SDavid du Colombier       trim_bottom_edge(dstinfo);
772*593dc095SDavid du Colombier     break;
773*593dc095SDavid du Colombier   case JXFORM_TRANSPOSE:
774*593dc095SDavid du Colombier     transpose_critical_parameters(dstinfo);
775*593dc095SDavid du Colombier     /* transpose does NOT have to trim anything */
776*593dc095SDavid du Colombier     break;
777*593dc095SDavid du Colombier   case JXFORM_TRANSVERSE:
778*593dc095SDavid du Colombier     transpose_critical_parameters(dstinfo);
779*593dc095SDavid du Colombier     if (info->trim) {
780*593dc095SDavid du Colombier       trim_right_edge(dstinfo);
781*593dc095SDavid du Colombier       trim_bottom_edge(dstinfo);
782*593dc095SDavid du Colombier     }
783*593dc095SDavid du Colombier     break;
784*593dc095SDavid du Colombier   case JXFORM_ROT_90:
785*593dc095SDavid du Colombier     transpose_critical_parameters(dstinfo);
786*593dc095SDavid du Colombier     if (info->trim)
787*593dc095SDavid du Colombier       trim_right_edge(dstinfo);
788*593dc095SDavid du Colombier     break;
789*593dc095SDavid du Colombier   case JXFORM_ROT_180:
790*593dc095SDavid du Colombier     if (info->trim) {
791*593dc095SDavid du Colombier       trim_right_edge(dstinfo);
792*593dc095SDavid du Colombier       trim_bottom_edge(dstinfo);
793*593dc095SDavid du Colombier     }
794*593dc095SDavid du Colombier     break;
795*593dc095SDavid du Colombier   case JXFORM_ROT_270:
796*593dc095SDavid du Colombier     transpose_critical_parameters(dstinfo);
797*593dc095SDavid du Colombier     if (info->trim)
798*593dc095SDavid du Colombier       trim_bottom_edge(dstinfo);
799*593dc095SDavid du Colombier     break;
800*593dc095SDavid du Colombier   }
801*593dc095SDavid du Colombier 
802*593dc095SDavid du Colombier   /* Return the appropriate output data set */
803*593dc095SDavid du Colombier   if (info->workspace_coef_arrays != NULL)
804*593dc095SDavid du Colombier     return info->workspace_coef_arrays;
805*593dc095SDavid du Colombier   return src_coef_arrays;
806*593dc095SDavid du Colombier }
807*593dc095SDavid du Colombier 
808*593dc095SDavid du Colombier 
809*593dc095SDavid du Colombier /* Execute the actual transformation, if any.
810*593dc095SDavid du Colombier  *
811*593dc095SDavid du Colombier  * This must be called *after* jpeg_write_coefficients, because it depends
812*593dc095SDavid du Colombier  * on jpeg_write_coefficients to have computed subsidiary values such as
813*593dc095SDavid du Colombier  * the per-component width and height fields in the destination object.
814*593dc095SDavid du Colombier  *
815*593dc095SDavid du Colombier  * Note that some transformations will modify the source data arrays!
816*593dc095SDavid du Colombier  */
817*593dc095SDavid du Colombier 
818*593dc095SDavid du Colombier GLOBAL(void)
jtransform_execute_transformation(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,jvirt_barray_ptr * src_coef_arrays,jpeg_transform_info * info)819*593dc095SDavid du Colombier jtransform_execute_transformation (j_decompress_ptr srcinfo,
820*593dc095SDavid du Colombier 				   j_compress_ptr dstinfo,
821*593dc095SDavid du Colombier 				   jvirt_barray_ptr *src_coef_arrays,
822*593dc095SDavid du Colombier 				   jpeg_transform_info *info)
823*593dc095SDavid du Colombier {
824*593dc095SDavid du Colombier   jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
825*593dc095SDavid du Colombier 
826*593dc095SDavid du Colombier   switch (info->transform) {
827*593dc095SDavid du Colombier   case JXFORM_NONE:
828*593dc095SDavid du Colombier     break;
829*593dc095SDavid du Colombier   case JXFORM_FLIP_H:
830*593dc095SDavid du Colombier     do_flip_h(srcinfo, dstinfo, src_coef_arrays);
831*593dc095SDavid du Colombier     break;
832*593dc095SDavid du Colombier   case JXFORM_FLIP_V:
833*593dc095SDavid du Colombier     do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
834*593dc095SDavid du Colombier     break;
835*593dc095SDavid du Colombier   case JXFORM_TRANSPOSE:
836*593dc095SDavid du Colombier     do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
837*593dc095SDavid du Colombier     break;
838*593dc095SDavid du Colombier   case JXFORM_TRANSVERSE:
839*593dc095SDavid du Colombier     do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
840*593dc095SDavid du Colombier     break;
841*593dc095SDavid du Colombier   case JXFORM_ROT_90:
842*593dc095SDavid du Colombier     do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
843*593dc095SDavid du Colombier     break;
844*593dc095SDavid du Colombier   case JXFORM_ROT_180:
845*593dc095SDavid du Colombier     do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
846*593dc095SDavid du Colombier     break;
847*593dc095SDavid du Colombier   case JXFORM_ROT_270:
848*593dc095SDavid du Colombier     do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
849*593dc095SDavid du Colombier     break;
850*593dc095SDavid du Colombier   }
851*593dc095SDavid du Colombier }
852*593dc095SDavid du Colombier 
853*593dc095SDavid du Colombier #endif /* TRANSFORMS_SUPPORTED */
854*593dc095SDavid du Colombier 
855*593dc095SDavid du Colombier 
856*593dc095SDavid du Colombier /* Setup decompression object to save desired markers in memory.
857*593dc095SDavid du Colombier  * This must be called before jpeg_read_header() to have the desired effect.
858*593dc095SDavid du Colombier  */
859*593dc095SDavid du Colombier 
860*593dc095SDavid du Colombier GLOBAL(void)
jcopy_markers_setup(j_decompress_ptr srcinfo,JCOPY_OPTION option)861*593dc095SDavid du Colombier jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)
862*593dc095SDavid du Colombier {
863*593dc095SDavid du Colombier #ifdef SAVE_MARKERS_SUPPORTED
864*593dc095SDavid du Colombier   int m;
865*593dc095SDavid du Colombier 
866*593dc095SDavid du Colombier   /* Save comments except under NONE option */
867*593dc095SDavid du Colombier   if (option != JCOPYOPT_NONE) {
868*593dc095SDavid du Colombier     jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
869*593dc095SDavid du Colombier   }
870*593dc095SDavid du Colombier   /* Save all types of APPn markers iff ALL option */
871*593dc095SDavid du Colombier   if (option == JCOPYOPT_ALL) {
872*593dc095SDavid du Colombier     for (m = 0; m < 16; m++)
873*593dc095SDavid du Colombier       jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
874*593dc095SDavid du Colombier   }
875*593dc095SDavid du Colombier #endif /* SAVE_MARKERS_SUPPORTED */
876*593dc095SDavid du Colombier }
877*593dc095SDavid du Colombier 
878*593dc095SDavid du Colombier /* Copy markers saved in the given source object to the destination object.
879*593dc095SDavid du Colombier  * This should be called just after jpeg_start_compress() or
880*593dc095SDavid du Colombier  * jpeg_write_coefficients().
881*593dc095SDavid du Colombier  * Note that those routines will have written the SOI, and also the
882*593dc095SDavid du Colombier  * JFIF APP0 or Adobe APP14 markers if selected.
883*593dc095SDavid du Colombier  */
884*593dc095SDavid du Colombier 
885*593dc095SDavid du Colombier GLOBAL(void)
jcopy_markers_execute(j_decompress_ptr srcinfo,j_compress_ptr dstinfo,JCOPY_OPTION option)886*593dc095SDavid du Colombier jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
887*593dc095SDavid du Colombier 		       JCOPY_OPTION option)
888*593dc095SDavid du Colombier {
889*593dc095SDavid du Colombier   jpeg_saved_marker_ptr marker;
890*593dc095SDavid du Colombier 
891*593dc095SDavid du Colombier   /* In the current implementation, we don't actually need to examine the
892*593dc095SDavid du Colombier    * option flag here; we just copy everything that got saved.
893*593dc095SDavid du Colombier    * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
894*593dc095SDavid du Colombier    * if the encoder library already wrote one.
895*593dc095SDavid du Colombier    */
896*593dc095SDavid du Colombier   for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
897*593dc095SDavid du Colombier     if (dstinfo->write_JFIF_header &&
898*593dc095SDavid du Colombier 	marker->marker == JPEG_APP0 &&
899*593dc095SDavid du Colombier 	marker->data_length >= 5 &&
900*593dc095SDavid du Colombier 	GETJOCTET(marker->data[0]) == 0x4A &&
901*593dc095SDavid du Colombier 	GETJOCTET(marker->data[1]) == 0x46 &&
902*593dc095SDavid du Colombier 	GETJOCTET(marker->data[2]) == 0x49 &&
903*593dc095SDavid du Colombier 	GETJOCTET(marker->data[3]) == 0x46 &&
904*593dc095SDavid du Colombier 	GETJOCTET(marker->data[4]) == 0)
905*593dc095SDavid du Colombier       continue;			/* reject duplicate JFIF */
906*593dc095SDavid du Colombier     if (dstinfo->write_Adobe_marker &&
907*593dc095SDavid du Colombier 	marker->marker == JPEG_APP0+14 &&
908*593dc095SDavid du Colombier 	marker->data_length >= 5 &&
909*593dc095SDavid du Colombier 	GETJOCTET(marker->data[0]) == 0x41 &&
910*593dc095SDavid du Colombier 	GETJOCTET(marker->data[1]) == 0x64 &&
911*593dc095SDavid du Colombier 	GETJOCTET(marker->data[2]) == 0x6F &&
912*593dc095SDavid du Colombier 	GETJOCTET(marker->data[3]) == 0x62 &&
913*593dc095SDavid du Colombier 	GETJOCTET(marker->data[4]) == 0x65)
914*593dc095SDavid du Colombier       continue;			/* reject duplicate Adobe */
915*593dc095SDavid du Colombier #ifdef NEED_FAR_POINTERS
916*593dc095SDavid du Colombier     /* We could use jpeg_write_marker if the data weren't FAR... */
917*593dc095SDavid du Colombier     {
918*593dc095SDavid du Colombier       unsigned int i;
919*593dc095SDavid du Colombier       jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);
920*593dc095SDavid du Colombier       for (i = 0; i < marker->data_length; i++)
921*593dc095SDavid du Colombier 	jpeg_write_m_byte(dstinfo, marker->data[i]);
922*593dc095SDavid du Colombier     }
923*593dc095SDavid du Colombier #else
924*593dc095SDavid du Colombier     jpeg_write_marker(dstinfo, marker->marker,
925*593dc095SDavid du Colombier 		      marker->data, marker->data_length);
926*593dc095SDavid du Colombier #endif
927*593dc095SDavid du Colombier   }
928*593dc095SDavid du Colombier }
929