Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/imageio-2.35.1-py3.8.egg/imageio/plugins/swf.py: 18%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

174 statements  

1# -*- coding: utf-8 -*- 

2# imageio is distributed under the terms of the (new) BSD License. 

3 

4""" Read/Write SWF files. 

5 

6Backend: internal 

7 

8Shockwave flash (SWF) is a media format designed for rich and 

9interactive animations. This plugin makes use of this format to 

10store a series of images in a lossless format with good compression 

11(zlib). The resulting images can be shown as an animation using 

12a flash player (such as the browser). 

13 

14SWF stores images in RGBA format. RGB or grayscale images are 

15automatically converted. SWF does not support meta data. 

16 

17Parameters for reading 

18---------------------- 

19loop : bool 

20 If True, the video will rewind as soon as a frame is requested 

21 beyond the last frame. Otherwise, IndexError is raised. Default False. 

22 

23Parameters for saving 

24--------------------- 

25fps : int 

26 The speed to play the animation. Default 12. 

27loop : bool 

28 If True, add a tag to the end of the file to play again from 

29 the first frame. Most flash players will then play the movie 

30 in a loop. Note that the imageio SWF Reader does not check this 

31 tag. Default True. 

32html : bool 

33 If the output is a file on the file system, write an html file 

34 (in HTML5) that shows the animation. Default False. 

35compress : bool 

36 Whether to compress the swf file. Default False. You probably don't 

37 want to use this. This does not decrease the file size since 

38 the images are already compressed. It will result in slower 

39 read and write time. The only purpose of this feature is to 

40 create compressed SWF files, so that we can test the 

41 functionality to read them. 

42 

43""" 

44 

45import os 

46import zlib 

47import logging 

48from io import BytesIO 

49 

50import numpy as np 

51 

52from ..core import Format, read_n_bytes, image_as_uint 

53 

54 

55logger = logging.getLogger(__name__) 

56 

57_swf = None # lazily loaded in lib() 

58 

59 

60def load_lib(): 

61 global _swf 

62 from . import _swf 

63 

64 return _swf 

65 

66 

67class SWFFormat(Format): 

68 """See :mod:`imageio.plugins.swf`""" 

69 

70 def _can_read(self, request): 

71 tmp = request.firstbytes[0:3].decode("ascii", "ignore") 

72 if tmp in ("FWS", "CWS"): 

73 return True 

74 

75 def _can_write(self, request): 

76 if request.extension in self.extensions: 

77 return True 

78 

79 # -- reader 

80 

81 class Reader(Format.Reader): 

82 def _open(self, loop=False): 

83 if not _swf: 

84 load_lib() 

85 

86 self._arg_loop = bool(loop) 

87 

88 self._fp = self.request.get_file() 

89 

90 # Check file ... 

91 tmp = self.request.firstbytes[0:3].decode("ascii", "ignore") 

92 if tmp == "FWS": 

93 pass # OK 

94 elif tmp == "CWS": 

95 # Compressed, we need to decompress 

96 bb = self._fp.read() 

97 bb = bb[:8] + zlib.decompress(bb[8:]) 

98 # Wrap up in a file object 

99 self._fp = BytesIO(bb) 

100 else: 

101 raise IOError("This does not look like a valid SWF file") 

102 

103 # Skip first bytes. This also tests support got seeking ... 

104 try: 

105 self._fp.seek(8) 

106 self._streaming_mode = False 

107 except Exception: 

108 self._streaming_mode = True 

109 self._fp_read(8) 

110 

111 # Skip header 

112 # Note that the number of frames is there, which we could 

113 # potentially use, but the number of frames does not necessarily 

114 # correspond to the number of images. 

115 nbits = _swf.bits2int(self._fp_read(1), 5) 

116 nbits = 5 + nbits * 4 

117 Lrect = nbits / 8.0 

118 if Lrect % 1: 

119 Lrect += 1 

120 Lrect = int(Lrect) 

121 self._fp_read(Lrect + 3) 

122 

123 # Now the rest is basically tags ... 

124 self._imlocs = [] # tuple (loc, sze, T, L1) 

125 if not self._streaming_mode: 

126 # Collect locations of frame, while skipping through the data 

127 # This does not read any of the tag *data*. 

128 try: 

129 while True: 

130 isimage, sze, T, L1 = self._read_one_tag() 

131 loc = self._fp.tell() 

132 if isimage: 

133 # Still need to check if the format is right 

134 format = ord(self._fp_read(3)[2:]) 

135 if format == 5: # RGB or RGBA lossless 

136 self._imlocs.append((loc, sze, T, L1)) 

137 self._fp.seek(loc + sze) # Skip over tag 

138 except IndexError: 

139 pass # done reading 

140 

141 def _fp_read(self, n): 

142 return read_n_bytes(self._fp, n) 

143 

144 def _close(self): 

145 pass 

146 

147 def _get_length(self): 

148 if self._streaming_mode: 

149 return np.inf 

150 else: 

151 return len(self._imlocs) 

152 

153 def _get_data(self, index): 

154 # Check index 

155 if index < 0: 

156 raise IndexError("Index in swf file must be > 0") 

157 if not self._streaming_mode: 

158 if self._arg_loop and self._imlocs: 

159 index = index % len(self._imlocs) 

160 if index >= len(self._imlocs): 

161 raise IndexError("Index out of bounds") 

162 

163 if self._streaming_mode: 

164 # Walk over tags until we find an image 

165 while True: 

166 isimage, sze, T, L1 = self._read_one_tag() 

167 bb = self._fp_read(sze) # always read data 

168 if isimage: 

169 im = _swf.read_pixels(bb, 0, T, L1) # can be None 

170 if im is not None: 

171 return im, {} 

172 

173 else: 

174 # Go to corresponding location, read data, and convert to image 

175 loc, sze, T, L1 = self._imlocs[index] 

176 self._fp.seek(loc) 

177 bb = self._fp_read(sze) 

178 # Read_pixels should return ndarry, since we checked format 

179 im = _swf.read_pixels(bb, 0, T, L1) 

180 return im, {} 

181 

182 def _read_one_tag(self): 

183 """ 

184 Return (True, loc, size, T, L1) if an image that we can read. 

185 Return (False, loc, size, T, L1) if any other tag. 

186 """ 

187 

188 # Get head 

189 head = self._fp_read(6) 

190 if not head: # pragma: no cover 

191 raise IndexError("Reached end of swf movie") 

192 

193 # Determine type and length 

194 T, L1, L2 = _swf.get_type_and_len(head) 

195 if not L2: # pragma: no cover 

196 raise RuntimeError("Invalid tag length, could not proceed") 

197 

198 # Read data 

199 isimage = False 

200 sze = L2 - 6 

201 # bb = self._fp_read(L2 - 6) 

202 

203 # Parse tag 

204 if T == 0: 

205 raise IndexError("Reached end of swf movie") 

206 elif T in [20, 36]: 

207 isimage = True 

208 # im = _swf.read_pixels(bb, 0, T, L1) # can be None 

209 elif T in [6, 21, 35, 90]: # pragma: no cover 

210 logger.warning("Ignoring JPEG image: cannot read JPEG.") 

211 else: 

212 pass # Not an image tag 

213 

214 # Done. Return image. Can be None 

215 # return im 

216 return isimage, sze, T, L1 

217 

218 def _get_meta_data(self, index): 

219 return {} # This format does not support meta data 

220 

221 # -- writer 

222 

223 class Writer(Format.Writer): 

224 def _open(self, fps=12, loop=True, html=False, compress=False): 

225 if not _swf: 

226 load_lib() 

227 

228 self._arg_fps = int(fps) 

229 self._arg_loop = bool(loop) 

230 self._arg_html = bool(html) 

231 self._arg_compress = bool(compress) 

232 

233 self._fp = self.request.get_file() 

234 self._framecounter = 0 

235 self._framesize = (100, 100) 

236 

237 # For compress, we use an in-memory file object 

238 if self._arg_compress: 

239 self._fp_real = self._fp 

240 self._fp = BytesIO() 

241 

242 def _close(self): 

243 self._complete() 

244 # Get size of (uncompressed) file 

245 sze = self._fp.tell() 

246 # set nframes, this is in the potentially compressed region 

247 self._fp.seek(self._location_to_save_nframes) 

248 self._fp.write(_swf.int2uint16(self._framecounter)) 

249 # Compress body? 

250 if self._arg_compress: 

251 bb = self._fp.getvalue() 

252 self._fp = self._fp_real 

253 self._fp.write(bb[:8]) 

254 self._fp.write(zlib.compress(bb[8:])) 

255 sze = self._fp.tell() # renew sze value 

256 # set size 

257 self._fp.seek(4) 

258 self._fp.write(_swf.int2uint32(sze)) 

259 self._fp = None # Disable 

260 

261 # Write html? 

262 if self._arg_html and os.path.isfile(self.request.filename): 

263 dirname, fname = os.path.split(self.request.filename) 

264 filename = os.path.join(dirname, fname[:-4] + ".html") 

265 w, h = self._framesize 

266 html = HTML % (fname, w, h, fname) 

267 with open(filename, "wb") as f: 

268 f.write(html.encode("utf-8")) 

269 

270 def _write_header(self, framesize, fps): 

271 self._framesize = framesize 

272 # Called as soon as we know framesize; when we get first frame 

273 bb = b"" 

274 bb += "FC"[self._arg_compress].encode("ascii") 

275 bb += "WS".encode("ascii") # signature bytes 

276 bb += _swf.int2uint8(8) # version 

277 bb += "0000".encode("ascii") # FileLength (leave open for now) 

278 bb += ( 

279 _swf.Tag().make_rect_record(0, framesize[0], 0, framesize[1]).tobytes() 

280 ) 

281 bb += _swf.int2uint8(0) + _swf.int2uint8(fps) # FrameRate 

282 self._location_to_save_nframes = len(bb) 

283 bb += "00".encode("ascii") # nframes (leave open for now) 

284 self._fp.write(bb) 

285 

286 # Write some initial tags 

287 taglist = _swf.FileAttributesTag(), _swf.SetBackgroundTag(0, 0, 0) 

288 for tag in taglist: 

289 self._fp.write(tag.get_tag()) 

290 

291 def _complete(self): 

292 # What if no images were saved? 

293 if not self._framecounter: 

294 self._write_header((10, 10), self._arg_fps) 

295 # Write stop tag if we do not loop 

296 if not self._arg_loop: 

297 self._fp.write(_swf.DoActionTag("stop").get_tag()) 

298 # finish with end tag 

299 self._fp.write("\x00\x00".encode("ascii")) 

300 

301 def _append_data(self, im, meta): 

302 # Correct shape and type 

303 if im.ndim == 3 and im.shape[-1] == 1: 

304 im = im[:, :, 0] 

305 im = image_as_uint(im, bitdepth=8) 

306 # Get frame size 

307 wh = im.shape[1], im.shape[0] 

308 # Write header on first frame 

309 isfirstframe = False 

310 if self._framecounter == 0: 

311 isfirstframe = True 

312 self._write_header(wh, self._arg_fps) 

313 # Create tags 

314 bm = _swf.BitmapTag(im) 

315 sh = _swf.ShapeTag(bm.id, (0, 0), wh) 

316 po = _swf.PlaceObjectTag(1, sh.id, move=(not isfirstframe)) 

317 sf = _swf.ShowFrameTag() 

318 # Write tags 

319 for tag in [bm, sh, po, sf]: 

320 self._fp.write(tag.get_tag()) 

321 self._framecounter += 1 

322 

323 def set_meta_data(self, meta): 

324 pass 

325 

326 

327HTML = """ 

328<!DOCTYPE html> 

329<html> 

330<head> 

331 <title>Show Flash animation %s</title> 

332</head> 

333<body> 

334 <embed width="%i" height="%i" src="%s"> 

335</html> 

336"""