Documentation: Icons and Images

| Documentation: Icons and Images [Remove Frame]

Icons and Images are part an parcel of attractive, user-friendly Graphical User Interfaces these days. Consequently, considerable effort has been expended in designing FOX to allow icon- and image-rich applications to be developed with the greatest ease.
In FOX, Images and Icons are objects that represent picture data. Images are simple pictures, whereas Icons are pictures with a shape mask that may be used to effectively mask out a certain area of the picture, and allow part the background to peek through as if the picture were transparent in some areas.
Both Icons and Images may have Client side pixel data as well as an X Server side pixmap representation. The typical application will construct the client-side pixel data by filling the Icon or Image with a picture, then create the server-side representation [after contact with the X Server has been established] by calling i`con->create()`, which creates an server side pixmap and uses a call to `icon->render()` to fill the pixmap with the pixel data .

Note that this is a two-step process which is very similar to that of constructing and creating regular FOX Widgets. This is no accident. The FOX philosophy is to construct [client-side] data structures such as Widgets and Icons and Images etc., then with all the information available, create their X Server side representation in one fell swoop by calling `app->create()`.

When you have given Buttons or Labels or other FOX Widgets icons, a call to that Widget's `create()` member function will also automatically call its icon `create()`. To allow icons to be shared by multiple Widgets, it is specifically allowed to call `create()` more than once on an icon or image.

In many cases, after calling an icon's create() member function, there is no need to keep the client-side pixel data around; thus, FOX icons will in most cases release the memory taken up by the pixel data. Should you want to repeatedly change the pixel data, however, FXIcon and FXImage have an option IMAGE_KEEP to allow you to hang on to the pixel data in the client. After making changes to the pixel data, you can call `icon->render()` again to render it into the pixmap.

Image Formats Supported

Currently, FOX supports CUR, BMP, GIF, ICO, IFF, JPEG, PCX, PNG, PPM, RAS, RGB, TGA, TIFF, XBM, and XPM based icons and images. The most preferred format is GIF, as it is about 10 times more compact than XPM, and about 2 times more compact than BMP. This is of some concern, as applications may have lots of icons [some analysis of our own applications revealed than one application's executable had about 1MB worth of XPM icons; with GIF, this would have been less than a 100kB].

Incorporating Icons and Images into an Application

One crucial problem with icon-rich applications is where to keep all those icons; obviously, keeping icons in separate files allows end-users to substitute icons and perhaps change them with an Icon Editor program. However, such a scenario also poses a maintainance problem:- software becomes extraordinarily dependent on specifics of a user installation, and end-users may actually break software by substituting corrupted icon files by accident, or perhaps other applications may overwrite them. Another common problem is the need for end-users to set paths and environment variables.

To eliminate these problems, the FOX approach is to embed all icons and images right into the application's executable. This is done by simply by compiling the icons into the code in the form of C data statements, and then linking them in.

XPM and XBM icons or images can be directly included into the source code, as these formats are basically just C++ data arrays already and there is consequently no reason to use reswrap.
XPM is particularly convenient as it allows you to build icons even without a graphical icon editor. Other image formats need to be transformed into a C++ data array with a small build-time utility called reswrap, which is provided in the FOX distribution.

Reswrap allows you to generate the C/C++ data arrays automatically from the icons during the build process of your application; simply add a few rules into your Makefile, or, under VC++, use the reswrap program in a so-called Utility Project. For example, given as input a GIF file image such as below:

Figure 1. Linux Penguin from file bigpenguin.gif.

After processing this file, reswrap generates a C data statement such as:

    /* Generated by reswrap from file bigpenguin.gif */
    const unsigned char bigpenguin[]={
      0x47,0x49,0x46,0x38,0x37,0x61,0x30,0x00,0x39,0x00,0xf3,0x00,0x00,0xb2,0xc0,0xdc,
      ...............................................................................
      ...............................................................................
      0xf4,0xe0,0x63,0x90,0x7c,0x7d,0x40,0xc5,0x92,0x0c,0x34,0x39,0x41,0x04,0x00,0x3b
      };

This can then be subsequently compiled into an object file, and linked in with the executable. To make use of such an icon, FOX supports deserialization from a memory stream. The icon data above could be used as follows to create an Icon:

    FXIcon *tux_icon = new FXGIFIcon(application,bigpenguin);

Wait! Is that all? Yes it is! This one statement creates an icon object, then deserializes the icon data from the GIF stream to build the icon's internal pixel data. A subsequent call:

    tux_icon->create();

Will create an X pixmap, render the icon into it, and subsequently release the pixel data after it is no longer needed. If you had created the icon with the IMAGE_KEEP option, the pixel data would have been kept around for subsequent manipulation by your application, and perhaps repeated rendering. To draw the icon in a window, simply:

    dc.drawIcon(tux_icon,x,y);

will do the job.

Bitmaps

Bitmaps (XBM images) in FOX behave very much like images. Except, unlike Images which are always 24 bits, and in color, Bitmaps are only one bit, or blank and white. Typical uses for Bitmaps are the creation of patterns and stipples, or shape masks against which other primitives are clipped.
In terms of constructing and using Bitmaps in FOX, it is completely analoguous:

    // Bitmap Data, in XBM Format

    #define gray_width 32
    #define gray_height 2
    static unsigned char gray_bits[] = {0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa};

    // Construct a bitmap object
    FXBitmap *grayBitmap=new FXBitmap(application, gray_bits, 0, gray_width, gray_height);

In terms of using Bitmaps for subsequent tiling and stippling operations, remember that MS-Windows has certain size limits such patterns; X-Windows has no such limit, but presumably smaller patterns are more efficient. It is probably a good idea to keep so widths such as 8,16, or 32.

Cursors

Cursors can be constructed in FOX to change the shape of the mouse-cursor. Constructing Cursors is very similar to constructing Bitmaps, except that Cursors comprise two bitmaps, a picture and a shape mask; also, Cursors have a so-called hot-spot, the point inside the cursor-glyph which is ``pointer to'' by the mouse.
FOX currently also supports color cursors with an alpha component, i.e. partially transparent cursors. This is limited to certain platforms; on platforms where color cursors are not supported, the color image is thresholded to a simple black/white image with the alpha channel mapping to fully transparent. Designing your color cursors with contrasting colors ensures that they will look reasonable on such platforms.

Besides defining your own ``custom'' cursors, FOX also allows you to simply create a ``stock'' cursor, i.e. a cursor whose shape has already been predefined by the system. To create a custom Cursor:

    // Picture bits, in XBM Format
    #define resize_width 32
    #define resize_height 32
    #define resize_x_hot 9
    #define resize_y_hot 9
    static unsigned char resize_bits[] = {
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
       ....
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    // Shape bits, in XBM Format
    #define resize_mask_width 32
    #define resize_mask_height 32
    #define resize_mask_x_hot 9
    #define resize_mask_y_hot 9
    static unsigned char resize_mask_bits[] = {
       0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
       ....
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

      // Resize corner
      resizeCursor=new FXCursor(application,resize_bits,resize_mask_bits,resize_width,resize_height,resize_x_hot,resize_y_hot);

To create a stock Cursor:

    // Text Cursor
    IBeamCursor=new FXCursor(application,CURSOR_IBEAM);

If you define your own Custom Cursors, make sure the size is exactly 32x32. MS-Windows does not support any other sizes. Also, the shape and the picture will have to be the same size.

If Icons Look Funny...

Sometimes, your icons may look funny. This is usually because FOX Icon routines determine the wrong value for the transparency color. FOX can handle images with a true alpha-channel, or images with a special transparency color. The latter is the more common approach, as many file formats do not support true alpha channels.
Different image formats guess the transparency color in different ways. For GIF Images, FOX uses the following algorithm:

- If a transparent color is found in the GIF file, that color is used.
- If not, the background color is used.
- If the option IMAGE_ALPHACOLOR is used when constructing the icon, the specified color is used.
- Finally, if the option IMAGE_OPAQUE is used, the icon is forced to be non-transparent.

For BMP images, there is no background or transparency color in the image file format; the algorithm is simpler:

- The assumed transparency color is the same as the default GUI background color, which is FXRGB(192,192,192).
- If the option IMAGE_ALPHACOLOR is used when constructing the icon, the specified color is used.
- Finally, if the option IMAGE_OPAQUE is used, the icon is forced to be non-transparent.

In most cases, you will create your icons simply as below:

    new FXGIFIcon(app,picture_data);

In some cases, when you want to override the transparency color,construct your icons as:

    new FXGIFIcon(app,picture_data,FXRGB(192,192,192),IMAGE_ALPHACOLOR);

To create an completely opaque icon:

    new FXGIFIcon(app,picture_data,0,IMAGE_OPQUE);

For more information on graphics file formats and their idiosyncracies, see the Graphics File Format Web Site.

More on Reswrap

The reswrap tool has a number of options to make it convenient to build C source and header files automatically from image files as a part of your regular project build process. Reswrap is normally invoked as follows:

    reswrap [options] [-o[a] outfile]  files....

Invoking reswrap with `-o outfile` will make reswrap write its output on the file outfile. With `-oa outfile`, reswrap will append additional data at the end of outfile.
Any number of input files may be specified. Reswrap typically produces one data statement for each of the input files specified on the command line.

Reswrap understands a few additional options:

-h

> Will print out a summary of the supported options.

-v

> Will print out the version number.

-d

> Reswrap normally generates its output as hexadecimal numbers; the -d option will make reswrap generate decimal numbers.

-x

> Forces reswrap to generate hexadecimal numbers [the default].

-e

> Places the storage modifier `extern` in front of the data array, ensuring that the data array can be linked with other compilation units.

-i

> Instead of a data array statement, reswrap will generate a declaration only. For example,

    reswrap -i bigpenguin.gif

> will produce the output:

    /* Generated by reswrap from file bigpenguin.gif
    */
    extern const unsigned char bigpenguin[];

Which you could include as a header file into whichever source file needs access to the data.
-s

> This option suppresses comments inserted by reswrap to indicate the original file name from which the data statement was generated.

-n name

> Instead of taking the filename less the extension, reswrap substitutes name for the name of the resource.

-c cols

> Uses cols columns instead of the default 16 columns in the data statements generated by reswrap.

-ppm

> Assumes the source file is a Portable Pixmap (ppm) file. Reswrap will output a simple rgb array.

Example of using reswrap in your Application's Makefile:

    OBJECTS = icons.o myapp.o
    ICONS = bigpenguin.gif applogo.gif
    icons.h: $(ICONS)
     reswrap -e -o icons.h $(ICONS)

    icons.cc: $(ICONS)
     reswrap -o icons.cc $(ICONS)

    myapp: $(OBJECTS)
       gcc -o myapp $(OBJECTS) -lFOX -lm -lSM -lICE -lXext -lX11

    myapp.o: myapp.cc icons.h

This will cause make to generate two files, `icons.h` and `icons.cc` which contain the declarations and definitions respectively for all the reswrapped icons listed in the ICONS variable.

Copyright © 1997-2005 Jeroen van der Zijp