Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
344
venv/Lib/site-packages/imageio/plugins/swf.py
Normal file
344
venv/Lib/site-packages/imageio/plugins/swf.py
Normal file
|
@ -0,0 +1,344 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# imageio is distributed under the terms of the (new) BSD License.
|
||||
|
||||
""" SWF plugin. Most of the actual work is done in _swf.py.
|
||||
"""
|
||||
|
||||
import os
|
||||
import zlib
|
||||
import logging
|
||||
from io import BytesIO
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .. import formats
|
||||
from ..core import Format, read_n_bytes, image_as_uint
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_swf = None # lazily loaded in lib()
|
||||
|
||||
|
||||
def load_lib():
|
||||
global _swf
|
||||
from . import _swf
|
||||
|
||||
return _swf
|
||||
|
||||
|
||||
class SWFFormat(Format):
|
||||
""" Shockwave flash (SWF) is a media format designed for rich and
|
||||
interactive animations. This plugin makes use of this format to
|
||||
store a series of images in a lossless format with good compression
|
||||
(zlib). The resulting images can be shown as an animation using
|
||||
a flash player (such as the browser).
|
||||
|
||||
SWF stores images in RGBA format. RGB or grayscale images are
|
||||
automatically converted. SWF does not support meta data.
|
||||
|
||||
Parameters for reading
|
||||
----------------------
|
||||
loop : bool
|
||||
If True, the video will rewind as soon as a frame is requested
|
||||
beyond the last frame. Otherwise, IndexError is raised. Default False.
|
||||
|
||||
Parameters for saving
|
||||
---------------------
|
||||
fps : int
|
||||
The speed to play the animation. Default 12.
|
||||
loop : bool
|
||||
If True, add a tag to the end of the file to play again from
|
||||
the first frame. Most flash players will then play the movie
|
||||
in a loop. Note that the imageio SWF Reader does not check this
|
||||
tag. Default True.
|
||||
html : bool
|
||||
If the output is a file on the file system, write an html file
|
||||
(in HTML5) that shows the animation. Default False.
|
||||
compress : bool
|
||||
Whether to compress the swf file. Default False. You probably don't
|
||||
want to use this. This does not decrease the file size since
|
||||
the images are already compressed. It will result in slower
|
||||
read and write time. The only purpose of this feature is to
|
||||
create compressed SWF files, so that we can test the
|
||||
functionality to read them.
|
||||
"""
|
||||
|
||||
def _can_read(self, request):
|
||||
if request.mode[1] in (self.modes + "?"):
|
||||
tmp = request.firstbytes[0:3].decode("ascii", "ignore")
|
||||
if tmp in ("FWS", "CWS"):
|
||||
return True
|
||||
|
||||
def _can_write(self, request):
|
||||
if request.mode[1] in (self.modes + "?"):
|
||||
if request.extension in self.extensions:
|
||||
return True
|
||||
|
||||
# -- reader
|
||||
|
||||
class Reader(Format.Reader):
|
||||
def _open(self, loop=False):
|
||||
if not _swf:
|
||||
load_lib()
|
||||
|
||||
self._arg_loop = bool(loop)
|
||||
|
||||
self._fp = self.request.get_file()
|
||||
|
||||
# Check file ...
|
||||
tmp = self.request.firstbytes[0:3].decode("ascii", "ignore")
|
||||
if tmp == "FWS":
|
||||
pass # OK
|
||||
elif tmp == "CWS":
|
||||
# Compressed, we need to decompress
|
||||
bb = self._fp.read()
|
||||
bb = bb[:8] + zlib.decompress(bb[8:])
|
||||
# Wrap up in a file object
|
||||
self._fp = BytesIO(bb)
|
||||
else:
|
||||
raise IOError("This does not look like a valid SWF file")
|
||||
|
||||
# Skip first bytes. This also tests support got seeking ...
|
||||
try:
|
||||
self._fp.seek(8)
|
||||
self._streaming_mode = False
|
||||
except Exception:
|
||||
self._streaming_mode = True
|
||||
self._fp_read(8)
|
||||
|
||||
# Skip header
|
||||
# Note that the number of frames is there, which we could
|
||||
# potentially use, but the number of frames does not necessarily
|
||||
# correspond to the number of images.
|
||||
nbits = _swf.bits2int(self._fp_read(1), 5)
|
||||
nbits = 5 + nbits * 4
|
||||
Lrect = nbits / 8.0
|
||||
if Lrect % 1:
|
||||
Lrect += 1
|
||||
Lrect = int(Lrect)
|
||||
self._fp_read(Lrect + 3)
|
||||
|
||||
# Now the rest is basically tags ...
|
||||
self._imlocs = [] # tuple (loc, sze, T, L1)
|
||||
if not self._streaming_mode:
|
||||
# Collect locations of frame, while skipping through the data
|
||||
# This does not read any of the tag *data*.
|
||||
try:
|
||||
while True:
|
||||
isimage, sze, T, L1 = self._read_one_tag()
|
||||
loc = self._fp.tell()
|
||||
if isimage:
|
||||
# Still need to check if the format is right
|
||||
format = ord(self._fp_read(3)[2:])
|
||||
if format == 5: # RGB or RGBA lossless
|
||||
self._imlocs.append((loc, sze, T, L1))
|
||||
self._fp.seek(loc + sze) # Skip over tag
|
||||
except IndexError:
|
||||
pass # done reading
|
||||
|
||||
def _fp_read(self, n):
|
||||
return read_n_bytes(self._fp, n)
|
||||
|
||||
def _close(self):
|
||||
pass
|
||||
|
||||
def _get_length(self):
|
||||
if self._streaming_mode:
|
||||
return np.inf
|
||||
else:
|
||||
return len(self._imlocs)
|
||||
|
||||
def _get_data(self, index):
|
||||
# Check index
|
||||
if index < 0:
|
||||
raise IndexError("Index in swf file must be > 0")
|
||||
if not self._streaming_mode:
|
||||
if self._arg_loop and self._imlocs:
|
||||
index = index % len(self._imlocs)
|
||||
if index >= len(self._imlocs):
|
||||
raise IndexError("Index out of bounds")
|
||||
|
||||
if self._streaming_mode:
|
||||
# Walk over tags until we find an image
|
||||
while True:
|
||||
isimage, sze, T, L1 = self._read_one_tag()
|
||||
bb = self._fp_read(sze) # always read data
|
||||
if isimage:
|
||||
im = _swf.read_pixels(bb, 0, T, L1) # can be None
|
||||
if im is not None:
|
||||
return im, {}
|
||||
|
||||
else:
|
||||
# Go to corresponding location, read data, and convert to image
|
||||
loc, sze, T, L1 = self._imlocs[index]
|
||||
self._fp.seek(loc)
|
||||
bb = self._fp_read(sze)
|
||||
# Read_pixels should return ndarry, since we checked format
|
||||
im = _swf.read_pixels(bb, 0, T, L1)
|
||||
return im, {}
|
||||
|
||||
def _read_one_tag(self):
|
||||
"""
|
||||
Return (True, loc, size, T, L1) if an image that we can read.
|
||||
Return (False, loc, size, T, L1) if any other tag.
|
||||
"""
|
||||
|
||||
# Get head
|
||||
head = self._fp_read(6)
|
||||
if not head: # pragma: no cover
|
||||
raise IndexError("Reached end of swf movie")
|
||||
|
||||
# Determine type and length
|
||||
T, L1, L2 = _swf.get_type_and_len(head)
|
||||
if not L2: # pragma: no cover
|
||||
raise RuntimeError("Invalid tag length, could not proceed")
|
||||
|
||||
# Read data
|
||||
isimage = False
|
||||
sze = L2 - 6
|
||||
# bb = self._fp_read(L2 - 6)
|
||||
|
||||
# Parse tag
|
||||
if T == 0:
|
||||
raise IndexError("Reached end of swf movie")
|
||||
elif T in [20, 36]:
|
||||
isimage = True
|
||||
# im = _swf.read_pixels(bb, 0, T, L1) # can be None
|
||||
elif T in [6, 21, 35, 90]: # pragma: no cover
|
||||
logger.warning("Ignoring JPEG image: cannot read JPEG.")
|
||||
else:
|
||||
pass # Not an image tag
|
||||
|
||||
# Done. Return image. Can be None
|
||||
# return im
|
||||
return isimage, sze, T, L1
|
||||
|
||||
def _get_meta_data(self, index):
|
||||
return {} # This format does not support meta data
|
||||
|
||||
# -- writer
|
||||
|
||||
class Writer(Format.Writer):
|
||||
def _open(self, fps=12, loop=True, html=False, compress=False):
|
||||
if not _swf:
|
||||
load_lib()
|
||||
|
||||
self._arg_fps = int(fps)
|
||||
self._arg_loop = bool(loop)
|
||||
self._arg_html = bool(html)
|
||||
self._arg_compress = bool(compress)
|
||||
|
||||
self._fp = self.request.get_file()
|
||||
self._framecounter = 0
|
||||
self._framesize = (100, 100)
|
||||
|
||||
# For compress, we use an in-memory file object
|
||||
if self._arg_compress:
|
||||
self._fp_real = self._fp
|
||||
self._fp = BytesIO()
|
||||
|
||||
def _close(self):
|
||||
self._complete()
|
||||
# Get size of (uncompressed) file
|
||||
sze = self._fp.tell()
|
||||
# set nframes, this is in the potentially compressed region
|
||||
self._fp.seek(self._location_to_save_nframes)
|
||||
self._fp.write(_swf.int2uint16(self._framecounter))
|
||||
# Compress body?
|
||||
if self._arg_compress:
|
||||
bb = self._fp.getvalue()
|
||||
self._fp = self._fp_real
|
||||
self._fp.write(bb[:8])
|
||||
self._fp.write(zlib.compress(bb[8:]))
|
||||
sze = self._fp.tell() # renew sze value
|
||||
# set size
|
||||
self._fp.seek(4)
|
||||
self._fp.write(_swf.int2uint32(sze))
|
||||
self._fp = None # Disable
|
||||
|
||||
# Write html?
|
||||
if self._arg_html and os.path.isfile(self.request.filename):
|
||||
dirname, fname = os.path.split(self.request.filename)
|
||||
filename = os.path.join(dirname, fname[:-4] + ".html")
|
||||
w, h = self._framesize
|
||||
html = HTML % (fname, w, h, fname)
|
||||
with open(filename, "wb") as f:
|
||||
f.write(html.encode("utf-8"))
|
||||
|
||||
def _write_header(self, framesize, fps):
|
||||
self._framesize = framesize
|
||||
# Called as soon as we know framesize; when we get first frame
|
||||
bb = b""
|
||||
bb += "FC"[self._arg_compress].encode("ascii")
|
||||
bb += "WS".encode("ascii") # signature bytes
|
||||
bb += _swf.int2uint8(8) # version
|
||||
bb += "0000".encode("ascii") # FileLength (leave open for now)
|
||||
bb += (
|
||||
_swf.Tag().make_rect_record(0, framesize[0], 0, framesize[1]).tobytes()
|
||||
)
|
||||
bb += _swf.int2uint8(0) + _swf.int2uint8(fps) # FrameRate
|
||||
self._location_to_save_nframes = len(bb)
|
||||
bb += "00".encode("ascii") # nframes (leave open for now)
|
||||
self._fp.write(bb)
|
||||
|
||||
# Write some initial tags
|
||||
taglist = _swf.FileAttributesTag(), _swf.SetBackgroundTag(0, 0, 0)
|
||||
for tag in taglist:
|
||||
self._fp.write(tag.get_tag())
|
||||
|
||||
def _complete(self):
|
||||
# What if no images were saved?
|
||||
if not self._framecounter:
|
||||
self._write_header((10, 10), self._arg_fps)
|
||||
# Write stop tag if we do not loop
|
||||
if not self._arg_loop:
|
||||
self._fp.write(_swf.DoActionTag("stop").get_tag())
|
||||
# finish with end tag
|
||||
self._fp.write("\x00\x00".encode("ascii"))
|
||||
|
||||
def _append_data(self, im, meta):
|
||||
# Correct shape and type
|
||||
if im.ndim == 3 and im.shape[-1] == 1:
|
||||
im = im[:, :, 0]
|
||||
im = image_as_uint(im, bitdepth=8)
|
||||
# Get frame size
|
||||
wh = im.shape[1], im.shape[0]
|
||||
# Write header on first frame
|
||||
isfirstframe = False
|
||||
if self._framecounter == 0:
|
||||
isfirstframe = True
|
||||
self._write_header(wh, self._arg_fps)
|
||||
# Create tags
|
||||
bm = _swf.BitmapTag(im)
|
||||
sh = _swf.ShapeTag(bm.id, (0, 0), wh)
|
||||
po = _swf.PlaceObjectTag(1, sh.id, move=(not isfirstframe))
|
||||
sf = _swf.ShowFrameTag()
|
||||
# Write tags
|
||||
for tag in [bm, sh, po, sf]:
|
||||
self._fp.write(tag.get_tag())
|
||||
self._framecounter += 1
|
||||
|
||||
def set_meta_data(self, meta):
|
||||
pass
|
||||
|
||||
|
||||
HTML = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Show Flash animation %s</title>
|
||||
</head>
|
||||
<body>
|
||||
<embed width="%i" height="%i" src="%s">
|
||||
</html>
|
||||
"""
|
||||
|
||||
# Register. You register an *instance* of a Format class. Here specify:
|
||||
format = SWFFormat(
|
||||
"swf", # shot name
|
||||
"Shockwave flash", # one line descr.
|
||||
".swf", # list of extensions as a space separated string
|
||||
"I", # modes, characters in iIvV
|
||||
)
|
||||
formats.add_format(format)
|
Loading…
Add table
Add a link
Reference in a new issue