summaryrefslogtreecommitdiff
path: root/graphics/jpeg
diff options
context:
space:
mode:
authorDirk Meyer <dinoex@FreeBSD.org>2004-03-18 14:53:47 +0000
committerDirk Meyer <dinoex@FreeBSD.org>2004-03-18 14:53:47 +0000
commit7a318b355a4c52d62ee6070475839a2eb7bb9d98 (patch)
treea9079928dc93bc9bc303b756fc34276b012bfc80 /graphics/jpeg
parent- Remove dead WWW (diff)
- Patches from
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=106060 , http://sylvana.net/jpegcrop/exifpatch.html Which add EXIF support to jpegtran (lossless JPEG transforms) and to rdjpgcom to add reporting of EXIF orientation in verbose mode. - Tools from http://sylvana.net/jpegcrop/exif_orientation.html which allow automatic JPEG orientation using the EXIF tag from the camera. (I think it should be done with DISTFILES rather than with PATCH_SITES, though). Roman Shterenzon (some cleanup done)
Diffstat (limited to 'graphics/jpeg')
-rw-r--r--graphics/jpeg/Makefile17
-rw-r--r--graphics/jpeg/distinfo4
-rw-r--r--graphics/jpeg/files/patch-ae18
-rw-r--r--graphics/jpeg/files/patch-configure (renamed from graphics/jpeg/files/patch-ab)0
-rw-r--r--graphics/jpeg/files/patch-djpeg.c (renamed from graphics/jpeg/files/patch-ad)0
-rw-r--r--graphics/jpeg/files/patch-exifautotran7
-rw-r--r--graphics/jpeg/files/patch-jpegtran.144
-rw-r--r--graphics/jpeg/files/patch-jpegtran.c99
-rw-r--r--graphics/jpeg/files/patch-rdjpgcom.c218
-rw-r--r--graphics/jpeg/files/patch-transupp.c284
-rw-r--r--graphics/jpeg/files/patch-transupp.h12
-rw-r--r--graphics/jpeg/pkg-descr7
-rw-r--r--graphics/jpeg/pkg-plist2
13 files changed, 689 insertions, 23 deletions
diff --git a/graphics/jpeg/Makefile b/graphics/jpeg/Makefile
index 0798e25df3ad..adedafc4f985 100644
--- a/graphics/jpeg/Makefile
+++ b/graphics/jpeg/Makefile
@@ -9,11 +9,15 @@
PORTNAME= jpeg
PORTVERSION= 6b
-PORTREVISION= 1
+PORTREVISION= 2
CATEGORIES= graphics
MASTER_SITES= http://www.ijg.org/files/ \
- ftp://ftp.uu.net/graphics/jpeg/
+ ftp://ftp.uu.net/graphics/jpeg/ \
+ http://sylvana.net/jpegcrop/:exif
DISTNAME= jpegsrc.v${PORTVERSION}
+DISTFILES= ${DISTNAME}${EXTRACT_SUFX} \
+ jpegexiforient.c:exif exifautotran.txt:exif
+EXTRACT_ONLY= ${DISTNAME}${EXTRACT_SUFX}
MAINTAINER= dinoex@FreeBSD.org
COMMENT= IJG's jpeg compression utilities
@@ -33,6 +37,13 @@ CONFIGURE_ARGS+= --enable-maxmem=${J_MAXMEM}
MAN1= cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
+post-extract:
+ @${CP} ${DISTDIR}/jpegexiforient.c ${WRKSRC}/
+ @${CP} ${DISTDIR}/exifautotran.txt ${WRKSRC}/exifautotran
+
+post-build:
+ @cd ${WRKSRC} && ${CC} ${CFLAGS} -o jpegexiforient jpegexiforient.c
+
post-install:
.if !defined(NOPORTDOCS)
@${MKDIR} ${PREFIX}/share/doc/jpeg
@@ -42,5 +53,7 @@ post-install:
.for header in ${ADDITIONAL_HEADER}
@${INSTALL_DATA} ${WRKSRC}/${header} ${PREFIX}/include
.endfor
+ ${INSTALL_PROGRAM} ${WRKSRC}/jpegexiforient ${PREFIX}/bin
+ ${INSTALL_SCRIPT} ${WRKSRC}/exifautotran ${PREFIX}/bin
.include <bsd.port.mk>
diff --git a/graphics/jpeg/distinfo b/graphics/jpeg/distinfo
index 1f693afe0442..eed8f6cd7739 100644
--- a/graphics/jpeg/distinfo
+++ b/graphics/jpeg/distinfo
@@ -1,2 +1,6 @@
MD5 (jpegsrc.v6b.tar.gz) = dbd5f3b47ed13132f04c685d608a7547
SIZE (jpegsrc.v6b.tar.gz) = 613261
+MD5 (jpegexiforient.c) = ff4657764cb885b9aec06449507bf29d
+SIZE (jpegexiforient.c) = 8192
+MD5 (exifautotran.txt) = c1cd9c876f900601682cf9db8d232386
+SIZE (exifautotran.txt) = 684
diff --git a/graphics/jpeg/files/patch-ae b/graphics/jpeg/files/patch-ae
deleted file mode 100644
index 5004e6cd3040..000000000000
--- a/graphics/jpeg/files/patch-ae
+++ /dev/null
@@ -1,18 +0,0 @@
---- rdjpgcom.c.orig Sat Oct 11 18:41:04 1997
-+++ rdjpgcom.c Mon Apr 24 16:04:13 2000
-@@ -14,6 +14,7 @@
- #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
- #include "jinclude.h" /* get auto-config symbols, <stdio.h> */
-
-+#include <locale.h> /* to declare setlocale() */
- #include <ctype.h> /* to declare isupper(), tolower() */
- #ifdef USE_SETMODE
- #include <fcntl.h> /* to declare setmode()'s parameter macros */
-@@ -231,6 +232,7 @@
- ERREXIT("Erroneous JPEG marker length");
- length -= 2;
-
-+ setlocale(LC_ALL, "");
- while (length > 0) {
- ch = read_1_byte();
- /* Emit the character in a readable form.
diff --git a/graphics/jpeg/files/patch-ab b/graphics/jpeg/files/patch-configure
index 85392d80c6ae..85392d80c6ae 100644
--- a/graphics/jpeg/files/patch-ab
+++ b/graphics/jpeg/files/patch-configure
diff --git a/graphics/jpeg/files/patch-ad b/graphics/jpeg/files/patch-djpeg.c
index 224fefe2e850..224fefe2e850 100644
--- a/graphics/jpeg/files/patch-ad
+++ b/graphics/jpeg/files/patch-djpeg.c
diff --git a/graphics/jpeg/files/patch-exifautotran b/graphics/jpeg/files/patch-exifautotran
new file mode 100644
index 000000000000..418f618019ba
--- /dev/null
+++ b/graphics/jpeg/files/patch-exifautotran
@@ -0,0 +1,7 @@
+--- exifautotran.orig Thu Mar 18 06:25:27 2004
++++ exifautotran Thu Mar 18 06:28:29 2004
+@@ -1,3 +1,4 @@
++#!/bin/sh
+ # exifautotran [list of files]
+ #
+ # Transforms Exif files so that Orientation becomes 1
diff --git a/graphics/jpeg/files/patch-jpegtran.1 b/graphics/jpeg/files/patch-jpegtran.1
new file mode 100644
index 000000000000..fe4eb1372f4d
--- /dev/null
+++ b/graphics/jpeg/files/patch-jpegtran.1
@@ -0,0 +1,44 @@
+--- jpegtran.1.exif 1997-08-03 22:01:01.000000000 +0200
++++ jpegtran.1 2003-09-30 14:35:36.000000000 +0200
+@@ -161,6 +161,14 @@
+ Copy all extra markers. This setting preserves miscellaneous markers
+ found in the source file, such as JFIF thumbnails and Photoshop settings.
+ In some files these extra markers can be sizable.
++See 'EXIF FILES' for special tratement of EXIF markers.
++.TP
++.B \-copy exif
++This setting preserves the EXIF marker, commonly found in JPEG files produced
++by digital cameras, in addition to any comment markers. If there is an EXIF
++marker it is copied and the JFIF marker (incompatible with EXIF) is
++omitted. If there is no EXIF marker a JFIF one is emitted as usual. See 'EXIF
++FILES' for special tratement of EXIF markers.
+ .PP
+ The default behavior is
+ .BR "\-copy comments" .
+@@ -189,6 +197,26 @@
+ .B \-debug
+ Same as
+ .BR \-verbose .
++.SH EXIF FILES
++The EXIF variety of JPEG files, which are often produced by digital cameras,
++are recognized by jpegtran as EXIF files (i.e. not as JFIF, the
++usual variety of JPEG files). If the input file is recognized as EXIF (i.e.,
++there is an EXIF marker and no JFIF marker) the '-copy exif' option is
++automatically turned on if '-copy comments', or no '-copy' option, was
++specified. Thus, unless '-copy none' is specified an EXIF file is kept as EXIF
++and not converted to JFIF.
++.PP
++If a geometrical transformation is applied (e.g., rotate, transpose) the EXIF
++width and height fields are set to the width and height of the output
++image. Furthermore, the orientation field is reset to one, meaning tha the
++orientation of the output image is upright (i.e. normal).
++.PP
++Note that an explicitely given '-copy exif' option will output an EXIF file if
++the input is an EXIF file that was saved as JFIF, and that the EXIF marker is
++still present. This option is useful for recovering EXIF files that where
++converted to JFIF by a non EXIF-aware software. Note however, that the data in
++the EXIF marker is not validated, unless a geometrical transformation is
++applied.
+ .SH EXAMPLES
+ .LP
+ This example converts a baseline JPEG file to progressive form:
diff --git a/graphics/jpeg/files/patch-jpegtran.c b/graphics/jpeg/files/patch-jpegtran.c
new file mode 100644
index 000000000000..429d1099e56d
--- /dev/null
+++ b/graphics/jpeg/files/patch-jpegtran.c
@@ -0,0 +1,99 @@
+--- jpegtran.c.exif 1997-07-24 04:37:26.000000000 +0200
++++ jpegtran.c 2003-09-29 22:31:22.000000000 +0200
+@@ -56,6 +56,7 @@
+ fprintf(stderr, " -copy none Copy no extra markers from source file\n");
+ fprintf(stderr, " -copy comments Copy only comment markers (default)\n");
+ fprintf(stderr, " -copy all Copy all extra markers\n");
++ fprintf(stderr, " -copy exif Copy EXIF marker and omit JFIF if EXIF\n");
+ #ifdef ENTROPY_OPT_SUPPORTED
+ fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
+ #endif
+@@ -109,6 +110,50 @@
+ #endif
+ }
+
++LOCAL(void)
++handle_exif (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
++ JCOPY_OPTION *copyoption)
++/* Adjust the marker writing options to create an EXIF file, instead of JFIF,
++ * if so requested or an EXIF file is detected as input. Must be called after
++ * jpeg_copy_critical_parameters() as that sets the defaults. */
++{
++ jpeg_saved_marker_ptr cur_marker, prev_marker;
++
++ /* Look for an exif marker */
++ prev_marker = NULL;
++ cur_marker = srcinfo->marker_list;
++ while (cur_marker != NULL) {
++ if (cur_marker->marker == JPEG_APP0+1 &&
++ cur_marker->data_length >= 6 &&
++ GETJOCTET(cur_marker->data[0]) == 0x45 &&
++ GETJOCTET(cur_marker->data[1]) == 0x78 &&
++ GETJOCTET(cur_marker->data[2]) == 0x69 &&
++ GETJOCTET(cur_marker->data[3]) == 0x66 &&
++ GETJOCTET(cur_marker->data[4]) == 0 &&
++ GETJOCTET(cur_marker->data[5]) == 0)
++ break; /* found an EXIF marker */
++ prev_marker = cur_marker;
++ cur_marker = cur_marker->next;
++ }
++ /* If we've found an EXIF marker but not JFIF this is an EXIF file. Unless
++ * explicitely requested, make sure we keep the EXIF marker and do not
++ * emit a JFIF marker (which would come before). EXIF requires that the
++ * first marker be EXIF. */
++ if (cur_marker != NULL &&
++ ((*copyoption != JCOPYOPT_NONE && !srcinfo->saw_JFIF_marker) ||
++ (*copyoption == JCOPYOPT_EXIF))) {
++ dstinfo->write_JFIF_header = FALSE;
++ if (*copyoption == JCOPYOPT_COMMENTS)
++ *copyoption = JCOPYOPT_EXIF;
++ }
++ /* If making an EXIF file, make sure that EXIF is first marker */
++ if (cur_marker != NULL && prev_marker != NULL &&
++ *copyoption == JCOPYOPT_EXIF) {
++ prev_marker->next = cur_marker->next;
++ cur_marker->next = srcinfo->marker_list;
++ srcinfo->marker_list = cur_marker;
++ }
++}
+
+ LOCAL(int)
+ parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+@@ -170,6 +215,8 @@
+ copyoption = JCOPYOPT_COMMENTS;
+ } else if (keymatch(argv[argn], "all", 1)) {
+ copyoption = JCOPYOPT_ALL;
++ } else if (keymatch(argv[argn], "exif", 1)) {
++ copyoption = JCOPYOPT_EXIF;
+ } else
+ usage();
+
+@@ -181,6 +228,7 @@
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
++ fprintf(stderr, "EXIF support v 0.1 added 29-Sep-2003\n");
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+@@ -452,6 +500,7 @@
+ /* Initialize destination compression parameters from source values */
+ jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
+
++
+ /* Adjust destination parameters if required by transform options;
+ * also find out which set of coefficient arrays will hold the output.
+ */
+@@ -464,8 +513,12 @@
+ #endif
+
+ /* Adjust default compression parameters by re-parsing the options */
++ /* Save value of copyoption */
+ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
+
++ /* If we want EXIF, make sure we do not write incompatible markers */
++ handle_exif(&srcinfo,&dstinfo,&copyoption);
++
+ /* Specify data destination for compression */
+ jpeg_stdio_dest(&dstinfo, output_file);
+
diff --git a/graphics/jpeg/files/patch-rdjpgcom.c b/graphics/jpeg/files/patch-rdjpgcom.c
new file mode 100644
index 000000000000..db6bd23c249f
--- /dev/null
+++ b/graphics/jpeg/files/patch-rdjpgcom.c
@@ -0,0 +1,218 @@
+--- rdjpgcom.c.orig Sun Oct 12 00:41:04 1997
++++ rdjpgcom.c Thu Mar 18 06:37:23 2004
+@@ -14,6 +14,7 @@
+ #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
+ #include "jinclude.h" /* get auto-config symbols, <stdio.h> */
+
++#include <locale.h> /* to declare setlocale() */
+ #include <ctype.h> /* to declare isupper(), tolower() */
+ #ifdef USE_SETMODE
+ #include <fcntl.h> /* to declare setmode()'s parameter macros */
+@@ -120,6 +121,7 @@
+ #define M_EOI 0xD9 /* End Of Image (end of datastream) */
+ #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
+ #define M_APP0 0xE0 /* Application-specific marker, type N */
++#define M_APP1 0xE1 /* Typically EXIF marker */
+ #define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */
+ #define M_COM 0xFE /* COMment */
+
+@@ -210,6 +212,175 @@
+ }
+ }
+
++/*
++ * Helper routine to skip the given number of bytes.
++ */
++
++static void
++skip_n (unsigned int length)
++{
++ while (length > 0) {
++ (void) read_1_byte();
++ length--;
++ }
++}
++
++/*
++ * Parses an APP1 marker looking for EXIF data. If EXIF, the orientation is
++ * reported to stdout.
++ */
++
++static void
++process_APP1 (void)
++{
++ unsigned int length, i;
++ int is_motorola; /* byte order indicator */
++ unsigned int offset, number_of_tags, tagnum;
++ int orientation;
++ char *ostr;
++ /* This 64K buffer would probably be best if allocated dynamically, but it's
++ * the only one on this program so it's really not that
++ * important. Allocating on the stack is not an option, as 64K might be too
++ * big for some (crippled) platforms. */
++ static unsigned char exif_data[65536L];
++
++ /* Get the marker parameter length count */
++ length = read_2_bytes();
++ /* Length includes itself, so must be at least 2 */
++ if (length < 2)
++ ERREXIT("Erroneous JPEG marker length");
++ length -= 2;
++
++ /* We only care if APP1 is really an EXIF marker. Minimum length is 6 for
++ * signature plus 12 for an IFD. */
++ if (length < 18) {
++ skip_n(length);
++ return;
++ }
++
++ /* Check for actual EXIF marker */
++ for (i=0; i < 6; i++)
++ exif_data[i] = (unsigned char) read_1_byte();
++ length -= 6;
++ 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) {
++ skip_n(length);
++ return;
++ }
++
++ /* Read all EXIF body */
++ for (i=0; i < length; i++)
++ exif_data[i] = (unsigned char) read_1_byte();
++
++ /* 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;
++
++ /* Check Tag Mark */
++ if (is_motorola) {
++ if (exif_data[2] != 0) return;
++ if (exif_data[3] != 0x2A) return;
++ } else {
++ if (exif_data[3] != 0) return;
++ if (exif_data[2] != 0x2A) return;
++ }
++
++ /* Get first IFD offset (offset to IFD0) */
++ if (is_motorola) {
++ if (exif_data[4] != 0) return;
++ if (exif_data[5] != 0) return;
++ offset = exif_data[6];
++ offset <<= 8;
++ offset += exif_data[7];
++ } else {
++ if (exif_data[7] != 0) return;
++ if (exif_data[6] != 0) return;
++ offset = exif_data[5];
++ offset <<= 8;
++ offset += exif_data[4];
++ }
++ if (offset > length - 2) return; /* 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;
++ offset += 2;
++
++ /* Search for Orientation Tag in IFD0 */
++ for (;;) {
++ if (offset > length - 12) return; /* 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;
++ offset += 12;
++ }
++
++ /* Get the Orientation value */
++ if (is_motorola) {
++ if (exif_data[offset+8] != 0) return;
++ orientation = exif_data[offset+9];
++ } else {
++ if (exif_data[offset+9] != 0) return;
++ orientation = exif_data[offset+8];
++ }
++ if (orientation == 0 || orientation > 8) return;
++
++ /* Print the orientation (position of the 0th row - 0th column) */
++ switch (orientation) {
++ case 1:
++ ostr = "top-left";
++ break;
++ case 2:
++ ostr = "top-right";
++ break;
++ case 3:
++ ostr = "bottom-right";
++ break;
++ case 4:
++ ostr = "bottom-left";
++ break;
++ case 5:
++ ostr = "left-top";
++ break;
++ case 6:
++ ostr = "right-top";
++ break;
++ case 7:
++ ostr = "right-bottom";
++ break;
++ case 8:
++ ostr = "left-bottom";
++ break;
++ default:
++ return;
++ }
++ printf("EXIF orientation: %s\n",ostr);
++}
+
+ /*
+ * Process a COM marker.
+@@ -231,6 +402,7 @@
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+
++ setlocale(LC_ALL, "");
+ while (length > 0) {
+ ch = read_1_byte();
+ /* Emit the character in a readable form.
+@@ -363,6 +535,15 @@
+
+ case M_COM:
+ process_COM();
++ break;
++
++ case M_APP1:
++ /* APP1 is usually the EXIF marker used by digital cameras, attempt to
++ * process it to give some useful info. */
++ if (verbose) {
++ process_APP1();
++ } else
++ skip_variable();
+ break;
+
+ case M_APP12:
diff --git a/graphics/jpeg/files/patch-transupp.c b/graphics/jpeg/files/patch-transupp.c
new file mode 100644
index 000000000000..48927aa80bc0
--- /dev/null
+++ b/graphics/jpeg/files/patch-transupp.c
@@ -0,0 +1,284 @@
+--- transupp.c.exif 1997-08-10 02:15:26.000000000 +0200
++++ transupp.c 2003-09-29 22:28:42.000000000 +0200
+@@ -717,6 +717,194 @@
+ }
+
+
++/* Adjust Exif image parameters.
++ *
++ * We try to adjust the Tags ExifImageWidth, ExifImageHeight and
++ * ExifOrientation if possible. If the given new_* value is zero the
++ * corresponding tag is not adjusted.
++ */
++
++LOCAL(void)
++adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
++ JDIMENSION new_width, JDIMENSION new_height,
++ unsigned int new_orient)
++{
++ boolean is_motorola; /* Flag for byte order */
++ unsigned int number_of_tags, tagnum;
++ unsigned int firstoffset, offset, exifsuboffset;
++ 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;
++ }
++
++ /* 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]);
++ }
++ if (firstoffset > length - 2) return; /* check end of data segment */
++
++ /* 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;
++
++ /* Search for ExifSubIFD offset and ExifOrient Tag in IFD0 */
++ exifsuboffset = 0;
++ for (;;) {
++ if (firstoffset > length - 12) break; /* 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 == 0x0112 && new_orient > 0) { /* found ExifOrientation */
++ if (is_motorola) {
++ data[firstoffset+2] = 0; /* Format = unsigned short (2 octets) */
++ data[firstoffset+3] = 3;
++ data[firstoffset+4] = 0; /* Number Of Components = 1 */
++ data[firstoffset+5] = 0;
++ data[firstoffset+6] = 0;
++ data[firstoffset+7] = 1;
++ data[firstoffset+8] = 0;
++ data[firstoffset+9] = (JOCTET)new_orient;
++ data[firstoffset+10] = 0;
++ data[firstoffset+11] = 0;
++ } else {
++ data[firstoffset+2] = 3; /* Format = unsigned short (2 octets) */
++ data[firstoffset+3] = 0;
++ data[firstoffset+4] = 1; /* Number Of Components = 1 */
++ data[firstoffset+5] = 0;
++ data[firstoffset+6] = 0;
++ data[firstoffset+7] = 0;
++ data[firstoffset+8] = (JOCTET)new_orient;
++ data[firstoffset+9] = 0;
++ data[firstoffset+10] = 0;
++ data[firstoffset+11] = 0;
++ }
++ } else if (tagnum == 0x8769) {
++ exifsuboffset = firstoffset; /* found ExifSubIFD offset Tag */
++ }
++ if (--number_of_tags == 0) break;
++ firstoffset += 12;
++ }
++ if (exifsuboffset == 0) return;
++
++ /* Get the ExifSubIFD offset */
++ if (is_motorola) {
++ if (GETJOCTET(data[exifsuboffset+8]) != 0) return;
++ if (GETJOCTET(data[exifsuboffset+9]) != 0) return;
++ offset = GETJOCTET(data[exifsuboffset+10]);
++ offset <<= 8;
++ offset += GETJOCTET(data[exifsuboffset+11]);
++ } else {
++ if (GETJOCTET(data[exifsuboffset+11]) != 0) return;
++ if (GETJOCTET(data[exifsuboffset+10]) != 0) return;
++ offset = GETJOCTET(data[exifsuboffset+9]);
++ offset <<= 8;
++ offset += GETJOCTET(data[exifsuboffset+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 && new_width > 0) ||
++ (tagnum == 0xA003 && new_height > 0)) {
++ 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);
++}
++
++
+ /* Adjust output image parameters as needed.
+ *
+ * This must be called after jpeg_copy_critical_parameters()
+@@ -734,6 +922,8 @@
+ jvirt_barray_ptr *src_coef_arrays,
+ jpeg_transform_info *info)
+ {
++ jpeg_saved_marker_ptr cur_marker; /* ptr to walk the marker list */
++
+ /* 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
+@@ -799,6 +989,28 @@
+ break;
+ }
+
++ /* Adjust Exif properties. Exif requires its APP marker to be the first
++ * one, but we allow other locations for mixed JFIF/Exif files. */
++ cur_marker = srcinfo->marker_list;
++ while (cur_marker != NULL) {
++ if (cur_marker->marker == JPEG_APP0+1 &&
++ cur_marker->data_length >= 6 &&
++ GETJOCTET(cur_marker->data[0]) == 0x45 &&
++ GETJOCTET(cur_marker->data[1]) == 0x78 &&
++ GETJOCTET(cur_marker->data[2]) == 0x69 &&
++ GETJOCTET(cur_marker->data[3]) == 0x66 &&
++ GETJOCTET(cur_marker->data[4]) == 0 &&
++ GETJOCTET(cur_marker->data[5]) == 0) {
++ /* Adjust Exif image parameters */
++ if (info->transform != JXFORM_NONE)
++ /* Align data segment to start of TIFF structure for parsing */
++ adjust_exif_parameters(cur_marker->data + 6,
++ cur_marker->data_length - 6,
++ dstinfo->image_width, dstinfo->image_height, 1);
++ }
++ cur_marker = cur_marker->next;
++ }
++
+ /* Return the appropriate output data set */
+ if (info->workspace_coef_arrays != NULL)
+ return info->workspace_coef_arrays;
+@@ -854,6 +1066,8 @@
+
+
+ /* Setup decompression object to save desired markers in memory.
++ * Unless JCOPYOPT_NONE is given, the COM and potential EXIF markers (APP1)
++ * are always saved.
+ * This must be called before jpeg_read_header() to have the desired effect.
+ */
+
+@@ -871,6 +1085,8 @@
+ if (option == JCOPYOPT_ALL) {
+ for (m = 0; m < 16; m++)
+ jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
++ } else if (option != JCOPYOPT_NONE) {
++ jpeg_save_markers(srcinfo, JPEG_APP0 + 1, 0xFFFF);
+ }
+ #endif /* SAVE_MARKERS_SUPPORTED */
+ }
+@@ -888,12 +1104,27 @@
+ {
+ jpeg_saved_marker_ptr marker;
+
+- /* In the current implementation, we don't actually need to examine the
+- * option flag here; we just copy everything that got saved.
+- * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
++ /* NOTE: to avoid confusion, we do not output JFIF and Adobe APP14 markers
+ * if the encoder library already wrote one.
+ */
++ if (option == JCOPYOPT_NONE) return;
+ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
++ if (option == JCOPYOPT_COMMENTS &&
++ marker->marker != JPEG_COM) {
++ continue; /* only COM accpeted if JCOPYOPT_COMMENTS */
++ }
++ if (option == JCOPYOPT_EXIF &&
++ marker->marker != JPEG_COM &&
++ !(marker->marker == JPEG_APP0+1 &&
++ marker->data_length >= 6 &&
++ GETJOCTET(marker->data[0]) == 0x45 &&
++ GETJOCTET(marker->data[1]) == 0x78 &&
++ GETJOCTET(marker->data[2]) == 0x69 &&
++ GETJOCTET(marker->data[3]) == 0x66 &&
++ GETJOCTET(marker->data[4]) == 0 &&
++ GETJOCTET(marker->data[5]) == 0)) {
++ continue; /* only COM and APP1-EXIF if JCOPYOPT_EXIF */
++ }
+ if (dstinfo->write_JFIF_header &&
+ marker->marker == JPEG_APP0 &&
+ marker->data_length >= 5 &&
diff --git a/graphics/jpeg/files/patch-transupp.h b/graphics/jpeg/files/patch-transupp.h
new file mode 100644
index 000000000000..f295b2803445
--- /dev/null
+++ b/graphics/jpeg/files/patch-transupp.h
@@ -0,0 +1,12 @@
+--- transupp.h.exif 1997-07-24 04:39:12.000000000 +0200
++++ transupp.h 2003-09-25 01:05:12.000000000 +0200
+@@ -121,7 +121,8 @@
+ typedef enum {
+ JCOPYOPT_NONE, /* copy no optional markers */
+ JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */
+- JCOPYOPT_ALL /* copy all optional markers */
++ JCOPYOPT_ALL, /* copy all optional markers */
++ JCOPYOPT_EXIF /* copy Exif APP1 marker */
+ } JCOPY_OPTION;
+
+ #define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */
diff --git a/graphics/jpeg/pkg-descr b/graphics/jpeg/pkg-descr
index af22241e014c..0fbedacc7a97 100644
--- a/graphics/jpeg/pkg-descr
+++ b/graphics/jpeg/pkg-descr
@@ -1,9 +1,6 @@
The Independent JPEG Group's JPEG software
==========================================
-README for release 6 of 2-Aug-95
-================================
-
This distribution contains the sixth public release of the Independent JPEG
Group's free JPEG software. You are welcome to redistribute this software and
to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
@@ -19,4 +16,8 @@ Ge' Weijers, and other members of the Independent JPEG Group.
IJG is not affiliated with the official ISO JPEG standards committee.
+Includes EXIF patches from:
+http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=106060
+http://sylvana.net/jpegcrop/exifpatch.html
+
WWW: http://www.ijg.org/
diff --git a/graphics/jpeg/pkg-plist b/graphics/jpeg/pkg-plist
index 8f67c7ec5e9b..2f19a75c6825 100644
--- a/graphics/jpeg/pkg-plist
+++ b/graphics/jpeg/pkg-plist
@@ -1,5 +1,7 @@
bin/cjpeg
bin/djpeg
+bin/exifautotran
+bin/jpegexiforient
bin/jpegtran
bin/rdjpgcom
bin/wrjpgcom