image.pngimage.pngimage.pngimage.png

背景

有这么一个需求,给定了一种字体的数字图片,用户可以通过拾色器更改字体的颜色。

如何实现

想到了两种实现方案

  1. 由设计提供多组不同颜色的字体,设置几个固定的色值。
    优点:实现简单,只需要进行不同颜色图片组的切换

确点:很显然,需要保存较多的图片,而且可选择的字体颜色有限制

  1. 扫描图片上的像素点,将非透明的像素替换为所选的色值

优点:可实现任意色值的字体颜色,仅需要一组数字图片
缺点:需要学习 canvas 替换像素点相关知识,可能多花费些时间,可行性有待验证
结论先行:经验证是完全可行的,所以缺点可忽略

具体实现

重点 api

  1. ctx.getImageData
    该方法获取图片上所有的像素点信息,信息存储在 Uint8ClampedArray 中,每4个元素一组,对应 r, g, b, a,

所以在进行遍历替换像素点时,增量设置为 4

  1. ctx.putImageData
    将替换后的 imageData 填充到 canvas 画布中
  2. canvas.toDataURL
    转成 dataUrl

    1. static replaceSystemFontColor = (color, src) => {
    2. const rgbObj = hex2rgb(color)
    3. if (!rgbObj || color === '#FFFFFF') return Promise.resolve(src)
    4. let image = new Image()
    5. image.crossOrigin = ''
    6. return new Promise((resolve) => {
    7. image.onload = () => {
    8. let canvas = document.createElement('canvas')
    9. canvas.width = image.width
    10. canvas.height = image.height
    11. const ctx = canvas.getContext('2d')
    12. ctx.drawImage(image, 0, 0)
    13. const imageData = ctx.getImageData(0, 0, image.width, image.height)
    14. for (let i = 0; i < imageData.data.length; i += 4) {
    15. imageData.data[i] = imageData.data[i] !== 0 ? rgbObj.r : imageData.data[i]
    16. imageData.data[i + 1] = imageData.data[i + 1] !== 0 ? rgbObj.g : imageData.data[i + 1]
    17. imageData.data[i + 2] = imageData.data[i + 2] !== 0 ? rgbObj.b : imageData.data[i + 2]
    18. }
    19. console.log()
    20. ctx.putImageData(imageData, 0, 0)
    21. const dataUrl = canvas.toDataURL('image/png')
    22. canvas = null
    23. image = null
    24. resolve(dataUrl)
    25. }
    26. image.src = src
    27. image.onerror = () => {
    28. resolve(src)
    29. }
    30. }).catch(() => Promise.resolve(src))
    31. }