Graphics Ports supports drawing images, and also reading/writing them from/to file via your code. A wide range of image types is supported. Also, several CAPI classes support the same image types.
To draw an image with Graphics Ports, you need an image object which is associated with an instance of output-pane (or a subclass of this). You can create an image object from:
Draw the image to the pane by calling draw-image. Certain images ("Plain Images") can be manipulated via the Image Access API. The image should be freed by calling free-image when you are done with it.
The CAPI classes image-pinboard-object, button, list-panel, list-view, tree-view, toolbar, toolbar-button and toolbar-component all support images. There is also limited support for images in menu. These classes handle the drawing and freeing for you.
Call the function list-known-image-formats to list the formats that the current platform supports for reading and drawing.
Note: On Microsoft Windows, LispWorks additionally supports Windows Icon files with scaling - see load-icon-image for details.
Graphic images can be written to files in several formats, using externalize-and-write-image.
All platforms can write at least BMP, JPG, PNG and TIFF files. Call the function list-known-image-formats with optional argument
t to list the formats that the current platform supports for writing.
On Microsoft Windows and Cocoa you can also write GIF files, while on GTK+ you can also write ICO and CUR (cursor) files. The cursor files that are written with GTK+ can be used on Windows and Cocoa, although on Cocoa it does not recognize the hot-spot in a CUR file.
An External Image is an intermediate object. It is a representation of a graphic but is not associated with a port and cannot be used directly for drawing. It is a Lisp object which can be loaded into Lisp and saved in a LispWorks image created by
An object of type external-image is created by reading an image from a file, or by externalizing an image object, or by copying an existing external-image. Or, if you have the image bitmap data, you can create one directly as in this example:
Convert an external-image to an object of type image ready for drawing to a port in several ways as described in Making an image that is suitable for drawing. Such conversions are cached but you can remove the caches by clear-external-image-conversions.
An External Image representing an image in a format with a color table but with no alpha channel (such as 8-bit BMP) can simulate transparency by specifying an index to represent the transparent color. When converted this color is replaced by the background color of the port (which is documented in simple-pane).
(gp:read-external-image file :transparent-color-index 42)
You can use an image tool such as Gimp (
) to figure out the transparent color index.
On platforms other than Motif you can actually make the background of such an image format truly transparent when displayed. To do this, supply
as a cons
One way to load an image is via a registered image identifier.
Registering an external image is the way to pre-load images while building an application. To do this, establish a registered image identifier by calling register-image-translation at build time:
Then at run time obtain the image object by:
(gp:load-image port 'info-image)
To create an image object suitable for drawing on a given pane, use one of convert-external-image, read-and-convert-external-image, load-image, make-image-from-port, make-sub-image, make-scaled-sub-image or (on Microsoft Windows) load-icon-image.
Images need to be freed after use. When the pane that an image was created for is destroyed, the image is freed automatically. However if you want to remove the image before the pane is destroyed, you must make an explicit call free-image. If the image is not freed, then a memory leak will occur.
Another way to create an image object is to supply a registered image identifier in a CAPI class that supports images. For example you can specify an image in an image-pinboard-object. Then, an image object is created implicitly when the pinboard object is displayed and freed implicitly when the pinboard object is destroyed.
In all cases, the functions that create the image object require the pane to be already created. So if you are displaying the image when first displaying your window, take care to create the image object late enough, for example in the
:before method of interface-display on the window's interface class, or in the first
:display-callback of the pane.
To obtain the pixel dimensions of an image, load the image using load-image and then use the readers
image-height. The first argument to load-image must be a pane in a displayed interface.
To query the dimensions before displaying anything you can create and "display" an interface made with the
:display-state :hidden initarg. Call load-image with this hidden interface and your external-image object, and then use the readers
The function to draw an image is draw-image.
As with the other drawing functions, this must be called in the same process as the pane, as outlined in Drawing functions.
You can read and write pixel values in an image via an Image Access object, but only if the image is a Plain Image. You can ensure you have a Plain Image by using the result of
(load-image pane image :force-plain t)
(setf image-access-pixel)with the coordinates of each pixel (or use image-access-pixels-from-bgra) to write pre-multiplied pixel RGB values and then call image-access-transfer-to-image on the Image Access object. This notionally transfers all the pixel data back to the window system from the access object. It might do nothing if the window system allows fast access to the pixel data directly.
It is also possible to get all the pixels into a single vector, where each color is represented by four elements, using image-access-pixels-from-bgra, and to change all the pixels in the image to values from a vector using image-access-pixels-to-bgra. When accessing many pixels, using these functions and accessing the vector is much faster than using the single pixel access.
The color values that are received and set using Image Access are premultiplied , which means that the value of each of the three components (Red, Green and Blue) are already multiplied by the value of the alpha. This is different from the way colors are represented elsewhere. The functions color-to-premultiplied and color-from-premultiplied can be used the convert between premultiplied colors and ordinary colors, although they lose some precision in the process.
For example, the form below creates an image from a pixmap filled with a color that has alpha 0.5. When accessing the image using Image Access, the values in the color that it returned are half of the values in the original color.
To create an external-image object from graphics ports operations, use with-pixmap-graphics-port, and in the scope of it do the drawing and then use make-image-from-port to create an image object. You can then use externalize-image or externalize-and-write-image to externalize the image.
Here output-pane must be a displayed instance of output-pane (or a subclass). The code does not affect the displayed pane.
CAPI User Guide and Reference Manual (Macintosh version) - 3 Aug 2017