背景
有这么一个需求,给定了一种字体的数字图片,用户可以通过拾色器更改字体的颜色。
如何实现
想到了两种实现方案
- 由设计提供多组不同颜色的字体,设置几个固定的色值。
优点:实现简单,只需要进行不同颜色图片组的切换
确点:很显然,需要保存较多的图片,而且可选择的字体颜色有限制
- 扫描图片上的像素点,将非透明的像素替换为所选的色值
优点:可实现任意色值的字体颜色,仅需要一组数字图片
缺点:需要学习 canvas 替换像素点相关知识,可能多花费些时间,可行性有待验证
结论先行:经验证是完全可行的,所以缺点可忽略
具体实现
重点 api
- ctx.getImageData
该方法获取图片上所有的像素点信息,信息存储在 Uint8ClampedArray 中,每4个元素一组,对应 r, g, b, a,
所以在进行遍历替换像素点时,增量设置为 4
- ctx.putImageData
将替换后的 imageData 填充到 canvas 画布中 canvas.toDataURL
转成 dataUrlstatic replaceSystemFontColor = (color, src) => {const rgbObj = hex2rgb(color)if (!rgbObj || color === '#FFFFFF') return Promise.resolve(src)let image = new Image()image.crossOrigin = ''return new Promise((resolve) => {image.onload = () => {let canvas = document.createElement('canvas')canvas.width = image.widthcanvas.height = image.heightconst ctx = canvas.getContext('2d')ctx.drawImage(image, 0, 0)const imageData = ctx.getImageData(0, 0, image.width, image.height)for (let i = 0; i < imageData.data.length; i += 4) {imageData.data[i] = imageData.data[i] !== 0 ? rgbObj.r : imageData.data[i]imageData.data[i + 1] = imageData.data[i + 1] !== 0 ? rgbObj.g : imageData.data[i + 1]imageData.data[i + 2] = imageData.data[i + 2] !== 0 ? rgbObj.b : imageData.data[i + 2]}console.log()ctx.putImageData(imageData, 0, 0)const dataUrl = canvas.toDataURL('image/png')canvas = nullimage = nullresolve(dataUrl)}image.src = srcimage.onerror = () => {resolve(src)}}).catch(() => Promise.resolve(src))}



