跳轉到主要內容

動態點陣圖

本節介紹如何使用動態點陣圖。注意,標準點陣圖會被編譯到應用中,因此必須在編譯時提供。點陣圖從PNG等格式的檔案轉換而來,與大小和格式資訊一起以內部格式保存。

此外,還可以在執行時間在RAM中創建點陣圖。這被稱為動態點陣圖。動態點陣圖的使用與編譯到應用中的靜態點陣圖相同。這意味著您可以通過圖像和按鈕等小部件使用動態點陣圖。

動態點陣圖配置​

在創建動態點陣圖時,從點陣圖快取分配像素存儲空間。因此,您必須先配置點陣圖快取,然後才能創建動態點陣圖。 This is a manual process that cannot be done in TouchGFX Designer or the Generator.

參見關於點陣圖快取的文章獲取配置說明。

必須定義應用中使用的動態點陣圖的最大數量。該最大值與點陣圖快取位址和大小一起傳遞到TouchGFX。這裡我們配置的是具有最多4張動態點陣圖的點陣圖快取。您可以在應用中的任何檔中執行。如需只執行一次,檔FrontendApplication.cpp是個不錯的選擇:

FrontendApplication.cpp (extract)
#include <gui/common/FrontendApplication.hpp>
#include <touchgfx/Bitmap.hpp>

FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
// Place cache start address in SDRAM at address 0xC0008000;
uint16_t* const cacheStartAddr = (uint16_t*)0xC0008000;
const uint32_t cacheSize = 0x300000; //3 MB, as example
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
}

如果您使用Windows模擬器,則還必須在此創建點陣圖快取。在Windows上,可以容易地宣告大陣列或使用malloc:

FrontendApplication.cpp (extract)
#include <gui/common/FrontendApplication.hpp>
#include <touchgfx/Bitmap.hpp>

FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
#ifdef SIMULATOR
const uint32_t cacheSize = 0x300000; //3 MB, as example
uint16_t* const cacheStartAddr = (uint16_t*)malloc(cacheSize);
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#else
// Place cache start address in SDRAM at address 0xC0008000;
uint16_t* const cacheStartAddr = (uint16_t*)0xC0008000;
const uint32_t cacheSize = 0x300000; //3 MB, as example
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#endif
}

使用動態點陣圖範例​

為了使用動態點陣圖,我們需要一個小部件來顯示它。 So insert an Image widget in the view (in code or in TouchGFX Designer):

#include <touchgfx/widgets/Image.hpp>
using namespace touchgfx;
class TemplateView : public View
{
private:
Image image;
}

此小部件和動態點陣圖的使用過程分為三步:

  1. Create the Dynamic Bitmap in the bitmap cache
  2. Initialize the memory used by the dynamic bitmap
  3. 將點陣圖分配給小部件
Pixel data is uninitialized by default

The pixel memory returned by dynamicBitmapCreate() (and dynamicBitmapCreateL8() / dynamicBitmapCreateCustom()) is not cleared or initialized in any way. It simply points into the bitmap cache and contains whatever was there before, e.g. leftover data from a previously deleted bitmap, or random contents on system startup.

This is one of the most common mistakes when working with dynamic bitmaps: forgetting to initialize the memory results in a bitmap with garbage pixel data being shown on the display, or even data leaking between what looks like unrelated bitmaps.

Always initialize every pixel before the bitmap is used, either by calling Bitmap::dynamicBitmapClear() right after creating the bitmap, or by immediately writing your own image/pixel data into it (e.g. loading an image from a file, see Loading Images At Runtime).

在setupScreen中創建動態點陣圖。這裡我們使用16bpp格式RGB565。如果影像緩衝為24位,則使用RGB888。如需創建透明點陣圖,使用格式ARGB8888。

The address of the pixels in the dynamic bitmap is returned by the dynamicBitmapGetAddress function, but since dynamicBitmapClear() already knows the size and layout of the bitmap, you no longer need to compute the pixel buffer size yourself (which is error prone, since it depends on both format and bitmap dimensions):

#include <touchgfx/Bitmap.hpp>
void TemplateView::setupScreen()
{
BitmapId bmpId;

//Create (16bit) dynamic bitmap of size 100x150
bmpId = Bitmap::dynamicBitmapCreate(100, 150, Bitmap::RGB565);

//Clear all pixels; the memory returned above is *not* initialized
if (bmpId != BITMAP_INVALID)
{
Bitmap::dynamicBitmapClear(bmpId);
}

//Make Image widget show the dynamic bitmap
image.setBitmap(Bitmap(bmpId));

//Position image and add to View
image.setXY(20, 20);
add(image);
...
}

As explained above, the pixel memory you get from the bitmap cache is not cleared automatically, so you must clear or overwrite it yourself before the bitmap is displayed. Bitmap::dynamicBitmapClear() is the recommended way to do this, it zeroes every pixel (and any CLUT/format specific data) of the dynamic bitmap in one call, without you having to know its size or format.

If you want to load your image from a file instead, you can skip the call to dynamicBitmapClear() and replace it with your loader code, since the loader will overwrite every pixel anyway. See the article Loading Images At Runtime.

動態點陣圖操作​

動態點陣圖操作全部位於Bitmap類中。

創建動態點陣圖​

以下方法用指定的寬度、高度和點陣圖格式創建動態點陣圖。僅當有足夠大的未使用存儲空間時,才能創建點陣圖。如果未創建點陣圖,該方法返回BITMAP_INVALID。

static BitmapId Bitmap::dynamicBitmapCreate(const uint16_t width, const uint16_t height, BitmapFormat format, ClutFormat clutFormat)
Remember to initialize the pixel data

This method (and dynamicBitmapCreateL8() / dynamicBitmapCreateCustom()) does not clear or initialize the pixel data of the new bitmap. The memory simply contains whatever was there before. Call Bitmap::dynamicBitmapClear() right after creating the bitmap, or overwrite every pixel yourself, before using or displaying it.

Clearing a Dynamic Bitmap​

Since the pixel data of a newly created dynamic bitmap is uninitialized (see above), it must be cleared or overwritten before use. The following method zeroes all pixel data of a dynamic bitmap:

static void Bitmap::dynamicBitmapClear(BitmapId id)

dynamicBitmapClear() clears the entire bitmap, including any format specific data such as the CLUT (Color LookUp Table) header of an L8 bitmap, and it resets the solid area (see below) back to the same default as when the bitmap was created. Since the method already knows the size and format of the bitmap, you do not need to compute the number of bytes to clear yourself, unlike a manual memset() call on the address returned by dynamicBitmapGetAddress().

If you intend to immediately fill the bitmap with your own pixel data, e.g. by loading an image from a file or drawing into it, you can skip calling dynamicBitmapClear() as long as you are certain that every pixel will be overwritten.

刪除動態點陣圖​

此方法刪除動態點陣圖。

static bool Bitmap::dynamicBitmapDelete(BitmapId id)

獲取動態點陣圖中像素的位址​

以下方法返回動態點陣圖的位址。檔案載入器使用此方法將圖像資料複製到點陣圖中。

static uint8_t* dynamicBitmapGetAddress(BitmapId id)

設置動態點陣圖的實心區域​

以下方法設置動態點陣圖的實心矩形。

static bool dynamicBitmapSetSolidRect(BitmapId id, const Rect& solidRect)

請閱讀Custom Widget一節中關於“實心區域”概念的更多內容。

對於像RGB565和RGB888這樣的非透明格式,將實心區域預設設置為整個點陣圖。對於像ARGB8888這樣的透明格式,將實心區域設置為空。

Creating a Dynamic Bitmap from memory​

It is also possible to create a dynamic bitmap directly from pixel data in flash memory without caching pixel data in RAM. Compared to regular Dynamic Bitmap, cache size does not need to take into account the pixel data:

Note that the pixel address must be 4-byte aligned.

static BitmapId Bitmap::dynamicBitmapCreateExternal(const uint16_t width, const uint16_t height, const void* pixels, BitmapFormat format, uint8_t customSubformat = 0);

豎屏模式的動態點陣圖​

TouchGFX能以豎屏模式運行。這適用於顯示器自其原始方向旋轉90度後安裝的情況。在該模式下使用動態點陣圖時,需要格外小心。

下面是STM32F746的專案範例。它的顯示器寬度為480像素,高度為272像素。影像緩衝具有相同大小。

豎屏專案

沒有為image1圖像小部件分配點陣圖。我們將使用它顯示動態點陣圖。

在使用豎屏模式時,坐標系統沿逆時針方向旋轉90度。 (0, 0) 座標位於“D”附近的左上角。影像緩衝的第一個位元組(將螢幕上第一個像素著色),位於右上角。

因此,當以豎屏模式運行時,不旋轉影像緩衝。對於動態點陣圖也是如此。但是我們希望在顯示器(安裝時)第一行顯示的像素必須繪製在影像緩衝區的左邊緣。

In the function below, we create a dynamic bitmap and make the upper row green, and the right edge red. Since we want a solid white base color rather than just zeroed/black memory, we use memset() directly here instead of Bitmap::dynamicBitmapClear() (which is only useful when zeroed/transparent memory is acceptable, e.g. as a starting point before drawing your own pattern):

Screen1View.cpp (extract)
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
BitmapId bmpId;
bmpId = Bitmap::dynamicBitmapCreate(100, 100, Bitmap::RGB565);

if (bmpId != BITMAP_INVALID)
{
//set all pixels white
uint16_t* const bitmapPixels = (uint16_t*)Bitmap::dynamicBitmapGetAddress(bmpId);
memset(bitmapPixels, 0xFF, 100*100*2);

//first 200 pixels red, => two column on the right on display
for (int i = 0; i<200; i++) bitmapPixels[i] = 0xF800;

//first two pixels in all rows green in bitmap => top two rows on display
for (int i = 0; i<100; i++)
{
bitmapPixels[i*100] = 0x07E0;
bitmapPixels[i*100 + 1] = 0x07E0;
}
}

image1.setBitmap(bmpId);
}

顯示器顯示動態點陣圖:

豎屏專案影像緩衝內容