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 / PcxImagePlugin.py < prev    next >
Text File  |  2001-05-03  |  4KB  |  159 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # PCX file handling
  6. #
  7. # This format was originally used by ZSoft's popular PaintBrush
  8. # program for the IBM PC.  It is also supported by many MS-DOS and
  9. # Windows applications, including the Windows PaintBrush program in
  10. # Windows 3.
  11. #
  12. # history:
  13. # 95-09-01 fl   Created
  14. # 96-05-20 fl   Fixed RGB support
  15. # 97-01-03 fl   Fixed 2-bit and 4-bit support
  16. # 99-02-03 fl   Fixed 8-bit support (broken in 1.0b1)
  17. # 99-02-07 fl   Added write support
  18. #
  19. # Copyright (c) Secret Labs AB 1997-98.
  20. # Copyright (c) Fredrik Lundh 1995-97.
  21. #
  22. # See the README file for information on usage and redistribution.
  23. #
  24.  
  25. __version__ = "0.4"
  26.  
  27. import Image, ImageFile, ImagePalette
  28.  
  29. def i16(c):
  30.     return ord(c[0]) + (ord(c[1])<<8)
  31.  
  32. def _accept(prefix):
  33.     return ord(prefix[0]) == 10 and ord(prefix[1]) in [0, 2, 3, 5]
  34.  
  35. class PcxImageFile(ImageFile.ImageFile):
  36.  
  37.     format = "PCX"
  38.     format_description = "Paintbrush"
  39.  
  40.     def _open(self):
  41.  
  42.         # header
  43.         s = self.fp.read(128)
  44.         if not _accept(s):
  45.             raise SyntaxError, "not a PCX file"
  46.  
  47.  
  48.         # image
  49.         bbox = i16(s[4:]), i16(s[6:]), i16(s[8:])+1, i16(s[10:])+1
  50.         if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
  51.             raise SyntaxError, "bad PCX image size"
  52.  
  53.         # format
  54.         version = ord(s[1])
  55.         bits = ord(s[3])
  56.         planes = ord(s[65])
  57.         stride = i16(s[66:])
  58.  
  59.         if bits == 1 and planes == 1:
  60.             mode = rawmode = "1"
  61.  
  62.         elif bits == 1 and planes in (2, 4):
  63.             mode = "P"
  64.             rawmode = "P;%dL" % planes
  65.             self.palette = ImagePalette.raw("RGB", s[16:64])
  66.  
  67.         elif version == 5 and bits == 8 and planes == 1:
  68.             mode = rawmode = "L"
  69.             # FIXME: hey, this doesn't work with the incremental loader !!!
  70.             self.fp.seek(-769, 2)
  71.             s = self.fp.read(769)
  72.             if len(s) == 769 and ord(s[0]) == 12:
  73.                 # check if the palette is linear greyscale
  74.                 for i in range(256):
  75.                     if s[i*3+1:i*3+4] != chr(i)*3:
  76.                         mode = rawmode = "P"
  77.                         break
  78.                 if mode == "P":
  79.                     self.palette = ImagePalette.raw("RGB", s[1:])
  80.  
  81.         elif version == 5 and bits == 8 and planes == 3:
  82.             mode = "RGB"
  83.             rawmode = "RGB;L"
  84.  
  85.         else:
  86.             raise IOError, "unknown PCX mode"
  87.  
  88.         self.mode = mode
  89.         self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
  90.  
  91.         self.tile = [("pcx", bbox, 128, rawmode)]
  92.  
  93.  
  94. # --------------------------------------------------------------------
  95. # save PCX files
  96.  
  97. SAVE = {
  98.     # mode: (version, bits, planes, raw mode)
  99.     "1": (2, 1, 1, "1"),
  100.     "L": (5, 8, 1, "L"),
  101.     "P": (5, 8, 1, "P"),
  102.     "RGB": (5, 8, 3, "RGB;L"),
  103. }
  104.  
  105. def o16(i):
  106.     return chr(i&255) + chr(i>>8&255)
  107.  
  108. def _save(im, fp, filename, check=0):
  109.  
  110.     try:
  111.         version, bits, planes, rawmode = SAVE[im.mode]
  112.     except KeyError:
  113.         raise ValueError, "Cannot save %s images as PCX" % im.mode
  114.  
  115.     if check:
  116.         return check
  117.  
  118.     # bytes per plane
  119.     stride = (im.size[0] * bits + 7) / 8
  120.  
  121.     # under windows, we could determine the current screen size with
  122.     # "Image.core.display_mode()[1]", but I think that's overkill...
  123.  
  124.     screen = im.size
  125.  
  126.     dpi = 100, 100
  127.  
  128.     # PCX header
  129.     fp.write(
  130.         chr(10) + chr(version) + chr(1) + chr(bits) + o16(0) +
  131.         o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) +
  132.         o16(dpi[1]) + chr(0)*24 + chr(255)*24 + chr(0) + chr(planes) +
  133.         o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
  134.         chr(0)*54
  135.         )
  136.  
  137.     assert fp.tell() == 128
  138.  
  139.     ImageFile._save(im, fp, [("pcx", (0,0)+im.size, 0,
  140.                               (rawmode, bits*planes))])
  141.  
  142.     if im.mode == "P":
  143.         # colour palette
  144.         fp.write(chr(12))
  145.         fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
  146.     elif im.mode == "L":
  147.         # greyscale palette
  148.         fp.write(chr(12))
  149.         for i in range(256):
  150.             fp.write(chr(i)*3)
  151.  
  152. # --------------------------------------------------------------------
  153. # registry
  154.  
  155. Image.register_open("PCX", PcxImageFile, _accept)
  156. Image.register_save("PCX", _save)
  157.  
  158. Image.register_extension("PCX", ".pcx")
  159.