跳轉到主要內容

SVG

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

SVG圖像可透過SVGImage小工具納入使用者介面中。 This widget is available in TouchGFX Designer and can be added to the user interface as any other widget.

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資料夾

In TouchGFX Designer we can insert an SVGImage widget:

插入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)。

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

目標設定

To use SVG images on a target you need to have Vector Rendering enabled in STM32CubeMX. 這會在專案中插入所需的程式碼,以建立SVGImage所需的向量渲染器。

Note
Vector Rendering is enabled in all TouchGFX Boards Specifications available in TouchGFX Designer (except STM32G0 and similar small platforms).

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

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

This problem is resolved by changing the configuration in STM32CubeMX. 請另行參閱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 runs the Image Converter on the .svg file and shows the error:

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

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

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

The SVGImage widget is available in TouchGFX Designer. The use of SVGImage widget in TouchGFX Designer is detailed here.