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