Annotation of embedaddon/php/ext/standard/image.c, revision 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>