Images
The GDISP module comes with a built-in image decoder. The decoder allows it to open an image of various formats and display it. As the GFILE module is being used internally, the image can be stored on different sources such as the internal flash or external memory like an SD card.
Before you continue to read this documentation, please consider using the ImageBox widget as it is much simpler to use.
Contents
Image formats
µGFX does currently come with the following image decoders:
Format | Description |
---|---|
BMP | Including BMP1, BMP4, BMP4_RLE, BMP8, BMP8_RLE, BMP16, BMP24, BMP32 |
GIF | Including transparency and multi-frame support (animations) |
NATIVE | Uses the display drivers native format. See below. |
We plan to add decoders for PNG and JPG images in the future.
NATIVE
The native image format consists of an 8 byte header followed by an array of bytes in the format your display controller accepts. Whilst hardware dependant, this format displays extremely quickly and with the least amount of RAM usage. It is ideal for images stored in FLASH. The header is:
{ 'N', 'I', width.hi, width.lo, height.hi, height.lo, format.hi, format.lo }
Where the format word is equal to GDISP_PIXELFORMAT which is defined in the confi.h file of your GDISP driver.
BMP
The BMP format is very performance friendly as it is a bitmap of pixels. There's only little to no decoding required to display a BMP image. Therefore, it is often used for UI designs. The advantage over the Native format is it's portability.
GIF
The GIF decoder can handle animated images and transparency out of the box.
Animated images
The GIF decoder does simply advance the image pointer by one frame on each gdispImageDraw()
call. Therefore, displaying an animated image is simply a matter of calling gdispDrawImage()
in a loop. However, the user manually has to imply the delay before loading the next image. This is done like the following:
while (1) { gdispImageDraw(&myImage, 0, 0, myImage.width, myImage.height, 0, 0) delay = gdispImageNext(&myImage); gfxSleepMilliseconds(delay); }
Note: This is just an illustrative example. A real world program would have to check for error return codes etc. A full example can be found under /demos/modules/gdisp/images_animated.
RAM Usage
Image decoders use RAM to decode and display images. Whilst the image handlers have been written to use as little RAM as possible, for small microcontrollers with limited RAM the image formats used should be choosen carefully. The image handlers do not allocate RAM to store the decompressed bitmaps (unlike most other image decoders), instead decoding the image again if it needs to be displayed. The only RAM used therefore is:
Some RAM to hold information on the image itself - typically 200 to 300 bytes. This RAM is maintained while the image is opened. It may vary slightly for some images with some image formats (due to holding palettes etc). RAM allocated during the decoding process and freed once the decoding is done. The GIF image format requires around 12K of RAM to decode an image. BMP and NATIVE images do not require any extra RAM for decoding. If you decide to cache the image then RAM is required for the full decoded image. This should not be considered for low memory micros. For example, caching a 320x240 image on a 2 bytes per pixel display will take 150K of RAM (plus the normal decoding RAM). Stack space. You may need to increase your available stack space if you get exceptions when trying to decode images. Some image formats require a few hundred bytes of stack space to decode an image. Our image decoders have been written from the ground up to keep the image decoders as lean and mean as possible. Our current decoders use significantly less than other decoding libraries available.
Accounting
It is possible to examine the amount of memory that is taken by an image. Ssetting GDISP_NEED_IMAGE_ACCOUNTING
to TRUE
in the configuration file will add the two members memused and maxmemused to the image struct (the gdispImage data type).
Caching
It's possible to cache a decoded image into your ram using the gdispImageCache() call. When you don't cache an image, it will always be re-read again from flash, decoded and then displayed. When you cache your image, you just have to load it from RAM and display it. This is way faster, especially for PNG, JPG and GIF formats since these require quite complex decoding algorithms. However, caching an image requires A LOT of RAM. Especially when you're using multiframe GIF images or large sized images.
If you cache your image you still have to open() the image before it can be displayed. When close() is called, it will free all memory used by the decoder including any cached images.
Calling the caching routine doesn't guarantee that the image will be cached. For example, if not enough RAM is available the image won't be cached. Since caching is fully optional, the image will still be drawn when you call the drawing routine. It will simply be decoded again.
A word about close()
The gdispImageClose() function performs a complete cleanup. Calling this routine will not only clean up all memory used by the decoder and the chaching, it will also close the file system. Therefore, this should really just be called when you're done with the image and you won't re-draw it for a longer time period.
Examples
The following code pieces shows how to use the GDISP image decoder correctly. Please refer to the GFILE article to learn how to use the different file systems.
#include "gfx.h" /** * The image file must be stored on a GFILE file-system. * Use either GFILE_NEED_NATIVEFS or GFILE_NEED_ROMFS (or both). * * The ROMFS uses the file "romfs_files.h" to describe the set of files in the ROMFS. */ static gdispImage myImage; int main(void) { coord_t swidth, sheight; // Initialize uGFX and the underlying system gfxInit(); // Get the display dimensions swidth = gdispGetWidth(); sheight = gdispGetHeight(); // Set up IO for our image gdispImageOpenFile(&myImage, "myImage.bmp"); gdispImageDraw(&myImage, 0, 0, swidth, sheight, 0, 0); gdispImageClose(&myImage); while(1) { gfxSleepMilliseconds(1000); } return 0; }
Troubleshooting
When troubleshooting, please check the return value of each function in order to track down the problem.
No image is shown
It is possible that the program compiles fine and that it runs without any crashes, but no image is being displayed. This behavior can be caused by a variety of different issues:
- The corresponding decoder has not been enabled in the configuration file
- The image could not be opened
- The image decoder could not allocate enough memory