Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/PIL/FpxImagePlugin.py: 1%

92 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1# 

2# THIS IS WORK IN PROGRESS 

3# 

4# The Python Imaging Library. 

5# $Id$ 

6# 

7# FlashPix support for PIL 

8# 

9# History: 

10# 97-01-25 fl Created (reads uncompressed RGB images only) 

11# 

12# Copyright (c) Secret Labs AB 1997. 

13# Copyright (c) Fredrik Lundh 1997. 

14# 

15# See the README file for information on usage and redistribution. 

16# 

17import olefile 

18 

19from . import Image, ImageFile 

20from ._binary import i32le as i32 

21 

22# we map from colour field tuples to (mode, rawmode) descriptors 

23MODES = { 

24 # opacity 

25 (0x00007FFE,): ("A", "L"), 

26 # monochrome 

27 (0x00010000,): ("L", "L"), 

28 (0x00018000, 0x00017FFE): ("RGBA", "LA"), 

29 # photo YCC 

30 (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"), 

31 (0x00028000, 0x00028001, 0x00028002, 0x00027FFE): ("RGBA", "YCCA;P"), 

32 # standard RGB (NIFRGB) 

33 (0x00030000, 0x00030001, 0x00030002): ("RGB", "RGB"), 

34 (0x00038000, 0x00038001, 0x00038002, 0x00037FFE): ("RGBA", "RGBA"), 

35} 

36 

37 

38# 

39# -------------------------------------------------------------------- 

40 

41 

42def _accept(prefix): 

43 return prefix[:8] == olefile.MAGIC 

44 

45 

46## 

47# Image plugin for the FlashPix images. 

48 

49 

50class FpxImageFile(ImageFile.ImageFile): 

51 

52 format = "FPX" 

53 format_description = "FlashPix" 

54 

55 def _open(self): 

56 # 

57 # read the OLE directory and see if this is a likely 

58 # to be a FlashPix file 

59 

60 try: 

61 self.ole = olefile.OleFileIO(self.fp) 

62 except OSError as e: 

63 raise SyntaxError("not an FPX file; invalid OLE file") from e 

64 

65 if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B": 

66 raise SyntaxError("not an FPX file; bad root CLSID") 

67 

68 self._open_index(1) 

69 

70 def _open_index(self, index=1): 

71 # 

72 # get the Image Contents Property Set 

73 

74 prop = self.ole.getproperties( 

75 [f"Data Object Store {index:06d}", "\005Image Contents"] 

76 ) 

77 

78 # size (highest resolution) 

79 

80 self._size = prop[0x1000002], prop[0x1000003] 

81 

82 size = max(self.size) 

83 i = 1 

84 while size > 64: 

85 size = size / 2 

86 i += 1 

87 self.maxid = i - 1 

88 

89 # mode. instead of using a single field for this, flashpix 

90 # requires you to specify the mode for each channel in each 

91 # resolution subimage, and leaves it to the decoder to make 

92 # sure that they all match. for now, we'll cheat and assume 

93 # that this is always the case. 

94 

95 id = self.maxid << 16 

96 

97 s = prop[0x2000002 | id] 

98 

99 colors = [] 

100 bands = i32(s, 4) 

101 if bands > 4: 

102 raise OSError("Invalid number of bands") 

103 for i in range(bands): 

104 # note: for now, we ignore the "uncalibrated" flag 

105 colors.append(i32(s, 8 + i * 4) & 0x7FFFFFFF) 

106 

107 self.mode, self.rawmode = MODES[tuple(colors)] 

108 

109 # load JPEG tables, if any 

110 self.jpeg = {} 

111 for i in range(256): 

112 id = 0x3000001 | (i << 16) 

113 if id in prop: 

114 self.jpeg[i] = prop[id] 

115 

116 self._open_subimage(1, self.maxid) 

117 

118 def _open_subimage(self, index=1, subimage=0): 

119 # 

120 # setup tile descriptors for a given subimage 

121 

122 stream = [ 

123 f"Data Object Store {index:06d}", 

124 f"Resolution {subimage:04d}", 

125 "Subimage 0000 Header", 

126 ] 

127 

128 fp = self.ole.openstream(stream) 

129 

130 # skip prefix 

131 fp.read(28) 

132 

133 # header stream 

134 s = fp.read(36) 

135 

136 size = i32(s, 4), i32(s, 8) 

137 # tilecount = i32(s, 12) 

138 tilesize = i32(s, 16), i32(s, 20) 

139 # channels = i32(s, 24) 

140 offset = i32(s, 28) 

141 length = i32(s, 32) 

142 

143 if size != self.size: 

144 raise OSError("subimage mismatch") 

145 

146 # get tile descriptors 

147 fp.seek(28 + offset) 

148 s = fp.read(i32(s, 12) * length) 

149 

150 x = y = 0 

151 xsize, ysize = size 

152 xtile, ytile = tilesize 

153 self.tile = [] 

154 

155 for i in range(0, len(s), length): 

156 

157 x1 = min(xsize, x + xtile) 

158 y1 = min(ysize, y + ytile) 

159 

160 compression = i32(s, i + 8) 

161 

162 if compression == 0: 

163 self.tile.append( 

164 ( 

165 "raw", 

166 (x, y, x1, y1), 

167 i32(s, i) + 28, 

168 (self.rawmode,), 

169 ) 

170 ) 

171 

172 elif compression == 1: 

173 

174 # FIXME: the fill decoder is not implemented 

175 self.tile.append( 

176 ( 

177 "fill", 

178 (x, y, x1, y1), 

179 i32(s, i) + 28, 

180 (self.rawmode, s[12:16]), 

181 ) 

182 ) 

183 

184 elif compression == 2: 

185 

186 internal_color_conversion = s[14] 

187 jpeg_tables = s[15] 

188 rawmode = self.rawmode 

189 

190 if internal_color_conversion: 

191 # The image is stored as usual (usually YCbCr). 

192 if rawmode == "RGBA": 

193 # For "RGBA", data is stored as YCbCrA based on 

194 # negative RGB. The following trick works around 

195 # this problem : 

196 jpegmode, rawmode = "YCbCrK", "CMYK" 

197 else: 

198 jpegmode = None # let the decoder decide 

199 

200 else: 

201 # The image is stored as defined by rawmode 

202 jpegmode = rawmode 

203 

204 self.tile.append( 

205 ( 

206 "jpeg", 

207 (x, y, x1, y1), 

208 i32(s, i) + 28, 

209 (rawmode, jpegmode), 

210 ) 

211 ) 

212 

213 # FIXME: jpeg tables are tile dependent; the prefix 

214 # data must be placed in the tile descriptor itself! 

215 

216 if jpeg_tables: 

217 self.tile_prefix = self.jpeg[jpeg_tables] 

218 

219 else: 

220 raise OSError("unknown/invalid compression") 

221 

222 x = x + xtile 

223 if x >= xsize: 

224 x, y = 0, y + ytile 

225 if y >= ysize: 

226 break # isn't really required 

227 

228 self.stream = stream 

229 self.fp = None 

230 

231 def load(self): 

232 

233 if not self.fp: 

234 self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"]) 

235 

236 return ImageFile.ImageFile.load(self) 

237 

238 

239# 

240# -------------------------------------------------------------------- 

241 

242 

243Image.register_open(FpxImageFile.format, FpxImageFile, _accept) 

244 

245Image.register_extension(FpxImageFile.format, ".fpx")