@@ -38,6 +38,21 @@ class SunImageFile(ImageFile.ImageFile):
3838
3939 def _open (self ):
4040
41+ # The Sun Raster file header is 32 bytes in length and has the following format:
42+
43+ # typedef struct _SunRaster
44+ # {
45+ # DWORD MagicNumber; /* Magic (identification) number */
46+ # DWORD Width; /* Width of image in pixels */
47+ # DWORD Height; /* Height of image in pixels */
48+ # DWORD Depth; /* Number of bits per pixel */
49+ # DWORD Length; /* Size of image data in bytes */
50+ # DWORD Type; /* Type of raster file */
51+ # DWORD ColorMapType; /* Type of color map */
52+ # DWORD ColorMapLength; /* Size of the color map in bytes */
53+ # } SUNRASTER;
54+
55+
4156 # HEAD
4257 s = self .fp .read (32 )
4358 if i32 (s ) != 0x59a66a95 :
@@ -48,31 +63,71 @@ def _open(self):
4863 self .size = i32 (s [4 :8 ]), i32 (s [8 :12 ])
4964
5065 depth = i32 (s [12 :16 ])
66+ data_length = i32 (s [16 :20 ]) # unreliable, ignore.
67+ file_type = i32 (s [20 :24 ])
68+ palette_type = i32 (s [24 :28 ]) # 0: None, 1: RGB, 2: Raw/arbitrary
69+ palette_length = i32 (s [28 :32 ])
70+
5171 if depth == 1 :
5272 self .mode , rawmode = "1" , "1;I"
73+ elif depth == 4 :
74+ self .mode , rawmode = "L" , "L;4"
5375 elif depth == 8 :
5476 self .mode = rawmode = "L"
5577 elif depth == 24 :
56- self .mode , rawmode = "RGB" , "BGR"
78+ if file_type == 3 :
79+ self .mode , rawmode = "RGB" , "RGB"
80+ else :
81+ self .mode , rawmode = "RGB" , "BGR"
82+ elif depth == 32 :
83+ if file_type == 3 :
84+ self .mode , rawmode = 'RGB' , 'RGBX'
85+ else :
86+ self .mode , rawmode = 'RGB' , 'BGRX'
5787 else :
58- raise SyntaxError ("unsupported mode" )
59-
60- compression = i32 (s [20 :24 ])
61-
62- if i32 (s [24 :28 ]) != 0 :
63- length = i32 (s [28 :32 ])
64- offset = offset + length
65- self .palette = ImagePalette .raw ("RGB;L" , self .fp .read (length ))
88+ raise SyntaxError ("Unsupported Mode/Bit Depth" )
89+
90+ if palette_length :
91+ if palette_length > 1024 :
92+ raise SyntaxError ("Unsupported Color Palette Length" )
93+
94+ if palette_type != 1 :
95+ raise SyntaxError ("Unsupported Palette Type" )
96+
97+ offset = offset + palette_length
98+ self .palette = ImagePalette .raw ("RGB;L" , self .fp .read (palette_length ))
6699 if self .mode == "L" :
67- self .mode = rawmode = "P"
68-
69- stride = (((self .size [0 ] * depth + 7 ) // 8 ) + 3 ) & (~ 3 )
70-
71- if compression == 1 :
100+ self .mode = "P"
101+ rawmode = rawmode .replace ('L' , 'P' )
102+
103+ # 16 bit boundaries on stride
104+ stride = ((self .size [0 ] * depth + 15 ) // 16 ) * 2
105+
106+ # file type: Type is the version (or flavor) of the bitmap
107+ # file. The following values are typically found in the Type
108+ # field:
109+ # 0000h Old
110+ # 0001h Standard
111+ # 0002h Byte-encoded
112+ # 0003h RGB format
113+ # 0004h TIFF format
114+ # 0005h IFF format
115+ # FFFFh Experimental
116+
117+ # Old and standard are the same, except for the length tag.
118+ # byte-encoded is run-length-encoded
119+ # RGB looks similar to standard, but RGB byte order
120+ # TIFF and IFF mean that they were converted from T/IFF
121+ # Experimental means that it's something else.
122+ # (http://www.fileformat.info/format/sunraster/egff.htm)
123+
124+ if file_type in (0 , 1 , 3 , 4 , 5 ):
72125 self .tile = [("raw" , (0 , 0 )+ self .size , offset , (rawmode , stride ))]
73- elif compression == 2 :
126+ elif file_type == 2 :
74127 self .tile = [("sun_rle" , (0 , 0 )+ self .size , offset , rawmode )]
75-
128+ else :
129+ raise SyntaxError ('Unsupported Sun Raster file type' )
130+
76131#
77132# registry
78133
0 commit comments