@@ -46,10 +46,13 @@ PHPAPI const char php_sig_swf[3] = {'F', 'W', 'S'};
46
46
PHPAPI const char php_sig_swc [3 ] = {'C' , 'W' , 'S' };
47
47
PHPAPI const char php_sig_jpg [3 ] = {(char ) 0xff , (char ) 0xd8 , (char ) 0xff };
48
48
PHPAPI const char php_sig_png [8 ] = {(char ) 0x89 , (char ) 0x50 , (char ) 0x4e , (char ) 0x47 ,
49
- (char ) 0x0d , (char ) 0x0a , (char ) 0x1a , (char ) 0x0a };
49
+ (char ) 0x0d , (char ) 0x0a , (char ) 0x1a , (char ) 0x0a };
50
50
PHPAPI const char php_sig_tif_ii [4 ] = {'I' ,'I' , (char )0x2A , (char )0x00 };
51
51
PHPAPI const char php_sig_tif_mm [4 ] = {'M' ,'M' , (char )0x00 , (char )0x2A };
52
- PHPAPI const char php_sig_jpc [3 ] = {(char )0xFF , (char )0x4F , (char )0xff };
52
+ PHPAPI const char php_sig_jpc [3 ] = {(char )0xff , (char )0x4f , (char )0xff };
53
+ PHPAPI const char php_sig_jp2 [12 ] = {(char )0x00 , (char )0x00 , (char )0x00 , (char )0x0c ,
54
+ (char )0x6a , (char )0x50 , (char )0x20 , (char )0x20 ,
55
+ (char )0x0d , (char )0x0a , (char )0x87 , (char )0x0a };
53
56
PHPAPI const char php_sig_iff [4 ] = {'F' ,'O' ,'R' ,'M' };
54
57
55
58
/* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */
@@ -76,7 +79,7 @@ PHP_MINIT_FUNCTION(imagetypes)
76
79
REGISTER_LONG_CONSTANT ("IMAGETYPE_BMP" , IMAGE_FILETYPE_BMP , CONST_CS | CONST_PERSISTENT );
77
80
REGISTER_LONG_CONSTANT ("IMAGETYPE_TIFF_II" , IMAGE_FILETYPE_TIFF_II , CONST_CS | CONST_PERSISTENT );
78
81
REGISTER_LONG_CONSTANT ("IMAGETYPE_TIFF_MM" , IMAGE_FILETYPE_TIFF_MM , CONST_CS | CONST_PERSISTENT );
79
- REGISTER_LONG_CONSTANT ("IMAGETYPE_JPC" , IMAGE_FILETYPE_JPC , CONST_CS | CONST_PERSISTENT );
82
+ REGISTER_LONG_CONSTANT ("IMAGETYPE_JPC" , IMAGE_FILETYPE_JPC , CONST_CS | CONST_PERSISTENT );
80
83
REGISTER_LONG_CONSTANT ("IMAGETYPE_JP2" , IMAGE_FILETYPE_JP2 , CONST_CS | CONST_PERSISTENT );
81
84
REGISTER_LONG_CONSTANT ("IMAGETYPE_JPX" , IMAGE_FILETYPE_JPX , CONST_CS | CONST_PERSISTENT );
82
85
REGISTER_LONG_CONSTANT ("IMAGETYPE_JB2" , IMAGE_FILETYPE_JB2 , CONST_CS | CONST_PERSISTENT );
@@ -85,6 +88,7 @@ PHP_MINIT_FUNCTION(imagetypes)
85
88
#endif
86
89
REGISTER_LONG_CONSTANT ("IMAGETYPE_IFF" , IMAGE_FILETYPE_IFF , CONST_CS | CONST_PERSISTENT );
87
90
REGISTER_LONG_CONSTANT ("IMAGETYPE_WBMP" , IMAGE_FILETYPE_WBMP , CONST_CS | CONST_PERSISTENT );
91
+ REGISTER_LONG_CONSTANT ("IMAGETYPE_JPEG2000" ,IMAGE_FILETYPE_JPC ,CONST_CS | CONST_PERSISTENT );/* keep alias */
88
92
return SUCCESS ;
89
93
}
90
94
/* }}} */
@@ -534,12 +538,6 @@ static struct gfxinfo *php_handle_jpeg (php_stream * stream, pval *info TSRMLS_D
534
538
}
535
539
/* }}} */
536
540
537
- /* {{{ jpeg2000 constants
538
- See ext/exif for more */
539
- #define JC_SOC 0x4F /* Start of codestream */
540
- #define JC_SIZ 0x51 /* Image and tile size */
541
- /* }}} */
542
-
543
541
/* {{{ php_read4
544
542
*/
545
543
static unsigned int php_read4 (php_stream * stream TSRMLS_DC )
@@ -556,37 +554,147 @@ static unsigned int php_read4(php_stream * stream TSRMLS_DC)
556
554
}
557
555
/* }}} */
558
556
559
- /* {{{ php_handle_tiff
560
- main loop to parse TIFF structure */
557
+ /* {{{ JPEG 2000 Marker Codes */
558
+ #define JPEG2000_MARKER_PREFIX 0xFF /* All marker codes start with this */
559
+ #define JPEG2000_MARKER_SOC 0x4F /* Start of Codestream */
560
+ #define JPEG2000_MARKER_SOT 0x90 /* Start of Tile part */
561
+ #define JPEG2000_MARKER_SOD 0x93 /* Start of Data */
562
+ #define JPEG2000_MARKER_EOC 0xD9 /* End of Codestream */
563
+ #define JPEG2000_MARKER_SIZ 0x51 /* Image and tile size */
564
+ #define JPEG2000_MARKER_COD 0x52 /* Coding style default */
565
+ #define JPEG2000_MARKER_COC 0x53 /* Coding style component */
566
+ #define JPEG2000_MARKER_RGN 0x5E /* Region of interest */
567
+ #define JPEG2000_MARKER_QCD 0x5C /* Quantization default */
568
+ #define JPEG2000_MARKER_QCC 0x5D /* Quantization component */
569
+ #define JPEG2000_MARKER_POC 0x5F /* Progression order change */
570
+ #define JPEG2000_MARKER_TLM 0x55 /* Tile-part lengths */
571
+ #define JPEG2000_MARKER_PLM 0x57 /* Packet length, main header */
572
+ #define JPEG2000_MARKER_PLT 0x58 /* Packet length, tile-part header */
573
+ #define JPEG2000_MARKER_PPM 0x60 /* Packed packet headers, main header */
574
+ #define JPEG2000_MARKER_PPT 0x61 /* Packed packet headers, tile part header */
575
+ #define JPEG2000_MARKER_SOP 0x91 /* Start of packet */
576
+ #define JPEG2000_MARKER_EPH 0x92 /* End of packet header */
577
+ #define JPEG2000_MARKER_CRG 0x63 /* Component registration */
578
+ #define JPEG2000_MARKER_COM 0x64 /* Comment */
579
+ /* }}} */
580
+
581
+ /* {{{ php_handle_jpc
582
+ Main loop to parse JPEG2000 raw codestream structure */
561
583
static struct gfxinfo * php_handle_jpc (php_stream * stream TSRMLS_DC )
562
584
{
563
585
struct gfxinfo * result = NULL ;
564
- unsigned int marker , dummy ;
565
- unsigned short length , ff_read = 1 ;
586
+ unsigned short dummy_short ;
587
+ int dummy_int , highest_bit_depth , bit_depth ;
588
+ unsigned char first_marker_id ;
589
+ int i ;
590
+
591
+ /* JPEG 2000 components can be vastly different from one another.
592
+ Each component can be sampled at a different resolution, use
593
+ a different colour space, have a seperate colour depth, and
594
+ be compressed totally differently! This makes giving a single
595
+ "bit depth" answer somewhat problematic. For this implementation
596
+ we'll use the highest depth encountered. */
597
+
598
+ /* Get the single byte that remains after the file type indentification */
599
+ first_marker_id = php_stream_getc (stream );
600
+
601
+ /* Ensure that this marker is SIZ (as is mandated by the standard) */
602
+ if (first_marker_id != JPEG2000_MARKER_SIZ ) {
603
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "JPEG2000 codestream corrupt(Expected SIZ marker not found after SOC)" );
604
+ return NULL ;
605
+ }
606
+
607
+ result = (struct gfxinfo * )ecalloc (1 , sizeof (struct gfxinfo ));
608
+ if (!result ) {
609
+ return NULL ;
610
+ }
611
+
612
+ dummy_short = php_read2 (stream TSRMLS_CC ); /* Lsiz */
613
+ dummy_short = php_read2 (stream TSRMLS_CC ); /* Rsiz */
614
+ result -> height = php_read4 (stream TSRMLS_CC ); /* Xsiz */
615
+ result -> width = php_read4 (stream TSRMLS_CC ); /* Ysiz */
616
+
617
+ dummy_int = php_read4 (stream TSRMLS_CC ); /* XOsiz */
618
+ dummy_int = php_read4 (stream TSRMLS_CC ); /* YOsiz */
619
+ dummy_int = php_read4 (stream TSRMLS_CC ); /* XTsiz */
620
+ dummy_int = php_read4 (stream TSRMLS_CC ); /* YTsiz */
621
+ dummy_int = php_read4 (stream TSRMLS_CC ); /* XTOsiz */
622
+ dummy_int = php_read4 (stream TSRMLS_CC ); /* YTOsiz */
623
+
624
+ result -> channels = php_read2 (stream TSRMLS_CC ); /* Csiz */
625
+
626
+ /* Collect and average bit depth info */
627
+ highest_bit_depth = bit_depth = 0 ;
628
+ for (i = 0 ; i < result -> channels ; i ++ ) {
629
+ bit_depth = php_stream_getc (stream ); /* Ssiz[i] */
630
+ bit_depth ++ ;
631
+ if (bit_depth > highest_bit_depth ) {
632
+ highest_bit_depth = bit_depth ;
633
+ }
634
+
635
+ php_stream_getc (stream ); /* XRsiz[i] */
636
+ php_stream_getc (stream ); /* YRsiz[i] */
637
+ }
638
+
639
+ result -> bits = highest_bit_depth ;
566
640
567
- marker = php_next_marker (stream , 0 , 0 , ff_read TSRMLS_CC );
568
- ff_read = 0 ;
569
- if ( marker == JC_SIZ )
641
+ return result ;
642
+ }
643
+ /* }}} */
644
+
645
+ /* {{{ php_handle_jp2
646
+ main loop to parse JPEG 2000 JP2 wrapper format structure */
647
+ static struct gfxinfo * php_handle_jp2 (php_stream * stream TSRMLS_DC )
648
+ {
649
+ struct gfxinfo * result = NULL ;
650
+ unsigned int box_length ;
651
+ unsigned int box_type ;
652
+ char jp2c_box_id [] = {(char )0x6a , (char )0x70 , (char )0x32 , (char )0x63 };
653
+
654
+ /* JP2 is a wrapper format for JPEG 2000. Data is contained within "boxes".
655
+ Boxes themselves can be contained within "super-boxes". Super-Boxes can
656
+ contain super-boxes which provides us with a hierarchical storage system.
657
+
658
+ It is valid for a JP2 file to contain multiple individual codestreams.
659
+ We'll just look for the first codestream at the root of the box structure
660
+ and handle that.
661
+ */
662
+
663
+ for (;;)
570
664
{
571
- length = php_read2 (stream TSRMLS_CC ); /* Lsiz: length of segment */
572
- if ( length < 42 || length > 49191 ) /* read the spec */
573
- return NULL ;
574
- result = (struct gfxinfo * ) ecalloc (1 , sizeof (struct gfxinfo ));
575
- if ( !result )
665
+ box_length = php_read4 (stream TSRMLS_CC ); /* LBox */
666
+ /* TBox */
667
+ if (php_stream_read (stream , (void * )& box_type , sizeof (box_type )) != sizeof (box_type )) {
668
+ break ;
669
+ }
670
+
671
+ /* Safe to use the 0 return for EOF as neither of these can be 0 */
672
+ if (box_length == 0 || box_type == 0 ) {
673
+ break ;
674
+ }
675
+
676
+ if (box_length == 1 ) {
677
+ /* We won't handle XLBoxes */
576
678
return NULL ;
577
- dummy = php_read2 (stream TSRMLS_CC ); /* Rsiz: capabilities */
578
- result -> height = php_read4 (stream TSRMLS_CC ); /* Xsiz */
579
- result -> width = php_read4 (stream TSRMLS_CC ); /* Ysiz */
580
- dummy = php_read4 (stream TSRMLS_CC ); /* X0siz */
581
- dummy = php_read4 (stream TSRMLS_CC ); /* Y0siz */
582
- dummy = php_read4 (stream TSRMLS_CC ); /* XTsiz */
583
- dummy = php_read4 (stream TSRMLS_CC ); /* YTsiz */
584
- dummy = php_read4 (stream TSRMLS_CC ); /* XT0siz */
585
- dummy = php_read4 (stream TSRMLS_CC ); /* YT0siz */
586
- result -> bits = php_read2 (stream TSRMLS_CC ); /* Csiz: precision in bitss */
587
- result -> channels = 0 ; /* don't know yet */
588
- return result ;
679
+ }
680
+
681
+ if (!memcmp (& box_type , jp2c_box_id , 4 ))
682
+ {
683
+ /* Skip the first 3 bytes to emulate the file type examination */
684
+ php_stream_seek (stream , 3 , SEEK_CUR );
685
+
686
+ result = php_handle_jpc (stream TSRMLS_CC );
687
+ break ;
688
+ }
689
+
690
+ /* Skip over LBox (Which includes both TBox and LBox itself */
691
+ php_stream_seek (stream , box_length - 8 , SEEK_CUR );
692
+ }
693
+
694
+ if (result == NULL ) {
695
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "JP2 file has no codestreams at root level" );
589
696
}
697
+
590
698
return result ;
591
699
}
592
700
/* }}} */
@@ -867,7 +975,6 @@ PHPAPI const char * php_image_type_to_mime_type(int image_type)
867
975
case IMAGE_FILETYPE_GIF :
868
976
return "image/gif" ;
869
977
case IMAGE_FILETYPE_JPEG :
870
- case IMAGE_FILETYPE_JPC :
871
978
return "image/jpeg" ;
872
979
case IMAGE_FILETYPE_PNG :
873
980
return "image/png" ;
@@ -885,6 +992,10 @@ PHPAPI const char * php_image_type_to_mime_type(int image_type)
885
992
return "image/iff" ;
886
993
case IMAGE_FILETYPE_WBMP :
887
994
return "image/vnd.wap.wbmp" ;
995
+ case IMAGE_FILETYPE_JPC :
996
+ return "application/octet-stream" ;
997
+ case IMAGE_FILETYPE_JP2 :
998
+ return "image/jp2" ;
888
999
default :
889
1000
case IMAGE_FILETYPE_UNKNOWN :
890
1001
return "application/octet-stream" ; /* suppose binary format */
@@ -912,20 +1023,24 @@ PHP_FUNCTION(image_type_to_mime_type)
912
1023
detect filetype from first bytes */
913
1024
PHPAPI int php_getimagetype (php_stream * stream , char * filetype TSRMLS_DC )
914
1025
{
915
- char tmp [8 ];
1026
+ char tmp [12 ];
916
1027
917
1028
if ( !filetype ) filetype = tmp ;
918
- if ((php_stream_read (stream , filetype , 3 )) <= 0 ) {
1029
+ if ((php_stream_read (stream , filetype , 3 )) != 3 ) {
919
1030
php_error_docref (NULL TSRMLS_CC , E_WARNING , "Read error !");
920
1031
return IMAGE_FILETYPE_UNKNOWN ;
921
1032
}
922
1033
1034
+ /* BYTES READ: 3 */
923
1035
if (!memcmp (filetype , php_sig_gif , 3 )) {
924
1036
return IMAGE_FILETYPE_GIF ;
925
1037
} else if (!memcmp (filetype , php_sig_jpg , 3 )) {
926
1038
return IMAGE_FILETYPE_JPEG ;
927
1039
} else if (!memcmp (filetype , php_sig_png , 3 )) {
928
- php_stream_read (stream , filetype + 3 , 5 );
1040
+ if (php_stream_read (stream , filetype + 3 , 5 ) != 5 ) {
1041
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Read error !");
1042
+ return IMAGE_FILETYPE_UNKNOWN ;
1043
+ }
929
1044
if (!memcmp (filetype , php_sig_png , 8 )) {
930
1045
return IMAGE_FILETYPE_PNG ;
931
1046
} else {
@@ -943,7 +1058,12 @@ PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
943
1058
} else if (!memcmp (filetype , php_sig_jpc , 3 )) {
944
1059
return IMAGE_FILETYPE_JPC ;
945
1060
}
946
- php_stream_read (stream , filetype + 3 , 1 );
1061
+
1062
+ if (php_stream_read (stream , filetype + 3 , 1 ) != 1 ) {
1063
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Read error !");
1064
+ return IMAGE_FILETYPE_UNKNOWN ;
1065
+ }
1066
+ /* BYTES READ: 4 */
947
1067
if (!memcmp (filetype , php_sig_tif_ii , 4 )) {
948
1068
return IMAGE_FILETYPE_TIFF_II ;
949
1069
} else
@@ -956,7 +1076,16 @@ PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
956
1076
if (php_get_wbmp (stream , NULL , 1 TSRMLS_CC )) {
957
1077
return IMAGE_FILETYPE_WBMP ;
958
1078
}
959
-
1079
+
1080
+ if (php_stream_read (stream , filetype + 4 , 8 ) != 8 ) {
1081
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Read error !");
1082
+ return IMAGE_FILETYPE_UNKNOWN ;
1083
+ }
1084
+ /* BYTES READ: 12 */
1085
+ if (!memcmp (filetype , php_sig_jp2 , 12 )) {
1086
+ return IMAGE_FILETYPE_JP2 ;
1087
+ }
1088
+
960
1089
return IMAGE_FILETYPE_UNKNOWN ;
961
1090
}
962
1091
/* }}} */
@@ -1042,10 +1171,13 @@ PHP_FUNCTION(getimagesize)
1042
1171
case IMAGE_FILETYPE_JPC :
1043
1172
result = php_handle_jpc (stream TSRMLS_CC );
1044
1173
break ;
1174
+ case IMAGE_FILETYPE_JP2 :
1175
+ result = php_handle_jp2 (stream TSRMLS_CC );
1176
+ break ;
1045
1177
case IMAGE_FILETYPE_IFF :
1046
- result = php_handle_iff (stream TSRMLS_CC );
1047
- break ;
1048
- case IMAGE_FILETYPE_WBMP :
1178
+ result = php_handle_iff (stream TSRMLS_CC );
1179
+ break ;
1180
+ case IMAGE_FILETYPE_WBMP :
1049
1181
result = php_handle_wbmp (stream TSRMLS_CC );
1050
1182
break ;
1051
1183
default :
0 commit comments