diff options
author | Marcus Boerger <helly@php.net> | 2002-03-05 19:47:19 +0000 |
---|---|---|
committer | Marcus Boerger <helly@php.net> | 2002-03-05 19:47:19 +0000 |
commit | 088450efce4fff7878a75daae93e25c5a1e8c8c6 (patch) | |
tree | 6e2792b12857d0ec071e18bb4a99bd8107b12135 /ext/exif/exif.c | |
parent | 80f121266060fc7c37777005eb6814a54ecb008f (diff) | |
download | php-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.c | 1642 |
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 |