summaryrefslogtreecommitdiff
path: root/src/libexif/exif.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexif/exif.c')
-rw-r--r--src/libexif/exif.c1274
1 files changed, 0 insertions, 1274 deletions
diff --git a/src/libexif/exif.c b/src/libexif/exif.c
deleted file mode 100644
index 3be72a3..0000000
--- a/src/libexif/exif.c
+++ /dev/null
@@ -1,1274 +0,0 @@
-/*
-
-Copyright © 2000 Matthias Wandel, The PHP Group, Curtis Galloway
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-*/
-
-#include <sys/time.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <math.h>
-#include <sys/stat.h>
-#include <stdarg.h>
-#include <fcntl.h>
-
-#include "exif.h"
-
-typedef unsigned char uchar;
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-/*
- This structure stores global state for an EXIF image file.
-*/
-typedef struct {
- exif_data_t *d;
- int MotorolaOrder;
- const char *filename;
-
- char *Thumbnail;
- int ThumbnailSize;
-} ImageInfoType;
-
-void *(*exif_malloc_fn)(int);
-void *(*exif_realloc_fn)(void *, int);
-void (*exif_free_fn)(void *);
-
-static char *
-exif_strndup(char *str, int len)
-{
- char *rval = (*exif_malloc_fn)(len+1);
- strncpy(rval, str, len);
- rval[len] = '\0';
- return rval;
-}
-
-struct exif_data *
-exif_alloc(void)
-{
- exif_data_t *d;
-
- d = (*exif_malloc_fn)(sizeof(exif_data_t));
- bzero(d, sizeof(*d));
- return d;
-}
-
-static void
-exif_error(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vprintf(fmt, ap);
- va_end(ap);
-}
-
-
-/* This structure is used to store a section of a Jpeg file. */
-typedef struct {
- uchar *Data;
- int Type;
- unsigned Size;
-} Section_t;
-
-#define EXIT_FAILURE 1
-#define EXIT_SUCCESS 0
-
-
-/*
- JPEG markers consist of one or more 0xFF bytes, followed by a marker
- code byte (which is not an FF). Here are the marker codes of interest
- in this program. (See jdmarker.c for a more complete list.)
-*/
-
-#define M_SOF0 0xC0 /* Start Of Frame N */
-#define M_SOF1 0xC1 /* N indicates which compression process */
-#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
-#define M_SOF3 0xC3
-#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
-#define M_SOF6 0xC6
-#define M_SOF7 0xC7
-#define M_SOF9 0xC9
-#define M_SOF10 0xCA
-#define M_SOF11 0xCB
-#define M_SOF13 0xCD
-#define M_SOF14 0xCE
-#define M_SOF15 0xCF
-#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
-#define M_EOI 0xD9 /* End Of Image (end of datastream) */
-#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
-#define M_EXIF 0xE1
-#define M_COM 0xFE /* COMment */
-
-
-#define PSEUDO_IMAGE_MARKER 0x123; /* Extra value. */
-
-#define EXIF_ALLOC_SIZE 16
-
-/*
- * The name gets copied, so you can pass a static string;
- * the data is not copied, so if it is a string,
- * you must allocate it yourself.
- */
-static int
-exif_append_data(exif_data_t **d_p,
- char *name,
- char rec_type,
- int exif_format,
- exif_rec_data_t *data)
-{
- exif_data_t *d = *d_p;
-
- if (rec_type == '\0')
- return EXIT_FAILURE;
-
- if (d->n_alloc <= d->n_recs) {
- d->n_alloc += EXIF_ALLOC_SIZE;
- d = (*exif_realloc_fn)(d, sizeof(exif_data_t) +
- sizeof(exif_record_t) * d->n_alloc);
- *d_p = d;
- }
- d->recs[d->n_recs].rec_type = rec_type;
- bcopy(data, &d->recs[d->n_recs].rec_data, sizeof(exif_rec_data_t));
- d->recs[d->n_recs].rec_name = (char*)strdup(name);
- d->n_recs++;
- return EXIT_SUCCESS;
-}
-
-/*
- Get 16 bits motorola order (always) for jpeg header stuff.
-*/
-static int
-Get16m(void *Short)
-{
- return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
-}
-
-
-/*
- Process a COM marker.
- We want to print out the marker contents as legible text;
- we must guard against random junk and varying newline representations.
-*/
-static void
-process_COM (ImageInfoType *ImageInfo, uchar *Data, int length)
-{
- int ch;
- char *Comment;
- int nch;
- int a;
- exif_rec_data_t rd;
-
- nch = 0;
- Comment = (*exif_malloc_fn)(length+1);
-
- for (a=2;a<length;a++) {
- ch = Data[a];
-
- if (ch == '\r' && Data[a+1] == '\n') continue; /* Remove cr followed by lf. */
-
- if (isprint(ch) || ch == '\n' || ch == '\t') {
- Comment[nch++] = (char)ch;
- } else {
- Comment[nch++] = '?';
- }
- }
-
- Comment[nch] = '\0'; /* Null terminate */
-
- rd.s = Comment;
- exif_append_data(&ImageInfo->d, "Comment", 's', EXIF_FMT_COMPUTED, &rd);
-}
-
-/* Process a SOFn marker. This is useful for the image dimensions. */
-static void
-process_SOFn (ImageInfoType *ImageInfo, uchar *Data, int marker)
-{
- int data_precision, num_components;
- const char *process;
- exif_rec_data_t rd;
-
- data_precision = Data[2];
- rd.l = Get16m(Data+3);
- exif_append_data(&ImageInfo->d,
- "Height",
- 'l',
- EXIF_FMT_COMPUTED,
- &rd);
- rd.l = Get16m(Data+5);
- exif_append_data(&ImageInfo->d,
- "Width",
- 'l',
- EXIF_FMT_COMPUTED,
- &rd);
- num_components = Data[7];
-
- if (num_components == 3) {
- rd.l = 1;
- } else {
- rd.l = 0;
- }
- exif_append_data(&ImageInfo->d, "IsColor", 'l', EXIF_FMT_COMPUTED, &rd);
-
- switch (marker) {
- case M_SOF0: process = "Baseline"; break;
- case M_SOF1: process = "Extended sequential"; break;
- case M_SOF2: process = "Progressive"; break;
- case M_SOF3: process = "Lossless"; break;
- case M_SOF5: process = "Differential sequential"; break;
- case M_SOF6: process = "Differential progressive"; break;
- case M_SOF7: process = "Differential lossless"; break;
- case M_SOF9: process = "Extended sequential, arithmetic coding"; break;
- case M_SOF10: process = "Progressive, arithmetic coding"; break;
- case M_SOF11: process = "Lossless, arithmetic coding"; break;
- case M_SOF13: process = "Differential sequential, arithmetic coding"; break;
- case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
- case M_SOF15: process = "Differential lossless, arithmetic coding"; break;
- default: process = "Unknown"; break;
- }
-}
-
-/*
- Describes format descriptor
-*/
-static int ExifBytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
-#define NUM_FORMATS EXIF_FMT_DOUBLE
-
-/*
- Describes tag values
-*/
-
-#define TAG_EXIF_OFFSET 0x8769
-#define TAG_INTEROP_OFFSET 0xa005
-
-#define TAG_COMPRESSION 0x0103
-
-#define TAG_MAKE 0x010F
-#define TAG_MODEL 0x0110
-#define TAG_ORIENTATION 0x0112
-
-#define TAG_SOFTWARE 0x0131
-
-/* Olympus specific tags */
-#define TAG_SPECIALMODE 0x0200
-#define TAG_JPEGQUAL 0x0201
-#define TAG_MACRO 0x0202
-#define TAG_DIGIZOOM 0x0204
-#define TAG_SOFTWARERELEASE 0x0207
-#define TAG_PICTINFO 0x0208
-#define TAG_CAMERAID 0x0209
-/* end Olympus specific tags */
-
-#define TAG_COPYRIGHT 0x8298
-
-#define TAG_EXPOSURETIME 0x829A
-#define TAG_FNUMBER 0x829D
-
-#define TAG_GPSINFO 0x8825
-#define TAG_ISOSPEED 0x8827
-#define TAG_EXIFVERSION 0x9000
-
-#define TAG_SHUTTERSPEED 0x9201
-#define TAG_APERTURE 0x9202
-#define TAG_MAXAPERTURE 0x9205
-#define TAG_FOCALLENGTH 0x920A
-
-#define TAG_DATETIME_ORIGINAL 0x9003
-#define TAG_USERCOMMENT 0x9286
-
-#define TAG_SUBJECT_DISTANCE 0x9206
-#define TAG_LIGHT_SOURCE 0x9208
-#define TAG_FLASH 0x9209
-
-#define TAG_FOCALPLANEXRES 0xa20E
-#define TAG_FOCALPLANEUNITS 0xa210
-#define TAG_IMAGEWIDTH 0xA002
-
-struct ExifTag {
- unsigned short Tag;
- char *Desc;
- void (*Func)();
-};
-
-
-
-/* Convert a 16 bit unsigned value from file's native byte order */
-static int
-Get16u(void *Short, int MotorolaOrder)
-{
- if (MotorolaOrder) {
- return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
- } else {
- return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
- }
-}
-
-/* Convert a 32 bit signed value from file's native byte order */
-static int
-Get32s(void *Long, int MotorolaOrder)
-{
- if (MotorolaOrder) {
- return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
- | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
- } else {
- return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
- | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
- }
-}
-
-/* Convert a 32 bit unsigned value from file's native byte order */
-static unsigned
-Get32u(void *Long, int MotorolaOrder)
-{
- return (unsigned)Get32s(Long, MotorolaOrder) & 0xffffffff;
-}
-
-
-/* Evaluate number, be it int, rational, or float from directory. */
-static double
-ConvertAnyFormat(void *ValuePtr, int Format, int MotorolaOrder)
-{
- double Value;
- Value = 0;
-
- switch(Format) {
- case EXIF_FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
- case EXIF_FMT_BYTE: Value = *(uchar *)ValuePtr; break;
-
- case EXIF_FMT_USHORT: Value = Get16u(ValuePtr,MotorolaOrder); break;
- case EXIF_FMT_ULONG: Value = Get32u(ValuePtr,MotorolaOrder); break;
-
- case EXIF_FMT_URATIONAL:
- case EXIF_FMT_SRATIONAL:
- {
- int Num,Den;
- Num = Get32s(ValuePtr,MotorolaOrder);
- Den = Get32s(4+(char *)ValuePtr,MotorolaOrder);
- if (Den == 0) {
- Value = 0;
- } else {
- Value = (double)Num/Den;
- }
- break;
- }
-
- case EXIF_FMT_SSHORT: Value = (signed short)Get16u(ValuePtr,MotorolaOrder); break;
- case EXIF_FMT_SLONG: Value = Get32s(ValuePtr,MotorolaOrder); break;
-
- /* Not sure if this is correct (never seen float used in Exif format) */
- case EXIF_FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
- case EXIF_FMT_DOUBLE: Value = *(double *)ValuePtr; break;
- }
- return Value;
-}
-
-/* Evaluate number, be it int, rational, or float from directory. */
-static char
-ConvertAnyFormat2(void *ValuePtr, int ByteCount, int Format, int MotorolaOrder, exif_rec_data_t *data_p)
-{
- char *str, *p;
- char r_type;
- unsigned char c;
- static char hexdigits[] = "0123456789ABCDEF";
-
- switch(Format) {
- case EXIF_FMT_STRING:
- data_p->s = exif_strndup(ValuePtr, ByteCount);
- r_type = 's';
- break;
-
- case EXIF_FMT_SBYTE:
- data_p->l = (long)*(signed char *)ValuePtr;
- r_type = 'l';
- break;
-
- case EXIF_FMT_BYTE:
- data_p->l = (long)*(uchar *)ValuePtr;
- r_type = 'l';
- break;
-
- case EXIF_FMT_USHORT:
- data_p->l = (long)Get16u(ValuePtr,MotorolaOrder);
- r_type = 'l';
- break;
- case EXIF_FMT_ULONG:
- data_p->l = (long)Get32u(ValuePtr,MotorolaOrder);
- r_type = 'l';
- break;
-
- case EXIF_FMT_URATIONAL:
- case EXIF_FMT_SRATIONAL:
- {
- int Num,Den;
- data_p->r.num = Get32s(ValuePtr,MotorolaOrder);
- data_p->r.denom = Get32s(4+(char *)ValuePtr,MotorolaOrder);
- r_type = 'r';
- break;
- }
-
- case EXIF_FMT_SSHORT:
- data_p->l = (signed short)Get16u(ValuePtr,MotorolaOrder);
- r_type = 'l';
- break;
- case EXIF_FMT_SLONG:
- data_p->l = (long)Get32s(ValuePtr,MotorolaOrder);
- r_type = 'l';
- break;
-
- /* Not sure if this is correct (never seen float used in Exif format) */
- case EXIF_FMT_SINGLE:
- data_p->f = *(float *)ValuePtr;
- r_type = 'f';
- break;
-
- case EXIF_FMT_DOUBLE:
- data_p->g = *(double *)ValuePtr;
- r_type = 'f';
- break;
-
- default:
- /* unknown type */
- p = str = (*exif_malloc_fn)(ByteCount*2 + 1);
- while (ByteCount--) {
- c = *(unsigned char *)ValuePtr++;
- *p++ = hexdigits[c / 16];
- *p++ = hexdigits[c % 16];
- }
- *p++ = '\0';
- data_p->s = str;
- r_type = 's';
- break;
- }
- return r_type;
-}
-
-
-static void
-ProcessFocalPlaneUnits(ImageInfoType *ImageInfo,
- void *ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p)
-{
- exif_rec_data_t rd;
- float FocalPlaneUnits;
-
- switch((int)ConvertAnyFormat(ValuePtr, Format, ImageInfo->MotorolaOrder)) {
- case 1:
- FocalPlaneUnits = 25.4;
- break; /* inch */
- case 2:
- /* According to the information I was using, 2 means meters.
- But looking at the Canon PowerShot's files, inches is the only
- sensible value. */
- FocalPlaneUnits = 25.4;
- break;
-
- case 3:
- FocalPlaneUnits = 10;
- break; /* centimeter */
- case 4:
- FocalPlaneUnits = 1;
- break; /* milimeter */
- case 5:
- FocalPlaneUnits = .001;
- break; /* micrometer */
- }
-
- rd.f = FocalPlaneUnits;
- exif_append_data(&ImageInfo->d,
- "FocalPlaneUnits",
- 'f',
- Format,
- &rd);
-}
-
-static void
-ProcessVersion(ImageInfoType *ImageInfo,
- void *ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p)
-{
- exif_rec_data_t rd;
- rd.s = exif_strndup(ValuePtr, ByteCount);
- exif_append_data(&ImageInfo->d,
- tag_p->Desc,
- 's',
- Format,
- &rd);
-}
-
-static void
-ProcessUserComment(ImageInfoType *ImageInfo,
- void *_ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p)
-{
- char *ValuePtr = (char *)_ValuePtr;
- exif_rec_data_t rd;
- int a;
-
- /* Olympus has this padded with trailing spaces. Remove these first. */
- for (a=ByteCount;;) {
- a--;
- if ((ValuePtr)[a] == ' ') {
- (ValuePtr)[a] = '\0';
- } else {
- break;
- }
- if (a == 0) break;
- }
-
- /* Copy the comment */
- if (memcmp(ValuePtr, "ASCII",5) == 0) {
- for (a=5;a<10;a++) {
- int c;
- c = (ValuePtr)[a];
- if (c != '\0' && c != ' ') {
- rd.s = exif_strndup(a+ValuePtr, ByteCount - a);
- exif_append_data(&ImageInfo->d,
- "UserComment",
- 's',
- Format,
- &rd);
- break;
- }
- }
-
- } else {
- rd.s = exif_strndup(ValuePtr, ByteCount);
- exif_append_data(&ImageInfo->d,
- "UserComment",
- 's',
- Format,
- &rd);
- }
-}
-
-static void
-ProcessShutterSpeed(ImageInfoType *ImageInfo,
- void *ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p)
-{
- exif_rec_data_t rd;
- char rec_type;
-
- rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format,
- ImageInfo->MotorolaOrder,
- &rd);
- exif_append_data(&ImageInfo->d,
- tag_p->Desc,
- rec_type,
- Format,
- &rd);
-
- /* Convert shutter speed value to shutter speed;
- * shutter speed is 1/(2**ShutterSpeedValue)
- */
- rd.r.denom = (int)pow(2.0, ((double)rd.r.num)/((double)rd.r.denom));
- rd.r.num = 1;
- exif_append_data(&ImageInfo->d,
- "ShutterSpeed",
- 'r',
- EXIF_FMT_COMPUTED,
- &rd);
-
-}
-
-static void
-ProcessAperture(ImageInfoType *ImageInfo,
- void *ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p)
-{
- exif_rec_data_t rd;
- char rec_type;
- double fstop;
- char label[32];
-
- rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format,
- ImageInfo->MotorolaOrder,
- &rd);
- exif_append_data(&ImageInfo->d,
- tag_p->Desc,
- rec_type,
- Format,
- &rd);
-
- if (exif_find_record(ImageInfo->d, "FNumber") == NULL) {
- /* Convert aperture to F-stop. */
- fstop = pow(sqrt(2), ((double)rd.r.num)/((double)rd.r.denom));
- sprintf(label, "f%.1g", fstop);
- rd.s = (char*)strdup(label);
- exif_append_data(&ImageInfo->d,
- "FNumber",
- 's',
- EXIF_FMT_COMPUTED,
- &rd);
- }
-}
-
-static void
-ProcessCanonMakerNote(ImageInfoType *ImageInfo,
- void *ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p,
- char *OffsetBase)
-{
-
- /* This is for the Canon MakerNote. */
- /* XXX - go by value of Maker tag. */
- exif_rec_data_t rd;
- char rec_type;
- unsigned long n_dir, tag, format, components, offset;
- char label[32];
- void *OffsetPtr;
-
- n_dir = Get16u(ValuePtr, ImageInfo->MotorolaOrder);
- ValuePtr += 2;
- while (n_dir--) {
- tag = Get16u(ValuePtr, ImageInfo->MotorolaOrder);
- ValuePtr += 2;
- format = Get16u(ValuePtr, ImageInfo->MotorolaOrder);
- ValuePtr += 2;
- components = Get32u(ValuePtr, ImageInfo->MotorolaOrder);
- ValuePtr += 4;
- offset = Get32u(ValuePtr, ImageInfo->MotorolaOrder);
- ByteCount = components * ExifBytesPerFormat[format];
- if (ByteCount > 4) {
- OffsetPtr = OffsetBase + offset;
- } else {
- OffsetPtr = ValuePtr;
- }
- ValuePtr += 4;
- rec_type = ConvertAnyFormat2(OffsetPtr, ByteCount, format,
- ImageInfo->MotorolaOrder,
- &rd);
- sprintf(label, "MakerNote%04x", tag);
- exif_append_data(&ImageInfo->d,
- label,
- rec_type,
- format,
- &rd);
-
- }
-}
-
-
-struct MakerNote {
- char *Make;
- void (*Func)();
-};
-
-static struct MakerNote
-MakerProcessors[] = {
- {"Canon", ProcessCanonMakerNote},
- {NULL, NULL}
-};
-
-static void
-ProcessMakerNote(ImageInfoType *ImageInfo,
- void *ValuePtr,
- int ByteCount,
- int Format,
- struct ExifTag *tag_p,
- char *OffsetBase)
-{
- struct MakerNote *mn_p;
- exif_record_t *rec_p;
-
- rec_p = exif_find_record(ImageInfo->d, "Make");
- if (rec_p == NULL) {
- return;
- }
-
- for(mn_p = &MakerProcessors[0]; mn_p->Make != NULL; mn_p++) {
- if (strcmp(mn_p->Make, rec_p->rec_data.s) == 0) {
- (*mn_p->Func)(ImageInfo, ValuePtr, ByteCount, Format, tag_p, OffsetBase);
- break;
- }
- }
-}
-
-static struct ExifTag
-TagTable[] = {
- { 0x0001, "InteroperabilityIndex"},
- { 0x0002, "InteroperabilityVersion", ProcessVersion},
- { 0x0100, "ImageWidth"},
- { 0x0101, "ImageLength"},
- { 0x0102, "BitsPerSample"},
- { 0x0103, "Compression"},
- { 0x0106, "PhotometricInterpretation"},
- { 0x010A, "FillOrder"},
- { 0x010D, "DocumentName"},
- { 0x010E, "ImageDescription"},
- { 0x010F, "Make"},
- { 0x0110, "Model"},
- { 0x0111, "StripOffsets"},
- { 0x0112, "Orientation"},
- { 0x0115, "SamplesPerPixel"},
- { 0x0116, "RowsPerStrip"},
- { 0x0117, "StripByteCounts"},
- { 0x011A, "XResolution"},
- { 0x011B, "YResolution"},
- { 0x011C, "PlanarConfiguration"},
- { 0x0128, "ResolutionUnit"},
- { 0x012D, "TransferFunction"},
- { 0x0131, "Software"},
- { 0x0132, "DateTime"},
- { 0x013B, "Artist"},
- { 0x013E, "WhitePoint"},
- { 0x013F, "PrimaryChromaticities"},
- { 0x0156, "TransferRange"},
- { 0x0200, "JPEGProc"},
- { 0x0201, "JPEGInterchangeFormat"},
- { 0x0202, "JPEGInterchangeFormatLength"},
- { 0x0211, "YCbCrCoefficients"},
- { 0x0212, "YCbCrSubSampling"},
- { 0x0213, "YCbCrPositioning"},
- { 0x0214, "ReferenceBlackWhite"},
- { 0x1000, "RelatedImageFileFormat"},
- { 0x1001, "RelatedImageWidth"},
- { 0x1002, "RelatedImageLength"},
- { 0x828D, "CFARepeatPatternDim"},
- { 0x828E, "CFAPattern"},
- { 0x828F, "BatteryLevel"},
- { 0x8298, "Copyright"},
- { 0x829A, "ExposureTime"},
- { 0x829D, "FNumber"},
- { 0x83BB, "IPTC/NAA"},
- { 0x8769, "ExifOffset"},
- { 0x8773, "InterColorProfile"},
- { 0x8822, "ExposureProgram"},
- { 0x8824, "SpectralSensitivity"},
- { 0x8825, "GPSInfo"},
- { 0x8827, "ISOSpeedRatings"},
- { 0x8828, "OECF"},
- { 0x9000, "ExifVersion", ProcessVersion},
- { 0x9003, "DateTimeOriginal"},
- { 0x9004, "DateTimeDigitized"},
- { 0x9101, "ComponentsConfiguration"},
- { 0x9102, "CompressedBitsPerPixel"},
- { 0x9201, "ShutterSpeedValue", ProcessShutterSpeed},
- { 0x9202, "ApertureValue", ProcessAperture},
- { 0x9203, "BrightnessValue"},
- { 0x9204, "ExposureBiasValue"},
- { 0x9205, "MaxApertureValue", ProcessAperture},
- { 0x9206, "SubjectDistance"},
- { 0x9207, "MeteringMode"},
- { 0x9208, "LightSource"},
- { 0x9209, "Flash"},
- { 0x920A, "FocalLength"},
- { 0x927C, "MakerNote", ProcessMakerNote},
- { 0x9286, "UserComment", ProcessUserComment},
- { 0x9290, "SubSecTime"},
- { 0x9291, "SubSecTimeOriginal"},
- { 0x9292, "SubSecTimeDigitized"},
- { 0xA000, "FlashPixVersion", ProcessVersion},
- { 0xA001, "ColorSpace"},
- { 0xA002, "ExifImageWidth"},
- { 0xA003, "ExifImageLength"},
- { 0xA005, "InteroperabilityOffset"},
- { 0xA20B, "FlashEnergy"}, /* 0x920B in TIFF/EP */
- { 0xA20C, "SpatialFrequencyResponse"}, /* 0x920C - - */
- { 0xA20E, "FocalPlaneXResolution"}, /* 0x920E - - */
- { 0xA20F, "FocalPlaneYResolution"}, /* 0x920F - - */
- { 0xA210, "FocalPlaneResolutionUnit", ProcessFocalPlaneUnits},
- /* 0x9210 - - */
- { 0xA214, "SubjectLocation"}, /* 0x9214 - - */
- { 0xA215, "ExposureIndex"}, /* 0x9215 - - */
- { 0xA217, "SensingMethod"}, /* 0x9217 - - */
- { 0xA300, "FileSource"},
- { 0xA301, "SceneType"},
- { 0, NULL}
-} ;
-
-
-
-/* Process one of the nested EXIF directories. */
-static int
-ProcessExifDir(ImageInfoType *ImageInfo, char *DirStart, char *OffsetBase, unsigned ExifLength, char *LastExifRefd)
-{
- int de;
- int a;
- int NumDirEntries;
- exif_rec_data_t rd;
- char rec_type;
- char label[32];
-
- NumDirEntries = Get16u(DirStart, ImageInfo->MotorolaOrder);
-
- if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)) {
- exif_error("Illegally sized directory");
- return FALSE;
- }
-
-
- for (de=0;de<NumDirEntries;de++) {
- int Tag, Format, Components;
- char *ValuePtr;
- int ByteCount;
- char *DirEntry;
- struct ExifTag *tag_p;
-
- DirEntry = DirStart+2+12*de;
-
- Tag = Get16u(DirEntry, ImageInfo->MotorolaOrder);
- Format = Get16u(DirEntry+2, ImageInfo->MotorolaOrder);
- Components = Get32u(DirEntry+4, ImageInfo->MotorolaOrder);
-
- if ((Format-1) >= NUM_FORMATS) {
- /* (-1) catches illegal zero case as unsigned underflows to positive large. */
- exif_error("Illegal format code in EXIF dir");
- return FALSE;
- }
-
- ByteCount = Components * ExifBytesPerFormat[Format];
-
- if (ByteCount > 4) {
- unsigned OffsetVal;
- OffsetVal = Get32u(DirEntry+8, ImageInfo->MotorolaOrder);
- /* If its bigger than 4 bytes, the dir entry contains an offset. */
- if (OffsetVal+ByteCount > ExifLength) {
- /* Bogus pointer offset and / or bytecount value */
- /* printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); */
-
- exif_error("Illegal pointer offset value in EXIF");
- return FALSE;
- }
- ValuePtr = OffsetBase+OffsetVal;
- } else {
- /* 4 bytes or less and value is in the dir entry itself */
- ValuePtr = DirEntry+8;
- }
-
- if (LastExifRefd < ValuePtr+ByteCount) {
- /*
- Keep track of last byte in the exif header that was actually referenced.
- That way, we know where the discardable thumbnail data begins.
- */
- LastExifRefd = ValuePtr+ByteCount;
- }
-
- if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET) {
- char *SubdirStart;
- SubdirStart = OffsetBase + Get32u(ValuePtr, ImageInfo->MotorolaOrder);
- if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) {
- exif_error("Illegal subdirectory link");
- return FALSE;
- }
- ProcessExifDir(ImageInfo, SubdirStart, OffsetBase, ExifLength, LastExifRefd);
- continue;
- }
-
- /* Search through tag table */
- for (tag_p = &TagTable[0]; tag_p->Desc != NULL; tag_p++) {
- if (tag_p->Tag == Tag) {
- if (tag_p->Func != NULL) {
- (*tag_p->Func)(ImageInfo, ValuePtr, ByteCount, Format, tag_p, OffsetBase);
- } else {
- rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format,
- ImageInfo->MotorolaOrder,
- &rd);
- exif_append_data(&ImageInfo->d,
- tag_p->Desc,
- rec_type,
- Format,
- &rd);
- }
- break;
- }
- }
- if (tag_p->Desc == NULL) {
- rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format,
- ImageInfo->MotorolaOrder,
- &rd);
- sprintf(label, "0x%04x", Tag);
- exif_append_data(&ImageInfo->d,
- label,
- rec_type,
- Format,
- &rd);
- }
- }
- return TRUE;
-}
-
-/*
- Process an EXIF marker
- Describes all the drivel that most digital cameras include...
-*/
-static int
-process_EXIF (ImageInfoType *ImageInfo, char *CharBuf, unsigned int length, char *LastExifRefd)
-{
- int cc;
- exif_rec_data_t rd;
- LastExifRefd = CharBuf;
-
- { /* Check the EXIF header component */
- static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
- if (memcmp(CharBuf+2, ExifHeader,6)) {
- exif_error("Incorrect Exif header");
- return FALSE;
- }
- }
-
- if (memcmp(CharBuf+8,"II",2) == 0) {
- ImageInfo->MotorolaOrder = 0;
- } else {
- if (memcmp(CharBuf+8,"MM",2) == 0) {
- ImageInfo->MotorolaOrder = 1;
- } else {
- exif_error("Invalid Exif alignment marker.");
- return FALSE;
- }
- }
-
- /* Check the next two values for correctness. */
- if (Get16u(CharBuf+10,ImageInfo->MotorolaOrder) != 0x2a
- || Get32u(CharBuf+12,ImageInfo->MotorolaOrder) != 0x08) {
- exif_error("Invalid Exif start (1, NULL)");
- return FALSE;
- }
-
- /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */
- cc = ProcessExifDir(ImageInfo, CharBuf+16, CharBuf+8, length-6, LastExifRefd);
- if (cc != TRUE) {
- return cc;
- }
- return TRUE;
-}
-
-/* Parse the marker stream until SOS or EOI is seen; */
-static int
-scan_JPEG_header (ImageInfoType *ImageInfo, FILE *infile, Section_t *Sections, int *SectionsRead, int ReadAll, char *LastExifRefd)
-{
- int a;
- int HaveCom = FALSE;
-
- a = fgetc(infile);
- if (a != 0xff || fgetc(infile) != M_SOI) {
- return FALSE;
- }
-
- for(*SectionsRead=0;*SectionsRead < 19;) {
- int itemlen;
- int marker = 0;
- int ll,lh, got;
- uchar *Data;
-
- for (a=0;a<7;a++) {
- marker = fgetc(infile);
- if (marker != 0xff) break;
- }
- if (marker == 0xff) {
- /* 0xff is legal padding, but if we get that many, something's wrong. */
- exif_error("too many padding bytes!");
- return FALSE;
- }
-
- Sections[*SectionsRead].Type = marker;
-
- /* Read the length of the section. */
- lh = fgetc(infile);
- ll = fgetc(infile);
-
- itemlen = (lh << 8) | ll;
-
- if (itemlen < 2) {
- exif_error("invalid marker");
- return FALSE;
- }
-
- Sections[*SectionsRead].Size = itemlen;
-
- Data = (uchar *)(*exif_malloc_fn)(itemlen+1); /* Add 1 to allow sticking a 0 at the end. */
- Sections[*SectionsRead].Data = Data;
-
- /* Store first two pre-read bytes. */
- Data[0] = (uchar)lh;
- Data[1] = (uchar)ll;
-
- got = fread(Data+2, 1, itemlen-2, infile); /* Read the whole section. */
- if (got != itemlen-2) {
- exif_error("reading from file");
- return FALSE;
- }
- *SectionsRead += 1;
-
- switch(marker) {
- case M_SOS: /* stop before hitting compressed data */
- /* If reading entire image is requested, read the rest of the data. */
- if (ReadAll) {
- int cp, ep, size;
- /* Determine how much file is left. */
- cp = ftell(infile);
- fseek(infile, 0, SEEK_END);
- ep = ftell(infile);
- fseek(infile, cp, SEEK_SET);
-
- size = ep-cp;
- Data = (uchar *)(*exif_malloc_fn)(size);
- if (Data == NULL) {
- exif_error("could not allocate data for entire image");
- return FALSE;
- }
-
- got = fread(Data, 1, size, infile);
- if (got != size) {
- exif_error("could not read the rest of the image");
- return FALSE;
- }
-
- Sections[*SectionsRead].Data = Data;
- Sections[*SectionsRead].Size = size;
- Sections[*SectionsRead].Type = PSEUDO_IMAGE_MARKER;
- (*SectionsRead)++;
- /*
- *HaveAll = 1;
- */
- }
- return TRUE;
-
- case M_EOI: /* in case it's a tables-only JPEG stream */
- exif_error("No image in jpeg!");
- return FALSE;
-
- case M_COM: /* Comment section */
- if (HaveCom) {
- (*SectionsRead) -= 1;
- (*exif_free_fn)(Sections[*SectionsRead].Data);
- } else {
- process_COM(ImageInfo, Data, itemlen);
- HaveCom = TRUE;
- }
- break;
-
- case M_EXIF:
- if (*SectionsRead <= 2) {
- /* Seen files from some 'U-lead' software with Vivitar scanner
- that uses marker 31 later in the file (no clue what for!) */
- process_EXIF(ImageInfo, (char *)Data, itemlen, LastExifRefd);
- }
- break;
-
- case M_SOF0:
- case M_SOF1:
- case M_SOF2:
- case M_SOF3:
- case M_SOF5:
- case M_SOF6:
- case M_SOF7:
- case M_SOF9:
- case M_SOF10:
- case M_SOF11:
- case M_SOF13:
- case M_SOF14:
- case M_SOF15:
- process_SOFn(ImageInfo, Data, marker);
- break;
- default:
- /* skip any other marker silently. */
- break;
- }
- }
- return TRUE;
-}
-
-/*
- Discard read data.
-*/
-static void
-DiscardData(Section_t *Sections, int *SectionsRead)
-{
- int a;
- for (a=0;a<*SectionsRead-1;a++) {
- (*exif_free_fn)(Sections[a].Data);
- }
- *SectionsRead = 0;
-}
-
-/*
- Read image data.
-*/
-static int
-ReadJpegFile(ImageInfoType *ImageInfo, Section_t *Sections,
- int *SectionsRead, int fd,
- int ReadAll, char *LastExifRefd)
-{
- FILE *infile;
- int ret;
- char *tmp;
- char **p_argv;
- int p_argc;
-
- infile = fdopen(fd, "rb"); /* Unix ignores 'b', windows needs it. */
-
- if (infile == NULL) {
- exif_error("Unable to open '%s'", ImageInfo->filename);
- return FALSE;
- }
-
- /* Start with an empty image information structure. */
- memset(ImageInfo, 0, sizeof(*ImageInfo));
- memset(Sections, 0, sizeof(*Sections));
-
- ImageInfo->d = exif_alloc();
-
- /* Scan the JPEG headers. */
- ret = scan_JPEG_header(ImageInfo, infile, Sections, SectionsRead, ReadAll, LastExifRefd);
- if (!ret) {
- exif_error("Invalid Jpeg file: '%s'",ImageInfo->filename);
- return FALSE;
- }
-
- fclose(infile);
-
- return ret;
-}
-
-static int
-read_jpeg_exif(ImageInfoType *ImageInfo, int fd, int ReadAll)
-{
- Section_t Sections[20];
- int SectionsRead;
- char *LastExifRefd=NULL;
- int ret;
- int thumbsize=0;
-
- ret = ReadJpegFile(ImageInfo, Sections, &SectionsRead, fd, ReadAll, LastExifRefd);
-#if 0
- /*
- * Thought this might pick out the embedded thumbnail, but it doesn't work. -RL
- */
- for (i=0;i<SectionsRead-1;i++) {
- if (Sections[i].Type == M_EXIF) {
- thumbsize = Sections[i].Size;
- if(thumbsize>0) {
- ImageInfo->Thumbnail = (*exif_malloc_fn)(thumbsize+5);
- ImageInfo->ThumbnailSize = thumbsize;
- ImageInfo->Thumbnail[0] = 0xff;
- ImageInfo->Thumbnail[1] = 0xd8;
- ImageInfo->Thumbnail[2] = 0xff;
- memcpy(ImageInfo->Thumbnail+4, Sections[i].Data, thumbsize+4);
- }
- }
- }
-#endif
- if (ret != FALSE) {
- DiscardData(Sections, &SectionsRead);
- }
- return(ret);
-}
-
-exif_data_t *
-exif_parse_fd(int fd)
-{
- ImageInfoType ImageInfo;
-
- ImageInfo.filename = "<file stream>";
- if (read_jpeg_exif(&ImageInfo, fd, 1) != TRUE) {
- return NULL;
- }
- return ImageInfo.d;
-}
-
-exif_data_t *
-exif_parse_file(const char *filename)
-{
- ImageInfoType ImageInfo;
- int fd;
-
- ImageInfo.filename = filename;
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- return NULL;
- }
-
- if (read_jpeg_exif(&ImageInfo, fd, 1) != TRUE) {
- return NULL;
- }
- return ImageInfo.d;
-}
-
-void
-exif_free_data(struct exif_data *d)
-{
- int i;
- for (i=0; i<d->n_recs; i++) {
- (*exif_free_fn)(d->recs[i].rec_name);
- if (d->recs[i].rec_type == 's') {
- (*exif_free_fn)(d->recs[i].rec_data.s);
- }
- }
- (*exif_free_fn)(d);
-}
-
-void
-exif_init(void *(*malloc_fn)(int),
- void (*free_fn)(void *),
- void *(*realloc_fn)(void *, int))
-{
- if (malloc_fn == NULL) {
- malloc_fn = (void *(*)(int))malloc;
- }
- exif_malloc_fn = malloc_fn;
- if (free_fn == NULL) {
- free_fn = (void (*)(void *))free;
- }
- exif_free_fn = free_fn;
- if (realloc_fn == NULL) {
- realloc_fn = (void *(*)(void *, int))realloc;
- }
- exif_realloc_fn = realloc_fn;
-}
-
-extern exif_record_t *
-exif_find_record(exif_data_t *d, const char *rec_name)
-{
- int i;
- for (i=0; i<d->n_recs; i++) {
- if (strcmp(d->recs[i].rec_name, rec_name) == 0) {
- return &d->recs[i];
- }
- }
- return NULL;
-}
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- */
-
-