Annotation of embedaddon/php/ext/standard/image.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 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_01.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: +----------------------------------------------------------------------+
18: */
19:
20: /* $Id: image.c 321634 2012-01-01 13:15:04Z felipe $ */
21:
22: #include "php.h"
23: #include <stdio.h>
24: #if HAVE_FCNTL_H
25: #include <fcntl.h>
26: #endif
27: #include "fopen_wrappers.h"
28: #include "ext/standard/fsock.h"
29: #if HAVE_UNISTD_H
30: #include <unistd.h>
31: #endif
32: #include "php_image.h"
33:
34: #include "zlib.h"
35:
36: /* file type markers */
37: PHPAPI const char php_sig_gif[3] = {'G', 'I', 'F'};
38: PHPAPI const char php_sig_psd[4] = {'8', 'B', 'P', 'S'};
39: PHPAPI const char php_sig_bmp[2] = {'B', 'M'};
40: PHPAPI const char php_sig_swf[3] = {'F', 'W', 'S'};
41: PHPAPI const char php_sig_swc[3] = {'C', 'W', 'S'};
42: PHPAPI const char php_sig_jpg[3] = {(char) 0xff, (char) 0xd8, (char) 0xff};
43: PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
44: (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
45: PHPAPI const char php_sig_tif_ii[4] = {'I','I', (char)0x2A, (char)0x00};
46: PHPAPI const char php_sig_tif_mm[4] = {'M','M', (char)0x00, (char)0x2A};
47: PHPAPI const char php_sig_jpc[3] = {(char)0xff, (char)0x4f, (char)0xff};
48: PHPAPI const char php_sig_jp2[12] = {(char)0x00, (char)0x00, (char)0x00, (char)0x0c,
49: (char)0x6a, (char)0x50, (char)0x20, (char)0x20,
50: (char)0x0d, (char)0x0a, (char)0x87, (char)0x0a};
51: PHPAPI const char php_sig_iff[4] = {'F','O','R','M'};
52: PHPAPI const char php_sig_ico[4] = {(char)0x00, (char)0x00, (char)0x01, (char)0x00};
53:
54: /* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */
55: /* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */
56:
57: /* return info as a struct, to make expansion easier */
58:
59: struct gfxinfo {
60: unsigned int width;
61: unsigned int height;
62: unsigned int bits;
63: unsigned int channels;
64: };
65:
66: /* {{{ PHP_MINIT_FUNCTION(imagetypes)
67: * Register IMAGETYPE_<xxx> constants used by GetImageSize(), image_type_to_mime_type, ext/exif */
68: PHP_MINIT_FUNCTION(imagetypes)
69: {
70: REGISTER_LONG_CONSTANT("IMAGETYPE_GIF", IMAGE_FILETYPE_GIF, CONST_CS | CONST_PERSISTENT);
71: REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG", IMAGE_FILETYPE_JPEG, CONST_CS | CONST_PERSISTENT);
72: REGISTER_LONG_CONSTANT("IMAGETYPE_PNG", IMAGE_FILETYPE_PNG, CONST_CS | CONST_PERSISTENT);
73: REGISTER_LONG_CONSTANT("IMAGETYPE_SWF", IMAGE_FILETYPE_SWF, CONST_CS | CONST_PERSISTENT);
74: REGISTER_LONG_CONSTANT("IMAGETYPE_PSD", IMAGE_FILETYPE_PSD, CONST_CS | CONST_PERSISTENT);
75: REGISTER_LONG_CONSTANT("IMAGETYPE_BMP", IMAGE_FILETYPE_BMP, CONST_CS | CONST_PERSISTENT);
76: REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_II", IMAGE_FILETYPE_TIFF_II, CONST_CS | CONST_PERSISTENT);
77: REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_MM", IMAGE_FILETYPE_TIFF_MM, CONST_CS | CONST_PERSISTENT);
78: REGISTER_LONG_CONSTANT("IMAGETYPE_JPC", IMAGE_FILETYPE_JPC, CONST_CS | CONST_PERSISTENT);
79: REGISTER_LONG_CONSTANT("IMAGETYPE_JP2", IMAGE_FILETYPE_JP2, CONST_CS | CONST_PERSISTENT);
80: REGISTER_LONG_CONSTANT("IMAGETYPE_JPX", IMAGE_FILETYPE_JPX, CONST_CS | CONST_PERSISTENT);
81: REGISTER_LONG_CONSTANT("IMAGETYPE_JB2", IMAGE_FILETYPE_JB2, CONST_CS | CONST_PERSISTENT);
82: REGISTER_LONG_CONSTANT("IMAGETYPE_SWC", IMAGE_FILETYPE_SWC, CONST_CS | CONST_PERSISTENT);
83: REGISTER_LONG_CONSTANT("IMAGETYPE_IFF", IMAGE_FILETYPE_IFF, CONST_CS | CONST_PERSISTENT);
84: REGISTER_LONG_CONSTANT("IMAGETYPE_WBMP", IMAGE_FILETYPE_WBMP, CONST_CS | CONST_PERSISTENT);
85: REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG2000",IMAGE_FILETYPE_JPC, CONST_CS | CONST_PERSISTENT); /* keep alias */
86: REGISTER_LONG_CONSTANT("IMAGETYPE_XBM", IMAGE_FILETYPE_XBM, CONST_CS | CONST_PERSISTENT);
87: REGISTER_LONG_CONSTANT("IMAGETYPE_ICO", IMAGE_FILETYPE_ICO, CONST_CS | CONST_PERSISTENT);
88: REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT);
89: REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_CS | CONST_PERSISTENT);
90: return SUCCESS;
91: }
92: /* }}} */
93:
94: /* {{{ php_handle_gif
95: * routine to handle GIF files. If only everything were that easy... ;} */
96: static struct gfxinfo *php_handle_gif (php_stream * stream TSRMLS_DC)
97: {
98: struct gfxinfo *result = NULL;
99: unsigned char dim[5];
100:
101: if (php_stream_seek(stream, 3, SEEK_CUR))
102: return NULL;
103:
104: if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
105: return NULL;
106:
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 */
112:
113: return result;
114: }
115: /* }}} */
116:
117: /* {{{ php_handle_psd
118: */
119: static struct gfxinfo *php_handle_psd (php_stream * stream TSRMLS_DC)
120: {
121: struct gfxinfo *result = NULL;
122: unsigned char dim[8];
123:
124: if (php_stream_seek(stream, 11, SEEK_CUR))
125: return NULL;
126:
127: if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
128: return NULL;
129:
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]);
133:
134: return result;
135: }
136: /* }}} */
137:
138: /* {{{ php_handle_bmp
139: */
140: static struct gfxinfo *php_handle_bmp (php_stream * stream TSRMLS_DC)
141: {
142: struct gfxinfo *result = NULL;
143: unsigned char dim[16];
144: int size;
145:
146: if (php_stream_seek(stream, 11, SEEK_CUR))
147: return NULL;
148:
149: if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
150: return NULL;
151:
152: size = (((unsigned int)dim[ 3]) << 24) + (((unsigned int)dim[ 2]) << 16) + (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]);
153: if (size == 12) {
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]);
163: } else {
164: return NULL;
165: }
166:
167: return result;
168: }
169: /* }}} */
170:
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)
174: {
175: unsigned int loop;
176: unsigned long int result = 0;
177:
178: for (loop = pos; loop < pos + count; loop++)
179: {
180: result = result +
181: ((((buffer[loop / 8]) >> (7 - (loop % 8))) & 0x01) << (count - (loop - pos) - 1));
182: }
183: return result;
184: }
185: /* }}} */
186:
187: /* {{{ php_handle_swc
188: */
189: static struct gfxinfo *php_handle_swc(php_stream * stream TSRMLS_DC)
190: {
191: struct gfxinfo *result = NULL;
192:
193: long bits;
194: unsigned char a[64];
195: unsigned long len=64, szlength;
196: int factor=1,maxfactor=16;
197: int slength, status=0;
198: char *b, *buf=NULL, *bufz=NULL;
199:
200: b = ecalloc (1, len + 1);
201:
202: if (php_stream_seek(stream, 5, SEEK_CUR))
203: return NULL;
204:
205: if (php_stream_read(stream, a, sizeof(a)) != sizeof(a))
206: return NULL;
207:
208: if (uncompress(b, &len, a, sizeof(a)) != Z_OK) {
209: /* failed to decompress the file, will try reading the rest of the file */
210: if (php_stream_seek(stream, 8, SEEK_SET))
211: return NULL;
212:
213: slength = php_stream_copy_to_mem(stream, &bufz, PHP_STREAM_COPY_ALL, 0);
214:
215: /*
216: * zlib::uncompress() wants to know the output data length
217: * if none was given as a parameter
218: * we try from input length * 2 up to input length * 2^8
219: * doubling it whenever it wasn't big enough
220: * that should be eneugh for all real life cases
221: */
222:
223: do {
224: szlength=slength*(1<<factor++);
225: buf = (char *) erealloc(buf,szlength);
226: status = uncompress(buf, &szlength, bufz, slength);
227: } while ((status==Z_BUF_ERROR)&&(factor<maxfactor));
228:
229: if (bufz) {
230: pefree(bufz, 0);
231: }
232:
233: if (status == Z_OK) {
234: memcpy(b, buf, len);
235: }
236:
237: if (buf) {
238: efree(buf);
239: }
240: }
241:
242: if (!status) {
243: result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
244: bits = php_swf_get_bits (b, 0, 5);
245: result->width = (php_swf_get_bits (b, 5 + bits, bits) -
246: php_swf_get_bits (b, 5, bits)) / 20;
247: result->height = (php_swf_get_bits (b, 5 + (3 * bits), bits) -
248: php_swf_get_bits (b, 5 + (2 * bits), bits)) / 20;
249: } else {
250: result = NULL;
251: }
252:
253: efree (b);
254: return result;
255: }
256: /* }}} */
257:
258: /* {{{ php_handle_swf
259: */
260: static struct gfxinfo *php_handle_swf (php_stream * stream TSRMLS_DC)
261: {
262: struct gfxinfo *result = NULL;
263: long bits;
264: unsigned char a[32];
265:
266: if (php_stream_seek(stream, 5, SEEK_CUR))
267: return NULL;
268:
269: if (php_stream_read(stream, a, sizeof(a)) != sizeof(a))
270: return NULL;
271:
272: result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
273: bits = php_swf_get_bits (a, 0, 5);
274: result->width = (php_swf_get_bits (a, 5 + bits, bits) -
275: php_swf_get_bits (a, 5, bits)) / 20;
276: result->height = (php_swf_get_bits (a, 5 + (3 * bits), bits) -
277: php_swf_get_bits (a, 5 + (2 * bits), bits)) / 20;
278: result->bits = 0;
279: result->channels = 0;
280: return result;
281: }
282: /* }}} */
283:
284: /* {{{ php_handle_png
285: * routine to handle PNG files */
286: static struct gfxinfo *php_handle_png (php_stream * stream TSRMLS_DC)
287: {
288: struct gfxinfo *result = NULL;
289: unsigned char dim[9];
290: /* Width: 4 bytes
291: * Height: 4 bytes
292: * Bit depth: 1 byte
293: * Color type: 1 byte
294: * Compression method: 1 byte
295: * Filter method: 1 byte
296: * Interlace method: 1 byte
297: */
298:
299: if (php_stream_seek(stream, 8, SEEK_CUR))
300: return NULL;
301:
302: if((php_stream_read(stream, dim, sizeof(dim))) < sizeof(dim))
303: return NULL;
304:
305: result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
306: result->width = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
307: result->height = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
308: result->bits = (unsigned int)dim[8];
309: return result;
310: }
311: /* }}} */
312:
313: /* routines to handle JPEG data */
314:
315: /* some defines for the different JPEG block types */
316: #define M_SOF0 0xC0 /* Start Of Frame N */
317: #define M_SOF1 0xC1 /* N indicates which compression process */
318: #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
319: #define M_SOF3 0xC3
320: #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
321: #define M_SOF6 0xC6
322: #define M_SOF7 0xC7
323: #define M_SOF9 0xC9
324: #define M_SOF10 0xCA
325: #define M_SOF11 0xCB
326: #define M_SOF13 0xCD
327: #define M_SOF14 0xCE
328: #define M_SOF15 0xCF
329: #define M_SOI 0xD8
330: #define M_EOI 0xD9 /* End Of Image (end of datastream) */
331: #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
332: #define M_APP0 0xe0
333: #define M_APP1 0xe1
334: #define M_APP2 0xe2
335: #define M_APP3 0xe3
336: #define M_APP4 0xe4
337: #define M_APP5 0xe5
338: #define M_APP6 0xe6
339: #define M_APP7 0xe7
340: #define M_APP8 0xe8
341: #define M_APP9 0xe9
342: #define M_APP10 0xea
343: #define M_APP11 0xeb
344: #define M_APP12 0xec
345: #define M_APP13 0xed
346: #define M_APP14 0xee
347: #define M_APP15 0xef
348: #define M_COM 0xFE /* COMment */
349:
350: #define M_PSEUDO 0xFFD8 /* pseudo marker for start of image(byte 0) */
351:
352: /* {{{ php_read2
353: */
354: static unsigned short php_read2(php_stream * stream TSRMLS_DC)
355: {
356: unsigned char a[2];
357:
358: /* just return 0 if we hit the end-of-file */
359: if((php_stream_read(stream, a, sizeof(a))) <= 0) return 0;
360:
361: return (((unsigned short)a[0]) << 8) + ((unsigned short)a[1]);
362: }
363: /* }}} */
364:
365: /* {{{ php_next_marker
366: * get next marker byte from file */
367: static unsigned int php_next_marker(php_stream * stream, int last_marker, int comment_correction, int ff_read TSRMLS_DC)
368: {
369: int a=0, marker;
370:
371: /* get marker byte, swallowing possible padding */
372: if (last_marker==M_COM && comment_correction) {
373: /* some software does not count the length bytes of COM section */
374: /* one company doing so is very much envolved in JPEG... so we accept too */
375: /* by the way: some of those companies changed their code now... */
376: comment_correction = 2;
377: } else {
378: last_marker = 0;
379: comment_correction = 0;
380: }
381: if (ff_read) {
382: a = 1; /* already read 0xff in filetype detection */
383: }
384: do {
385: if ((marker = php_stream_getc(stream)) == EOF)
386: {
387: return M_EOI;/* we hit EOF */
388: }
389: if (last_marker==M_COM && comment_correction>0)
390: {
391: if (marker != 0xFF)
392: {
393: marker = 0xff;
394: comment_correction--;
395: } else {
396: last_marker = M_PSEUDO; /* stop skipping non 0xff for M_COM */
397: }
398: }
399: a++;
400: } while (marker == 0xff);
401: if (a < 2)
402: {
403: return M_EOI; /* at least one 0xff is needed before marker code */
404: }
405: if ( last_marker==M_COM && comment_correction)
406: {
407: return M_EOI; /* ah illegal: char after COM section not 0xFF */
408: }
409: return (unsigned int)marker;
410: }
411: /* }}} */
412:
413: /* {{{ php_skip_variable
414: * skip over a variable-length block; assumes proper length marker */
415: static int php_skip_variable(php_stream * stream TSRMLS_DC)
416: {
417: off_t length = ((unsigned int)php_read2(stream TSRMLS_CC));
418:
419: if (length < 2) {
420: return 0;
421: }
422: length = length - 2;
423: php_stream_seek(stream, (long)length, SEEK_CUR);
424: return 1;
425: }
426: /* }}} */
427:
428: /* {{{ php_read_APP
429: */
430: static int php_read_APP(php_stream * stream, unsigned int marker, zval *info TSRMLS_DC)
431: {
432: unsigned short length;
433: unsigned char *buffer;
434: unsigned char markername[16];
435: zval *tmp;
436:
437: length = php_read2(stream TSRMLS_CC);
438: if (length < 2) {
439: return 0;
440: }
441: length -= 2; /* length includes itself */
442:
443: buffer = emalloc(length);
444:
445: if (php_stream_read(stream, buffer, (long) length) <= 0) {
446: efree(buffer);
447: return 0;
448: }
449:
450: snprintf(markername, sizeof(markername), "APP%d", marker - M_APP0);
451:
452: if (zend_hash_find(Z_ARRVAL_P(info), markername, strlen(markername)+1, (void **) &tmp) == FAILURE) {
453: /* XXX we onyl catch the 1st tag of it's kind! */
454: add_assoc_stringl(info, markername, buffer, length, 1);
455: }
456:
457: efree(buffer);
458: return 1;
459: }
460: /* }}} */
461:
462: /* {{{ php_handle_jpeg
463: main loop to parse JPEG structure */
464: static struct gfxinfo *php_handle_jpeg (php_stream * stream, zval *info TSRMLS_DC)
465: {
466: struct gfxinfo *result = NULL;
467: unsigned int marker = M_PSEUDO;
468: unsigned short length, ff_read=1;
469:
470: for (;;) {
471: marker = php_next_marker(stream, marker, 1, ff_read TSRMLS_CC);
472: ff_read = 0;
473: switch (marker) {
474: case M_SOF0:
475: case M_SOF1:
476: case M_SOF2:
477: case M_SOF3:
478: case M_SOF5:
479: case M_SOF6:
480: case M_SOF7:
481: case M_SOF9:
482: case M_SOF10:
483: case M_SOF11:
484: case M_SOF13:
485: case M_SOF14:
486: case M_SOF15:
487: if (result == NULL) {
488: /* handle SOFn block */
489: result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
490: length = php_read2(stream TSRMLS_CC);
491: result->bits = php_stream_getc(stream);
492: result->height = php_read2(stream TSRMLS_CC);
493: result->width = php_read2(stream TSRMLS_CC);
494: result->channels = php_stream_getc(stream);
495: if (!info || length < 8) { /* if we don't want an extanded info -> return */
496: return result;
497: }
498: if (php_stream_seek(stream, length - 8, SEEK_CUR)) { /* file error after info */
499: return result;
500: }
501: } else {
502: if (!php_skip_variable(stream TSRMLS_CC)) {
503: return result;
504: }
505: }
506: break;
507:
508: case M_APP0:
509: case M_APP1:
510: case M_APP2:
511: case M_APP3:
512: case M_APP4:
513: case M_APP5:
514: case M_APP6:
515: case M_APP7:
516: case M_APP8:
517: case M_APP9:
518: case M_APP10:
519: case M_APP11:
520: case M_APP12:
521: case M_APP13:
522: case M_APP14:
523: case M_APP15:
524: if (info) {
525: if (!php_read_APP(stream, marker, info TSRMLS_CC)) { /* read all the app markes... */
526: return result;
527: }
528: } else {
529: if (!php_skip_variable(stream TSRMLS_CC)) {
530: return result;
531: }
532: }
533: break;
534:
535: case M_SOS:
536: case M_EOI:
537: return result; /* we're about to hit image data, or are at EOF. stop processing. */
538:
539: default:
540: if (!php_skip_variable(stream TSRMLS_CC)) { /* anything else isn't interesting */
541: return result;
542: }
543: break;
544: }
545: }
546:
547: return result; /* perhaps image broken -> no info but size */
548: }
549: /* }}} */
550:
551: /* {{{ php_read4
552: */
553: static unsigned int php_read4(php_stream * stream TSRMLS_DC)
554: {
555: unsigned char a[4];
556:
557: /* just return 0 if we hit the end-of-file */
558: if ((php_stream_read(stream, a, sizeof(a))) != sizeof(a)) return 0;
559:
560: return (((unsigned int)a[0]) << 24)
561: + (((unsigned int)a[1]) << 16)
562: + (((unsigned int)a[2]) << 8)
563: + (((unsigned int)a[3]));
564: }
565: /* }}} */
566:
567: /* {{{ JPEG 2000 Marker Codes */
568: #define JPEG2000_MARKER_PREFIX 0xFF /* All marker codes start with this */
569: #define JPEG2000_MARKER_SOC 0x4F /* Start of Codestream */
570: #define JPEG2000_MARKER_SOT 0x90 /* Start of Tile part */
571: #define JPEG2000_MARKER_SOD 0x93 /* Start of Data */
572: #define JPEG2000_MARKER_EOC 0xD9 /* End of Codestream */
573: #define JPEG2000_MARKER_SIZ 0x51 /* Image and tile size */
574: #define JPEG2000_MARKER_COD 0x52 /* Coding style default */
575: #define JPEG2000_MARKER_COC 0x53 /* Coding style component */
576: #define JPEG2000_MARKER_RGN 0x5E /* Region of interest */
577: #define JPEG2000_MARKER_QCD 0x5C /* Quantization default */
578: #define JPEG2000_MARKER_QCC 0x5D /* Quantization component */
579: #define JPEG2000_MARKER_POC 0x5F /* Progression order change */
580: #define JPEG2000_MARKER_TLM 0x55 /* Tile-part lengths */
581: #define JPEG2000_MARKER_PLM 0x57 /* Packet length, main header */
582: #define JPEG2000_MARKER_PLT 0x58 /* Packet length, tile-part header */
583: #define JPEG2000_MARKER_PPM 0x60 /* Packed packet headers, main header */
584: #define JPEG2000_MARKER_PPT 0x61 /* Packed packet headers, tile part header */
585: #define JPEG2000_MARKER_SOP 0x91 /* Start of packet */
586: #define JPEG2000_MARKER_EPH 0x92 /* End of packet header */
587: #define JPEG2000_MARKER_CRG 0x63 /* Component registration */
588: #define JPEG2000_MARKER_COM 0x64 /* Comment */
589: /* }}} */
590:
591: /* {{{ php_handle_jpc
592: Main loop to parse JPEG2000 raw codestream structure */
593: static struct gfxinfo *php_handle_jpc(php_stream * stream TSRMLS_DC)
594: {
595: struct gfxinfo *result = NULL;
596: unsigned short dummy_short;
597: int highest_bit_depth, bit_depth;
598: unsigned char first_marker_id;
599: unsigned int i;
600:
601: /* JPEG 2000 components can be vastly different from one another.
602: Each component can be sampled at a different resolution, use
603: a different colour space, have a seperate colour depth, and
604: be compressed totally differently! This makes giving a single
605: "bit depth" answer somewhat problematic. For this implementation
606: we'll use the highest depth encountered. */
607:
608: /* Get the single byte that remains after the file type indentification */
609: first_marker_id = php_stream_getc(stream);
610:
611: /* Ensure that this marker is SIZ (as is mandated by the standard) */
612: if (first_marker_id != JPEG2000_MARKER_SIZ) {
613: php_error_docref(NULL TSRMLS_CC, E_WARNING, "JPEG2000 codestream corrupt(Expected SIZ marker not found after SOC)");
614: return NULL;
615: }
616:
617: result = (struct gfxinfo *)ecalloc(1, sizeof(struct gfxinfo));
618:
619: dummy_short = php_read2(stream TSRMLS_CC); /* Lsiz */
620: dummy_short = php_read2(stream TSRMLS_CC); /* Rsiz */
621: result->width = php_read4(stream TSRMLS_CC); /* Xsiz */
622: result->height = php_read4(stream TSRMLS_CC); /* Ysiz */
623:
624: #if MBO_0
625: php_read4(stream TSRMLS_CC); /* XOsiz */
626: php_read4(stream TSRMLS_CC); /* YOsiz */
627: php_read4(stream TSRMLS_CC); /* XTsiz */
628: php_read4(stream TSRMLS_CC); /* YTsiz */
629: php_read4(stream TSRMLS_CC); /* XTOsiz */
630: php_read4(stream TSRMLS_CC); /* YTOsiz */
631: #else
632: if (php_stream_seek(stream, 24, SEEK_CUR)) {
633: efree(result);
634: return NULL;
635: }
636: #endif
637:
638: result->channels = php_read2(stream TSRMLS_CC); /* Csiz */
639: if (result->channels < 0 || result->channels > 256) {
640: efree(result);
641: return NULL;
642: }
643:
644: /* Collect bit depth info */
645: highest_bit_depth = 0;
646: for (i = 0; i < result->channels; i++) {
647: bit_depth = php_stream_getc(stream); /* Ssiz[i] */
648: bit_depth++;
649: if (bit_depth > highest_bit_depth) {
650: highest_bit_depth = bit_depth;
651: }
652:
653: php_stream_getc(stream); /* XRsiz[i] */
654: php_stream_getc(stream); /* YRsiz[i] */
655: }
656:
657: result->bits = highest_bit_depth;
658:
659: return result;
660: }
661: /* }}} */
662:
663: /* {{{ php_handle_jp2
664: main loop to parse JPEG 2000 JP2 wrapper format structure */
665: static struct gfxinfo *php_handle_jp2(php_stream *stream TSRMLS_DC)
666: {
667: struct gfxinfo *result = NULL;
668: unsigned int box_length;
669: unsigned int box_type;
670: char jp2c_box_id[] = {(char)0x6a, (char)0x70, (char)0x32, (char)0x63};
671:
672: /* JP2 is a wrapper format for JPEG 2000. Data is contained within "boxes".
673: Boxes themselves can be contained within "super-boxes". Super-Boxes can
674: contain super-boxes which provides us with a hierarchical storage system.
675:
676: It is valid for a JP2 file to contain multiple individual codestreams.
677: We'll just look for the first codestream at the root of the box structure
678: and handle that.
679: */
680:
681: for (;;)
682: {
683: box_length = php_read4(stream TSRMLS_CC); /* LBox */
684: /* TBox */
685: if (php_stream_read(stream, (void *)&box_type, sizeof(box_type)) != sizeof(box_type)) {
686: /* Use this as a general "out of stream" error */
687: break;
688: }
689:
690: if (box_length == 1) {
691: /* We won't handle XLBoxes */
692: return NULL;
693: }
694:
695: if (!memcmp(&box_type, jp2c_box_id, 4))
696: {
697: /* Skip the first 3 bytes to emulate the file type examination */
698: php_stream_seek(stream, 3, SEEK_CUR);
699:
700: result = php_handle_jpc(stream TSRMLS_CC);
701: break;
702: }
703:
704: /* Stop if this was the last box */
705: if ((int)box_length <= 0) {
706: break;
707: }
708:
709: /* Skip over LBox (Which includes both TBox and LBox itself */
710: if (php_stream_seek(stream, box_length - 8, SEEK_CUR)) {
711: break;
712: }
713: }
714:
715: if (result == NULL) {
716: php_error_docref(NULL TSRMLS_CC, E_WARNING, "JP2 file has no codestreams at root level");
717: }
718:
719: return result;
720: }
721: /* }}} */
722:
723: /* {{{ tiff constants
724: */
725: PHPAPI const int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
726:
727: /* uncompressed only */
728: #define TAG_IMAGEWIDTH 0x0100
729: #define TAG_IMAGEHEIGHT 0x0101
730: /* compressed images only */
731: #define TAG_COMP_IMAGEWIDTH 0xA002
732: #define TAG_COMP_IMAGEHEIGHT 0xA003
733:
734: #define TAG_FMT_BYTE 1
735: #define TAG_FMT_STRING 2
736: #define TAG_FMT_USHORT 3
737: #define TAG_FMT_ULONG 4
738: #define TAG_FMT_URATIONAL 5
739: #define TAG_FMT_SBYTE 6
740: #define TAG_FMT_UNDEFINED 7
741: #define TAG_FMT_SSHORT 8
742: #define TAG_FMT_SLONG 9
743: #define TAG_FMT_SRATIONAL 10
744: #define TAG_FMT_SINGLE 11
745: #define TAG_FMT_DOUBLE 12
746: /* }}} */
747:
748: /* {{{ php_ifd_get16u
749: * Convert a 16 bit unsigned value from file's native byte order */
750: static int php_ifd_get16u(void *Short, int motorola_intel)
751: {
752: if (motorola_intel) {
753: return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
754: } else {
755: return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
756: }
757: }
758: /* }}} */
759:
760: /* {{{ php_ifd_get16s
761: * Convert a 16 bit signed value from file's native byte order */
762: static signed short php_ifd_get16s(void *Short, int motorola_intel)
763: {
764: return (signed short)php_ifd_get16u(Short, motorola_intel);
765: }
766: /* }}} */
767:
768: /* {{{ php_ifd_get32s
769: * Convert a 32 bit signed value from file's native byte order */
770: static int php_ifd_get32s(void *Long, int motorola_intel)
771: {
772: if (motorola_intel) {
773: return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
774: | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
775: } else {
776: return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
777: | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
778: }
779: }
780: /* }}} */
781:
782: /* {{{ php_ifd_get32u
783: * Convert a 32 bit unsigned value from file's native byte order */
784: static unsigned php_ifd_get32u(void *Long, int motorola_intel)
785: {
786: return (unsigned)php_ifd_get32s(Long, motorola_intel) & 0xffffffff;
787: }
788: /* }}} */
789:
790: /* {{{ php_handle_tiff
791: main loop to parse TIFF structure */
792: static struct gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int motorola_intel TSRMLS_DC)
793: {
794: struct gfxinfo *result = NULL;
795: int i, num_entries;
796: unsigned char *dir_entry;
797: size_t ifd_size, dir_size, entry_value, width=0, height=0, ifd_addr;
798: int entry_tag , entry_type;
799: char *ifd_data, ifd_ptr[4];
800:
801: if (php_stream_read(stream, ifd_ptr, 4) != 4)
802: return NULL;
803: ifd_addr = php_ifd_get32u(ifd_ptr, motorola_intel);
804: if (php_stream_seek(stream, ifd_addr-8, SEEK_CUR))
805: return NULL;
806: ifd_size = 2;
807: ifd_data = emalloc(ifd_size);
808: if (php_stream_read(stream, ifd_data, 2) != 2) {
809: efree(ifd_data);
810: return NULL;
811: }
812: num_entries = php_ifd_get16u(ifd_data, motorola_intel);
813: dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/;
814: ifd_size = dir_size;
815: ifd_data = erealloc(ifd_data,ifd_size);
816: if (php_stream_read(stream, ifd_data+2, dir_size-2) != dir_size-2) {
817: efree(ifd_data);
818: return NULL;
819: }
820: /* now we have the directory we can look how long it should be */
821: ifd_size = dir_size;
822: for(i=0;i<num_entries;i++) {
823: dir_entry = ifd_data+2+i*12;
824: entry_tag = php_ifd_get16u(dir_entry+0, motorola_intel);
825: entry_type = php_ifd_get16u(dir_entry+2, motorola_intel);
826: switch(entry_type) {
827: case TAG_FMT_BYTE:
828: case TAG_FMT_SBYTE:
829: entry_value = (size_t)(dir_entry[8]);
830: break;
831: case TAG_FMT_USHORT:
832: entry_value = php_ifd_get16u(dir_entry+8, motorola_intel);
833: break;
834: case TAG_FMT_SSHORT:
835: entry_value = php_ifd_get16s(dir_entry+8, motorola_intel);
836: break;
837: case TAG_FMT_ULONG:
838: entry_value = php_ifd_get32u(dir_entry+8, motorola_intel);
839: break;
840: case TAG_FMT_SLONG:
841: entry_value = php_ifd_get32s(dir_entry+8, motorola_intel);
842: break;
843: default:
844: continue;
845: }
846: switch(entry_tag) {
847: case TAG_IMAGEWIDTH:
848: case TAG_COMP_IMAGEWIDTH:
849: width = entry_value;
850: break;
851: case TAG_IMAGEHEIGHT:
852: case TAG_COMP_IMAGEHEIGHT:
853: height = entry_value;
854: break;
855: }
856: }
857: efree(ifd_data);
858: if ( width && height) {
859: /* not the same when in for-loop */
860: result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
861: result->height = height;
862: result->width = width;
863: result->bits = 0;
864: result->channels = 0;
865: return result;
866: }
867: return NULL;
868: }
869: /* }}} */
870:
871: /* {{{ php_handle_psd
872: */
873: static struct gfxinfo *php_handle_iff(php_stream * stream TSRMLS_DC)
874: {
875: struct gfxinfo * result;
876: unsigned char a[10];
877: int chunkId;
878: int size;
879: short width, height, bits;
880:
881: if (php_stream_read(stream, a, 8) != 8) {
882: return NULL;
883: }
884: if (strncmp(a+4, "ILBM", 4) && strncmp(a+4, "PBM ", 4)) {
885: return NULL;
886: }
887:
888: /* loop chunks to find BMHD chunk */
889: do {
890: if (php_stream_read(stream, a, 8) != 8) {
891: return NULL;
892: }
893: chunkId = php_ifd_get32s(a+0, 1);
894: size = php_ifd_get32s(a+4, 1);
895: if (size < 0) {
896: return NULL;
897: }
898: if ((size & 1) == 1) {
899: size++;
900: }
901: if (chunkId == 0x424d4844) { /* BMHD chunk */
902: if (size < 9 || php_stream_read(stream, a, 9) != 9) {
903: return NULL;
904: }
905: width = php_ifd_get16s(a+0, 1);
906: height = php_ifd_get16s(a+2, 1);
907: bits = a[8] & 0xff;
908: if (width > 0 && height > 0 && bits > 0 && bits < 33) {
909: result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
910: result->width = width;
911: result->height = height;
912: result->bits = bits;
913: result->channels = 0;
914: return result;
915: }
916: } else {
917: if (php_stream_seek(stream, size, SEEK_CUR)) {
918: return NULL;
919: }
920: }
921: } while (1);
922: }
923: /* }}} */
924:
925: /* {{{ php_get_wbmp
926: * int WBMP file format type
927: * byte Header Type
928: * byte Extended Header
929: * byte Header Data (type 00 = multibyte)
930: * byte Header Data (type 11 = name/pairs)
931: * int Number of columns
932: * int Number of rows
933: */
934: static int php_get_wbmp(php_stream *stream, struct gfxinfo **result, int check TSRMLS_DC)
935: {
936: int i, width = 0, height = 0;
937:
938: if (php_stream_rewind(stream)) {
939: return 0;
940: }
941:
942: /* get type */
943: if (php_stream_getc(stream) != 0) {
944: return 0;
945: }
946:
947: /* skip header */
948: do {
949: i = php_stream_getc(stream);
950: if (i < 0) {
951: return 0;
952: }
953: } while (i & 0x80);
954:
955: /* get width */
956: do {
957: i = php_stream_getc(stream);
958: if (i < 0) {
959: return 0;
960: }
961: width = (width << 7) | (i & 0x7f);
962: } while (i & 0x80);
963:
964: /* get height */
965: do {
966: i = php_stream_getc(stream);
967: if (i < 0) {
968: return 0;
969: }
970: height = (height << 7) | (i & 0x7f);
971: } while (i & 0x80);
972:
973: /* maximum valid sizes for wbmp (although 127x127 may be a more accurate one) */
974: if (!height || !width || height > 2048 || width > 2048) {
975: return 0;
976: }
977:
978: if (!check) {
979: (*result)->width = width;
980: (*result)->height = height;
981: }
982:
983: return IMAGE_FILETYPE_WBMP;
984: }
985: /* }}} */
986:
987: /* {{{ php_handle_wbmp
988: */
989: static struct gfxinfo *php_handle_wbmp(php_stream * stream TSRMLS_DC)
990: {
991: struct gfxinfo *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
992:
993: if (!php_get_wbmp(stream, &result, 0 TSRMLS_CC)) {
994: efree(result);
995: return NULL;
996: }
997:
998: return result;
999: }
1000: /* }}} */
1001:
1002: /* {{{ php_get_xbm
1003: */
1004: static int php_get_xbm(php_stream *stream, struct gfxinfo **result TSRMLS_DC)
1005: {
1006: char *fline;
1007: char *iname;
1008: char *type;
1009: int value;
1010: unsigned int width = 0, height = 0;
1011:
1012: if (result) {
1013: *result = NULL;
1014: }
1015: if (php_stream_rewind(stream)) {
1016: return 0;
1017: }
1018: while ((fline=php_stream_gets(stream, NULL, 0)) != NULL) {
1019: iname = estrdup(fline); /* simple way to get necessary buffer of required size */
1020: if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
1021: if (!(type = strrchr(iname, '_'))) {
1022: type = iname;
1023: } else {
1024: type++;
1025: }
1026:
1027: if (!strcmp("width", type)) {
1028: width = (unsigned int) value;
1029: if (height) {
1030: efree(iname);
1031: break;
1032: }
1033: }
1034: if (!strcmp("height", type)) {
1035: height = (unsigned int) value;
1036: if (width) {
1037: efree(iname);
1038: break;
1039: }
1040: }
1041: }
1042: efree(fline);
1043: efree(iname);
1044: }
1045: if (fline) {
1046: efree(fline);
1047: }
1048:
1049: if (width && height) {
1050: if (result) {
1051: *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1052: (*result)->width = width;
1053: (*result)->height = height;
1054: }
1055: return IMAGE_FILETYPE_XBM;
1056: }
1057:
1058: return 0;
1059: }
1060: /* }}} */
1061:
1062: /* {{{ php_handle_xbm
1063: */
1064: static struct gfxinfo *php_handle_xbm(php_stream * stream TSRMLS_DC)
1065: {
1066: struct gfxinfo *result;
1067: php_get_xbm(stream, &result TSRMLS_CC);
1068: return result;
1069: }
1070: /* }}} */
1071:
1072: /* {{{ php_handle_ico
1073: */
1074: static struct gfxinfo *php_handle_ico(php_stream * stream TSRMLS_DC)
1075: {
1076: struct gfxinfo *result = NULL;
1077: unsigned char dim[16];
1078: int num_icons = 0;
1079:
1080: if (php_stream_read(stream, dim, 2) != 2)
1081: return NULL;
1082:
1083: num_icons = (((unsigned int)dim[1]) << 8) + ((unsigned int) dim[0]);
1084:
1085: if (num_icons < 1 || num_icons > 255)
1086: return NULL;
1087:
1088: result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1089:
1090: while (num_icons > 0)
1091: {
1092: if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
1093: break;
1094:
1095: if ((((unsigned int)dim[7]) << 8) + ((unsigned int)dim[6]) >= result->bits)
1096: {
1097: result->width = (unsigned int)dim[0];
1098: result->height = (unsigned int)dim[1];
1099: result->bits = (((unsigned int)dim[7]) << 8) + ((unsigned int)dim[6]);
1100: }
1101: num_icons--;
1102: }
1103:
1104: return result;
1105: }
1106: /* }}} */
1107:
1108: /* {{{ php_image_type_to_mime_type
1109: * Convert internal image_type to mime type */
1110: PHPAPI char * php_image_type_to_mime_type(int image_type)
1111: {
1112: switch( image_type) {
1113: case IMAGE_FILETYPE_GIF:
1114: return "image/gif";
1115: case IMAGE_FILETYPE_JPEG:
1116: return "image/jpeg";
1117: case IMAGE_FILETYPE_PNG:
1118: return "image/png";
1119: case IMAGE_FILETYPE_SWF:
1120: case IMAGE_FILETYPE_SWC:
1121: return "application/x-shockwave-flash";
1122: case IMAGE_FILETYPE_PSD:
1123: return "image/psd";
1124: case IMAGE_FILETYPE_BMP:
1125: return "image/x-ms-bmp";
1126: case IMAGE_FILETYPE_TIFF_II:
1127: case IMAGE_FILETYPE_TIFF_MM:
1128: return "image/tiff";
1129: case IMAGE_FILETYPE_IFF:
1130: return "image/iff";
1131: case IMAGE_FILETYPE_WBMP:
1132: return "image/vnd.wap.wbmp";
1133: case IMAGE_FILETYPE_JPC:
1134: return "application/octet-stream";
1135: case IMAGE_FILETYPE_JP2:
1136: return "image/jp2";
1137: case IMAGE_FILETYPE_XBM:
1138: return "image/xbm";
1139: case IMAGE_FILETYPE_ICO:
1140: return "image/vnd.microsoft.icon";
1141: default:
1142: case IMAGE_FILETYPE_UNKNOWN:
1143: return "application/octet-stream"; /* suppose binary format */
1144: }
1145: }
1146: /* }}} */
1147:
1148: /* {{{ proto string image_type_to_mime_type(int imagetype)
1149: Get Mime-Type for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
1150: PHP_FUNCTION(image_type_to_mime_type)
1151: {
1152: long p_image_type;
1153:
1154: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &p_image_type) == FAILURE) {
1155: return;
1156: }
1157:
1158: ZVAL_STRING(return_value, (char*)php_image_type_to_mime_type(p_image_type), 1);
1159: }
1160: /* }}} */
1161:
1162: /* {{{ proto string image_type_to_extension(int imagetype [, bool include_dot])
1163: Get file extension for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
1164: PHP_FUNCTION(image_type_to_extension)
1165: {
1166: long image_type;
1167: zend_bool inc_dot=1;
1168:
1169: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &image_type, &inc_dot) == FAILURE) {
1170: RETURN_FALSE;
1171: }
1172:
1173: switch (image_type) {
1174: case IMAGE_FILETYPE_GIF:
1175: RETURN_STRING(".gif" + !inc_dot, 1);
1176: case IMAGE_FILETYPE_JPEG:
1177: RETURN_STRING(".jpeg" + !inc_dot, 1);
1178: case IMAGE_FILETYPE_PNG:
1179: RETURN_STRING(".png" + !inc_dot, 1);
1180: case IMAGE_FILETYPE_SWF:
1181: case IMAGE_FILETYPE_SWC:
1182: RETURN_STRING(".swf" + !inc_dot, 1);
1183: case IMAGE_FILETYPE_PSD:
1184: RETURN_STRING(".psd" + !inc_dot, 1);
1185: case IMAGE_FILETYPE_BMP:
1186: case IMAGE_FILETYPE_WBMP:
1187: RETURN_STRING(".bmp" + !inc_dot, 1);
1188: case IMAGE_FILETYPE_TIFF_II:
1189: case IMAGE_FILETYPE_TIFF_MM:
1190: RETURN_STRING(".tiff" + !inc_dot, 1);
1191: case IMAGE_FILETYPE_IFF:
1192: RETURN_STRING(".iff" + !inc_dot, 1);
1193: case IMAGE_FILETYPE_JPC:
1194: RETURN_STRING(".jpc" + !inc_dot, 1);
1195: case IMAGE_FILETYPE_JP2:
1196: RETURN_STRING(".jp2" + !inc_dot, 1);
1197: case IMAGE_FILETYPE_JPX:
1198: RETURN_STRING(".jpx" + !inc_dot, 1);
1199: case IMAGE_FILETYPE_JB2:
1200: RETURN_STRING(".jb2" + !inc_dot, 1);
1201: case IMAGE_FILETYPE_XBM:
1202: RETURN_STRING(".xbm" + !inc_dot, 1);
1203: case IMAGE_FILETYPE_ICO:
1204: RETURN_STRING(".ico" + !inc_dot, 1);
1205: }
1206:
1207: RETURN_FALSE;
1208: }
1209: /* }}} */
1210:
1211: /* {{{ php_imagetype
1212: detect filetype from first bytes */
1213: PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
1214: {
1215: char tmp[12];
1216:
1217: if ( !filetype) filetype = tmp;
1218: if((php_stream_read(stream, filetype, 3)) != 3) {
1219: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
1220: return IMAGE_FILETYPE_UNKNOWN;
1221: }
1222:
1223: /* BYTES READ: 3 */
1224: if (!memcmp(filetype, php_sig_gif, 3)) {
1225: return IMAGE_FILETYPE_GIF;
1226: } else if (!memcmp(filetype, php_sig_jpg, 3)) {
1227: return IMAGE_FILETYPE_JPEG;
1228: } else if (!memcmp(filetype, php_sig_png, 3)) {
1229: if (php_stream_read(stream, filetype+3, 5) != 5) {
1230: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
1231: return IMAGE_FILETYPE_UNKNOWN;
1232: }
1233: if (!memcmp(filetype, php_sig_png, 8)) {
1234: return IMAGE_FILETYPE_PNG;
1235: } else {
1236: php_error_docref(NULL TSRMLS_CC, E_WARNING, "PNG file corrupted by ASCII conversion");
1237: return IMAGE_FILETYPE_UNKNOWN;
1238: }
1239: } else if (!memcmp(filetype, php_sig_swf, 3)) {
1240: return IMAGE_FILETYPE_SWF;
1241: } else if (!memcmp(filetype, php_sig_swc, 3)) {
1242: return IMAGE_FILETYPE_SWC;
1243: } else if (!memcmp(filetype, php_sig_psd, 3)) {
1244: return IMAGE_FILETYPE_PSD;
1245: } else if (!memcmp(filetype, php_sig_bmp, 2)) {
1246: return IMAGE_FILETYPE_BMP;
1247: } else if (!memcmp(filetype, php_sig_jpc, 3)) {
1248: return IMAGE_FILETYPE_JPC;
1249: }
1250:
1251: if (php_stream_read(stream, filetype+3, 1) != 1) {
1252: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
1253: return IMAGE_FILETYPE_UNKNOWN;
1254: }
1255: /* BYTES READ: 4 */
1256: if (!memcmp(filetype, php_sig_tif_ii, 4)) {
1257: return IMAGE_FILETYPE_TIFF_II;
1258: } else if (!memcmp(filetype, php_sig_tif_mm, 4)) {
1259: return IMAGE_FILETYPE_TIFF_MM;
1260: } else if (!memcmp(filetype, php_sig_iff, 4)) {
1261: return IMAGE_FILETYPE_IFF;
1262: } else if (!memcmp(filetype, php_sig_ico, 4)) {
1263: return IMAGE_FILETYPE_ICO;
1264: }
1265:
1266: if (php_stream_read(stream, filetype+4, 8) != 8) {
1267: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
1268: return IMAGE_FILETYPE_UNKNOWN;
1269: }
1270: /* BYTES READ: 12 */
1271: if (!memcmp(filetype, php_sig_jp2, 12)) {
1272: return IMAGE_FILETYPE_JP2;
1273: }
1274:
1275: /* AFTER ALL ABOVE FAILED */
1276: if (php_get_wbmp(stream, NULL, 1 TSRMLS_CC)) {
1277: return IMAGE_FILETYPE_WBMP;
1278: }
1279: if (php_get_xbm(stream, NULL TSRMLS_CC)) {
1280: return IMAGE_FILETYPE_XBM;
1281: }
1282: return IMAGE_FILETYPE_UNKNOWN;
1283: }
1284: /* }}} */
1285:
1286: /* {{{ proto array getimagesize(string imagefile [, array info])
1287: Get the size of an image as 4-element array */
1288: PHP_FUNCTION(getimagesize)
1289: {
1290: zval **info = NULL;
1291: char *arg1, *temp;
1292: int arg1_len, itype = 0, argc = ZEND_NUM_ARGS();
1293: struct gfxinfo *result = NULL;
1294: php_stream * stream = NULL;
1295:
1296: if (zend_parse_parameters(argc TSRMLS_CC, "s|Z", &arg1, &arg1_len, &info) == FAILURE) {
1297: return;
1298: }
1299:
1300: if (argc == 2) {
1301: zval_dtor(*info);
1302: array_init(*info);
1303: }
1304:
1305: stream = php_stream_open_wrapper(arg1, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL);
1306:
1307: if (!stream) {
1308: RETURN_FALSE;
1309: }
1310:
1311: itype = php_getimagetype(stream, NULL TSRMLS_CC);
1312: switch( itype) {
1313: case IMAGE_FILETYPE_GIF:
1314: result = php_handle_gif(stream TSRMLS_CC);
1315: break;
1316: case IMAGE_FILETYPE_JPEG:
1317: if (info) {
1318: result = php_handle_jpeg(stream, *info TSRMLS_CC);
1319: } else {
1320: result = php_handle_jpeg(stream, NULL TSRMLS_CC);
1321: }
1322: break;
1323: case IMAGE_FILETYPE_PNG:
1324: result = php_handle_png(stream TSRMLS_CC);
1325: break;
1326: case IMAGE_FILETYPE_SWF:
1327: result = php_handle_swf(stream TSRMLS_CC);
1328: break;
1329: case IMAGE_FILETYPE_SWC:
1330: result = php_handle_swc(stream TSRMLS_CC);
1331: break;
1332: case IMAGE_FILETYPE_PSD:
1333: result = php_handle_psd(stream TSRMLS_CC);
1334: break;
1335: case IMAGE_FILETYPE_BMP:
1336: result = php_handle_bmp(stream TSRMLS_CC);
1337: break;
1338: case IMAGE_FILETYPE_TIFF_II:
1339: result = php_handle_tiff(stream, NULL, 0 TSRMLS_CC);
1340: break;
1341: case IMAGE_FILETYPE_TIFF_MM:
1342: result = php_handle_tiff(stream, NULL, 1 TSRMLS_CC);
1343: break;
1344: case IMAGE_FILETYPE_JPC:
1345: result = php_handle_jpc(stream TSRMLS_CC);
1346: break;
1347: case IMAGE_FILETYPE_JP2:
1348: result = php_handle_jp2(stream TSRMLS_CC);
1349: break;
1350: case IMAGE_FILETYPE_IFF:
1351: result = php_handle_iff(stream TSRMLS_CC);
1352: break;
1353: case IMAGE_FILETYPE_WBMP:
1354: result = php_handle_wbmp(stream TSRMLS_CC);
1355: break;
1356: case IMAGE_FILETYPE_XBM:
1357: result = php_handle_xbm(stream TSRMLS_CC);
1358: break;
1359: case IMAGE_FILETYPE_ICO:
1360: result = php_handle_ico(stream TSRMLS_CC);
1361: break;
1362: default:
1363: case IMAGE_FILETYPE_UNKNOWN:
1364: break;
1365: }
1366:
1367: php_stream_close(stream);
1368:
1369: if (result) {
1370: array_init(return_value);
1371: add_index_long(return_value, 0, result->width);
1372: add_index_long(return_value, 1, result->height);
1373: add_index_long(return_value, 2, itype);
1374: spprintf(&temp, 0, "width=\"%d\" height=\"%d\"", result->width, result->height);
1375: add_index_string(return_value, 3, temp, 0);
1376:
1377: if (result->bits != 0) {
1378: add_assoc_long(return_value, "bits", result->bits);
1379: }
1380: if (result->channels != 0) {
1381: add_assoc_long(return_value, "channels", result->channels);
1382: }
1383: add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype), 1);
1384: efree(result);
1385: } else {
1386: RETURN_FALSE;
1387: }
1388: }
1389: /* }}} */
1390:
1391: /*
1392: * Local variables:
1393: * tab-width: 4
1394: * c-basic-offset: 4
1395: * End:
1396: * vim600: sw=4 ts=4 fdm=marker
1397: * vim<600: sw=4 ts=4
1398: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>