Image Format
The Image Engine makes the distinction between:
The input format: the format of the original image.
The output format: the image format used by the Image Renderer.
Several formats are managed in input: PNG, JPEG, BMP, etc. A specific VEE Port can support additional input formats.
Several formats are managed in output: the MicroEJ formats and the binary format. The output format can be:
Generated from the input format using the off-board tool Image Generator at application compile-time.
Generated from the input format by using a runtime decoder of the Image Loader at application run-time.
Dynamically created when using a BufferedImage.
The Image Renderer manages only the MicroEJ formats (MicroEJ Format: Standard, MicroEJ Format: Display, and MicroEJ Format: Custom).
The following table lists all the formats and their usage.
Format |
Input |
Output |
BufferedImage |
---|---|---|---|
no |
yes |
yes |
|
no |
yes |
yes [1] |
|
no |
yes |
yes [1] |
|
no |
yes |
no |
|
no |
not yet |
yes [1] |
|
no |
yes |
no |
|
yes |
no |
no |
The following sections list all the formats and their usage.
MicroEJ Format: Display
The display back buffer holds a pixel encoding which is:
standard: see Standard Output Formats,
grayscale: see Grayscale Output Formats,
non-standard: see Display Output Format and Pixel Structure.
The non-standard display format can be customized to encode the pixel in the same encoding as the display.
The number of bits per pixel and the pixel bit organization is asked during the MicroEJ format generation and when the drawImage
algorithms are running.
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 to free up some memory space.
Notes:
From the Image Engine point of view, the non-standard display format stays a MicroEJ format, readable by the Image Renderer.
The required memory to encode an image with a non-standard display format is similar to MicroEJ Format: Standard.
When the display format is standard or grayscale, the encoded image format is replaced by the related standard format.
The Graphics Engine’s drawing software algorithms only target (are only compatible with) the buffered images whose format is the same as the display format (standard or non-standard).
MicroEJ Format: Standard
This format requires a small header (around 20 bytes) to store the image size (width, height), format, flags (is_transparent, etc.), row stride, etc. The required memory also depends on the number of bits per pixel of the MicroEJ format:
required_memory = header + (image_width * image_height) * bpp / 8;
The pixel array is stored after the MicroEJ image file header. A padding between the header and the pixel array is added to force to start the pixel array at a memory address aligned on the number of bits-per-pixels.
Here are the conversions of 32-bit to each format:
ARGB8888: 32-bit format, 8 bits for transparency, 8 per color.
u32 convertARGB8888toRAWFormat(u32 c){ return c; }
ARGB4444: 16-bit format, 4 bits for transparency, 4 per color.
u32 convertARGB8888toRAWFormat(u32 c){ return 0 | ((c & 0xf0000000) >> 16) | ((c & 0x00f00000) >> 12) | ((c & 0x0000f000) >> 8) | ((c & 0x000000f0) >> 4) ; }
ARGB1555: 16-bit format, 1 bit for transparency, 5 per color.
u32 convertARGB8888toRAWFormat(u32 c){ return 0 | (((c & 0xff000000) == 0xff000000) ? 0x8000 : 0) | ((c & 0xf80000) >> 9) | ((c & 0x00f800) >> 6) | ((c & 0x0000f8) >> 3) ; }
RGB888: 24-bit format, 8 per color.
u32 convertARGB8888toRAWFormat(u32 c){ return c & 0xffffff; }
RGB565: 16-bit format, 5 for red, 6 for green, 5 for blue.
u32 convertARGB8888toRAWFormat(u32 c){ return 0 | ((c & 0xf80000) >> 8) | ((c & 0x00fc00) >> 5) | ((c & 0x0000f8) >> 3) ; }
A8: 8-bit format, only transparency is encoded.
u32 convertARGB8888toRAWFormat(u32 c){ return 0xff - (toGrayscale(c) & 0xff); }
A4: 4-bit format, only transparency is encoded.
u32 convertARGB8888toRAWFormat(u32 c){ return (0xff - (toGrayscale(c) & 0xff)) / 0x11; }
A2: 2-bit format, only transparency is encoded.
u32 convertARGB8888toRAWFormat(u32 c){ return (0xff - (toGrayscale(c) & 0xff)) / 0x55; }
A1: 1-bit format, only transparency is encoded.
u32 convertARGB8888toRAWFormat(u32 c){ return (0xff - (toGrayscale(c) & 0xff)) / 0xff; }
- The pixel order follows this rule:
pixel_offset = (pixel_Y * image_width + pixel_X) * bpp / 8;
MicroEJ Format: Grayscale
This format requires a small header (around 20 bytes) to store the image size (width, height), format, flags (is_transparent, etc.), row stride, etc. The required memory also depends on the number of bits per pixel of the MicroEJ format:
required_memory = header + (image_width * image_height) * bpp / 8;
AC44: 4 bits for transparency, 4 bits with grayscale conversion.
u32 convertARGB8888toRAWFormat(u32 c){ return 0 | ((color >> 24) & 0xf0) | ((toGrayscale(color) & 0xff) / 0x11) ; }
AC22: 2 bits for transparency, 2 bits with grayscale conversion.
u32 convertARGB8888toRAWFormat(u32 c){ return 0 | ((color >> 28) & 0xc0) | ((toGrayscale(color) & 0xff) / 0x55) ; }
AC11: 1 bit for transparency, 1 bit with grayscale conversion.
u32 convertARGB8888toRAWFormat(u32 c){ return 0 | ((c & 0xff000000) == 0xff000000 ? 0x2 : 0x0) | ((toGrayscale(color) & 0xff) / 0xff) ; }
C4: 4 bits with grayscale conversion.
u32 convertARGB8888toRAWFormat(u32 c){ return (toGrayscale(c) & 0xff) / 0x11; }
C2: 2 bits with grayscale conversion.
u32 convertARGB8888toRAWFormat(u32 c){ return (toGrayscale(c) & 0xff) / 0x55; }
C1: 1 bit with grayscale conversion.
u32 convertARGB8888toRAWFormat(u32 c){ return (toGrayscale(c) & 0xff) / 0xff; }
- The pixel order follows this rule:
pixel_offset = (pixel_Y * image_width + pixel_X) * bpp / 8;
MicroEJ Format: RLE Compressed
MicroEJ Format: Custom
A custom format embeds a buffer whose data are VEE Port specific. This data may be:
a pixel buffer whose encoding is different than the formats proposed before,
a buffer that is not a pixel buffer.
This format is identified by a specific format value between 0 and 7: see custom formats.
Images with a custom format can be used as any other image. For that, it requires some support at different levels depending on their usage:
To convert an image to this format at compile-time and embed it, an extension of the image generator is necessary; see VEE Port MicroEJ Custom Format.
To create a new one at runtime, some native extension is necessary; see Buffered Image.
To use it as a source (to draw the image in another buffer), some native extension is necessary; see Custom Format Support.
To use it as a destination (to draw into the image), some native extension is necessary; see Buffered Image.
Binary Format
This format is not compatible with the Image Renderer and MicroUI. It can be used by MicroUI addon libraries which provide their image management procedures.
Advantages:
Encoding is known by VEE Port.
Compression is inherent to the format itself.
Disadvantages:
This format cannot target a MicroUI Image (unsupported format).
Original Input Format
See Unspecified Output Format.
An image can be embedded without any conversion/compression. This allows embedding the resource as it is to keep the source image characteristics (compression, bpp, etc.). This option produces the same result as specifying an image as a resource in the MicroEJ launcher.
The following table lists the original formats that can be decoded at run-time and/or compile-time:
Image Generator: the off-board tool that converts an image into an output format. All AWT ImageIO default formats are supported and always enabled.
Front Panel: the decoders embedded by the simulator part. All AWT ImageIO default formats are supported but disabled by default.
Runtime Decoders: the decoders embedded by the embedded part.
Type |
Image Generator |
Front Panel |
Runtime Decoders |
---|---|---|---|
Graphics Interchange Format (GIF) |
yes |
yes [2] |
no [7] |
Joint Photographic Experts Group (JPEG) |
yes |
yes [2] |
no [7] |
Portable Network Graphics (PNG) |
yes |
yes [3] |
yes [3] |
Windows bitmap (BMP) |
yes |
yes [4] |
yes/no [4] |
Web Picture (WebP) |
yes [5] |
yes [5] |
yes [6] |
The formats are disabled by default; see Image Decoders.
The PNG format is supported when the module PNG
is selected in the VEE Port configuration file (see Encoded Image).
The Monochrome BMP is supported when the module BMPM
is selected in the VEE Port configuration file (see Encoded Image); the colored BMP format is only supported by the Front Panel (disabled by default, see Image Decoders).
Install the tool com.microej.tool#imageio-webp-1.0.1
from the Developer Repository in the VEE Port to support the WEBP format (see Service Image Loader and Image Decoders).
Install the C component com.microej.clibrary.thirdparty#libwebp-1.0.1
in the BSP to support the WEBP format at runtime.
The UI-pack does not provide some runtime decoders for these formats, but a BSP can add its decoders (see Encoded Image).
GPU Format Support
The MicroEJ formats display, standard and grayscale may be customized to be compatible with the hardware (usually GPU). It can be extended by one or several restrictions on the pixels array:
Its start address has to be aligned on a higher value than the number of bits-per-pixels.
A padding has to be added after each line (row stride).
The MicroEJ format can hold a VEE Port-dependent header between the MicroEJ format header (start of file) and the pixel array. The MicroEJ format is designed to let the VEE Port encode and decode this additional header. This header is unnecessary and never used for Image Engine software algorithms.
Note
From the Image Engine point of view, the format stays a MicroEJ format, readable by the Image Engine Renderer.
Advantages:
The GPU recognizes encoding.
Drawing an image is often very fast.
Supports opacity encoding.
Disadvantages:
No compression: the image size in bytes is proportional to the number of pixels. The required memory is similar to MicroEJ Format: Standard when no custom header exists.
When the MicroEJ format holds another header (called custom_header
), the required memory is:
required_memory = header + custom_header + (image_width * image_height) * bpp / 8;
The row stride allows adding some padding at the end of each line to start the next line at an address with a specific memory alignment; it is often required by hardware accelerators (GPU).
The row stride is, by default, a value in relation to the image width: row_stride_in_bytes = image_width * bpp / 8
.
Thanks to the Abstraction Layer API LLUI_DISPLAY_IMPL_getNewImageStrideInBytes
, it can be customized at image buffer creation.
The required memory becomes:
required_memory = header + custom_header + row_stride * image_height;