home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / GifImagePlugin.py < prev    next >
Encoding:
Text File  |  2004-04-20  |  10.4 KB  |  381 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: //modules/pil/PIL/GifImagePlugin.py#2 $
  4. #
  5. # GIF file handling
  6. #
  7. # History:
  8. # 1995-09-01 fl   Created
  9. # 1996-12-14 fl   Added interlace support
  10. # 1996-12-30 fl   Added animation support
  11. # 1997-01-05 fl   Added write support, fixed local colour map bug
  12. # 1997-02-23 fl   Make sure to load raster data in getdata()
  13. # 1997-07-05 fl   Support external decoder (0.4)
  14. # 1998-07-09 fl   Handle all modes when saving (0.5)
  15. # 1998-07-15 fl   Renamed offset attribute to avoid name clash
  16. # 2001-04-16 fl   Added rewind support (seek to frame 0) (0.6)
  17. # 2001-04-17 fl   Added palette optimization (0.7)
  18. #
  19. # Copyright (c) 1997-2001 by Secret Labs AB
  20. # Copyright (c) 1995-1997 by Fredrik Lundh
  21. #
  22. # See the README file for information on usage and redistribution.
  23. #
  24.  
  25.  
  26. __version__ = "0.7"
  27.  
  28.  
  29. import Image, ImageFile, ImagePalette
  30.  
  31.  
  32. # --------------------------------------------------------------------
  33. # Helpers
  34.  
  35. def i16(c):
  36.     return ord(c[0]) + (ord(c[1])<<8)
  37.  
  38. def o16(i):
  39.     return chr(i&255) + chr(i>>8&255)
  40.  
  41.  
  42. # --------------------------------------------------------------------
  43. # Identify/read GIF files
  44.  
  45. def _accept(prefix):
  46.     return prefix[:6] in ["GIF87a", "GIF89a"]
  47.  
  48. class GifImageFile(ImageFile.ImageFile):
  49.  
  50.     format = "GIF"
  51.     format_description = "Compuserve GIF"
  52.  
  53.     global_palette = None
  54.  
  55.     def data(self):
  56.         s = self.fp.read(1)
  57.         if s and ord(s):
  58.             return self.fp.read(ord(s))
  59.         return None
  60.  
  61.     def _open(self):
  62.  
  63.         # Screen
  64.         s = self.fp.read(13)
  65.         if s[:6] not in ["GIF87a", "GIF89a"]:
  66.             raise SyntaxError, "not a GIF file"
  67.  
  68.         self.info["version"] = s[:6]
  69.  
  70.         self.size = i16(s[6:]), i16(s[8:])
  71.  
  72.         self.tile = []
  73.  
  74.         flags = ord(s[10])
  75.  
  76.         bits = (flags & 7) + 1
  77.  
  78.         if flags & 128:
  79.             # get global palette
  80.             self.info["background"] = ord(s[11])
  81.             # check if palette contains colour indices
  82.             p = self.fp.read(3<<bits)
  83.             for i in range(0, len(p), 3):
  84.                 if not (chr(i/3) == p[i] == p[i+1] == p[i+2]):
  85.                     p = ImagePalette.raw("RGB", p)
  86.                     self.global_palette = self.palette = p
  87.                     break
  88.  
  89.         self.__fp = self.fp # FIXME: hack
  90.         self.__rewind = self.fp.tell()
  91.         self.seek(0) # get ready to read first frame
  92.  
  93.     def seek(self, frame):
  94.  
  95.         if frame == 0:
  96.             # rewind
  97.             self.__offset = 0
  98.             self.dispose = None
  99.             self.__frame = -1
  100.             self.__fp.seek(self.__rewind)
  101.  
  102.         if frame != self.__frame + 1:
  103.             raise ValueError, "cannot seek to frame %d" % frame
  104.         self.__frame = frame
  105.  
  106.         self.tile = []
  107.  
  108.         self.fp = self.__fp
  109.         if self.__offset:
  110.             # backup to last frame
  111.             self.fp.seek(self.__offset)
  112.             while self.data():
  113.                 pass
  114.             self.__offset = 0
  115.  
  116.         if self.dispose:
  117.             self.im = self.dispose
  118.             self.dispose = None
  119.  
  120.         self.palette = self.global_palette
  121.  
  122.         while 1:
  123.  
  124.             s = self.fp.read(1)
  125.             if not s or s == ";":
  126.                 break
  127.  
  128.             elif s == "!":
  129.                 #
  130.                 # extensions
  131.                 #
  132.                 s = self.fp.read(1)
  133.                 block = self.data()
  134.                 if ord(s) == 249:
  135.                     #
  136.                     # graphic control extension
  137.                     #
  138.                     flags = ord(block[0])
  139.                     if flags & 1:
  140.                         self.info["transparency"] = ord(block[3])
  141.                     self.info["duration"] = i16(block[1:3]) * 10
  142.                     try:
  143.                         # disposal methods
  144.                         if flags & 8:
  145.                             # replace with background colour
  146.                             self.dispose = Image.core.fill("P", self.size,
  147.                                 self.info["background"])
  148.                         elif flags & 16:
  149.                             # replace with previous contents
  150.                             self.dispose = self.im.copy()
  151.                     except (AttributeError, KeyError):
  152.                         pass
  153.                 elif ord(s) == 255:
  154.                     #
  155.                     # application extension
  156.                     #
  157.                     self.info["extension"] = block, self.fp.tell()
  158.                     if block[:11] == "NETSCAPE2.0":
  159.                         self.info["loop"] = 1 # FIXME
  160.                 while self.data():
  161.                     pass
  162.  
  163.             elif s == ",":
  164.                 #
  165.                 # local image
  166.                 #
  167.                 s = self.fp.read(9)
  168.  
  169.                 # extent
  170.                 x0, y0 = i16(s[0:]), i16(s[2:])
  171.                 x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:])
  172.                 flags = ord(s[8])
  173.  
  174.                 interlace = (flags & 64) != 0
  175.  
  176.                 if flags & 128:
  177.                     bits = (flags & 7) + 1
  178.                     self.palette =\
  179.                         ImagePalette.raw("RGB", self.fp.read(3<<bits))
  180.  
  181.                 # image data
  182.                 bits = ord(self.fp.read(1))
  183.                 self.__offset = self.fp.tell()
  184.                 self.tile = [("gif",
  185.                              (x0, y0, x1, y1),
  186.                              self.__offset,
  187.                              (bits, interlace))]
  188.                 break
  189.  
  190.             else:
  191.                 pass
  192.                 # raise IOError, "illegal GIF tag `%x`" % ord(s)
  193.  
  194.         if not self.tile:
  195.             # self.__fp = None
  196.             raise EOFError, "no more images in GIF file"
  197.  
  198.         self.mode = "L"
  199.         if self.palette:
  200.             self.mode = "P"
  201.  
  202.     def tell(self):
  203.         return self.__frame
  204.  
  205.  
  206. # --------------------------------------------------------------------
  207. # Write GIF files
  208.  
  209. try:
  210.     import _imaging_gif
  211. except ImportError:
  212.     _imaging_gif = None
  213.  
  214. RAWMODE = {
  215.     "1": "L",
  216.     "L": "L",
  217.     "P": "P",
  218. }
  219.  
  220. def _save(im, fp, filename):
  221.  
  222.     if _imaging_gif:
  223.         # call external driver
  224.         try:
  225.             _imaging_gif.save(im, fp, filename)
  226.             return
  227.         except IOError:
  228.             pass # write uncompressed file
  229.  
  230.     try:
  231.         rawmode = RAWMODE[im.mode]
  232.         imOut = im
  233.     except KeyError:
  234.         # convert on the fly (EXPERIMENTAL -- I'm not sure PIL
  235.         # should automatically convert images on save...)
  236.         if Image.getmodebase(im.mode) == "RGB":
  237.             imOut = im.convert("P")
  238.             rawmode = "P"
  239.         else:
  240.             imOut = im.convert("L")
  241.             rawmode = "L"
  242.  
  243.     # header
  244.     for s in getheader(imOut, im.encoderinfo):
  245.         fp.write(s)
  246.  
  247.     flags = 0
  248.  
  249.     try:
  250.         interlace = im.encoderinfo["interlace"]
  251.     except:
  252.         # default is on (since we're writing uncompressed images)
  253.         interlace = 1
  254.         flags = flags | 64
  255.  
  256.     # local image header
  257.     fp.write("," +
  258.              o16(0) + o16(0) +          # bounding box
  259.              o16(im.size[0]) +          # size
  260.              o16(im.size[1]) +
  261.              chr(flags) +               # flags
  262.              chr(8))                    # bits
  263.  
  264.     imOut.encoderconfig = (8, interlace)
  265.  
  266.     ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)])
  267.  
  268.     fp.write("\0") # end of image data
  269.  
  270.     fp.write(";") # end of file
  271.  
  272.     try:
  273.         fp.flush()
  274.     except: pass
  275.  
  276. def _save_netpbm(im, fp, filename):
  277.  
  278.     #
  279.     # If you need real GIF compression and/or RGB quantization, you
  280.     # can use the external NETPBM/PBMPLUS utilities.  See comments
  281.     # below for information on how to enable this.
  282.  
  283.     import os
  284.     file = im._dump()
  285.     if im.mode != "RGB":
  286.         os.system("ppmtogif %s >%s" % (file, filename))
  287.     else:
  288.         os.system("ppmquant 256 %s | ppmtogif >%s" % (file, filename))
  289.     try: os.unlink(file)
  290.     except: pass
  291.  
  292.  
  293. # --------------------------------------------------------------------
  294. # GIF utilities
  295.  
  296. def getheader(im, info=None):
  297.     """Return a list of strings representing a GIF header"""
  298.  
  299.     optimize = info and info.get("optimize", 0)
  300.  
  301.     s = [
  302.         "GIF87a" +              # magic
  303.         o16(im.size[0]) +       # size
  304.         o16(im.size[1]) +
  305.         chr(7 + 128) +          # flags: bits + palette
  306.         chr(0) +                # background
  307.         chr(0)                  # reserved/aspect
  308.     ]
  309.  
  310.     if optimize:
  311.         # minimize color palette
  312.         i = 0
  313.         maxcolor = 0
  314.         for count in im.histogram():
  315.             if count:
  316.                 maxcolor = i
  317.             i = i + 1
  318.     else:
  319.         maxcolor = 256
  320.  
  321.     # global palette
  322.     if im.mode == "P":
  323.         # colour palette
  324.         s.append(im.im.getpalette("RGB")[:maxcolor*3])
  325.     else:
  326.         # greyscale
  327.         for i in range(maxcolor):
  328.             s.append(chr(i) * 3)
  329.  
  330.     return s
  331.  
  332. def getdata(im, offset = (0, 0), **params):
  333.     """Return a list of strings representing this image.
  334.        The first string is a local image header, the rest contains
  335.        encoded image data."""
  336.  
  337.     class collector:
  338.         data = []
  339.         def write(self, data):
  340.             self.data.append(data)
  341.  
  342.     im.load() # make sure raster data is available
  343.  
  344.     fp = collector()
  345.  
  346.     try:
  347.         im.encoderinfo = params
  348.  
  349.         # local image header
  350.         fp.write("," +
  351.                  o16(offset[0]) +       # offset
  352.                  o16(offset[1]) +
  353.                  o16(im.size[0]) +      # size
  354.                  o16(im.size[1]) +
  355.                  chr(0) +               # flags
  356.                  chr(8))                # bits
  357.  
  358.         ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])])
  359.  
  360.         fp.write("\0") # end of image data
  361.  
  362.     finally:
  363.         del im.encoderinfo
  364.  
  365.     return fp.data
  366.  
  367.  
  368. # --------------------------------------------------------------------
  369. # Registry
  370.  
  371. Image.register_open(GifImageFile.format, GifImageFile, _accept)
  372. Image.register_save(GifImageFile.format, _save)
  373. Image.register_extension(GifImageFile.format, ".gif")
  374. Image.register_mime(GifImageFile.format, "image/gif")
  375.  
  376. #
  377. # Uncomment the following line if you wish to use NETPBM/PBMPLUS
  378. # instead of the built-in "uncompressed" GIF encoder
  379.  
  380. # Image.register_save(GifImageFile.format, _save_netpbm)
  381.