預覽裡有 3 張圖,成品只剩 1 張
起點是一份 sv_image_rel.svg:594 B,3 個 <image>,兩條以相對路徑外部引用同一張 64×64 瓦片,第三條是 data: URI 內嵌。預覽裡三張都在,探針記到 3 次 load;轉成 PNG 拿回來的成品 2576 B,外部引用那一塊墨跡 px=0,只剩內嵌那條的 4096 px。差的是兩套載入機制。
行內 DOM 與 Blob→Image→drawImage
把檔案交給SVG 轉換格式之後,「載入」與「轉換並下載」是兩段不相交的鏈路。預覽側(行 121-168):DOMParser 解析字串,取第一個 <svg> 嵌進文件,不建 Image 也不建 Blob URL,外部引用按一般網頁資源去取。匯出側(行 200-255):字串→Blob→objectURL→new Image→onload 後 drawImage 進 canvas。以圖片解碼時這份文件是 opaque origin,內部引用另算一套,分岔就是從這裡來的。
四類內部依賴,兩側讀數不同
跨檔案 <use>(249 B)在 DOM 側觸發了 load,點陣側卻是整幅 px=0。外部引用的 @import(284 B)給 64px 文字定的規則沒生效,computed 回落成 -apple-system、14px,長度讀數 85.83;同一條規則改成行內(332 B),讀數是 475.06。成品側同樣分裂:外部引用那份匯出 4972 B 的 PNG,墨跡只有 692 px。
外部引用的 @font-face(322 B)與同一個字型以 data: 內嵌(612547 B)在 DOM 欄同寬,兩邊讀數都是 400.55;點陣欄卻是 px=5401、bbox 315×49 對 px=4855、314×43。fill:url(外部圖) 那一份 256 B:DOM 裡 fill 的計算值原樣帶著 url,點陣側整幅 px=0,成品 2544 B 是一張純空圖,toast 照樣報成功。
這些不能寫成「外部引用依賴實測不支援」。本機 Chrome 是以 --allow-file-access-from-files 啟動的,改成 file:/// 與 https:// 絕對路徑外部引用的兩份樣張,匯出時反而都進了點陣,ink px=3327,成品同為 8075 B。所以能寫的只有:預覽與匯出這兩條路徑的墨跡不同,而無頭環境未能觸發攔截——不外推成線上口徑。
圖 1 四類內部依賴在兩條路徑下的讀數
兩個尺寸框與 viewBox 的成對覆蓋
convert-out-w / convert-out-h 寫的是畫布像素,跟 SVG 自身只在「原始尺寸」那一步有關:viewBox 存在且 split 出 4 段、而寬或高缺位時,兩個值會成對被它的第 3、4 段頂掉;兩個屬性都寫時 viewBox 完全不參與;匯出側則只讀框。max="10000" 只是個 HTML 屬性,程式碼不讀它——勾了等比時把高打 10000,寬被反算成 13333 寫進框裡;探針寫 100000 也原樣回讀,報錯位是 null。
| svg 根上的寫法 | 兩框讀數 | 取哪一邊 |
|---|---|---|
| 只有 viewBox="0 0 320 240" | 320 × 240 | 缺位時 viewBox 頂上來 |
| width="100" + viewBox | 320 × 240 | 寫進去的 100 被成對丟掉 |
| width="320" height="240" + viewBox="0 0 100 50" | 320 × 240 | 兩個都在,viewBox 不參與 |
取整方向也不統一:origin 與等比反算用 Math.round,匯出取值卻用 parseInt,同一個框裡 "333.7" 被截成 333、"1e3" 被截成 1;寫 0 或留空都是假值,一律退回 origin。
超過畫布上限,靜默交出空載荷
16385×16385 與 20000×20000 時,data URL 只剩 6 個字元,載荷就是 "data:,";toast 仍是「已轉換為 PNG (20000×20000) 並開始下載」。上限之內才是真位元組:320×240 基準圖出 35990 B,6000×6000 是 697011 B,10000×10000 是 1889260 B,魔數全是 89 50 4e 47 0d 0a 1a 0a。
字寬這筆帳:點陣一律裁到 320
"VECTOR-0123" @64,在 12 個 font-family 下的 DOM 長度讀數從 352.00(monospace 與宋體)一路排到 484.97(Arial Black),差 132.97;族名不存在也不報錯,落回繼承那一檔的 392.44。DOM 裡的 rect 還要再乘上預覽縮放,預覽因此看起來剛剛好;320 寬的畫布則把點陣墨跡一律裁到 ≤320。
圖 2 族名字寬譜,與 320 寬畫布的鉛直上限
單次處理與 object URL 回收
這一頁沒有批次入口:fileInputMultiple=false,拖曳與 change 兩處(行 104、107)都只取 files[0]。整輪 13 步測得 object URL made=11 / revoked=11,一次匯出就是 1 造 1 銷,沒有累積。「該轉多大、存成什麼格式」是另一筆帳,SVG 轉 PNG 的匯出尺寸與格式選擇那篇已經拆過,這裡不複述。
幾個常見追問
Q:預覽和成品對不上,先查哪裡?
查 SVG 裡指向外部的引用:<image> 的相對路徑、跨檔案 <use>、外部引用 @import / @font-face、fill:url(外部圖)。它們都活在 DOM 裡,點陣化時是另算一套。
Q:框裡寫大數沒報錯,是不是就安全?
不是。max 屬性和報錯位都攔不住寫入,13333 照樣進框;越過畫布上限也只不過是 6 字元的空載荷配上一則成功 toast,得自己核對成品位元組與魔數。
Q:成品文字比預覽窄?
font-family 依賴本機字型,12 族的讀數能差 132.97;320 寬的畫布再把點陣一律裁到 ≤320。要穩:匯出前把規則改成行內、字型以 data: 內嵌。