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 / ImImagePlugin.py < prev    next >
Text File  |  2001-05-03  |  9KB  |  320 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # IFUNC IM file handling for PIL
  6. #
  7. # history:
  8. # 1995-09-01 fl Created.
  9. # 1997-01-03 fl Save palette images
  10. # 1997-01-08 fl Added sequence support
  11. # 1997-01-23 fl Added P and RGB save support
  12. # 1997-05-31 fl Read floating point images
  13. # 1997-06-22 fl Save floating point images
  14. # 1997-08-27 fl Read and save 1-bit images
  15. # 1998-06-25 fl Added support for RGB+LUT images
  16. # 1998-07-02 fl Added support for YCC images
  17. # 1998-07-15 fl Renamed offset attribute to avoid name clash
  18. # 1998-12-29 fl Added I;16 support
  19. # 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.7)
  20. #
  21. # Copyright (c) Secret Labs AB 1997-2001.
  22. # Copyright (c) Fredrik Lundh 1995-2001.
  23. #
  24. # See the README file for information on usage and redistribution.
  25. #
  26.  
  27.  
  28. __version__ = "0.7"
  29.  
  30. import re, string
  31. import Image, ImageFile, ImagePalette
  32.  
  33.  
  34. # --------------------------------------------------------------------
  35. # Standard tags
  36.  
  37. COMMENT = "Comment"
  38. DATE = "Date"
  39. EQUIPMENT = "Digitalization equipment"
  40. FRAMES = "File size (no of images)"
  41. LUT = "Lut"
  42. NAME = "Name"
  43. SCALE = "Scale (x,y)"
  44. SIZE = "Image size (x*y)"
  45. MODE = "Image type"
  46.  
  47. TAGS = { COMMENT:0, DATE:0, EQUIPMENT:0, FRAMES:0, LUT:0, NAME:0,
  48.          SCALE:0, SIZE:0, MODE:0 }
  49.  
  50. OPEN = {
  51.     # ifunc93/p3cfunc formats
  52.     "0 1 image": ("1", "1"),
  53.     "L 1 image": ("1", "1"),
  54.     "Greyscale image": ("L", "L"),
  55.     "Grayscale image": ("L", "L"),
  56.     "RGB image": ("RGB", "RGB;L"),
  57.     "RLB image": ("RGB", "RLB"),
  58.     "RYB image": ("RGB", "RLB"),
  59.     "B1 image": ("1", "1"),
  60.     "B2 image": ("P", "P;2"),
  61.     "B4 image": ("P", "P;4"),
  62.     "X 24 image": ("RGB", "RGB"),
  63.     "L 32 S image": ("I", "I;32"),
  64.     "L 32 F image": ("F", "F;32"),
  65.     # old p3cfunc formats
  66.     "RGB3 image": ("RGB", "RGB;T"),
  67.     "RYB3 image": ("RGB", "RYB;T"),
  68.     # extensions
  69.     "RGBA image": ("RGBA", "RGBA;L"),
  70.     "RGBX image": ("RGBX", "RGBX;L"),
  71.     "CMYK image": ("CMYK", "CMYK;L"),
  72.     "YCC image": ("YCbCr", "YCbCr;L"),
  73. }
  74.  
  75. # ifunc95 extensions
  76. for i in ["8", "8S", "16", "16S", "32", "32F"]:
  77.     OPEN["L %s image" % i] = ("F", "F;%s" % i)
  78.     OPEN["L*%s image" % i] = ("F", "F;%s" % i)
  79. for i in ["16", "16B"]:
  80.     OPEN["L %s image" % i] = ("I;%s" % i, "I;%s" % i)
  81.     OPEN["L*%s image" % i] = ("I;%s" % i, "I;%s" % i)
  82. for i in ["32S"]:
  83.     OPEN["L %s image" % i] = ("I", "I;%s" % i)
  84.     OPEN["L*%s image" % i] = ("I", "I;%s" % i)
  85. for i in range(2, 33):
  86.     OPEN["L*%s image" % i] = ("F", "F;%s" % i)
  87.  
  88.  
  89. # --------------------------------------------------------------------
  90. # Read IM directory
  91.  
  92. split = re.compile(r"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$")
  93.  
  94. class ImImageFile(ImageFile.ImageFile):
  95.  
  96.     format = "IM"
  97.     format_description = "IFUNC Image Memory"
  98.  
  99.     def _open(self):
  100.  
  101.         # Quick rejection: if there's not an LF among the first
  102.         # 100 bytes, this is (probably) not a text header.
  103.  
  104.         if not "\n" in self.fp.read(100):
  105.             raise SyntaxError, "not an IM file"
  106.         self.fp.seek(0)
  107.  
  108.         n = 0
  109.  
  110.         # Default values
  111.         self.info[MODE] = "L"
  112.         self.info[SIZE] = (512, 512)
  113.         self.info[FRAMES] = 1
  114.  
  115.         self.rawmode = "L"
  116.  
  117.         while 1:
  118.  
  119.             s = self.fp.read(1)
  120.  
  121.             # Some versions of IFUNC uses \n\r instead of \r\n...
  122.             if s == "\r":
  123.                 continue
  124.  
  125.             if not s or s[0] == chr(0) or s[0] == chr(26):
  126.                 break
  127.  
  128.             # FIXME: this may read whole file if not a text file
  129.             s = s + self.fp.readline()
  130.  
  131.             if len(s) > 100:
  132.                 raise SyntaxError, "not an IM file"
  133.  
  134.             if s[-2:] == '\r\n':
  135.                 s = s[:-2]
  136.             elif s[-1:] == '\n':
  137.                 s = s[:-1]
  138.  
  139.             try:
  140.                 m = split.match(s)
  141.             except re.error, v:
  142.                 raise SyntaxError, "not an IM file"
  143.  
  144.             if m:
  145.  
  146.                 k, v = m.group(1,2)
  147.  
  148.                 # Convert value as appropriate
  149.                 if k in [FRAMES, SCALE, SIZE]:
  150.                     i = string.find(v, "*")
  151.                     if i >= 0:
  152.                         v = v[:i] + "," + v[i+1:]
  153.                     v = eval(v)
  154.                 elif k == MODE and OPEN.has_key(v):
  155.                     v, self.rawmode = OPEN[v]
  156.  
  157.                 # Add to dictionary. Note that COMMENT tags are
  158.                 # combined into a list of strings.
  159.                 if k == COMMENT:
  160.                     if self.info.has_key(k):
  161.                         self.info[k].append(v)
  162.                     else:
  163.                         self.info[k] = [v]
  164.                 else:
  165.                     self.info[k] = v
  166.  
  167.                 if TAGS.has_key(k):
  168.                     n = n + 1
  169.  
  170.             else:
  171.  
  172.                 raise SyntaxError, "Syntax error in IM header: " + s
  173.  
  174.         if not n:
  175.             raise SyntaxError, "Not an IM file"
  176.  
  177.         # Basic attributes
  178.         self.size = self.info[SIZE]
  179.         self.mode = self.info[MODE]
  180.  
  181.         # Skip forward to start of image data
  182.         while s and s[0] != chr(26):
  183.             s = self.fp.read(1)
  184.         if not s:
  185.             raise SyntaxError, "File truncated"
  186.  
  187.         if self.info.has_key(LUT):
  188.             # convert lookup table to palette or lut attribute
  189.             palette = self.fp.read(768)
  190.             greyscale = 1 # greyscale palette
  191.             linear = 1 # linear greyscale palette
  192.             for i in range(256):
  193.                 if palette[i] == palette[i+256] == palette[i+512]:
  194.                     if palette[i] != chr(i):
  195.                         linear = 0
  196.                 else:
  197.                     greyscale = 0
  198.             if self.mode == "L":
  199.                 if greyscale:
  200.                     if not linear:
  201.                         self.lut = map(ord, palette[:256])
  202.                 else:
  203.                     self.mode = self.rawmode = "P"
  204.                     self.palette = ImagePalette.raw("RGB;L", palette)
  205.             elif self.mode == "RGB":
  206.                 if not greyscale or not linear:
  207.                     self.lut = map(ord, palette)
  208.  
  209.         self.frame = 0
  210.  
  211.         self.__offset = offs = self.fp.tell()
  212.  
  213.         self.__fp = self.fp # FIXME: hack
  214.  
  215.         if self.rawmode[:2] == "F;":
  216.  
  217.             # ifunc95 formats
  218.             try:
  219.                 # use bit decoder (if necessary)
  220.                 bits = int(self.rawmode[2:])
  221.                 if bits not in [8, 16, 32]:
  222.                     self.tile = [("bit", (0,0)+self.size, offs,
  223.                                  (bits, 8, 3, 0, -1))]
  224.                     return
  225.             except ValueError:
  226.                 pass
  227.  
  228.         if self.rawmode in ["RGB;T", "RYB;T"]:
  229.             # Old LabEye/3PC files.  Would be very surprised if anyone
  230.             # ever stumbled upon such a file ;-)
  231.             size = self.size[0] * self.size[1]
  232.             self.tile = [("raw", (0,0)+self.size, offs, ("G", 0, -1)),
  233.                          ("raw", (0,0)+self.size, offs+size, ("R", 0, -1)),
  234.                          ("raw", (0,0)+self.size, offs+2*size, ("B", 0, -1))]
  235.         else:
  236.             # LabEye/IFUNC files
  237.             self.tile = [("raw", (0,0)+self.size, offs, (self.rawmode, 0, -1))]
  238.  
  239.     def seek(self, frame):
  240.  
  241.         if frame < 0 or frame >= self.info[FRAMES]:
  242.             raise EOFError, "seek outside sequence"
  243.  
  244.         if self.frame == frame:
  245.             return
  246.  
  247.         self.frame = frame
  248.  
  249.         if self.mode == "1":
  250.             bits = 1
  251.         else:
  252.             bits = 8 * len(self.mode)
  253.  
  254.         size = ((self.size[0] * bits + 7) / 8) * self.size[1]
  255.         offs = self.__offset + frame * size
  256.  
  257.         self.fp = self.__fp
  258.  
  259.         self.tile = [("raw", (0,0)+self.size, offs, (self.rawmode, 0, -1))]
  260.  
  261.     def tell(self):
  262.  
  263.         return self.frame
  264.  
  265. #
  266. # --------------------------------------------------------------------
  267. # Save IM files
  268.  
  269. SAVE = {
  270.     # mode: (im type, raw mode)
  271.     "1": ("0 1", "1"),
  272.     "L": ("Greyscale", "L"),
  273.     "P": ("Greyscale", "P"),
  274.     "I": ("L 32S", "I;32S"),
  275.     "I;16": ("L 16", "I;16"),
  276.     "I;16B": ("L 16B", "I;16B"),
  277.     "F": ("L 32F", "F;32F"),
  278.     "RGB": ("RGB", "RGB;L"),
  279.     "RGBA": ("RGBA", "RGBA;L"),
  280.     "RGBX": ("RGBX", "RGBX;L"),
  281.     "CMYK": ("CMYK", "CMYK;L"),
  282.     "YCbCr": ("YCC", "YCbCr;L")
  283. }
  284.  
  285. def _save(im, fp, filename, check=0):
  286.  
  287.     try:
  288.         type, rawmode = SAVE[im.mode]
  289.     except KeyError:
  290.         raise ValueError, "Cannot save %s images as IM" % im.mode
  291.  
  292.     try:
  293.         frames = im.encoderinfo["frames"]
  294.     except KeyError:
  295.         frames = 1
  296.  
  297.     if check:
  298.         return check
  299.  
  300.     fp.write("Image type: %s image\r\n" % type)
  301.     if filename:
  302.         fp.write("Name: %s\r\n" % filename)
  303.     fp.write("Image size (x*y): %d*%d\r\n" % im.size)
  304.     fp.write("File size (no of images): %d\r\n" % frames)
  305.     if im.mode == "P":
  306.         fp.write("Lut: 1\r\n")
  307.     fp.write("\000" * (511-fp.tell()) + "\032")
  308.     if im.mode == "P":
  309.         fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
  310.     ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, -1))])
  311.  
  312. #
  313. # --------------------------------------------------------------------
  314. # Registry
  315.  
  316. Image.register_open("IM", ImImageFile)
  317. Image.register_save("IM", _save)
  318.  
  319. Image.register_extension("IM", ".im")
  320.