Difference between revisions of "Images"

From uGFX Wiki
Jump to: navigation, search
(Color Palettes)
(Image formats)
Line 26: Line 26:
 
  |-
 
  |-
 
  |}
 
  |}
We plan to add decoders for PNG and JPG images in the future.
+
We plan to add decoders for other formats such as JPG in the future.
  
 
=== NATIVE ===
 
=== NATIVE ===

Revision as of 18:25, 11 November 2016

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.

API reference

The API reference for the image support can be found here.

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)
PNG Including transparency and alpha support
NATIVE Uses the display drivers native format. See below.

We plan to add decoders for other formats such as JPG 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 conf.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 simply advances 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 impliment the delay before loading the next image. This can be done like this:

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.

PNG

The PNG image decoder can handle all PNG features including transparency except for interlacing.

Color Palettes

Certain image formats support color palettes. The following functions are available to access and modify the color palettes:

uint16_t   gdispImageGetPaletteSize(gdispImage *img);
color_t    gdispImageGetPalette(gdispImage *img, uint16_t index);
bool_t     gdispImageAdjustPalette(gdispImage *img, uint16_t index, color_t newColor);

Please check the API reference to learn more about these functions.

RAM Usage

Image decoders use RAM to decode and display images. Whilst the image handlers have been written from scratch 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 full decompressed bitmap as do most other image decoders, instead the image is decoded 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 exact amount of memory that is used by an image. Setting 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). The first one gives information about the currently used memory, the second one keeps track of the maximum amount of memory that was ever used by this image.

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
  • When loading an image from a file, it's possible that the maximum number of file handles has been reached and opening the file fails. In that case, increase GFILE_MAX_GFILES in the configuration file or close an already opened file that is no longer needed.