summaryrefslogtreecommitdiff
path: root/ext/exif/exif.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/exif/exif.c')
-rw-r--r--ext/exif/exif.c1063
1 files changed, 0 insertions, 1063 deletions
diff --git a/ext/exif/exif.c b/ext/exif/exif.c
deleted file mode 100644
index 925335506e..0000000000
--- a/ext/exif/exif.c
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP version 4.0 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.02 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at |
- | http://www.php.net/license/2_02.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Rasmus Lerdorf <rasmus@php.net> |
- +----------------------------------------------------------------------+
- */
-/* Much of the code in this module was borrowed from the public domain
- jhead.c package with the author's consent. The main changes have been
- to eliminate all the global variables to make it thread safe and to wrap
- it in the PHP 4 API.
-
- The original header from the jhead.c file was:
-
- --------------------------------------------------------------------------
- Program to pull the information out of various types of EFIF digital
- camera files and show it in a reasonably consistent way
-
- Version 0.9
-
- Compiles with MSVC on Windows, or with GCC on Linux
-
- Compileing under linux: Must include math library.
- Use: cc -lm -O3 -o jhead jhead.c
-
- Matthias Wandel, Dec 1999 - April 2000
- --------------------------------------------------------------------------
- */
-#include "php.h"
-
-#if HAVE_EXIF
-
-#include "php_exif.h"
-#include <math.h>
-#include "php_ini.h"
-#include "ext/standard/php_string.h"
-#include "ext/standard/info.h"
-
-typedef unsigned char uchar;
-
-#ifndef TRUE
- #define TRUE 1
- #define FALSE 0
-#endif
-
-/*
- This structure stores Exif header image elements in a simple manner
- Used to store camera data as extracted from the various ways that it can be
- stored in a nexif header
-*/
-typedef struct {
- char FileName [120];
- time_t FileDateTime;
- unsigned FileSize;
- char CameraMake [32];
- char CameraModel [64];
- char DateTime [20];
- int Height, Width;
- int IsColor;
- int FlashUsed;
- float FocalLength;
- float ExposureTime;
- float ApertureFNumber;
- float Distance;
- float CCDWidth;
- char Comments[200];
- double FocalplaneXRes;
- double FocalplaneUnits;
- int ExifImageWidth;
- int MotorolaOrder;
- int Orientation;
- char GPSinfo[48];
- int ISOspeed;
- char ExifVersion[16];
- char Copyright[32];
- char Software[32];
- char *Thumbnail;
- int ThumbnailSize;
-} ImageInfoType;
-
-/* 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
-
-function_entry exif_functions[] = {
- PHP_FE(read_exif_data, NULL)
- {0}
-};
-
-PHP_MINFO_FUNCTION(exif);
-
-zend_module_entry exif_module_entry = {
- "exif",
- exif_functions,
- NULL, NULL,
- NULL, NULL,
- PHP_MINFO(exif),
- STANDARD_MODULE_PROPERTIES
-};
-
-#ifdef COMPILE_DL_EXIF
-ZEND_GET_MODULE(exif)
-#endif
-
-PHP_MINFO_FUNCTION(exif) {
- php_info_print_table_start();
- php_info_print_table_row(2, "EXIF Support", "enabled" );
- php_info_print_table_end();
-}
-
-/*
- 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. */
-
-/*
- 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[250];
- int nch;
- int a;
-
- nch = 0;
-
- if (length > 200) length = 200; /* Truncate if it won't fit in our structure. */
-
- 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 */
-
- /*
- if (ShowTags) {
- printf("COM marker comment: %s\n",Comment);
- }
- */
-
- strcpy(ImageInfo->Comments,Comment);
-}
-
-
-/* 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;
-
- data_precision = Data[2];
- ImageInfo->Height = Get16m(Data+3);
- ImageInfo->Width = Get16m(Data+5);
- num_components = Data[7];
-
- if (num_components == 3) {
- ImageInfo->IsColor = 1;
- } else {
- ImageInfo->IsColor = 0;
- }
-
- 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 12
-
-#define FMT_BYTE 1
-#define FMT_STRING 2
-#define FMT_USHORT 3
-#define FMT_ULONG 4
-#define FMT_URATIONAL 5
-#define FMT_SBYTE 6
-#define FMT_UNDEFINED 7
-#define FMT_SSHORT 8
-#define FMT_SLONG 9
-#define FMT_SRATIONAL 10
-#define FMT_SINGLE 11
-#define FMT_DOUBLE 12
-
-/*
- 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
-
-#define TAG_THUMBOFFSET 0x0201
-#define TAG_THUMBSIZE 0x0202
-
-#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
-
-static const struct {
- unsigned short Tag;
- char *Desc;
-} TagTable[] = {
- { 0x100, "ImageWidth"},
- { 0x101, "ImageLength"},
- { 0x102, "BitsPerSample"},
- { 0x103, "Compression"},
- { 0x106, "PhotometricInterpretation"},
- { 0x10A, "FillOrder"},
- { 0x10D, "DocumentName"},
- { 0x10E, "ImageDescription"},
- { 0x10F, "Make"},
- { 0x110, "Model"},
- { 0x111, "StripOffsets"},
- { 0x112, "Orientation"},
- { 0x115, "SamplesPerPixel"},
- { 0x116, "RowsPerStrip"},
- { 0x117, "StripByteCounts"},
- { 0x11A, "XResolution"},
- { 0x11B, "YResolution"},
- { 0x11C, "PlanarConfiguration"},
- { 0x128, "ResolutionUnit"},
- { 0x12D, "TransferFunction"},
- { 0x131, "Software"},
- { 0x132, "DateTime"},
- { 0x13B, "Artist"},
- { 0x13E, "WhitePoint"},
- { 0x13F, "PrimaryChromaticities"},
- { 0x156, "TransferRange"},
- { 0x200, "JPEGProc"},
- { 0x201, "JPEGInterchangeFormat"},
- { 0x202, "JPEGInterchangeFormatLength"},
- { 0x211, "YCbCrCoefficients"},
- { 0x212, "YCbCrSubSampling"},
- { 0x213, "YCbCrPositioning"},
- { 0x214, "ReferenceBlackWhite"},
- { 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"},
- { 0x9003, "DateTimeOriginal"},
- { 0x9004, "DateTimeDigitized"},
- { 0x9101, "ComponentsConfiguration"},
- { 0x9102, "CompressedBitsPerPixel"},
- { 0x9201, "ShutterSpeedValue"},
- { 0x9202, "ApertureValue"},
- { 0x9203, "BrightnessValue"},
- { 0x9204, "ExposureBiasValue"},
- { 0x9205, "MaxApertureValue"},
- { 0x9206, "SubjectDistance"},
- { 0x9207, "MeteringMode"},
- { 0x9208, "LightSource"},
- { 0x9209, "Flash"},
- { 0x920A, "FocalLength"},
- { 0x927C, "MakerNote"},
- { 0x9286, "UserComment"},
- { 0x9290, "SubSecTime"},
- { 0x9291, "SubSecTimeOriginal"},
- { 0x9292, "SubSecTimeDigitized"},
- { 0xA000, "FlashPixVersion"},
- { 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"}, /* 0x9210 - - */
- { 0xA214, "SubjectLocation"}, /* 0x9214 - - */
- { 0xA215, "ExposureIndex"}, /* 0x9215 - - */
- { 0xA217, "SensingMethod"}, /* 0x9217 - - */
- { 0xA300, "FileSource"},
- { 0xA301, "SceneType"},
- { 0, NULL}
-} ;
-
-
-
-/* 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 FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
- case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
-
- case FMT_USHORT: Value = Get16u(ValuePtr,MotorolaOrder); break;
- case FMT_ULONG: Value = Get32u(ValuePtr,MotorolaOrder); break;
-
- case FMT_URATIONAL:
- case 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 FMT_SSHORT: Value = (signed short)Get16u(ValuePtr,MotorolaOrder); break;
- case FMT_SLONG: Value = Get32s(ValuePtr,MotorolaOrder); break;
-
- /* Not sure if this is correct (never seen float used in Exif format) */
- case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
- case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
- }
- return Value;
-}
-
-/* Process one of the nested EXIF directories. */
-static void ProcessExifDir(ImageInfoType *ImageInfo, char *DirStart, char *OffsetBase, unsigned ExifLength, char *LastExifRefd)
-{
- int de;
- int a;
- int NumDirEntries;
-
- NumDirEntries = Get16u(DirStart, ImageInfo->MotorolaOrder);
-
- if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)) {
- php_error(E_ERROR,"Illegally sized directory");
- }
-
-
- /*
- if (ShowTags) {
- printf("Directory with %d entries\n",NumDirEntries);
- }
- */
-
- for (de=0;de<NumDirEntries;de++) {
- int Tag, Format, Components;
- char *ValuePtr;
- int ByteCount;
- char *DirEntry;
- 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. */
- php_error(E_ERROR,"Illegal format code in EXIF dir");
- }
-
- 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); */
-
- php_error(E_ERROR,"Illegal pointer offset value in EXIF");
- }
- 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;
- }
-
- /* Extract useful components of tag */
- switch(Tag) {
-
- case TAG_MAKE:
- strncpy(ImageInfo->CameraMake, ValuePtr, 31);
- break;
-
- case TAG_MODEL:
- strncpy(ImageInfo->CameraModel, ValuePtr, 63);
- break;
-
- case TAG_GPSINFO:
- strncpy(ImageInfo->GPSinfo, ValuePtr, 47);
- break;
-
- case TAG_EXIFVERSION:
- strncpy(ImageInfo->ExifVersion, ValuePtr, 15);
- break;
-
- case TAG_COPYRIGHT:
- strncpy(ImageInfo->Copyright, ValuePtr, 31);
- break;
-
- case TAG_SOFTWARE:
- strncpy(ImageInfo->Software, ValuePtr, 31);
- break;
-
- case TAG_ORIENTATION:
- ImageInfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_ISOSPEED:
- ImageInfo->ISOspeed = (int)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_DATETIME_ORIGINAL:
- strncpy(ImageInfo->DateTime, ValuePtr, 19);
- break;
-
- case TAG_USERCOMMENT:
- /* 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 != ' ') {
- strncpy(ImageInfo->Comments, a+ValuePtr, 199);
- break;
- }
- }
-
- } else {
- strncpy(ImageInfo->Comments, ValuePtr, 199);
- }
- break;
-
- case TAG_FNUMBER:
- /* Simplest way of expressing aperture, so I trust it the most.
- (overwrite previously computd value if there is one) */
- ImageInfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_APERTURE:
- case TAG_MAXAPERTURE:
- /* More relevant info always comes earlier, so only use this field if we don't
- have appropriate aperture information yet. */
- if (ImageInfo->ApertureFNumber == 0) {
- ImageInfo->ApertureFNumber
- = (float)exp(ConvertAnyFormat(ValuePtr, Format, ImageInfo->MotorolaOrder)*log(2)*0.5);
- }
- break;
-
- case TAG_FOCALLENGTH:
- /* Nice digital cameras actually save the focal length as a function
- of how farthey are zoomed in. */
- ImageInfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_SUBJECT_DISTANCE:
- /* Inidcates the distacne the autofocus camera is focused to.
- Tends to be less accurate as distance increases. */
- ImageInfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_EXPOSURETIME:
- /* Simplest way of expressing exposure time, so I trust it most.
- (overwrite previously computd value if there is one) */
- ImageInfo->ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_SHUTTERSPEED:
- /* More complicated way of expressing exposure time, so only use
- this value if we don't already have it from somewhere else. */
- if (ImageInfo->ExposureTime == 0) {
- ImageInfo->ExposureTime
- = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format, ImageInfo->MotorolaOrder)*log(2)));
- }
- break;
-
- case TAG_FLASH:
- if (ConvertAnyFormat(ValuePtr, Format, ImageInfo->MotorolaOrder)) {
- ImageInfo->FlashUsed = 1;
- }
- break;
-
- case TAG_IMAGEWIDTH:
- ImageInfo->ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_FOCALPLANEXRES:
- ImageInfo->FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder);
- break;
-
- case TAG_FOCALPLANEUNITS:
- switch((int)ConvertAnyFormat(ValuePtr, Format,ImageInfo->MotorolaOrder)) {
- case 1: ImageInfo->FocalplaneUnits = 25.4; break; /* inch */
- case 2:
- /* According to the information I was using, 2 measn meters.
- But looking at the Cannon powershot's files, inches is the only
- sensible value. */
- ImageInfo->FocalplaneUnits = 25.4;
- break;
-
- case 3: ImageInfo->FocalplaneUnits = 10; break; /* centimeter */
- case 4: ImageInfo->FocalplaneUnits = 1; break; /* milimeter */
- case 5: ImageInfo->FocalplaneUnits = .001; break; /* micrometer */
- }
- break;
-
- case TAG_LIGHT_SOURCE:
- /* Rarely set or useful. */
- break;
- }
-
- if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET) {
- char *SubdirStart;
- SubdirStart = OffsetBase + Get32u(ValuePtr, ImageInfo->MotorolaOrder);
- if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) {
- php_error(E_ERROR,"Illegal subdirectory link");
- }
- ProcessExifDir(ImageInfo, SubdirStart, OffsetBase, ExifLength, LastExifRefd);
- continue;
- }
- }
-}
-
-/*
- Process an EXIF marker
- Describes all the drivel that most digital cameras include...
-*/
-static void process_EXIF (ImageInfoType *ImageInfo, char *CharBuf, unsigned int length, char *LastExifRefd)
-{
- ImageInfo->FlashUsed = 0; /* If it s from a digicam, and it used flash, it says so. */
- LastExifRefd = CharBuf;
-
- ImageInfo->FocalplaneXRes = 0;
- ImageInfo->FocalplaneUnits = 0;
- ImageInfo->ExifImageWidth = 0;
-
- { /* Check the EXIF header component */
- static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
- if (memcmp(CharBuf+2, ExifHeader,6)) {
- php_error(E_ERROR,"Incorrect Exif header");
- }
- }
-
- if (memcmp(CharBuf+8,"II",2) == 0) {
-/* if (ShowTags) printf("Exif section in Intel order\n"); */
- ImageInfo->MotorolaOrder = 0;
- } else {
- if (memcmp(CharBuf+8,"MM",2) == 0) {
-/* if (ShowTags) printf("Exif section in Motorola order\n"); */
- ImageInfo->MotorolaOrder = 1;
- } else {
- php_error(E_ERROR,"Invalid Exif alignment marker.");
- }
- }
-
- /* Check the next two values for correctness. */
- if (Get16u(CharBuf+10,ImageInfo->MotorolaOrder) != 0x2a
- || Get32u(CharBuf+12,ImageInfo->MotorolaOrder) != 0x08) {
- php_error(E_ERROR,"Invalid Exif start (1)");
- }
-
- /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */
- ProcessExifDir(ImageInfo, CharBuf+16, CharBuf+8, length-6, LastExifRefd);
-
- /* Compute the CCD width, in milimeters. */
- if (ImageInfo->FocalplaneXRes != 0) {
- ImageInfo->CCDWidth = (float)(ImageInfo->ExifImageWidth * ImageInfo->FocalplaneUnits / ImageInfo->FocalplaneXRes);
- }
-}
-
-/* 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. */
- php_error(E_ERROR,"too many padding bytes!");
- }
-
- Sections[*SectionsRead].Type = marker;
-
- /* Read the length of the section. */
- lh = fgetc(infile);
- ll = fgetc(infile);
-
- itemlen = (lh << 8) | ll;
-
- if (itemlen < 2) {
- php_error(E_ERROR,"invalid marker");
- }
-
- Sections[*SectionsRead].Size = itemlen;
-
- Data = (uchar *)emalloc(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) {
- php_error(E_ERROR,"reading from file");
- }
- *SectionsRead += 1;
-
- /*printf("Marker '%x' size %d\n",marker, itemlen);*/
- 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 *)malloc(size);
- if (Data == NULL) {
- php_error(E_ERROR,"could not allocate data for entire image");
- }
-
- got = fread(Data, 1, size, infile);
- if (got != size) {
- php_error(E_ERROR,"could not read the rest of the image");
- }
-
- 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 */
- php_error(E_ERROR,"No image in jpeg!");
- return FALSE;
-
- case M_COM: /* Comment section */
- if (HaveCom) {
- (*SectionsRead) -= 1;
- efree(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.
-*/
-void DiscardData(Section_t *Sections, int *SectionsRead)
-{
- int a;
- for (a=0;a<*SectionsRead-1;a++) {
- efree(Sections[a].Data);
- }
- *SectionsRead = 0;
-}
-
-/*
- Read image data.
-*/
-int ReadJpegFile(ImageInfoType *ImageInfo, Section_t *Sections,
- int *SectionsRead, char *FileName,
- int ReadAll, char *LastExifRefd)
-{
- FILE *infile;
- int ret;
- char *tmp;
-
- infile = V_FOPEN(FileName, "rb"); /* Unix ignores 'b', windows needs it. */
-
- if (infile == NULL) {
- php_error(E_ERROR, "Unable to open '%s'", FileName);
- return FALSE;
- }
-/* CurrentFile = FileName; */
-
- /* Start with an empty image information structure. */
- memset(ImageInfo, 0, sizeof(*ImageInfo));
- memset(Sections, 0, sizeof(*Sections));
-
- tmp = php_basename(FileName,strlen(FileName));
- strncpy(ImageInfo->FileName, tmp, 119);
- efree(tmp);
- ImageInfo->FocalLength = 0;
- ImageInfo->ExposureTime = 0;
- ImageInfo->ApertureFNumber = 0;
- ImageInfo->Distance = 0;
- ImageInfo->CCDWidth = 0;
- ImageInfo->FlashUsed = -1;
-
- {
- /* Store file date/time. */
- struct stat st;
- if (stat(FileName, &st) >= 0) {
- ImageInfo->FileDateTime = st.st_mtime;
- ImageInfo->FileSize = st.st_size;
- } else {
- php_error(E_ERROR,"Can't get file statitics");
- }
- }
-
- /* Scan the JPEG headers. */
- ret = scan_JPEG_header(ImageInfo, infile, Sections, SectionsRead, ReadAll, LastExifRefd);
- if (!ret) {
- php_error(E_ERROR,"Invalid Jpeg file: '%s'\n",FileName);
- }
-
- fclose(infile);
-
- return ret;
-}
-
-int php_read_jpeg_exif(ImageInfoType *ImageInfo, char *FileName, int ReadAll)
-{
- Section_t Sections[20];
- int SectionsRead;
- char *LastExifRefd=NULL;
- int ret;
- int thumbsize=0;
- /* int i; */
-
- ImageInfo->MotorolaOrder = 0;
-
- ret = ReadJpegFile(ImageInfo, Sections, &SectionsRead, FileName, ReadAll, LastExifRefd);
- /*
- * Thought this might pick out the embedded thumbnail, but it doesn't work.
- for (i=0;i<SectionsRead-1;i++) {
- if (Sections[i].Type == M_EXIF) {
- thumbsize = Sections[i].Size;
- if(thumbsize>0) {
- ImageInfo->Thumbnail = emalloc(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);
- }
- }
- }
- */
- if (ret != FALSE) {
- DiscardData(Sections, &SectionsRead);
- }
- return(ret);
-}
-
-/* {{{ proto string read_exif_data(string filename)
- Reads the EXIF header data from a JPEG file */
-PHP_FUNCTION(read_exif_data) {
- pval **p_name;
- int ac = ZEND_NUM_ARGS(), ret;
- ImageInfoType ImageInfo;
- char tmp[64];
-
- ImageInfo.Thumbnail = NULL;
- ImageInfo.ThumbnailSize = 0;
-
- if (ac != 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE)
- WRONG_PARAM_COUNT;
-
- convert_to_string_ex(p_name);
- ret = php_read_jpeg_exif(&ImageInfo, (*p_name)->value.str.val,1);
- if (array_init(return_value) == FAILURE) {
- RETURN_FALSE;
- }
- add_assoc_string(return_value,"FileName",ImageInfo.FileName,1);
- add_assoc_long(return_value,"FileDateTime",ImageInfo.FileDateTime);
- add_assoc_long(return_value,"FileSize",ImageInfo.FileSize);
- if (ImageInfo.CameraMake[0]) {
- add_assoc_string(return_value,"CameraMake",ImageInfo.CameraMake,1);
- }
- if (ImageInfo.CameraModel[0]) {
- add_assoc_string(return_value,"CameraModel",ImageInfo.CameraModel,1);
- }
- if (ImageInfo.DateTime[0]) {
- add_assoc_string(return_value,"DateTime",ImageInfo.DateTime,1);
- }
- add_assoc_long(return_value,"Height",ImageInfo.Height);
- add_assoc_long(return_value,"Width",ImageInfo.Width);
- add_assoc_long(return_value,"IsColor",ImageInfo.IsColor);
- if(ImageInfo.FlashUsed >= 0) {
- add_assoc_long(return_value,"FlashUsed",ImageInfo.FlashUsed);
- }
- if (ImageInfo.FocalLength) {
- sprintf(tmp,"%4.1fmm",ImageInfo.FocalLength);
- add_assoc_string(return_value,"FocalLength",tmp,1);
- if(ImageInfo.CCDWidth) {
- sprintf(tmp,"%dmm",(int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*35+0.5));
- add_assoc_string(return_value,"35mmFocalLength",tmp,1);
- }
- add_assoc_double(return_value,"RawFocalLength",ImageInfo.FocalLength);
- }
- if(ImageInfo.ExposureTime) {
- if(ImageInfo.ExposureTime <= 0.5) {
- sprintf(tmp,"%6.3f s (1/%d)",ImageInfo.ExposureTime,(int)(0.5 + 1/ImageInfo.ExposureTime));
- } else {
- sprintf(tmp,"%6.3f s",ImageInfo.ExposureTime);
- }
- add_assoc_string(return_value,"ExposureTime",tmp,1);
- add_assoc_double(return_value,"RawExposureTime",ImageInfo.ExposureTime);
- }
- if(ImageInfo.ApertureFNumber) {
- sprintf(tmp,"f/%4.1f",ImageInfo.ApertureFNumber);
- add_assoc_string(return_value,"ApertureFNumber",tmp,1);
- add_assoc_double(return_value,"RawApertureFNumber",ImageInfo.ApertureFNumber);
- }
- if(ImageInfo.Distance) {
- if(ImageInfo.Distance<0) {
- add_assoc_string(return_value,"FocusDistance","Infinite",1);
- } else {
- sprintf(tmp,"%5.2fm",ImageInfo.Distance);
- add_assoc_string(return_value,"FocusDistance",tmp,1);
- }
- add_assoc_double(return_value,"RawFocusDistance",ImageInfo.Distance);
- }
- if(ImageInfo.CCDWidth) {
- add_assoc_double(return_value,"CCDWidth",ImageInfo.CCDWidth);
- }
- if(ImageInfo.Orientation) {
- add_assoc_long(return_value,"Orientation",ImageInfo.Orientation);
- }
- if (ImageInfo.GPSinfo[0]) {
- add_assoc_string(return_value,"GPSinfo",ImageInfo.GPSinfo,1);
- }
- if(ImageInfo.ISOspeed) {
- add_assoc_long(return_value,"ISOspeed",ImageInfo.ISOspeed);
- }
- if (ImageInfo.ExifVersion[0]) {
- add_assoc_string(return_value,"ExifVersion",ImageInfo.ExifVersion,1);
- }
- if (ImageInfo.Copyright[0]) {
- add_assoc_string(return_value,"Copyright",ImageInfo.Copyright,1);
- }
- if (ImageInfo.Software[0]) {
- add_assoc_string(return_value,"Software",ImageInfo.Software,1);
- }
- if(ImageInfo.Comments[0]) {
- add_assoc_string(return_value,"Comments",ImageInfo.Comments,1);
- }
- if(ImageInfo.ThumbnailSize) {
- add_assoc_stringl(return_value,"Thumbnail",ImageInfo.Thumbnail,ImageInfo.ThumbnailSize,1);
- add_assoc_long(return_value,"ThumbnailSize",ImageInfo.ThumbnailSize);
- efree(ImageInfo.Thumbnail);
- }
-}
-
-#endif
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- */