11 GIF File Writing
(require file/gif) | package: draw-lib |
The file/gif library provides functions for writing GIF files to a stream, including GIF files with multiple images and controls (such as animated GIFs).
A GIF stream is created by gif-start, and then individual images are written with gif-add-image. Optionally, gif-add-control inserts instructions for rendering the images. The gif-end function ends the GIF stream.
A GIF stream can be in any one of the following states:
'init : no images or controls have been added to the stream
'image-or-control : another image or control can be written
'image : another image can be written (but not a control, since a control was written)
'done : nothing more can be added
procedure
(gif-stream? v) → boolean?
v : any/c
procedure
v : any/c
procedure
v : any/c
procedure
(empty-gif-stream? v) → boolean?
v : any/c
procedure
(gif-colormap? v) → boolean?
v : any/c
procedure
(dimension? v) → boolean?
v : any/c
procedure
stream : gif-stream?
procedure
(gif-start out w h bg-color cmap) → gif-stream?
out : output-port? w : dimension? h : dimension? bg-color : color? cmap : (or/c gif-colormap? #f)
The width and height determine a virtual space for the overall GIF image. Individual images added to the GIF stream must fit within this virtual space. The space is initialized by the given background color.
Finally, the default meaning of color numbers (such as the background color) is determined by the given colormap, but individual images within the GIF file can have their own colormaps.
A global colormap need not be supplied, in which case a colormap must be supplied for each image. Beware that bg-color is ill-defined if a global colormap is not provided.
procedure
(gif-add-image stream left top width height interlaced? cmap bstr) → void? stream : image-ready-gif-stream? left : dimension? top : dimension? width : dimension? height : dimension? interlaced? : any/c cmap : (or/c gif-colormap? #f) bstr : bytes?
If interlaced? is true, then bstr should provide bytes ininterlaced order instead of top-to-bottom order. Interlaced order is:
every 8th row, starting with 0
every 8th row, starting with 4
every 4th row, starting with 2
every 2nd row, starting with 1
If a global color is provided with gif-start, a #f value can be provided for cmap.
The bstr argument specifies the pixel content of the image. Each byte specifies a color (i.e., an index in the colormap). Each row is provided left-to-right, and the rows provided either top-to-bottom or in interlaced order (see above). If the image is prefixed with a control that specifies an transparent index (see gif-add-control), then the corresponding “color” doesn’t draw into the overall GIF image.
An exception is raised if any byte value in bstr is larger than the colormap’s length, if the bstr length is not width times height, or if the top, left, width, and height dimensions specify a region beyond the overall GIF image’s virtual space.
procedure
(gif-add-control stream disposal wait-for-input? delay transparent) → void? stream : image-or-control-ready-gif-stream? disposal : (or/c 'any 'keep 'restore-bg 'restore-prev) wait-for-input? : any/c delay : dimension? transparent : (or/c color? #f)
The GIF image model involves processing images one by one, placing each image into the specified position within the overall image’s virtual space. An image-control command can specify a delay before an image is added (to create animated GIFs), and it also specifies how the image should be kept or removed from the overall image before proceeding to the next one (also for GIF animation).
The disposal argument specifies how to proceed:
'any : doesn’t matter (perhaps because the next image completely overwrites the current one)
'keep : leave the image in place
'restore-bg : replace the image with the background color
'restore-prev : restore the overall image content to the content before the image is added
If wait-for-input? is true, then the display program may wait for some cue from the user (perhaps a mouse click) before adding the image.
The delay argument specifies a delay in 1/100s of a second.
If the transparent argument is a color, then it determines an index that is used to represent transparent pixels in the follow image (as opposed to the color specified by the colormap for the index).
An exception is raised if a control is already added to stream without a corresponding image.
procedure
(gif-add-loop-control stream iteration) → void?
stream : empty-gif-stream? iteration : dimension?
An exception is raise if some control or image has been added to the stream already.
procedure
(gif-add-comment stream bstr) → void?
stream : image-or-control-ready-gif-stream? bstr : bytes?
An exception is raised if an image-control command was just written to the stream (so that an image is required next).
procedure
stream : image-or-control-ready-gif-stream?
An exception is raised if an image-control command was just written to the stream (so that an image is required next).
procedure
(quantize bstr) →
bytes? gif-colormap? (or/c color? #f)
bstr :
(and/c bytes? (lambda (bstr) (zero? (remainder (bytes-length bstr) 4))))
Given a set of pixels expressed in ARGB format (i.e., each four bytes is a set of values for one pixel: alpha, red, blue, and green), quantize produces produces
bytes for the image (i.e., a array of colors, expressed as a byte string)
a colormap
either #f or a color index for the transparent “color”
The conversion treats alpha values less than 128 as transparent pixels, and other alpha values as solid.
The quantization process uses Octrees [Gervautz1990] to construct an adaptive palette for all (non-transparent) colors in the image. This implementation is based on an article by Dean Clark [Clark1996].
To convert a collection of images all with the same quantization, simply append them for the input of a single call of quantize, and then break apart the result bytes.