2
+----------------------------------------------------------------------+
4
+----------------------------------------------------------------------+
5
| Copyright (c) 1997-2004 The PHP Group |
6
+----------------------------------------------------------------------+
7
| This source file is subject to version 3.0 of the PHP license, |
8
| that is bundled with this package in the file LICENSE, and is |
9
| available through the world-wide-web at the following url: |
10
| http://www.php.net/license/3_0.txt. |
11
| If you did not receive a copy of the PHP license and are unable to |
12
| obtain it through the world-wide-web, please send a note to |
13
| license@php.net so we can mail you a copy immediately. |
14
+----------------------------------------------------------------------+
15
| Authors: Rasmus Lerdorf <rasmus@php.net> |
16
| Marcus Boerger <helly@php.net> |
17
+----------------------------------------------------------------------+
20
/* $Id: image.c,v 1.98.2.10 2005/06/28 15:22:39 hyanantha Exp $ */
27
#include "fopen_wrappers.h"
28
#include "ext/standard/fsock.h"
32
#include "php_image.h"
34
#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
38
/* file type markers */
39
PHPAPI const char php_sig_gif[3] = {'G', 'I', 'F'};
40
PHPAPI const char php_sig_psd[4] = {'8', 'B', 'P', 'S'};
41
PHPAPI const char php_sig_bmp[2] = {'B', 'M'};
42
PHPAPI const char php_sig_swf[3] = {'F', 'W', 'S'};
43
PHPAPI const char php_sig_swc[3] = {'C', 'W', 'S'};
44
PHPAPI const char php_sig_jpg[3] = {(char) 0xff, (char) 0xd8, (char) 0xff};
45
PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
46
(char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
47
PHPAPI const char php_sig_tif_ii[4] = {'I','I', (char)0x2A, (char)0x00};
48
PHPAPI const char php_sig_tif_mm[4] = {'M','M', (char)0x00, (char)0x2A};
49
PHPAPI const char php_sig_jpc[3] = {(char)0xff, (char)0x4f, (char)0xff};
50
PHPAPI const char php_sig_jp2[12] = {(char)0x00, (char)0x00, (char)0x00, (char)0x0c,
51
(char)0x6a, (char)0x50, (char)0x20, (char)0x20,
52
(char)0x0d, (char)0x0a, (char)0x87, (char)0x0a};
53
PHPAPI const char php_sig_iff[4] = {'F','O','R','M'};
55
/* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */
56
/* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */
58
/* return info as a struct, to make expansion easier */
64
unsigned int channels;
67
/* {{{ PHP_MINIT_FUNCTION(imagetypes)
68
* Register IMAGETYPE_<xxx> constants used by GetImageSize(), image_type_to_mime_type, ext/exif */
69
PHP_MINIT_FUNCTION(imagetypes)
71
REGISTER_LONG_CONSTANT("IMAGETYPE_GIF", IMAGE_FILETYPE_GIF, CONST_CS | CONST_PERSISTENT);
72
REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG", IMAGE_FILETYPE_JPEG, CONST_CS | CONST_PERSISTENT);
73
REGISTER_LONG_CONSTANT("IMAGETYPE_PNG", IMAGE_FILETYPE_PNG, CONST_CS | CONST_PERSISTENT);
74
REGISTER_LONG_CONSTANT("IMAGETYPE_SWF", IMAGE_FILETYPE_SWF, CONST_CS | CONST_PERSISTENT);
75
REGISTER_LONG_CONSTANT("IMAGETYPE_PSD", IMAGE_FILETYPE_PSD, CONST_CS | CONST_PERSISTENT);
76
REGISTER_LONG_CONSTANT("IMAGETYPE_BMP", IMAGE_FILETYPE_BMP, CONST_CS | CONST_PERSISTENT);
77
REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_II", IMAGE_FILETYPE_TIFF_II, CONST_CS | CONST_PERSISTENT);
78
REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_MM", IMAGE_FILETYPE_TIFF_MM, CONST_CS | CONST_PERSISTENT);
79
REGISTER_LONG_CONSTANT("IMAGETYPE_JPC", IMAGE_FILETYPE_JPC, CONST_CS | CONST_PERSISTENT);
80
REGISTER_LONG_CONSTANT("IMAGETYPE_JP2", IMAGE_FILETYPE_JP2, CONST_CS | CONST_PERSISTENT);
81
REGISTER_LONG_CONSTANT("IMAGETYPE_JPX", IMAGE_FILETYPE_JPX, CONST_CS | CONST_PERSISTENT);
82
REGISTER_LONG_CONSTANT("IMAGETYPE_JB2", IMAGE_FILETYPE_JB2, CONST_CS | CONST_PERSISTENT);
83
#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
84
REGISTER_LONG_CONSTANT("IMAGETYPE_SWC", IMAGE_FILETYPE_SWC, CONST_CS | CONST_PERSISTENT);
86
REGISTER_LONG_CONSTANT("IMAGETYPE_IFF", IMAGE_FILETYPE_IFF, CONST_CS | CONST_PERSISTENT);
87
REGISTER_LONG_CONSTANT("IMAGETYPE_WBMP", IMAGE_FILETYPE_WBMP, CONST_CS | CONST_PERSISTENT);
88
REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG2000",IMAGE_FILETYPE_JPC, CONST_CS | CONST_PERSISTENT); /* keep alias */
89
REGISTER_LONG_CONSTANT("IMAGETYPE_XBM", IMAGE_FILETYPE_XBM, CONST_CS | CONST_PERSISTENT);
95
* routine to handle GIF files. If only everything were that easy... ;} */
96
static struct gfxinfo *php_handle_gif (php_stream * stream TSRMLS_DC)
98
struct gfxinfo *result = NULL;
101
if (php_stream_seek(stream, 3, SEEK_CUR))
104
if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
107
result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
108
result->width = (unsigned int)dim[0] | (((unsigned int)dim[1])<<8);
109
result->height = (unsigned int)dim[2] | (((unsigned int)dim[3])<<8);
110
result->bits = dim[4]&0x80 ? ((((unsigned int)dim[4])&0x07) + 1) : 0;
111
result->channels = 3; /* allways */
117
/* {{{ php_handle_psd
119
static struct gfxinfo *php_handle_psd (php_stream * stream TSRMLS_DC)
121
struct gfxinfo *result = NULL;
122
unsigned char dim[8];
124
if (php_stream_seek(stream, 11, SEEK_CUR))
127
if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
130
result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
131
result->height = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
132
result->width = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
138
/* {{{ php_handle_bmp
140
static struct gfxinfo *php_handle_bmp (php_stream * stream TSRMLS_DC)
142
struct gfxinfo *result = NULL;
143
unsigned char dim[16];
146
if (php_stream_seek(stream, 11, SEEK_CUR))
149
if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
152
size = (((unsigned int)dim[ 3]) << 24) + (((unsigned int)dim[ 2]) << 16) + (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]);
154
result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo));
155
result->width = (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);
156
result->height = (((unsigned int)dim[ 7]) << 8) + ((unsigned int) dim[ 6]);
157
result->bits = ((unsigned int)dim[11]);
158
} else if (size > 12 && (size <= 64 || size == 108)) {
159
result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo));
160
result->width = (((unsigned int)dim[ 7]) << 24) + (((unsigned int)dim[ 6]) << 16) + (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);
161
result->height = (((unsigned int)dim[11]) << 24) + (((unsigned int)dim[10]) << 16) + (((unsigned int)dim[ 9]) << 8) + ((unsigned int) dim[ 8]);
162
result->bits = (((unsigned int)dim[15]) << 8) + ((unsigned int)dim[14]);
171
/* {{{ php_swf_get_bits
172
* routines to handle SWF files. */
173
static unsigned long int php_swf_get_bits (unsigned char* buffer, unsigned int pos, unsigned int count)
176
unsigned long int result = 0;
178
for (loop = pos; loop < pos + count; loop++)
181
((((buffer[loop / 8]) >> (7 - (loop % 8))) & 0x01) << (count - (loop - pos) - 1));
187
#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
188
/* {{{ php_handle_swc
190
static struct gfxinfo *php_handle_swc(php_stream * stream TSRMLS_DC)
192
struct gfxinfo *result = NULL;
196
unsigned long len=64, szlength;
197
int factor=1,maxfactor=16;
198
int slength, status=0;
199
char *b, *buf=NULL, *bufz=NULL;
201
b = ecalloc (1, len + 1);
203
if (php_stream_seek(stream, 5, SEEK_CUR))
206
if (php_stream_read(stream, a, sizeof(a)) != sizeof(a))
209
if (uncompress(b, &len, a, sizeof(a)) != Z_OK) {
210
/* failed to decompress the file, will try reading the rest of the file */
211
if (php_stream_seek(stream, 8, SEEK_SET))
214
slength = php_stream_copy_to_mem(stream, &bufz, PHP_STREAM_COPY_ALL, 0);
217
* zlib::uncompress() wants to know the output data length
218
* if none was given as a parameter
219
* we try from input length * 2 up to input length * 2^8
220
* doubling it whenever it wasn't big enough
221
* that should be eneugh for all real life cases
225
szlength=slength*(1<<factor++);
226
buf = (char *) erealloc(buf,szlength);
227
status = uncompress(buf, &szlength, bufz, slength);
228
} while ((status==Z_BUF_ERROR)&&(factor<maxfactor));
234
if (status == Z_OK) {
244
result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
245
bits = php_swf_get_bits (b, 0, 5);
246
result->width = (php_swf_get_bits (b, 5 + bits, bits) -
247
php_swf_get_bits (b, 5, bits)) / 20;
248
result->height = (php_swf_get_bits (b, 5 + (3 * bits), bits) -
249
php_swf_get_bits (b, 5 + (2 * bits), bits)) / 20;
260
/* {{{ php_handle_swf
262
static struct gfxinfo *php_handle_swf (php_stream * stream TSRMLS_DC)
264
struct gfxinfo *result = NULL;
268
if (php_stream_seek(stream, 5, SEEK_CUR))
271
if (php_stream_read(stream, a, sizeof(a)) != sizeof(a))
274
result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
275
bits = php_swf_get_bits (a, 0, 5);
276
result->width = (php_swf_get_bits (a, 5 + bits, bits) -
277
php_swf_get_bits (a, 5, bits)) / 20;
278
result->height = (php_swf_get_bits (a, 5 + (3 * bits), bits) -
279
php_swf_get_bits (a, 5 + (2 * bits), bits)) / 20;
281
result->channels = 0;
286
/* {{{ php_handle_png
287
* routine to handle PNG files */
288
static struct gfxinfo *php_handle_png (php_stream * stream TSRMLS_DC)
290
struct gfxinfo *result = NULL;
291
unsigned char dim[9];
296
* Compression method: 1 byte
297
* Filter method: 1 byte
298
* Interlace method: 1 byte
301
if (php_stream_seek(stream, 8, SEEK_CUR))
304
if((php_stream_read(stream, dim, sizeof(dim))) < sizeof(dim))
307
result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
308
result->width = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
309
result->height = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
310
result->bits = (unsigned int)dim[8];
315
/* routines to handle JPEG data */
317
/* some defines for the different JPEG block types */
318
#define M_SOF0 0xC0 /* Start Of Frame N */
319
#define M_SOF1 0xC1 /* N indicates which compression process */
320
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
322
#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
332
#define M_EOI 0xD9 /* End Of Image (end of datastream) */
333
#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
350
#define M_COM 0xFE /* COMment */
352
#define M_PSEUDO 0xFFD8 /* pseudo marker for start of image(byte 0) */
356
static unsigned short php_read2(php_stream * stream TSRMLS_DC)
360
/* just return 0 if we hit the end-of-file */
361
if((php_stream_read(stream, a, sizeof(a))) <= 0) return 0;
363
return (((unsigned short)a[0]) << 8) + ((unsigned short)a[1]);
367
/* {{{ php_next_marker
368
* get next marker byte from file */
369
static unsigned int php_next_marker(php_stream * stream, int last_marker, int comment_correction, int ff_read TSRMLS_DC)
373
/* get marker byte, swallowing possible padding */
374
if (last_marker==M_COM && comment_correction) {
375
/* some software does not count the length bytes of COM section */
376
/* one company doing so is very much envolved in JPEG... so we accept too */
377
/* by the way: some of those companies changed their code now... */
378
comment_correction = 2;
381
comment_correction = 0;
384
a = 1; /* already read 0xff in filetype detection */
387
if ((marker = php_stream_getc(stream)) == EOF)
389
return M_EOI;/* we hit EOF */
391
if (last_marker==M_COM && comment_correction>0)
396
comment_correction--;
398
last_marker = M_PSEUDO; /* stop skipping non 0xff for M_COM */
403
/* who knows the maxim amount of 0xff? though 7 */
404
/* but found other implementations */
407
} while (marker == 0xff);
410
return M_EOI; /* at least one 0xff is needed before marker code */
412
if ( last_marker==M_COM && comment_correction)
414
return M_EOI; /* ah illegal: char after COM section not 0xFF */
416
return (unsigned int)marker;
420
/* {{{ php_skip_variable
421
* skip over a variable-length block; assumes proper length marker */
422
static int php_skip_variable(php_stream * stream TSRMLS_DC)
424
off_t length = ((unsigned int)php_read2(stream TSRMLS_CC));
430
php_stream_seek(stream, (long)length, SEEK_CUR);
437
static int php_read_APP(php_stream * stream, unsigned int marker, zval *info TSRMLS_DC)
439
unsigned short length;
440
unsigned char *buffer;
441
unsigned char markername[16];
444
length = php_read2(stream TSRMLS_CC);
448
length -= 2; /* length includes itself */
450
buffer = emalloc(length);
452
if (php_stream_read(stream, buffer, (long) length) <= 0) {
457
sprintf(markername, "APP%d", marker - M_APP0);
459
if (zend_hash_find(Z_ARRVAL_P(info), markername, strlen(markername)+1, (void **) &tmp) == FAILURE) {
460
/* XXX we onyl catch the 1st tag of it's kind! */
461
add_assoc_stringl(info, markername, buffer, length, 1);
469
/* {{{ php_handle_jpeg
470
main loop to parse JPEG structure */
471
static struct gfxinfo *php_handle_jpeg (php_stream * stream, pval *info TSRMLS_DC)
473
struct gfxinfo *result = NULL;
474
unsigned int marker = M_PSEUDO;
475
unsigned short length, ff_read=1;
478
marker = php_next_marker(stream, marker, 1, ff_read TSRMLS_CC);
494
if (result == NULL) {
495
/* handle SOFn block */
496
result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
497
length = php_read2(stream TSRMLS_CC);
498
result->bits = php_stream_getc(stream);
499
result->height = php_read2(stream TSRMLS_CC);
500
result->width = php_read2(stream TSRMLS_CC);
501
result->channels = php_stream_getc(stream);
502
if (!info || length < 8) { /* if we don't want an extanded info -> return */
505
if (php_stream_seek(stream, length - 8, SEEK_CUR)) { /* file error after info */
509
if (!php_skip_variable(stream TSRMLS_CC)) {
532
if (!php_read_APP(stream, marker, info TSRMLS_CC)) { /* read all the app markes... */
536
if (!php_skip_variable(stream TSRMLS_CC)) {
544
return result; /* we're about to hit image data, or are at EOF. stop processing. */
547
if (!php_skip_variable(stream TSRMLS_CC)) { /* anything else isn't interesting */
554
return result; /* perhaps image broken -> no info but size */
560
static unsigned int php_read4(php_stream * stream TSRMLS_DC)
564
/* just return 0 if we hit the end-of-file */
565
if ((php_stream_read(stream, a, sizeof(a))) != sizeof(a)) return 0;
567
return (((unsigned int)a[0]) << 24)
568
+ (((unsigned int)a[1]) << 16)
569
+ (((unsigned int)a[2]) << 8)
570
+ (((unsigned int)a[3]));
574
/* {{{ JPEG 2000 Marker Codes */
575
#define JPEG2000_MARKER_PREFIX 0xFF /* All marker codes start with this */
576
#define JPEG2000_MARKER_SOC 0x4F /* Start of Codestream */
577
#define JPEG2000_MARKER_SOT 0x90 /* Start of Tile part */
578
#define JPEG2000_MARKER_SOD 0x93 /* Start of Data */
579
#define JPEG2000_MARKER_EOC 0xD9 /* End of Codestream */
580
#define JPEG2000_MARKER_SIZ 0x51 /* Image and tile size */
581
#define JPEG2000_MARKER_COD 0x52 /* Coding style default */
582
#define JPEG2000_MARKER_COC 0x53 /* Coding style component */
583
#define JPEG2000_MARKER_RGN 0x5E /* Region of interest */
584
#define JPEG2000_MARKER_QCD 0x5C /* Quantization default */
585
#define JPEG2000_MARKER_QCC 0x5D /* Quantization component */
586
#define JPEG2000_MARKER_POC 0x5F /* Progression order change */
587
#define JPEG2000_MARKER_TLM 0x55 /* Tile-part lengths */
588
#define JPEG2000_MARKER_PLM 0x57 /* Packet length, main header */
589
#define JPEG2000_MARKER_PLT 0x58 /* Packet length, tile-part header */
590
#define JPEG2000_MARKER_PPM 0x60 /* Packed packet headers, main header */
591
#define JPEG2000_MARKER_PPT 0x61 /* Packed packet headers, tile part header */
592
#define JPEG2000_MARKER_SOP 0x91 /* Start of packet */
593
#define JPEG2000_MARKER_EPH 0x92 /* End of packet header */
594
#define JPEG2000_MARKER_CRG 0x63 /* Component registration */
595
#define JPEG2000_MARKER_COM 0x64 /* Comment */
598
/* {{{ php_handle_jpc
599
Main loop to parse JPEG2000 raw codestream structure */
600
static struct gfxinfo *php_handle_jpc(php_stream * stream TSRMLS_DC)
602
struct gfxinfo *result = NULL;
603
unsigned short dummy_short;
604
int highest_bit_depth, bit_depth;
605
unsigned char first_marker_id;
608
/* JPEG 2000 components can be vastly different from one another.
609
Each component can be sampled at a different resolution, use
610
a different colour space, have a seperate colour depth, and
611
be compressed totally differently! This makes giving a single
612
"bit depth" answer somewhat problematic. For this implementation
613
we'll use the highest depth encountered. */
615
/* Get the single byte that remains after the file type indentification */
616
first_marker_id = php_stream_getc(stream);
618
/* Ensure that this marker is SIZ (as is mandated by the standard) */
619
if (first_marker_id != JPEG2000_MARKER_SIZ) {
620
php_error_docref(NULL TSRMLS_CC, E_WARNING, "JPEG2000 codestream corrupt(Expected SIZ marker not found after SOC)");
624
result = (struct gfxinfo *)ecalloc(1, sizeof(struct gfxinfo));
626
dummy_short = php_read2(stream TSRMLS_CC); /* Lsiz */
627
dummy_short = php_read2(stream TSRMLS_CC); /* Rsiz */
628
result->width = php_read4(stream TSRMLS_CC); /* Ysiz */
629
result->height = php_read4(stream TSRMLS_CC); /* Xsiz */
632
php_read4(stream TSRMLS_CC); /* XOsiz */
633
php_read4(stream TSRMLS_CC); /* YOsiz */
634
php_read4(stream TSRMLS_CC); /* XTsiz */
635
php_read4(stream TSRMLS_CC); /* YTsiz */
636
php_read4(stream TSRMLS_CC); /* XTOsiz */
637
php_read4(stream TSRMLS_CC); /* YTOsiz */
639
if (php_stream_seek(stream, 24, SEEK_CUR)) {
645
result->channels = php_read2(stream TSRMLS_CC); /* Csiz */
646
if (result->channels < 0 || result->channels > 256) {
651
/* Collect bit depth info */
652
highest_bit_depth = bit_depth = 0;
653
for (i = 0; i < result->channels; i++) {
654
bit_depth = php_stream_getc(stream); /* Ssiz[i] */
656
if (bit_depth > highest_bit_depth) {
657
highest_bit_depth = bit_depth;
660
php_stream_getc(stream); /* XRsiz[i] */
661
php_stream_getc(stream); /* YRsiz[i] */
664
result->bits = highest_bit_depth;
670
/* {{{ php_handle_jp2
671
main loop to parse JPEG 2000 JP2 wrapper format structure */
672
static struct gfxinfo *php_handle_jp2(php_stream *stream TSRMLS_DC)
674
struct gfxinfo *result = NULL;
675
unsigned int box_length;
676
unsigned int box_type;
677
char jp2c_box_id[] = {(char)0x6a, (char)0x70, (char)0x32, (char)0x63};
679
/* JP2 is a wrapper format for JPEG 2000. Data is contained within "boxes".
680
Boxes themselves can be contained within "super-boxes". Super-Boxes can
681
contain super-boxes which provides us with a hierarchical storage system.
683
It is valid for a JP2 file to contain multiple individual codestreams.
684
We'll just look for the first codestream at the root of the box structure
690
box_length = php_read4(stream TSRMLS_CC); /* LBox */
692
if (php_stream_read(stream, (void *)&box_type, sizeof(box_type)) != sizeof(box_type)) {
693
/* Use this as a general "out of stream" error */
697
if (box_length == 1) {
698
/* We won't handle XLBoxes */
702
if (!memcmp(&box_type, jp2c_box_id, 4))
704
/* Skip the first 3 bytes to emulate the file type examination */
705
php_stream_seek(stream, 3, SEEK_CUR);
707
result = php_handle_jpc(stream TSRMLS_CC);
711
/* Stop if this was the last box */
712
if ((int)box_length <= 0) {
716
/* Skip over LBox (Which includes both TBox and LBox itself */
717
if (php_stream_seek(stream, box_length - 8, SEEK_CUR)) {
722
if (result == NULL) {
723
php_error_docref(NULL TSRMLS_CC, E_WARNING, "JP2 file has no codestreams at root level");
730
/* {{{ tiff constants
732
PHPAPI const int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
734
/* uncompressed only */
735
#define TAG_IMAGEWIDTH 0x0100
736
#define TAG_IMAGEHEIGHT 0x0101
737
/* compressed images only */
738
#define TAG_COMP_IMAGEWIDTH 0xA002
739
#define TAG_COMP_IMAGEHEIGHT 0xA003
741
#define TAG_FMT_BYTE 1
742
#define TAG_FMT_STRING 2
743
#define TAG_FMT_USHORT 3
744
#define TAG_FMT_ULONG 4
745
#define TAG_FMT_URATIONAL 5
746
#define TAG_FMT_SBYTE 6
747
#define TAG_FMT_UNDEFINED 7
748
#define TAG_FMT_SSHORT 8
749
#define TAG_FMT_SLONG 9
750
#define TAG_FMT_SRATIONAL 10
751
#define TAG_FMT_SINGLE 11
752
#define TAG_FMT_DOUBLE 12
755
/* {{{ php_ifd_get16u
756
* Convert a 16 bit unsigned value from file's native byte order */
757
static int php_ifd_get16u(void *Short, int motorola_intel)
759
if (motorola_intel) {
760
return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
762
return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
767
/* {{{ php_ifd_get16s
768
* Convert a 16 bit signed value from file's native byte order */
769
static signed short php_ifd_get16s(void *Short, int motorola_intel)
771
return (signed short)php_ifd_get16u(Short, motorola_intel);
775
/* {{{ php_ifd_get32s
776
* Convert a 32 bit signed value from file's native byte order */
777
static int php_ifd_get32s(void *Long, int motorola_intel)
779
if (motorola_intel) {
780
return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
781
| (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
783
return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
784
| (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
789
/* {{{ php_ifd_get32u
790
* Convert a 32 bit unsigned value from file's native byte order */
791
static unsigned php_ifd_get32u(void *Long, int motorola_intel)
793
return (unsigned)php_ifd_get32s(Long, motorola_intel) & 0xffffffff;
797
/* {{{ php_handle_tiff
798
main loop to parse TIFF structure */
799
static struct gfxinfo *php_handle_tiff (php_stream * stream, pval *info, int motorola_intel TSRMLS_DC)
801
struct gfxinfo *result = NULL;
803
unsigned char *dir_entry;
804
size_t ifd_size, dir_size, entry_value, width=0, height=0, ifd_addr;
805
int entry_tag , entry_type;
806
char *ifd_data, ifd_ptr[4];
808
if (php_stream_read(stream, ifd_ptr, 4) != 4)
810
ifd_addr = php_ifd_get32u(ifd_ptr, motorola_intel);
811
if (php_stream_seek(stream, ifd_addr-8, SEEK_CUR))
814
ifd_data = emalloc(ifd_size);
815
if (php_stream_read(stream, ifd_data, 2) != 2) {
819
num_entries = php_ifd_get16u(ifd_data, motorola_intel);
820
dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/;
822
ifd_data = erealloc(ifd_data,ifd_size);
823
if (php_stream_read(stream, ifd_data+2, dir_size-2) != dir_size-2) {
827
/* now we have the directory we can look how long it should be */
829
for(i=0;i<num_entries;i++) {
830
dir_entry = ifd_data+2+i*12;
831
entry_tag = php_ifd_get16u(dir_entry+0, motorola_intel);
832
entry_type = php_ifd_get16u(dir_entry+2, motorola_intel);
836
entry_value = (size_t)(dir_entry[8]);
839
entry_value = php_ifd_get16u(dir_entry+8, motorola_intel);
842
entry_value = php_ifd_get16s(dir_entry+8, motorola_intel);
845
entry_value = php_ifd_get32u(dir_entry+8, motorola_intel);
848
entry_value = php_ifd_get32s(dir_entry+8, motorola_intel);
855
case TAG_COMP_IMAGEWIDTH:
858
case TAG_IMAGEHEIGHT:
859
case TAG_COMP_IMAGEHEIGHT:
860
height = entry_value;
865
if ( width && height) {
866
/* not the same when in for-loop */
867
result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
868
result->height = height;
869
result->width = width;
871
result->channels = 0;
878
/* {{{ php_handle_psd
880
static struct gfxinfo *php_handle_iff(php_stream * stream TSRMLS_DC)
882
struct gfxinfo * result;
886
short width, height, bits;
888
if (php_stream_read(stream, a, 8) != 8) {
891
if (strncmp(a+4, "ILBM", 4) && strncmp(a+4, "PBM ", 4)) {
895
/* loop chunks to find BMHD chunk */
897
if (php_stream_read(stream, a, 8) != 8) {
900
chunkId = php_ifd_get32s(a+0, 1);
901
size = php_ifd_get32s(a+4, 1);
905
if ((size & 1) == 1) {
908
if (chunkId == 0x424d4844) { /* BMHD chunk */
909
if (size < 9 || php_stream_read(stream, a, 9) != 9) {
912
width = php_ifd_get16s(a+0, 1);
913
height = php_ifd_get16s(a+2, 1);
915
if (width > 0 && height > 0 && bits > 0 && bits < 33) {
916
result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
917
result->width = width;
918
result->height = height;
920
result->channels = 0;
924
if (php_stream_seek(stream, size, SEEK_CUR)) {
933
* int WBMP file format type
935
* byte Extended Header
936
* byte Header Data (type 00 = multibyte)
937
* byte Header Data (type 11 = name/pairs)
938
* int Number of columns
941
static int php_get_wbmp(php_stream *stream, struct gfxinfo **result, int check TSRMLS_DC)
943
int i, width = 0, height = 0;
945
if (php_stream_rewind(stream)) {
950
if (php_stream_getc(stream) != 0) {
956
i = php_stream_getc(stream);
964
i = php_stream_getc(stream);
968
width = (width << 7) | (i & 0x7f);
973
i = php_stream_getc(stream);
977
height = (height << 7) | (i & 0x7f);
980
/* maximum valid sizes for wbmp (although 127x127 may be a more accurate one) */
981
if (!height || !width || height > 2048 || width > 2048) {
986
(*result)->width = width;
987
(*result)->height = height;
990
return IMAGE_FILETYPE_WBMP;
994
/* {{{ php_handle_wbmp
996
static struct gfxinfo *php_handle_wbmp(php_stream * stream TSRMLS_DC)
998
struct gfxinfo *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1000
if (!php_get_wbmp(stream, &result, 0 TSRMLS_CC)) {
1011
static int php_get_xbm(php_stream *stream, struct gfxinfo **result TSRMLS_DC)
1017
unsigned int width = 0, height = 0;
1022
if (php_stream_rewind(stream)) {
1025
while ((fline=php_stream_gets(stream, NULL, 0)) != NULL) {
1026
iname = estrdup(fline); /* simple way to get necessary buffer of required size */
1027
if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
1028
if (!(type = strrchr(iname, '_'))) {
1034
if (!strcmp("width", type)) {
1035
width = (unsigned int) value;
1041
if (!strcmp("height", type)) {
1042
height = (unsigned int) value;
1056
if (width && height) {
1058
*result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1059
(*result)->width = width;
1060
(*result)->height = height;
1062
return IMAGE_FILETYPE_XBM;
1069
/* {{{ php_handle_xbm
1071
static struct gfxinfo *php_handle_xbm(php_stream * stream TSRMLS_DC)
1073
struct gfxinfo *result;
1074
php_get_xbm(stream, &result TSRMLS_CC);
1079
/* {{{ php_image_type_to_mime_type
1080
* Convert internal image_type to mime type */
1081
PHPAPI char * php_image_type_to_mime_type(int image_type)
1083
switch( image_type) {
1084
case IMAGE_FILETYPE_GIF:
1086
case IMAGE_FILETYPE_JPEG:
1087
return "image/jpeg";
1088
case IMAGE_FILETYPE_PNG:
1090
case IMAGE_FILETYPE_SWF:
1091
case IMAGE_FILETYPE_SWC:
1092
return "application/x-shockwave-flash";
1093
case IMAGE_FILETYPE_PSD:
1095
case IMAGE_FILETYPE_BMP:
1097
case IMAGE_FILETYPE_TIFF_II:
1098
case IMAGE_FILETYPE_TIFF_MM:
1099
return "image/tiff";
1100
case IMAGE_FILETYPE_IFF:
1102
case IMAGE_FILETYPE_WBMP:
1103
return "image/vnd.wap.wbmp";
1104
case IMAGE_FILETYPE_JPC:
1105
return "application/octet-stream";
1106
case IMAGE_FILETYPE_JP2:
1108
case IMAGE_FILETYPE_XBM:
1111
case IMAGE_FILETYPE_UNKNOWN:
1112
return "application/octet-stream"; /* suppose binary format */
1117
/* {{{ proto string image_type_to_mime_type(int imagetype)
1118
Get Mime-Type for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
1119
PHP_FUNCTION(image_type_to_mime_type)
1121
zval **p_image_type;
1122
int arg_c = ZEND_NUM_ARGS();
1124
if ((arg_c!=1) || zend_get_parameters_ex(arg_c, &p_image_type) == FAILURE) {
1128
convert_to_long_ex(p_image_type);
1129
ZVAL_STRING(return_value, (char*)php_image_type_to_mime_type(Z_LVAL_PP(p_image_type)), 1);
1133
/* {{{ proto string image_type_to_extension(int imagetype [, bool include_dot])
1134
Get file extension for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
1135
PHP_FUNCTION(image_type_to_extension)
1138
zend_bool inc_dot=1;
1140
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &image_type, &inc_dot) == FAILURE) {
1144
switch (image_type) {
1145
case IMAGE_FILETYPE_GIF:
1146
RETURN_STRING(".gif" + !inc_dot, 1);
1147
case IMAGE_FILETYPE_JPEG:
1148
RETURN_STRING(".jpeg" + !inc_dot, 1);
1149
case IMAGE_FILETYPE_PNG:
1150
RETURN_STRING(".png" + !inc_dot, 1);
1151
case IMAGE_FILETYPE_SWF:
1152
case IMAGE_FILETYPE_SWC:
1153
RETURN_STRING(".swf" + !inc_dot, 1);
1154
case IMAGE_FILETYPE_PSD:
1155
RETURN_STRING(".psd" + !inc_dot, 1);
1156
case IMAGE_FILETYPE_BMP:
1157
case IMAGE_FILETYPE_WBMP:
1158
RETURN_STRING(".bmp" + !inc_dot, 1);
1159
case IMAGE_FILETYPE_TIFF_II:
1160
case IMAGE_FILETYPE_TIFF_MM:
1161
RETURN_STRING(".tiff" + !inc_dot, 1);
1162
case IMAGE_FILETYPE_IFF:
1163
RETURN_STRING(".iff" + !inc_dot, 1);
1164
case IMAGE_FILETYPE_JPC:
1165
RETURN_STRING(".jpc" + !inc_dot, 1);
1166
case IMAGE_FILETYPE_JP2:
1167
RETURN_STRING(".jp2" + !inc_dot, 1);
1168
case IMAGE_FILETYPE_XBM:
1169
RETURN_STRING(".xbm" + !inc_dot, 1);
1176
/* {{{ php_imagetype
1177
detect filetype from first bytes */
1178
PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
1182
if ( !filetype) filetype = tmp;
1183
if((php_stream_read(stream, filetype, 3)) != 3) {
1184
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Read error!");
1185
return IMAGE_FILETYPE_UNKNOWN;
1189
if (!memcmp(filetype, php_sig_gif, 3)) {
1190
return IMAGE_FILETYPE_GIF;
1191
} else if (!memcmp(filetype, php_sig_jpg, 3)) {
1192
return IMAGE_FILETYPE_JPEG;
1193
} else if (!memcmp(filetype, php_sig_png, 3)) {
1194
if (php_stream_read(stream, filetype+3, 5) != 5) {
1195
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Read error!");
1196
return IMAGE_FILETYPE_UNKNOWN;
1198
if (!memcmp(filetype, php_sig_png, 8)) {
1199
return IMAGE_FILETYPE_PNG;
1201
php_error_docref(NULL TSRMLS_CC, E_WARNING, "PNG file corrupted by ASCII conversion");
1202
return IMAGE_FILETYPE_UNKNOWN;
1204
} else if (!memcmp(filetype, php_sig_swf, 3)) {
1205
return IMAGE_FILETYPE_SWF;
1206
} else if (!memcmp(filetype, php_sig_swc, 3)) {
1207
return IMAGE_FILETYPE_SWC;
1208
} else if (!memcmp(filetype, php_sig_psd, 3)) {
1209
return IMAGE_FILETYPE_PSD;
1210
} else if (!memcmp(filetype, php_sig_bmp, 2)) {
1211
return IMAGE_FILETYPE_BMP;
1212
} else if (!memcmp(filetype, php_sig_jpc, 3)) {
1213
return IMAGE_FILETYPE_JPC;
1216
if (php_stream_read(stream, filetype+3, 1) != 1) {
1217
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Read error!");
1218
return IMAGE_FILETYPE_UNKNOWN;
1221
if (!memcmp(filetype, php_sig_tif_ii, 4)) {
1222
return IMAGE_FILETYPE_TIFF_II;
1224
if (!memcmp(filetype, php_sig_tif_mm, 4)) {
1225
return IMAGE_FILETYPE_TIFF_MM;
1227
if (!memcmp(filetype, php_sig_iff, 4)) {
1228
return IMAGE_FILETYPE_IFF;
1231
if (php_stream_read(stream, filetype+4, 8) != 8) {
1232
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Read error!");
1233
return IMAGE_FILETYPE_UNKNOWN;
1235
/* BYTES READ: 12 */
1236
if (!memcmp(filetype, php_sig_jp2, 12)) {
1237
return IMAGE_FILETYPE_JP2;
1240
/* AFTER ALL ABOVE FAILED */
1241
if (php_get_wbmp(stream, NULL, 1 TSRMLS_CC)) {
1242
return IMAGE_FILETYPE_WBMP;
1244
if (php_get_xbm(stream, NULL TSRMLS_CC)) {
1245
return IMAGE_FILETYPE_XBM;
1247
return IMAGE_FILETYPE_UNKNOWN;
1251
/* {{{ proto array getimagesize(string imagefile [, array info])
1252
Get the size of an image as 4-element array */
1253
PHP_FUNCTION(getimagesize)
1255
zval **arg1, **info = NULL;
1258
struct gfxinfo *result = NULL;
1259
php_stream * stream = NULL;
1261
switch(ZEND_NUM_ARGS()) {
1264
if (zend_get_parameters_ex(1, &arg1) == FAILURE) {
1268
convert_to_string_ex(arg1);
1272
if (zend_get_parameters_ex(2, &arg1, &info) == FAILURE) {
1280
convert_to_string_ex(arg1);
1288
stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL);
1294
itype = php_getimagetype(stream, NULL TSRMLS_CC);
1296
case IMAGE_FILETYPE_GIF:
1297
result = php_handle_gif (stream TSRMLS_CC);
1299
case IMAGE_FILETYPE_JPEG:
1301
result = php_handle_jpeg(stream, *info TSRMLS_CC);
1303
result = php_handle_jpeg(stream, NULL TSRMLS_CC);
1306
case IMAGE_FILETYPE_PNG:
1307
result = php_handle_png(stream TSRMLS_CC);
1309
case IMAGE_FILETYPE_SWF:
1310
result = php_handle_swf(stream TSRMLS_CC);
1312
case IMAGE_FILETYPE_SWC:
1313
#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
1314
result = php_handle_swc(stream TSRMLS_CC);
1316
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The image is a compressed SWF file, but you do not have a static version of the zlib extension enabled.");
1320
case IMAGE_FILETYPE_PSD:
1321
result = php_handle_psd(stream TSRMLS_CC);
1323
case IMAGE_FILETYPE_BMP:
1324
result = php_handle_bmp(stream TSRMLS_CC);
1326
case IMAGE_FILETYPE_TIFF_II:
1327
result = php_handle_tiff(stream, NULL, 0 TSRMLS_CC);
1329
case IMAGE_FILETYPE_TIFF_MM:
1330
result = php_handle_tiff(stream, NULL, 1 TSRMLS_CC);
1332
case IMAGE_FILETYPE_JPC:
1333
result = php_handle_jpc(stream TSRMLS_CC);
1335
case IMAGE_FILETYPE_JP2:
1336
result = php_handle_jp2(stream TSRMLS_CC);
1338
case IMAGE_FILETYPE_IFF:
1339
result = php_handle_iff(stream TSRMLS_CC);
1341
case IMAGE_FILETYPE_WBMP:
1342
result = php_handle_wbmp(stream TSRMLS_CC);
1344
case IMAGE_FILETYPE_XBM:
1345
result = php_handle_xbm(stream TSRMLS_CC);
1348
case IMAGE_FILETYPE_UNKNOWN:
1352
php_stream_close(stream);
1355
array_init(return_value);
1356
add_index_long(return_value, 0, result->width);
1357
add_index_long(return_value, 1, result->height);
1358
add_index_long(return_value, 2, itype);
1359
spprintf(&temp, 0, "width=\"%d\" height=\"%d\"", result->width, result->height);
1360
add_index_string(return_value, 3, temp, 0);
1362
if (result->bits != 0) {
1363
add_assoc_long(return_value, "bits", result->bits);
1365
if (result->channels != 0) {
1366
add_assoc_long(return_value, "channels", result->channels);
1368
add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype), 1);
1381
* vim600: sw=4 ts=4 fdm=marker
1382
* vim<600: sw=4 ts=4