iT邦幫忙

2023 iThome 鐵人賽

DAY 25
1

對於渲染引擎而言,不論我們如何用 override-colors 的方式調整 Color Font 的顏色,顯示的都是「字」,在記憶體裡面儲存的其實是該字符的「碼位」與「字型資訊」。

如果我們把這個「字」複製到別的地方,在沒有設定 css 的情況下,顏色設定就會跑掉,通常會以預設的第 0 個基本色盤表示。

所以如果想要保存我們設定的「彩色字」、或是讓使用者可以自由地分享,除了連 css 資訊一併紀錄之外,另一種方式就是將文字轉成圖片。

透過 <canvas> 標籤

在 HTML 標準裡面,我們可以透過 canvas 標籤來繪製圖案,以繪製一個矩形來說,先在 html 裡面定義一個 300x300 的 畫布(canvas),為了更清楚範圍,在這裡替畫布補上一個黑色外框,實際上是可以省略的:

<canvas id="myCanvas" width="300" height="300" 
        style="border:1px solid black">
</canvas>

接著透過 javascript,指定該畫布後,藉由 canvas.getContext 繪製想要的東西,在這裡我們指定 2d,也就是二維的圖像(除此之外也可以繪製 3D 的 webgl 等,但瀏覽器的支援程度不一,很容易破圖)。接著,我們填入一個自座標 (x, y) = (30, 50) 起算,長寬各為 80100#FF0000 紅色矩形:

let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(30, 50, 80, 100);  // (x, y, w, h),以左上角為原點

在 canvas 裡面填入字

<canvas> 標籤除了製作幾何圖形之外,也可以用來繪製文字。假設我們把「字」被記錄在 id 為 #dolphin 這個 <div> tag 裡面:

<div id="dolphin" style="font-family: Noto Color Emoji; font-size: 10em">🐬</div>

我們想要繪製出一模一樣大小的圖片,首先就必須要讓畫布 #myCanvas 的大小和 #dolphin 這個 DOM 的大小一致。因此,和上面畫圖不同的是,這次我們不在 #myCanvas 的 tag 裡預設長寬尺寸,而是應該要透過參照的方式讓 #myCanvas 獲取 #dolphin 的長寬尺寸:

canvas.width = document.getElementById("dolphin").clientWidth;
canvas.height = document.getElementById("dolphin").clientHeight;

接著,我們要讓畫布恢復成空白的狀態。之所以要這樣做,是因為我們也許會重複使用這個畫布,如果上一次的結果沒有先清掉的話,就會將這一次的結果直接疊在舊稿之上,透過每次繪製前的重設畫布,也算是一種防呆機制吧!此外,背景設定為白色的之後,只要另存成 *.png 格式,就會是去背的樣式。

ctx.clearRect(0, 0, canvas.width, canvas.height);

接著就是設定需要的字型資訊以及字型大小,就可以將字轉成圖片啦:

ctx.font = "10em Noto Color Emoji";
ctx.fillText("🐬", canvas.width / 2, canvas.height / 2);

畫質?

不過,如果把圖片打開來看的話,會發現畫質其實不是那麼好,這是因為我們預設都是使用 1:1 的方式去渲染 #dolphin 這個 tag 的 🐬,雖然對於向量儲存的 COLR/CPAL Color Font 來說,放大縮小都不會讓字型失真,但因為我們已經將他轉成點陣形式的圖片了,所以會遇到畫質不佳的問題。

至於解決方式呢?也很簡單,就是在更大張的畫布上繪製就好——我們可以定義一個 scaleProp 參數來控制畫布大小的倍率。

// 縮放的參數,假設放大十倍
const scaleProp = 10

canvas.width = document.getElementById("dolphin").clientWidth * scaleProp;
canvas.height = document.getElementById("dolphin").clientHeight * scaleProp;

// 讓繪製的結果也跟著放大
ctx.scale(scaleProp, scaleProp);

如此一來,我們就能得到更高畫質的「文字圖片」了。

另存檔案

在「文字」的情況下,要轉載或是分享都會麻煩,但要將 <canvas> 的「圖片」轉成圖片就很簡單了,至於是要存成 image/png 、還是 image/jpeg 格式,就端看需求了。

const dataURL = canvas.toDataURL("image/png");

這個 dataURL 已經可以在瀏覽器內開啟了,不過如果想要做一個按鈕,在按下去的時候觸發下載的話,就必需要透過 Dummy Element 來處理:

const downloadLink = document.createElement("a");
downloadLink.href = dataURL;
downloadLink.download = "filename.png";  
downloadLink.click(); // 模擬點擊

在今天,我們搞定了文字和圖片的轉換關係,無論使用者怎麼調用 COLR/CPAL Color Font 色盤的顏色,都可以透過轉存圖片的方式保存。


上一篇
DAY 24|Emoji Mart:讓使用者挑喜歡的 Emoji
下一篇
DAY 26|功能需求與檢討
系列文
一起成為新世紀文字藝術師:深入玩轉 Unicode 和 OpenType30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言