mirror of
https://git.freebsd.org/ports.git
synced 2025-06-23 05:30:31 -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)
284 lines
9.7 KiB
C
284 lines
9.7 KiB
C
--- 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 &&
|