diff options
author | tnn <tnn@pkgsrc.org> | 2007-06-05 22:07:25 +0000 |
---|---|---|
committer | tnn <tnn@pkgsrc.org> | 2007-06-05 22:07:25 +0000 |
commit | 4646b00220643bbdad557d9e2281f195dd1072c5 (patch) | |
tree | 4f86b88f5691ccc60c107607ba30dd61cd78b72e /graphics/jpeg | |
parent | c022e4ea2b8d65cd33afb1a0db670c989877e2c0 (diff) | |
download | pkgsrc-4646b00220643bbdad557d9e2281f195dd1072c5.tar.gz |
Adopt some new features from www.jpegclub.org that have already been
adopted by many Linux distributions as well as FreeBSD ports:
o jpegtran: add "-perfect" switch:
Fail if there are non-transformable edge blocks.
o jpegtran: add "-crop" switch:
Crop to a rectangular subarea.
o jpegtran: correct EXIF handling.
o jpegexiforient: Get and set the Exif Orientation Tag.
o exifautotran: Transforms Exif files so that Orientation becomes 1.
Suggested by dzoe on #NetBSD IRCNet.
Diffstat (limited to 'graphics/jpeg')
-rw-r--r-- | graphics/jpeg/Makefile | 8 | ||||
-rw-r--r-- | graphics/jpeg/PLIST | 4 | ||||
-rw-r--r-- | graphics/jpeg/distinfo | 7 | ||||
-rw-r--r-- | graphics/jpeg/files/exifautotran | 38 | ||||
-rw-r--r-- | graphics/jpeg/files/jpegexiforient.c | 292 | ||||
-rw-r--r-- | graphics/jpeg/patches/patch-ab | 1501 | ||||
-rw-r--r-- | graphics/jpeg/patches/patch-ac | 12 | ||||
-rw-r--r-- | graphics/jpeg/patches/patch-ad | 193 | ||||
-rw-r--r-- | graphics/jpeg/patches/patch-ae | 182 | ||||
-rw-r--r-- | graphics/jpeg/patches/patch-af | 52 |
10 files changed, 2285 insertions, 4 deletions
diff --git a/graphics/jpeg/Makefile b/graphics/jpeg/Makefile index fea15721bab..3bb544a9f99 100644 --- a/graphics/jpeg/Makefile +++ b/graphics/jpeg/Makefile @@ -1,9 +1,9 @@ -# $NetBSD: Makefile,v 1.35 2006/11/02 18:00:43 joerg Exp $ +# $NetBSD: Makefile,v 1.36 2007/06/05 22:07:25 tnn Exp $ # DISTNAME= jpegsrc.v6b PKGNAME= jpeg-6b -PKGREVISION= 3 +PKGREVISION= 4 CATEGORIES= graphics MASTER_SITES= ftp://ftp.fu-berlin.de/unix/graphics/jpeg/ \ ftp://ftp.uu.net/graphics/jpeg/ @@ -27,7 +27,11 @@ INSTALLATION_DIRS= bin lib include ${PKGMANDIR}/man1 INSTALL_MAKE_FLAGS+= prefix=${DESTDIR}${PREFIX} +post-extract: + ${CP} ${FILESDIR}/jpegexiforient.c ${WRKSRC} + post-install: + ${INSTALL_SCRIPT} ${FILESDIR}/exifautotran ${PREFIX}/bin ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/share/doc/jpeg ${INSTALL_DATA} ${WRKSRC}/*.doc ${DESTDIR}${PREFIX}/share/doc/jpeg ${INSTALL_DATA} ${WRKSRC}/jpegint.h ${DESTDIR}${PREFIX}/include diff --git a/graphics/jpeg/PLIST b/graphics/jpeg/PLIST index d3b2f87733a..1db1fd52167 100644 --- a/graphics/jpeg/PLIST +++ b/graphics/jpeg/PLIST @@ -1,6 +1,8 @@ -@comment $NetBSD: PLIST,v 1.5 2004/10/30 01:02:43 wiz Exp $ +@comment $NetBSD: PLIST,v 1.6 2007/06/05 22:07:25 tnn Exp $ bin/cjpeg bin/djpeg +bin/exifautotran +bin/jpegexiforient bin/jpegtran bin/rdjpgcom bin/wrjpgcom diff --git a/graphics/jpeg/distinfo b/graphics/jpeg/distinfo index 70cc612b1e3..c961ae4f36c 100644 --- a/graphics/jpeg/distinfo +++ b/graphics/jpeg/distinfo @@ -1,6 +1,11 @@ -$NetBSD: distinfo,v 1.5 2006/11/02 18:00:43 joerg Exp $ +$NetBSD: distinfo,v 1.6 2007/06/05 22:07:25 tnn Exp $ SHA1 (jpegsrc.v6b.tar.gz) = 7079f0d6c42fad0cfba382cf6ad322add1ace8f9 RMD160 (jpegsrc.v6b.tar.gz) = 18892206014fbb8cae2a44e281f4ed53feaf7882 Size (jpegsrc.v6b.tar.gz) = 613261 bytes SHA1 (patch-aa) = ffb4a89925187ebc74487ad8980266d1230a5efb +SHA1 (patch-ab) = e57da4f693e638cf58b414bfbc50e21d80270109 +SHA1 (patch-ac) = 6c34738effc7df671d4522b4ecca06dab640ed16 +SHA1 (patch-ad) = 73afda7c2c849c93d1c1dd2c632e1e67a1db97dc +SHA1 (patch-ae) = 4d2b3316df3a6b3ae9c0ef5099620f5f24300cca +SHA1 (patch-af) = d414c8133878b9fe5f24a6ce008c36112f417e6d diff --git a/graphics/jpeg/files/exifautotran b/graphics/jpeg/files/exifautotran new file mode 100644 index 00000000000..3fc90d3fc48 --- /dev/null +++ b/graphics/jpeg/files/exifautotran @@ -0,0 +1,38 @@ +#! /bin/sh +# +# Based on http://www.jpegclub.org/exifautotran.txt +# +if [ "$#" = "0" ] +then +cat << EOF 1>&2 +usage: exifautotran [list of files] +Transforms Exif files so that Orientation becomes 1 +EOF +exit 1 +fi + +for i +do + case `jpegexiforient -n "$i"` in + 1) transform="";; + 2) transform="-flip horizontal";; + 3) transform="-rotate 180";; + 4) transform="-flip vertical";; + 5) transform="-transpose";; + 6) transform="-rotate 90";; + 7) transform="-transverse";; + 8) transform="-rotate 270";; + *) transform="";; + esac + if test -n "$transform"; then + echo Executing: jpegtran -copy all $transform $i + jpegtran -copy all $transform "$i" > tempfile + if test $? -ne 0; then + echo Error while transforming $i - skipped. + else + rm "$i" + mv tempfile "$i" + jpegexiforient -1 "$i" > /dev/null + fi + fi +done diff --git a/graphics/jpeg/files/jpegexiforient.c b/graphics/jpeg/files/jpegexiforient.c new file mode 100644 index 00000000000..ac17d7deef2 --- /dev/null +++ b/graphics/jpeg/files/jpegexiforient.c @@ -0,0 +1,292 @@ +/* + * jpegexiforient.c + * + * This is a utility program to get and set the Exif Orientation Tag. + * It can be used together with jpegtran in scripts for automatic + * orientation correction of digital camera pictures. + * + * The Exif orientation value gives the orientation of the camera + * relative to the scene when the image was captured. The relation + * of the '0th row' and '0th column' to visual position is shown as + * below. + * + * Value | 0th Row | 0th Column + * ------+-------------+----------- + * 1 | top | left side + * 2 | top | rigth side + * 3 | bottom | rigth side + * 4 | bottom | left side + * 5 | left side | top + * 6 | right side | top + * 7 | right side | bottom + * 8 | left side | bottom + * + * For convenience, here is what the letter F would look like if it were + * tagged correctly and displayed by a program that ignores the orientation + * tag: + * + * 1 2 3 4 5 6 7 8 + * + * 888888 888888 88 88 8888888888 88 88 8888888888 + * 88 88 88 88 88 88 88 88 88 88 88 88 + * 8888 8888 8888 8888 88 8888888888 8888888888 88 + * 88 88 88 88 + * 88 88 888888 888888 + * + */ + +#include <stdio.h> +#include <stdlib.h> + +static FILE * myfile; /* My JPEG file */ + +static unsigned char exif_data[65536L]; + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(myfile) + +/* Error exit handler */ +#define ERREXIT(msg) (exit(0)) + +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) + ERREXIT("Premature EOF in JPEG file"); + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + ERREXIT("Premature EOF in JPEG file"); + c2 = NEXTBYTE(); + if (c2 == EOF) + ERREXIT("Premature EOF in JPEG file"); + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + +static const char * progname; /* program name for error messages */ + +static void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "jpegexiforient reads or writes the Exif Orientation Tag "); + fprintf(stderr, "in a JPEG Exif file.\n"); + + fprintf(stderr, "Usage: %s [switches] jpegfile\n", progname); + + fprintf(stderr, "Switches:\n"); + fprintf(stderr, " -n Do not output the trailing newline\n"); + fprintf(stderr, " -1 .. -8 Set orientation value 1 .. 8\n"); +} + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int n_flag, set_flag; + unsigned int length, i; + int is_motorola; /* Flag for byte order */ + unsigned int offset, number_of_tags, tagnum; + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "jpegexiforient"; /* in case C library doesn't provide it */ + + if (argc < 2) { usage(); return 0; } + + n_flag = 0; set_flag = 0; + + i = 1; + while (argv[i][0] == '-') { + switch (argv[i][1]) { + case 'n': + n_flag = 1; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + set_flag = argv[i][1] - '0'; + break; + default: + usage(); return 0; + } + if (++i >= argc) { usage(); return 0; } + } + + if (set_flag) { + if ((myfile = fopen(argv[i], "rb+")) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[i]); + return 0; + } + } else { + if ((myfile = fopen(argv[i], "rb")) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[i]); + return 0; + } + } + + /* Read File head, check for JPEG SOI + Exif APP1 */ + for (i = 0; i < 4; i++) + exif_data[i] = (unsigned char) read_1_byte(); + if (exif_data[0] != 0xFF || + exif_data[1] != 0xD8 || + exif_data[2] != 0xFF || + exif_data[3] != 0xE1) + return 0; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + /* Following Exif data length must be at least 6 */ + if (length < 8) + return 0; + length -= 8; + /* Read Exif head, check for "Exif" */ + for (i = 0; i < 6; i++) + exif_data[i] = (unsigned char) read_1_byte(); + if (exif_data[0] != 0x45 || + exif_data[1] != 0x78 || + exif_data[2] != 0x69 || + exif_data[3] != 0x66 || + exif_data[4] != 0 || + exif_data[5] != 0) + return 0; + /* Read Exif body */ + for (i = 0; i < length; i++) + exif_data[i] = (unsigned char) read_1_byte(); + + if (length < 12) return 0; /* Length of an IFD entry */ + + /* Discover byte order */ + if (exif_data[0] == 0x49 && exif_data[1] == 0x49) + is_motorola = 0; + else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D) + is_motorola = 1; + else + return 0; + + /* Check Tag Mark */ + if (is_motorola) { + if (exif_data[2] != 0) return 0; + if (exif_data[3] != 0x2A) return 0; + } else { + if (exif_data[3] != 0) return 0; + if (exif_data[2] != 0x2A) return 0; + } + + /* Get first IFD offset (offset to IFD0) */ + if (is_motorola) { + if (exif_data[4] != 0) return 0; + if (exif_data[5] != 0) return 0; + offset = exif_data[6]; + offset <<= 8; + offset += exif_data[7]; + } else { + if (exif_data[7] != 0) return 0; + if (exif_data[6] != 0) return 0; + offset = exif_data[5]; + offset <<= 8; + offset += exif_data[4]; + } + if (offset > length - 2) return 0; /* check end of data segment */ + + /* Get the number of directory entries contained in this IFD */ + if (is_motorola) { + number_of_tags = exif_data[offset]; + number_of_tags <<= 8; + number_of_tags += exif_data[offset+1]; + } else { + number_of_tags = exif_data[offset+1]; + number_of_tags <<= 8; + number_of_tags += exif_data[offset]; + } + if (number_of_tags == 0) return 0; + offset += 2; + + /* Search for Orientation Tag in IFD0 */ + for (;;) { + if (offset > length - 12) return 0; /* check end of data segment */ + /* Get Tag number */ + if (is_motorola) { + tagnum = exif_data[offset]; + tagnum <<= 8; + tagnum += exif_data[offset+1]; + } else { + tagnum = exif_data[offset+1]; + tagnum <<= 8; + tagnum += exif_data[offset]; + } + if (tagnum == 0x0112) break; /* found Orientation Tag */ + if (--number_of_tags == 0) return 0; + offset += 12; + } + + if (set_flag) { + /* Set the Orientation value */ + if (is_motorola) { + exif_data[offset+2] = 0; /* Format = unsigned short (2 octets) */ + exif_data[offset+3] = 3; + exif_data[offset+4] = 0; /* Number Of Components = 1 */ + exif_data[offset+5] = 0; + exif_data[offset+6] = 0; + exif_data[offset+7] = 1; + exif_data[offset+8] = 0; + exif_data[offset+9] = (unsigned char)set_flag; + exif_data[offset+10] = 0; + exif_data[offset+11] = 0; + } else { + exif_data[offset+2] = 3; /* Format = unsigned short (2 octets) */ + exif_data[offset+3] = 0; + exif_data[offset+4] = 1; /* Number Of Components = 1 */ + exif_data[offset+5] = 0; + exif_data[offset+6] = 0; + exif_data[offset+7] = 0; + exif_data[offset+8] = (unsigned char)set_flag; + exif_data[offset+9] = 0; + exif_data[offset+10] = 0; + exif_data[offset+11] = 0; + } + fseek(myfile, (4 + 2 + 6 + 2) + offset, SEEK_SET); + fwrite(exif_data + 2 + offset, 1, 10, myfile); + } else { + /* Get the Orientation value */ + if (is_motorola) { + if (exif_data[offset+8] != 0) return 0; + set_flag = exif_data[offset+9]; + } else { + if (exif_data[offset+9] != 0) return 0; + set_flag = exif_data[offset+8]; + } + if (set_flag > 8) return 0; + } + + /* Write out Orientation value */ + if (n_flag) + printf("%c", '0' + set_flag); + else + printf("%c\n", '0' + set_flag); + + /* All done. */ + return 0; +} diff --git a/graphics/jpeg/patches/patch-ab b/graphics/jpeg/patches/patch-ab new file mode 100644 index 00000000000..f0e570dc5b6 --- /dev/null +++ b/graphics/jpeg/patches/patch-ab @@ -0,0 +1,1501 @@ +$NetBSD: patch-ab,v 1.1 2007/06/05 22:07:26 tnn Exp $ + +--- transupp.c.orig 2007-06-05 22:33:58.000000000 +0200 ++++ transupp.c +@@ -1,7 +1,7 @@ + /* + * transupp.c + * +- * Copyright (C) 1997, Thomas G. Lane. ++ * Copyright (C) 1997-2001, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * +@@ -20,6 +20,7 @@ + #include "jinclude.h" + #include "jpeglib.h" + #include "transupp.h" /* My own external interface */ ++#include <ctype.h> /* to declare isdigit() */ + + + #if TRANSFORMS_SUPPORTED +@@ -28,7 +29,8 @@ + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. +- * Thanks to Guido Vollbeding for the initial design and code of this feature. ++ * Thanks to Guido Vollbeding for the initial design and code of this feature, ++ * and to Ben Jackson for introducing the cropping feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the +@@ -42,6 +44,13 @@ + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * ++ * If cropping or trimming is involved, the destination arrays may be smaller ++ * than the source arrays. Note it is not possible to do horizontal flip ++ * in-place when a nonzero Y crop offset is specified, since we'd have to move ++ * data from one block row to another but the virtual array manager doesn't ++ * guarantee we can touch more than one row at a time. So in that case, ++ * we have to use a separate destination array. ++ * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the +@@ -54,20 +63,65 @@ + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. +- * 5. All the routines assume that the source and destination buffers are ++ * 5. When "crop" is in effect, the destination's dimensions will be the ++ * cropped values but the source's will be uncropped. Each transform ++ * routine is responsible for picking up source data starting at the ++ * correct X and Y offset for the crop region. (The X and Y offsets ++ * passed to the transform routines are measured in iMCU blocks of the ++ * destination.) ++ * 6. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. +- * Notes 2,3,4 boil down to this: generally we should use the destination's +- * dimensions and ignore the source's. + */ + + + LOCAL(void) +-do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, +- jvirt_barray_ptr *src_coef_arrays) +-/* Horizontal flip; done in-place, so no separate dest array is required */ ++do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, ++ jvirt_barray_ptr *src_coef_arrays, ++ jvirt_barray_ptr *dst_coef_arrays) ++/* Crop. This is only used when no rotate/flip is requested with the crop. */ ++{ ++ JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; ++ int ci, offset_y; ++ JBLOCKARRAY src_buffer, dst_buffer; ++ jpeg_component_info *compptr; ++ ++ /* We simply have to copy the right amount of data (the destination's ++ * image size) starting at the given X and Y offsets in the source. ++ */ ++ for (ci = 0; ci < dstinfo->num_components; ci++) { ++ compptr = dstinfo->comp_info + ci; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; ++ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; ++ dst_blk_y += compptr->v_samp_factor) { ++ dst_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ++ (JDIMENSION) compptr->v_samp_factor, TRUE); ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, ++ (JDIMENSION) compptr->v_samp_factor, FALSE); ++ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { ++ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, ++ dst_buffer[offset_y], ++ compptr->width_in_blocks); ++ } ++ } ++ } ++} ++ ++ ++LOCAL(void) ++do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, ++ jvirt_barray_ptr *src_coef_arrays) ++/* Horizontal flip; done in-place, so no separate dest array is required. ++ * NB: this only works when y_crop_offset is zero. ++ */ + { +- JDIMENSION MCU_cols, comp_width, blk_x, blk_y; ++ JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; +@@ -79,17 +133,19 @@ do_flip_h (j_decompress_ptr srcinfo, j_c + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { ++ /* Do the mirroring */ + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; +@@ -105,6 +161,79 @@ do_flip_h (j_decompress_ptr srcinfo, j_c + *ptr2++ = -temp1; + } + } ++ if (x_crop_blocks > 0) { ++ /* Now left-justify the portion of the data to be kept. ++ * We can't use a single jcopy_block_row() call because that routine ++ * depends on memcpy(), whose behavior is unspecified for overlapping ++ * source and destination areas. Sigh. ++ */ ++ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { ++ jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, ++ buffer[offset_y] + blk_x, ++ (JDIMENSION) 1); ++ } ++ } ++ } ++ } ++ } ++} ++ ++ ++LOCAL(void) ++do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, ++ jvirt_barray_ptr *src_coef_arrays, ++ jvirt_barray_ptr *dst_coef_arrays) ++/* Horizontal flip in general cropping case */ ++{ ++ JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; ++ int ci, k, offset_y; ++ JBLOCKARRAY src_buffer, dst_buffer; ++ JBLOCKROW src_row_ptr, dst_row_ptr; ++ JCOEFPTR src_ptr, dst_ptr; ++ jpeg_component_info *compptr; ++ ++ /* Here we must output into a separate array because we can't touch ++ * different rows of a single virtual array simultaneously. Otherwise, ++ * this is essentially the same as the routine above. ++ */ ++ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ ++ for (ci = 0; ci < dstinfo->num_components; ci++) { ++ compptr = dstinfo->comp_info + ci; ++ comp_width = MCU_cols * compptr->h_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; ++ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; ++ dst_blk_y += compptr->v_samp_factor) { ++ dst_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, ++ (JDIMENSION) compptr->v_samp_factor, TRUE); ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, ++ (JDIMENSION) compptr->v_samp_factor, FALSE); ++ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { ++ dst_row_ptr = dst_buffer[offset_y]; ++ src_row_ptr = src_buffer[offset_y]; ++ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Do the mirrorable blocks */ ++ dst_ptr = dst_row_ptr[dst_blk_x]; ++ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; ++ /* this unrolled loop doesn't need to know which row it's on... */ ++ for (k = 0; k < DCTSIZE2; k += 2) { ++ *dst_ptr++ = *src_ptr++; /* copy even column */ ++ *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ ++ } ++ } else { ++ /* Copy last partial block(s) verbatim */ ++ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, ++ dst_row_ptr + dst_blk_x, ++ (JDIMENSION) 1); ++ } ++ } + } + } + } +@@ -113,11 +242,13 @@ do_flip_h (j_decompress_ptr srcinfo, j_c + + LOCAL(void) + do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* Vertical flip */ + { + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; +@@ -131,33 +262,38 @@ do_flip_v (j_decompress_ptr srcinfo, j_c + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], +- comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, ++ comp_height - y_crop_blocks - dst_blk_y - ++ (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; ++ src_row_ptr += x_crop_blocks; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; +@@ -173,7 +309,8 @@ do_flip_v (j_decompress_ptr srcinfo, j_c + } + } else { + /* Just copy row verbatim. */ +- jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], ++ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, ++ dst_buffer[offset_y], + compptr->width_in_blocks); + } + } +@@ -184,11 +321,12 @@ do_flip_v (j_decompress_ptr srcinfo, j_c + + LOCAL(void) + do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* Transpose source into destination */ + { +- JDIMENSION dst_blk_x, dst_blk_y; ++ JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; +@@ -201,6 +339,8 @@ do_transpose (j_decompress_ptr srcinfo, + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -210,11 +350,12 @@ do_transpose (j_decompress_ptr srcinfo, + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -228,6 +369,7 @@ do_transpose (j_decompress_ptr srcinfo, + + LOCAL(void) + do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* 90 degree rotation is equivalent to +@@ -237,6 +379,7 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c + */ + { + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; +@@ -246,11 +389,13 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -259,15 +404,26 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { +- src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, +- (JDIMENSION) compptr->h_samp_factor, FALSE); ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Block is within the mirrorable area. */ ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ comp_width - x_crop_blocks - dst_blk_x - ++ (JDIMENSION) compptr->h_samp_factor, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } else { ++ /* Edge blocks are transposed but not mirrored. */ ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; +- if (dst_blk_x < comp_width) { ++ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ +- dst_ptr = dst_buffer[offset_y] +- [comp_width - dst_blk_x - offset_x - 1]; ++ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -277,7 +433,8 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c + } + } else { + /* Edge blocks are transposed but not mirrored. */ +- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -292,6 +449,7 @@ do_rot_90 (j_decompress_ptr srcinfo, j_c + + LOCAL(void) + do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* 270 degree rotation is equivalent to +@@ -301,6 +459,7 @@ do_rot_270 (j_decompress_ptr srcinfo, j_ + */ + { + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; +@@ -310,11 +469,13 @@ do_rot_270 (j_decompress_ptr srcinfo, j_ + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -324,14 +485,15 @@ do_rot_270 (j_decompress_ptr srcinfo, j_ + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] +- [comp_height - dst_blk_y - offset_y - 1]; ++ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -341,7 +503,8 @@ do_rot_270 (j_decompress_ptr srcinfo, j_ + } + } else { + /* Edge blocks are transposed but not mirrored. */ +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; ++ src_ptr = src_buffer[offset_x] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -356,6 +519,7 @@ do_rot_270 (j_decompress_ptr srcinfo, j_ + + LOCAL(void) + do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* 180 degree rotation is equivalent to +@@ -365,89 +529,93 @@ do_rot_180 (j_decompress_ptr srcinfo, j_ + */ + { + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); +- if (dst_blk_y < comp_height) { ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], +- comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, ++ comp_height - y_crop_blocks - dst_blk_y - ++ (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { +- if (dst_blk_y < comp_height) { ++ dst_row_ptr = dst_buffer[offset_y]; ++ if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ +- dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; +- /* Process the blocks that can be mirrored both ways. */ +- for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { ++ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; +- for (i = 0; i < DCTSIZE; i += 2) { +- /* For even row, negate every odd column. */ +- for (j = 0; j < DCTSIZE; j += 2) { +- *dst_ptr++ = *src_ptr++; +- *dst_ptr++ = - *src_ptr++; ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Process the blocks that can be mirrored both ways. */ ++ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; ++ for (i = 0; i < DCTSIZE; i += 2) { ++ /* For even row, negate every odd column. */ ++ for (j = 0; j < DCTSIZE; j += 2) { ++ *dst_ptr++ = *src_ptr++; ++ *dst_ptr++ = - *src_ptr++; ++ } ++ /* For odd row, negate every even column. */ ++ for (j = 0; j < DCTSIZE; j += 2) { ++ *dst_ptr++ = - *src_ptr++; ++ *dst_ptr++ = *src_ptr++; ++ } + } +- /* For odd row, negate every even column. */ +- for (j = 0; j < DCTSIZE; j += 2) { +- *dst_ptr++ = - *src_ptr++; +- *dst_ptr++ = *src_ptr++; ++ } else { ++ /* Any remaining right-edge blocks are only mirrored vertically. */ ++ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; ++ for (i = 0; i < DCTSIZE; i += 2) { ++ for (j = 0; j < DCTSIZE; j++) ++ *dst_ptr++ = *src_ptr++; ++ for (j = 0; j < DCTSIZE; j++) ++ *dst_ptr++ = - *src_ptr++; + } + } + } +- /* Any remaining right-edge blocks are only mirrored vertically. */ +- for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { +- dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[dst_blk_x]; +- for (i = 0; i < DCTSIZE; i += 2) { +- for (j = 0; j < DCTSIZE; j++) +- *dst_ptr++ = *src_ptr++; +- for (j = 0; j < DCTSIZE; j++) +- *dst_ptr++ = - *src_ptr++; +- } +- } + } else { + /* Remaining rows are just mirrored horizontally. */ +- dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; +- /* Process the blocks that can be mirrored. */ +- for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { +- dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; +- for (i = 0; i < DCTSIZE2; i += 2) { +- *dst_ptr++ = *src_ptr++; +- *dst_ptr++ = - *src_ptr++; ++ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Process the blocks that can be mirrored. */ ++ dst_ptr = dst_row_ptr[dst_blk_x]; ++ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; ++ for (i = 0; i < DCTSIZE2; i += 2) { ++ *dst_ptr++ = *src_ptr++; ++ *dst_ptr++ = - *src_ptr++; ++ } ++ } else { ++ /* Any remaining right-edge blocks are only copied. */ ++ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, ++ dst_row_ptr + dst_blk_x, ++ (JDIMENSION) 1); + } + } +- /* Any remaining right-edge blocks are only copied. */ +- for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { +- dst_ptr = dst_row_ptr[dst_blk_x]; +- src_ptr = src_row_ptr[dst_blk_x]; +- for (i = 0; i < DCTSIZE2; i++) +- *dst_ptr++ = *src_ptr++; +- } + } + } + } +@@ -457,6 +625,7 @@ do_rot_180 (j_decompress_ptr srcinfo, j_ + + LOCAL(void) + do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ++ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) + /* Transverse transpose is equivalent to +@@ -470,18 +639,21 @@ do_transverse (j_decompress_ptr srcinfo, + */ + { + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; ++ JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + +- MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); +- MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); ++ MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); ++ MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; ++ x_crop_blocks = x_crop_offset * compptr->h_samp_factor; ++ y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) +@@ -490,17 +662,26 @@ do_transverse (j_decompress_ptr srcinfo, + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { +- src_buffer = (*srcinfo->mem->access_virt_barray) +- ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, +- (JDIMENSION) compptr->h_samp_factor, FALSE); ++ if (x_crop_blocks + dst_blk_x < comp_width) { ++ /* Block is within the mirrorable area. */ ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ comp_width - x_crop_blocks - dst_blk_x - ++ (JDIMENSION) compptr->h_samp_factor, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } else { ++ src_buffer = (*srcinfo->mem->access_virt_barray) ++ ((j_common_ptr) srcinfo, src_coef_arrays[ci], ++ dst_blk_x + x_crop_blocks, ++ (JDIMENSION) compptr->h_samp_factor, FALSE); ++ } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { +- if (dst_blk_y < comp_height) { +- src_ptr = src_buffer[offset_x] +- [comp_height - dst_blk_y - offset_y - 1]; +- if (dst_blk_x < comp_width) { ++ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ if (y_crop_blocks + dst_blk_y < comp_height) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ +- dst_ptr = dst_buffer[offset_y] +- [comp_width - dst_blk_x - offset_x - 1]; ++ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] ++ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -516,7 +697,8 @@ do_transverse (j_decompress_ptr srcinfo, + } + } else { + /* Right-edge blocks are mirrored in y only */ +- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x] ++ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -526,11 +708,10 @@ do_transverse (j_decompress_ptr srcinfo, + } + } + } else { +- src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; +- if (dst_blk_x < comp_width) { ++ if (x_crop_blocks + dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ +- dst_ptr = dst_buffer[offset_y] +- [comp_width - dst_blk_x - offset_x - 1]; ++ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -540,7 +721,8 @@ do_transverse (j_decompress_ptr srcinfo, + } + } else { + /* At lower right corner, just transpose, no mirroring */ +- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; ++ src_ptr = src_buffer[offset_x] ++ [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; +@@ -554,8 +736,116 @@ do_transverse (j_decompress_ptr srcinfo, + } + + ++/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. ++ * Returns TRUE if valid integer found, FALSE if not. ++ * *strptr is advanced over the digit string, and *result is set to its value. ++ */ ++ ++LOCAL(boolean) ++jt_read_integer (const char ** strptr, JDIMENSION * result) ++{ ++ const char * ptr = *strptr; ++ JDIMENSION val = 0; ++ ++ for (; isdigit(*ptr); ptr++) { ++ val = val * 10 + (JDIMENSION) (*ptr - '0'); ++ } ++ *result = val; ++ if (ptr == *strptr) ++ return FALSE; /* oops, no digits */ ++ *strptr = ptr; ++ return TRUE; ++} ++ ++ ++/* Parse a crop specification (written in X11 geometry style). ++ * The routine returns TRUE if the spec string is valid, FALSE if not. ++ * ++ * The crop spec string should have the format ++ * <width>x<height>{+-}<xoffset>{+-}<yoffset> ++ * where width, height, xoffset, and yoffset are unsigned integers. ++ * Each of the elements can be omitted to indicate a default value. ++ * (A weakness of this style is that it is not possible to omit xoffset ++ * while specifying yoffset, since they look alike.) ++ * ++ * This code is loosely based on XParseGeometry from the X11 distribution. ++ */ ++ ++GLOBAL(boolean) ++jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) ++{ ++ info->crop = FALSE; ++ info->crop_width_set = JCROP_UNSET; ++ info->crop_height_set = JCROP_UNSET; ++ info->crop_xoffset_set = JCROP_UNSET; ++ info->crop_yoffset_set = JCROP_UNSET; ++ ++ if (isdigit(*spec)) { ++ /* fetch width */ ++ if (! jt_read_integer(&spec, &info->crop_width)) ++ return FALSE; ++ info->crop_width_set = JCROP_POS; ++ } ++ if (*spec == 'x' || *spec == 'X') { ++ /* fetch height */ ++ spec++; ++ if (! jt_read_integer(&spec, &info->crop_height)) ++ return FALSE; ++ info->crop_height_set = JCROP_POS; ++ } ++ if (*spec == '+' || *spec == '-') { ++ /* fetch xoffset */ ++ info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; ++ spec++; ++ if (! jt_read_integer(&spec, &info->crop_xoffset)) ++ return FALSE; ++ } ++ if (*spec == '+' || *spec == '-') { ++ /* fetch yoffset */ ++ info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; ++ spec++; ++ if (! jt_read_integer(&spec, &info->crop_yoffset)) ++ return FALSE; ++ } ++ /* We had better have gotten to the end of the string. */ ++ if (*spec != '\0') ++ return FALSE; ++ info->crop = TRUE; ++ return TRUE; ++} ++ ++ ++/* Trim off any partial iMCUs on the indicated destination edge */ ++ ++LOCAL(void) ++trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) ++{ ++ JDIMENSION MCU_cols; ++ ++ MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE); ++ if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == ++ full_width / (info->max_h_samp_factor * DCTSIZE)) ++ info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE); ++} ++ ++LOCAL(void) ++trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) ++{ ++ JDIMENSION MCU_rows; ++ ++ MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE); ++ if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == ++ full_height / (info->max_v_samp_factor * DCTSIZE)) ++ info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE); ++} ++ ++ + /* Request any required workspace. + * ++ * This routine figures out the size that the output image will be ++ * (which implies that all the transform parameters must be set before ++ * it is called). ++ * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. +@@ -569,9 +859,13 @@ jtransform_request_workspace (j_decompre + jpeg_transform_info *info) + { + jvirt_barray_ptr *coef_arrays = NULL; ++ boolean need_workspace, transpose_it; + jpeg_component_info *compptr; +- int ci; ++ JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs; ++ JDIMENSION width_in_blocks, height_in_blocks; ++ int ci, h_samp_factor, v_samp_factor; + ++ /* Determine number of components in output image */ + if (info->force_grayscale && + srcinfo->jpeg_color_space == JCS_YCbCr && + srcinfo->num_components == 3) { +@@ -581,55 +875,181 @@ jtransform_request_workspace (j_decompre + /* Process all the components */ + info->num_components = srcinfo->num_components; + } ++ /* If there is only one output component, force the iMCU size to be 1; ++ * else use the source iMCU size. (This allows us to do the right thing ++ * when reducing color to grayscale, and also provides a handy way of ++ * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) ++ */ ++ ++ switch (info->transform) { ++ case JXFORM_TRANSPOSE: ++ case JXFORM_TRANSVERSE: ++ case JXFORM_ROT_90: ++ case JXFORM_ROT_270: ++ info->output_width = srcinfo->image_height; ++ info->output_height = srcinfo->image_width; ++ if (info->num_components == 1) { ++ info->max_h_samp_factor = 1; ++ info->max_v_samp_factor = 1; ++ } else { ++ info->max_h_samp_factor = srcinfo->max_v_samp_factor; ++ info->max_v_samp_factor = srcinfo->max_h_samp_factor; ++ } ++ break; ++ default: ++ info->output_width = srcinfo->image_width; ++ info->output_height = srcinfo->image_height; ++ if (info->num_components == 1) { ++ info->max_h_samp_factor = 1; ++ info->max_v_samp_factor = 1; ++ } else { ++ info->max_h_samp_factor = srcinfo->max_h_samp_factor; ++ info->max_v_samp_factor = srcinfo->max_v_samp_factor; ++ } ++ break; ++ } ++ ++ /* If cropping has been requested, compute the crop area's position and ++ * dimensions, ensuring that its upper left corner falls at an iMCU boundary. ++ */ ++ if (info->crop) { ++ /* Insert default values for unset crop parameters */ ++ if (info->crop_xoffset_set == JCROP_UNSET) ++ info->crop_xoffset = 0; /* default to +0 */ ++ if (info->crop_yoffset_set == JCROP_UNSET) ++ info->crop_yoffset = 0; /* default to +0 */ ++ if (info->crop_xoffset >= info->output_width || ++ info->crop_yoffset >= info->output_height) ++ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); ++ if (info->crop_width_set == JCROP_UNSET) ++ info->crop_width = info->output_width - info->crop_xoffset; ++ if (info->crop_height_set == JCROP_UNSET) ++ info->crop_height = info->output_height - info->crop_yoffset; ++ /* Ensure parameters are valid */ ++ if (info->crop_width <= 0 || info->crop_width > info->output_width || ++ info->crop_height <= 0 || info->crop_height > info->output_height || ++ info->crop_xoffset > info->output_width - info->crop_width || ++ info->crop_yoffset > info->output_height - info->crop_height) ++ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); ++ /* Convert negative crop offsets into regular offsets */ ++ if (info->crop_xoffset_set == JCROP_NEG) ++ xoffset = info->output_width - info->crop_width - info->crop_xoffset; ++ else ++ xoffset = info->crop_xoffset; ++ if (info->crop_yoffset_set == JCROP_NEG) ++ yoffset = info->output_height - info->crop_height - info->crop_yoffset; ++ else ++ yoffset = info->crop_yoffset; ++ /* Now adjust so that upper left corner falls at an iMCU boundary */ ++ info->output_width = ++ info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE)); ++ info->output_height = ++ info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE)); ++ /* Save x/y offsets measured in iMCUs */ ++ info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE); ++ info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE); ++ } else { ++ info->x_crop_offset = 0; ++ info->y_crop_offset = 0; ++ } + ++ /* Figure out whether we need workspace arrays, ++ * and if so whether they are transposed relative to the source. ++ */ ++ need_workspace = FALSE; ++ transpose_it = FALSE; + switch (info->transform) { + case JXFORM_NONE: ++ if (info->x_crop_offset != 0 || info->y_crop_offset != 0) ++ need_workspace = TRUE; ++ /* No workspace needed if neither cropping nor transforming */ ++ break; + case JXFORM_FLIP_H: +- /* Don't need a workspace array */ ++ if (info->trim) ++ trim_right_edge(info, srcinfo->image_width); ++ if (info->y_crop_offset != 0) ++ need_workspace = TRUE; ++ /* do_flip_h_no_crop doesn't need a workspace array */ + break; + case JXFORM_FLIP_V: +- case JXFORM_ROT_180: +- /* Need workspace arrays having same dimensions as source image. +- * Note that we allocate arrays padded out to the next iMCU boundary, +- * so that transform routines need not worry about missing edge blocks. +- */ +- coef_arrays = (jvirt_barray_ptr *) +- (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, +- SIZEOF(jvirt_barray_ptr) * info->num_components); +- for (ci = 0; ci < info->num_components; ci++) { +- compptr = srcinfo->comp_info + ci; +- coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) +- ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, +- (JDIMENSION) jround_up((long) compptr->width_in_blocks, +- (long) compptr->h_samp_factor), +- (JDIMENSION) jround_up((long) compptr->height_in_blocks, +- (long) compptr->v_samp_factor), +- (JDIMENSION) compptr->v_samp_factor); +- } ++ if (info->trim) ++ trim_bottom_edge(info, srcinfo->image_height); ++ /* Need workspace arrays having same dimensions as source image. */ ++ need_workspace = TRUE; + break; + case JXFORM_TRANSPOSE: ++ /* transpose does NOT have to trim anything */ ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; + case JXFORM_TRANSVERSE: ++ if (info->trim) { ++ trim_right_edge(info, srcinfo->image_height); ++ trim_bottom_edge(info, srcinfo->image_width); ++ } ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; + case JXFORM_ROT_90: ++ if (info->trim) ++ trim_right_edge(info, srcinfo->image_height); ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; ++ case JXFORM_ROT_180: ++ if (info->trim) { ++ trim_right_edge(info, srcinfo->image_width); ++ trim_bottom_edge(info, srcinfo->image_height); ++ } ++ /* Need workspace arrays having same dimensions as source image. */ ++ need_workspace = TRUE; ++ break; + case JXFORM_ROT_270: +- /* Need workspace arrays having transposed dimensions. +- * Note that we allocate arrays padded out to the next iMCU boundary, +- * so that transform routines need not worry about missing edge blocks. +- */ ++ if (info->trim) ++ trim_bottom_edge(info, srcinfo->image_width); ++ /* Need workspace arrays having transposed dimensions. */ ++ need_workspace = TRUE; ++ transpose_it = TRUE; ++ break; ++ } ++ ++ /* Allocate workspace if needed. ++ * Note that we allocate arrays padded out to the next iMCU boundary, ++ * so that transform routines need not worry about missing edge blocks. ++ */ ++ if (need_workspace) { + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, +- SIZEOF(jvirt_barray_ptr) * info->num_components); ++ SIZEOF(jvirt_barray_ptr) * info->num_components); ++ width_in_iMCUs = (JDIMENSION) ++ jdiv_round_up((long) info->output_width, ++ (long) (info->max_h_samp_factor * DCTSIZE)); ++ height_in_iMCUs = (JDIMENSION) ++ jdiv_round_up((long) info->output_height, ++ (long) (info->max_v_samp_factor * DCTSIZE)); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; ++ if (info->num_components == 1) { ++ /* we're going to force samp factors to 1x1 in this case */ ++ h_samp_factor = v_samp_factor = 1; ++ } else if (transpose_it) { ++ h_samp_factor = compptr->v_samp_factor; ++ v_samp_factor = compptr->h_samp_factor; ++ } else { ++ h_samp_factor = compptr->h_samp_factor; ++ v_samp_factor = compptr->v_samp_factor; ++ } ++ width_in_blocks = width_in_iMCUs * h_samp_factor; ++ height_in_blocks = height_in_iMCUs * v_samp_factor; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, +- (JDIMENSION) jround_up((long) compptr->height_in_blocks, +- (long) compptr->v_samp_factor), +- (JDIMENSION) jround_up((long) compptr->width_in_blocks, +- (long) compptr->h_samp_factor), +- (JDIMENSION) compptr->h_samp_factor); ++ width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); + } +- break; + } ++ + info->workspace_coef_arrays = coef_arrays; + } + +@@ -642,14 +1062,8 @@ transpose_critical_parameters (j_compres + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; +- JDIMENSION dtemp; + UINT16 qtemp; + +- /* Transpose basic image dimensions */ +- dtemp = dstinfo->image_width; +- dstinfo->image_width = dstinfo->image_height; +- dstinfo->image_height = dtemp; +- + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; +@@ -674,46 +1088,159 @@ transpose_critical_parameters (j_compres + } + + +-/* Trim off any partial iMCUs on the indicated destination edge */ ++/* Adjust Exif image parameters. ++ * ++ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. ++ */ + + LOCAL(void) +-trim_right_edge (j_compress_ptr dstinfo) ++adjust_exif_parameters (JOCTET FAR * data, unsigned int length, ++ JDIMENSION new_width, JDIMENSION new_height) + { +- int ci, max_h_samp_factor; +- JDIMENSION MCU_cols; ++ boolean is_motorola; /* Flag for byte order */ ++ unsigned int number_of_tags, tagnum; ++ unsigned int firstoffset, offset; ++ JDIMENSION new_value; ++ ++ if (length < 12) return; /* Length of an IFD entry */ ++ ++ /* Discover byte order */ ++ if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) ++ is_motorola = FALSE; ++ else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) ++ is_motorola = TRUE; ++ else ++ return; ++ ++ /* Check Tag Mark */ ++ if (is_motorola) { ++ if (GETJOCTET(data[2]) != 0) return; ++ if (GETJOCTET(data[3]) != 0x2A) return; ++ } else { ++ if (GETJOCTET(data[3]) != 0) return; ++ if (GETJOCTET(data[2]) != 0x2A) return; ++ } + +- /* We have to compute max_h_samp_factor ourselves, +- * because it hasn't been set yet in the destination +- * (and we don't want to use the source's value). +- */ +- max_h_samp_factor = 1; +- for (ci = 0; ci < dstinfo->num_components; ci++) { +- int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; +- max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); ++ /* Get first IFD offset (offset to IFD0) */ ++ if (is_motorola) { ++ if (GETJOCTET(data[4]) != 0) return; ++ if (GETJOCTET(data[5]) != 0) return; ++ firstoffset = GETJOCTET(data[6]); ++ firstoffset <<= 8; ++ firstoffset += GETJOCTET(data[7]); ++ } else { ++ if (GETJOCTET(data[7]) != 0) return; ++ if (GETJOCTET(data[6]) != 0) return; ++ firstoffset = GETJOCTET(data[5]); ++ firstoffset <<= 8; ++ firstoffset += GETJOCTET(data[4]); + } +- MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); +- if (MCU_cols > 0) /* can't trim to 0 pixels */ +- dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); +-} ++ if (firstoffset > length - 2) return; /* check end of data segment */ + +-LOCAL(void) +-trim_bottom_edge (j_compress_ptr dstinfo) +-{ +- int ci, max_v_samp_factor; +- JDIMENSION MCU_rows; ++ /* Get the number of directory entries contained in this IFD */ ++ if (is_motorola) { ++ number_of_tags = GETJOCTET(data[firstoffset]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[firstoffset+1]); ++ } else { ++ number_of_tags = GETJOCTET(data[firstoffset+1]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[firstoffset]); ++ } ++ if (number_of_tags == 0) return; ++ firstoffset += 2; + +- /* We have to compute max_v_samp_factor ourselves, +- * because it hasn't been set yet in the destination +- * (and we don't want to use the source's value). +- */ +- max_v_samp_factor = 1; +- for (ci = 0; ci < dstinfo->num_components; ci++) { +- int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; +- max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); ++ /* Search for ExifSubIFD offset Tag in IFD0 */ ++ for (;;) { ++ if (firstoffset > length - 12) return; /* check end of data segment */ ++ /* Get Tag number */ ++ if (is_motorola) { ++ tagnum = GETJOCTET(data[firstoffset]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[firstoffset+1]); ++ } else { ++ tagnum = GETJOCTET(data[firstoffset+1]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[firstoffset]); ++ } ++ if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ ++ if (--number_of_tags == 0) return; ++ firstoffset += 12; + } +- MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); +- if (MCU_rows > 0) /* can't trim to 0 pixels */ +- dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); ++ ++ /* Get the ExifSubIFD offset */ ++ if (is_motorola) { ++ if (GETJOCTET(data[firstoffset+8]) != 0) return; ++ if (GETJOCTET(data[firstoffset+9]) != 0) return; ++ offset = GETJOCTET(data[firstoffset+10]); ++ offset <<= 8; ++ offset += GETJOCTET(data[firstoffset+11]); ++ } else { ++ if (GETJOCTET(data[firstoffset+11]) != 0) return; ++ if (GETJOCTET(data[firstoffset+10]) != 0) return; ++ offset = GETJOCTET(data[firstoffset+9]); ++ offset <<= 8; ++ offset += GETJOCTET(data[firstoffset+8]); ++ } ++ if (offset > length - 2) return; /* check end of data segment */ ++ ++ /* Get the number of directory entries contained in this SubIFD */ ++ if (is_motorola) { ++ number_of_tags = GETJOCTET(data[offset]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[offset+1]); ++ } else { ++ number_of_tags = GETJOCTET(data[offset+1]); ++ number_of_tags <<= 8; ++ number_of_tags += GETJOCTET(data[offset]); ++ } ++ if (number_of_tags < 2) return; ++ offset += 2; ++ ++ /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ ++ do { ++ if (offset > length - 12) return; /* check end of data segment */ ++ /* Get Tag number */ ++ if (is_motorola) { ++ tagnum = GETJOCTET(data[offset]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[offset+1]); ++ } else { ++ tagnum = GETJOCTET(data[offset+1]); ++ tagnum <<= 8; ++ tagnum += GETJOCTET(data[offset]); ++ } ++ if (tagnum == 0xA002 || tagnum == 0xA003) { ++ if (tagnum == 0xA002) ++ new_value = new_width; /* ExifImageWidth Tag */ ++ else ++ new_value = new_height; /* ExifImageHeight Tag */ ++ if (is_motorola) { ++ data[offset+2] = 0; /* Format = unsigned long (4 octets) */ ++ data[offset+3] = 4; ++ data[offset+4] = 0; /* Number Of Components = 1 */ ++ data[offset+5] = 0; ++ data[offset+6] = 0; ++ data[offset+7] = 1; ++ data[offset+8] = 0; ++ data[offset+9] = 0; ++ data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); ++ data[offset+11] = (JOCTET)(new_value & 0xFF); ++ } else { ++ data[offset+2] = 4; /* Format = unsigned long (4 octets) */ ++ data[offset+3] = 0; ++ data[offset+4] = 1; /* Number Of Components = 1 */ ++ data[offset+5] = 0; ++ data[offset+6] = 0; ++ data[offset+7] = 0; ++ data[offset+8] = (JOCTET)(new_value & 0xFF); ++ data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); ++ data[offset+10] = 0; ++ data[offset+11] = 0; ++ } ++ } ++ offset += 12; ++ } while (--number_of_tags); + } + + +@@ -736,18 +1263,22 @@ jtransform_adjust_parameters (j_decompre + { + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { +- /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed +- * properly. Among other things, the target h_samp_factor & v_samp_factor +- * will get set to 1, which typically won't match the source. +- * In fact we do this even if the source is already grayscale; that +- * provides an easy way of coercing a grayscale JPEG with funny sampling +- * factors to the customary 1,1. (Some decoders fail on other factors.) ++ /* First, ensure we have YCbCr or grayscale data, and that the source's ++ * Y channel is full resolution. (No reasonable person would make Y ++ * be less than full resolution, so actually coping with that case ++ * isn't worth extra code space. But we check it to avoid crashing.) + */ +- if ((dstinfo->jpeg_color_space == JCS_YCbCr && +- dstinfo->num_components == 3) || +- (dstinfo->jpeg_color_space == JCS_GRAYSCALE && +- dstinfo->num_components == 1)) { +- /* We have to preserve the source's quantization table number. */ ++ if (((dstinfo->jpeg_color_space == JCS_YCbCr && ++ dstinfo->num_components == 3) || ++ (dstinfo->jpeg_color_space == JCS_GRAYSCALE && ++ dstinfo->num_components == 1)) && ++ srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && ++ srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { ++ /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed ++ * properly. Among other things, it sets the target h_samp_factor & ++ * v_samp_factor to 1, which typically won't match the source. ++ * We have to preserve the source's quantization table number, however. ++ */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; +@@ -755,50 +1286,52 @@ jtransform_adjust_parameters (j_decompre + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } ++ } else if (info->num_components == 1) { ++ /* For a single-component source, we force the destination sampling factors ++ * to 1x1, with or without force_grayscale. This is useful because some ++ * decoders choke on grayscale images with other sampling factors. ++ */ ++ dstinfo->comp_info[0].h_samp_factor = 1; ++ dstinfo->comp_info[0].v_samp_factor = 1; + } + +- /* Correct the destination's image dimensions etc if necessary */ ++ /* Correct the destination's image dimensions as necessary ++ * for crop and rotate/flip operations. ++ */ ++ dstinfo->image_width = info->output_width; ++ dstinfo->image_height = info->output_height; ++ ++ /* Transpose destination image parameters */ + switch (info->transform) { +- case JXFORM_NONE: +- /* Nothing to do */ +- break; +- case JXFORM_FLIP_H: +- if (info->trim) +- trim_right_edge(dstinfo); +- break; +- case JXFORM_FLIP_V: +- if (info->trim) +- trim_bottom_edge(dstinfo); +- break; + case JXFORM_TRANSPOSE: +- transpose_critical_parameters(dstinfo); +- /* transpose does NOT have to trim anything */ +- break; + case JXFORM_TRANSVERSE: +- transpose_critical_parameters(dstinfo); +- if (info->trim) { +- trim_right_edge(dstinfo); +- trim_bottom_edge(dstinfo); +- } +- break; + case JXFORM_ROT_90: +- transpose_critical_parameters(dstinfo); +- if (info->trim) +- trim_right_edge(dstinfo); +- break; +- case JXFORM_ROT_180: +- if (info->trim) { +- trim_right_edge(dstinfo); +- trim_bottom_edge(dstinfo); +- } +- break; + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); +- if (info->trim) +- trim_bottom_edge(dstinfo); + break; + } + ++ /* Adjust Exif properties */ ++ if (srcinfo->marker_list != NULL && ++ srcinfo->marker_list->marker == JPEG_APP0+1 && ++ srcinfo->marker_list->data_length >= 6 && ++ GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && ++ GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && ++ GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && ++ GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && ++ GETJOCTET(srcinfo->marker_list->data[4]) == 0 && ++ GETJOCTET(srcinfo->marker_list->data[5]) == 0) { ++ /* Suppress output of JFIF marker */ ++ dstinfo->write_JFIF_header = FALSE; ++ /* Adjust Exif image parameters */ ++ if (dstinfo->image_width != srcinfo->image_width || ++ dstinfo->image_height != srcinfo->image_height) ++ /* Align data segment to start of TIFF structure for parsing */ ++ adjust_exif_parameters(srcinfo->marker_list->data + 6, ++ srcinfo->marker_list->data_length - 6, ++ dstinfo->image_width, dstinfo->image_height); ++ } ++ + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; +@@ -816,40 +1349,108 @@ jtransform_adjust_parameters (j_decompre + */ + + GLOBAL(void) +-jtransform_execute_transformation (j_decompress_ptr srcinfo, +- j_compress_ptr dstinfo, +- jvirt_barray_ptr *src_coef_arrays, +- jpeg_transform_info *info) ++jtransform_execute_transform (j_decompress_ptr srcinfo, ++ j_compress_ptr dstinfo, ++ jvirt_barray_ptr *src_coef_arrays, ++ jpeg_transform_info *info) + { + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + ++ /* Note: conditions tested here should match those in switch statement ++ * in jtransform_request_workspace() ++ */ + switch (info->transform) { + case JXFORM_NONE: ++ if (info->x_crop_offset != 0 || info->y_crop_offset != 0) ++ do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_FLIP_H: +- do_flip_h(srcinfo, dstinfo, src_coef_arrays); ++ if (info->y_crop_offset != 0) ++ do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); ++ else ++ do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, ++ src_coef_arrays); + break; + case JXFORM_FLIP_V: +- do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: +- do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: +- do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: +- do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: +- do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: +- do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); ++ do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, ++ src_coef_arrays, dst_coef_arrays); + break; + } + } + ++/* jtransform_perfect_transform ++ * ++ * Determine whether lossless transformation is perfectly ++ * possible for a specified image and transformation. ++ * ++ * Inputs: ++ * image_width, image_height: source image dimensions. ++ * MCU_width, MCU_height: pixel dimensions of MCU. ++ * transform: transformation identifier. ++ * Parameter sources from initialized jpeg_struct ++ * (after reading source header): ++ * image_width = cinfo.image_width ++ * image_height = cinfo.image_height ++ * MCU_width = cinfo.max_h_samp_factor * DCTSIZE ++ * MCU_height = cinfo.max_v_samp_factor * DCTSIZE ++ * Result: ++ * TRUE = perfect transformation possible ++ * FALSE = perfect transformation not possible ++ * (may use custom action then) ++ */ ++ ++GLOBAL(boolean) ++jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, ++ int MCU_width, int MCU_height, ++ JXFORM_CODE transform) ++{ ++ boolean result = TRUE; /* initialize TRUE */ ++ ++ switch (transform) { ++ case JXFORM_FLIP_H: ++ case JXFORM_ROT_270: ++ if (image_width % (JDIMENSION) MCU_width) ++ result = FALSE; ++ break; ++ case JXFORM_FLIP_V: ++ case JXFORM_ROT_90: ++ if (image_height % (JDIMENSION) MCU_height) ++ result = FALSE; ++ break; ++ case JXFORM_TRANSVERSE: ++ case JXFORM_ROT_180: ++ if (image_width % (JDIMENSION) MCU_width) ++ result = FALSE; ++ if (image_height % (JDIMENSION) MCU_height) ++ result = FALSE; ++ break; ++ } ++ ++ return result; ++} ++ + #endif /* TRANSFORMS_SUPPORTED */ + + diff --git a/graphics/jpeg/patches/patch-ac b/graphics/jpeg/patches/patch-ac new file mode 100644 index 00000000000..1a6ef79dcb5 --- /dev/null +++ b/graphics/jpeg/patches/patch-ac @@ -0,0 +1,12 @@ +$NetBSD: patch-ac,v 1.1 2007/06/05 22:07:26 tnn Exp $ + +--- jerror.h.orig 2007-06-05 22:37:04.000000000 +0200 ++++ jerror.h +@@ -45,6 +45,7 @@ JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYP + JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") + JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") + JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") ++JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") + JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") + JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") + JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") diff --git a/graphics/jpeg/patches/patch-ad b/graphics/jpeg/patches/patch-ad new file mode 100644 index 00000000000..fb3ba4f64af --- /dev/null +++ b/graphics/jpeg/patches/patch-ad @@ -0,0 +1,193 @@ +$NetBSD: patch-ad,v 1.1 2007/06/05 22:07:26 tnn Exp $ + +--- jpegtran.c.orig 2007-06-05 22:37:58.000000000 +0200 ++++ jpegtran.c +@@ -1,7 +1,7 @@ + /* + * jpegtran.c + * +- * Copyright (C) 1995-1997, Thomas G. Lane. ++ * Copyright (C) 1995-2001, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * +@@ -64,8 +64,10 @@ usage (void) + #endif + #if TRANSFORMS_SUPPORTED + fprintf(stderr, "Switches for modifying the image:\n"); ++ fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n"); + fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n"); + fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n"); ++ fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n"); + fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n"); + fprintf(stderr, " -transpose Transpose image\n"); + fprintf(stderr, " -transverse Transverse transpose image\n"); +@@ -133,7 +135,9 @@ parse_switches (j_compress_ptr cinfo, in + copyoption = JCOPYOPT_DEFAULT; + transformoption.transform = JXFORM_NONE; + transformoption.trim = FALSE; ++ transformoption.perfect = FALSE; + transformoption.force_grayscale = FALSE; ++ transformoption.crop = FALSE; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ +@@ -160,7 +164,7 @@ parse_switches (j_compress_ptr cinfo, in + exit(EXIT_FAILURE); + #endif + +- } else if (keymatch(arg, "copy", 1)) { ++ } else if (keymatch(arg, "copy", 2)) { + /* Select which extra markers to copy. */ + if (++argn >= argc) /* advance to next argument */ + usage(); +@@ -173,6 +177,20 @@ parse_switches (j_compress_ptr cinfo, in + } else + usage(); + ++ } else if (keymatch(arg, "crop", 2)) { ++ /* Perform lossless cropping. */ ++#if TRANSFORMS_SUPPORTED ++ if (++argn >= argc) /* advance to next argument */ ++ usage(); ++ if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) { ++ fprintf(stderr, "%s: bogus -crop argument '%s'\n", ++ progname, argv[argn]); ++ exit(EXIT_FAILURE); ++ } ++#else ++ select_transform(JXFORM_NONE); /* force an error */ ++#endif ++ + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ +@@ -233,7 +251,12 @@ parse_switches (j_compress_ptr cinfo, in + usage(); + outfilename = argv[argn]; /* save it away for later use */ + +- } else if (keymatch(arg, "progressive", 1)) { ++ } else if (keymatch(arg, "perfect", 2)) { ++ /* Fail if there is any partial edge MCUs that the transform can't ++ * handle. */ ++ transformoption.perfect = TRUE; ++ ++ } else if (keymatch(arg, "progressive", 2)) { + /* Select simple progressive mode. */ + #ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; +@@ -342,8 +365,10 @@ main (int argc, char **argv) + jvirt_barray_ptr * src_coef_arrays; + jvirt_barray_ptr * dst_coef_arrays; + int file_index; +- FILE * input_file; +- FILE * output_file; ++ /* We assume all-in-memory processing and can therefore use only a ++ * single file pointer for sequential input and output operation. ++ */ ++ FILE * fp; + + /* On Mac, fetch a command line. */ + #ifdef USE_CCOMMAND +@@ -406,24 +431,13 @@ main (int argc, char **argv) + + /* Open the input file. */ + if (file_index < argc) { +- if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { +- fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); ++ if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { ++ fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +- input_file = read_stdin(); +- } +- +- /* Open the output file. */ +- if (outfilename != NULL) { +- if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { +- fprintf(stderr, "%s: can't open %s\n", progname, outfilename); +- exit(EXIT_FAILURE); +- } +- } else { +- /* default output file is stdout */ +- output_file = write_stdout(); ++ fp = read_stdin(); + } + + #ifdef PROGRESS_REPORT +@@ -431,7 +445,7 @@ main (int argc, char **argv) + #endif + + /* Specify data source for decompression */ +- jpeg_stdio_src(&srcinfo, input_file); ++ jpeg_stdio_src(&srcinfo, fp); + + /* Enable saving of extra markers that we want to copy */ + jcopy_markers_setup(&srcinfo, copyoption); +@@ -443,6 +457,15 @@ main (int argc, char **argv) + * jpeg_read_coefficients so that memory allocation will be done right. + */ + #if TRANSFORMS_SUPPORTED ++ /* Fails right away if -perfect is given and transformation is not perfect. ++ */ ++ if (transformoption.perfect && ++ !jtransform_perfect_transform(srcinfo.image_width, srcinfo.image_height, ++ srcinfo.max_h_samp_factor * DCTSIZE, srcinfo.max_v_samp_factor * DCTSIZE, ++ transformoption.transform)) { ++ fprintf(stderr, "%s: transformation is not perfect\n", progname); ++ exit(EXIT_FAILURE); ++ } + jtransform_request_workspace(&srcinfo, &transformoption); + #endif + +@@ -463,11 +486,32 @@ main (int argc, char **argv) + dst_coef_arrays = src_coef_arrays; + #endif + ++ /* Close input file, if we opened it. ++ * Note: we assume that jpeg_read_coefficients consumed all input ++ * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will ++ * only consume more while (! cinfo->inputctl->eoi_reached). ++ * We cannot call jpeg_finish_decompress here since we still need the ++ * virtual arrays allocated from the source object for processing. ++ */ ++ if (fp != stdin) ++ fclose(fp); ++ ++ /* Open the output file. */ ++ if (outfilename != NULL) { ++ if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { ++ fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename); ++ exit(EXIT_FAILURE); ++ } ++ } else { ++ /* default output file is stdout */ ++ fp = write_stdout(); ++ } ++ + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ +- jpeg_stdio_dest(&dstinfo, output_file); ++ jpeg_stdio_dest(&dstinfo, fp); + + /* Start compressor (note no image data is actually written here) */ + jpeg_write_coefficients(&dstinfo, dst_coef_arrays); +@@ -488,11 +532,9 @@ main (int argc, char **argv) + (void) jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + +- /* Close files, if we opened them */ +- if (input_file != stdin) +- fclose(input_file); +- if (output_file != stdout) +- fclose(output_file); ++ /* Close output file, if we opened it */ ++ if (fp != stdout) ++ fclose(fp); + + #ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &dstinfo); diff --git a/graphics/jpeg/patches/patch-ae b/graphics/jpeg/patches/patch-ae new file mode 100644 index 00000000000..f2f047ed06a --- /dev/null +++ b/graphics/jpeg/patches/patch-ae @@ -0,0 +1,182 @@ +$NetBSD: patch-ae,v 1.1 2007/06/05 22:07:26 tnn Exp $ + +--- transupp.h.orig 2007-06-05 22:46:42.000000000 +0200 ++++ transupp.h +@@ -1,7 +1,7 @@ + /* + * transupp.h + * +- * Copyright (C) 1997, Thomas G. Lane. ++ * Copyright (C) 1997-2001, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * +@@ -22,32 +22,6 @@ + #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ + #endif + +-/* Short forms of external names for systems with brain-damaged linkers. */ +- +-#ifdef NEED_SHORT_EXTERNAL_NAMES +-#define jtransform_request_workspace jTrRequest +-#define jtransform_adjust_parameters jTrAdjust +-#define jtransform_execute_transformation jTrExec +-#define jcopy_markers_setup jCMrkSetup +-#define jcopy_markers_execute jCMrkExec +-#endif /* NEED_SHORT_EXTERNAL_NAMES */ +- +- +-/* +- * Codes for supported types of image transformations. +- */ +- +-typedef enum { +- JXFORM_NONE, /* no transformation */ +- JXFORM_FLIP_H, /* horizontal flip */ +- JXFORM_FLIP_V, /* vertical flip */ +- JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ +- JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ +- JXFORM_ROT_90, /* 90-degree clockwise rotation */ +- JXFORM_ROT_180, /* 180-degree rotation */ +- JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +-} JXFORM_CODE; +- + /* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images +@@ -75,6 +49,19 @@ typedef enum { + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * ++ * We also offer a lossless-crop option, which discards data outside a given ++ * image region but losslessly preserves what is inside. Like the rotate and ++ * flip transforms, lossless crop is restricted by the JPEG format: the upper ++ * left corner of the selected region must fall on an iMCU boundary. If this ++ * does not hold for the given crop parameters, we silently move the upper left ++ * corner up and/or left to make it so, simultaneously increasing the region ++ * dimensions to keep the lower right crop corner unchanged. (Thus, the ++ * output image covers at least the requested region, but may cover more.) ++ * ++ * If both crop and a rotate/flip transform are requested, the crop is applied ++ * last --- that is, the crop region is specified in terms of the destination ++ * image. ++ * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of +@@ -83,20 +70,89 @@ typedef enum { + * be aware of the option to know how many components to work on. + */ + ++ ++/* Short forms of external names for systems with brain-damaged linkers. */ ++ ++#ifdef NEED_SHORT_EXTERNAL_NAMES ++#define jtransform_parse_crop_spec jTrParCrop ++#define jtransform_request_workspace jTrRequest ++#define jtransform_adjust_parameters jTrAdjust ++#define jtransform_execute_transform jTrExec ++#define jtransform_perfect_transform jTrPerfect ++#define jcopy_markers_setup jCMrkSetup ++#define jcopy_markers_execute jCMrkExec ++#endif /* NEED_SHORT_EXTERNAL_NAMES */ ++ ++ ++/* ++ * Codes for supported types of image transformations. ++ */ ++ ++typedef enum { ++ JXFORM_NONE, /* no transformation */ ++ JXFORM_FLIP_H, /* horizontal flip */ ++ JXFORM_FLIP_V, /* vertical flip */ ++ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ ++ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ ++ JXFORM_ROT_90, /* 90-degree clockwise rotation */ ++ JXFORM_ROT_180, /* 180-degree rotation */ ++ JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ ++} JXFORM_CODE; ++ ++/* ++ * Codes for crop parameters, which can individually be unspecified, ++ * positive, or negative. (Negative width or height makes no sense, though.) ++ */ ++ ++typedef enum { ++ JCROP_UNSET, ++ JCROP_POS, ++ JCROP_NEG ++} JCROP_CODE; ++ ++/* ++ * Transform parameters struct. ++ * NB: application must not change any elements of this struct after ++ * calling jtransform_request_workspace. ++ */ ++ + typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ ++ boolean perfect; /* if TRUE, fail if partial MCUs are requested */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ ++ boolean crop; /* if TRUE, crop source image */ ++ ++ /* Crop parameters: application need not set these unless crop is TRUE. ++ * These can be filled in by jtransform_parse_crop_spec(). ++ */ ++ JDIMENSION crop_width; /* Width of selected region */ ++ JCROP_CODE crop_width_set; ++ JDIMENSION crop_height; /* Height of selected region */ ++ JCROP_CODE crop_height_set; ++ JDIMENSION crop_xoffset; /* X offset of selected region */ ++ JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ ++ JDIMENSION crop_yoffset; /* Y offset of selected region */ ++ JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ ++ JDIMENSION output_width; /* cropped destination dimensions */ ++ JDIMENSION output_height; ++ JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ ++ JDIMENSION y_crop_offset; ++ int max_h_samp_factor; /* destination iMCU size */ ++ int max_v_samp_factor; + } jpeg_transform_info; + + + #if TRANSFORMS_SUPPORTED + ++/* Parse a crop specification (written in X11 geometry style) */ ++EXTERN(boolean) jtransform_parse_crop_spec ++ JPP((jpeg_transform_info *info, const char *spec)); + /* Request any required workspace */ + EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +@@ -106,10 +162,24 @@ EXTERN(jvirt_barray_ptr *) jtransform_ad + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + /* Execute the actual transformation, if any */ +-EXTERN(void) jtransform_execute_transformation ++EXTERN(void) jtransform_execute_transform + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); ++/* Determine whether lossless transformation is perfectly ++ * possible for a specified image and transformation. ++ */ ++EXTERN(boolean) jtransform_perfect_transform ++ JPP((JDIMENSION image_width, JDIMENSION image_height, ++ int MCU_width, int MCU_height, ++ JXFORM_CODE transform)); ++ ++/* jtransform_execute_transform used to be called ++ * jtransform_execute_transformation, but some compilers complain about ++ * routine names that long. This macro is here to avoid breaking any ++ * old source code that uses the original name... ++ */ ++#define jtransform_execute_transformation jtransform_execute_transform + + #endif /* TRANSFORMS_SUPPORTED */ + diff --git a/graphics/jpeg/patches/patch-af b/graphics/jpeg/patches/patch-af new file mode 100644 index 00000000000..c58f5ccf085 --- /dev/null +++ b/graphics/jpeg/patches/patch-af @@ -0,0 +1,52 @@ +$NetBSD: patch-af,v 1.1 2007/06/05 22:07:26 tnn Exp $ + +--- makefile.cfg.orig 2007-06-05 23:27:21.000000000 +0200 ++++ makefile.cfg +@@ -86,7 +86,7 @@ SYSDEPSOURCES= jmemansi.c jmemname.c jme + # source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom + APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ +- rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c ++ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c jpegexiforient.c + SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) + # files included by source files + INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ +@@ -133,7 +133,7 @@ DOBJECTS= djpeg.$(O) wrppm.$(O) wrgif.$( + TROBJECTS= jpegtran.$(O) rdswitch.$(O) cdjpeg.$(O) transupp.$(O) + + +-all: @A2K_DEPS@ libjpeg.$(A) cjpeg djpeg jpegtran rdjpgcom wrjpgcom ++all: @A2K_DEPS@ libjpeg.$(A) cjpeg djpeg jpegtran rdjpgcom wrjpgcom jpegexiforient + + # Special compilation rules to support ansi2knr and libtool. + .SUFFIXES: .lo .la +@@ -179,6 +179,9 @@ cjpeg: $(COBJECTS) libjpeg.$(A) + djpeg: $(DOBJECTS) libjpeg.$(A) + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.$(A) $(LDLIBS) + ++jpegexiforient: jpegexiforient.$(O) ++ $(LN) $(LDFLAGS) -o jpegexiforient jpegexiforient.$(O) $(LDLIBS) ++ + jpegtran: $(TROBJECTS) libjpeg.$(A) + $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.$(A) $(LDLIBS) + +@@ -190,9 +193,10 @@ wrjpgcom: wrjpgcom.$(O) + + # Installation rules: + +-install: cjpeg djpeg jpegtran rdjpgcom wrjpgcom @FORCE_INSTALL_LIB@ ++install: cjpeg djpeg jpegtran rdjpgcom wrjpgcom jpegexiforient @FORCE_INSTALL_LIB@ + $(INSTALL_PROGRAM) cjpeg $(bindir)/$(binprefix)cjpeg + $(INSTALL_PROGRAM) djpeg $(bindir)/$(binprefix)djpeg ++ $(INSTALL_PROGRAM) jpegexiforient $(bindir)/$(binprefix)jpegexiforient + $(INSTALL_PROGRAM) jpegtran $(bindir)/$(binprefix)jpegtran + $(INSTALL_PROGRAM) rdjpgcom $(bindir)/$(binprefix)rdjpgcom + $(INSTALL_PROGRAM) wrjpgcom $(bindir)/$(binprefix)wrjpgcom +@@ -300,6 +304,7 @@ jmemdos.$(O): jmemdos.c jinclude.h jconf + jmemmac.$(O): jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h + cjpeg.$(O): cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h + djpeg.$(O): djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h ++jpegexiforient.$(O): jpegexiforient.c + jpegtran.$(O): jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h + rdjpgcom.$(O): rdjpgcom.c jinclude.h jconfig.h + wrjpgcom.$(O): wrjpgcom.c jinclude.h jconfig.h |