diff options
Diffstat (limited to 'PIL/ImageFile.py')
-rw-r--r-- | PIL/ImageFile.py | 520 |
1 files changed, 0 insertions, 520 deletions
diff --git a/PIL/ImageFile.py b/PIL/ImageFile.py deleted file mode 100644 index d51aff3..0000000 --- a/PIL/ImageFile.py +++ /dev/null @@ -1,520 +0,0 @@ -# -# The Python Imaging Library. -# $Id: ImageFile.py 2930 2006-12-02 13:50:40Z fredrik $ -# -# base class for image file handlers -# -# history: -# 1995-09-09 fl Created -# 1996-03-11 fl Fixed load mechanism. -# 1996-04-15 fl Added pcx/xbm decoders. -# 1996-04-30 fl Added encoders. -# 1996-12-14 fl Added load helpers -# 1997-01-11 fl Use encode_to_file where possible -# 1997-08-27 fl Flush output in _save -# 1998-03-05 fl Use memory mapping for some modes -# 1999-02-04 fl Use memory mapping also for "I;16" and "I;16B" -# 1999-05-31 fl Added image parser -# 2000-10-12 fl Set readonly flag on memory-mapped images -# 2002-03-20 fl Use better messages for common decoder errors -# 2003-04-21 fl Fall back on mmap/map_buffer if map is not available -# 2003-10-30 fl Added StubImageFile class -# 2004-02-25 fl Made incremental parser more robust -# -# Copyright (c) 1997-2004 by Secret Labs AB -# Copyright (c) 1995-2004 by Fredrik Lundh -# -# See the README file for information on usage and redistribution. -# - -import Image -import traceback, sys, string, os - -MAXBLOCK = 65536 - -SAFEBLOCK = 1024*1024 - -ERRORS = { - -1: "image buffer overrun error", - -2: "decoding error", - -3: "unknown error", - -8: "bad configuration", - -9: "out of memory error" -} - -# -# -------------------------------------------------------------------- -# Helpers - -def _tilesort(t1, t2): - # sort on offset - return cmp(t1[2], t2[2]) - -# -# -------------------------------------------------------------------- -# ImageFile base class - -## -# Base class for image file handlers. - -class ImageFile(Image.Image): - "Base class for image file format handlers." - - def __init__(self, fp=None, filename=None): - Image.Image.__init__(self) - - self.tile = None - self.readonly = 1 # until we know better - - self.decoderconfig = () - self.decodermaxblock = MAXBLOCK - - if Image.isStringType(fp): - # filename - self.fp = open(fp, "rb") - self.filename = fp - else: - # stream - self.fp = fp - self.filename = filename - - try: - self._open() - except IndexError, v: # end of data - if Image.DEBUG > 1: - traceback.print_exc() - raise SyntaxError, v - except TypeError, v: # end of data (ord) - if Image.DEBUG > 1: - traceback.print_exc() - raise SyntaxError, v - except KeyError, v: # unsupported mode - if Image.DEBUG > 1: - traceback.print_exc() - raise SyntaxError, v - except EOFError, v: # got header but not the first frame - if Image.DEBUG > 1: - traceback.print_exc() - raise SyntaxError, v - - if not self.mode or self.size[0] <= 0: - raise SyntaxError, "not identified by this driver" - - def draft(self, mode, size): - "Set draft mode" - - pass - - def verify(self): - "Check file integrity" - - # raise exception if something's wrong. must be called - # directly after open, and closes file when finished. - self.fp = None - - def load(self): - "Load image data based on tile list" - - pixel = Image.Image.load(self) - - if self.tile is None: - raise IOError("cannot load this image") - if not self.tile: - return pixel - - self.map = None - - readonly = 0 - - if self.filename and len(self.tile) == 1: - # try memory mapping - d, e, o, a = self.tile[0] - if d == "raw" and a[0] == self.mode and a[0] in Image._MAPMODES: - try: - if hasattr(Image.core, "map"): - # use built-in mapper - self.map = Image.core.map(self.filename) - self.map.seek(o) - self.im = self.map.readimage( - self.mode, self.size, a[1], a[2] - ) - else: - # use mmap, if possible - import mmap - file = open(self.filename, "r+") - size = os.path.getsize(self.filename) - # FIXME: on Unix, use PROT_READ etc - self.map = mmap.mmap(file.fileno(), size) - self.im = Image.core.map_buffer( - self.map, self.size, d, e, o, a - ) - readonly = 1 - except (AttributeError, EnvironmentError, ImportError): - self.map = None - - self.load_prepare() - - # look for read/seek overrides - try: - read = self.load_read - except AttributeError: - read = self.fp.read - - try: - seek = self.load_seek - except AttributeError: - seek = self.fp.seek - - if not self.map: - - # sort tiles in file order - self.tile.sort(_tilesort) - - try: - # FIXME: This is a hack to handle TIFF's JpegTables tag. - prefix = self.tile_prefix - except AttributeError: - prefix = "" - - for d, e, o, a in self.tile: - d = Image._getdecoder(self.mode, d, a, self.decoderconfig) - seek(o) - try: - d.setimage(self.im, e) - except ValueError: - continue - b = prefix - t = len(b) - while 1: - s = read(self.decodermaxblock) - if not s: - self.tile = [] - raise IOError("image file is truncated (%d bytes not processed)" % len(b)) - b = b + s - n, e = d.decode(b) - if n < 0: - break - b = b[n:] - t = t + n - - self.tile = [] - self.readonly = readonly - - self.fp = None # might be shared - - if not self.map and e < 0: - error = ERRORS.get(e, "decoder error %d" % e) - raise IOError(error + " when reading image file") - - # post processing - if hasattr(self, "tile_post_rotate"): - # FIXME: This is a hack to handle rotated PCD's - self.im = self.im.rotate(self.tile_post_rotate) - self.size = self.im.size - - self.load_end() - - return Image.Image.load(self) - - def load_prepare(self): - # create image memory if necessary - if not self.im or\ - self.im.mode != self.mode or self.im.size != self.size: - self.im = Image.core.new(self.mode, self.size) - # create palette (optional) - if self.mode == "P": - Image.Image.load(self) - - def load_end(self): - # may be overridden - pass - - # may be defined for contained formats - # def load_seek(self, pos): - # pass - - # may be defined for blocked formats (e.g. PNG) - # def load_read(self, bytes): - # pass - -## -# Base class for stub image loaders. -# <p> -# A stub loader is an image loader that can identify files of a -# certain format, but relies on external code to load the file. - -class StubImageFile(ImageFile): - "Base class for stub image loaders." - - def _open(self): - raise NotImplementedError( - "StubImageFile subclass must implement _open" - ) - - def load(self): - loader = self._load() - if loader is None: - raise IOError("cannot find loader for this %s file" % self.format) - image = loader.load(self) - assert image is not None - # become the other object (!) - self.__class__ = image.__class__ - self.__dict__ = image.__dict__ - - ## - # (Hook) Find actual image loader. - - def _load(self): - raise NotImplementedError( - "StubImageFile subclass must implement _load" - ) - -## -# (Internal) Support class for the <b>Parser</b> file. - -class _ParserFile: - # parser support class. - - def __init__(self, data): - self.data = data - self.offset = 0 - - def close(self): - self.data = self.offset = None - - def tell(self): - return self.offset - - def seek(self, offset, whence=0): - if whence == 0: - self.offset = offset - elif whence == 1: - self.offset = self.offset + offset - else: - # force error in Image.open - raise IOError("illegal argument to seek") - - def read(self, bytes=0): - pos = self.offset - if bytes: - data = self.data[pos:pos+bytes] - else: - data = self.data[pos:] - self.offset = pos + len(data) - return data - - def readline(self): - # FIXME: this is slow! - s = "" - while 1: - c = self.read(1) - if not c: - break - s = s + c - if c == "\n": - break - return s - -## -# Incremental image parser. This class implements the standard -# feed/close consumer interface. - -class Parser: - - incremental = None - image = None - data = None - decoder = None - finished = 0 - - ## - # (Consumer) Reset the parser. Note that you can only call this - # method immediately after you've created a parser; parser - # instances cannot be reused. - - def reset(self): - assert self.data is None, "cannot reuse parsers" - - ## - # (Consumer) Feed data to the parser. - # - # @param data A string buffer. - # @exception IOError If the parser failed to parse the image file. - - def feed(self, data): - # collect data - - if self.finished: - return - - if self.data is None: - self.data = data - else: - self.data = self.data + data - - # parse what we have - if self.decoder: - - if self.offset > 0: - # skip header - skip = min(len(self.data), self.offset) - self.data = self.data[skip:] - self.offset = self.offset - skip - if self.offset > 0 or not self.data: - return - - n, e = self.decoder.decode(self.data) - - if n < 0: - # end of stream - self.data = None - self.finished = 1 - if e < 0: - # decoding error - self.image = None - error = ERRORS.get(e, "decoder error %d" % e) - raise IOError(error + " when reading image file") - else: - # end of image - return - self.data = self.data[n:] - - elif self.image: - - # if we end up here with no decoder, this file cannot - # be incrementally parsed. wait until we've gotten all - # available data - pass - - else: - - # attempt to open this file - try: - try: - fp = _ParserFile(self.data) - im = Image.open(fp) - finally: - fp.close() # explicitly close the virtual file - except IOError: - pass # not enough data - else: - flag = hasattr(im, "load_seek") or hasattr(im, "load_read") - if flag or len(im.tile) != 1: - # custom load code, or multiple tiles - self.decode = None - else: - # initialize decoder - im.load_prepare() - d, e, o, a = im.tile[0] - im.tile = [] - self.decoder = Image._getdecoder( - im.mode, d, a, im.decoderconfig - ) - self.decoder.setimage(im.im, e) - - # calculate decoder offset - self.offset = o - if self.offset <= len(self.data): - self.data = self.data[self.offset:] - self.offset = 0 - - self.image = im - - ## - # (Consumer) Close the stream. - # - # @return An image object. - # @exception IOError If the parser failed to parse the image file. - - def close(self): - # finish decoding - if self.decoder: - # get rid of what's left in the buffers - self.feed("") - self.data = self.decoder = None - if not self.finished: - raise IOError("image was incomplete") - if not self.image: - raise IOError("cannot parse this image") - if self.data: - # incremental parsing not possible; reopen the file - # not that we have all data - try: - fp = _ParserFile(self.data) - self.image = Image.open(fp) - finally: - fp.close() # explicitly close the virtual file - return self.image - -# -------------------------------------------------------------------- - -## -# (Helper) Save image body to file. -# -# @param im Image object. -# @param fp File object. -# @param tile Tile list. - -def _save(im, fp, tile): - "Helper to save image based on tile list" - - im.load() - if not hasattr(im, "encoderconfig"): - im.encoderconfig = () - tile.sort(_tilesort) - # FIXME: make MAXBLOCK a configuration parameter - bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c - try: - fh = fp.fileno() - fp.flush() - except AttributeError: - # compress to Python file-compatible object - for e, b, o, a in tile: - e = Image._getencoder(im.mode, e, a, im.encoderconfig) - if o > 0: - fp.seek(o, 0) - e.setimage(im.im, b) - while 1: - l, s, d = e.encode(bufsize) - fp.write(d) - if s: - break - if s < 0: - raise IOError("encoder error %d when writing image file" % s) - else: - # slight speedup: compress to real file object - for e, b, o, a in tile: - e = Image._getencoder(im.mode, e, a, im.encoderconfig) - if o > 0: - fp.seek(o, 0) - e.setimage(im.im, b) - s = e.encode_to_file(fh, bufsize) - if s < 0: - raise IOError("encoder error %d when writing image file" % s) - try: - fp.flush() - except: pass - - -## -# Reads large blocks in a safe way. Unlike fp.read(n), this function -# doesn't trust the user. If the requested size is larger than -# SAFEBLOCK, the file is read block by block. -# -# @param fp File handle. Must implement a <b>read</b> method. -# @param size Number of bytes to read. -# @return A string containing up to <i>size</i> bytes of data. - -def _safe_read(fp, size): - if size <= 0: - return "" - if size <= SAFEBLOCK: - return fp.read(size) - data = [] - while size > 0: - block = fp.read(min(size, SAFEBLOCK)) - if not block: - break - data.append(block) - size = size - len(block) - return string.join(data, "") |