Skip to main content

Creating Dynamic L8 Images

This section explains the use of dynamic L8 images and especially how to create the palette.

Read in general about Dynamic Bitmaps here and about the L8 image format here.

Dynamic L8 Images

Dynamic L8 bitmaps are created like any other dynamic bitmap, except that we also have to specify the type of palette to create for the bitmap.

TouchGFX supports 3 types of palettes:

PaletteDescription
CLUT_FORMAT_L8_ARGB888832-bit, 8 bits for each of red, green, blue and per pixel alpha channel
CLUT_FORMAT_L8_RGB88824-bit, 8 bits for each of red, green and blue, no per pixel alpha channel
CLUT_FORMAT_L8_RGB56516-bit, 5 bits for red, 6 bits for green, 5 bits for blue, no per pixel alpha channel

Creating a Dynamic L8 image with 24-bit palette

Here we create a 100x100 pixels L8 bitmap with a 24-bit palette:

Screen1View.cpp
BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreate(100, 100, Bitmap::L8, Bitmap::CLUT_FORMAT_L8_RGB888);

This call allocated a 100x100 L8 bitmap and a 24-bit palette in the bitmap cache. The palette always holds 256 colors for dynamic bitmaps.

Accessing the palette

The palette is located 4 bytes after the pixels (aligned on 32-bit). The bytes contains information about the palette type and length of the palette.

We can get a pointer to the (so far uninitialized) palette like this:

Screen1View.cpp
//Get a pointer to the bitmap data (pixels and palette)
uint8_t* data = Bitmap::dynamicBitmapGetAddress(dynamicBitmap1);

//1 byte pr pixel, round up to 32-bit
uint32_t byteSize = 100*100;
byteSize = ((byteSize + 3) & ~3);

//Palette starts four bytes after the pixels
uint8_t* pal = (data + byteSize + 4);

Dynamic L8 Bitmap Example

We will now go through an example of creating a dynamic L8 bitmap and manipulating the palette. Manipulating the palette if not a typical thing to do for a general application. The example serves the purpose of illustrating how to access and generate a palette.

First we create a Screen in TouchGFXDesigner and insert a white Box in the background and an Image at e.g. x=140, y=8:

Creating a Screen

Now generate the code and open the Screen1View.cpp file. We must insert code in setupScreen to initialize the bitmap cache and create a dynamic bitmap.

We create a bitmap of 200*256 pixels. Remember each pixel in an L8 bitmap is one byte. We color each row of the image with a different color. First row has color 0, last row has color 255.

Then we initialize the colors in the palette. We calculate the start address of the palette and set the RGB values of the 256 colors. Here we create colors that go from green to red and back to green again.

Screen1View.cpp
#ifdef SIMULATOR
uint32_t cacheBuffer[320*1024/4]; //simulate PSRAM
uint16_t* psram = (uint16_t*)cacheBuffer;
#else
uint16_t* psram = (uint16_t*)(0xd0000000 + 480*272*2*2); //Address after two 16bit framebuffers
#endif

Screen1View::Screen1View()
{

}

void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();

//Create one dynamic bitmap
Bitmap::setCache(psram, 320*1024, 1); //320Kb cache
BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreate(200, 256, Bitmap::L8, Bitmap::CLUT_FORMAT_L8_RGB888);
imageDynamic.setBitmap(Bitmap(dynamicBitmap1));

if (dynamicBitmap1 == BITMAP_INVALID)
{
touchgfx_printf("Unable to create dynamic bitmap\n");
}
else
{
uint8_t* data = Bitmap::dynamicBitmapGetAddress(dynamicBitmap1);

uint8_t* pixel = data;
//make colored rows
for (int y = 0; y<256; y++)
{
for (int x = 0; x<200; x++)
{
*pixel++ = y;
}
}

uint32_t byteSize = 200*256;
byteSize = ((byteSize + 3) & ~3);

//Palette starts four bytes after the pixels
uint8_t* pal = (data + byteSize + 4);

//Make palette with 256 colors from green to red to green
for (int i = 0; i<256; i++)
{
//BGR
pal[i*3 + 0] = 0x00;
pal[i*3 + 1] = 127*(1+cosf(i*6.28f/255));
pal[i*3 + 2] = 255*(sinf(i*3.14f/255));
}
}
}

This gives us a Screen that looks like this:

Showing L8 image

Manipulating the Palette

Since we have access to the palette used for the dynamic L8 bitmap, we can easily manipulate it.

Here we cycle the colors one index down and force a redraw of the image in every frame:

Screen1View.cpp
...
void Screen1View::handleTickEvent()
{
//get palette address
uint8_t* data = Bitmap::dynamicBitmapGetAddress(imageDynamic.getBitmap());
uint32_t byteSize = 200*256;
byteSize = ((byteSize + 3) & ~3);
uint8_t* pal = (data + byteSize + 4);

//Cycle palette, copy color 0
int8_t blue = pal[0], green = pal[1], red = pal[2];

//Move palette down, 1->0, 2->1, ...
for (int i = 0; i<255*3; i+=3)
{
pal[i] = pal[i+3];
pal[i+1] = pal[i+4];
pal[i+2] = pal[i+5];
}

//Insert color 0 as color 255
pal[255*3+0] = blue;
pal[255*3+1] = green;
pal[255*3+2] = red;

//Force redraw by invalidating
imageDynamic.invalidate();
}

This will move colors in the dynamic bitmap "upwards":

Cycling the L8 palette