创建动态L8图像
本节介绍动态L8图像的使用,特别是如何创建调色板。
动态L8图像
动态L8图像的创建与任何其他动态位图一样,区别在于还必须指定要为位图其创建的调色板类型。
TouchGFX支持3种调色板:
调色板 | 说明 |
---|---|
CLUT_FORMAT_L8_ARGB8888 | 32位,红、绿、蓝色和像素阿尔法通道各8位 |
CLUT_FORMAT_L8_RGB888 | 24位,红、绿和蓝色各8位,无像素阿尔法通道 |
CLUT_FORMAT_L8_RGB565 | 16位,红、绿和蓝色分别为5位、6位和5位,无像素阿尔法通道 |
用24位调色板创建动态L8图像
下面我们用24位调色板创建一幅100x100像素L8位图:
Screen1View.cpp
BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreateL8(100, 100, Bitmap::CLUT_FORMAT_L8_RGB888, 256);
该句实现了在位图缓存中分配了100x100像素L8位图和24位调色板。 该调色板可以为动态位图提供的256种颜色,但为了减少存储空间的浪费,可以调整为需要的数量。
访问调色板
像素(前32位对齐地址)后面依次是包含L8调色板格式(以小端模式保存)的2个字节、包含调色板中条目数量的2个字节(以小端模式保存)然后是实际调色板颜色。 这意味着调色板颜色数据位于像素数据后面4个字节之后(32位对齐)。
我们可以获取指向(目前为止未初始化)调色板的指针,如下:
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 size is saved in byte 2 and 3
int palSize = (data[3] << 8) | data[2];
//Palette starts four bytes after the pixels
uint8_t* pal = (data + byteSize + 4);
动态L8位图示例
下面我们来看一个创建动态L8位图和操作调色板的完整示例。 通常不会对一般应用进行调色板操作。 该示例旨在描述如何访问和生成调色板。
首先,在TouchGFXDesigner中创建一个屏幕,在背景上插入一个白色方框,并插入一幅图像,例如在位置(x=140, y=8):
现在生成代码并打开Screen1View.cpp文件。 我们必须在setupScreen中插入代码,进行位图缓存初始化并创建动态位图。
我们先创建一幅200*256像素的位图。 记住,L8位图中的每个像素为一个字节。 我们对图像的每一行使用不同颜色。 第一行为0号色,最后一行为255号色。
然后,我们初始化调色板中的颜色。 计算出调色板的起始地址,并设置256种颜色的RGB值。 这里,我们创建的颜色从绿色渐变为红色并再次渐变回绿色。
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
const uint16_t palSize = 256;
BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreateL8(200, 256, Bitmap::CLUT_FORMAT_L8_RGB888, palSize);
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 < palSize; i++)
{
//BGR
pal[i * 3 + 0] = 0x00;
pal[i * 3 + 1] = 127 * (1 + cosf(i * 6.28f / (palSize - 1)));
pal[i * 3 + 2] = 255 * (sinf(i * 3.14f / (palSize - 1)));
}
}
}
我们得到了一个这样的屏幕:
操作调色板
由于我们可以访问动态L8位图使用的调色板,因此可以轻松地操作它。
我们将调色板颜色循环改变,每次向下循环一个颜色值,并强制每帧重新绘制图像:
Screen1View.cpp
...
void Screen1View::handleTickEvent()
{
//get palette address
uint8_t* data = Bitmap::dynamicBitmapGetAddress(imageDynamic.getBitmap());
uint32_t byteSize = 200*256;
byteSize = ((byteSize + 3) & ~3);
const int palSize = (data[3] << 8) | data[2];
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 = 3; i < palSize * 3; i++)
{
pal[i - 3] = pal[i];
}
//Insert color 0 as color 255
pal[(palSize - 1) * 3 + 0] = blue;
pal[(palSize - 1) * 3 + 1] = green;
pal[(palSize - 1) * 3 + 2] = red;
//Force redraw by invalidating
imageDynamic.invalidate();
}
这会造成动态向上移动动态位图中的颜色: