home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pypil112.zip / PIL-1.1.2.zip / Lib / site-packages / PIL / ImageFile.py < prev    next >
Text File  |  2001-05-03  |  11KB  |  379 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # base class for image file handlers
  6. #
  7. # history:
  8. # 1995-09-09 fl   Created
  9. # 1996-03-11 fl   Fixed load mechanism.
  10. # 1996-04-15 fl   Added pcx/xbm decoders.
  11. # 1996-04-30 fl   Added encoders.
  12. # 1996-12-14 fl   Added load helpers
  13. # 1997-01-11 fl   Use encode_to_file where possible
  14. # 1997-08-27 fl   Flush output in _save
  15. # 1998-03-05 fl   Use memory mapping for some modes
  16. # 1999-02-04 fl   Use memory mapping also for "I;16" and "I;16B"
  17. # 1999-05-31 fl   Added image parser
  18. # 2000-10-12 fl   Set readonly flag on memory-mapped images
  19. #
  20. # Copyright (c) 1997-2000 by Secret Labs AB
  21. # Copyright (c) 1995-2000 by Fredrik Lundh
  22. #
  23. # See the README file for information on usage and redistribution.
  24. #
  25.  
  26. import Image
  27. import traceback, sys
  28.  
  29. MAXBLOCK = 65536
  30.  
  31. # raw modes that may be memory mapped.  NOTE: if you change this, you
  32. # may have to modify the stride calculation in map.c too!
  33. MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16B")
  34.  
  35. #
  36. # --------------------------------------------------------------------
  37. # Helpers
  38.  
  39. def _tilesort(t1, t2):
  40.     # sort on offset
  41.     return cmp(t1[2], t2[2])
  42.  
  43. #
  44. # --------------------------------------------------------------------
  45. # ImageFile base class
  46.  
  47. class ImageFile(Image.Image):
  48.     "Base class for image file format handlers."
  49.  
  50.     def __init__(self, fp=None, filename=None):
  51.         Image.Image.__init__(self)
  52.  
  53.         self.tile = None
  54.         self.readonly = 1 # until we know better
  55.  
  56.         self.decoderconfig = ()
  57.         self.decodermaxblock = MAXBLOCK
  58.  
  59.         if type(fp) == type(""):
  60.             # filename
  61.             self.fp = open(fp, "rb")
  62.             self.filename = fp
  63.         else:
  64.             # stream
  65.             self.fp = fp
  66.             self.filename = filename
  67.  
  68.         try:
  69.             self._open()
  70.         except IndexError, v: # end of data
  71.             if Image.DEBUG > 1:
  72.                 traceback.print_exc()
  73.             raise SyntaxError, v
  74.         except TypeError, v: # end of data (ord)
  75.             if Image.DEBUG > 1:
  76.                 traceback.print_exc()
  77.             raise SyntaxError, v
  78.         except KeyError, v: # unsupported mode
  79.             if Image.DEBUG > 1:
  80.                 traceback.print_exc()
  81.             raise SyntaxError, v
  82.  
  83.         if not self.mode or self.size[0] <= 0:
  84.             raise SyntaxError, "not identified by this driver"
  85.  
  86.     def draft(self, mode, size):
  87.         "Set draft mode"
  88.  
  89.         pass
  90.  
  91.     def verify(self):
  92.         "Check file integrity"
  93.  
  94.         # raise exception if something's wrong.  must be called
  95.         # directly after open, and closes file when finished.
  96.         self.fp = None
  97.  
  98.     def load(self):
  99.         "Load image data based on tile list"
  100.  
  101.         Image.Image.load(self)
  102.  
  103.         if self.tile is None:
  104.             raise IOError, "cannot load this image"
  105.         if not self.tile:
  106.             return
  107.  
  108.         self.map = None
  109.  
  110.         readonly = 0
  111.  
  112.         if self.filename and len(self.tile) == 1:
  113.             # try memory mapping
  114.             d, e, o, a = self.tile[0]
  115.             if d == "raw" and a[0] == self.mode and a[0] in MAPMODES:
  116.                 try:
  117.                     self.map = Image.core.map(self.filename)
  118.                     self.map.seek(o)
  119.                     self.im = self.map.readimage(
  120.                         self.mode, self.size, a[1], a[2]
  121.                         )
  122.                     readonly = 1
  123.                 except (AttributeError, IOError):
  124.                     self.map = None
  125.  
  126.         self.load_prepare()
  127.  
  128.         if not self.map:
  129.  
  130.             # sort tiles in file order
  131.             self.tile.sort(_tilesort)
  132.  
  133.             try:
  134.                 # FIXME: This is a hack to handle TIFF's JpegTables tag.
  135.                 prefix = self.tile_prefix
  136.             except AttributeError:
  137.                 prefix = ""
  138.  
  139.             for d, e, o, a in self.tile:
  140.                 d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
  141.                 self.load_seek(o)
  142.                 try:
  143.                     d.setimage(self.im, e)
  144.                 except ValueError:
  145.                     continue
  146.                 b = prefix
  147.                 t = len(b)
  148.                 while 1:
  149.                     s = self.load_read(self.decodermaxblock)
  150.                     if not s:
  151.                         self.tile = []
  152.                         raise IOError, "image file is truncated, %d bytes left in buffer" % len(b)
  153.                     b = b + s
  154.                     n, e = d.decode(b)
  155.                     if n < 0:
  156.                         break
  157.                     b = b[n:]
  158.                     t = t + n
  159.  
  160.         self.tile = []
  161.         self.readonly = readonly
  162.  
  163.         self.fp = None # might be shared
  164.  
  165.         if not self.map and e < 0:
  166.             raise IOError, "decoder error %d when reading image file" % e
  167.  
  168.         # post processing
  169.         if hasattr(self, "tile_post_rotate"):
  170.             # FIXME: This is a hack to handle rotated PCD's
  171.             self.im = self.im.rotate(self.tile_post_rotate)
  172.             self.size = self.im.size
  173.  
  174.         self.load_end()
  175.  
  176.     def load_prepare(self):
  177.         # create image memory if necessary
  178.         if not self.im or\
  179.            self.im.mode != self.mode or self.im.size != self.size:
  180.             self.im = Image.core.new(self.mode, self.size)
  181.         # create palette (optional)
  182.         if self.mode == "P":
  183.             Image.Image.load(self)
  184.  
  185.     def load_end(self):
  186.         # may be overridden
  187.         pass
  188.  
  189.     def load_seek(self, pos):
  190.         # may be overridden for contained formats
  191.         self.fp.seek(pos)
  192.  
  193.     def load_read(self, bytes):
  194.         # may be overridden for blocked formats (e.g. PNG)
  195.         return self.fp.read(bytes)
  196.  
  197.  
  198. class _ParserFile:
  199.     # parser support class.
  200.  
  201.     def __init__(self, data):
  202.         self.data = data
  203.         self.offset = 0
  204.  
  205.     def close(self):
  206.         self.data = self.offset = None
  207.  
  208.     def tell(self):
  209.         return self.offset
  210.  
  211.     def seek(self, offset, whence=0):
  212.         if whence == 0:
  213.             self.offset = offset
  214.         elif whence == 1:
  215.             self.offset = self.offset + offset
  216.         else:
  217.             # force error in Image.open
  218.             raise IOError, "illegal argument to seek"
  219.  
  220.     def read(self, bytes=0):
  221.         pos = self.offset
  222.         if bytes:
  223.             data = self.data[pos:pos+bytes]
  224.         else:
  225.             data = self.data[pos:]
  226.         self.offset = pos + len(data)
  227.         return data
  228.  
  229.     def readline(self):
  230.         # FIXME: this is slow!
  231.         s = ""
  232.         while 1:
  233.             c = self.read(1)
  234.             if not c:
  235.                 break
  236.             s = s + c
  237.             if c == "\n":
  238.                 break
  239.         return s
  240.  
  241. class Parser:
  242.     # incremental image parser.  implements the consumer
  243.     # interface.
  244.  
  245.     image = None
  246.     data = None
  247.     decoder = None
  248.     finished = 0
  249.  
  250.     def reset(self):
  251.         assert self.data is None, "cannot reuse parsers"
  252.  
  253.     def feed(self, data):
  254.         # collect data
  255.  
  256.         if self.finished:
  257.             return
  258.  
  259.         if self.data is None:
  260.             self.data = data
  261.         else:
  262.             self.data = self.data + data
  263.  
  264.         # parse what we have
  265.         if self.decoder:
  266.  
  267.             if self.offset > 0:
  268.                 # skip header
  269.                 skip = min(len(self.data), self.offset)
  270.                 self.data = self.data[skip:]
  271.                 self.offset = self.offset - skip
  272.                 if self.offset > 0 or not self.data:
  273.                     return
  274.  
  275.             n, e = self.decoder.decode(self.data)
  276.  
  277.             if n < 0:
  278.                 # end of stream
  279.                 self.data = None
  280.                 self.finished = 1
  281.                 if e < 0:
  282.                     # decoding error
  283.                     self.image = None
  284.                     raise IOError,\
  285.                           "decoder error %d when reading image file" % e
  286.                 else:
  287.                     # end of image
  288.                     return
  289.             self.data = self.data[n:]
  290.  
  291.         else:
  292.  
  293.             # attempt to open this file
  294.             try:
  295.                 try:
  296.                     fp = _ParserFile(self.data)
  297.                     im = Image.open(fp)
  298.                 finally:
  299.                     fp.close() # explicitly close the virtual file
  300.             except IOError:
  301.                 pass # not enough data
  302.             else:
  303.  
  304.                 # sanity check
  305.                 if len(im.tile) != 1:
  306.                     raise IOError, "cannot parse this image"
  307.  
  308.                 # initialize decoder
  309.                 im.load_prepare()
  310.                 d, e, o, a = im.tile[0]
  311.                 im.tile = []
  312.                 self.decoder = Image._getdecoder(
  313.                     im.mode, d, a, im.decoderconfig
  314.                     )
  315.                 self.decoder.setimage(im.im, e)
  316.  
  317.                 # calculate decoder offset
  318.                 self.offset = o
  319.                 if self.offset <= len(self.data):
  320.                     self.data = self.data[self.offset:]
  321.                     self.offset = 0
  322.  
  323.                 self.image = im
  324.  
  325.     def close(self):
  326.         # finish decoding
  327.         if self.decoder:
  328.             # get rid of what's left in the buffers
  329.             self.feed("")
  330.             self.data = self.decoder = None
  331.             if not self.finished:
  332.                 raise IOError, "image was incomplete"
  333.         if not self.image:
  334.             raise IOError, "cannot parse this image"
  335.         return self.image
  336.  
  337. #
  338. # --------------------------------------------------------------------
  339. # Save image body
  340.  
  341. def _save(im, fp, tile):
  342.     "Helper to save image based on tile list"
  343.  
  344.     im.load()
  345.     if not hasattr(im, "encoderconfig"):
  346.         im.encoderconfig = ()
  347.     tile.sort(_tilesort)
  348.     bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c
  349.     try:
  350.         fh = fp.fileno()
  351.         fp.flush()
  352.     except AttributeError:
  353.         # compress to Python file-compatible object
  354.         for e, b, o, a in tile:
  355.             e = Image._getencoder(im.mode, e, a, im.encoderconfig)
  356.             if o > 0:
  357.                 fp.seek(o, 0)
  358.             e.setimage(im.im, b)
  359.             while 1:
  360.                 l, s, d = e.encode(bufsize)
  361.                 fp.write(d)
  362.                 if s:
  363.                     break
  364.             if s < 0:
  365.                 raise IOError, "encoder error %d when writing image file" % s
  366.     else:
  367.         # slight speedup: compress to real file object
  368.         for e, b, o, a in tile:
  369.             e = Image._getencoder(im.mode, e, a, im.encoderconfig)
  370.             if o > 0:
  371.                 fp.seek(o, 0)
  372.             e.setimage(im.im, b)
  373.             s = e.encode_to_file(fh, bufsize)
  374.             if s < 0:
  375.                 raise IOError, "encoder error %d when writing image file" % s
  376.     try:
  377.         fp.flush()
  378.     except: pass
  379.