mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Merge pull request #736 from hugovk/arg
Remove obsolete Animated Raster Graphics (ARG) support
This commit is contained in:
commit
c28dfce2f9
|
@ -1,506 +0,0 @@
|
||||||
#
|
|
||||||
# THIS IS WORK IN PROGRESS
|
|
||||||
#
|
|
||||||
# The Python Imaging Library.
|
|
||||||
# $Id$
|
|
||||||
#
|
|
||||||
# ARG animation support code
|
|
||||||
#
|
|
||||||
# history:
|
|
||||||
# 1996-12-30 fl Created
|
|
||||||
# 1996-01-06 fl Added safe scripting environment
|
|
||||||
# 1996-01-10 fl Added JHDR, UHDR and sYNC support
|
|
||||||
# 2005-03-02 fl Removed AAPP and ARUN support
|
|
||||||
#
|
|
||||||
# Copyright (c) Secret Labs AB 1997.
|
|
||||||
# Copyright (c) Fredrik Lundh 1996-97.
|
|
||||||
#
|
|
||||||
# See the README file for information on usage and redistribution.
|
|
||||||
#
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
__version__ = "0.4"
|
|
||||||
|
|
||||||
from PIL import Image, ImageFile, ImagePalette
|
|
||||||
|
|
||||||
from PIL.PngImagePlugin import i8, i16, i32, ChunkStream, _MODES
|
|
||||||
|
|
||||||
MAGIC = b"\212ARG\r\n\032\n"
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# ARG parser
|
|
||||||
|
|
||||||
class ArgStream(ChunkStream):
|
|
||||||
"Parser callbacks for ARG data"
|
|
||||||
|
|
||||||
def __init__(self, fp):
|
|
||||||
|
|
||||||
ChunkStream.__init__(self, fp)
|
|
||||||
|
|
||||||
self.eof = 0
|
|
||||||
|
|
||||||
self.im = None
|
|
||||||
self.palette = None
|
|
||||||
|
|
||||||
self.__reset()
|
|
||||||
|
|
||||||
def __reset(self):
|
|
||||||
|
|
||||||
# reset decoder state (called on init and sync)
|
|
||||||
|
|
||||||
self.count = 0
|
|
||||||
self.id = None
|
|
||||||
self.action = ("NONE",)
|
|
||||||
|
|
||||||
self.images = {}
|
|
||||||
self.names = {}
|
|
||||||
|
|
||||||
|
|
||||||
def chunk_AHDR(self, offset, bytes):
|
|
||||||
"AHDR -- animation header"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count != 0:
|
|
||||||
raise SyntaxError("misplaced AHDR chunk")
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
self.size = i32(s), i32(s[4:])
|
|
||||||
try:
|
|
||||||
self.mode, self.rawmode = _MODES[(i8(s[8]), i8(s[9]))]
|
|
||||||
except:
|
|
||||||
raise SyntaxError("unknown ARG mode")
|
|
||||||
|
|
||||||
if Image.DEBUG:
|
|
||||||
print("AHDR size", self.size)
|
|
||||||
print("AHDR mode", self.mode, self.rawmode)
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_AFRM(self, offset, bytes):
|
|
||||||
"AFRM -- next frame follows"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count != 0:
|
|
||||||
raise SyntaxError("misplaced AFRM chunk")
|
|
||||||
|
|
||||||
self.show = 1
|
|
||||||
self.id = 0
|
|
||||||
self.count = 1
|
|
||||||
self.repair = None
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
if len(s) >= 2:
|
|
||||||
self.id = i16(s)
|
|
||||||
if len(s) >= 4:
|
|
||||||
self.count = i16(s[2:4])
|
|
||||||
if len(s) >= 6:
|
|
||||||
self.repair = i16(s[4:6])
|
|
||||||
else:
|
|
||||||
self.repair = None
|
|
||||||
|
|
||||||
if Image.DEBUG:
|
|
||||||
print("AFRM", self.id, self.count)
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_ADEF(self, offset, bytes):
|
|
||||||
"ADEF -- store image"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count != 0:
|
|
||||||
raise SyntaxError("misplaced ADEF chunk")
|
|
||||||
|
|
||||||
self.show = 0
|
|
||||||
self.id = 0
|
|
||||||
self.count = 1
|
|
||||||
self.repair = None
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
if len(s) >= 2:
|
|
||||||
self.id = i16(s)
|
|
||||||
if len(s) >= 4:
|
|
||||||
self.count = i16(s[2:4])
|
|
||||||
|
|
||||||
if Image.DEBUG:
|
|
||||||
print("ADEF", self.id, self.count)
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_NAME(self, offset, bytes):
|
|
||||||
"NAME -- name the current image"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced NAME chunk")
|
|
||||||
|
|
||||||
name = self.fp.read(bytes)
|
|
||||||
self.names[self.id] = name
|
|
||||||
|
|
||||||
return name
|
|
||||||
|
|
||||||
def chunk_AEND(self, offset, bytes):
|
|
||||||
"AEND -- end of animation"
|
|
||||||
|
|
||||||
if Image.DEBUG:
|
|
||||||
print("AEND")
|
|
||||||
|
|
||||||
self.eof = 1
|
|
||||||
|
|
||||||
raise EOFError("end of ARG file")
|
|
||||||
|
|
||||||
def __getmodesize(self, s, full=1):
|
|
||||||
|
|
||||||
size = i32(s), i32(s[4:])
|
|
||||||
|
|
||||||
try:
|
|
||||||
mode, rawmode = _MODES[(i8(s[8]), i8(s[9]))]
|
|
||||||
except:
|
|
||||||
raise SyntaxError("unknown image mode")
|
|
||||||
|
|
||||||
if full:
|
|
||||||
if i8(s[12]):
|
|
||||||
pass # interlace not yet supported
|
|
||||||
if i8(s[11]):
|
|
||||||
raise SyntaxError("unknown filter category")
|
|
||||||
|
|
||||||
return size, mode, rawmode
|
|
||||||
|
|
||||||
def chunk_PAST(self, offset, bytes):
|
|
||||||
"PAST -- paste one image into another"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced PAST chunk")
|
|
||||||
|
|
||||||
if self.repair is not None:
|
|
||||||
# we must repair the target image before we
|
|
||||||
# start pasting
|
|
||||||
|
|
||||||
# brute force; a better solution would be to
|
|
||||||
# update only the dirty rectangles in images[id].
|
|
||||||
# note that if images[id] doesn't exist, it must
|
|
||||||
# be created
|
|
||||||
|
|
||||||
self.images[self.id] = self.images[self.repair].copy()
|
|
||||||
self.repair = None
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
im = self.images[i16(s)]
|
|
||||||
x, y = i32(s[2:6]), i32(s[6:10])
|
|
||||||
bbox = x, y, im.size[0]+x, im.size[1]+y
|
|
||||||
|
|
||||||
if im.mode in ["RGBA"]:
|
|
||||||
# paste with transparency
|
|
||||||
# FIXME: should handle P+transparency as well
|
|
||||||
self.images[self.id].paste(im, bbox, im)
|
|
||||||
else:
|
|
||||||
# paste without transparency
|
|
||||||
self.images[self.id].paste(im, bbox)
|
|
||||||
|
|
||||||
self.action = ("PAST",)
|
|
||||||
self.__store()
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_BLNK(self, offset, bytes):
|
|
||||||
"BLNK -- create blank image"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced BLNK chunk")
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
size, mode, rawmode = self.__getmodesize(s, 0)
|
|
||||||
|
|
||||||
# store image (FIXME: handle colour)
|
|
||||||
self.action = ("BLNK",)
|
|
||||||
self.im = Image.core.fill(mode, size, 0)
|
|
||||||
self.__store()
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_IHDR(self, offset, bytes):
|
|
||||||
"IHDR -- full image follows"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced IHDR chunk")
|
|
||||||
|
|
||||||
# image header
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
size, mode, rawmode = self.__getmodesize(s)
|
|
||||||
|
|
||||||
# decode and store image
|
|
||||||
self.action = ("IHDR",)
|
|
||||||
self.im = Image.core.new(mode, size)
|
|
||||||
self.decoder = Image.core.zip_decoder(rawmode)
|
|
||||||
self.decoder.setimage(self.im, (0,0) + size)
|
|
||||||
self.data = b""
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_DHDR(self, offset, bytes):
|
|
||||||
"DHDR -- delta image follows"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced DHDR chunk")
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
|
|
||||||
size, mode, rawmode = self.__getmodesize(s)
|
|
||||||
|
|
||||||
# delta header
|
|
||||||
diff = i8(s[13])
|
|
||||||
offs = i32(s[14:18]), i32(s[18:22])
|
|
||||||
|
|
||||||
bbox = offs + (offs[0]+size[0], offs[1]+size[1])
|
|
||||||
|
|
||||||
if Image.DEBUG:
|
|
||||||
print("DHDR", diff, bbox)
|
|
||||||
|
|
||||||
# FIXME: decode and apply image
|
|
||||||
self.action = ("DHDR", diff, bbox)
|
|
||||||
|
|
||||||
# setup decoder
|
|
||||||
self.im = Image.core.new(mode, size)
|
|
||||||
|
|
||||||
self.decoder = Image.core.zip_decoder(rawmode)
|
|
||||||
self.decoder.setimage(self.im, (0,0) + size)
|
|
||||||
|
|
||||||
self.data = b""
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_JHDR(self, offset, bytes):
|
|
||||||
"JHDR -- JPEG image follows"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced JHDR chunk")
|
|
||||||
|
|
||||||
# image header
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
size, mode, rawmode = self.__getmodesize(s, 0)
|
|
||||||
|
|
||||||
# decode and store image
|
|
||||||
self.action = ("JHDR",)
|
|
||||||
self.im = Image.core.new(mode, size)
|
|
||||||
self.decoder = Image.core.jpeg_decoder(rawmode)
|
|
||||||
self.decoder.setimage(self.im, (0,0) + size)
|
|
||||||
self.data = b""
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_UHDR(self, offset, bytes):
|
|
||||||
"UHDR -- uncompressed image data follows (EXPERIMENTAL)"
|
|
||||||
|
|
||||||
# assertions
|
|
||||||
if self.count == 0:
|
|
||||||
raise SyntaxError("misplaced UHDR chunk")
|
|
||||||
|
|
||||||
# image header
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
size, mode, rawmode = self.__getmodesize(s, 0)
|
|
||||||
|
|
||||||
# decode and store image
|
|
||||||
self.action = ("UHDR",)
|
|
||||||
self.im = Image.core.new(mode, size)
|
|
||||||
self.decoder = Image.core.raw_decoder(rawmode)
|
|
||||||
self.decoder.setimage(self.im, (0,0) + size)
|
|
||||||
self.data = b""
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_IDAT(self, offset, bytes):
|
|
||||||
"IDAT -- image data block"
|
|
||||||
|
|
||||||
# pass compressed chunks through the decoder
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
self.data = self.data + s
|
|
||||||
n, e = self.decoder.decode(self.data)
|
|
||||||
if n < 0:
|
|
||||||
# end of image
|
|
||||||
if e < 0:
|
|
||||||
raise IOError("decoder error %d" % e)
|
|
||||||
else:
|
|
||||||
self.data = self.data[n:]
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_DEND(self, offset, bytes):
|
|
||||||
return self.chunk_IEND(offset, bytes)
|
|
||||||
|
|
||||||
def chunk_JEND(self, offset, bytes):
|
|
||||||
return self.chunk_IEND(offset, bytes)
|
|
||||||
|
|
||||||
def chunk_UEND(self, offset, bytes):
|
|
||||||
return self.chunk_IEND(offset, bytes)
|
|
||||||
|
|
||||||
def chunk_IEND(self, offset, bytes):
|
|
||||||
"IEND -- end of image"
|
|
||||||
|
|
||||||
# we now have a new image. carry out the operation
|
|
||||||
# defined by the image header.
|
|
||||||
|
|
||||||
# won't need these anymore
|
|
||||||
del self.decoder
|
|
||||||
del self.data
|
|
||||||
|
|
||||||
self.__store()
|
|
||||||
|
|
||||||
return self.fp.read(bytes)
|
|
||||||
|
|
||||||
def __store(self):
|
|
||||||
|
|
||||||
# apply operation
|
|
||||||
cid = self.action[0]
|
|
||||||
|
|
||||||
if cid in ["BLNK", "IHDR", "JHDR", "UHDR"]:
|
|
||||||
# store
|
|
||||||
self.images[self.id] = self.im
|
|
||||||
|
|
||||||
elif cid == "DHDR":
|
|
||||||
# paste
|
|
||||||
cid, mode, bbox = self.action
|
|
||||||
im0 = self.images[self.id]
|
|
||||||
im1 = self.im
|
|
||||||
if mode == 0:
|
|
||||||
im1 = im1.chop_add_modulo(im0.crop(bbox))
|
|
||||||
im0.paste(im1, bbox)
|
|
||||||
|
|
||||||
self.count -= 1
|
|
||||||
|
|
||||||
if self.count == 0 and self.show:
|
|
||||||
self.im = self.images[self.id]
|
|
||||||
raise EOFError # end of this frame
|
|
||||||
|
|
||||||
def chunk_PLTE(self, offset, bytes):
|
|
||||||
"PLTE -- palette data"
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
if self.mode == "P":
|
|
||||||
self.palette = ImagePalette.raw("RGB", s)
|
|
||||||
return s
|
|
||||||
|
|
||||||
def chunk_sYNC(self, offset, bytes):
|
|
||||||
"SYNC -- reset decoder"
|
|
||||||
|
|
||||||
if self.count != 0:
|
|
||||||
raise SyntaxError("misplaced sYNC chunk")
|
|
||||||
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
self.__reset()
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# ARG reader
|
|
||||||
|
|
||||||
def _accept(prefix):
|
|
||||||
return prefix[:8] == MAGIC
|
|
||||||
|
|
||||||
##
|
|
||||||
# Image plugin for the experimental Animated Raster Graphics format.
|
|
||||||
|
|
||||||
class ArgImageFile(ImageFile.ImageFile):
|
|
||||||
|
|
||||||
format = "ARG"
|
|
||||||
format_description = "Animated raster graphics"
|
|
||||||
|
|
||||||
def _open(self):
|
|
||||||
|
|
||||||
if Image.warnings:
|
|
||||||
Image.warnings.warn(
|
|
||||||
"The ArgImagePlugin driver is obsolete, and will be removed "
|
|
||||||
"from a future release of PIL. If you rely on this module, "
|
|
||||||
"please contact the PIL authors.",
|
|
||||||
RuntimeWarning
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.fp.read(8) != MAGIC:
|
|
||||||
raise SyntaxError("not an ARG file")
|
|
||||||
|
|
||||||
self.arg = ArgStream(self.fp)
|
|
||||||
|
|
||||||
# read and process the first chunk (AHDR)
|
|
||||||
|
|
||||||
cid, offset, bytes = self.arg.read()
|
|
||||||
|
|
||||||
if cid != "AHDR":
|
|
||||||
raise SyntaxError("expected an AHDR chunk")
|
|
||||||
|
|
||||||
s = self.arg.call(cid, offset, bytes)
|
|
||||||
|
|
||||||
self.arg.crc(cid, s)
|
|
||||||
|
|
||||||
# image characteristics
|
|
||||||
self.mode = self.arg.mode
|
|
||||||
self.size = self.arg.size
|
|
||||||
|
|
||||||
def load(self):
|
|
||||||
|
|
||||||
if self.arg.im is None:
|
|
||||||
self.seek(0)
|
|
||||||
|
|
||||||
# image data
|
|
||||||
self.im = self.arg.im
|
|
||||||
self.palette = self.arg.palette
|
|
||||||
|
|
||||||
# set things up for further processing
|
|
||||||
Image.Image.load(self)
|
|
||||||
|
|
||||||
def seek(self, frame):
|
|
||||||
|
|
||||||
if self.arg.eof:
|
|
||||||
raise EOFError("end of animation")
|
|
||||||
|
|
||||||
self.fp = self.arg.fp
|
|
||||||
|
|
||||||
while True:
|
|
||||||
|
|
||||||
#
|
|
||||||
# process chunks
|
|
||||||
|
|
||||||
cid, offset, bytes = self.arg.read()
|
|
||||||
|
|
||||||
if self.arg.eof:
|
|
||||||
raise EOFError("end of animation")
|
|
||||||
|
|
||||||
try:
|
|
||||||
s = self.arg.call(cid, offset, bytes)
|
|
||||||
except EOFError:
|
|
||||||
break
|
|
||||||
|
|
||||||
except "glurk": # AttributeError
|
|
||||||
if Image.DEBUG:
|
|
||||||
print(cid, bytes, "(unknown)")
|
|
||||||
s = self.fp.read(bytes)
|
|
||||||
|
|
||||||
self.arg.crc(cid, s)
|
|
||||||
|
|
||||||
self.fp.read(4) # ship extra CRC
|
|
||||||
|
|
||||||
def tell(self):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def verify(self):
|
|
||||||
"Verify ARG file"
|
|
||||||
|
|
||||||
# back up to first chunk
|
|
||||||
self.fp.seek(8)
|
|
||||||
|
|
||||||
self.arg.verify(self)
|
|
||||||
self.arg.close()
|
|
||||||
|
|
||||||
self.fp = None
|
|
||||||
|
|
||||||
#
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
|
|
||||||
Image.register_open("ARG", ArgImageFile, _accept)
|
|
||||||
|
|
||||||
Image.register_extension("ARG", ".arg")
|
|
||||||
|
|
||||||
Image.register_mime("ARG", "video/x-arg")
|
|
|
@ -14,8 +14,7 @@
|
||||||
VERSION = '1.1.7' # PIL version
|
VERSION = '1.1.7' # PIL version
|
||||||
PILLOW_VERSION = '2.4.0' # Pillow
|
PILLOW_VERSION = '2.4.0' # Pillow
|
||||||
|
|
||||||
_plugins = ['ArgImagePlugin',
|
_plugins = ['BmpImagePlugin',
|
||||||
'BmpImagePlugin',
|
|
||||||
'BufrStubImagePlugin',
|
'BufrStubImagePlugin',
|
||||||
'CurImagePlugin',
|
'CurImagePlugin',
|
||||||
'DcxImagePlugin',
|
'DcxImagePlugin',
|
||||||
|
|
|
@ -18,25 +18,6 @@ import sys
|
||||||
Image.DEBUG = 0
|
Image.DEBUG = 0
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# experimental: support ARG animation scripts
|
|
||||||
|
|
||||||
import ArgImagePlugin
|
|
||||||
|
|
||||||
def applet_hook(animation, images):
|
|
||||||
app = animation(animation_display, images)
|
|
||||||
app.run()
|
|
||||||
|
|
||||||
ArgImagePlugin.APPLET_HOOK = applet_hook
|
|
||||||
|
|
||||||
class AppletDisplay:
|
|
||||||
def __init__(self, ui):
|
|
||||||
self.__ui = ui
|
|
||||||
def paste(self, im, bbox):
|
|
||||||
self.__ui.image.paste(im, bbox)
|
|
||||||
def update(self):
|
|
||||||
self.__ui.update_idletasks()
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# an image animation player
|
# an image animation player
|
||||||
|
|
||||||
|
@ -56,10 +37,6 @@ class UI(Label):
|
||||||
else:
|
else:
|
||||||
self.image = ImageTk.PhotoImage(im)
|
self.image = ImageTk.PhotoImage(im)
|
||||||
|
|
||||||
# APPLET SUPPORT (very crude, and not 100% safe)
|
|
||||||
global animation_display
|
|
||||||
animation_display = AppletDisplay(self)
|
|
||||||
|
|
||||||
Label.__init__(self, master, image=self.image, bg="black", bd=0)
|
Label.__init__(self, master, image=self.image, bg="black", bd=0)
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
Plugin reference
|
Plugin reference
|
||||||
================
|
================
|
||||||
|
|
||||||
:mod:`ArgImagePlugin` Module
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
.. automodule:: PIL.ArgImagePlugin
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
:mod:`BmpImagePlugin` Module
|
:mod:`BmpImagePlugin` Module
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user