|2.x||Added rate-adaptive progressive JPEG (PJPEG) and animated GIF support. Also, custom palette support added for Windows, in which the 8-bit hardware palette was matched to the displayed image.|
|4.x||Imagelib partially rewritten for cleaner API. As a consequence of schedule pressure, custom palette support was disabled.|
Layout issues a request to get/display an image URL as a client for the image library. The request could come from an HTML tag <img src=foo.gif> or a "View Image" request, for example.
The image library doesn't care how the image request was originally generated. It accepts data from whatever data stream is specified, buffering it until it has enough to process.
The main entry to the image library is the function IL_GetImage(). Layout calls IL_GetImage through lo_GetImage() in ns/lib/layout/layimage.c. IL_GetImage() returns a data structure called IL_ImageReq. Although multiple requests for the same image may be made on the same html page, a unique IL_ImageReq handle is generated for every request.
This does not mean the image must be decoded for each request. A single image URL may be used countless times on a page. A cache of previously decoded and sized images is kept and each image's information is kept in a data structure called an image_container. When an image request is issued, the imagelib searches through the cache to find a matching image_container. If it finds a matching container, it uses the previously decoded data. If not, it decodes the image data and creates a new image container which is added to the image cache for future use.
An image observer is created for the image request. The observer is
a mechanism designed to monitor the image_request status and
states like the following:
- the image's progress
- the image pixmap was updated
- the image finished decoding
- a frame of an image/animation finished decoding
- a cached image completed decoding
- the image request was destroyed and the observer list is ready for cleanup.
After the image's header has been read and the image's natural dimensions and target dimensions are understood, the image library decodes until it has a line's worth of data. The decoded data is resized to the target image size. If a transparency mask exists, the mask is also resized to the target image size. Any transformations needed to match the target color depth also occurs here.
The image libary deals with the image by line, rather than by blocks. The line ready for front end display is sent to the front end, by way of the function IL_DisplaySubImage().
When the observer realizes the image finished decoding, clean up can occur. Clean up, however, does not occur until the page is unloaded. First the image request is destroyed. The image container is destroyed. A image group container is destroyed last and insures all image structures are freed.
For each image, an image container is created for each decompressed/sized
il_container_struct (in ns/modules/libimg/src/if.h)
Each time the client(layout) asks the image library to display an image, an new image request handle is generated by IL_GetImage():
IL_ImageReq (in ns/modules/libimg/src/if.h)
IL_Image_struct (in ns/modules/libimg/src/il.h)
The function il_first_write() in file if.c sets up the vtable and attaches it to the the image_container for the new image. First it associates the newly created image container with the data stream. After determining the image format type, it assigns the five functions for that image type to the virtual table.
init = il_jpeg_init;
ic->write = il_jpeg_write;
ic->abort = il_jpeg_abort;
ic->complete = il_jpeg_complete;
ILTRACE(1,("il: ignoring unknown image type (%d)", ic->type));
/* end example */
The vtable-like interfaces that the imagelib uses are currently implemented using JMC, a componentization scheme that was used internally at Netscape for a short while, but which was abandoned shortly after its introduction. Any use of JMC should be expunged, as it adds a good deal of unnecessary complexity to the build process and the JMC tools won't be supported in the future. Ideally, the new imagelib interfaces should be migrated to the COM-like componentization scheme that is being introduced by the next generation plugin code in 5.0.
Aside from the problem of modularizing the core, cross-platform imagelib functionality, there is the separate issue that the platform-specific code that actually draws the image pixels on the screen currently resides within each platform's front-end, e.g. the code for Windows is in the ns/cmd/winfe directory. (There is also a PostScript "front-end" for printing mages on PostScript printers.). This code tends to be somewhat gratuitously entangled with each platforms's native widgets and classes. This image-drawing code should be isolated and placed in an "md" directory within the imagelib ("md" stands for machine-dependent). Again, the final goal is to build a standalone image viewer for each of the three platforms, using only the imagelib and a little glue code, so as to streamline imagelib development.
On X11, it should be possible to adapt to any existing colors in the palette. In existing version, nav attempts to allocate a regular lattice of RGB colors (a "color cube"). However, the eight "corner" colors of the cube, combined with any well-distributed set of colors in the cube interior should provide reasonable levels of dithering.
Ideally, should allocate 216-color cube, but if that's not possible, ...
A much better system would expose an entry-point into the imagelib that would be called whenever a low-memory situation is encountered. This code would attempt to purge the pixmap memory for images that haven't been recently displayed or which aren't visible on the screen. Even though the image pixmap would be discarded, all the information necessary to reconstruct it could be maintained, i.e. the image's source URL, image dimensions, etc. When a request is made to display a purged image, the imagelib would refetch it and redecode it.