跳轉到主要內容

SVG

從4.21版本開始,TouchGFX支援使用SVG圖像。 SVG圖像可搭配使用向量圖形及傳統的點陣圖,用於建立使用者介面。

SVG圖像可透過SVGImage小工具納入使用者介面中。 這款小工具於TouchGFX Designer之中提供使用,並可作為任何其他小工具新增至使用者介面。

SVG圖像僅於16bpp、24bpp或32bpp影像緩衝區獲得支援。

什麼是SVG

SVG是可縮放向量圖形的縮寫,是一種以XML為基礎的檔案格式,可使用一組少量的圖形基本元素定義2D圖像。 其中部分的基本元素為矩形、圓形及曲線。 基本元素之中可填充色彩或漸層, 外框(筆觸)也可依據特定寬度繪製。

SVG圖形的第一項重大功能就是可以縮放。 這代表指定的繪圖不僅可於單一解析度使用,也可放大或縮小而不會喪失品質。 相較於點陣圖,這是一大優勢;點陣圖放大時會產生假影,縮小時則會喪失細節。

SVG圖形的第二項重要功能,就是這類圖形是以向量為基礎。 這代表圖像是由線條和圓形等幾何圖形組成,互相結合以完成繪製。 相較之下,點陣圖圖像基本上只是對圖像的所有像素定義色彩值。 向量定義的優勢在於大多數圖像與點陣圖相比都非常小,而且更加彈性靈活。 例如顯示黃色橢圓形的圖像,可輕易變更為由綠色橢圓形組成的圖像。

TouchGFX支援SVG Tiny 1.2子集。 由於硬體和執行階段環境的種種限制,以及TouchGFX的效能特性,因此不可能支援完整規格。

SVG圖像可利用多種成像工具建立,或是透過手寫方式建立。 如果您想瞭解如何編寫自己的SVG,建議您在此參閱簡介。

以TouchGFX使用SVG

SVG圖像的使用方式與PNG圖像相同。 您在專案中如果需要使用SVG檔案,必須將其放置於assets/images資料夾。 TouchGFX Image Converter及TouchGFX Designer可讀取該資料夾中的圖像。

SVG圖像會轉換為CPP程式碼,並連結至應用程式。 前述CPP程式碼儲存於以下檔案:generated/images/src/SVGDatabase.cpp

SVG圖像是以SVGImage小工具使用, 可在程式碼或TouchGFX Designer中使用, 這款小工具可縮放、平移及旋轉SVG圖像。

SVGImage小工具使用另一個名為VectorRenderer的元件執行渲染。

使用SVG圖像時的軟體元件

範例

我們將使用此SVG作為範例:

<?xml version="1.0" encoding="iso-8859-1"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="green" />
<polygon points="50,10 78,78 22,78" fill="gold" />
</svg>

SVG包含一個半徑40的深綠色圓形,以及一個黃色(金色)三角形。

這邊可以發現SVG圖像為簡易的文字檔案,可利用一般的文字編輯器加以修改。 SVG檔案可利用各式各樣的標準工具開啟。 Chrome瀏覽器就是SVG檢視器的範例之一。

此SVG的渲染如下:

箭頭SVG

如要以TouchGFX使用此SVG,我們將檔案(arrow.svg)放置於專案的assets/images目錄中。 這與PNG檔案及TouchGFX Designer所使用圖像的目錄相同:

SVG檔案放置於assets/images資料夾

我們可以在TouchGFX Designer中插入SVGImage小工具:

插入SVGImage小工具

如果使用右側的SVGImage屬性,我們可以變更小工具的大小和縮放比例:

顯示SVG箭頭

請注意「Fit Image To Size」(調整圖像配合大小)核取方塊。 如果加以勾選,就會縮放SVG以配合小工具的大小(且會重設旋轉)。 這是一種Helper函數,可讓您拖動小工具角落以調整SVG大小,直到大小符合需求為止。

顯示SVG箭頭三次

如果要進行以上所示的旋轉,設定旋轉中心相當重要。 預設值為x=0、y=0,也就是小工具的左上角。 如果我們使用這個旋轉中心旋轉SVG,就會順時針旋轉到SVGImage小工具的左側,如下圖所示:

顯示環繞0,0旋轉45度的SVG箭頭

如上圖所示,超出SVGImage的SVG部分將會遭到裁剪(未顯示)。 灰色矩形的部分代表SVGImage。 任何部分只要超出灰色區域就不會繪製。 如果要在SVGImage內部旋轉SVG,我們必須將旋轉中心設定為小工具中心(50, 50)。

請另行參閱後續章節有關轉換的詳細資料。

目標設定

如要在目標使用SVG圖像,您需要在CubeMX啟用向量渲染。 這會在專案中插入所需的程式碼,以建立SVGImage所需的向量渲染器。

Note
向量渲染會在TouchGFX Designer中所有可用的TouchGFX開發板規格中啟用(除了STM32G0及類似的小平台)。

如果未啟用向量渲染,則建構專案時就會出現連結器錯誤(undefined reference to `touchgfx::VectorRenderer::getInstance()):

未啟用向量渲染時的連結器錯誤

變更CubeMX中的設定可解決此項問題。 請另行參閱Generator使用者指南

SVG圖像會自動以C++程式碼的形式納入目標專案中,所以不需要採取進一步動作。

由於SVG圖像的渲染時間可能遠高於點陣圖,我們建議使用雙緩衝區(或單緩衝區搭配嵌入式GRAM顯示)。 雖然可使用單一影像緩衝區,但應監控渲染時間及顯示撕裂問題。 請在此深入瞭解使用單一影像緩衝區。

Canvas緩衝區

在大部分平台上(除了U5X9),SVG是以Canvas小工具渲染器進行渲染。 這項軟體元件會在渲染期間使用緩衝區。 此緩衝區的大小會影響效能。 如果可能的話,建議增加緩衝區大小(通常20-30Kb為適當)。 緩衝區可在TouchGFX Designer之中輕易變更:

變更Canvas緩衝區大小

請記得在所有相關螢幕中變更值。

目標效能及Flash使用

為箭頭產生的SVG資料大小低於350位元組。 相較於點陣圖,這正是使用SVG的效益之一。 如果是100x100大小的點陣圖箭頭,在24位元色彩情況下可能達到30,000位元組。 SVG大小接近點陣圖大小的1%。

圖像類型Flash使用
點陣圖30,000位元組
SVG350位元組

使用SVG圖像時,會在應用程式中增加5-10K的額外程式碼。

至於使用SVG的缺點,就是在大部分情況下,繪製SVG圖像的效能低於點陣圖。 SVG渲染取決於SVG的元素數量,而且沒有上限。 點陣圖渲染取決於解析度及Alpha混合,而且具有上限。
第二,SVG圖像渲染時會高度使用軟體渲染,因此會讓CPU負載偏高。 另一方面,點陣圖完全是由DMA2D加速器進行渲染,CPU負載低。

SVG箭頭在STM32F746(影像緩衝區位於外部RAM)的渲染時間為1.32ms,算是非常可以使用的程度。 H7系列的MCU速度更快,可縮短渲染時間。 SVG放大時渲染時間會增加(需要渲染更多像素),旋轉時則不會增加太多時間。 下圖顯示在STM32F746探索套件的箭頭:

在F746探索套件顯示SVG箭頭

最左側的圖片並未顯示SVG,只有綠色的Box背景。 中間圖片顯示縮放比例1的箭頭。 最右側圖片顯示縮放比例2的箭頭。 以下列出完整畫面及僅含SVG的渲染時間:

螢幕渲染時間僅含SVG
2.96 ms不適用
4.28 ms1.32 ms
6.37 ms3.41 ms
旋轉6.53 ms3.57 ms

最後一列顯示箭頭旋轉77度情況下的渲染時間。 我們可以發現旋轉對渲染時間的影響非常小。

圖形品質

下圖顯示在STM32F746探索套件執行的專案:

顯示在F746探索套件上的SVG箭頭

在此專案中,我們在多個SVGImage小工具中使用相同的SVG。

我們在適當大小的相片中,由影像緩衝區插入縮放細節(三個箭頭)。 其中顯示SVG繪圖的線條全部都消除鋸齒,即使在旋轉及縮放時也是如此。 這正是使用SVG圖像的主要原因:可在旋轉及縮放時保持品質。

支援的SVG元素

TouchGFX並未實作完整的SVG Tiny 1.2標準。 TouchGFX之中讀取.svg檔案的圖像轉換器,會在您使用任何未支援元素或屬性時提出警告。 其中未納入支援的重要部分包括放射漸層、文字及動畫。

TouchGFX支援下列SVG元素。 以下範例顯示支援的元素屬性:

  • 矩形<rect x="10" y="20" width="100" height="200" rx="5" ry="40" />

  • 圓形<circle cx="100" cy="200" r="20" />

  • 橢圓形<ellipse cx="100" cy="200" rx="20" ry="30" />

  • 線條<line x1="10" y1="10" x2="300" y2="150 />

  • 路徑<path d="M100 100L75 200h50z" />

  • 多邊形<polygon points="10,10 30,30 10,90" />

  • 聚合線條<polyline points="10,10 30,30 10,90" />

  • 線性漸層<lineargradient id="grad1" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="100%" />

此外也支援以下結構元素

  • 群組<g />
  • Defs <defs />

TouchGFX支援所有的形狀轉換:矩陣、平移、縮放、旋轉、skewX、skewY。

線性漸層必須在<defs>元素內部定義。

對於<path>元素,TouchGFX支援所有的路徑指令:M、m、L、l、H、h、V、v、C、c、S、s、Q、q、T、t、A、a。

其中也支援填充和筆觸。

不支援的SVG元素

TouchGFX不支援以下元素:

  • 動畫<animate><animateColor><animateMotion><animateTransform><discard><handler><listener><mpath><script><set><switch>
  • 音訊<audio />
  • ClipPath <clipPath id=.... />
  • Desc <desc />
  • 濾鏡<filter>
  • 外部物件<foreignObject>
  • 漸層轉換<linearGradient gradientTransform="..." />, <prefetch>
  • 放射漸層<radialGradient ... />
  • 純色<solidColor>
  • 筆觸dasharray屬性<path stroke-dasharray="10,10" ... />
  • 文字與字型<font><glyph><text><hkern><missing-glyph><tbreak><textArea><tspan>
  • 使用<use>
  • 圖像<image>
  • 影片<video>

在此省略中繼資料及標題元素。

ViewBox

ViewBox屬性常用於SVG圖像,在TouchGFX之中並未支援。 ViewBox屬性用於定義SVG繪製(使用者空間)中使用的座標系統轉換,將其轉換至繪製SVG的視窗區。

範例如下:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
...
</svg>

這代表SVG在(0,0)至(200,200)矩形範圍內繪製的任何圖形,都應該延伸(或縮小)以配合視窗(SVGImage小工具)。

TouchGFX會忽略viewBox屬性, 代表圖形不會縮放。 對許多SVG圖像而言,這並不會造成問題,因為圖形是以正確比例繪製。 如果是這樣的話,您就不必理會viewBox屬性或將其刪除。
此外圖形也不會依據viewBox剪裁,而是依據SVGImage小工具剪裁。

如果真的需要使用viewBox縮放特定繪圖,您可利用插入轉換的方式在SVG檔案套用縮放,例如在額外的<g>元素上進行,或是在TouchGFX中縮放繪圖。

以下範例是將從(0,0)到(1000,1000)的線條,利用viewBox(不會作用)縮小為(0,0)至(100,100):

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1000 1000">
<path d="M10 10L990,990" stroke="blue" stroke-width="10" stroke-linecap="round"/>
</svg>

原本預定產生的結果是從(0,0)到(200,200)的線條, 但由於TouchGFX忽略ViewBox,因此會產生1000x1000像素的SVG圖像。 其中一種轉換方式就是修改SVG檔案,以便在其中納入縮放轉換:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<g transform="scale(0.2)">
<path d="M10 10L990,990" stroke="blue" stroke-width="10" stroke-linecap="round"/>
</g>
</svg>

這項轉換可縮放一切,縮放比例可達5倍。

在SVGImage小工具套用縮放也能獲得此項效果:

在TouchGFX Designer之中縮小SVG

如果您一定要在自己的應用程式中縮放,那麼最好不要修改.svg檔案。

線性漸層必須使用ObjectBoundingBox

SVG之中的線性漸層可使用兩種不同座標系統指定。 「userSpaceOnUse」或「objectBoundingBox」。 TouchGFX僅支援「objectBoundingBox」。 我們在此將簡單介紹「objectBoundingBox」,以便讓您將任何使用「userSpaceOnUse」的SVG變更為使用「objectBoundingBox」。 我們從以下範例開始說明:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="blue" />
<stop offset="50%" stop-color="green" />
<stop offset="100%" stop-color="red" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#gradient1)" />
<rect x="130" y="10" width="40" height="80" fill="url(#gradient1)" />
</svg>

以上範例定義的漸層,是從一開始的藍色轉移到中間的綠色,然後再到最後的紅色。 使用漸層是為了填充圓形及矩形:

線性漸層:左上角的藍色及右下角的紅色

漸層的起始點指定為(x1, y1) = (0%, 0%)。 這代表任何形狀(例如圓形或矩形)週框方塊的左上角,利用此項漸層進行繪製。 同樣地終點為週框方塊的右下角。

由於圓形和矩形這兩種形狀的寬度不同(80像素及40像素),漸層在套用至形狀時的角度也不同。 如果您不想要這項行為,可以定義多個漸層, 讓每張圖都有一種漸層。

另外一種在SVG的可能作法,就是使用「userSpaceOnUse」座標系統:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
<defs>
<linearGradient id="gradient1" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="blue" />
<stop offset="50%" stop-color="green" />
<stop offset="100%" stop-color="red" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#gradient1)" />
<rect x="130" y="10" width="40" height="80" fill="url(#gradient1)" />
</svg>

這將造成不同的渲染(TouchGFX不支援):

線性漸層使用userSpaceOnUse

這會看起來不同,因為對這兩種形狀而言,漸層起始點位在整個圖像的左上角(涵蓋兩種形狀)。

如果您的SVG使用userSpaceOnUse,可以計算相對於使用漸層形狀的漸層起始點,以便將其轉換為objectBoundingBox。 在以下範例中,漸層以userSpaceOnUse搭配像素座標對圓形著色:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
<defs>
<linearGradient id="gradient1" gradientUnits="userSpaceOnUse" x1="10" y1="10" x2="90" y2="90">
<stop offset="0%" stop-color="blue" />
<stop offset="50%" stop-color="green" />
<stop offset="100%" stop-color="red" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#gradient1)" />
</svg>

我們可以計算圓形的週框方塊,以便將漸層轉換為使用objectBoundingBox。 週框方塊座標為(10,10)至(90,90),與漸層相符。 因此我們可以將「10」變更為「0%」,將「90」變更為「100%」,以便將座標轉換為相對形狀座標。

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="blue" />
<stop offset="50%" stop-color="green" />
<stop offset="100%" stop-color="red" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#gradient1)" />
</svg>

請記得「%」。 y1=「10」代表y1=「1000%」。

Image Converter警告

如果您使用不支援的元素或屬性,TouchGFX Image Converter就會輸出警告或錯誤。 例如我們如果放置箭頭文字:

<?xml version="1.0" encoding="iso-8859-1"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="green" />
<polygon points="50,10 78,78 22,78" fill="gold" />
<text x="38" y="78">ABC</text>
</svg>

TouchGFX Designer於.svg檔案執行Image Converter並顯示錯誤:

使用不支援SVG <text>元素時的錯誤

錯誤輸出顯示哪一個SVG檔案包含錯誤,在哪一個程式行發現錯誤,以及使用了哪一種不支援的元素。

如前所述,目標專案的向量圖形支援是在TouchGFX Generator中設定。 相關說明請參閱Generator使用者指南

SVGImage小工具於Designer中提供使用。 有關SVGImage小工具在Designer中使用的詳細資料,請參閱此處