Pixmaps

$Revision: 1.1.1.1.8.1 $

Introduction
Using Properties
Pixmap Properties
Creating a Pixmap Programmatically
Textures
  Texture Properties
  Texture-Infos
Cached Pixmaps
Controls that Use Pixmaps
Outline Controls and Pixmaps
Pixmap Handle Functions
Converting from .bmp Files to Lisp Code
Enhancing the IDE with Pixmaps
Mouse Cursors

Introduction

While the term "pixmap" is often used in a general way to describe the actual array of pixels or the image that they create, Common Graphics now uses the term to describe a class of objects that are used to manage pixmap images.

Applications may use Common Graphics pixmap objects (referred to as pixmaps) to manage their images. A pixmap can be created either by loading it from a .bmp file with load-pixmap, or by defining it programmatically with a make-instance form. Once defined, a pixmap can then be used either directly by copying it to a window or printer stream with copy-to-stream, or indirectly by associating it with a static-picture, picture-button, or multi-picture-button control. (Note that while a bitmap-pane is sometimes said to have a backing-store pixmap or bitmap, this is actually an internal object and not a pixmap.)

Using Properties

This document describes much of the programmatic interface to pixmaps rather briefly in terms of properties. When we mention, for example, that a pixmap has a "name property", this generally implies that the name can be specified when creating a pixmap by passing a :name initarg to make-instance, that the name can be read later by calling name on the pixmap, and that the name can be modified later with setf and name.

The names of the initarg and accessor symbols will always be the same as the property name (rare exceptions occur and will be noted). Some properties are defined as read-only, and so the setf will not be defined. When editing properties in the inspector, the property definition also tells the inspector what sort of extended editing to use when the button on the right side of the property row is clicked, and what sort of replacement values will be allowed. Properties also know how to enact needed side effects when modified.

Pixmap Properties

Pixmaps have the following properties. While pixmap properties can be modified at any time, they typically are specified at creation time since the various properties must be mutually compatible, and a pixmap is typically a static object. (To use a different image, it's best to create a separate pixmap.)

bits-per-pixel Specifies the number of bits that are used to denote each pixel value. Must be either 1, 4, 8, 16, or 24. Must be large enough for the largest pixel value used by the pixmap.
  • 1-bit-per-pixel values are 0 and 1
  • 4-bits-per-pixel values are 0 through 15
  • 8-bits-per-pixel values are 0 through 255
  • 16-bits-per-pixel values are 0 through 65535
  • 24-bits-per-pixel (true color) values are not a single index into a colormap, but instead uses one byte for each of the red, green, and blue components of the color.
colors A vector of RGB color structures that determines the color that will be used for each pixel value. Pixels with the value 0 will use the first color in the color vector, and in general pixels with the value N will use the Nth member of the color vector. The colors vector should contain at least (one more than) as many members as the largest pixel value in the contents list.
contents A list of lists containing the individual pixel values of the pixmap. Each inner list contains the pixels for one row of the pixmap from left to right, and the outer list contains the rows from top to bottom. When pretty-printed, the contents list is oriented as the image will appear, giving a rough idea of what the real thing will look like.
mask-contents An optional property to define part of the pixmap as transparent. If supplied, it is a list of lists that corresponds to the contents list. Each member of the inner lists is either a 1 to indicate that the pixel at that location should be transparent, or a 0 to indicate that the pixel should be the color in the corresponding contents list (or in the texture, if a texture is supplied rather than a contents list).

When a mask is used, the main contents list (or texture) should have a zero for each transparent pixel. Therefore, the first entry in the colors vector of a pixmap that uses a mask will normally be a dummy color that never appears in the image, since index zero is reserved for transparent pixels.

Also note that if a pixmap uses a mask then it should not also use a pixmap-handle, because the "device-dependent bitmap" that the handle points to will not incorporate the mask. This restriction may be removed in the future.

height The height in pixels of the pixmap's texture. Normally this need not be specified, as it is computed automatically from the contents property.
invert-p A flag indicating whether the rows of the contents list are specified from top to bottom or from bottom to top.
  • If invert-p is nil, then the rows of the contents list will be pretty-printed so as to look right-side-up.
  • If invert-p is non-nil, then the pretty-printed contents will look upside down.

Note, though, that the operating system specifies pixmaps from bottom to top, so when invert-p is non-nil, this is actually the most natural orientation from the operating system's point of view, and an "inverted" pixmap will actually be somewhat faster. In addition, pixmaps created by calling load-pixmap will be "inverted" because that is the way that the data is read from the .bmp file most efficiently.

name An arbitrary symbol used for finding the pixmap programmatically. A pixmap may be associated with a control by specifying its name as the pixmap-name property of the control (assuming that the pixmap has been cached).

See Also cache-pixmap

palette-size Normally this is computed automatically from the colors property, but may be specified for backward compatibility as an alternative to the bits-per-pixel property.
  • If specified directly, it should be the maximum number of colors allowed, either 2, 16, 256, or 65536.
  • If computed automatically from the colors property, it is the actual number of colors in the color vector, which may be less than the maximum possible for the bits-per-pixel of the pixmap.

The maximum number of colors allowed is determined by (expt 2 bits-per-pixel). 24-bit (true color) pixmaps do not use a color vector at all.

pixmap-handle The handle to an optional more efficient version of the pixmap which is managed inside the operating system. This property should not be set directly by an application, but instead is set indirectly by calling open-pixmap-handle on the pixmap to create the handle. The handle can be destroyed later by calling close-pixmap-handle on the pixmap.

This property is optional because there is a trade-off to using a pixmap handle. While they draw faster, they essentially double the amount of memory required for the pixmap since the operating system is making its own copy of the pixels that are defined in Lisp for the pixmap. It is a good idea to close pixmap handles that are no longer being used by calling close-pixmap-handle on the pixmaps that had used them.

Sometimes Common Graphics automatically opens a pixmap handle for a pixmap, in particular if it is used by a control (since controls tend to be small enough that we can assume that the extra space is not very significant). A multi-picture-button button-info MUST use a pixmap handle, since its implementation currently depends on that, so the handle should not be removed from a pixmap that is used in a multi-picture-button.

source If this pixmap was created by calling load-pixmap on a .bmp file, then the path namestring will be preserved as the value of the source property. If the pixmap was defined programmatically instead, then the source property will be nil.
texture A texture object that describes each pixel in the pixmap. Typically the pixels are specified with the contents property, but alternatively a texture object may first be created and then specified here. This is most useful for backward compatibility with version 3.0.2, where textures and texture-infos are used individually.
mask An optional second texture object that describes whether or not the pixmap is transparent at each pixel. Typically the mask pixels are specified with the mask-contents property, but alternately a texture object may first be created and then specified here. If supplied, the mask texture's bits-per-pixel must be 1, and the texture should have a 1 for each transparent pixel and a 0 for each non-transparent pixel.
texture-info A structure that internally contains the colors, bits-per-pixel, width, and height properties of the pixmap.

Provided as a property that is redundant with these other properties, primarily for backward compatibility with version 3.0.2 applications that have created texture-info structures, so that these structures can be specified directly as the texture-info property of a pixmap as an alternative to specifying the other properties separately.

width The width in pixels of the texture-info's texture. Normally this need not be specified, as it is computed automatically from the contents property.

Creating a Pixmap Programmatically

An example of a programmatically created pixmap:

(make-instance 'pixmap
  :name :find-debug-prompt
  :bits-per-pixel 4
  :colors (vector black dark-red dark-green
             dark-yellow dark-blue dark-magenta
             dark-cyan light-gray gray red green
             yellow blue magenta cyan white)
  :contents
  '((7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 0 0 7 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 0 0 0 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7)
    (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7)
    (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7)
    (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7)
    (7 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7)
    (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7)
    (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7)
    (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7)
    (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7)
    (7 0 0 0 7 7 7 7 7 0 0 0 0 0 7 7)
    (7 0 0 7 7 7 7 7 7 0 0 0 0 0 7 7)
    (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)))

In the above example, each "7" pixel will be drawn in light-gray because light-gray is at position 7 in the color vector of the pixmap.

While the example color vector above uses the built-in constants for the system colors, the general format using arbitrary colors is:

:colors (vector (make-rgb :red 200 :green 200)
                (make-rbg :red 200 :green 100 :blue 200)
                ...)

As a side note, if a pixmap uses the exact color vector shown in this example, then it could instead specify (default-palette-vector *system*) as its colors property, since it returns a vector with these particular colors. This saves space by reusing the same vector. The IDE uses the default-palette-vector for many of its picture buttons. There is also (default-gray-palette-vector *system*) which is just like the default-palette-vector except that black (at position 0) has been replaced by the value of (system-edge-shadow-color). Replacing a pixmap's color with this palette vector can make it appear to be dimmed. If your application uses multiple pixmaps that can share the same color vector, then consider storing such color vectors globally and reusing them to save space.

A more interesting reason to use the default-palette-vector: When the IDE or a standalone application starts up, a few of the colors in the default-palette-vector and default-gray-palette-vector are modified.

These special functions return the colors that the end user has set up in the Windows Control Panel. If you use the default-palette-vector for your application's buttons, then the buttons will adapt at runtime to match the end user's color preferences. You can demonstrate this by choosing a new color scheme in Control Panel and then switching back to the Allegro IDE. Using the default-palette-vector will cause your own application to adapt in the same way.

Textures

A texture specifies the rectangular array of pixel values that are used by a pixmap, without the additional information such as colors that are included in a pixmap (or texture-info) object. While a pixmap internally includes a texture, using a pixmap does not require dealing with the texture object directly at all, since the information contained in the texture is available directly from the pixmap by using its contents, bits-per-pixel, width, and height properties.

Texture Properties

A texture shares some of the properties of a pixmap, and these properties are accessed in the same way. The shared properties are contents, bits-per-pixel, palette-size, width, and height. In addition, a texture has the following unique properties:

texture-array An internal two-dimensional array that implements the texture. The texture-array can be passed to Windows functions, like StretchDIBits, if direct WinAPI calls are made. Usually, the texture-array is not specified when making an instance; instead, the contents property is specified and the texture-array is created from the contents.
texture-array-height The height of the internal texture array.
texture-array-width The width of the internal texture array. This may be larger than the logical width of the texture (accessed with the width property) due to an internal need to pad the array rows to 32-bit boundaries (which is now done automatically, unlike version 3.0.2).

Here is how to create the texture used by the earlier pixmap example. This texture would be created automatically by that example, but an application can alternately create a texture in this way and then pass it to a pixmap.

(make-instance 'texture
   :bits-per-pixel 4
   :contents
   '((7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 0 0 7 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 0 0 0 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7)
    (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7)
    (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7)
    (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7)
    (7 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7)
    (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7)
    (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7)
    (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7)
    (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7)
    (7 0 0 0 7 7 7 7 7 0 0 0 0 0 7 7)
    (7 0 0 7 7 7 7 7 7 0 0 0 0 0 7 7)
    (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)
    (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)))

Texture-Infos

A texture-info is a structure that is retained in versions 6.0 mostly for backward compatibility with version 3.0.2. It internally holds the colors, width, height, and bits-per-pixel property values of a pixmap. When using a pixmap object, you do not need to know about the texture-info used by the pixmap because each of the values held in the texture-info are immediately accessible from the pixmap by using the accessor functions colors, width, height, and bits-per-pixel.

Note: In order to access these values from a texture-info itself, the older accessor functions texture-info-colors, texture-info-width, texture-info-height, and texture-info-bits-per-pixel must be used instead.

A texture-info may be created by calling make-texture-info and then passed as the :texture-info initarg when creating a pixmap, as an alternative to passing separate initargs for the four corresponding properties when creating the pixmap.

Cached Pixmaps

cache-pixmap A cached pixmap is simply a pixmap on which the function cache-pixmap has been called, and which therefore is a member of an internal global list of pixmaps.
  • An application may choose to cache a pixmap so that it can later look up the pixmap from its name, rather than keeping the pixmap itself around in a variable somewhere.
  • An IDE user may want to cache a pixmap so that it will appear in the list of available pixmaps that drops down when using the inspector to modify the pixmap-name property of a static-picture, picture-button, or multi-picture-button control.

A list of all cached pixmaps (with tiny representations of their images) can be viewed from the IDE menubar by selecting the Tools | Inspect System Data | Internal System Parameters menu-item and then inspecting the "cached-pixmaps" item.

find-pixmap (name) Finds the cached pixmap with the specified name and returns it. Returns nil if no such pixmap is found. The name argument may be the actual name property of the pixmap (an arbitrary symbol) or the source property (a path namestring of the .bmp file from which the pixmap was originally loaded).

Pixmap names should be mutually unique to ensure finding the desired one.

uncache-pixmap (pixmap) Removes the specified pixmap from the global list of cached pixmaps. The pixmap can still be used but it may no longer be found by its name.


Controls that Use Pixmaps

A control that can display a pixmap has several properties that provide alternate ways of specifying the pixmap that it will display. These properties exist on a static-picture, or picture-button control, or on a button-info object (which specifies a single button of a multi-picture-button control). If you are editing one of these objects in the inspector and change one of these properties, the other properties in this set will update themselves to match.

pixmap The actual pixmap object to be displayed. This property may be specified programmatically, but it is read-only on the inspector since it's not feasible to type in a pixmap object. This property is handy in the inspector for jumping from a control to the pixmap that it displays.
pixmap-name The arbitrary symbol that is the name property of a pixmap that has been cached by calling cache-pixmap on it. The inspector's extended editor button for this property will drop down a list of all cached pixmaps to choose from. When building a form, any of these pixmaps may be used (even if they are currently used only by the IDE) since a copy will be saved in the .bml file associated with the dialog that the control is on.
pixmap-source The path namestring of a .bmp file from which to load the pixmap. When this property is modified, load-pixmap is internally called at that time to create a pixmap from the file contents. The pixmap is then cached and used as the pixmap for the control. The inspector's extended editor button for this property will invoke the file selection dialog for choosing a .bmp file. The pixmap-source property will be nil if the pixmap was created programmatically rather than being loaded from a .bmp file.

As long as the pixmap is not replaced again, the path namestring will remain as the pixmap-source property of the control even though the original .bmp file may no longer exist. This is not a problem, because the pixmap is loaded only a single time and (when building a form) the pixmap definition is thereafter stored in the .bml file associated with the dialog that the control is on.

If the original .bmp file has changed and you need to update all pixmaps that were loaded from that file,  update-widgets-of-image-file can be called. Or use the "Sync to Pixmap File" item on the right-button shortcut menu of a pixmap control on a form.

pixmap-icon Some controls can display an icon instead of a pixmap. An icon is similar to a pixmap that has a mask, but they are always managed within the operating system. Currently, controls that can display an icon can handle only the five icons that are pre-supplied by the operating system and are the values of the constants error-icon, warning-icon, question-icon, information-icon, and application-icon. The inspector's extended-editor button for this property drops down a list of these five built-in icons.

Note that setting a control's pixmap-icon will remove its pixmap, and vice versa.

pixmap-use-handle A flag that specifies whether the pixmap displayed by this control will create and use a more efficient version of the pixmap that is managed within the operating system. When this property is toggled on, the pixmap handle is created and stored on the pixmap itself. When this property is toggled off, the pixmap handle is removed from the pixmap and destroyed.


Outline Controls and Pixmaps

Outlines and outline-items also use pixmaps as the other controls mentioned above do, but instead of having a single pixmap property, there are separate properties for the leaf, opened, and closed pixmaps. An icon cannot be used instead of a pixmap, and there is no pixmap-use-handle property since pixmap handles are always used for outlines. Typically these properties are specified for the outline as a whole rather than for each outline-item, but the latter is provided if needed. The pixmap properties of an outline or outline-item are leaf-pixmap, leaf-pixmap-name, leaf-pixmap-source, opened-pixmap, opened-pixmap-name, opened-pixmap-source, closed-pixmap, closed-pixmap-name, and closed-pixmap-source. These behave similarly to the corresponding control properties documented above.


Pixmap Handle Functions

Here's the difference between the several functions for creating and deleting pixmap handles. ("Creating a pixmap handle" is a lazy way of saying "telling the operating system to create an optimized internal version of the pixmap and returning a handle to this internal pixmap to Common Graphics".)

When working with textures and texture-infos, the pixmap handle must be created and managed as a separate object. create-pixmap-handle creates and returns a pixmap handle, and destroy-pixmap-handle will destroy it later to free up operating system resources. (If destroy-pixmap-handle is not called explicitly, the handle will be destroyed automatically when Lisp or a standalone application exits.)

When working with pixmaps, open-pixmap-handle will create a handle and store it on the pixmap, while close-pixmap-handle will remove the handle from the pixmap and destroy it. These functions may also be called on a control that uses a pixmap in order to address its pixmap indirectly.

When working with controls that use pixmaps, calling (setf pixmap-use-handle) on the control will establish whether its pixmap uses a handle.


Converting from .bmp Files to Lisp Code

Since loading pixmaps from .bmp files is pretty fast, an application can simply include any needed .bmp files with it and load them at runtime. But if you would rather embed the pixmap data in your Lisp code to avoid distributing the .bmp files, then you can convert the .bmp data into Lisp source code. The simplest way is simply to call save-lisp-pixmap on a pixmap that has been loaded from a .bmp file with load-pixmap, which will create a new Lisp source code file with the programmatic definition of the pixmap in it. load-lisp-pixmap will then load this file and return the saved pixmap. The saved file may optionally be compiled in the meantime, and then load-lisp-pixmap called on the compiled file.

load-lisp-pixmap cannot be used at runtime, though, if the individual source code or fasl files have been replaced by an image file for distribution. In order to use save-lisp-pixmap for a generated application without distributing the pixmap source or fasl files, you would need to either edit the source code file that save-lisp-pixmap creates to force it to store the returned pixmap in some accessible location, or else make your application code call find-pixmap on the name of the pixmap that was saved. (The generated code does call cache-pixmap on the created pixmap.)

An alternative to using save-lisp-pixmap at all is to evaluate a form like (pprint (recreation-code my-pixmap)) in the debug window, and then to simply cut and paste the printed source code into your application. This allows placing multiple pixmaps into a single Lisp source file. Or inspect a pixmap object, go to the internals tab, and click on the button at the right side of the top line to invoke the "extended editor" for the pixmap. The modal editor window that pops up will contain the recreation code for the pixmap, which you could copy and paste into your application. (Though the editor is read-only, you can still copy the text from it.)


Enhancing the IDE with Pixmaps

pixmap (object)
Returns a pixmap to be associated with a certain class of object. Normally this is a 4-bits-per-pixel 16 by 16 pixmap. The inspector will display a pixmap in its history list for any object for which a pixmap method returns a pixmap. For example, adding the following method would cause all conses that appear in the inspector's history list to be represented by the :macroexp and pixmap.

(defmethod pixmap ((object cons))
  (find-pixmap :macroexpand))

Mouse Cursors

Mouse cursors are now standard-objects with some of the same properties as pixmaps. The object is called a cursor and has the properties name, texture, mask, cursor-handle, and click-position. Click-position is a position indicating the point within the cursor's image (relative to its upper left corner) that is considered to be the exact location pointed to by the cursor. The properties texture-info, width, and height from pixmaps are not needed for mouse cursors since all cursors are the same size and depth. (The depth is always 1-bit-per-pixel, and the standard mouse cursor size is returned by the functions mouse-cursor-width and mouse-cursor-height.) The function cursor and its setf get and set the mouse cursor of a window; the new cursor can be either a cursor object or a cursor handle (as in version 3.0.2 for backward compatibility). There is a cursor property on every window for its current cursor. Cursors can be cached similar to pixmaps using the functions cache-cursor, find-cursor, and uncache-cursor.

A cursor object will create its handle as needed when the cursor is assigned to a window.

Below is the IDE's definition of the "hand" mouse cursor. After defining a cursor in this way, you can immediately tell a window to use it with a form like

(setf (cursor my-window)(find-cursor :hand-cursor))

Note that black pixels require a "zero" in both the main texture and the mask texture, white pixels require a "one" in the main texture and a "zero" in the mask texture, and transparent pixels require a "zero" in the main texture and a "one" in the mask texture.

(cache-cursor
    (make-instance 'cursor
      :name :hand-cursor
      :click-position (make-position 13 4)
      :texture (make-instance 'texture
                 :bits-per-pixel 1
                 :contents
                 '(
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000011000000000000000000
                   #*00000000000011000000000000000000
                   #*00000000000011000000000000000000
                   #*00000000000011000000000000000000
                   #*00000000000011000000000000000000
                   #*00000000000011011000000000000000
                   #*00000000000011011011000000000000
                   #*00000000000011011011010000000000
                   #*00000000000011011011011000000000
                   #*00000000110011111111011000000000
                   #*00000000111011111111111000000000
                   #*00000000011011111111111000000000
                   #*00000000001011111111111000000000
                   #*00000000001111111111111000000000
                   #*00000000000111111111111000000000
                   #*00000000000111111111110000000000
                   #*00000000000011111111110000000000
                   #*00000000000011111111110000000000
                   #*00000000000001111111100000000000
                   #*00000000000001111111100000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000
                   #*00000000000000000000000000000000 
                   #*00000000000000000000000000000000
                   ))

      :mask (make-instance 'texture
              :bits-per-pixel 1
              :contents
              '(
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111
                #*11111111111100111111111111111111
                #*11111111111000011111111111111111
                #*11111111111000011111111111111111
                #*11111111111000011111111111111111
                #*11111111111000011111111111111111
                #*11111111111000000011111111111111
                #*11111111111000000000111111111111
                #*11111111111000000000001111111111
                #*11111111111000000000000111111111
                #*11111110001000000000000011111111
                #*11111110000000000000000011111111
                #*11111110000000000000000011111111
                #*11111111000000000000000011111111
                #*11111111100000000000000011111111
                #*11111111100000000000000011111111
                #*11111111110000000000000011111111
                #*11111111110000000000000111111111
                #*11111111111000000000000111111111
                #*11111111111000000000000111111111
                #*11111111111100000000001111111111
                #*11111111111100000000001111111111
                #*11111111111100000000001111111111
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111
                #*11111111111111111111111111111111 
                #*11111111111111111111111111111111
                ))))

Copyright (C) 1998-2000, Franz Inc., Berkeley, CA. All Rights Reserved.