ports/graphics/jpeg/files/patch-rdjpgcom.c
Dirk Meyer 7a318b355a - 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)
2004-03-18 14:53:47 +00:00

218 lines
5.6 KiB
C

--- 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: