mirror of
https://git.freebsd.org/ports.git
synced 2025-06-21 12:40:45 -04:00
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)
218 lines
5.6 KiB
C
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:
|