WebGL Tutorial
and more

Unicode Char To PNG

撰写时间:2025-03-28

修订时间:2025-04-03

Unicode To PNG

下面将一个代表7筒麻将牌Unicode字符转换为一个编码为Base64字符串的URL,并向一个Imagesrc赋值。

ctx.font = '130px Helvetica'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#BBB'; ctx.fillText('\u{1F01F}', canvas.clientWidth / 2, canvas.clientHeight / 2); const dataURL = canvas.toDataURL("image/png", 1); console.log(dataURL); let img = new Image(); img.src = dataURL; let lastChild = document.body.lastChild; if (canvas !== lastChild) { lastChild.remove(); } document.body.appendChild(img);
body { display: flex; gap: 1em; } canvas { border: 1px solid gray; width: 200px; height: 200px; } img { width: 200px; height: 200px; border: 1px solid gray; }

HTMLCanvasElementtoDataURL方法,目前只支持image/pngimage/jpegMIME Type

指定Canvas的大小

function initCanvas(width, height) { canvas.style.width = width; canvas.style.height = height; canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; ctx = canvas.getContext('2d'); ctx.scale(devicePixelRatio, devicePixelRatio); ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); } function drawCharInCanvas(char, font, fillColor) { ctx.font = font; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = fillColor; ctx.fillText(char, canvas.clientWidth / 2, canvas.clientHeight / 2); } initCanvas('150px', '200px'); drawCharInCanvas('\u{1F01F}', '130px Helvetica', '#BBB');
canvas { border: 1px solid gray; }

initCanvas很重要,它在根据用户的要求来定制canvas的大小的前提下,又可享受高清分辨率的重要保障。

求出字符的边框

function initCanvas(width, height) { canvas.style.width = width; canvas.style.height = height; canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; ctx = canvas.getContext('2d'); ctx.scale(devicePixelRatio, devicePixelRatio); ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); } function drawCharInCanvas(char, font, fillColor) { ctx.font = font; ctx.textAlign = 'left'; ctx.textBaseline = 'top'; ctx.fillStyle = fillColor; ctx.fillText(char, 0, 0); const metrics = ctx.measureText(char); let width = metrics.width; let height = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; ctx.strokeStyle = 'cyan'; ctx.strokeRect(0, 0, width, height); } initCanvas('150px', '200px'); drawCharInCanvas('\u{1F01F}', '130px Monospace', '#BBB');
canvas { border: 1px solid gray; }

根据不同的字体,每个字符的实际大小、上下左右的偏移值都不一样,代表7筒的这个字符稍微往下偏移了一点(这属于该Unicode字符的设计缺陷),但所求出的外围方框基本上均将其包含在内了。可换成其他字符及字体查看不同的效果。

在Canvas中居中绘制

function initCanvas(width, height) { canvas.style.width = width; canvas.style.height = height; canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; ctx = canvas.getContext('2d'); ctx.scale(devicePixelRatio, devicePixelRatio); ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); } function drawCharInCanvas(char, font, fillColor) { ctx.font = font; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; const metrics = ctx.measureText(char); let width = metrics.width; let height = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; ctx.strokeStyle = 'cyan'; ctx.strokeRect((canvas.clientWidth - width) / 2, (canvas.clientHeight - height) / 2, width, height); ctx.fillStyle = fillColor; ctx.fillText(char, canvas.clientWidth / 2, canvas.clientHeight / 2); } initCanvas('150px', '200px'); drawCharInCanvas('\u{1F01F}', '130px Monospace', '#BBB');
canvas { border: 1px solid gray; }

这样,在指定了canvas的大小后,我们就可以微调其字体大小来达到最佳效果。下面将扑克牌中的大鬼字符转换为PNG图像。

function initCanvas(width, height) { canvas.style.width = width; canvas.style.height = height; canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; ctx = canvas.getContext('2d'); ctx.scale(devicePixelRatio, devicePixelRatio); ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); } function drawCharInCanvas(char, font, fillColor) { ctx.font = font; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; const metrics = ctx.measureText(char); let width = metrics.width; let height = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; ctx.fillStyle = fillColor; ctx.fillText(char, canvas.clientWidth / 2, canvas.clientHeight / 2); } function drawImage() { const dataURL = canvas.toDataURL("image/png", 1); let img = new Image(); img.src = dataURL; img.width = canvas.clientWidth; img.height = canvas.clientHeight; let lastChild = document.body.lastChild; if (canvas !== lastChild) { lastChild.remove(); } document.body.appendChild(img); } initCanvas('150px', '200px'); drawCharInCanvas('\u{1F0CF}', '130px Monospace', '#BBB'); drawImage();
body { display: flex; gap: 1em; } canvas, img { border: 1px solid gray; }

通过这种方式,我们可将任意Unicode字符无损耗地转换个任意大小的PNG图像,并且可以精细调节图像的颜色、图像的位置,我们可用的图像来源又多了许多,从而有效解决了图像资源匮乏的问题。

访问本站的Unicode查询表,找到中意的字符后,将其Unicode编码粘帖至上面代码中,即可生成相应的PNG图像,对其按右边即可下载使用。

要想了解如何居中源图像后再绘制,可参见getImageData

参考资源

  1. HTMLCanvasElement: toDataURL() method
  2. Potrace
  3. Potrace online demo
  4. Download Canvas API-Generated Images Using toBlob
  5. How To Develop an Interactive File Uploader with JavaScript and Canvas