home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / ArgImagePlugin.py < prev    next >
Encoding:
Python Source  |  2004-04-20  |  14.6 KB  |  583 lines

  1. #
  2. # THIS IS WORK IN PROGRESS
  3. #
  4. # The Python Imaging Library.
  5. # $Id: //modules/pil/PIL/ArgImagePlugin.py#2 $
  6. #
  7. # ARG animation support code
  8. #
  9. # history:
  10. #       96-12-30 fl     Created
  11. #       96-01-06 fl     Added safe scripting environment
  12. #       96-01-10 fl     Added JHDR, UHDR and sYNC support
  13. #
  14. # Copyright (c) Secret Labs AB 1997.
  15. # Copyright (c) Fredrik Lundh 1996-97.
  16. #
  17. # See the README file for information on usage and redistribution.
  18. #
  19.  
  20. __version__ = "0.3"
  21.  
  22. import marshal, rexec, string
  23.  
  24. import Image, ImageFile, ImagePalette
  25.  
  26. from PngImagePlugin import i16, i32, ChunkStream, _MODES
  27.  
  28. MAGIC = "\212ARG\r\n\032\n"
  29.  
  30. APPLET_HOOK = None # must be explicitly enabled to support embedded scripts
  31.  
  32. # --------------------------------------------------------------------
  33. # ARG parser
  34.  
  35. class ArgStream(ChunkStream):
  36.     "Parser callbacks for ARG data"
  37.  
  38.     def __init__(self, fp):
  39.  
  40.         ChunkStream.__init__(self, fp)
  41.  
  42.         self.eof = 0
  43.  
  44.         self.im = None
  45.         self.palette = None
  46.  
  47.         self.__reset()
  48.  
  49.     def __reset(self):
  50.  
  51.         # reset decoder state (called on init and sync)
  52.  
  53.         self.count = 0
  54.         self.id = None
  55.         self.action = ("NONE",)
  56.  
  57.         self.images = {}
  58.         self.names = {}
  59.  
  60.         self.applets = {} # level 2
  61.  
  62.  
  63.     def chunk_AHDR(self, offset, bytes):
  64.         "AHDR -- animation header"
  65.  
  66.         # assertions
  67.         if self.count != 0:
  68.             raise SyntaxError, "misplaced AHDR chunk"
  69.  
  70.         s = self.fp.read(bytes)
  71.         self.size = i32(s), i32(s[4:])
  72.         try:
  73.             self.mode, self.rawmode = _MODES[(ord(s[8]), ord(s[9]))]
  74.         except:
  75.             raise SyntaxError, "unknown ARG mode"
  76.  
  77.         if Image.DEBUG:
  78.             print "AHDR size", self.size
  79.             print "AHDR mode", self.mode, self.rawmode
  80.  
  81.         return s
  82.  
  83.     def chunk_AFRM(self, offset, bytes):
  84.         "AFRM -- next frame follows"
  85.  
  86.         # assertions
  87.         if self.count != 0:
  88.             raise SyntaxError, "misplaced AFRM chunk"
  89.  
  90.         self.show = 1
  91.         self.id = 0
  92.         self.count = 1
  93.         self.repair = None
  94.  
  95.         s = self.fp.read(bytes)
  96.         if len(s) >= 2:
  97.             self.id = i16(s)
  98.             if len(s) >= 4:
  99.                 self.count = i16(s[2:4])
  100.                 if len(s) >= 6:
  101.                     self.repair = i16(s[4:6])
  102.                 else:
  103.                     self.repair = None
  104.  
  105.         if Image.DEBUG:
  106.             print "AFRM", self.id, self.count
  107.  
  108.         return s
  109.  
  110.     def chunk_ADEF(self, offset, bytes):
  111.         "ADEF -- store image"
  112.  
  113.         # assertions
  114.         if self.count != 0:
  115.             raise SyntaxError, "misplaced ADEF chunk"
  116.  
  117.         self.show = 0
  118.         self.id = 0
  119.         self.count = 1
  120.         self.repair = None
  121.  
  122.         s = self.fp.read(bytes)
  123.         if len(s) >= 2:
  124.             self.id = i16(s)
  125.             if len(s) >= 4:
  126.                 self.count = i16(s[2:4])
  127.  
  128.         if Image.DEBUG:
  129.             print "ADEF", self.id, self.count
  130.  
  131.         return s
  132.  
  133.     def chunk_NAME(self, offset, bytes):
  134.         "NAME -- name the current image"
  135.  
  136.         # assertions
  137.         if self.count == 0:
  138.             raise SyntaxError, "misplaced NAME chunk"
  139.  
  140.         name = self.fp.read(bytes)
  141.         self.names[self.id] = name
  142.  
  143.         return name
  144.  
  145.     def chunk_AEND(self, offset, bytes):
  146.         "AEND -- end of animation"
  147.  
  148.         if Image.DEBUG:
  149.             print "AEND"
  150.  
  151.         self.eof = 1
  152.  
  153.         raise EOFError, "end of ARG file"
  154.  
  155.     def __getmodesize(self, s, full=1):
  156.  
  157.         size = i32(s), i32(s[4:])
  158.  
  159.         try:
  160.             mode, rawmode = _MODES[(ord(s[8]), ord(s[9]))]
  161.         except:
  162.             raise SyntaxError, "unknown image mode"
  163.  
  164.         if full:
  165.             if ord(s[12]):
  166.                 pass # interlace not yet supported
  167.             if ord(s[11]):
  168.                 raise SyntaxError, "unknown filter category"
  169.  
  170.         return size, mode, rawmode
  171.  
  172.     def chunk_PAST(self, offset, bytes):
  173.         "PAST -- paste one image into another"
  174.  
  175.         # assertions
  176.         if self.count == 0:
  177.             raise SyntaxError, "misplaced PAST chunk"
  178.  
  179.         if self.repair is not None:
  180.             # we must repair the target image before we
  181.             # start pasting
  182.  
  183.             # brute force; a better solution would be to
  184.             # update only the dirty rectangles in images[id].
  185.             # note that if images[id] doesn't exist, it must
  186.             # be created
  187.  
  188.             self.images[self.id] = self.images[self.repair].copy()
  189.             self.repair = None
  190.  
  191.         s = self.fp.read(bytes)
  192.         im = self.images[i16(s)]
  193.         x, y = i32(s[2:6]), i32(s[6:10])
  194.         bbox = x, y, im.size[0]+x, im.size[1]+y
  195.  
  196.         if im.mode in ["RGBA"]:
  197.             # paste with transparency
  198.             # FIXME: should handle P+transparency as well
  199.             self.images[self.id].paste(im, bbox, im)
  200.         else:
  201.             # paste without transparency
  202.             self.images[self.id].paste(im, bbox)
  203.  
  204.         self.action = ("PAST",)
  205.         self.__store()
  206.  
  207.         return s
  208.  
  209.     def chunk_BLNK(self, offset, bytes):
  210.         "BLNK -- create blank image"
  211.  
  212.         # assertions
  213.         if self.count == 0:
  214.             raise SyntaxError, "misplaced BLNK chunk"
  215.  
  216.         s = self.fp.read(bytes)
  217.         size, mode, rawmode = self.__getmodesize(s, 0)
  218.  
  219.         # store image (FIXME: handle colour)
  220.         self.action = ("BLNK",)
  221.         self.im = Image.core.fill(mode, size, 0)
  222.         self.__store()
  223.  
  224.         return s
  225.  
  226.     def chunk_IHDR(self, offset, bytes):
  227.         "IHDR -- full image follows"
  228.  
  229.         # assertions
  230.         if self.count == 0:
  231.             raise SyntaxError, "misplaced IHDR chunk"
  232.  
  233.         # image header
  234.         s = self.fp.read(bytes)
  235.         size, mode, rawmode = self.__getmodesize(s)
  236.  
  237.         # decode and store image
  238.         self.action = ("IHDR",)
  239.         self.im = Image.core.new(mode, size)
  240.         self.decoder = Image.core.zip_decoder(rawmode)
  241.         self.decoder.setimage(self.im, (0,0) + size)
  242.         self.data = ""
  243.  
  244.         return s
  245.  
  246.     def chunk_DHDR(self, offset, bytes):
  247.         "DHDR -- delta image follows"
  248.  
  249.         # assertions
  250.         if self.count == 0:
  251.             raise SyntaxError, "misplaced DHDR chunk"
  252.  
  253.         s = self.fp.read(bytes)
  254.  
  255.         size, mode, rawmode = self.__getmodesize(s)
  256.  
  257.         # delta header
  258.         diff = ord(s[13])
  259.         offs = i32(s[14:18]), i32(s[18:22])
  260.  
  261.         bbox = offs + (offs[0]+size[0], offs[1]+size[1])
  262.  
  263.         if Image.DEBUG:
  264.             print "DHDR", diff, bbox
  265.  
  266.         # FIXME: decode and apply image
  267.         self.action = ("DHDR", diff, bbox)
  268.  
  269.         # setup decoder
  270.         self.im = Image.core.new(mode, size)
  271.  
  272.         self.decoder = Image.core.zip_decoder(rawmode)
  273.         self.decoder.setimage(self.im, (0,0) + size)
  274.  
  275.         self.data = ""
  276.  
  277.         return s
  278.  
  279.     def chunk_JHDR(self, offset, bytes):
  280.         "JHDR -- JPEG image follows"
  281.  
  282.         # assertions
  283.         if self.count == 0:
  284.             raise SyntaxError, "misplaced JHDR chunk"
  285.  
  286.         # image header
  287.         s = self.fp.read(bytes)
  288.         size, mode, rawmode = self.__getmodesize(s, 0)
  289.  
  290.         # decode and store image
  291.         self.action = ("JHDR",)
  292.         self.im = Image.core.new(mode, size)
  293.         self.decoder = Image.core.jpeg_decoder(rawmode)
  294.         self.decoder.setimage(self.im, (0,0) + size)
  295.         self.data = ""
  296.  
  297.         return s
  298.  
  299.     def chunk_UHDR(self, offset, bytes):
  300.         "UHDR -- uncompressed image data follows (EXPERIMENTAL)"
  301.  
  302.         # assertions
  303.         if self.count == 0:
  304.             raise SyntaxError, "misplaced UHDR chunk"
  305.  
  306.         # image header
  307.         s = self.fp.read(bytes)
  308.         size, mode, rawmode = self.__getmodesize(s, 0)
  309.  
  310.         # decode and store image
  311.         self.action = ("UHDR",)
  312.         self.im = Image.core.new(mode, size)
  313.         self.decoder = Image.core.raw_decoder(rawmode)
  314.         self.decoder.setimage(self.im, (0,0) + size)
  315.         self.data = ""
  316.  
  317.         return s
  318.  
  319.     def chunk_IDAT(self, offset, bytes):
  320.         "IDAT -- image data block"
  321.  
  322.         # pass compressed chunks through the decoder
  323.         s = self.fp.read(bytes)
  324.         self.data = self.data + s
  325.         n, e = self.decoder.decode(self.data)
  326.         if n < 0:
  327.             # end of image
  328.             if e < 0:
  329.                 raise IOError, "decoder error %d" % e
  330.         else:
  331.             self.data = self.data[n:]
  332.  
  333.         return s
  334.  
  335.     def chunk_DEND(self, offset, bytes):
  336.         return self.chunk_IEND(offset, bytes)
  337.  
  338.     def chunk_JEND(self, offset, bytes):
  339.         return self.chunk_IEND(offset, bytes)
  340.  
  341.     def chunk_UEND(self, offset, bytes):
  342.         return self.chunk_IEND(offset, bytes)
  343.  
  344.     def chunk_IEND(self, offset, bytes):
  345.         "IEND -- end of image"
  346.  
  347.         # we now have a new image.  carry out the operation
  348.         # defined by the image header.
  349.  
  350.         # won't need these anymore
  351.         del self.decoder
  352.         del self.data
  353.  
  354.         self.__store()
  355.  
  356.         return self.fp.read(bytes)
  357.  
  358.     def __store(self):
  359.  
  360.         # apply operation
  361.         cid = self.action[0]
  362.  
  363.         if cid in ["BLNK", "IHDR", "JHDR", "UHDR"]:
  364.             # store
  365.             self.images[self.id] = self.im
  366.  
  367.         elif cid == "DHDR":
  368.             # paste
  369.             cid, mode, bbox = self.action
  370.             im0 = self.images[self.id]
  371.             im1 = self.im
  372.             if mode == 0:
  373.                 im1 = im1.chop_add_modulo(im0.crop(bbox))
  374.             im0.paste(im1, bbox)
  375.  
  376.         self.count = self.count - 1
  377.  
  378.         if self.count == 0 and self.show:
  379.             self.im = self.images[self.id]
  380.             raise EOFError # end of this frame
  381.  
  382.     def chunk_PLTE(self, offset, bytes):
  383.         "PLTE -- palette data"
  384.  
  385.         s = self.fp.read(bytes)
  386.         if self.mode == "P":
  387.             self.palette = ImagePalette.raw("RGB", s)
  388.         return s
  389.  
  390.     def chunk_sYNC(self, offset, bytes):
  391.         "SYNC -- reset decoder"
  392.  
  393.         if self.count != 0:
  394.             raise SyntaxError, "misplaced sYNC chunk"
  395.  
  396.         s = self.fp.read(bytes)
  397.         self.__reset()
  398.         return s
  399.  
  400.     #
  401.     # LEVEL 2 STUFF
  402.  
  403.     def chunk_aAPP(self, offset, bytes):
  404.         "aAPP -- store application"
  405.  
  406.         s = self.fp.read(bytes)
  407.  
  408.         # extract type, name and code chunk
  409.         j = string.find(s, "\0")
  410.         name = s[:j]
  411.  
  412.         i = j + 1
  413.         j = string.find(s, "\0", i)
  414.         type = s[i:j]
  415.  
  416.         code = s[j+1:]
  417.  
  418.         if Image.DEBUG:
  419.             print "AAPP", repr(type), repr(name)
  420.  
  421.         if not code:
  422.             # delete existing applet
  423.             if self.applets.has_key(name):
  424.                 del self.applets[name]
  425.         else:
  426.             # store or execute applet
  427.             if type != "python":
  428.                 raise IOError, "unsupported script type " + type
  429.             # convert to executable object
  430.             code = marshal.loads(code)
  431.             if not name:
  432.                 # unnamed; execute immediately
  433.                 self.__applet(code)
  434.             else:
  435.                 try:
  436.                     # named applet; store in dictionary
  437.                     self.applets[name] = marshal.loads(code)
  438.                 except:
  439.                     pass # applet loading error
  440.  
  441.         return s
  442.  
  443.     def chunk_aRUN(self, offset, bytes):
  444.         "aRUN -- execute application"
  445.  
  446.         s = self.fp.read(bytes)
  447.  
  448.         j = string.find(s, "\0")
  449.         name = s[:j]
  450.  
  451.         # FIXME: should handle arguments
  452.         print "ARUN", name
  453.  
  454.         self.__applet(self.applets[name])
  455.  
  456.         return s
  457.  
  458.     def __applet(self, code):
  459.  
  460.         if not APPLET_HOOK:
  461.             return
  462.  
  463.         # run script in safe environment
  464.         safe = rexec.RExec()
  465.         safe.r_exec(code)
  466.  
  467.         # must convert images to Image object form
  468.         images = {}
  469.         for id, im in self.images.items():
  470.             # FIXME: this is crude: support for this operation
  471.             # should be moved to the Image module itself (or
  472.             # better; change this module to use Image objects
  473.             # instead of core objects)
  474.             i = Image.new(im.mode, im.size)
  475.             i.im = im
  476.             images[id] = i
  477.             if self.names.has_key(id):
  478.                 # add named image
  479.                 images[self.names[id]] = i
  480.  
  481.         APPLET_HOOK(safe.modules["__main__"].Animation, images)
  482.  
  483.  
  484. # --------------------------------------------------------------------
  485. # ARG reader
  486.  
  487. def _accept(prefix):
  488.     return prefix[:8] == MAGIC
  489.  
  490.  
  491. class ArgImageFile(ImageFile.ImageFile):
  492.  
  493.     format = "ARG"
  494.     format_description = "Animated raster graphics"
  495.  
  496.     def _open(self):
  497.  
  498.         if self.fp.read(8) != MAGIC:
  499.             raise SyntaxError, "not an ARG file"
  500.  
  501.         self.arg = ArgStream(self.fp)
  502.  
  503.         # read and process the first chunk (AHDR)
  504.  
  505.         cid, offset, bytes = self.arg.read()
  506.  
  507.         if cid != "AHDR":
  508.             raise SyntaxError, "expected an AHDR chunk"
  509.  
  510.         s = self.arg.call(cid, offset, bytes)
  511.  
  512.         self.arg.crc(cid, s)
  513.  
  514.         # image characteristics
  515.         self.mode = self.arg.mode
  516.         self.size = self.arg.size
  517.  
  518.     def load(self):
  519.  
  520.         if self.arg.im is None:
  521.             self.seek(0)
  522.  
  523.         # image data
  524.         self.im = self.arg.im
  525.         self.palette = self.arg.palette
  526.  
  527.         # set things up for further processing
  528.         Image.Image.load(self)
  529.  
  530.     def seek(self, frame):
  531.  
  532.         if self.arg.eof:
  533.             raise EOFError, "end of animation"
  534.  
  535.         self.fp = self.arg.fp
  536.  
  537.         while 1:
  538.  
  539.             #
  540.             # process chunks
  541.  
  542.             cid, offset, bytes = self.arg.read()
  543.  
  544.             if self.arg.eof:
  545.                 raise EOFError, "end of animation"
  546.  
  547.             try:
  548.                 s = self.arg.call(cid, offset, bytes)
  549.             except EOFError:
  550.                 break
  551.  
  552.             except "glurk": # AttributeError
  553.                 if Image.DEBUG:
  554.                     print cid, bytes, "(unknown)"
  555.                 s = self.fp.read(bytes)
  556.  
  557.             self.arg.crc(cid, s)
  558.  
  559.         self.fp.read(4) # ship extra CRC
  560.  
  561.     def tell(self):
  562.         return 0
  563.  
  564.     def verify(self):
  565.         "Verify ARG file"
  566.  
  567.         # back up to first chunk
  568.         self.fp.seek(8)
  569.  
  570.         self.arg.verify(self)
  571.         self.arg.close()
  572.  
  573.         self.fp = None
  574.  
  575. #
  576. # --------------------------------------------------------------------
  577.  
  578. Image.register_open("ARG", ArgImageFile, _accept)
  579.  
  580. Image.register_extension("ARG", ".arg")
  581.  
  582. Image.register_mime("ARG", "video/x-arg")
  583.