Date: Wed, 18 Dec 1996 12:53:56 +0100 Message-Id: <9612181153.AA14221@arnold.image.ivab.se> From: Fredrik Lundh Subject: Update: "Animated Raster Graphics" ==================================================================== Animated Raster Graphics! (Yet Another Proposal) ==================================================================== -------------------------------------------------------------------- 1. Goals + To provide a "simple multi-image framework that would take an afternoon to figure out". And to implement, for that matter. + To cleanly offer all the important mechanisms from GIF89a, but based on PNG and PND encodings. + To allow simple streaming decoders, with minimal decoder state (except for a possible list of uncompressed images). This includes the ability to "feed" data to a decoder, without having to use threads to run multiple decoders in parallel. + To allow simple streaming encoders. + To support most of the cases covered by the current MNG proposal, except for those where a script execution facility would be a good solution. A simple "composition" language could be devised in a later stage. + To allow anyone that has 1) a decent PNG decoder, and 2) an application that already supports animated GIFs (or any progressively decoded format) to implement the format, with little effort. There shouldn't be much excuses for the big guys out there not to support this format ;-) /F -------------------------------------------------------------------- 2. Chunk Summary AHDR -- introduces an animation size type depth length (if known, 0 if not) frame duration number of loops Note: added type/depth to allow the decoder to allocate/configure its display properly. removed all that weird resource stuff; I think it's safe to assume that the decoder knows about dynamic memory allocation, and that its most likely will be doing other things simultaneously that may cause it to run out of resources anyway... AFRM -- stores and displays an image id count (number of elements to follow) frame duration (if changed, 0 if not) Note: no implicit display stuff, no complex modes. ADEF -- stores an image for later use id count (number of elements to follow) DISC -- discard stored images list of image ids AEND -- end the animation Probably: tEXt, pHYS Maybe: sAVE/sEEK * Advanced chunks Note: This should be further investigated. Basically, an animation file that uses a script should be designed to display at least a static image if the animation script cannot be executed. aAPP -- store a script script name script type (e.g. "python", "tcl", "simple") script data (blob) aRUN -- play a script with given arguments script name default action (??) list of arguments (key/value pairs) * Image elements Note: These are only allowed after AFRM or ADEF. gAMA/PLTE/tRNS/pHYS details to be sorted out. IHDR/IDAT/IEND -- a full image same as for PNG DHDR/IDAT/DEND -- a delta image (target is specified by AFRM/ADEF) delta mode size offset BLNK -- a constant image size type depth pixel data for one pixel PAST -- paste an image into another id (source image) offset -------------------------------------------------------------------- 3. Decoder outline Note: The following pseudo-like code describes the expected behaviour of the decoder. However, a decoder implemented in this fashion will be fairly optimal. * Data structures class Display: int xsize int ysize int type int depth class Image: int xsize int ysize int type int depth (gamma, palette, transparency setting) storage class Context: Display display bool show int duration int id map images * Chunks semantics chunk AFRM: ASSERT(count == 0) show = true id = AFRM.id count = AFRM.count if AFRM.duration != 0: duration = AFRM.duration chunk ADEF: ASSERT(count == 0) show = false id = ADEF.id count = ADEF.count chunk IHDR, DHDR, BLNK, PAST: ASSERT(count > 0) process image data chunk (as described below) count = count - 1 if count == 0 and show: (note: can this be detected earlier?) ASSERT(display.size/type/depth == images[id].size/type/depth) copy images[id] to display chunk DISC: ASSERT(count == 0) ??? if len(list) == 0: delete images (note: all of them) else: for id in list of image ids: if id in images: delete images[id] chunk AEND: ASSERT(count == 0) ??? detete images if loop > 0: loop = loop -1 rewind input stream process chunk IHDR: if show: ASSERT(display.size/type/depth == IHDR.size/type/depth) if id in images: delete images[id] (note: decoder may reuse image memory if size/type/depth matches) images[id] = new Image(IHDR.size/type/depth) decode IDAT until IEND into images[id] process chunk DHDR: ASSERT(id in images) ASSERT(size/offset inside images[id].size) decode IDAT until IEND, paste/add into images[id] at DHDR.offset process chunk BLNK: if show: ASSERT(display.size/type/depth == BLNK.size/type/depth) if id not in images: images[id] = new Image(BLNK.size/type/depth) fill images[id] with colour process chunk PAST: ASSERT(id in images) or create blank image (as in IDHR)??? ASSERT(images[PAST.id].type/depth == images[id].type/depth) paste images[PAST.id] into images[id] at PAST.offset (note: size/offset may extend outside target, alpha is taken into account)