UWP 手繪視頻創作工具技術分享系列 - SVG 的解析和繪製

来源:http://www.cnblogs.com/shaomeng/archive/2017/09/09/7476480.html
-Advertisement-
Play Games

本篇作為技術分享系列的第一篇,詳細講一下 SVG 的解析和繪製,這部分功能的研究和最終實現由團隊的 @黃超超 同學負責,感謝提供技術文檔和支持。 首先我們來看一下 SVG 的文件結構和組成 SVG (Scalable Vector Graphics) 是一種可縮放矢量圖形,使用 XML 格式來定義, ...


本篇作為技術分享系列的第一篇,詳細講一下 SVG 的解析和繪製,這部分功能的研究和最終實現由團隊的 @黃超超 同學負責,感謝提供技術文檔和支持。 

首先我們來看一下 SVG 的文件結構和組成

SVG (Scalable Vector Graphics) 是一種可縮放矢量圖形,使用 XML 格式來定義,是一種 W3C 標準,圖像在放大或改變尺寸的情況下其圖形質量不會有所損失。

下麵是一個簡單的 SVG 的文件結構例子:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>

從文件結構來看,SVG 確實是一種標準的 XML 格式,而裡面的元素,從字面上來看,是一個坐標為(100,50),半徑為40,填充色為紅色,線條為黑色,線寬為2的圓形。下麵我們來看看 SVG 文件裡面的基本元素和屬性:

1. 結構元素

<defs>, <g>, <svg>, <symbol>, <use>

2. 圖形元素

<line>, <circle>, <ellipse>, <polygon>, <polyline>, <rect>, <path> 

這些標簽相信大家都不陌生,幾乎每種界面語言都有類似的標記。在 SVG 里,最常用的還是<path>, 用它可以表示前面所有的標簽。 

3. 特殊元素

<image> :圖片,源通常由 base64 string 或 url 表示。它通常出現在這種場景:通過 PhotoShop 編輯一張圖片後,導出為 SVG 格式,這時文件里就存在 <image> 標簽,之後再導入到 AI 中進行路徑編輯,導出為 SVG 格式,就有了一張可以描繪路徑,又包含 <image> 底圖的 SVG 文件了。

<text> :文本,設置文字內容和字體字型大小等信息後,就可以在 SVG 中顯示這些文字。 <text> 支持 transform 屬性,可以旋轉縮放文字,同時還支持 style, css 代碼可以直接添加進來。

完整的元素列表參考這裡:https://developer.mozilla.org/zh-CN/docs/Web/SVG/element

4. 元素的若幹屬性

opacity, fill, stroke, stroke-width, stroke-miterlimit, fill-opacity, stroke-opacity, fill-rule, stroke-dasharray, stroke-dashoffset, stroke-linecap, stroke-linejoin, transform

這些都不難理解,代表了元素的透明度,填充,線條,變換等,因為 SVG 是 W3C 標準,所以以上這些外觀屬性,在 CSS 中都有對應的屬性。另外,SVG 還支持其他的屬性類型,如動畫事件/動畫定時/關鍵幀動畫/圖形屬性/過濾器等,十分強大。

完整的屬性列表參考這裡:https://developer.mozilla.org/zh-CN/docs/Web/SVG/attribute

來看一個例子:自上而下,分別包含了 兩個矩形,一個圓形,一個橢圓,一條直線,一條折線,一個多邊形和一條自定義 path。

<?xml version="1.0" standalone="no"?>
<svg width="200" height="250" version="1.1" viewBox="0 0 200 250" xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
  <rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
  <circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
  <ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
  <line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
  <polyline points="60,110 65,120 70,115 75,130 80,125 85,140 90,135 95,150 100,145"
      stroke="orange" fill="transparent" stroke-width="5"/>
  <polygon points="50,160 55,180 70,180 60,190 65,205 50,195 35,205 40 190 30 180 45 180"
      stroke="green" fill="transparent" stroke-width="5"/>
  <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
</svg>

這裡對上面的示例代碼做一些補充說明:

計量單位 width height x y 等沒有顯示指定單位,這時我們認為單位就是 px。也可以明確指定單位 in cm 等,這時會根據當前設備的環境來換算為 px 顯示。

viewBox 定義了畫布上可以顯示的區域,格式為 “x y width height”,如上圖的 viewBox=“0 0 200 250”,從(0,0)點開始,寬高 200 * 250的區域,SVG 的 width=“200”,height=“250”,所以當前縮放比是1. 如果 SVG width=“400” height=“500”,則會有兩倍的放大效果。

path 和其他元素的對比 在 SVG 中 path 是最常用的元素,和 polyline 做對比,path 也可以通過 d 的設置完成一樣的折線或曲線,而且只需要很少的點就可以創建平滑的曲線,但 polyline 需要設置大量的點才能達到平滑的效果。所以從製作難度和縮放效果看,path 是更好的選擇。

接下來看一下 SVG 的繪製過程

首先說明繪製的兩個基本原則:

1. 解析順序和繪製順序一致,都要遵守 XML 中元素的位置排列。借用上面的例子,SVG 中元素在 XML 中有固定的排列順序,我們解析時會遵守這個順序,繪製時同樣也會遵守這個順序。也就是說先出現的元素,會出現在繪製的底層,而後出現的元素,會出現在繪製的頂層,如果元素間位置有重疊,則會出現頂層元素遮擋底層元素的情況。

2. 子節點會繼承父節點的一些屬性,如 opacity,transform 等。這點在繪製時需要特別註意,opacity 等靜態屬性需要繼承,而 transform 等屬性需要做矩陣變換才能得到子節點最終 transform。

來畫手繪視頻中對 SVG 的處理過程

處理中遇到的一些特殊情況和處理

1、解析SVG文檔時,忽略DTD驗證

    雖然是 DTD 是 XML 解析的標準驗證方式,但是很多工具製作的 SVG,DTD 會缺失,所以解析時應該忽略 DTD 驗證,不然會直接造成解析錯誤

2、解析SVG文檔時,一些元素的屬性值可能有多種分隔/表明方式

    多邊形的點集,元素的 transform,都是一個數字集合,集合的分割方式可能是 “空格”,“,” 也可能是其他符號,所以在解析時需要相容多種分割方式。

    顏色的表示,長度單位等,也可能會出現多種形式,如顏色有已知顏色和顏色值等形式,都需要做相容。

3、元素的某些屬性會繼承父級元素  

    transform,透明度等屬性,都需要考慮父級元素的繼承關係。transform 會複雜一些,transform [3*2] 的 矩陣,會包括縮放/平移/旋轉 等信息,子元素的平移信息,需要和父級元素做縮放相乘後,再做平移。

4、元素屬性的預設值

     很多工具導出的 SVG,是會忽略一些屬性的,而這些屬性如果沒有值,我們是沒辦法正確顯示的。所以我們需要針對它們設置預設值。例如 fill 預設應該是 none,stroke 預設是 black,stroke-width 預設為1px,fill-rule 預設為 nonzero。這裡重點說一下 fill-rule,它分為 evenodd 和 nonzero 兩種方式:

    EvenOdd:確定一個點是否位於填充區域內的規則,具體方法是從該點沿任意方向畫一條無限長的射線,然後計算該射線在給定形狀中因交叉而形成的路徑段數。 如果該數為奇數,則點在內部;如果為偶數,則點在外部。

    Nonzero:確定一個點是否位於路徑填充區域內的規則,具體方法是從該點沿任意方向畫一條無限長的射線,然後檢查形狀段與該射線的交點。 從零開始計數,每當線段從左向右穿過該射線時加1,而每當路徑段從右向左穿過該射線時減 1。 計算交點的數目後,如果結果為零,則說明該點位於路徑外部。 否則,它位於路徑內部。

5、解析順序與渲染順序,描邊與填色的順序

     解析順序和渲染順序必須一致,並且和 XML 中的順序一致,否則會出現錯誤的遮擋現象和繪製順序倒轉。描邊和填色的順序,基本原則是,單個元素的描邊完成後,操作填色,然後再操作下一個元素。當然這裡的填色可以靈活控制,比如保存所有填色,等所有描邊完成後,一次性填色。

6、包含<image>標簽的繪製

    包含 <image> 標簽的 SVG,處理起來會有些特殊的地方。這種 SVG 的存在,一般是畫師通過 PS 編輯圖片後,再導入 AI 中生成的 SVG。處理這種 SVG 的繪製時,基本思路是:解析 <image> 標簽,當做 SVG 的底圖,用一個透明遮罩擋住;然後解析後面的 <path> 標簽,這是只需要解析 path 和 stroke,不需要 fill,用這裡的 path 去塗抹底圖,塗抹過的地方,透明遮罩失效,底圖露出,就達到了塗抹出底圖線條的目的。按照這個思路把底圖塗抹出來,類似刮刮卡的感覺。

 

到這裡,SVG 的基本知識、解析和繪製原理就介紹完了,當然這隻是很基礎的過程,在後面我們會整理出一些很特殊的 SVG 格式的解析和繪製思路,屆時和大家分享,謝謝。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上面第二步要有寫文件的許可權,如果沒有可以切換為root賬戶進行操作 上面的第一個路徑根據自己安裝後的python地址確認 ...
  • NodeJS,MongoDB,Vue,VSCode 集成學習 開源項目地址:http://www.mangdot.com ...
  • 使用環境:Win7+VS2017 一、新建一個.NET Core2.0的MVC項目 二、使用Nuget添加EF的依賴 輸入命令:Install-Package Microsoft.EntityFrameworkCore.SqlServer 三、如果是使用db first,需要根據資料庫生成model ...
  • 在現代應用程式中,認證已不再是簡單的將用戶憑證保存在瀏覽器中,而要適應多種場景,如App,WebAPI,第三方登錄等等。在 ASP.NET 4.x 時代的Windows認證和Forms認證已無法滿足現代化的需求,因此在ASP.NET Core 中對認證及授權進行了全新設計,使其更加靈活,可以應付各種 ...
  • 在前面一篇博文記錄了C#中的APM非同步編程的知識,今天再來分享一下EAP(基於事件的非同步編程模式)非同步編程的知識。後面會繼續奉上TPL任務並行庫的知識,喜歡的朋友請持續關註哦。 ...
  • 1 概述 1 概述 本篇文章主要從操作上簡要分析Controller<=>View之間相互傳值,關於頁面之間傳值,如果感興趣,可參考我另外一篇文章ASP.NET 頁面之間傳值的幾種方式 。 Controller=》View:Model,ViewBag,ViewData,TempData,ViewBa ...
  • 距離上次發東西已經過去了貌似不知多少天了,突然發現自己懶得總結了。這毛病感覺不好,還得寫點東西來充實一下自己,不然這樣整天渾渾噩噩的過日子,也太平淡了,不管怎麼說,起碼得給自己的經歷留下點東西吧。閑話不扯了,最近一直在忙著搞GIS的東西;國內主流的二大地圖:百度和高德地圖,確實直接調用SDK是很不錯 ...
  • 但是這種操作方式存在兩個問題:1.通過反射的方式,效率不高。2.如果是一個感測器,那麼定義的實時數據屬性不多;如果是一個站點(可以理解為生產單位或網關層)上傳的數據,可能有成千上萬監測點,那麼不可能在繼承DeviceDynamic介面的子類中定義這麼多屬性。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...