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