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"]
}
}](../../../_images/graphviz-798e2ad9ee91f7b6cf0005a7cc23d850848eb6cd.png)
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.Image.getImage() draws the image straight from flash and requires no allocation in the Images Heap, but it works only on an asset already in RAW format (one converted offline by the Image Generator). On an encoded asset (e.g. a PNG embedded as-is), it does not decode the image: it throws a MicroUIException, because the resource requires a loading step.
ej.microui.display.ResourceImage.loadImage() works on both: on a RAW asset it uses the same no-allocation path, and on an encoded asset it decodes the image into the Images Heap (the returned ResourceImage must then be closed to free that memory).
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
displayformat 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.
Format |
Source |
Result |
|---|---|---|
ARGB8888 |
|
|
ARGB4444 |
|
|
ARGB1555 |
|
|
ARGB8888_PRE |
|
|
ARGB4444_PRE |
|
|
ARGB1555_PRE |
|
|
RGB888 |
|
|
|
|
|
RGB565 |
|
|
|
|
|
A8 |
|
|
With 0x0000ff as color and option |
|
|
With 0x0000ff as color and option |
|
|
|
|
|
With 0x0000ff as color and option |
|
|
With 0x0000ff as color and option |
|
|
A4 |
option |
|
option |
||
A2 |
option |
|
option |
||
A1 |
option |
|
option |
||
C4 |
|
|
C2 |
|
|
C1 |
|
|
AC44 |
|
|
AC22 |
|
|
AC11 |
|
|
ARGB1565_RLE |
|
|
A8_RLE |
option |
|
option |
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(s) |
bpp |
Use when |
|---|---|---|
A1 / A2 / A4 / A8 |
1–8 |
Monochrome pictograms (icons, shapes) to tint per
UI state (see Alpha Format
for the |
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. |
|
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, andA8/A4/A2/A1are the standard candidates that GPUs often support, but support is still per-port.*_PRE(premultiplied) variants exist for GPUs that blend only premultiplied sources.CxandACxx(grayscale) and*_RLEcompressed 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.
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.
