summaryrefslogtreecommitdiff
path: root/ext/exif/exif.c
diff options
context:
space:
mode:
authorMarcus Boerger <helly@php.net>2002-03-05 19:47:19 +0000
committerMarcus Boerger <helly@php.net>2002-03-05 19:47:19 +0000
commit088450efce4fff7878a75daae93e25c5a1e8c8c6 (patch)
tree6e2792b12857d0ec071e18bb4a99bd8107b12135 /ext/exif/exif.c
parent80f121266060fc7c37777005eb6814a54ecb008f (diff)
downloadphp-git-088450efce4fff7878a75daae93e25c5a1e8c8c6.tar.gz
-fixes
-changed internal data structures #nearly stripped off all jhead code
Diffstat (limited to 'ext/exif/exif.c')
-rw-r--r--ext/exif/exif.c1642
1 files changed, 907 insertions, 735 deletions
diff --git a/ext/exif/exif.c b/ext/exif/exif.c
index e5edc2d100..00a39ebfbc 100644
--- a/ext/exif/exif.c
+++ b/ext/exif/exif.c
@@ -62,7 +62,7 @@
* while extending the module as it shows if you are at the right position.
* You are always considered to have a copy of TIFF6.0 and EXIF 2.10 standard.
*/
-/* #define EXIF_DEBUG /**/
+/* #undef EXIF_DEBUG /**/
#include "php_exif.h"
#include <math.h>
@@ -78,35 +78,440 @@ typedef unsigned char uchar;
#define FALSE 0
#endif
-#define EXIF_MAX_COMMENTS 12
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
-/* EXIF standard defines Copyright as "<Photographer> [ '\0' <Editor> ] ['\0']" */
-#define EXIF_MAX_COPYRIGHT 2
+/* {{{ exif_functions[]
+ */
+function_entry exif_functions[] = {
+ PHP_FE(read_exif_data, NULL)
+ PHP_FALIAS(exif_read_data,read_exif_data, NULL)
+ PHP_FE(exif_headername, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
-/* {{{ structs
- 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
+#define EXIF_VERSION "1.1b $Revision$"
+
+PHP_MINFO_FUNCTION(exif);
+
+/* {{{ exif_module_entry
+ */
+zend_module_entry exif_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "exif",
+ exif_functions,
+ NULL, NULL,
+ NULL, NULL,
+ PHP_MINFO(exif),
+ EXIF_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_EXIF
+ZEND_GET_MODULE(exif)
+#endif
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(exif)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "EXIF Support", "enabled" );
+ php_info_print_table_row(2, "EXIF Version", EXIF_VERSION );
+ php_info_print_table_row(2, "Supported EXIF Version", "02100");
+ php_info_print_table_row(2, "Supported filetypes", "JPEG,TIFF");
+ php_info_print_table_row(2, "Thumbnails", "none");
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ php_strnlen
+ * get length of string if buffer if less than buffer size or buffer size */
+static size_t php_strnlen( char* str, size_t maxlen) {
+ size_t len = 0;
+
+ if ( str && maxlen && *str) {
+ do {
+ len++;
+ } while ( --maxlen && *(++str));
+ }
+ return len;
+}
+/* }}} */
+
+/* {{{ format description defines
+ Describes format descriptor
*/
+static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
+#define NUM_FORMATS 12
-/* Constants taken from function getimagesize with additional TIFF */
-/* This structure is used to store a section of a Jpeg file. */
+#define TAG_FMT_BYTE 1
+#define TAG_FMT_STRING 2
+#define TAG_FMT_USHORT 3
+#define TAG_FMT_ULONG 4
+#define TAG_FMT_URATIONAL 5
+#define TAG_FMT_SBYTE 6
+#define TAG_FMT_UNDEFINED 7
+#define TAG_FMT_SSHORT 8
+#define TAG_FMT_SLONG 9
+#define TAG_FMT_SRATIONAL 10
+#define TAG_FMT_SINGLE 11
+#define TAG_FMT_DOUBLE 12
-#define FOUND_ANY_TAG 0x0001
-#define FOUND_IFD0 0x0002
-#define FOUND_COMMENT 0x0004
-#define FOUND_APP0 0x0010
-#define FOUND_EXIF 0x0020
-#define FOUND_FPIX 0x0040
-#define FOUND_APP12 0x0080
-#define FOUND_GPS 0x0100
-#define FOUND_INTEROP 0x0200
+/* Describes tag values */
+#define TAG_TIFF_COMMENT 0x00FE /* SHOUDLNT HAPPEN */
+#define TAG_NEW_SUBFILE 0x00FE /* New version of subfile tag */
+#define TAG_SUBFILE_TYPE 0x00FF /* Old version of subfile tag */
+#define TAG_IMAGEWIDTH 0x0100
+#define TAG_IMAGEHEIGHT 0x0101
+#define TAG_BITS_PER_SAMPLE 0x0102
+#define TAG_COMPRESSION 0x0103
+#define TAG_PHOTOMETRIC_INTERPRETATION 0x0106
+#define TAG_TRESHHOLDING 0x0107
+#define TAG_CELL_WIDTH 0x0108
+#define TAG_CELL_HEIGHT 0x0109
+#define TAG_FILL_ORDER 0x010A
+#define TAG_DOCUMENT_NAME 0x010D
+#define TAG_IMAGE_DESCRIPTION 0x010E
+#define TAG_MAKE 0x010F
+#define TAG_MODEL 0x0110
+#define TAG_STRIP_OFFSETS 0x0111
+#define TAG_ORIENTATION 0x0112
+#define TAG_SAMPLES_PER_PIXEL 0x0115
+#define TAG_ROWS_PER_STRIP 0x0116
+#define TAG_STRIP_BYTE_COUNTS 0x0117
+#define TAG_MIN_SAMPPLE_VALUE 0x0118
+#define TAG_MAX_SAMPLE_VALUE 0x0119
+#define TAG_X_RESOLUTION 0x011A
+#define TAG_Y_RESOLUTION 0x011B
+#define TAG_PLANAR_CONFIGURATION 0x011C
+#define TAG_PAGE_NAME 0x011D
+#define TAG_X_POSITION 0x011E
+#define TAG_Y_POSITION 0x011F
+#define TAG_FREE_OFFSETS 0x0120
+#define TAG_FREE_BYTE_COUNTS 0x0121
+#define TAG_GRAY_RESPONSE_UNIT 0x0122
+#define TAG_GRAY_RESPONSE_CURVE 0x0123
+#define TAG_RESOLUTION_UNIT 0x0128
+#define TAG_PAGE_NUMBER 0x0129
+#define TAG_TRANSFER_FUNCTION 0x012D
+#define TAG_SOFTWARE 0x0131
+#define TAG_DATETIME 0x0132
+#define TAG_ARTIST 0x013B
+#define TAG_HOST_COMPUTER 0x013C
+#define TAG_PREDICATOR 0x013D
+#define TAG_WHITE_POINT 0x013E
+#define TAG_PRIMARY_CHROMATICITIES 0x013F
+#define TAG_COLOR_MAP 0x0140
+#define TAG_HALFTONE_HINTS 0x0141
+#define TAG_TILE_WIDTH 0x0142
+#define TAG_TILE_LENGTH 0x0143
+#define TAG_TILE_OFFSETS 0x0144
+#define TAG_TILE_BYTE_COUNTS 0x0145
+#define TAG_INK_SETMPUTER 0x014C
+#define TAG_NUMBER_OF_INKS 0x014E
+#define TAG_INK_NAMES 0x014D
+#define TAG_DOT_RANGE 0x0150
+#define TAG_TARGET_PRINTER 0x0151
+#define TAG_EXTRA_SAMPLE 0x0152
+#define TAG_SAMPLE_FORMAT 0x0153
+#define TAG_S_MIN_SAMPLE_VALUE 0x0154
+#define TAG_S_MAX_SAMPLE_VALUE 0x0155
+#define TAG_TRANSFER_RANGE 0x0156
+#define TAG_JPEG_PROC 0x0200
+#define TAG_JPEG_INTERCHANGE_FORMAT 0x0201
+#define TAG_JPEG_INTERCHANGE_FORMAT_LEN 0x0202
+#define TAG_JPEG_RESTART_INTERVAL 0x0203
+#define TAG_JPEG_LOSSLESS_PREDICTOR 0x0205
+#define TAG_JPEG_POINT_TRANSFORMS 0x0206
+#define TAG_JPEG_Q_TABLES 0x0207
+#define TAG_JPEG_DC_TABLES 0x0208
+#define TAG_JPEG_AC_TABLES 0x0209
+#define TAG_YCC_COEFFICIENTS 0x0211
+#define TAG_YCC_SUB_SAMPLING 0x0212
+#define TAG_YCC_POSITIONING 0x0213
+#define TAG_REFERENCE_BLACK_WHITE 0x0214
+#define TAG_COPYRIGHT 0x8298
+#define TAG_EXPOSURETIME 0x829A
+#define TAG_FNUMBER 0x829D
+#define TAG_EXIF_IFD_POINTER 0x8769
+#define TAG_GPS_IFD_POINTER 0x8825
+#define TAG_ISOSPEED 0x8827
+#define TAG_EXIFVERSION 0x9000
+#define TAG_SHUTTERSPEED 0x9201
+#define TAG_APERTURE 0x9202
+#define TAG_DATETIME_ORIGINAL 0x9003
+#define TAG_MAXAPERTURE 0x9205
+#define TAG_SUBJECT_DISTANCE 0x9206
+#define TAG_LIGHT_SOURCE 0x9208
+#define TAG_FLASH 0x9209
+#define TAG_FOCALLENGTH 0x920A
+#define TAG_MARKER_NOTE 0x927C
+#define TAG_USERCOMMENT 0x9286
+#define TAG_FLASH_PIX_VERSION 0xA000
+#define TAG_COLOR_SPACE 0xA001
+#define TAG_COMP_IMAGEWIDTH 0xA002 /* compressed images only */
+#define TAG_COMP_IMAGEHEIGHT 0xA003
+#define TAG_INTEROP_IFD_POINTER 0xA005 /* IFD pointer */
+#define TAG_FOCALPLANEXRES 0xA20E
+#define TAG_FOCALPLANEUNITS 0xA210
-typedef struct {
- uchar *Data;
- int Type;
- size_t Size;
-} section_t;
+/* Olympus specific tags */
+#define TAG_OLYMPUS_SPECIALMODE 0x0200
+#define TAG_OLYMPUS_JPEGQUAL 0x0201
+#define TAG_OLYMPUS_MACRO 0x0202
+#define TAG_OLYMPUS_DIGIZOOM 0x0204
+#define TAG_OLYMPUS_SOFTWARERELEASE 0x0207
+#define TAG_OLYMPUS_PICTINFO 0x0208
+#define TAG_OLYMPUS_CAMERAID 0x0209
+/* end Olympus specific tags */
+
+
+/* Values for TAG_PHOTOMETRIC_INTERPRETATION */
+#define PMI_BLACK_IS_ZERO 0
+#define PMI_WHITE_IS_ZERO 1
+#define PMI_RGB 2
+#define PMI_PALETTE_COLOR 3
+#define PMI_TRANSPARENCY_MASK 4
+#define PMI_SEPARATED 5
+#define PMI_YCBCR 6
+#define PMI_CIELAB 8
+
+/* }}} */
+
+/* {{{ TabTable[]
+ */
+static const struct {
+ unsigned short Tag;
+ char *Desc;
+} TagTable[] = {
+ { 0x00FE, "NewSubFile"},
+ { 0x00FF, "SubFile"},
+ { 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"},
+ { 0x0118, "MinSampleValue"},
+ { 0x0119, "MaxSampleValue"},
+ { 0x011A, "XResolution"},
+ { 0x011B, "YResolution"},
+ { 0x011C, "PlanarConfiguration"},
+ { 0x011D, "PageName"},
+ { 0x011E, "XPosition"},
+ { 0x011F, "YPosition"},
+ { 0x0120, "FreeOffsets"},
+ { 0x0121, "FreeByteCounts"},
+ { 0x0122, "GrayResponseUnit"},
+ { 0x0123, "GrayResponseCurve"},
+ { 0x0124, "T4Options"},
+ { 0x0125, "T6Options"},
+ { 0x0128, "ResolutionUnit"},
+ { 0x0129, "PageNumber"},
+ { 0x012D, "TransferFunction"},
+ { 0x0131, "Software"},
+ { 0x0132, "DateTime"},
+ { 0x013B, "Artist"},
+ { 0x013C, "HostComputer"},
+ { 0x013D, "Predictor"},
+ { 0x013E, "WhitePoint"},
+ { 0x013F, "PrimaryChromaticities"},
+ { 0x0140, "ColorMap"},
+ { 0x0141, "HalfToneHints"},
+ { 0x0142, "TileWidth"},
+ { 0x0143, "TileLength"},
+ { 0x0144, "TileOffsets"},
+ { 0x0145, "TileByteCounts"},
+ { 0x014C, "InkSet"},
+ { 0x014D, "InkNames"},
+ { 0x014E, "NumberOfInks"},
+ { 0x0150, "DotRange"},
+ { 0x0151, "TargetPrinter"},
+ { 0x0152, "ExtraSample"},
+ { 0x0153, "SampleFormat"},
+ { 0x0154, "SMinSampleValue"},
+ { 0x0155, "SMaxSampleValue"},
+ { 0x0156, "TransferRange"},
+ { 0x0200, "JPEGProc"},
+ { 0x0201, "JPEGInterchangeFormat"},
+ { 0x0202, "JPEGInterchangeFormatLength"},
+ { 0x0203, "JPEGRestartInterval"},
+ { 0x0205, "JPEGLosslessPredictors"},
+ { 0x0206, "JPEGPointTransforms"},
+ { 0x0207, "JPEGQTables"},
+ { 0x0208, "JPEGDCTables"},
+ { 0x0209, "JPEGACTables"},
+ { 0x0211, "YCbCrCoefficients"},
+ { 0x0212, "YCbCrSubSampling"},
+ { 0x0213, "YCbCrPositioning"},
+ { 0x0214, "ReferenceBlackWhite"},
+ { 0x1000, "RelatedImageFileFormat"},
+ { 0x828D, "CFARepeatPatternDim"},
+ { 0x828E, "CFAPattern"},
+ { 0x828F, "BatteryLevel"},
+ { 0x8298, "Copyright"},
+ { 0x829A, "ExposureTime"},
+ { 0x829D, "FNumber"},
+ { 0x83BB, "IPTC/NAA"},
+ { 0x8769, "Exif_IFD_Pointer"},
+ { 0x8773, "InterColorProfile"},
+ { 0x8822, "ExposureProgram"},
+ { 0x8824, "SpectralSensitivity"},
+ { 0x8825, "GPS_IFD_Pointer"},
+ { 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"},
+ { 0x920B, "FlashEnergy"}, /* 0xA20B in JPEG */
+ { 0x920C, "SpatialFrequencyResponse"}, /* 0xA20C - - */
+ { 0x920E, "FocalPlaneXResolution"}, /* 0xA20E - - */
+ { 0x920F, "FocalPlaneYResolution"}, /* 0xA20F - - */
+ { 0x9210, "FocalPlaneResolutionUnit"}, /* 0xA210 - - */
+ { 0x9214, "SubjectLocation"}, /* 0xA214 - - */
+ { 0x9215, "ExposureIndex"}, /* 0xA215 - - */
+ { 0x9217, "SensingMethod"}, /* 0xA217 - - */
+ { 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, "UndefinedTag"} /* Important for exif_get_tagname() */
+} ;
+/* }}} */
+
+/* {{{ php_ifd_get16u
+ * Convert a 16 bit unsigned value from file's native byte order */
+static int php_ifd_get16u(void *value, int motorola_intel)
+{
+ if (motorola_intel) {
+ return (((uchar *)value)[0] << 8) | ((uchar *)value)[1];
+ } else {
+ return (((uchar *)value)[1] << 8) | ((uchar *)value)[0];
+ }
+}
+/* }}} */
+
+/* {{{ php_ifd_get16s
+ * Convert a 16 bit signed value from file's native byte order */
+static signed short php_ifd_get16s(void *value, int motorola_intel)
+{
+ return (signed short)php_ifd_get16u(value, motorola_intel);
+}
+/* }}} */
+
+/* {{{ php_ifd_get32s
+ * Convert a 32 bit signed value from file's native byte order */
+static int php_ifd_get32s(void *value, int motorola_intel)
+{
+ if (motorola_intel) {
+ return ((( char *)value)[0] << 24)
+ | (((uchar *)value)[1] << 16)
+ | (((uchar *)value)[2] << 8 )
+ | (((uchar *)value)[3] );
+ } else {
+ return ((( char *)value)[3] << 24)
+ | (((uchar *)value)[2] << 16)
+ | (((uchar *)value)[1] << 8 )
+ | (((uchar *)value)[0] );
+ }
+}
+/* }}} */
+
+/* {{{ php_ifd_get32u
+ * Convert a 32 bit unsigned value from file's native byte order */
+static unsigned php_ifd_get32u(void *value, int motorola_intel)
+{
+ return (unsigned)php_ifd_get32s(value, motorola_intel) & 0xffffffff;
+}
+/* }}} */
+
+/* {{{ exif_convert_any_format
+ * Evaluate number, be it int, rational, or float from directory. */
+static double exif_convert_any_format(void *value, int format, int motorola_intel)
+{
+ int s_den;
+ unsigned u_den;
+
+ switch(format) {
+ case TAG_FMT_SBYTE: return *(signed char *)value;
+ case TAG_FMT_BYTE: return *(uchar *)value;
+
+ case TAG_FMT_USHORT: return php_ifd_get16u(value, motorola_intel);
+ case TAG_FMT_ULONG: return php_ifd_get32u(value, motorola_intel);
+
+ case TAG_FMT_URATIONAL:
+ u_den = php_ifd_get32u(4+(char *)value, motorola_intel);
+ if (u_den == 0) {
+ return 0;
+ } else {
+ return (double)php_ifd_get32u(value, motorola_intel) / u_den;
+ }
+
+ case TAG_FMT_SRATIONAL:
+ s_den = php_ifd_get32s(4+(char *)value, motorola_intel);
+ if (s_den == 0) {
+ return 0;
+ } else {
+ return (double)php_ifd_get32s(value, motorola_intel) / s_den;
+ }
+
+ case TAG_FMT_SSHORT: return (signed short)php_ifd_get16u(value, motorola_intel);
+ case TAG_FMT_SLONG: return php_ifd_get32s(value, motorola_intel);
+
+ /* Not sure if this is correct (never seen float used in Exif format) */
+ case TAG_FMT_SINGLE:
+ php_error(E_WARNING, "Found value of type single");
+ return (double)*(float *)value;
+ case TAG_FMT_DOUBLE:
+ php_error(E_WARNING, "Found value of type double");
+ return *(double *)value;
+ }
+ return 0;
+}
+/* }}} */
+
+/* {{{ structs
+*/
#ifndef WORD
#define WORD short
@@ -116,35 +521,275 @@ typedef struct {
#endif
typedef struct {
+ int num;
+ int den;
+} signed_rational;
+
+typedef struct {
+ unsigned int num;
+ unsigned int den;
+} unsigned_rational;
+
+typedef struct {
WORD tag;
- WORD type;
- DWORD len;
+ WORD format;
+ DWORD length;
union {
- char *s;
- DWORD u;
- int i;
+ char *s;
+ unsigned int u;
+ int i;
+ float f;
+ double d;
+ signed_rational sr;
+ unsigned_rational ur;
} value;
-} IFD_tag_type;
-
-typedef struct {
- char *name;
- char *value;
+ char *name;
} image_info_value;
typedef struct {
- int count;
+ int count;
image_info_value *list;
} image_info_list;
+#define ADD_IMAGE_INFO_xSTR( _image_info_ptr_ , _name_ , _tag_ , _length_ , _value_ ) \
+ _image_info_ptr_.list = erealloc(_image_info_ptr_.list,(_image_info_ptr_.count+1)*sizeof(image_info_value)); \
+ ((_image_info_ptr_).list[_image_info_ptr_.count]).tag = _tag_; \
+ ((_image_info_ptr_).list[_image_info_ptr_.count]).format = TAG_FMT_STRING; \
+ ((_image_info_ptr_).list[_image_info_ptr_.count]).length = _length_; \
+ ((_image_info_ptr_).list[_image_info_ptr_.count]).value.s = emalloc(_length_+1); \
+ memcpy(((_image_info_ptr_).list[_image_info_ptr_.count]).value.s, _value_, _length_); \
+ (((_image_info_ptr_).list[_image_info_ptr_.count]).value.s)[_length_] = '\0'; \
+ ((_image_info_ptr_).list[_image_info_ptr_.count]).name = emalloc(strlen(_name_)+1); \
+ strcpy(((_image_info_ptr_).list[_image_info_ptr_.count]).name, _name_); \
+ (_image_info_ptr_).count++; \
+
+/* }}} */
+
+/* {{{ exif_add_image_info
+ Free memory allocated for image_info
+*/
+void exif_add_image_info( image_info_list *image_info, char *name, int tag, int format, int length, void* value, int motorola_intel)
+{
+ image_info_value *info_value;
+ image_info_value *list;
+
+ list = erealloc(image_info->list,(image_info->count+1)*sizeof(image_info_value));
+ if ( !list) {
+ php_error(E_WARNING,"Unable to allocate more memory for data");
+ return;
+ }
+
+ image_info->list = list;
+ info_value = &(image_info->list[image_info->count]);
+
+ info_value->tag = tag;
+ info_value->format = format;
+ info_value->length = 1; /* we do not support arrays other than STRING/UNDEFINED */
+ switch (format) {
+ case TAG_FMT_BYTE:
+ info_value->value.u = *(uchar*)value;
+ break;
+
+ case TAG_FMT_STRING:
+ length = php_strnlen(value,length);
+ info_value->value.s = emalloc(length+1);
+ strcpy(info_value->value.s,value);
+ info_value->length = length;
+ break;
+
+ case TAG_FMT_USHORT:
+ info_value->value.u = php_ifd_get16u(value,motorola_intel);
+ break;
+
+ case TAG_FMT_ULONG:
+ info_value->value.u = php_ifd_get32u(value,motorola_intel);
+ break;
+
+ case TAG_FMT_URATIONAL:
+ info_value->value.ur.num = php_ifd_get32u(value, motorola_intel);
+ info_value->value.ur.den = php_ifd_get32u(4+(char *)value, motorola_intel);
+ break;
+
+ case TAG_FMT_SBYTE:
+ info_value->value.i = *(char*)value;
+ break;
+
+ default:
+ /* Standard says more types possible but skip them...
+ * but allow users to handle data if they know how to
+ * So not return but use type UNDEFINED
+ * return;
+ */
+ case TAG_FMT_UNDEFINED:
+ info_value->value.s = emalloc(length+1);
+ memcpy(info_value->value.s,value,length);
+ info_value->value.s[length] = '\0';
+ info_value->length = length; /* not +1 !!! */
+ break;
+
+ case TAG_FMT_SSHORT:
+ info_value->value.i = php_ifd_get16s(value,motorola_intel);
+ break;
+
+ case TAG_FMT_SLONG:
+ info_value->value.i = php_ifd_get32s(value,motorola_intel);
+ break;
+
+ case TAG_FMT_SRATIONAL:
+ info_value->value.sr.num = php_ifd_get32u(value, motorola_intel);
+ info_value->value.sr.den = php_ifd_get32u(4+(char *)value, motorola_intel);
+ break;
+
+ case TAG_FMT_SINGLE:
+ php_error(E_WARNING, "Found value of type single");
+ info_value->value.f = (double)*(float *)value;
+
+ case TAG_FMT_DOUBLE:
+ php_error(E_WARNING, "Found value of type double");
+ info_value->value.d = *(double *)value;
+ break;
+ }
+ info_value->name = emalloc(strlen(name)+1);
+ strcpy(info_value->name, name);
+ image_info->count++;
+}
+/* }}} */
+
+/* {{{ exif_free_image_info
+ Free memory allocated for image_info
+*/
+void exif_free_image_info( image_info_list *image_info)
+{
+ if ( image_info->count) {
+ int i;
+
+ for (i=0; i<image_info->count; i++)
+ {
+ efree((image_info->list)[i].name);
+ if ((image_info->list)[i].format == TAG_FMT_STRING)
+ {
+ efree((image_info->list)[i].value.s);
+ }
+ }
+ efree(image_info->list);
+ }
+}
+/* }}} */
+
+#undef RETURN_SUB_ARRAYS
+
+/* {{{ add_assoc_image_info
+ Add image_info to associative array value.
+*/
+void add_assoc_image_info( pval *value, int sub_array, char *name, image_info_list *image_info)
+{
+ char buffer[64];
+
+ if ( image_info->count)
+ {
+ int i;
+ pval *tmpi;
+
+ if ( sub_array) {
+ MAKE_STD_ZVAL(tmpi);
+ array_init(tmpi);
+ } else {
+ tmpi = value;
+ }
+
+ for(i=0; i<image_info->count; i++)
+ {
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"adding info #%d: '%s:%s'", i, name, image_info->list[i].name);
+ #endif
+ switch(image_info->list[i].format)
+ {
+ default:
+ /* Standard says more types possible but skip them...
+ * but allow users to handle data if they know how to
+ * So not return but use type UNDEFINED
+ * return;
+ */
+ case TAG_FMT_UNDEFINED:
+ add_assoc_stringl(tmpi, image_info->list[i].name, image_info->list[i].value.s, image_info->list[i].length, 1);
+ break;
+
+ case TAG_FMT_STRING:
+ add_assoc_string(tmpi, image_info->list[i].name, image_info->list[i].value.s, 1);
+ break;
+
+ case TAG_FMT_BYTE:
+ case TAG_FMT_USHORT:
+ case TAG_FMT_ULONG:
+ add_assoc_long(tmpi, image_info->list[i].name, image_info->list[i].value.u);
+ break;
+
+ case TAG_FMT_URATIONAL:
+ sprintf(buffer,"%i/%i", image_info->list[i].value.ur.num, image_info->list[i].value.ur.den);
+ add_assoc_string(tmpi, image_info->list[i].name, buffer, 1);
+ break;
+
+ case TAG_FMT_SBYTE:
+ case TAG_FMT_SSHORT:
+ case TAG_FMT_SLONG:
+ add_assoc_long(tmpi, image_info->list[i].name, image_info->list[i].value.i);
+ break;
+
+ case TAG_FMT_SRATIONAL:
+ sprintf(buffer,"%i/%i", image_info->list[i].value.sr.num, image_info->list[i].value.sr.den);
+ add_assoc_string(tmpi, image_info->list[i].name, buffer, 1);
+ break;
+
+ case TAG_FMT_SINGLE:
+ add_assoc_double(tmpi, image_info->list[i].name, image_info->list[i].value.f);
+ break;
+
+ case TAG_FMT_DOUBLE:
+ add_assoc_double(tmpi, image_info->list[i].name, image_info->list[i].value.d);
+ break;
+ }
+ }
+ if ( sub_array) {
+ add_assoc_zval(value, name, tmpi);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ structs
+ 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
+*/
+
+#define FOUND_ANY_TAG 0x00000001
+#define FOUND_IFD0 0x00000002
+#define FOUND_THUMBNAIL 0x00000002
+#define FOUND_COMMENT 0x00000008
+#define FOUND_APP0 0x00000010
+#define FOUND_EXIF 0x00000020
+#define FOUND_FPIX 0x00000040
+#define FOUND_GPS 0x00000080
+#define FOUND_INTEROP 0x00000100
+#define FOUND_APP12 0x00000200
+
+typedef struct {
+ uchar *Data;
+ int Type;
+ size_t Size;
+} section_t;
+
+#define EXIF_MAX_COMMENTS 12
+
+/* EXIF standard defines Copyright as "<Photographer> [ '\0' <Editor> ] ['\0']" */
+#define EXIF_MAX_COPYRIGHT 2
+
+/* This structure is used to store a section of a Jpeg file. */
typedef struct {
char *FileName;
time_t FileDateTime;
size_t FileSize;
image_filetype FileType;
- char *CameraMake;
- char *CameraModel;
- char DateTimeOriginal[20];
- char DateTime[20];
int Height, Width;
int IsColor;
int FlashUsed;
@@ -153,36 +798,39 @@ typedef struct {
float ApertureFNumber;
float Distance;
float CCDWidth;
- char *Description;
char *Comments[EXIF_MAX_COMMENTS];
+ int numComments;
char UserCommentEncoding[12];
char *UserComment;
- int numComments;
double FocalplaneXRes;
double FocalplaneUnits;
int ExifImageWidth;
int MotorolaOrder;
int Orientation;
int ISOspeed;
- char ExifVersion[8];
char *RawCopyright;
int lenRawCopyright;
char *Copyright[EXIF_MAX_COPYRIGHT];
int numCopyrights;
- char *Artist;
- char *Software;
char *Thumbnail;
int ThumbnailSize;
int ThumbnailOffset;
/* Olympus vars */
- int SpecialMode;
+/* int SpecialMode;
int JpegQual;
int Macro;
int DigiZoom;
char SoftwareRelease[16];
char PictInfo[64];
- char CameraId[64];
+ char CameraId[64];*/
/* other */
+ image_info_list ANY;
+ image_info_list IFD0;
+ image_info_list APP1;
+ image_info_list EXIF;
+ image_info_list FPIX;
+ image_info_list GPS;
+ image_info_list INTEROP;
image_info_list APP12;
/* for parsing */
int read_thumbnail;
@@ -195,54 +843,6 @@ typedef struct {
} image_info_type;
/* }}} */
-#define EXIT_FAILURE 1
-#define EXIT_SUCCESS 0
-
-/* {{{ exif_functions[]
- */
-function_entry exif_functions[] = {
- PHP_FE(read_exif_data, NULL)
- PHP_FALIAS(exif_read_data,read_exif_data, NULL)
- PHP_FE(exif_headername, NULL)
- {NULL, NULL, NULL}
-};
-/* }}} */
-
-#define EXIF_VERSION "1.1a $Revision$"
-
-PHP_MINFO_FUNCTION(exif);
-
-/* {{{ exif_module_entry
- */
-zend_module_entry exif_module_entry = {
- STANDARD_MODULE_HEADER,
- "exif",
- exif_functions,
- NULL, NULL,
- NULL, NULL,
- PHP_MINFO(exif),
- EXIF_VERSION,
- STANDARD_MODULE_PROPERTIES
-};
-/* }}} */
-
-#ifdef COMPILE_DL_EXIF
-ZEND_GET_MODULE(exif)
-#endif
-
-/* {{{ PHP_MINFO_FUNCTION
- */
-PHP_MINFO_FUNCTION(exif)
-{
- php_info_print_table_start();
- php_info_print_table_row(2, "EXIF Support", "enabled" );
- php_info_print_table_row(2, "EXIF Version", EXIF_VERSION );
- php_info_print_table_row(2, "Supported EXIF Version", "02100");
- php_info_print_table_row(2, "Supported filetypes", "JPEG,TIFF");
- php_info_print_table_end();
-}
-/* }}} */
-
/* {{{ Markers
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
@@ -292,7 +892,6 @@ PHP_MINFO_FUNCTION(exif)
#define M_COM 0xFE /* COMment */
#define M_TEM 0x01
-
#define PSEUDO_IMAGE_MARKER 0x123; /* Extra value. */
/* }}} */
@@ -387,261 +986,18 @@ static void exif_process_SOFn (image_info_type *ImageInfo, uchar *Data, int mark
}
/* }}} */
-/* {{{ format description defines
- Describes format descriptor
-*/
-static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
-#define NUM_FORMATS 12
-
-#define TAG_FMT_BYTE 1
-#define TAG_FMT_STRING 2
-#define TAG_FMT_USHORT 3
-#define TAG_FMT_ULONG 4
-#define TAG_FMT_URATIONAL 5
-#define TAG_FMT_SBYTE 6
-#define TAG_FMT_UNDEFINED 7
-#define TAG_FMT_SSHORT 8
-#define TAG_FMT_SLONG 9
-#define TAG_FMT_SRATIONAL 10
-#define TAG_FMT_SINGLE 11
-#define TAG_FMT_DOUBLE 12
-
-/*
- Describes tag values
-*/
-
-#define TAG_TIFF_COMMENT 0x00FE
-#define TAG_NEW_SUBFILE 0x00FE
-#define TAG_SUBFILE_TYPE 0x00FF
-
-#define TAG_IMAGEWIDTH 0x0100
-#define TAG_IMAGEHEIGHT 0x0101
-#define TAG_BITS_PER_SAMPLE 0x0102
-#define TAG_COMPRESSION 0x0103
-#define TAG_PHOTOMETRIC_INTERPRETATION 0x0106
-#define TAG_TRESHHOLDING 0x0107
-#define TAG_CELL_WIDTH 0x0108
-#define TAG_CELL_HEIGHT 0x0109
-#define TAG_FILL_ORDER 0x010A
-#define TAG_DOCUMENT_NAME 0x010D
-#define TAG_IMAGE_DESCRIPTION 0x010E
-#define TAG_MAKE 0x010F
-#define TAG_MODEL 0x0110
-#define TAG_STRIP_OFFSETS 0x0111
-#define TAG_ORIENTATION 0x0112
-#define TAG_SAMPLES_PER_PIXEL 0x0115
-#define TAG_ROWS_PER_STRIP 0x0116
-#define TAG_STRIP_BYTE_COUNTS 0x0117
-#define TAG_MIN_SAMPPLE_VALUE 0x0118
-#define TAG_MAX_SAMPLE_VALUE 0x0119
-#define TAG_X_RESOLUTION 0x011A
-#define TAG_Y_RESOLUTION 0x011B
-#define TAG_PLANAR_CONFIGURATION 0x011C
-#define TAG_PAGE_NAME 0x011D
-#define TAG_X_POSITION 0x011E
-#define TAG_Y_POSITION 0x011F
-#define TAG_FREE_OFFSETS 0x0120
-#define TAG_FREE_BYTE_COUNTS 0x0121
-#define TAG_GRAY_RESPONSE_UNIT 0x0122
-#define TAG_GRAY_RESPONSE_CURVE 0x0123
-#define TAG_RESOLUTION_UNIT 0x0128
-#define TAG_PAGE_NUMBER 0x0129
-#define TAG_TRANSFER_FUNCTION 0x012D
-#define TAG_SOFTWARE 0x0131
-#define TAG_DATETIME 0x0132
-#define TAG_ARTIST 0x013B
-#define TAG_HOST_COMPUTER 0x013C
-#define TAG_PREDICATOR 0x013D
-#define TAG_WHITE_POINT 0x013E
-#define TAG_PRIMARY_CHROMATICITIES 0x013F
-#define TAG_COLOR_MAP 0x0140
-#define TAG_HALFTONE_HINTS 0x0141
-#define TAG_TILE_WIDTH 0x0142
-#define TAG_TILE_LENGTH 0x0143
-#define TAG_TILE_OFFSETS 0x0144
-#define TAG_TILE_BYTE_COUNTS 0x0145
-#define TAG_INK_SETMPUTER 0x014C
-#define TAG_NUMBER_OF_INKS 0x014E
-#define TAG_INK_NAMES 0x014D
-#define TAG_DOT_RANGE 0x0150
-#define TAG_TARGET_PRINTER 0x0151
-#define TAG_EXTRA_SAMPLE 0x0152
-#define TAG_SAMPLE_FORMAT 0x0153
-#define TAG_S_MIN_SAMPLE_VALUE 0x0154
-#define TAG_S_MAX_SAMPLE_VALUE 0x0155
-#define TAG_TRANSFER_RANGE 0x0156
-
-#define TAG_JPEG_PROC 0x0200
-#define TAG_JPEG_INTERCHANGE_FORMAT 0x0201
-#define TAG_JPEG_INTERCHANGE_F_LEN 0x0202
-#define TAG_JPEG_RESTART_INTERVAL 0x0203
-#define TAG_JPEG_LOSSLESS_PREDICTOR 0x0205
-#define TAG_JPEG_POINT_TRANSFORMS 0x0206
-#define TAG_JPEG_Q_TABLES 0x0207
-#define TAG_JPEG_DC_TABLES 0x0208
-#define TAG_JPEG_AC_TABLES 0x0209
-#define TAG_YCC_COEFFICIENTS 0x0211
-#define TAG_YCC_SUB_SAMPLING 0x0212
-#define TAG_YCC_POSITIONING 0x0213
-#define TAG_REFERENCE_BLACK_WHITE 0x0214
-
-/* 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_EXIF_IFD_POINTER 0x8769
-#define TAG_GPS_IFD_POINTER 0x8825
-#define TAG_ISOSPEED 0x8827
-
-#define TAG_EXIFVERSION 0x9000
-#define TAG_SHUTTERSPEED 0x9201
-#define TAG_APERTURE 0x9202
-#define TAG_DATETIME_ORIGINAL 0x9003
-#define TAG_MAXAPERTURE 0x9205
-#define TAG_SUBJECT_DISTANCE 0x9206
-#define TAG_LIGHT_SOURCE 0x9208
-#define TAG_FLASH 0x9209
-#define TAG_FOCALLENGTH 0x920A
-#define TAG_MARKER_NOTE 0x927C
-#define TAG_USERCOMMENT 0x9286
-
-
-#define TAG_FLASH_PIX_VERSION 0xA000
-#define TAG_COLOR_SPACE 0xA001
-#define TAG_COMP_IMAGEWIDTH 0xA002 /* compressed images only */
-#define TAG_COMP_IMAGEHEIGHT 0xA003
-#define TAG_INTEROP_IFD_POINTER 0xA005 /* IFD pointer */
-#define TAG_FOCALPLANEXRES 0xA20E
-#define TAG_FOCALPLANEUNITS 0xA210
-
-/*
- */
-#define PMI_BLACK_IS_ZERO 0
-#define PMI_WHITE_IS_ZERO 1
-#define PMI_RGB 2
-#define PMI_PALETTE_COLOR 3
-#define PMI_TRANSPARENCY_MASK 4
-#define PMI_SEPARATED 5
-#define PMI_YCBCR 6
-#define PMI_CIELAB 8
-
-/* }}} */
-
-/* {{{ TabTable[]
- */
-static const struct {
- unsigned short Tag;
- char *Desc;
-} TagTable[] = {
- { 0x00FE, "Comment"},
- { 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"},
- { 0x828D, "CFARepeatPatternDim"},
- { 0x828E, "CFAPattern"},
- { 0x828F, "BatteryLevel"},
- { 0x8298, "Copyright"},
- { 0x829A, "ExposureTime"},
- { 0x829D, "FNumber"},
- { 0x83BB, "IPTC/NAA"},
- { 0x8769, "Exif_IFD_Pointer"},
- { 0x8773, "InterColorProfile"},
- { 0x8822, "ExposureProgram"},
- { 0x8824, "SpectralSensitivity"},
- { 0x8825, "GPS_IFD_Pointer"},
- { 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} /* Important for exif_get_headername() */
-} ;
-/* }}} */
-
static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart, char *OffsetBase, unsigned IFDlength);
-/* {{{ exif_get_headername
+/* {{{ exif_get_tagname
Get headername for tag_num or NULL if not defined */
-char * exif_get_headername(int tag_num)
+char * exif_get_tagname(int tag_num)
{
int i,t;
for (i=0;;i++) {
if ( (t=TagTable[i].Tag) == tag_num || !t) return TagTable[i].Desc;
}
- return NULL;
+ return "";
}
/* }}} */
@@ -712,7 +1068,7 @@ PHP_FUNCTION(exif_headername)
}
convert_to_long_ex(p_num);
- if ( (szTemp = exif_get_headername(Z_LVAL_PP(p_num))) == NULL) {
+ if ( (szTemp = exif_get_tagname(Z_LVAL_PP(p_num))) == NULL) {
RETURN_BOOL(FALSE);
} else {
RETURN_STRING(szTemp, 1)
@@ -720,139 +1076,45 @@ PHP_FUNCTION(exif_headername)
}
/* }}} */
-/* {{{ php_ifd_get16u
- * Convert a 16 bit unsigned value from file's native byte order */
-static int php_ifd_get16u(void *Short, int MotorolaOrder)
-{
- if (MotorolaOrder) {
- return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
- } else {
- return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
- }
-}
-/* }}} */
-
-/* {{{ php_ifd_get16s
- * Convert a 16 bit signed value from file's native byte order */
-static signed short php_ifd_get16s(void *Short, int motorola_intel)
-{
- return (signed short)php_ifd_get16u(Short, motorola_intel);
-}
-/* }}} */
-
-/* {{{ php_ifd_get32s
- * Convert a 32 bit signed value from file's native byte order */
-static int php_ifd_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 );
- }
-}
-/* }}} */
-
-/* {{{ php_ifd_get32u
- * Convert a 32 bit unsigned value from file's native byte order */
-static unsigned php_ifd_get32u(void *Long, int MotorolaOrder)
-{
- return (unsigned)php_ifd_get32s(Long, MotorolaOrder) & 0xffffffff;
-}
-/* }}} */
-
-/* {{{ exif_convert_any_format
- * Evaluate number, be it int, rational, or float from directory. */
-static double exif_convert_any_format(void *ValuePtr, int Format, int MotorolaOrder)
-{
- double Value;
- Value = 0;
-
- switch(Format) {
- case TAG_FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
- case TAG_FMT_BYTE: Value = *(uchar *)ValuePtr; break;
-
- case TAG_FMT_USHORT: Value = php_ifd_get16u(ValuePtr, MotorolaOrder); break;
- case TAG_FMT_ULONG: Value = php_ifd_get32u(ValuePtr, MotorolaOrder); break;
-
- case TAG_FMT_URATIONAL:
- case TAG_FMT_SRATIONAL:
- {
- int Num, Den;
-
- Num = php_ifd_get32s(ValuePtr, MotorolaOrder);
- Den = php_ifd_get32s(4+(char *)ValuePtr, MotorolaOrder);
- if (Den == 0) {
- Value = 0;
- } else {
- Value = (double)Num/Den;
- }
- break;
- }
-
- case TAG_FMT_SSHORT: Value = (signed short)php_ifd_get16u(ValuePtr, MotorolaOrder); break;
- case TAG_FMT_SLONG: Value = php_ifd_get32s(ValuePtr, MotorolaOrder); break;
-
- /* Not sure if this is correct (never seen float used in Exif format) */
- case TAG_FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
- case TAG_FMT_DOUBLE: Value = *(double *)ValuePtr; break;
- }
- return Value;
-}
-/* }}} */
-
/* {{{ exif_extract_thumbnail
* Grab the thumbnail - by Matt Bonneau */
-static void exif_extract_thumbnail(image_info_type *ImageInfo, char *OffsetBase, unsigned ExifLength) {
+static void exif_extract_thumbnail(image_info_type *ImageInfo, char *offset, unsigned length) {
/* according to exif2.1, the thumbnail is not supposed to be greater than 64K */
- if (ImageInfo->ThumbnailSize > 65536 || ImageInfo->ThumbnailSize < 0) {
- php_error(E_WARNING, "Illegal thumbnail size");
+ if ( ImageInfo->ThumbnailSize >= 65536
+ || ImageInfo->ThumbnailSize <= 0
+ || ImageInfo->ThumbnailOffset <= 0)
+ {
+ php_error(E_WARNING, "Illegal thumbnail size/offset");
return;
}
-
ImageInfo->Thumbnail = emalloc(ImageInfo->ThumbnailSize);
if (!ImageInfo->Thumbnail) {
php_error(E_WARNING, "Could not allocate memory for thumbnail");
return;
} else {
/* Check to make sure we are not going to go past the ExifLength */
- if ((unsigned)(ImageInfo->ThumbnailOffset + ImageInfo->ThumbnailSize) > ExifLength) {
+ if ((unsigned)(ImageInfo->ThumbnailOffset + ImageInfo->ThumbnailSize) > length) {
php_error(E_WARNING, "Thumbnail goes beyond exif header boundary");
return;
} else {
- memcpy(ImageInfo->Thumbnail, OffsetBase + ImageInfo->ThumbnailOffset, ImageInfo->ThumbnailSize);
+ memcpy(ImageInfo->Thumbnail, offset + ImageInfo->ThumbnailOffset, ImageInfo->ThumbnailSize);
}
}
}
/* }}} */
-/* {{{ php_strnlen
- * get length of string if buffer if less than buffer size or buffer size */
-static size_t php_strnlen( char* str, size_t maxlen) {
- size_t len = 0;
-
- if ( str && maxlen && *str) {
- do {
- len++;
- } while ( --maxlen && *(++str));
- }
- return len;
-}
-/* }}} */
-
/* {{{ exif_process_string_raw
* Copy a string in Exif header to a character string returns length of allocated buffer if any. */
-static int exif_process_string_raw(char **pszInfoPtr,char *szValuePtr,size_t ByteCount) {
+static int exif_process_string_raw(char **result,char *value,size_t byte_count) {
/* we cannot use strlcpy - here the problem is that we have to copy NUL
- * chars up to ByteCount, we also have to add a single NUL character to
+ * chars up to byte_count, we also have to add a single NUL character to
* force end of string.
*/
- if (ByteCount) {
- (*pszInfoPtr) = emalloc(ByteCount+1);
- memcpy(*pszInfoPtr, szValuePtr, ByteCount);
- (*pszInfoPtr)[ByteCount] = '\0';
- return ByteCount+1;
+ if (byte_count) {
+ (*result) = emalloc(byte_count+1);
+ memcpy(*result, value, byte_count);
+ (*result)[byte_count] = '\0';
+ return byte_count+1;
}
return 0;
}
@@ -860,18 +1122,18 @@ static int exif_process_string_raw(char **pszInfoPtr,char *szValuePtr,size_t Byt
/* {{{ exif_process_string
* Copy a string in Exif header to a character string returns length of allocated buffer if any. */
-static int exif_process_string(char **pszInfoPtr,char *szValuePtr,size_t ByteCount) {
+static int exif_process_string(char **result,char *value,size_t byte_count) {
/* we cannot use strlcpy - here the problem is that we cannot use strlen to
- * determin length of string and we cannot use strlcpy with len=ByteCount+1
+ * determin length of string and we cannot use strlcpy with len=byte_count+1
* because then we might get into an EXCEPTION if we exceed an allocated
* memory page...so we use php_strnlen in conjunction with memcpy and add the NUL
* char.
*/
- if ((ByteCount=php_strnlen(szValuePtr,ByteCount)) > 0) {
- (*pszInfoPtr) = emalloc(ByteCount+1);
- memcpy(*pszInfoPtr, szValuePtr, ByteCount);
- (*pszInfoPtr)[ByteCount] = '\0';
- return ByteCount+1;
+ if ((byte_count=php_strnlen(value,byte_count)) > 0) {
+ (*result) = emalloc(byte_count+1);
+ memcpy(*result, value, byte_count);
+ (*result)[byte_count] = '\0';
+ return byte_count+1;
}
return 0;
}
@@ -927,210 +1189,177 @@ static int exif_process_user_comment(char **pszInfoPtr,char *szEncoding,char *sz
}
/* }}} */
-/* {{{ char_dump
+/* {{{ exif_char_dump
* Do not use! This is a debug function... */
#ifdef EXIF_DEBUG
-static unsigned char* char_dump( unsigned char * Addr, int Len)
+static unsigned char* exif_char_dump( unsigned char * addr, int len)
{
- static unsigned char Buf[1024+1];
- int i,p=0;
+ static unsigned char buf[1024+1];
+ int i, p=0;
- for(i=0;i<Len&&p<sizeof(Buf);i++)
+ for(i=0; i<len && p<sizeof(buf); i++)
{
- if ( i%64==0) Buf[p++] = '\n';
- if (Addr[i]>=32)
+ if ( i%64==0) buf[p++] = '\n';
+ if (*addr>=32)
{
- Buf[p++] = Addr[i];
+ buf[p++] = *addr;
}
else
{
- Buf[p++] = '?';
+ buf[p++] = '?';
}
+ addr++;
}
- Buf[sizeof(Buf)-1]=0;
- return Buf;
+ buf[sizeof(buf)-1]=0;
+ return buf;
}
#endif
/* }}} */
/* {{{ exif_process_IFD_TAG
* Process one of the nested IFDs directories. */
-static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *DirEntry, char *OffsetBase, size_t IFDlength, int ReadNextIFD)
+static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, int ReadNextIFD)
{
int l;
- int Tag, Format, Components;
- char *ValuePtr;
- size_t ByteCount;
- unsigned OffsetVal;
+ int tag, format, components;
+ char *value_ptr;
+ size_t byte_count;
+ unsigned offset_val;
- Tag = php_ifd_get16u(DirEntry, ImageInfo->MotorolaOrder);
- Format = php_ifd_get16u(DirEntry+2, ImageInfo->MotorolaOrder);
- Components = php_ifd_get32u(DirEntry+4, ImageInfo->MotorolaOrder);
+ tag = php_ifd_get16u(dir_entry, ImageInfo->MotorolaOrder);
+ format = php_ifd_get16u(dir_entry+2, ImageInfo->MotorolaOrder);
+ components = php_ifd_get32u(dir_entry+4, ImageInfo->MotorolaOrder);
- if ((Format-1) >= NUM_FORMATS) {
+ if ((format-1) >= NUM_FORMATS) {
/* (-1) catches illegal zero case as unsigned underflows to positive large. */
php_error(E_WARNING, "Illegal format code in IFD");
return;
}
- ByteCount = Components * php_tiff_bytes_per_format[Format];
+ byte_count = components * php_tiff_bytes_per_format[format];
- if (ByteCount > 4) {
- OffsetVal = php_ifd_get32u(DirEntry+8, ImageInfo->MotorolaOrder);
+ if (byte_count > 4) {
+ offset_val = php_ifd_get32u(dir_entry+8, ImageInfo->MotorolaOrder);
/* If its bigger than 4 bytes, the dir entry contains an offset. */
- if (OffsetVal+ByteCount > IFDlength) {
- /* Bogus pointer offset and / or bytecount value */
- php_error(E_WARNING, "Illegal pointer offset(x%04X + x%04X > x%04X) in IFD for Tag(x%04X=%s): ", OffsetVal, ByteCount, IFDlength, Tag, exif_get_headername(Tag));
+ if (offset_val+byte_count > IFDlength) {
+ /* Bogus pointer offset and / or byte_count value */
+ php_error(E_WARNING, "Illegal pointer offset(x%04X + x%04X > x%04X) in IFD for Tag(x%04X=%s): ", offset_val, byte_count, IFDlength, tag, exif_get_tagname(tag));
return;
}
- ValuePtr = OffsetBase+OffsetVal;
+ value_ptr = offset_base+offset_val;
} else {
/* 4 bytes or less and value is in the dir entry itself */
- ValuePtr = DirEntry+8;
+ value_ptr = dir_entry+8;
}
/* Extract useful components of IFD */
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"process tag(x%04x=%s,@x%04X+%i): %s", Tag, exif_get_headername(Tag), ValuePtr-OffsetBase, ByteCount, Format==TAG_FMT_STRING?(ValuePtr?ValuePtr:"<no data>"):"<no string>");
+ php_error(E_NOTICE,"process tag(x%04x=%s,@x%04X+%i): %s", tag, exif_get_tagname(tag), value_ptr-offset_base, byte_count, format==TAG_FMT_STRING?(value_ptr?value_ptr:"<no data>"):"<no string>");
#endif
- switch(Tag) {
- case TAG_MAKE:
- exif_process_string(&ImageInfo->CameraMake,ValuePtr,ByteCount);
- break;
-
- case TAG_MODEL:
- exif_process_string(&ImageInfo->CameraModel,ValuePtr,ByteCount);
- break;
-
- case TAG_EXIFVERSION:
- strncpy(ImageInfo->ExifVersion, ValuePtr, 4);
- ImageInfo->ExifVersion[4] = '\0';
- break;
-
+ switch(tag) {
case TAG_COPYRIGHT:
- if (exif_process_string_raw(&ImageInfo->RawCopyright,ValuePtr,ByteCount)) {
+ if (exif_process_string_raw(&ImageInfo->RawCopyright,value_ptr,byte_count)) {
l = strlen(ImageInfo->RawCopyright);
} else {
l = 0;
}
- ImageInfo->lenRawCopyright = ByteCount;
- if ( ImageInfo->numCopyrights==0 && ByteCount>1 && l<ByteCount-1) {
- exif_process_string(&((ImageInfo->Copyright)[ImageInfo->numCopyrights++]), ValuePtr, l);
- exif_process_string(&((ImageInfo->Copyright)[ImageInfo->numCopyrights++]), ValuePtr+l+1, ByteCount-l-1);
+ ImageInfo->lenRawCopyright = byte_count;
+ if ( ImageInfo->numCopyrights==0 && byte_count>1 && l<byte_count-1) {
+ exif_process_string(&((ImageInfo->Copyright)[ImageInfo->numCopyrights++]), value_ptr, l);
+ exif_process_string(&((ImageInfo->Copyright)[ImageInfo->numCopyrights++]), value_ptr+l+1, byte_count-l-1);
}
break;
- case TAG_ARTIST:
- exif_process_string(&ImageInfo->Artist,ValuePtr,ByteCount);
- break;
-
- case TAG_SOFTWARE:
- exif_process_string(&ImageInfo->Software,ValuePtr,ByteCount);
- break;
-
- case TAG_ORIENTATION:
- ImageInfo->Orientation = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
-
- case TAG_ISOSPEED:
- ImageInfo->ISOspeed = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
-
- case TAG_DATETIME:
- strlcpy(ImageInfo->DateTime, ValuePtr, sizeof(ImageInfo->DateTime));
- break;
-
- case TAG_DATETIME_ORIGINAL:
- strlcpy(ImageInfo->DateTimeOriginal, ValuePtr, sizeof(ImageInfo->DateTimeOriginal));
- break;
-
- case TAG_IMAGE_DESCRIPTION:
- exif_process_string(&ImageInfo->Description,ValuePtr,ByteCount);
- break;
+/* case TAG_ORIENTATION:
+ ImageInfo->Orientation = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
+ break;*/
+/* case TAG_ISOSPEED:
+ ImageInfo->ISOspeed = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
+ break;*/
case TAG_USERCOMMENT:
- exif_process_user_comment(&(ImageInfo->UserComment),ImageInfo->UserCommentEncoding,ValuePtr,ByteCount);
+ exif_process_user_comment(&(ImageInfo->UserComment),ImageInfo->UserCommentEncoding,value_ptr,byte_count);
break;
- case TAG_TIFF_COMMENT:
- /* this is only a comment if type is string! */
- if (Format == TAG_FMT_STRING) {
+ /* this is only a comment if type is string! */
+/* case TAG_TIFF_COMMENT:
+ if (format == TAG_FMT_STRING) {
php_error(E_WARNING,"Found TIFF Comment with wrong TAG 0x00FE");
if (ImageInfo->numComments < EXIF_MAX_COMMENTS) {
- if (exif_process_string(&((ImageInfo->Comments)[ImageInfo->numComments]),ValuePtr,ByteCount)) {
+ if (exif_process_string(&((ImageInfo->Comments)[ImageInfo->numComments]),value_ptr,byte_count)) {
ImageInfo->numComments++;
}
}
}
- break;
+ break;*/
#ifdef EXIF_DEBUG
/*case TAG_MARKER_NOTE:
- * php_error(E_NOTICE,char_dump(ValuePtr,ByteCount));
+ * php_error(E_NOTICE,exif_char_dump(value_ptr,byte_count));
* break;
*/
#endif
- 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)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
+ /* Simplest way of expressing aperture, so I trust it the most.
+ (overwrite previously computd value if there is one) */
+/* case TAG_FNUMBER:
+ ImageInfo->ApertureFNumber = (float)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
+ break;*/
+ /* More relevant info always comes earlier, so only use this field if we don't
+ have appropriate aperture information yet. */
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(exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder)*log(2)*0.5);
+ = (float)exp(exif_convert_any_format(value_ptr, 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)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
+ /* Nice digital cameras actually save the focal length as a function
+ of how farthey are zoomed in. */
+/* case TAG_FOCALLENGTH:
+ ImageInfo->FocalLength = (float)exif_convert_any_format(value_ptr, 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)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
+ /* Inidcates the distacne the autofocus camera is focused to.
+ Tends to be less accurate as distance increases. */
+/* case TAG_SUBJECT_DISTANCE:
+ ImageInfo->Distance = (float)exif_convert_any_format(value_ptr, 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)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
+ /* Simplest way of expressing exposure time, so I trust it most.
+ (overwrite previously computd value if there is one) */
+/* case TAG_EXPOSURETIME:
+ ImageInfo->ExposureTime = (float)exif_convert_any_format(value_ptr, 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(exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder)*log(2)));
+ = (float)(1/exp(exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder)*log(2)));
}
break;
- case TAG_FLASH:
- if (exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder)) {
+/* case TAG_FLASH:
+ if (exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder)) {
ImageInfo->FlashUsed = 1;
}
- break;
+ break;*/
case TAG_COMP_IMAGEWIDTH:
- ImageInfo->ExifImageWidth = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
+ ImageInfo->ExifImageWidth = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
break;
- case TAG_FOCALPLANEXRES:
- ImageInfo->FocalplaneXRes = exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder);
- break;
+/* case TAG_FOCALPLANEXRES:
+ ImageInfo->FocalplaneXRes = exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
+ break;*/
case TAG_FOCALPLANEUNITS:
- switch((int)exif_convert_any_format(ValuePtr, Format, ImageInfo->MotorolaOrder)) {
+ switch((int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder)) {
case 1: ImageInfo->FocalplaneUnits = 25.4; break; /* inch */
case 2:
/* According to the information I was using, 2 measn meters.
@@ -1145,48 +1374,31 @@ static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *DirEntry, cha
}
break;
- case TAG_LIGHT_SOURCE:
- /* Rarely set or useful. */
- break;
-
- case TAG_SPECIALMODE:
- ImageInfo->SpecialMode = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->SpecialMode);
- break;
-
- case TAG_JPEGQUAL: /* I think that this is a pointer to the thumbnail - let's see */
- ImageInfo->ThumbnailOffset = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->ThumbnailOffset);
-
- /* see if we know the size */
- if (ImageInfo->ThumbnailSize && ImageInfo->read_thumbnail) {
- exif_extract_thumbnail(ImageInfo, OffsetBase, IFDlength);
- }
- /*ImageInfo->JpegQual = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->JpegQual);*/
+/*
+ case TAG_OLYMPUS_SPECIALMODE:
+ ImageInfo->SpecialMode = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
+ break;*
+ case TAG_OLYMPUS_DIGIZOOM:
+ ImageInfo->DigiZoom = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
break;
-
- case TAG_MACRO: /* I think this is the size of the Thumbnail */
- ImageInfo->ThumbnailSize = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->ThumbnailSize);
-
- /* see if we have the offset */
- if (ImageInfo->ThumbnailOffset && ImageInfo->read_thumbnail) {
- exif_extract_thumbnail(ImageInfo, OffsetBase, IFDlength);
- }
- /*ImageInfo->Macro = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->Macro);*/
+ case TAG_OLYMPUS_SOFTWARERELEASE:
+ strlcpy(ImageInfo->SoftwareRelease, value_ptr, sizeof(ImageInfo->SoftwareRelease));
break;
-
- case TAG_DIGIZOOM:
- ImageInfo->DigiZoom = (int)exif_convert_any_format(ValuePtr, Format, ImageInfo->DigiZoom);
+ case TAG_OLYMPUS_PICTINFO:
+ strlcpy(ImageInfo->PictInfo, value_ptr, sizeof(ImageInfo->PictInfo));
break;
-
- case TAG_SOFTWARERELEASE:
- strlcpy(ImageInfo->SoftwareRelease, ValuePtr, sizeof(ImageInfo->SoftwareRelease));
+ case TAG_OLYMPUS_CAMERAID:
+ strlcpy(ImageInfo->CameraId, value_ptr, sizeof(ImageInfo->CameraId));
break;
-
- case TAG_PICTINFO:
- strlcpy(ImageInfo->PictInfo, ValuePtr, sizeof(ImageInfo->PictInfo));
+*/
+ case TAG_JPEG_INTERCHANGE_FORMAT:
+ ImageInfo->ThumbnailOffset = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
break;
- case TAG_CAMERAID:
- strlcpy(ImageInfo->CameraId, ValuePtr, sizeof(ImageInfo->CameraId));
+ case TAG_JPEG_INTERCHANGE_FORMAT_LEN:
+ ImageInfo->ThumbnailSize = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
+ /* no need to check for offset here: Exif says values have to be stored in tag order */
+ exif_extract_thumbnail(ImageInfo, offset_base, IFDlength);
break;
case TAG_EXIF_IFD_POINTER:
@@ -1194,27 +1406,40 @@ static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *DirEntry, cha
case TAG_INTEROP_IFD_POINTER:
if ( ReadNextIFD) {
char *SubdirStart;
-
- switch(Tag) {
+ switch(tag) {
case TAG_EXIF_IFD_POINTER:
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"found EXIF");
+ #endif
ImageInfo->sections_found |= FOUND_EXIF;
break;
case TAG_GPS_IFD_POINTER:
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"found GPS");
+ #endif
ImageInfo->sections_found |= FOUND_GPS;
break;
case TAG_INTEROP_IFD_POINTER:
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"found INTEROPERABILITY");
+ #endif
ImageInfo->sections_found |= FOUND_INTEROP;
- break;
+ return;
+/* break;*/
}
- SubdirStart = OffsetBase + php_ifd_get32u(ValuePtr, ImageInfo->MotorolaOrder);
- if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+IFDlength) {
+ SubdirStart = offset_base + php_ifd_get32u(value_ptr, ImageInfo->MotorolaOrder);
+ if (SubdirStart < offset_base || SubdirStart > offset_base+IFDlength) {
php_error(E_WARNING, "Illegal IFD Pointer");
return;
}
- exif_process_IFD_in_JPEG(ImageInfo, SubdirStart, OffsetBase, IFDlength);
+ exif_process_IFD_in_JPEG(ImageInfo, SubdirStart, offset_base, IFDlength);
/* continue? */
}
- break;
+ break;
+
+ default:
+ exif_add_image_info( &ImageInfo->ANY, exif_get_tagname(tag), tag, format, byte_count, value_ptr, ImageInfo->MotorolaOrder);
+ break;
}
}
/* }}} */
@@ -1228,7 +1453,7 @@ static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart,
int NextDirOffset;
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"exif_process_IFD(%d=x%04X)", IFDlength, IFDlength);
+ php_error(E_NOTICE,"exif_process_IFD_in_JPEG(%d=x%04X)", IFDlength, IFDlength);
#endif
ImageInfo->sections_found |= FOUND_IFD0;
@@ -1254,7 +1479,12 @@ static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart,
php_error(E_WARNING, "Illegal directory offset");
return;
}
+ /* That is the IFD for the first thumbnail
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"expect next IFD to be thumbnail");
+ #endif
exif_process_IFD_in_JPEG(ImageInfo, OffsetBase + NextDirOffset, OffsetBase, IFDlength);
+ */
}
}
/* }}} */
@@ -1294,7 +1524,7 @@ static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf,
exif_process_IFD_in_JPEG(ImageInfo, CharBuf+8, CharBuf, length-14);
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"exif_process_IFD, done");
+ php_error(E_NOTICE,"exif_process_TIFF_in_JPEG, done");
#endif
/* MB: This is where I will make my attempt to get the tumbnail */
@@ -1323,40 +1553,23 @@ static void exif_process_APP1(image_info_type *ImageInfo, char *CharBuf, unsigne
}
/* }}} */
-#define ADD_IMAGE_INFO(_type_, _name_, _value_, _value_strlen_) \
- ImageInfo->_type_.list = erealloc(ImageInfo->_type_.list,(ImageInfo->_type_.count+1)*sizeof(image_info_type)); \
- ((ImageInfo->_type_.list)[ImageInfo->_type_.count]).name = emalloc(strlen(_name_)+1); \
- strcpy(((ImageInfo->_type_.list)[ImageInfo->_type_.count]).name, _name_); \
- ((ImageInfo->_type_.list)[ImageInfo->_type_.count]).value = emalloc(_value_strlen_+1); \
- strlcpy(((ImageInfo->_type_.list)[ImageInfo->_type_.count++]).value, _value_, _value_strlen_+1);
-
/* {{{ exif_process_APP12
Process an JPEG APP12 block marker used by OLYMPUS
*/
-static void exif_process_APP12(image_info_type *ImageInfo, char *CharBuf, unsigned int length)
+static void exif_process_APP12(image_info_type *ImageInfo, char *buffer, unsigned int length)
{
- int l1, l2;
+ int l1, l2=0;
- if ( (l1 = php_strnlen(CharBuf+2,length-2)) > 0) {
- #ifdef EXIF_DEBUG
- php_error(E_NOTICE,"process section APP12: l1=%d",l1);
- #endif
- ADD_IMAGE_INFO(APP12,"Company",CharBuf+2,l1)
+ if ( (l1 = php_strnlen(buffer+2,length-2)) > 0) {
+ exif_add_image_info( &ImageInfo->APP12, "Company", 1, TAG_FMT_STRING, l1, buffer+2, ImageInfo->MotorolaOrder);
if ( length > 2+l1+1) {
- l2 = php_strnlen(CharBuf+2+l1+1,length-2-l1+1);
- #ifdef EXIF_DEBUG
- php_error(E_NOTICE,"process section APP12: l2=%d",l2);
- #endif
- ImageInfo->APP12.list = erealloc(ImageInfo->APP12.list,(ImageInfo->APP12.count+1)*sizeof(image_info_type));
- (ImageInfo->APP12.list)[ImageInfo->APP12.count].name = emalloc(strlen("Info")+1);
- strcpy((ImageInfo->APP12.list)[ImageInfo->APP12.count].name, "Info");
- (ImageInfo->APP12.list)[ImageInfo->APP12.count].value = emalloc(l2+1);
- strlcpy((ImageInfo->APP12.list)[ImageInfo->APP12.count++].value, CharBuf+2+l1+1, l2+1);
+ l2 = php_strnlen(buffer+2+l1+1,length-2-l1+1);
+ exif_add_image_info( &ImageInfo->APP12, "Info", 1, TAG_FMT_STRING, l2, buffer+2+l1+1, ImageInfo->MotorolaOrder);
}
ImageInfo->sections_found |= FOUND_APP12;
}
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"process section APP12 done");
+ php_error(E_NOTICE,"process section APP12 with l1=%d, l2=%d done", l1, l2);
#endif
}
/* }}} */
@@ -1647,7 +1860,7 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, si
}
entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->MotorolaOrder);
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"Found other IFD: %s at x%04X", exif_get_headername(entry_tag), entry_offset);
+ php_error(E_NOTICE,"Found other IFD: %s at x%04X", exif_get_tagname(entry_tag), entry_offset);
#endif
exif_process_IFD_in_TIFF(ImageInfo,infile,entry_offset);
} else {
@@ -1747,13 +1960,8 @@ int php_exif_discard_imageinfo(image_info_type *ImageInfo)
int i;
if (ImageInfo->FileName) efree(ImageInfo->FileName);
- if (ImageInfo->CameraMake) efree(ImageInfo->CameraMake);
- if (ImageInfo->CameraModel) efree(ImageInfo->CameraModel);
- if (ImageInfo->Software) efree(ImageInfo->Software);
if (ImageInfo->UserComment) efree(ImageInfo->UserComment);
- if (ImageInfo->Description) efree(ImageInfo->Description);
if (ImageInfo->Thumbnail) efree(ImageInfo->Thumbnail);
- if (ImageInfo->Artist) efree(ImageInfo->Artist);
if (ImageInfo->RawCopyright) efree(ImageInfo->RawCopyright);
if (ImageInfo->numCopyrights) {
for(i=0; i<ImageInfo->numCopyrights; i++) {
@@ -1767,13 +1975,14 @@ int php_exif_discard_imageinfo(image_info_type *ImageInfo)
}
ImageInfo->numComments = 0;
}
- if ( ImageInfo->APP12.count) {
- for (i=0; i<ImageInfo->APP12.count; i++) {
- efree((ImageInfo->APP12.list)[i].name);
- efree((ImageInfo->APP12.list)[i].value);
- }
- efree(ImageInfo->APP12.list);
- }
+ exif_free_image_info( &(ImageInfo->ANY));
+ exif_free_image_info( &(ImageInfo->IFD0));
+ exif_free_image_info( &(ImageInfo->APP1));
+ exif_free_image_info( &(ImageInfo->EXIF));
+ exif_free_image_info( &(ImageInfo->FPIX));
+ exif_free_image_info( &(ImageInfo->GPS));
+ exif_free_image_info( &(ImageInfo->INTEROP));
+ exif_free_image_info( &(ImageInfo->APP12));
memset(ImageInfo, 0, sizeof(*ImageInfo));
return TRUE;
}
@@ -1807,10 +2016,12 @@ int php_exif_read_file(image_info_type *ImageInfo, char *FileName, int read_thum
ImageInfo->Distance = 0;
ImageInfo->CCDWidth = 0;
ImageInfo->FlashUsed = -1;
+/*
ImageInfo->SpecialMode = -1;
ImageInfo->JpegQual = -1;
ImageInfo->Macro = -1;
ImageInfo->DigiZoom = -1;
+*/
ImageInfo->read_thumbnail = read_thumbnail;
ImageInfo->read_all = read_all;
@@ -1878,24 +2089,26 @@ PHP_FUNCTION(read_exif_data)
strlcpy(sections_str,Z_STRVAL_PP(p_sections_needed),sizeof(sections_str)-1/*!!*/);
sections_str[strlen(sections_str)+1] = '\0';
sections_str[strlen(sections_str)+0] = ',';
- sections_needed |= strstr(sections_str,"ANY_TAG,") ? FOUND_ANY_TAG : 0;
- sections_needed |= strstr(sections_str,"IFD0,") ? FOUND_IFD0 : 0;
- sections_needed |= strstr(sections_str,"COMMENT,") ? FOUND_COMMENT : 0;
- sections_needed |= strstr(sections_str,"EXIF,") ? FOUND_EXIF : 0;
- sections_needed |= strstr(sections_str,"GPS,") ? FOUND_GPS : 0;
- sections_needed |= strstr(sections_str,"INTEROP,") ? FOUND_INTEROP : 0;
- sections_needed |= strstr(sections_str,"FPIX,") ? FOUND_FPIX : 0;
- sections_needed |= strstr(sections_str,"APP12,") ? FOUND_APP12 : 0;
+ sections_needed |= strstr(sections_str,"ANY_TAG,") ? FOUND_ANY_TAG : 0;
+ sections_needed |= strstr(sections_str,"IFD0,") ? FOUND_IFD0 : 0;
+ sections_needed |= strstr(sections_str,"THUMBNAIL,") ? FOUND_THUMBNAIL : 0;
+ sections_needed |= strstr(sections_str,"COMMENT,") ? FOUND_COMMENT : 0;
+ sections_needed |= strstr(sections_str,"EXIF,") ? FOUND_EXIF : 0;
+ sections_needed |= strstr(sections_str,"GPS,") ? FOUND_GPS : 0;
+ sections_needed |= strstr(sections_str,"INTEROP,") ? FOUND_INTEROP : 0;
+ sections_needed |= strstr(sections_str,"FPIX,") ? FOUND_FPIX : 0;
+ sections_needed |= strstr(sections_str,"APP12,") ? FOUND_APP12 : 0;
#ifdef EXIF_DEBUG
- sprintf(sections_str,"%s%s%s%s%s%s%s%s",
- (sections_needed&FOUND_ANY_TAG) ? "ANY_TAG," : "",
- (sections_needed&FOUND_IFD0) ? "IFD0," : "",
- (sections_needed&FOUND_COMMENT) ? "COMMENT," : "",
- (sections_needed&FOUND_EXIF) ? "EXIF," : "",
- (sections_needed&FOUND_GPS) ? "GPS," : "",
- (sections_needed&FOUND_INTEROP) ? "INTEROP," : "",
- (sections_needed&FOUND_FPIX) ? "FPIX," : "",
- (sections_needed&FOUND_APP12) ? "APP12," : ""
+ sprintf(sections_str,"%s%s%s%s%s%s%s%s%s",
+ (sections_needed&FOUND_ANY_TAG) ? "ANY_TAG," : "",
+ (sections_needed&FOUND_IFD0) ? "IFD0," : "",
+ (sections_needed&FOUND_IFD0) ? "THUMBNAIL," : "",
+ (sections_needed&FOUND_COMMENT) ? "COMMENT," : "",
+ (sections_needed&FOUND_EXIF) ? "EXIF," : "",
+ (sections_needed&FOUND_GPS) ? "GPS," : "",
+ (sections_needed&FOUND_INTEROP) ? "INTEROP," : "",
+ (sections_needed&FOUND_FPIX) ? "FPIX," : "",
+ (sections_needed&FOUND_APP12) ? "APP12," : ""
);
if ( (i=strlen(sections_str)) > 0) sections_str[i-1] = '\0'; /* skip last ',' */
php_error(E_NOTICE,"Sections needed: %s", sections_str[0] ? sections_str : "None");
@@ -1915,15 +2128,16 @@ PHP_FUNCTION(read_exif_data)
ret = php_exif_read_file(&ImageInfo, Z_STRVAL_PP(p_name), read_thumbnail, read_all TSRMLS_CC);
- sprintf(sections_str,"%s%s%s%s%s%s%s%s",
- (ImageInfo.sections_found&FOUND_ANY_TAG) ? "ANY_TAG," : "",
- (ImageInfo.sections_found&FOUND_IFD0) ? "IFD0," : "",
- (ImageInfo.sections_found&FOUND_COMMENT) ? "COMMENT," : "",
- (ImageInfo.sections_found&FOUND_EXIF) ? "EXIF," : "",
- (ImageInfo.sections_found&FOUND_GPS) ? "GPS," : "",
- (ImageInfo.sections_found&FOUND_INTEROP) ? "INTEROP," : "",
- (ImageInfo.sections_found&FOUND_FPIX) ? "FPIX," : "",
- (ImageInfo.sections_found&FOUND_APP12) ? "APP12," : ""
+ sprintf(sections_str,"%s%s%s%s%s%s%s%s%s",
+ (ImageInfo.sections_found&FOUND_ANY_TAG) ? "ANY_TAG," : "",
+ (ImageInfo.sections_found&FOUND_IFD0) ? "IFD0," : "",
+ (ImageInfo.sections_found&FOUND_COMMENT) ? "THUMBNAIL," : "",
+ (ImageInfo.sections_found&FOUND_COMMENT) ? "COMMENT," : "",
+ (ImageInfo.sections_found&FOUND_EXIF) ? "EXIF," : "",
+ (ImageInfo.sections_found&FOUND_GPS) ? "GPS," : "",
+ (ImageInfo.sections_found&FOUND_INTEROP) ? "INTEROP," : "",
+ (ImageInfo.sections_found&FOUND_FPIX) ? "FPIX," : "",
+ (ImageInfo.sections_found&FOUND_APP12) ? "APP12," : ""
);
if ( (i=strlen(sections_str)) > 0) sections_str[i-1] = '\0'; /* skip last ',' */
#ifdef EXIF_DEBUG
@@ -1952,18 +2166,6 @@ PHP_FUNCTION(read_exif_data)
add_assoc_long(return_value, "Width", ImageInfo.Width);
}
add_assoc_long(return_value, "IsColor", ImageInfo.IsColor);
- if (ImageInfo.CameraMake && ImageInfo.CameraMake[0]) {
- add_assoc_string(return_value, "CameraMake", ImageInfo.CameraMake, 1);
- }
- if (ImageInfo.CameraModel && 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);
- }
- if (ImageInfo.DateTimeOriginal[0]) {
- add_assoc_string(return_value, "DateTime", ImageInfo.DateTimeOriginal, 1);
- }
if(ImageInfo.FlashUsed >= 0) {
add_assoc_long(return_value, "FlashUsed", ImageInfo.FlashUsed);
}
@@ -2008,9 +2210,6 @@ PHP_FUNCTION(read_exif_data)
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.RawCopyright || ImageInfo.numCopyrights) {
if (ImageInfo.RawCopyright && !ImageInfo.numCopyrights && ImageInfo.lenRawCopyright) {
add_assoc_stringl(return_value, "Copyright", ImageInfo.RawCopyright, ImageInfo.lenRawCopyright, 1);
@@ -2024,12 +2223,6 @@ PHP_FUNCTION(read_exif_data)
add_assoc_zval(return_value, "Copyright", tmpi);
}
}
- if (ImageInfo.Artist && ImageInfo.Artist[0]) {
- add_assoc_string(return_value, "Artist", ImageInfo.Artist, 1);
- }
- if (ImageInfo.Software && ImageInfo.Software[0]) {
- add_assoc_string(return_value, "Software", ImageInfo.Software, 1);
- }
if(ImageInfo.numComments) {
if(ImageInfo.numComments==1) {
add_assoc_string(return_value, "Comments", (ImageInfo.Comments)[0], 1);
@@ -2050,53 +2243,32 @@ PHP_FUNCTION(read_exif_data)
add_assoc_string(return_value, "UserCommentEncoding", ImageInfo.UserCommentEncoding, 1);
}
}
- if (ImageInfo.Description) {
- add_assoc_string(return_value, "Description", ImageInfo.Description, 1);
- }
if (ImageInfo.ThumbnailSize) {
add_assoc_long(return_value, "ThumbnailSize", ImageInfo.ThumbnailSize);
}
if(ImageInfo.Thumbnail && ImageInfo.ThumbnailSize) {
add_assoc_stringl(return_value, "Thumbnail", ImageInfo.Thumbnail, ImageInfo.ThumbnailSize, 1);
}
- if(ImageInfo.SpecialMode >= 0) {
- add_assoc_long(return_value, "SpecialMode", ImageInfo.SpecialMode);
- }
- if(ImageInfo.JpegQual >= 0) {
- add_assoc_long(return_value, "JpegQual", ImageInfo.JpegQual);
- }
- if(ImageInfo.Macro >= 0) {
- add_assoc_long(return_value, "Macro", ImageInfo.Macro);
- }
- if(ImageInfo.DigiZoom >= 0) {
- add_assoc_long(return_value, "DigiZoom", ImageInfo.DigiZoom);
- }
- if (ImageInfo.SoftwareRelease[0]) {
- add_assoc_string(return_value, "SoftwareRelease", ImageInfo.SoftwareRelease, 1);
- }
- if (ImageInfo.PictInfo[0]) {
- add_assoc_string(return_value, "PictInfo", ImageInfo.PictInfo, 1);
- }
- if (ImageInfo.CameraId[0]) {
- add_assoc_string(return_value, "CameraId", ImageInfo.CameraId, 1);
- }
+
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"Adding APP12");
+ php_error(E_NOTICE,"adding image infos");
#endif
- if(ImageInfo.APP12.count) {
- pval *tmpi;
- MAKE_STD_ZVAL(tmpi);
- array_init(tmpi);
- for(i=0; i<ImageInfo.APP12.count; i++) {
- add_assoc_string(tmpi, (ImageInfo.APP12.list)[i].name, (ImageInfo.APP12.list)[i].value, 1);
- }
- add_assoc_zval(return_value, "APP12", tmpi);
- }
+ add_assoc_image_info( return_value, 0, "ANY", &(ImageInfo.ANY));
+ add_assoc_image_info( return_value, 0, "IFD0", &(ImageInfo.IFD0));
+ add_assoc_image_info( return_value, 0, "APP1", &(ImageInfo.APP1));
+ add_assoc_image_info( return_value, 0, "EXIF", &(ImageInfo.EXIF));
+ add_assoc_image_info( return_value, 0, "FPIX", &(ImageInfo.FPIX));
+ add_assoc_image_info( return_value, 0, "GPS", &(ImageInfo.GPS));
+ add_assoc_image_info( return_value, 0, "INTEROP", &(ImageInfo.INTEROP));
+ add_assoc_image_info( return_value, 0, "APP12", &(ImageInfo.APP12));
+
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"Discarding info");
#endif
+
php_exif_discard_imageinfo(&ImageInfo);
+
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"read_exif_data done");
#endif