Embedded Artists


We are the leading providers of products and services around prototyping, evaluation and OEM platforms using NXP's ARM-based microcontrollers.

LPC4088DM Using Images

The DMBasicGUI library comes with, among other things, a image decoding.

Images are decoded using the Image class:

Import library

Static Public Member Functions

static int decode (const unsigned char *pDataIn, unsigned int sizeIn, Resolution res, ImageData_t *pDataOut)
Decodes the specified image data.
static int decode (const char *filename, Resolution res, ImageData_t *pDataOut, Mutex *pLock=NULL)
Reads the specified file and decodes the image data.
static int decode ( Resource *res, Resolution resolution, ImageData_t *pDataOut, Mutex *pLock=NULL)
Decodes the specified image resource.

Image Formats

Currently three image formats are supported at runtime:

  • Portable Network Graphics (*.png)
  • Bitmaps (*.bmp)
  • Raw images (*.raw)

PNG and BMP are both standard formats, but the RAW image is a special format that is used in this library. The RAW images contain a 10-byte header (including the width and height of the image) and the uncompressed data.

it takes no time to decode a RAW image, but it will take up more space than e.g. a PNG image. The RAW image always uses (width*height*2 + 10) bytes to store the image, regardless of what is in the image.

To convert a image from any format into *.raw use the imgConverter.py script. As the conversion into the raw format is done on a PC the input format is limited only by the python image library which supports many more formats and not just PNG and BMP.

There is a section about image files on the Performance wiki page.

Images on the File System

If the image is stored on the file system:

#include "Image.h"
...
// decode an image from a file
Image::ImageData_t img;
if (Image::decode("/ram/image.png", &img) == 0) {
    // draw on display using img.pixels, img.width and img.height
    ...
    free(img.pointerToFree);
}


Images in Flash

Images can also be compiled into the program so that it doesn't require a uSD card or a USB Memory Stick. The img2c.py script can be used to prepare the images.

The output of the script looks something like this:

image_data.h

#include "basic_image_data.h"

extern const unsigned char img_empty[];
extern const unsigned int img_size_empty;


image_data.cpp

#define IMAGE_LOCATION
//#define IMAGE_LOCATION  __attribute__((section("SPIFI_MEM"))) 

const unsigned char img_empty[] = {
	0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52, 
	0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x08,0x02,0x00,0x00,0x00,0x25,0x0B,0xE6, 
	0x89,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC4,0x00,0x00,0x0E, 
	0xC4,0x01,0x95,0x2B,0x0E,0x1B,0x00,0x00,0x02,0x8B,0x49,0x44,0x41,0x54,0x78,0x9C, 
        ...
	0x49,0x9C,0xF0,0xEB,0x0F,0xB7,0x97,0x16,0xD2,0x38,0x59,0xDC,0x57,0x00,0x00,0x00, 
	0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
};
const unsigned int img_size_empty = sizeof(img_empty);


To load such an image in your program:

#include "Image.h"
#include "image_data.h"
...
// decode an image from a file
Image::ImageData_t img;
if (Image::decode(img_empty, img_size_empty, &img) == 0) {
    // draw on display using img.pixels, img.width and img.height
    ...
    free(img.pointerToFree);
}


Note

The IMAGE_LOCATION define can be used to move the image data into the external QSPI flash to save space in the internal flash for code.

Showing the Image

Displaying the decoded image can be as simple as drawing directly on the framebuffer (assuming the image is the same size as the display):

#include "mbed.h"
#include "DMBoard.h"
#include "Image.h"

void main() {
  // initialize DMBoard
  ...
  // create the frame buffer
  void* fb = disp->allocateFramebuffer();
  
  // decode the image
  Image::ImageData_t img;
  if (Image::decode("/ram/image.png", &img) == 0) {
    // draw on display using img.pixels, img.width and img.height
    memcpy(fb, img.pixels, img.width * img.height * 2);

    // now that the image has been copied, the raw data can be freed
    free(img.pointerToFree);

    // Start display in default mode (16-bit)
    Display::DisplayError disperr = disp->powerUp(fb);
    if (disperr != Display::DisplayError_Ok) {
      // Failed to initialize the display
    }
  }
 ...
}


The SWIM library contains functions to help when drawing images. There are functions to rotate, scale and invert images.

Resources

It is shown above how to store images in both arrays and as files and how to decode them. Apps that use images must have functions to handle both ways or possibly have the image locations hardcoded.

The Resource class will help with this. It encapsulates the image location information allowing the App to only deal with the resource for an image instead of knowing where it is stored.

Import library

Public Member Functions

Resource (const char *filename, int width, int height)
Create a new file resource.
Resource (const unsigned char *data, const unsigned int dataSize, int width, int height)
Create a new resource from a data array.
int width ()
Returns the width of the resource.
int height ()
Returns the height of the resource.

Friends

class Image

Using the Resource class to decode an image:

#include "Resource.h"
#include "Image.h"

const unsigned char img_ok[] = { ... };
const unsigned int img_size_ok = sizeof(img_ok);

void foo() {
  Resource rOk(img_ok, img_size_ok, 40, 40);
  Resource rCancel("/qspi/cancel.png", 40, 40);

  Image::ImageData_t imgOk;
  Image::ImageData_t imgCancel;

  if (Image::decode(rOk, Image::RES_16BIT, &imgOk) != 0) {
    // failed to load image
  }
  if (Image::decode(rCancel, Image::RES_16BIT, &imgCancel) != 0) {
    // failed to load image
  }

  // use and then free the images
}


The Apps in the DMBasicGUI library don't have any hard links to the images for the ok, cancel and repeat buttons. They use the resource class instead. The classes will have something like this:

AppColorPicker.h

    enum Resources {
        Resource_Ok_button,
    };

    /** Specifies the resource to use
     *
     *  Adds a resource for a specific id. This allows the
     *  user program to select e.g. which image to use and
     *  if it should be loaded from a file or an array.
     *
     *  @param id  the identifier
     *  @param res the resource
     */
    void addResource(Resources id, Resource* res);


When using the AppColorPicker class the resources it needs (as specified by the enum above) must be supplied before calling the setup() function:

#include "Resource.h"
#include "AppColorPicker.h"

Resource rOk480("/qspi/cancel480.png", 40, 40);
Resource rOk800("/qspi/cancel800.png", 64, 64);

void foo() {
  ...
  AppColorPicker a;
  
  if (DMBoard::instance().display()->width() == 480) {
    a.addResource(AppColorPicker::Resource_Ok_button, &rOk480);
  } else {
    a.addResource(AppColorPicker::Resource_Ok_button, &rOk800);
  }

  a.setup();
  a.runToCompletion();
  a.teardown();
}


The example above also shows different images being passed to the AppColorPicker based on the display resolution.

Performance

The performance of the MCI, USB Host MassStorage and QSPI file systems has been measured as well as the performance of decoding images stored on each of them. The result is available on thePerformance wiki page.


All wikipages