跳轉到主要內容

創建動態L8圖像

本節介紹動態L8圖像的使用,特別是如何創建調色板。

閱讀此處的動態點陣圖L8圖像格式

動態L8圖像

動態L8圖像的創建與任何其他動態點陣圖一樣,區別在於還必須指定要為點陣圖創建的調色板類型。

TouchGFX支持3種調色板:

調色板說明
CLUT_FORMAT_L8_ARGB888832位元,紅、綠、藍色和像素阿爾法通道各8位
CLUT_FORMAT_L8_RGB88824位,紅、綠和藍色各8位元,像素阿爾法通道0位
CLUT_FORMAT_L8_RGB56516位,紅、綠和藍色分別為5位、6位元和5位元,像素阿爾法通道0位

用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個位元組(以 little endian 保存)和實際調色板顏色。 這意味著調色板顏色位於像素後面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點陣圖和操作調色板的完整範例。 通常不會對一般應用進行調色板操作。 該範例的目的為描述如何存取和生成調色板。

首先,在TouchGFX Designer中創建一個螢幕,在背景上插入一個白色方框,並插入一幅圖像,例如在位置(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圖像

操作調色板

由於我們可以存取動態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();
}

這將移動動態點陣圖“upwards”中的顏色:

L8調色板迴圈