用canvas2d繪製font texture的注意事項
前言
用canvas2d繪製font可以輕鬆地找到範例,但繪製時有些需要注意的事,在此把過程做個紀錄。內容
由於WebGL本身不提供字型,所以需要產生font texture,產生的流程如下圖產生font texture的流程 |
繪製字型是用canvas2d繪製後輸出到image,再來將imgae的資料輸出到WebGL的texture,之後WebGL再利用該texture來繪製font,整個流程不是很簡潔,但是我目前找到的方法中最好的。
基本的繪製範例如下
let canvas=document.getElementById('myCanvas'); let ctx=canvas.getContext('2d'); canvas.width=300; canvas.height=300; let fontSize=36; let str='|_jx/|'; ctx.fillStyle='#ff0000'; ctx.font=fontSize+'px sans-serif'; ctx.textBaseline='top'; for(let i=0,curOffset=0;i<str.length;i++){ let width=ctx.measureText(str[i]).width; ctx.fillStyle='#ff0000ff'; ctx.fillText(str[i],curOffset,0); curOffset+=width; }
繪製的結果如下
範例繪製的結果 |
繪製的結果看起來沒問題,但事實上有問題,請看"_"與"j"連接的部分會連在一起,這對font texture而言可不是好事,如果WebGL在繪製"_"時會看到與"j"的部分,再想想如果將"_"改成"A",在繪製"A"時下方會多出"j"的一部分,這樣是無法讓人接受的。為什麼會發生這個問題呢?看看範例是如何知道該字的寬,"ctx.measureText()"就這個method,這是唯一可以得到字寬的方法,字高呢?font size有多高該字就多高,像"_"與"A"的高明顯不同,但只能把字型高的空間整個拿去畫。
前面提到透過"ctx.measureText()"來取得字寬,但"j"這個字很特別,它的左側會會超出繪製的字寬,如下圖
"j"的字寬很特別 |
第一個"j"的左側會被截掉,是因為超出canvas的左側,第二個"j"就可以看到該字的左側會超出邊框,這就是問題了。這問題怎麼解決呢?目前我想到的是針對"j"來做特例處理,讓"j"的左側會多出一些空間來包住"j",具體的範例如下
let canvas=document.getElementById('myCanvas'); let ctx=canvas.getContext('2d'); canvas.width=300; canvas.height=300; let fontSize=36; let str='jj|_jx/|'; let modWidth=10; ctx.fillStyle='#ff0000'; ctx.font=fontSize+'px sans-serif'; ctx.textBaseline='top'; for(let i=0,curOffset=0;i<str.length;i++){ let width=ctx.measureText(str[i]).width; if(str[i] === 'j') modWidth=5/72 *fontSize; else modWidth=0; ctx.fillStyle='#ff0000ff'; ctx.fillText(str[i],curOffset+modWidth,0); ctx.strokeRect(curOffset+modWidth,0,width,fontSize); curOffset+=width+modWidth; }
這個範例會對"j"這個字的左側增加"5/72"的寬度,這個寬度是我實驗的寬度,可以依據需要自己改,並且會考慮新增的寬度繪製新的邊框(邊框的寬度還是原本的寬度,但字跟字不會連在一起了),繪製的結果如下
修正"j"的寬度的繪製結果 |
沒有留言:
張貼留言