summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Boerger <helly@php.net>2002-03-06 09:31:32 +0000
committerMarcus Boerger <helly@php.net>2002-03-06 09:31:32 +0000
commit0ecd2f0876fc5c9d4ad8ef95acc8162b8fbdae9b (patch)
tree3fbef6b6234edc6e6c7f21beb0cfe54df3f3773a
parentca59cb7cf90b10161b96b8d34d88fd8244e15272 (diff)
downloadphp-git-0ecd2f0876fc5c9d4ad8ef95acc8162b8fbdae9b.tar.gz
-new working thumbnail code
-everything uses new data structures -new function exif_thumbnail #nearly stripped off all jhead code @read_exif_data is now an alias for exif_read_data @ important to differenciate old/new version for tests) @new function exif_tagname returns the names of tags @new function exif_thumbnail extracts embedded thumbnail (Marcus) #switched to internal version 1.2
-rw-r--r--ext/exif/exif.c1273
-rw-r--r--ext/exif/php_exif.h5
2 files changed, 623 insertions, 655 deletions
diff --git a/ext/exif/exif.c b/ext/exif/exif.c
index 00a39ebfbc..ddcceaead2 100644
--- a/ext/exif/exif.c
+++ b/ext/exif/exif.c
@@ -19,10 +19,6 @@
/* $Id$ */
-/* Some parts of the code in this module was borrowed from the public domain
- * jhead.c package with the author's consent.
- */
-
/* ToDos
*
* JIS encoding for comments
@@ -32,7 +28,10 @@
* Create/Remove/Update image thumbnails.
*/
-/* The original header from the jhead.c file was:
+/* Fragments of the code in this module were borrowed from the public domain
+ * jhead.c package with the author's consent.
+ *
+ * The original header from the jhead.c file was:
*
* --------------------------------------------------------------------------
* Program to pull the information out of various types of EFIF digital
@@ -62,7 +61,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.
*/
-/* #undef EXIF_DEBUG /**/
+#undef EXIF_DEBUG /**/
#include "php_exif.h"
#include <math.h>
@@ -84,14 +83,15 @@ typedef unsigned char uchar;
/* {{{ 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)
+ PHP_FE(exif_read_data, NULL)
+ PHP_FALIAS(read_exif_data, exif_read_data, NULL)
+ PHP_FE(exif_tagname, NULL)
+ PHP_FE(exif_thumbnail, NULL)
{NULL, NULL, NULL}
};
/* }}} */
-#define EXIF_VERSION "1.1b $Revision$"
+#define EXIF_VERSION "1.2"
PHP_MINFO_FUNCTION(exif);
@@ -122,7 +122,6 @@ PHP_MINFO_FUNCTION(exif)
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();
}
/* }}} */
@@ -160,6 +159,25 @@ static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}
#define TAG_FMT_SINGLE 11
#define TAG_FMT_DOUBLE 12
+static char *exif_get_tagformat(int format)
+{
+ switch(format) {
+ case TAG_FMT_BYTE: return "BYTE";
+ case TAG_FMT_STRING: return "STRING";
+ case TAG_FMT_USHORT: return "USHORT";
+ case TAG_FMT_ULONG: return "ULONG";
+ case TAG_FMT_URATIONAL: return "URATIONAL";
+ case TAG_FMT_SBYTE: return "SBYTE";
+ case TAG_FMT_UNDEFINED: return "UNDEFINED";
+ case TAG_FMT_SSHORT: return "SSHORT";
+ case TAG_FMT_SLONG: return "SLONG";
+ case TAG_FMT_SRATIONAL: return "SRATIONAL";
+ case TAG_FMT_SINGLE: return "SINGLE";
+ case TAG_FMT_DOUBLE: return "DOUBLE";
+ }
+ return "*Illegal";
+}
+
/* Describes tag values */
#define TAG_TIFF_COMMENT 0x00FE /* SHOUDLNT HAPPEN */
#define TAG_NEW_SUBFILE 0x00FE /* New version of subfile tag */
@@ -172,6 +190,7 @@ static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}
#define TAG_TRESHHOLDING 0x0107
#define TAG_CELL_WIDTH 0x0108
#define TAG_CELL_HEIGHT 0x0109
+#define TAG_STRIP_OFFSETS 0x0111
#define TAG_FILL_ORDER 0x010A
#define TAG_DOCUMENT_NAME 0x010D
#define TAG_IMAGE_DESCRIPTION 0x010E
@@ -268,6 +287,9 @@ static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}
#define TAG_OLYMPUS_CAMERAID 0x0209
/* end Olympus specific tags */
+/* Internal */
+#define TAG_NONE -1 /* note that -1 <> 0xFFFF */
+#define TAG_COMPUTED_VALUE -2
/* Values for TAG_PHOTOMETRIC_INTERPRETATION */
#define PMI_BLACK_IS_ZERO 0
@@ -283,6 +305,7 @@ static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}
/* {{{ TabTable[]
*/
+
static const struct {
unsigned short Tag;
char *Desc;
@@ -415,8 +438,44 @@ static const struct {
{ 0xA217, "SensingMethod"}, /* 0x9217 - - */
{ 0xA300, "FileSource"},
{ 0xA301, "SceneType"},
- { 0, "UndefinedTag"} /* Important for exif_get_tagname() */
+ {TAG_NONE, "no tag value"},
+ {TAG_COMPUTED_VALUE, "computed value"},
+ { 0, ""} /* Important for exif_get_tagname() IF value != "" functionresult is != false */
} ;
+
+/* }}} */
+
+/* {{{ exif_get_tagname
+ Get headername for tag_num or NULL if not defined */
+static char * exif_get_tagname(int tag_num, char *ret)
+{
+ int i,t;
+
+ for (i=0;;i++) {
+ if ( (t=TagTable[i].Tag) == tag_num || !t) {
+ if (ret) {
+ strcpy(ret,TagTable[i].Desc);
+ if ( !t) sprintf(ret,"UndefinedTag:0x%04X", tag_num);
+ return ret;
+ }
+ return TagTable[i].Desc;
+ }
+ }
+ if (ret) {
+ sprintf(ret,"UndefinedTag:0x%04X", tag_num);
+ return ret;
+ }
+ return "";
+}
+/* }}} */
+
+/* {{{ php_ifd_get16m
+ Get 16 bits motorola order (always) for jpeg header stuff.
+*/
+static int php_ifd_get16m(void *value)
+{
+ return (((uchar *)value)[0] << 8) | ((uchar *)value)[1];
+}
/* }}} */
/* {{{ php_ifd_get16u
@@ -510,9 +569,8 @@ static double exif_convert_any_format(void *value, int format, int motorola_inte
}
/* }}} */
-/* {{{ structs
+/* {{{ struct image_info_value, image_info_list
*/
-
#ifndef WORD
#define WORD short
#endif
@@ -536,7 +594,7 @@ typedef struct {
DWORD length;
union {
char *s;
- unsigned int u;
+ unsigned u;
int i;
float f;
double d;
@@ -550,39 +608,153 @@ typedef struct {
int count;
image_info_value *list;
} image_info_list;
+/* }}} */
+
+/* {{{ exif_get_sectionname
+ Returns the name of a section
+*/
+#define SECTION_FILE 0
+#define SECTION_COMPUTED 1
+#define SECTION_ANY_TAG 2
+#define SECTION_IFD0 3
+#define SECTION_THUMBNAIL 4
+#define SECTION_COMMENT 5
+#define SECTION_APP0 6
+#define SECTION_EXIF 7
+#define SECTION_FPIX 8
+#define SECTION_GPS 9
+#define SECTION_INTEROP 10
+#define SECTION_APP12 11
+#define SECTION_COUNT 12
+
+#define FOUND_FILE (1<<SECTION_FILE)
+#define FOUND_COMPUTED (1<<SECTION_COMPUTED)
+#define FOUND_ANY_TAG (1<<SECTION_ANY_TAG)
+#define FOUND_IFD0 (1<<SECTION_IFD0)
+#define FOUND_THUMBNAIL (1<<SECTION_THUMBNAIL)
+#define FOUND_COMMENT (1<<SECTION_COMMENT)
+#define FOUND_APP0 (1<<SECTION_APP0)
+#define FOUND_EXIF (1<<SECTION_EXIF)
+#define FOUND_FPIX (1<<SECTION_FPIX)
+#define FOUND_GPS (1<<SECTION_GPS)
+#define FOUND_INTEROP (1<<SECTION_INTEROP)
+#define FOUND_APP12 (1<<SECTION_APP12)
+
+static char *exif_get_sectionname(int section)
+{
+ switch(section) {
+ case SECTION_FILE: return "FILE";
+ case SECTION_COMPUTED: return "COMPUTED";
+ case SECTION_ANY_TAG: return "ANY_TAG";
+ case SECTION_IFD0: return "IFD0";
+ case SECTION_THUMBNAIL: return "THUMBNAIL";
+ case SECTION_COMMENT: return "COMMENT";
+ case SECTION_APP0: return "APP0";
+ case SECTION_EXIF: return "EXIF";
+ case SECTION_FPIX: return "FPIX";
+ case SECTION_GPS: return "GPS";
+ case SECTION_INTEROP: return "INTEROP";
+ case SECTION_APP12: return "APP12";
+ }
+ return "";
+}
+/* }}} */
-#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_get_sectionlist
+ Return list of sectionnames specified by sectionlist. Return value must be freed
+*/
+static char *exif_get_sectionlist(int sectionlist)
+{
+ int i,len=0;
+ char *sections;
+
+ for(i=0; i<SECTION_COUNT; i++) len += strlen(exif_get_sectionname(i))+2;
+ sections = emalloc(len+1);
+ sections[0] = '\0';
+ len = 0;
+ for(i=0; i<SECTION_COUNT; i++) {
+ if (sectionlist&(1<<i)) {
+ sprintf(sections+len,"%s, ",exif_get_sectionname(i));
+ len = strlen(sections);
+ }
+ }
+ if (len>2) sections[len-2] = '\0';
+ return sections;
+}
+/* }}} */
+/* {{{ struct image_info_type
+ This structure stores Exif header image elements in a simple manner
+ Used to store camera data as extracted from the various ways that it can be
+ stored in a nexif header
+*/
+
+typedef struct {
+ uchar *Data;
+ int Type;
+ size_t Size;
+} section_t;
+
+/* EXIF standard defines Copyright as "<Photographer> [ '\0' <Editor> ] ['\0']" */
+/* 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;
+ int Height, Width;
+ int IsColor;
+
+ float ApertureFNumber;
+ float ExposureTime;
+ double FocalplaneUnits;
+ float CCDWidth;
+ double FocalplaneXRes;
+ int ExifImageWidth;
+ float FocalLength;
+ float Distance;
+
+ int motorola_intel; /* 1 Motorola; 0 Intel */
+
+ char *UserComment;
+ char UserCommentEncoding[12];
+
+ char *Thumbnail;
+ int ThumbnailSize;
+ int ThumbnailOffset;
+ /* other */
+ int sections_found; /* FOUND_<marker> */
+ image_info_list info_list[SECTION_COUNT];
+ /* for parsing */
+ int read_thumbnail;
+ int read_all;
+ /* internal */
+ section_t sections[20];
+ int sections_count;
+} image_info_type;
/* }}} */
/* {{{ 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)
+void exif_add_image_info( image_info_type *image_info, int section_index, char *name, int tag, int format, int length, void* value)
{
- image_info_value *info_value;
- image_info_value *list;
+ image_info_value *info_value, *list;
- list = erealloc(image_info->list,(image_info->count+1)*sizeof(image_info_value));
+ list = erealloc(image_info->info_list[section_index].list,(image_info->info_list[section_index].count+1)*sizeof(image_info_value));
if ( !list) {
- php_error(E_WARNING,"Unable to allocate more memory for data");
+ php_error(E_WARNING,"Cannot allocate memory for all data");
return;
}
+ image_info->info_list[section_index].list = list;
+ image_info->sections_found |= 1<<section_index;
- image_info->list = list;
- info_value = &(image_info->list[image_info->count]);
+ info_value = &image_info->info_list[section_index].list[image_info->info_list[section_index].count];
- info_value->tag = tag;
+ info_value->name = emalloc(strlen(name)+1);
+ strcpy(info_value->name, name);
+
+ info_value->tag = tag;
info_value->format = format;
info_value->length = 1; /* we do not support arrays other than STRING/UNDEFINED */
switch (format) {
@@ -598,16 +770,16 @@ void exif_add_image_info( image_info_list *image_info, char *name, int tag, int
break;
case TAG_FMT_USHORT:
- info_value->value.u = php_ifd_get16u(value,motorola_intel);
+ info_value->value.u = php_ifd_get16u(value,image_info->motorola_intel);
break;
case TAG_FMT_ULONG:
- info_value->value.u = php_ifd_get32u(value,motorola_intel);
+ info_value->value.u = php_ifd_get32u(value,image_info->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);
+ info_value->value.ur.num = php_ifd_get32u(value, image_info->motorola_intel);
+ info_value->value.ur.den = php_ifd_get32u(4+(char *)value, image_info->motorola_intel);
break;
case TAG_FMT_SBYTE:
@@ -620,6 +792,7 @@ void exif_add_image_info( image_info_list *image_info, char *name, int tag, int
* So not return but use type UNDEFINED
* return;
*/
+ info_value->tag = TAG_FMT_UNDEFINED;/* otherwise not freed from memory */
case TAG_FMT_UNDEFINED:
info_value->value.s = emalloc(length+1);
memcpy(info_value->value.s,value,length);
@@ -628,16 +801,16 @@ void exif_add_image_info( image_info_list *image_info, char *name, int tag, int
break;
case TAG_FMT_SSHORT:
- info_value->value.i = php_ifd_get16s(value,motorola_intel);
+ info_value->value.i = php_ifd_get16s(value,image_info->motorola_intel);
break;
case TAG_FMT_SLONG:
- info_value->value.i = php_ifd_get32s(value,motorola_intel);
+ info_value->value.i = php_ifd_get32s(value,image_info->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);
+ info_value->value.sr.num = php_ifd_get32u(value, image_info->motorola_intel);
+ info_value->value.sr.den = php_ifd_get32u(4+(char *)value, image_info->motorola_intel);
break;
case TAG_FMT_SINGLE:
@@ -649,29 +822,31 @@ void exif_add_image_info( image_info_list *image_info, char *name, int tag, int
info_value->value.d = *(double *)value;
break;
}
- info_value->name = emalloc(strlen(name)+1);
- strcpy(info_value->name, name);
- image_info->count++;
+
+ image_info->info_list[section_index].count++;
}
/* }}} */
/* {{{ exif_free_image_info
Free memory allocated for image_info
*/
-void exif_free_image_info( image_info_list *image_info)
+void exif_free_image_info( image_info_type *image_info, int section_index)
{
- if ( image_info->count) {
- int i;
+ int i;
- for (i=0; i<image_info->count; i++)
+ if (image_info->info_list[section_index].count)
+ {
+ for (i=0; i < image_info->info_list[section_index].count; i++)
{
- efree((image_info->list)[i].name);
- if ((image_info->list)[i].format == TAG_FMT_STRING)
+ efree(image_info->info_list[section_index].list[i].name);
+ if ( image_info->info_list[section_index].list[i].format == TAG_FMT_STRING
+ ||image_info->info_list[section_index].list[i].format == TAG_FMT_UNDEFINED
+ )
{
- efree((image_info->list)[i].value.s);
+ efree(image_info->info_list[section_index].list[i].value.s);
}
}
- efree(image_info->list);
+ efree(image_info->info_list[section_index].list);
}
}
/* }}} */
@@ -681,11 +856,12 @@ void exif_free_image_info( image_info_list *image_info)
/* {{{ 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)
+void add_assoc_image_info( pval *value, int sub_array, image_info_type *image_info, int section_index)
{
char buffer[64];
+ image_info_value *info_value;
- if ( image_info->count)
+ if ( image_info->info_list[section_index].count)
{
int i;
pval *tmpi;
@@ -697,12 +873,13 @@ void add_assoc_image_info( pval *value, int sub_array, char *name, image_info_li
tmpi = value;
}
- for(i=0; i<image_info->count; i++)
+ for(i=0; i<image_info->info_list[section_index].count; i++)
{
+ info_value = &image_info->info_list[section_index].list[i];
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"adding info #%d: '%s:%s'", i, name, image_info->list[i].name);
+ /* php_error(E_NOTICE,"adding info #%d: '%s:%s'", i, exif_get_sectionname(section_index), info_value->name);/**/
#endif
- switch(image_info->list[i].format)
+ switch(info_value->format)
{
default:
/* Standard says more types possible but skip them...
@@ -711,144 +888,58 @@ void add_assoc_image_info( pval *value, int sub_array, char *name, image_info_li
* 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);
+ add_assoc_stringl(tmpi, info_value->name, info_value->value.s, info_value->length, 1);
break;
case TAG_FMT_STRING:
- add_assoc_string(tmpi, image_info->list[i].name, image_info->list[i].value.s, 1);
+ add_assoc_string(tmpi, info_value->name, info_value->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);
+ add_assoc_long(tmpi, info_value->name, (int)info_value->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);
+ sprintf(buffer,"%i/%i", info_value->value.ur.num, info_value->value.ur.den);
+ add_assoc_string(tmpi, info_value->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);
+ add_assoc_long(tmpi, info_value->name, info_value->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);
+ sprintf(buffer,"%i/%i", info_value->value.sr.num, info_value->value.sr.den);
+ add_assoc_string(tmpi, info_value->name, buffer, 1);
break;
case TAG_FMT_SINGLE:
- add_assoc_double(tmpi, image_info->list[i].name, image_info->list[i].value.f);
+ add_assoc_double(tmpi, info_value->name, info_value->value.f);
break;
case TAG_FMT_DOUBLE:
- add_assoc_double(tmpi, image_info->list[i].name, image_info->list[i].value.d);
+ add_assoc_double(tmpi, info_value->name, info_value->value.d);
break;
}
}
if ( sub_array) {
- add_assoc_zval(value, name, tmpi);
+ add_assoc_zval(value, exif_get_sectionname(section_index), 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;
- int Height, Width;
- int IsColor;
- int FlashUsed;
- float FocalLength;
- float ExposureTime;
- float ApertureFNumber;
- float Distance;
- float CCDWidth;
- char *Comments[EXIF_MAX_COMMENTS];
- int numComments;
- char UserCommentEncoding[12];
- char *UserComment;
- double FocalplaneXRes;
- double FocalplaneUnits;
- int ExifImageWidth;
- int MotorolaOrder;
- int Orientation;
- int ISOspeed;
- char *RawCopyright;
- int lenRawCopyright;
- char *Copyright[EXIF_MAX_COPYRIGHT];
- int numCopyrights;
- char *Thumbnail;
- int ThumbnailSize;
- int ThumbnailOffset;
- /* Olympus vars */
-/* int SpecialMode;
- int JpegQual;
- int Macro;
- int DigiZoom;
- char SoftwareRelease[16];
- char PictInfo[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;
- int read_all;
- /* internal */
- int sections_found; /* FOUND_<marker> */
- section_t sections[20];
- int sections_count;
- /* End Olympus vars */
-} image_info_type;
-/* }}} */
-
/* {{{ 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
in this program. (See jdmarker.c for a more complete list.)
*/
+#define M_TEM 0x01
#define M_SOF0 0xC0 /* Start Of Frame N */
#define M_SOF1 0xC1 /* N indicates which compression process */
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
@@ -890,62 +981,19 @@ typedef struct {
#define M_JPG0 0xF0
#define M_JPG13 0xFD
#define M_COM 0xFE /* COMment */
-#define M_TEM 0x01
#define PSEUDO_IMAGE_MARKER 0x123; /* Extra value. */
/* }}} */
-/* {{{ php_ifd_get16m
- Get 16 bits motorola order (always) for jpeg header stuff.
-*/
-static int php_ifd_get16m(void *Short)
-{
- return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
-}
-/* }}} */
-
/* {{{ exif_process_COM
Process a COM marker.
We want to print out the marker contents as legible text;
we must guard against random junk and varying newline representations.
*/
-static void exif_process_COM (image_info_type *ImageInfo, uchar *Data, int length)
+static void exif_process_COM (image_info_type *image_info, uchar *value, int length)
{
- int ch;
- char Comment[250];
- int nch;
- int a;
-
- if(ImageInfo->numComments == EXIF_MAX_COMMENTS) return;
-
- nch = 0;
-
- if (length > 200) length = 200; /* Truncate if it won't fit in our structure. */
-
- for (a=2;a<length;a++) {
- ch = Data[a];
-
- if (ch == '\r' && Data[a+1] == '\n') continue; /* Remove cr followed by lf. */
-
- if (isprint(ch) || ch == '\n' || ch == '\t') {
- Comment[nch++] = (char)ch;
- } else {
- Comment[nch++] = '?';
- }
- }
-
- Comment[nch] = '\0'; /* Null terminate */
-
- a = ImageInfo->numComments;
-
- (ImageInfo->Comments)[a] = emalloc(nch+1);
- strcpy(ImageInfo->Comments[a], Comment);
- (ImageInfo->numComments)++;
- ImageInfo->sections_found |= FOUND_COMMENT;
- #ifdef EXIF_DEBUG
- php_error(E_NOTICE,"process comment section: '%s'",ImageInfo->Comments[a]);
- #endif
+ exif_add_image_info( image_info, SECTION_COMMENT, "Comment", TAG_COMPUTED_VALUE, TAG_FMT_STRING, length, value);
}
/* }}} */
@@ -986,20 +1034,7 @@ static void exif_process_SOFn (image_info_type *ImageInfo, uchar *Data, int mark
}
/* }}} */
-static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart, char *OffsetBase, unsigned IFDlength);
-
-/* {{{ exif_get_tagname
- Get headername for tag_num or NULL if not defined */
-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 "";
-}
-/* }}} */
+static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart, char *OffsetBase, unsigned IFDlength, int sub_section_index);
/* {{{ exif_get_markername
Get name of marker */
@@ -1055,12 +1090,12 @@ char * exif_get_markername(int marker)
#endif
/* }}} */
-/* {{{ proto string|false exif_headername(index)
+/* {{{ proto string|false exif_tagname(index)
Get headername for index or false if not defined */
-PHP_FUNCTION(exif_headername)
+PHP_FUNCTION(exif_tagname)
{
pval **p_num;
- int ac = ZEND_NUM_ARGS();
+ int tag, ac = ZEND_NUM_ARGS();
char *szTemp;
if ((ac < 1 || ac > 1) || zend_get_parameters_ex(ac, &p_num) == FAILURE) {
@@ -1068,7 +1103,9 @@ PHP_FUNCTION(exif_headername)
}
convert_to_long_ex(p_num);
- if ( (szTemp = exif_get_tagname(Z_LVAL_PP(p_num))) == NULL) {
+ tag = Z_LVAL_PP(p_num);
+ szTemp = exif_get_tagname(tag,NULL);
+ if ( tag<0 || !szTemp || !szTemp[0]) {
RETURN_BOOL(FALSE);
} else {
RETURN_STRING(szTemp, 1)
@@ -1080,24 +1117,26 @@ PHP_FUNCTION(exif_headername)
* Grab the thumbnail - by Matt Bonneau */
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
- || 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) > length) {
- php_error(E_WARNING, "Thumbnail goes beyond exif header boundary");
+ if ( ImageInfo->read_thumbnail) {
+ 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 {
- memcpy(ImageInfo->Thumbnail, offset + ImageInfo->ThumbnailOffset, ImageInfo->ThumbnailSize);
+ /* Check to make sure we are not going to go past the ExifLength */
+ if ((unsigned)(ImageInfo->ThumbnailOffset + ImageInfo->ThumbnailSize) > length) {
+ php_error(E_WARNING, "Thumbnail goes beyond exif header boundary");
+ return;
+ } else {
+ memcpy(ImageInfo->Thumbnail, offset + ImageInfo->ThumbnailOffset, ImageInfo->ThumbnailSize);
+ }
}
}
}
@@ -1218,17 +1257,17 @@ static unsigned char* exif_char_dump( unsigned char * addr, int len)
/* {{{ exif_process_IFD_TAG
* Process one of the nested IFDs directories. */
-static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, char *offset_base, 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 section_index, int ReadNextIFD)
{
int l;
int tag, format, components;
- char *value_ptr;
+ char *value_ptr, *buffer, tagname[64];
size_t byte_count;
unsigned offset_val;
- 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);
+ tag = php_ifd_get16u(dir_entry, ImageInfo->motorola_intel);
+ format = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
+ components = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel);
if ((format-1) >= NUM_FORMATS) {
/* (-1) catches illegal zero case as unsigned underflows to positive large. */
@@ -1239,11 +1278,11 @@ static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, ch
byte_count = components * php_tiff_bytes_per_format[format];
if (byte_count > 4) {
- offset_val = php_ifd_get32u(dir_entry+8, ImageInfo->MotorolaOrder);
+ offset_val = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
/* If its bigger than 4 bytes, the dir entry contains an offset. */
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));
+ 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,NULL));
return;
}
value_ptr = offset_base+offset_val;
@@ -1252,201 +1291,166 @@ static void exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, ch
value_ptr = dir_entry+8;
}
- /* Extract useful components of IFD */
+ ImageInfo->sections_found |= FOUND_ANY_TAG;
#ifdef EXIF_DEBUG
- 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>");
+ php_error(E_NOTICE,"process tag(x%04x=%s,@x%04X+%i): %s", tag, exif_get_tagname(tag,NULL), value_ptr-offset_base, byte_count, format==TAG_FMT_STRING?(value_ptr?value_ptr:"<no data>"):exif_get_tagformat(format));
#endif
- switch(tag) {
- case TAG_COPYRIGHT:
- if (exif_process_string_raw(&ImageInfo->RawCopyright,value_ptr,byte_count)) {
- l = strlen(ImageInfo->RawCopyright);
- } else {
- l = 0;
- }
- 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_ORIENTATION:
- ImageInfo->Orientation = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
- break;*/
+ if (section_index==SECTION_THUMBNAIL) {
+ switch(tag) {
+ case TAG_STRIP_OFFSETS:
+ case TAG_JPEG_INTERCHANGE_FORMAT:
+ /* accept both formats */
+ ImageInfo->ThumbnailOffset = (int)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel);
+ return;
+
+ case TAG_JPEG_INTERCHANGE_FORMAT_LEN:
+ ImageInfo->ThumbnailSize = (int)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel);
+ /* no need to check for offset here: Exif says values have to be stored in tag order */
+ if ( ImageInfo->FileType == IMAGE_FILETYPE_JPEG) {
+ exif_extract_thumbnail(ImageInfo, offset_base, IFDlength);
+ }
+ break;
-/* case TAG_ISOSPEED:
- ImageInfo->ISOspeed = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
- break;*/
+ }
+ } else{
+ switch(tag) {
+ case TAG_COPYRIGHT:
+ if (byte_count>1 && (l=php_strnlen(value_ptr,byte_count)) > 0) {
+ if ( l<byte_count-1) {
+ /* When there are any characters after the first NUL */
+ exif_add_image_info( ImageInfo, SECTION_COMPUTED, "Copyright.Photographer", TAG_COPYRIGHT, TAG_FMT_STRING, l, value_ptr);
+ exif_add_image_info( ImageInfo, SECTION_COMPUTED, "Copyright.Editor", TAG_COPYRIGHT, TAG_FMT_STRING, byte_count-l-1, value_ptr+l+1);
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"added copyrights: %s, %s", value_ptr, value_ptr+l+1);
+ #endif
+ }
+ }
+ break;
- case TAG_USERCOMMENT:
- exif_process_user_comment(&(ImageInfo->UserComment),ImageInfo->UserCommentEncoding,value_ptr,byte_count);
- break;
+ case TAG_USERCOMMENT:
+ exif_process_user_comment(&(ImageInfo->UserComment),ImageInfo->UserCommentEncoding,value_ptr,byte_count);
+ break;
- /* 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]),value_ptr,byte_count)) {
- ImageInfo->numComments++;
+ /* 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]),value_ptr,byte_count)) {
+ ImageInfo->numComments++;
+ }
}
}
- }
- break;*/
-
- #ifdef EXIF_DEBUG
- /*case TAG_MARKER_NOTE:
- * php_error(E_NOTICE,exif_char_dump(value_ptr,byte_count));
- * break;
- */
- #endif
-
- /* 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:
- if (ImageInfo->ApertureFNumber == 0) {
- ImageInfo->ApertureFNumber
- = (float)exp(exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder)*log(2)*0.5);
- }
- 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;*/
-
- /* 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;*/
-
- /* 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(value_ptr, format, ImageInfo->MotorolaOrder)*log(2)));
- }
- break;
+ 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:
+ if (ImageInfo->ApertureFNumber == 0) {
+ ImageInfo->ApertureFNumber
+ = (float)exp(exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel)*log(2)*0.5);
+ }
+ break;
-/* case TAG_FLASH:
- if (exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder)) {
- ImageInfo->FlashUsed = 1;
- }
- 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.
+ SHUTTERSPEED comes after EXPOSURE TIME
+ */
+ if (ImageInfo->ExposureTime == 0) {
+ ImageInfo->ExposureTime
+ = (float)(1/exp(exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel)*log(2)));
+ }
+ break;
+ case TAG_EXPOSURETIME:
+ ImageInfo->ExposureTime = -1;
+ break;
- case TAG_COMP_IMAGEWIDTH:
- ImageInfo->ExifImageWidth = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
- break;
+ case TAG_COMP_IMAGEWIDTH:
+ ImageInfo->ExifImageWidth = (int)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel);
+ 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(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.
- But looking at the Cannon powershot's files, inches is the only
- sensible value. */
- ImageInfo->FocalplaneUnits = 25.4;
- break;
+ case TAG_FOCALPLANEXRES:
+ ImageInfo->FocalplaneXRes = exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel);
+ break;
- case 3: ImageInfo->FocalplaneUnits = 10; break; /* centimeter */
- case 4: ImageInfo->FocalplaneUnits = 1; break; /* milimeter */
- case 5: ImageInfo->FocalplaneUnits = .001; break; /* micrometer */
- }
- break;
+ case TAG_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(value_ptr, format, ImageInfo->motorola_intel);
+ break;
-/*
- 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_OLYMPUS_SOFTWARERELEASE:
- strlcpy(ImageInfo->SoftwareRelease, value_ptr, sizeof(ImageInfo->SoftwareRelease));
- break;
- case TAG_OLYMPUS_PICTINFO:
- strlcpy(ImageInfo->PictInfo, value_ptr, sizeof(ImageInfo->PictInfo));
- break;
- case TAG_OLYMPUS_CAMERAID:
- strlcpy(ImageInfo->CameraId, value_ptr, sizeof(ImageInfo->CameraId));
- break;
-*/
- case TAG_JPEG_INTERCHANGE_FORMAT:
- ImageInfo->ThumbnailOffset = (int)exif_convert_any_format(value_ptr, format, ImageInfo->MotorolaOrder);
- break;
+ case TAG_FOCALPLANEUNITS:
+ switch((int)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel)) {
+ case 1: ImageInfo->FocalplaneUnits = 25.4; break; /* inch */
+ case 2:
+ /* According to the information I was using, 2 measn meters.
+ But looking at the Cannon powershot's files, inches is the only
+ sensible value. */
+ ImageInfo->FocalplaneUnits = 25.4;
+ break;
- case 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 3: ImageInfo->FocalplaneUnits = 10; break; /* centimeter */
+ case 4: ImageInfo->FocalplaneUnits = 1; break; /* milimeter */
+ case 5: ImageInfo->FocalplaneUnits = .001; break; /* micrometer */
+ }
+ break;
- case TAG_EXIF_IFD_POINTER:
- case TAG_GPS_IFD_POINTER:
- case TAG_INTEROP_IFD_POINTER:
- if ( ReadNextIFD) {
- char *SubdirStart;
- 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;
+ case TAG_EXIF_IFD_POINTER:
+ case TAG_GPS_IFD_POINTER:
+ case TAG_INTEROP_IFD_POINTER:
+ if ( ReadNextIFD) {
+ char *SubdirStart;
+ int sub_section_index;
+ switch(tag) {
+ case TAG_EXIF_IFD_POINTER:
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"found EXIF");
+ #endif
+ ImageInfo->sections_found |= FOUND_EXIF;
+ sub_section_index = SECTION_EXIF;
+ break;
+ case TAG_GPS_IFD_POINTER:
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"found GPS");
+ #endif
+ ImageInfo->sections_found |= FOUND_GPS;
+ sub_section_index = SECTION_GPS;
+ break;
+ case TAG_INTEROP_IFD_POINTER:
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"found INTEROPERABILITY");
+ #endif
+ ImageInfo->sections_found |= FOUND_INTEROP;
+ sub_section_index = SECTION_INTEROP;
+/* return;/* we do not know how to handle that yet */
+ break;/**/
+ }
+ SubdirStart = offset_base + php_ifd_get32u(value_ptr, ImageInfo->motorola_intel);
+ if (SubdirStart < offset_base || SubdirStart > offset_base+IFDlength) {
+ php_error(E_WARNING, "Illegal IFD Pointer");
return;
-/* break;*/
- }
- 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");
+ }
+ exif_process_IFD_in_JPEG(ImageInfo, SubdirStart, offset_base, IFDlength, sub_section_index);
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"subsection %s done", exif_get_sectionname(sub_section_index));
+ #endif
return;
}
- exif_process_IFD_in_JPEG(ImageInfo, SubdirStart, offset_base, IFDlength);
- /* continue? */
- }
- break;
-
- default:
- exif_add_image_info( &ImageInfo->ANY, exif_get_tagname(tag), tag, format, byte_count, value_ptr, ImageInfo->MotorolaOrder);
- break;
+ return;
+ }
}
+ /* correctly would be to set components as length
+ * but we are ignoring length for those types where it is not the same as byte_count
+ */
+ exif_add_image_info( ImageInfo, section_index, exif_get_tagname(tag,tagname), tag, format, byte_count, value_ptr);
}
/* }}} */
/* {{{ exif_process_IFD_in_JPEG
* Process one of the nested IFDs directories. */
-static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart, char *OffsetBase, unsigned IFDlength)
+static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart, char *OffsetBase, unsigned IFDlength, int section_index)
{
int de;
int NumDirEntries;
@@ -1458,33 +1462,32 @@ static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart,
ImageInfo->sections_found |= FOUND_IFD0;
- NumDirEntries = php_ifd_get16u(DirStart, ImageInfo->MotorolaOrder);
+ NumDirEntries = php_ifd_get16u(DirStart, ImageInfo->motorola_intel);
if ((DirStart+2+NumDirEntries*12) > (OffsetBase+IFDlength)) {
php_error(E_WARNING, "Illegally sized directory");
return;
}
- ImageInfo->sections_found |= FOUND_ANY_TAG;
for (de=0;de<NumDirEntries;de++) {
- exif_process_IFD_TAG(ImageInfo,DirStart+2+12*de,OffsetBase,IFDlength,1);
+ exif_process_IFD_TAG(ImageInfo,DirStart+2+12*de,OffsetBase,IFDlength,section_index,1);
}
/*
* Hack to make it process IDF1 I hope
* There are 2 IDFs, the second one holds the keys (0x0201 and 0x0202) to the thumbnail
*/
- NextDirOffset = php_ifd_get32u(DirStart+2+12*de, ImageInfo->MotorolaOrder);
+ NextDirOffset = php_ifd_get32u(DirStart+2+12*de, ImageInfo->motorola_intel);
if (NextDirOffset) {
+ /* the next line seems false but here IFDlength means length of all IFDs */
if (OffsetBase + NextDirOffset < OffsetBase || OffsetBase + NextDirOffset > OffsetBase+IFDlength) {
php_error(E_WARNING, "Illegal directory offset");
return;
}
- /* That is the IFD for the first thumbnail
+ /* 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);
- */
+ exif_process_IFD_in_JPEG(ImageInfo, OffsetBase + NextDirOffset, OffsetBase, IFDlength, SECTION_THUMBNAIL);/**/
}
}
/* }}} */
@@ -1494,42 +1497,30 @@ static void exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *DirStart,
*/
static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf, unsigned int length)
{
- ImageInfo->FlashUsed = 0; /* If it s from a digicam, and it used flash, it says so. */
-
- ImageInfo->FocalplaneXRes = 0;
- ImageInfo->FocalplaneUnits = 0;
- ImageInfo->ExifImageWidth = 0;
-
/* set the thumbnail stuff to nothing so we can test to see if they get set up */
- ImageInfo->Thumbnail = NULL;
- ImageInfo->ThumbnailSize = 0;
-
if (memcmp(CharBuf, "II", 2) == 0) {
- ImageInfo->MotorolaOrder = 0;
+ ImageInfo->motorola_intel = 0;
} else if (memcmp(CharBuf, "MM", 2) == 0) {
- ImageInfo->MotorolaOrder = 1;
+ ImageInfo->motorola_intel = 1;
} else {
php_error(E_WARNING, "Invalid TIFF alignment marker.");
return;
}
/* Check the next two values for correctness. */
- if (php_ifd_get16u(CharBuf+2, ImageInfo->MotorolaOrder) != 0x2a
- || php_ifd_get32u(CharBuf+4, ImageInfo->MotorolaOrder) != 0x08) {
+ if (php_ifd_get16u(CharBuf+2, ImageInfo->motorola_intel) != 0x2a
+ || php_ifd_get32u(CharBuf+4, ImageInfo->motorola_intel) != 0x08) {
php_error(E_WARNING, "Invalid TIFF start (1)");
return;
}
/* First directory starts at offset 8. Offsets starts at 0. */
- exif_process_IFD_in_JPEG(ImageInfo, CharBuf+8, CharBuf, length-14);
+ exif_process_IFD_in_JPEG(ImageInfo, CharBuf+8, CharBuf, length-14, SECTION_IFD0);
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"exif_process_TIFF_in_JPEG, done");
#endif
- /* MB: This is where I will make my attempt to get the tumbnail */
-
-
/* Compute the CCD width, in milimeters. */
if (ImageInfo->FocalplaneXRes != 0) {
ImageInfo->CCDWidth = (float)(ImageInfo->ExifImageWidth * ImageInfo->FocalplaneUnits / ImageInfo->FocalplaneXRes);
@@ -1561,12 +1552,11 @@ static void exif_process_APP12(image_info_type *ImageInfo, char *buffer, unsigne
int l1, l2=0;
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);
+ exif_add_image_info( ImageInfo, SECTION_APP12, "Company", TAG_NONE, TAG_FMT_STRING, l1, buffer+2);
if ( length > 2+l1+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);
+ exif_add_image_info( ImageInfo, SECTION_APP12, "Info", TAG_NONE, TAG_FMT_STRING, l2, buffer+2+l1+1);
}
- ImageInfo->sections_found |= FOUND_APP12;
}
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"process section APP12 with l1=%d, l2=%d done", l1, l2);
@@ -1677,7 +1667,7 @@ static int exif_scan_JPEG_header(image_info_type *ImageInfo, FILE *infile)
case M_EOI: /* in case it's a tables-only JPEG stream */
php_error(E_WARNING, "No image in jpeg!");
- return ImageInfo->sections_found ? TRUE : FALSE;
+ return (ImageInfo->sections_found&(~FOUND_COMPUTED)) ? TRUE : FALSE;
case M_COM: /* Comment section */
exif_process_COM(ImageInfo, Data, itemlen);
@@ -1692,11 +1682,11 @@ static int exif_scan_JPEG_header(image_info_type *ImageInfo, FILE *infile)
}
break;
case M_FPIX:
- ImageInfo->sections_found |= FOUND_FPIX;
+ /*ImageInfo->sections_found |= FOUND_FPIX;*/
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"Found Flash Pix Extension Data");
#endif
- //exif_process_TIFF_in_JPEG(ImageInfo,(char *)Data,itemlen);
+ /*exif_process_TIFF_in_JPEG(ImageInfo,(char *)Data,itemlen);*/
break;
case M_APP12:
exif_process_APP12(ImageInfo,(char *)Data,itemlen);
@@ -1732,9 +1722,9 @@ static int exif_scan_JPEG_header(image_info_type *ImageInfo, FILE *infile)
/* {{{ exif_process_IFD_in_TIFF
* Parse the TIFF header; */
-static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, size_t dir_offset)
+static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, size_t dir_offset, int section_index)
{
- int i, sn, num_entries;
+ int i, sn, num_entries, sub_section_index;
unsigned char *dir_entry;
size_t ifd_size, dir_size, entry_offset, next_offset, entry_length, entry_value;
int entry_tag , entry_type;
@@ -1745,7 +1735,7 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, si
ImageInfo->sections[sn].Data = emalloc(ImageInfo->sections[sn].Size);
fseek(infile,dir_offset,SEEK_SET); /* we do not know the order of sections */
fread(ImageInfo->sections[sn].Data, 1, 2, infile);
- num_entries = php_ifd_get16u(ImageInfo->sections[sn].Data, ImageInfo->MotorolaOrder);
+ num_entries = php_ifd_get16u(ImageInfo->sections[sn].Data, ImageInfo->motorola_intel);
dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/;
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"Read from TIFF: filesize(x%04X), IFD dir(x%04X + x%04X), IFD entries(%d)", ImageInfo->FileSize, dir_offset, dir_size, num_entries);
@@ -1754,38 +1744,38 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, si
ImageInfo->sections[sn].Size = dir_size;
ImageInfo->sections[sn].Data = erealloc(ImageInfo->sections[sn].Data,ImageInfo->sections[sn].Size);
fread(ImageInfo->sections[sn].Data+2, 1, dir_size-2, infile);
- next_offset = php_ifd_get32u(ImageInfo->sections[sn].Data + dir_size - 4, ImageInfo->MotorolaOrder);
+ next_offset = php_ifd_get32u(ImageInfo->sections[sn].Data + dir_size - 4, ImageInfo->motorola_intel);
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"Read in TIFF done, next offset x%04X", next_offset);
+ php_error(E_NOTICE,"Read from TIFF done, next offset x%04X", next_offset);
#endif
/* now we have the directory we can look how long it should be */
ifd_size = dir_size;
for(i=0;i<num_entries;i++) {
dir_entry = ImageInfo->sections[sn].Data+2+i*12;
- entry_tag = php_ifd_get16u(dir_entry+0, ImageInfo->MotorolaOrder);
- entry_type = php_ifd_get16u(dir_entry+2, ImageInfo->MotorolaOrder);
+ entry_tag = php_ifd_get16u(dir_entry+0, ImageInfo->motorola_intel);
+ entry_type = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
if ( entry_type > NUM_FORMATS) {
php_error(E_WARNING,"Error in TIFF: Illegal format, suppose bytes");
entry_type = TAG_FMT_BYTE;
}
- entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->MotorolaOrder) * php_tiff_bytes_per_format[entry_type];
- entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->MotorolaOrder) * php_tiff_bytes_per_format[entry_type];
+ entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel) * php_tiff_bytes_per_format[entry_type];
+ entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel) * php_tiff_bytes_per_format[entry_type];
if ( entry_length > 4) {
- entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->MotorolaOrder);
+ entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
if ( entry_offset + entry_length > ifd_size) ifd_size = entry_offset + entry_length;
} else {
switch(entry_type) {
case TAG_FMT_USHORT:
- entry_value = php_ifd_get16u(dir_entry+8, ImageInfo->MotorolaOrder);
+ entry_value = php_ifd_get16u(dir_entry+8, ImageInfo->motorola_intel);
break;
case TAG_FMT_SSHORT:
- entry_value = php_ifd_get16s(dir_entry+8, ImageInfo->MotorolaOrder);
+ entry_value = php_ifd_get16s(dir_entry+8, ImageInfo->motorola_intel);
break;
case TAG_FMT_ULONG:
- entry_value = php_ifd_get32u(dir_entry+8, ImageInfo->MotorolaOrder);
+ entry_value = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
break;
case TAG_FMT_SLONG:
- entry_value = php_ifd_get32s(dir_entry+8, ImageInfo->MotorolaOrder);
+ entry_value = php_ifd_get32s(dir_entry+8, ImageInfo->motorola_intel);
break;
default:
continue;
@@ -1836,12 +1826,11 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, si
#endif
}
/* now process the tags */
- ImageInfo->sections_found |= FOUND_ANY_TAG;
for(i=0;i<num_entries;i++) {
dir_entry = ImageInfo->sections[sn].Data+2+i*12;
- entry_tag = php_ifd_get16u(dir_entry+0, ImageInfo->MotorolaOrder);
- /*entry_type = php_ifd_get16u(dir_entry+2, ImageInfo->MotorolaOrder);*/
- /*entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->MotorolaOrder);*/
+ entry_tag = php_ifd_get16u(dir_entry+0, ImageInfo->motorola_intel);
+ /*entry_type = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);*/
+ /*entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel);*/
if (entry_tag == TAG_EXIF_IFD_POINTER ||
entry_tag == TAG_INTEROP_IFD_POINTER ||
entry_tag == TAG_GPS_IFD_POINTER
@@ -1850,30 +1839,52 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, FILE *infile, si
switch(entry_tag) {
case TAG_EXIF_IFD_POINTER:
ImageInfo->sections_found |= FOUND_EXIF;
+ sub_section_index = SECTION_EXIF;
break;
case TAG_GPS_IFD_POINTER:
ImageInfo->sections_found |= FOUND_GPS;
+ sub_section_index = SECTION_GPS;
break;
case TAG_INTEROP_IFD_POINTER:
ImageInfo->sections_found |= FOUND_INTEROP;
- break;
+ sub_section_index = SECTION_INTEROP;
+/* return; /* we do not know how to handle that yet */
+ break;/**/
}
- entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->MotorolaOrder);
+ entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"Found other IFD: %s at x%04X", exif_get_tagname(entry_tag), entry_offset);
+ php_error(E_NOTICE,"Found other IFD: %s at x%04X", exif_get_tagname(entry_tag,NULL), entry_offset);
+ #endif
+ exif_process_IFD_in_TIFF(ImageInfo,infile,entry_offset,sub_section_index);
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"TIFF subsection %s done", exif_get_sectionname(sub_section_index));
#endif
- exif_process_IFD_in_TIFF(ImageInfo,infile,entry_offset);
} else {
- exif_process_IFD_TAG(ImageInfo,dir_entry,ImageInfo->sections[sn].Data-dir_offset,ifd_size,0);
+ exif_process_IFD_TAG(ImageInfo,dir_entry,ImageInfo->sections[sn].Data-dir_offset,ifd_size,section_index,0);
}
}
- if (next_offset) {
+ if (next_offset && section_index != SECTION_THUMBNAIL) {
/* this should be a thumbnail IFD */
/* the thumbnail itself is stored at Tag=StripOffsets */
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"Read next IFD at x%04X", next_offset);
+ php_error(E_NOTICE,"Read next IFD (THUMBNAIL) at x%04X", next_offset);
+ #endif
+ exif_process_IFD_in_TIFF(ImageInfo,infile,next_offset,SECTION_THUMBNAIL);
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"Read THUMBNAIL @0x%04X + 0x%04X", ImageInfo->ThumbnailOffset, ImageInfo->ThumbnailSize);
+ #endif
+ if (ImageInfo->ThumbnailOffset && ImageInfo->ThumbnailSize) {
+ ImageInfo->Thumbnail = emalloc(ImageInfo->ThumbnailSize);
+ if (!ImageInfo->Thumbnail) {
+ php_error(E_WARNING, "Could not allocate memory for thumbnail");
+ } else {
+ fseek(infile,ImageInfo->ThumbnailOffset,SEEK_SET);
+ fread(ImageInfo->Thumbnail, 1, ImageInfo->ThumbnailSize, infile);
+ }
+ }
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"Read next IFD (THUMBNAIL) done");
#endif
- /*exif_process_IFD_in_TIFF(ImageInfo,infile,entry_offset);*/
}
return TRUE;
} else {
@@ -1910,23 +1921,23 @@ static int exif_scan_FILE_header (image_info_type *ImageInfo, FILE *infile)
if ( !memcmp(file_header,"II\x2A\x00\x08\x00\x00\x00", 8))
{
ImageInfo->FileType = IMAGE_FILETYPE_TIFF;
- ImageInfo->MotorolaOrder = 0;
+ ImageInfo->motorola_intel = 0;
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"File(%s) has TIFF/II format", ImageInfo->FileName);
#endif
ImageInfo->sections_found |= FOUND_IFD0;
- return exif_process_IFD_in_TIFF(ImageInfo,infile,8);
+ return exif_process_IFD_in_TIFF(ImageInfo,infile,8,SECTION_IFD0);
}
else
if ( !memcmp(file_header,"MM\x00\x2a\x00\x00\x00\x08", 8))
{
ImageInfo->FileType = IMAGE_FILETYPE_TIFF;
- ImageInfo->MotorolaOrder = 1;
+ ImageInfo->motorola_intel = 1;
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"File(%s) has TIFF/MM format", ImageInfo->FileName);
#endif
ImageInfo->sections_found |= FOUND_IFD0;
- return exif_process_IFD_in_TIFF(ImageInfo,infile,8);
+ return exif_process_IFD_in_TIFF(ImageInfo,infile,8,SECTION_IFD0);
}
}
}
@@ -1960,29 +1971,11 @@ int php_exif_discard_imageinfo(image_info_type *ImageInfo)
int i;
if (ImageInfo->FileName) efree(ImageInfo->FileName);
- if (ImageInfo->UserComment) efree(ImageInfo->UserComment);
if (ImageInfo->Thumbnail) efree(ImageInfo->Thumbnail);
- if (ImageInfo->RawCopyright) efree(ImageInfo->RawCopyright);
- if (ImageInfo->numCopyrights) {
- for(i=0; i<ImageInfo->numCopyrights; i++) {
- efree((ImageInfo->Copyright)[i]);
- }
- ImageInfo->numCopyrights = 0;
+ for (i=0; i<SECTION_COUNT; i++) {
+ exif_free_image_info( ImageInfo, i);
}
- if (ImageInfo->numComments) {
- for(i=0; i<ImageInfo->numComments; i++) {
- efree((ImageInfo->Comments)[i]);
- }
- ImageInfo->numComments = 0;
- }
- 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));
+ php_exif_discard_sections(ImageInfo);
memset(ImageInfo, 0, sizeof(*ImageInfo));
return TRUE;
}
@@ -1995,7 +1988,7 @@ int php_exif_read_file(image_info_type *ImageInfo, char *FileName, int read_thum
int ret;
FILE *infile;
- ImageInfo->MotorolaOrder = 0;
+ ImageInfo->motorola_intel = 0;
infile = VCWD_FOPEN(FileName, "rb"); /* Unix ignores 'b', windows needs it. */
@@ -2003,26 +1996,11 @@ int php_exif_read_file(image_info_type *ImageInfo, char *FileName, int read_thum
php_error(E_WARNING, "Unable to open '%s'", FileName);
return FALSE;
}
-/* CurrentFile = FileName; */
-
/* php_error(E_WARNING,"EXIF: Process %s%s: %s", read_thumbnail?"thumbs ":"", read_all?"All ":"", FileName); /**/
/* Start with an empty image information structure. */
memset(ImageInfo, 0, sizeof(*ImageInfo));
ImageInfo->FileName = php_basename(FileName, strlen(FileName), NULL, 0);
- ImageInfo->FocalLength = 0;
- ImageInfo->ExposureTime = 0;
- ImageInfo->ApertureFNumber = 0;
- 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;
@@ -2042,26 +2020,7 @@ int php_exif_read_file(image_info_type *ImageInfo, char *FileName, int read_thum
ret = exif_scan_FILE_header(ImageInfo, infile);
if (!ret) {
php_error(E_WARNING, "Invalid JPEG/TIFF file: '%s'", FileName);
- } else {
- /*
- * Thought this might pick out the embedded thumbnail, but it doesn't work. -RL
- for (i=0;i<ImageInfo->sections_count-1;i++) {
- if (ImageInfo->sections[i].Type == M_EXIF) {
- thumbsize = ImageInfo->sections[i].Size;
- if(thumbsize>0) {
- ImageInfo->Thumbnail = emalloc(thumbsize+7);
- ImageInfo->ThumbnailSize = thumbsize;
- ImageInfo->Thumbnail[0] = 0xff;
- ImageInfo->Thumbnail[1] = 0xd8;
- ImageInfo->Thumbnail[2] = 0xff;
- memcpy(ImageInfo->Thumbnail+4, ImageInfo->sections[i].Data, thumbsize+4);
- }
- }
- }
- */
}
- /* discard sections not yet image info */
- php_exif_discard_sections(ImageInfo);
fclose(infile);
@@ -2069,16 +2028,19 @@ int php_exif_read_file(image_info_type *ImageInfo, char *FileName, int read_thum
}
/* }}} */
-/* {{{ proto array read_exif_data(string filename [, read_thumbnails [, int read_all]])
- Reads the EXIF header data from the JPEG identified by filename and optionally reads the internal thumbnails */
-PHP_FUNCTION(read_exif_data)
+/* {{{ proto array|false read_exif_data(string filename [, sections_needed [, sub_arrays[, read_thumbnail]]])
+ Reads header data from the JPEG/TIFF image filename and optionally reads the internal thumbnails */
+PHP_FUNCTION(exif_read_data)
{
- pval **p_name, **p_read_thumbnail, **p_sections_needed, **p_read_all;
- int i, ac = ZEND_NUM_ARGS(), ret, sections_needed=0, read_thumbnail=0, read_all=0;
+ pval **p_name, **p_sections_needed, **p_sub_arrays, **p_read_thumbnail, **p_read_all;
+ int i, len, ac = ZEND_NUM_ARGS(), ret, sections_needed=0, sub_arrays=0, read_thumbnail=0, read_all=0;
+ int self_motorola_intel;
image_info_type ImageInfo;
- char tmp[64], sections_str[64];
+ char tmp[64], *sections_str, *s;
+
+ memset(&ImageInfo, 0, sizeof(ImageInfo));
- if ((ac < 1 || ac > 2) || zend_get_parameters_ex(ac, &p_name, &p_sections_needed, &p_read_thumbnail, &p_read_all) == FAILURE) {
+ if ((ac < 1 || ac > 4) || zend_get_parameters_ex(ac, &p_name, &p_sections_needed, &p_sub_arrays, &p_read_thumbnail, &p_read_all) == FAILURE) {
WRONG_PARAM_COUNT;
}
@@ -2086,64 +2048,53 @@ PHP_FUNCTION(read_exif_data)
if(ac >= 2) {
convert_to_string_ex(p_sections_needed);
- 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,"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;
+ sections_str = emalloc(strlen(Z_STRVAL_PP(p_sections_needed))+3);
+ sprintf(sections_str,",%s,",Z_STRVAL_PP(p_sections_needed));
+ /* sections_str DOES start with , and SPACES are NOT allowed in names */
+ s = sections_str;
+ while(*++s)
+ {
+ if(*s==' ') *s = ',';
+ }
+ for (i=0; i<SECTION_COUNT; i++)
+ {
+ sprintf(tmp,",%s,",exif_get_sectionname(i));
+ if ( strstr(sections_str,tmp))
+ {
+ sections_needed |= 1<<i;
+ }
+ }
#ifdef EXIF_DEBUG
- 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 ',' */
+ sections_str = exif_get_sectionlist(sections_needed);
php_error(E_NOTICE,"Sections needed: %s", sections_str[0] ? sections_str : "None");
+ efree(sections_str);
#endif
}
if(ac >= 3) {
+ convert_to_long_ex(p_sub_arrays);
+ sub_arrays = Z_LVAL_PP(p_sub_arrays);
+ }
+ if(ac >= 4) {
convert_to_long_ex(p_read_thumbnail);
read_thumbnail = Z_LVAL_PP(p_read_thumbnail);
}
- if(ac >= 4) {
+ if(ac >= 5) {
convert_to_long_ex(p_read_all);
read_all = Z_LVAL_PP(p_read_all);
}
/* parameters 3,4 will be working in later versions.... */
- read_thumbnail = 0; /* just to make function work for 4.2 tree */
read_all = 0; /* just to make function work for 4.2 tree */
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%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 ',' */
+ sections_str = exif_get_sectionlist(ImageInfo.sections_found);
+
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"Sections found: %s", sections_str[0] ? sections_str : "None");
#endif
+ ImageInfo.sections_found |= FOUND_COMPUTED;/* do not inform about in debug*/
+
if (ret==FALSE || array_init(return_value) == FAILURE || (sections_needed && !(sections_needed&ImageInfo.sections_found))) {
php_exif_discard_imageinfo(&ImageInfo);
RETURN_FALSE;
@@ -2153,115 +2104,131 @@ PHP_FUNCTION(read_exif_data)
php_error(E_NOTICE,"Returning information");
#endif
- /* generic created information */
- add_assoc_string(return_value, "FileName", ImageInfo.FileName, 1);
- add_assoc_long(return_value, "FileDateTime", ImageInfo.FileDateTime);
- add_assoc_long(return_value, "FileSize", ImageInfo.FileSize);
- add_assoc_string(return_value, "SectionsFound", sections_str, 1);
+ /*************************************************************************************************/
+ /* generic created information must use motorola/intel organisation from the executing processor */
+ i = 1;
+ ImageInfo.motorola_intel = (*(char*)&i) ? 0 : 1;
+ /* no more external processing from here */
+ /*************************************************************************************************/
+
+ /* now we can add our information */
+ exif_add_image_info( &ImageInfo, SECTION_FILE, "FileName", TAG_NONE, TAG_FMT_STRING, strlen(ImageInfo.FileName), ImageInfo.FileName);
+ exif_add_image_info( &ImageInfo, SECTION_FILE, "FileDateTime", TAG_NONE, TAG_FMT_SLONG, 1, &ImageInfo.FileDateTime);
+ exif_add_image_info( &ImageInfo, SECTION_FILE, "FileSize", TAG_NONE, TAG_FMT_SLONG, 1, &ImageInfo.FileSize);
+ exif_add_image_info( &ImageInfo, SECTION_FILE, "SectionsFound", TAG_NONE, TAG_FMT_STRING, strlen(sections_str), sections_str);
+ efree(sections_str);
/* ifd0/comment/exif/gps/interop information */
if (ImageInfo.Width>0 && ImageInfo.Height>0) {
sprintf(tmp, "width=\"%d\" height=\"%d\"", ImageInfo.Width, ImageInfo.Height);
- add_assoc_string(return_value, "html", tmp, 1);
- add_assoc_long(return_value, "Height", ImageInfo.Height);
- add_assoc_long(return_value, "Width", ImageInfo.Width);
- }
- add_assoc_long(return_value, "IsColor", ImageInfo.IsColor);
- if(ImageInfo.FlashUsed >= 0) {
- add_assoc_long(return_value, "FlashUsed", ImageInfo.FlashUsed);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "html", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "Height", TAG_NONE, TAG_FMT_SLONG, 1, &ImageInfo.Height);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "Width", TAG_NONE, TAG_FMT_SLONG, 1, &ImageInfo.Width);
}
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "IsColor", TAG_NONE, TAG_FMT_SLONG, 1, &ImageInfo.IsColor);
if (ImageInfo.FocalLength) {
sprintf(tmp, "%4.1fmm", ImageInfo.FocalLength);
- add_assoc_string(return_value, "FocalLength", tmp, 1);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "FocalLength", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
if(ImageInfo.CCDWidth) {
sprintf(tmp, "%dmm", (int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*35+0.5));
- add_assoc_string(return_value, "35mmFocalLength", tmp, 1);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "35mmFocalLength", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
}
- add_assoc_double(return_value, "RawFocalLength", ImageInfo.FocalLength);
}
- if(ImageInfo.ExposureTime) {
+ if(ImageInfo.CCDWidth) {
+ sprintf(tmp, "%dmm", (int)ImageInfo.CCDWidth);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "CCDWidth", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
+ }
+ if(ImageInfo.ExposureTime>0) {
if(ImageInfo.ExposureTime <= 0.5) {
- sprintf(tmp, "%6.3f s (1/%d)", ImageInfo.ExposureTime, (int)(0.5 + 1/ImageInfo.ExposureTime));
+ sprintf(tmp, "%0.3f s (1/%d)", ImageInfo.ExposureTime, (int)(0.5 + 1/ImageInfo.ExposureTime));
} else {
- sprintf(tmp, "%6.3f s", ImageInfo.ExposureTime);
+ sprintf(tmp, "%0.3f s", ImageInfo.ExposureTime);
}
- add_assoc_string(return_value, "ExposureTime", tmp, 1);
- add_assoc_double(return_value, "RawExposureTime", ImageInfo.ExposureTime);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "ExposureTime", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
}
if(ImageInfo.ApertureFNumber) {
- sprintf(tmp, "f/%4.1f", ImageInfo.ApertureFNumber);
- add_assoc_string(return_value, "ApertureFNumber", tmp, 1);
- add_assoc_double(return_value, "RawApertureFNumber", ImageInfo.ApertureFNumber);
+ sprintf(tmp, "f/%.1f", ImageInfo.ApertureFNumber);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "ApertureFNumber", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
}
if(ImageInfo.Distance) {
if(ImageInfo.Distance<0) {
- add_assoc_string(return_value, "FocusDistance", "Infinite", 1);
+ sprintf(tmp,"%s","Infinite");
} else {
- sprintf(tmp, "%5.2fm", ImageInfo.Distance);
- add_assoc_string(return_value, "FocusDistance", tmp, 1);
+ sprintf(tmp, "%0.2fm", ImageInfo.Distance);
}
- add_assoc_double(return_value, "RawFocusDistance", ImageInfo.Distance);
- }
- if(ImageInfo.CCDWidth) {
- add_assoc_double(return_value, "CCDWidth", ImageInfo.CCDWidth);
- }
- if(ImageInfo.Orientation) {
- add_assoc_long(return_value, "Orientation", ImageInfo.Orientation);
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "FocusDistance", TAG_NONE, TAG_FMT_STRING, strlen(tmp), tmp);
}
- if(ImageInfo.ISOspeed) {
- add_assoc_long(return_value, "ISOspeed", ImageInfo.ISOspeed);
- }
- if (ImageInfo.RawCopyright || ImageInfo.numCopyrights) {
- if (ImageInfo.RawCopyright && !ImageInfo.numCopyrights && ImageInfo.lenRawCopyright) {
- add_assoc_stringl(return_value, "Copyright", ImageInfo.RawCopyright, ImageInfo.lenRawCopyright, 1);
- }else{
- pval *tmpi;
-
- MAKE_STD_ZVAL(tmpi);
- array_init(tmpi);
- add_assoc_string(tmpi, "Photographer", ImageInfo.Copyright[0], 1);
- add_assoc_string(tmpi, "Editor", ImageInfo.Copyright[1], 1);
- add_assoc_zval(return_value, "Copyright", tmpi);
+ if (ImageInfo.UserComment) {
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "UserComment", TAG_NONE, TAG_FMT_STRING, strlen(ImageInfo.UserComment), ImageInfo.UserComment);
+ if ( (len=ImageInfo.UserCommentEncoding[0])) {
+ exif_add_image_info( &ImageInfo, SECTION_COMPUTED, "UserCommentEncoding", TAG_NONE, TAG_FMT_STRING, len, ImageInfo.UserCommentEncoding);
}
}
- if(ImageInfo.numComments) {
- if(ImageInfo.numComments==1) {
- add_assoc_string(return_value, "Comments", (ImageInfo.Comments)[0], 1);
- } else {
- pval *tmpi;
- MAKE_STD_ZVAL(tmpi);
- array_init(tmpi);
- for(i=0; i<ImageInfo.numComments; i++) {
- add_index_string(tmpi, i, (ImageInfo.Comments)[i], 0);
- }
- add_assoc_zval(return_value, "Comments", tmpi);
- }
+ if ( read_thumbnail && ImageInfo.ThumbnailSize) {
+ exif_add_image_info( &ImageInfo, SECTION_THUMBNAIL, "THUMBNAIL", TAG_NONE, TAG_FMT_UNDEFINED, ImageInfo.ThumbnailSize, ImageInfo.Thumbnail);
}
- if (ImageInfo.UserComment) {
- add_assoc_string(return_value, "UserComment", ImageInfo.UserComment, 1);
- if ( ImageInfo.UserCommentEncoding[0]) {
- add_assoc_string(return_value, "UserCommentEncoding", ImageInfo.UserCommentEncoding, 1);
- }
+
+ #ifdef EXIF_DEBUG
+ php_error(E_NOTICE,"adding image infos");
+ #endif
+
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_FILE);
+ add_assoc_image_info( return_value, 1, &ImageInfo, SECTION_COMPUTED);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_ANY_TAG);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_IFD0);
+ add_assoc_image_info( return_value, 1, &ImageInfo, SECTION_THUMBNAIL);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_COMMENT);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_EXIF);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_GPS);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_INTEROP);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_FPIX);
+ add_assoc_image_info( return_value, sub_arrays, &ImageInfo, SECTION_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
+}
+/* }}} */
+
+/* {{{ proto string|false read_exif_data(string filename)
+ Reads the embedded thumbnail */
+PHP_FUNCTION(exif_thumbnail)
+{
+ pval **p_name;
+ int ret, ac = ZEND_NUM_ARGS();
+ image_info_type ImageInfo;
+
+ memset(&ImageInfo, 0, sizeof(ImageInfo));
+
+ if ( (ac != 1) || zend_get_parameters_ex(ac, &p_name) == FAILURE) {
+ WRONG_PARAM_COUNT;
}
- if (ImageInfo.ThumbnailSize) {
- add_assoc_long(return_value, "ThumbnailSize", ImageInfo.ThumbnailSize);
+
+ convert_to_string_ex(p_name);
+
+ ret = php_exif_read_file(&ImageInfo, Z_STRVAL_PP(p_name), 1, 0 TSRMLS_CC);
+ if (ret==FALSE) {
+ php_exif_discard_imageinfo(&ImageInfo);
+ RETURN_FALSE;
}
- if(ImageInfo.Thumbnail && ImageInfo.ThumbnailSize) {
- add_assoc_stringl(return_value, "Thumbnail", ImageInfo.Thumbnail, ImageInfo.ThumbnailSize, 1);
+
+ if ( !ImageInfo.Thumbnail || !ImageInfo.ThumbnailSize) {
+ php_exif_discard_imageinfo(&ImageInfo);
+ php_error(E_NOTICE,"No thumbnail data found");
+ RETURN_FALSE;
}
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"adding image infos");
+ php_error(E_NOTICE,"Returning thumbnail(%d)", ImageInfo.ThumbnailSize);
#endif
- 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));
+ ZVAL_STRINGL( return_value, ImageInfo.Thumbnail, ImageInfo.ThumbnailSize, 1);
#ifdef EXIF_DEBUG
php_error(E_NOTICE,"Discarding info");
@@ -2270,7 +2237,7 @@ PHP_FUNCTION(read_exif_data)
php_exif_discard_imageinfo(&ImageInfo);
#ifdef EXIF_DEBUG
- php_error(E_NOTICE,"read_exif_data done");
+ php_error(E_NOTICE,"exif_thumbnail done");
#endif
}
/* }}} */
diff --git a/ext/exif/php_exif.h b/ext/exif/php_exif.h
index 1ee86dc274..29f5fb2ceb 100644
--- a/ext/exif/php_exif.h
+++ b/ext/exif/php_exif.h
@@ -23,6 +23,7 @@
extern zend_module_entry exif_module_entry;
#define phpext_exif_ptr &exif_module_entry
-PHP_FUNCTION(read_exif_data);
-PHP_FUNCTION(exif_headername);
+PHP_FUNCTION(exif_read_data);
+PHP_FUNCTION(exif_tagname);
+PHP_FUNCTION(exif_thumbnail);
#endif