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