Images

This page covers the three facets of images in MicroUI:

  • Immutable images: read-only resources, either converted offline to a RAW format or decoded at runtime from an encoded format such as PNG.

  • Mutable images: images the application draws into at runtime (BufferedImage).

  • The images heap: the RAM region holding the pixels of runtime-decoded and mutable images.

Immutable Images

Overview

Immutable images are graphical resources that can be accessed with a call to ej.microui.display.Image.getImage() or ej.microui.display.ResourceImage.loadImage(). As their name suggests, immutable images can not be modified. Therefore, there is no way to get a Graphics Context to draw into these images. To be displayed, these images have to be converted from their source format to a RAW format. The conversion can either be done:

  • At build-time, using the Image Generator.

  • At run-time, using the relevant decoder library.

Immutable images are declared in Classpath *.images.list files (or in *.externimages.list for an external resource, see External Images).

digraph D {

    internalImage [shape=diamond, label="internal?"]
    imagesList [shape=box, label="*.images.list"]
    imagesExt [shape=box, label="*.externimages.list \lor *.imagesext.list"]
    subgraph cluster_image {
        label ="Image"
        internalImage -> imagesList [label="yes"]
        internalImage -> imagesExt [label="no=external"]
    }
}

The file format is a standard Java properties file. Each line contains a /-separated resource path relative to the Classpath root referring to a standard image file (e.g. .png, .jpg). The resource may be followed by an optional parameter (separated by a :) which defines and/or describes the image output file format (RAW format). When no option is specified, the image is embedded as-is and will be decoded at run-time. Example:

# The following image is embedded as
# a PNG resource (decoded at run-time)
com/mycompany/MyImage1.png

# The following image is embedded as
# a 16-bit encoding without transparency (decoded at build-time)
com/mycompany/MyImage2.png:RGB565

# The following image is embedded as
# a 16-bit encoding with transparency (decoded at build-time)
com/mycompany/MyImage3.png:ARGB1555

getImage vs loadImage

The two entry points to retrieve an immutable image do not have the same requirements nor the same memory cost:

ej.microui.display.ResourceImage.loadImage() is the safer default when an asset’s output format may change: it works on both RAW and encoded assets, so changing the format in a *.images.list file never breaks the loading code. The trade-off is lifecycle management: a ResourceImage that allocated on the Images Heap must be closed (ResourceImage.close()) to free it; otherwise it leaks. ej.microui.display.Image.getImage() needs no such handling and suits assets that are always converted offline and kept allocation-free.

Configuration File

Here is the format of the *.images.list files.

ConfigFile          ::= Line [ 'EOL' Line ]*
Line                ::= ImagePath [ ':' ImageOption ]*
ImagePath           ::= Identifier [ '/' Identifier ]*
ImageOption         ::= [^:]*
Identifier          ::= Letter [ LetterOrDigit ]*
Letter              ::= 'a-zA-Z_$'
LetterOrDigit       ::= 'a-zA-Z_$0-9'

Unspecified Output Format

When no output format is set in the image list file, the image is embedded without any conversion / compression. This allows you to embed the resource as-is, in order to keep the source image characteristics (compression, bpp, size, etc.). This option produces the same result as specifying an image as a resource in the MicroEJ launcher (i.e. in a .resources.list file).

Refer to the platform specification to retrieve the list of runtime decoders.

Advantages

  • Preserves the image characteristics.

  • Preserves the original image compression.

Disadvantages

  • Requires an image runtime decoder.

  • Requires some RAM in which to store the decoded image.

  • Requires execution time to decode the image.

  • The decoded image lands on a wide format: unless the load call requests one, the runtime decoder uses its default (often ARGB8888).

  • Compact formats (in particular sub-byte alpha such as A4) are reachable only offline via the Image Generator, not through a runtime decode (whose output is given in Encoded Image).

image1

Display Output Format

It encodes the image into the exact display memory representation. If the image to encode contains some transparent pixels, the output file will embed the transparency according to the display’s implementation capacity. When all pixels are fully opaque, no extra information will be stored in the output file in order to free up some memory space.

Note

When the display memory representation is standard, the display output format is automatically replaced by a standard format.

Advantages

  • Drawing an image is very fast because no pixel conversion is required at runtime.

  • Supports alpha encoding when the display pixel format allows it.

Disadvantages

  • No compression: the image size in bytes is proportional to the number of pixels.

image1:display

Standard Output Formats

Some image formats are well known and commonly implemented by GPUs.

Refer to the platform specification to retrieve the list of natively supported formats.

Advantages

  • The pixel layout and bit format are standard, so it is easy to manipulate these images on the C-side.

  • Drawing an image is very fast when the display driver recognizes the format (with or without transparency).

Disadvantages

  • No compression: the image size in bytes is proportional to the number of pixels.

  • Slower than display format when the display driver does not recognize the format: a pixel conversion is required at runtime.

Here is the list of the standard formats:

  • Transparent images:

    • ARGB8888: 32-bit format, 8 bits for transparency, 8 per color,

    • ARGB4444: 16-bit format, 4 bits for transparency, 4 per color,

    • ARGB1555: 16-bit format, 1 bit for transparency, 5 per color.

  • Transparent images with premultiplied alpha (RGB and alpha are linked)

    • ARGB8888_PRE: 32-bit format, 8 bits for transparency, 8 per color,

    • ARGB4444_PRE: 16-bit format, 4 bits for transparency, 4 per color,

    • ARGB1555_PRE: 16-bit format, 1 bit for transparency, 5 per color.

  • Opaque images:

    • RGB888: 24-bit format, 8 per color,

    • RGB565: 16-bit format, 5 for red, 6 for green, 5 for blue.

  • Alpha images, only transparency is encoded (the color applied when drawing the image is the current GraphicsContext color):

    • A8: 8-bit format,

    • A4: 4-bit format,

    • A2: 2-bit format,

    • A1: 1-bit format.

Examples:

image1:ARGB8888
image2:RGB565
image3:A4

Grayscale Output Formats

Some grayscale formats may be useful on grayscale or black and white displays. These formats are produced offline by the Image Generator only; they are not reachable through a runtime decode, which falls back to its default format for them (see Unspecified Output Format and the mapping in Encoded Image).

Advantages

  • Reduced footprint with less bits per pixels.

Disadvantages

  • No compression: the image size in bytes is proportional to the number of pixels.

  • Slower: a pixel conversion is required at runtime.

Here is the list of the grayscale formats:

  • With transparency:

    • AC44: 4 bits for transparency, 4 bits with grayscale conversion,

    • AC22: 2 bits for transparency, 2 bits with grayscale conversion,

    • AC11: 1 bit for transparency, 1 bit with grayscale conversion.

  • Without transparency:

    • C4: 4 bits with grayscale conversion,

    • C2: 2 bits with grayscale conversion,

    • C1: 1 bit with grayscale conversion.

Examples:

image1:AC44
image2:C2

Compressed Output Formats

Some image formats are compressed using run-length encoding. This compression is lossless. The principle is that identical consecutive pixels are stored as one entry (value and count). The more the consecutive pixels are identical, the more the compression is efficient.

Advantages

  • Good compression when there are a lot of identical consecutive pixels.

Disadvantages

  • Drawing an image may be slightly slower than using an uncompressed format supported by the GPU.

  • Not designed for images with many different pixel colors: in such case, the output file size may be larger than the original image file.

Here is the list of the compressed formats:

  • ARGB1565_RLE: 1 bit for transparency, 5 for red, 6 for green, 5 for blue. Colors are encoded as RGB565 and the transparency bit is encoded as part of the RLE block format (Formerly named RLE1 up to UI Pack 13.3.X.)

  • A8_RLE: similar to A8.

image1:ARGB1565_RLE
image2:RLE1 # Deprecated
image3:A8_RLE

Alpha Format

As described above, the formats A8, A4, A2, A1 and A8_RLE (also called Picto) only handle the opacity information. The source image can be transparent or not, colored or grayscaled. The alpha format provides two options to interpret the source image’s pixels:

  • grayscale: The source image is first grayscaled and then drawn over a white background. The black pixels are encoded as fully opaque pixels, the white pixels as fully transparent pixels and gray pixels as transparent pixels (the closer the pixel is to black, the more opaque the encoded opacity is).

  • alpha: Only the opacity component is encoded (the R-G-B components are ignored).

  • no option: same as grayscale (backward compatibility).

image1:A8:grayscale
image2:A8_RLE:alpha
image3:A4

Note

The MicroUI ResourceImage OutputFormat A8 encodes in the same way as the option alpha.

Fonts are alpha-only assets too: a per-glyph bit depth controls a font’s footprint the same way an image’s alpha format does (see Fonts).

Expected Result

The following table summarizes the usage of the different formats and the actual result on a white background.

Image Output Formats Usage

Format

Source

Result

ARGB8888

../../../_images/transparent.png ../../../_images/argb8888.png

ARGB4444

../../../_images/transparent.png ../../../_images/argb4444.png

ARGB1555

../../../_images/transparent.png ../../../_images/argb1555.png

ARGB8888_PRE

../../../_images/transparent.png ../../../_images/argb8888.png

ARGB4444_PRE

../../../_images/transparent.png ../../../_images/argb4444.png

ARGB1555_PRE

../../../_images/transparent.png ../../../_images/argb1555.png

RGB888

../../../_images/opaque.png ../../../_images/rgb888_o.png
../../../_images/transparent.png ../../../_images/rgb888_t.png

RGB565

../../../_images/opaque.png ../../../_images/rgb565_o.png
../../../_images/transparent.png ../../../_images/rgb565_t.png

A8

../../../_images/picto.png ../../../_images/a8.png

With 0x0000ff as color

and option grayscale

../../../_images/a8_c.png

With 0x0000ff as color

and option alpha

../../../_images/a8_c_a.png
../../../_images/a8_a.png ../../../_images/a8_a.png

With 0x0000ff as color

and option grayscale

../../../_images/a8_w.png

With 0x0000ff as color

and option alpha

../../../_images/a8_c.png

A4

../../../_images/picto.png

option grayscale

../../../_images/a4.png
../../../_images/a8_a.png

option alpha

A2

../../../_images/picto.png

option grayscale

../../../_images/a2.png
../../../_images/a8_a.png

option alpha

A1

../../../_images/picto.png

option grayscale

../../../_images/a1.png
../../../_images/a8_a.png

option alpha

C4

../../../_images/grayscale.png ../../../_images/c4.png

C2

../../../_images/grayscale.png ../../../_images/c2.png

C1

../../../_images/grayscale.png ../../../_images/c1.png

AC44

../../../_images/grayscale_t.png ../../../_images/ac44.png

AC22

../../../_images/grayscale_t.png ../../../_images/ac22.png

AC11

../../../_images/grayscale_t.png ../../../_images/ac11.png

ARGB1565_RLE

../../../_images/transparent.png ../../../_images/argb1555.png

A8_RLE

../../../_images/picto.png

option grayscale

../../../_images/a8.png
../../../_images/a8_a.png

option alpha

Choosing a Format

Most RAW formats are uncompressed: flash size is bpp × width × height (plus a ~20-byte header), and bpp is fixed by the format. RLE formats (ARGB1565_RLE, A8_RLE) are compressed; their size depends on pixel repetition (see Compressed Output Formats). There is no safe single default; picking the minimal format the image content needs is the only way to control footprint.

Format bpp and typical use

Format(s)

bpp

Use when

A1 / A2 / A4 / A8

1–8

Monochrome pictograms (icons, shapes) to tint per UI state (see Alpha Format for the alpha option). A4 (4 bpp, 16 opacity levels) is a sound default.

RGB565

16

Opaque full-color images (no transparency).

RGB888

24

Opaque images needing full 8-bit color (when RGB565 shows visible banding).

ARGB4444

16

Soft-edged transparency (icons, gradients).

ARGB1555

16

Hard-edge transparency with more color depth.

ARGB8888

32

Full 8-bit color and alpha; use only when the image genuinely needs both at full depth.

display

16+

Opaque image drawn frequently: drawn as a direct copy, no per-pixel blending. See Display Output Format below.

C1 / C2 / C4 AC11 / AC22 / AC44

1–4

Grayscale content on a grayscale display. Software-only in practice (no GPU support).

ARGB1565_RLE A8_RLE

var

When the image has many consecutive identical pixels.

Monochrome pictograms: alpha-only format. A monochrome picto belongs in an alpha-only format (A4, A8, A2, A1): the current GraphicsContext color tints it at draw time, so one asset serves every UI state color, and its footprint is minimal (A4 at 4 bpp is 8× smaller than ARGB8888 and 4× smaller than a 16-bpp format). One trap: a source whose shape lives in the alpha channel (white or colored shapes on a transparent background) must set the alpha option, e.g. mypicto.png:A4:alpha, or the default grayscale mode reads luminance and mishandles it (the Alpha Format section details the alpha vs grayscale source options).

Display format: footprint vs draw speed. The display format (see Display Output Format) trades a larger RAW for the fastest draw of an opaque image, by storing it in the display’s native pixel layout (on an RGB565 display, image:display and image:RGB565 produce the same RAW). It sits at the opposite end of the footprint-vs-speed axis from A4: pick display for an opaque image drawn frequently over a fixed background, and A4 for a tinted monochrome picto.

Flatten a fixed background into the image. When an image is transparent only because it is always drawn over a known, uniform background, that background can be baked into the asset so the image becomes fully opaque. It can then be stored in an opaque format (e.g. RGB565, 16 bpp, half of ARGB8888) and drawn without alpha blending; both gains are independent of the display’s own pixel depth, so storing in RGB565 pays off even on a 24-bit display. If the chosen opaque format also matches the display’s native layout, the draw reduces to a per-line memory copy with no pixel conversion (see Display Output Format). This is a per-image optimization, valid only while the background stays truly fixed and uniform; otherwise the image loses its reusability.

Format and GPU compatibility. Which formats are GPU-accelerated is fixed by the VEE Port, not by the application: it depends both on the GPU itself (a GPU may accelerate RGB565 but not ARGB1555, or A8 but not A4) and on how the integrator’s GPU port (binding a library such as VGLite, DMA2D, or NemaGFX) exposes that capability to MicroUI. A format the port does not accelerate does not cause an error; it silently falls back to a software renderer, which is slower.

Quick reference for GPU compatibility:

  • ARGB8888, ARGB4444, ARGB1555, RGB888, RGB565, and A8/A4/A2/A1 are the standard candidates that GPUs often support, but support is still per-port.

  • *_PRE (premultiplied) variants exist for GPUs that blend only premultiplied sources.

  • Cx and ACxx (grayscale) and *_RLE compressed formats are MicroUI-specific encodings with no GPU support.

Validate the chosen format against the target VEE Port; do not assume support. The accelerated-format list is documented per GPU binding in the C modules.

Note

See Unspecified Output Format for the PNG-vs-RAW trade-off (runtime decode vs build-time conversion). That is a separate storage-encoding axis, orthogonal to the per-format bpp footprint covered here.

Caching Generated Images

Images converted using the Image Generator can be cached so that they are not rebuilt every time the application is launched. Doing so can significantly speed up the application build phase.

The cache is enabled by default. It may be disabled by setting the Application option ej.microui.imageConverter.disableCache to true.

The Image Generator obeys several rules when choosing whether an image should be converted.

  • If the cache is disabled, all images are generated every time the application is launched.

  • All images will be regenerated if the application is launched using another VEE port and the new VEE port uses a different Image Generator or another set of Image Generator plugins.

  • If the generated image does not exist, it will be generated.

  • If the source image has been modified since the last time it was converted, the image will be regenerated.

  • The image will be regenerated if the destination format has been modified in the images.list file.

Cached images are stored in .cache/images, which is located in the application output folder. You may delete this directory to force the generation of all images in your application. An image that was previously generated but is no longer listed in the *.images.list files when the application is launched will be deleted from the cache directory.

Warning

When testing an Image Generator extension project, the image cache is automatically disabled.

External Images

To fetch immutable images from external memory, the application must pre-register the external Image resources. The management of this kind of image may be different than the internal images and may require some allocations in the Images Heap. For more details about the external image management, refers to the VEE Port Guide chapter External Resource.

Image Generator Error Messages

These errors can occur while preprocessing images.

Static Image Generator Error Messages

ID

Type

Description

0

Error

The image generator has encountered an unexpected internal error.

1

Error

The images list file has not been specified.

2

Error

The image generator cannot create the final, raw file.

3

Error

The image generator cannot read the images list file. Make sure the system allows reading of this file.

4

Warning

The image generator has found no image to generate.

5

Error

The image generator cannot load the images list file.

6

Warning

The specified image path is invalid: The image will be not converted.

7

Warning

There are too many or too few options for the desired format.

8

Error

The display format is not generic; a MicroUIRawImageGeneratorExtension implementation is required to generate the MicroUI raw image.

9

Error

The image cannot be read.

10

Error

The image generator has encountered an unexpected internal error (invalid endianness).

11

Error

The image generator has encountered an unexpected internal error (invalid bpp).

12

Error

The image generator has encountered an unexpected internal error (invalid display format).

13

Error

The image generator has encountered an unexpected internal error (invalid pixel layout).

14

Error

The image generator has encountered an unexpected internal error (invalid output folder).

15

Error

The image generator has encountered an unexpected internal error (invalid memory alignment).

16

Error

The input image format and / or the ouput format are not managed by the image generator.

17

Error

The image has been already loaded with another output format.

Mutable Images

Overview

Unlike immutable images, mutable images are graphical resources that can be created and modified at runtime. The application can draw into such images using the Painter classes with the image’s Graphics Context as the destination. Mutable images can be created with a call to constructor ej.microui.display.BufferedImage().

BufferedImage image = new BufferedImage(320,  240);
GraphicsContext g = image.getGraphicsContext();
g.setColor(Colors.BLACK);
Painter.fillRectangle(g, 0, 0, 320, 240);
g.setColor(Colors.RED);
Painter.drawHorizontalLine(g, 50, 50, 100);
image.close();

Display Format

By default, the output format of a BufferedImage matches the display’s pixel organization (layout, depth, etc.). The algorithms used to draw in such an image are the same as those used on the display (for footprint purposes). The algorithm cannot draw transparent pixels since the display back buffer is opaque.

In addition, GraphicsContext.setColor() does not consider the alpha channel and only accepts RGB values. The given color value is interpreted as a 24-bit RGB color, where the high-order byte is ignored, and the remaining bytes contain the red, green, and blue channels, respectively.

Other Formats

It is also possible to create a buffered image with another format using the constructor with the format parameter.

The other formats than the display one are not supported by MicroUI. But a VEE port can manage one or more formats (see Destination Format).

Depending on the format, the transparency may be supported.

Images Heap

The image heap is used to allocate the pixel data of:

  • Mutable images (i.e. BufferedImage instances).

  • Immutable images decoded at runtime, typically a PNG: the heap is used to store the decoded image and the runtime decoder’s temporary buffers, required during the decoding step. After the decoding step, all the temporary buffers are freed. Note that the size of the temporary buffers depends on the decoder and on the original image itself (compression level, pixel encoding, etc.).

  • Immutable images which are not byte-addressable, such as images opened with an input stream (i.e. ResourceImage instances).

  • Immutable images which are byte-addressable but converted to a different output format (i.e. ResourceImage instances).

In other words, every image which cannot be retrieved using ej.microui.display.Image.getImage() is saved on the image heap.

The size of the images heap can be configured with the ej.microui.memory.imagesheap.size property. The peak RAM reached while an image is decoding (the decoded buffer plus the decoder’s temporary buffers) exceeds the final image size and is content-dependent, so the heap cannot be sized as a static sum of the decoded image sizes. The repeated load/close cycle of ResourceImage instances also fragments the heap over time, so an allocation can fail for lack of a large enough contiguous block even when the total free space would suffice. Size it from the peak observed while running the worst case on target.

Warning

A ResourceImage allocated on the images heap must be closed manually by the application (ResourceImage.close()); otherwise, a memory leak will occur on the images heap.

For more details about the images heap implementation, refers to this chapter in the VEE Port Guide.