为 Spritefonts 提供 canvas2d 图像色调

Providing canvas2d image tint for Spritefonts

我正在做 Spritefonts,目前正在 WebGL 上为它实现色调!

但在 canvas2d 上,我尝试通过 ctx.globalCompositeOperation 进行操作,但它显示以下内容

如你所见,黑色像素也被填充...

这是我的代码...

var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    ctx.save();
    if (q) ctx.drawImage(fonts[0].src, q.x, q.y, q.w, q.h, x + (spacing || 0) + (i * size), y, size, size);
    ctx.globalCompositeOperation = "source-in";
    ctx.fillStyle = "green";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.restore();
}

当尝试使用“变暗”模式时,它会正确填充但也会填充背景(我不想要这个...)

我也试过 ctx.getImageData()ctx.putImageData() 但字母没有显示

var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    if (q) {
        ctx.drawImage(fonts[0].src, q.x, q.y, q.w, q.h, x + (spacing || 0) + (i * size), y, size, size);
        f = ctx.getImageData(x + (spacing || 0) + (i * size), y, size, size);
        for (var i = 0; i < f.data.length; i += 4) {
            f.data[i + 0] = 100;
            f.data[i + 1] = 100;
            f.data[i + 2] = 255;
            f.data[i + 3] = 255;
        }
        ctx.putImageData(f, x + (spacing || 0) + (i * size), y, 0, 0, size, size);
    }
}               

我使用的图片来自here

通过对填充背景的黑色像素使用“变亮”模式进行修复,然后应用“变暗”模式而不是“源输入”,全部完成!

var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    ctx.save();
    ctx.globalCompositeOperation = "lighten";
    ctx.fillStyle = ctx.canvas.style.backgroundColor;
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    if (q) ctx.drawImage(fonts[0].src, q.x, q.y, q.w, q.h, x + (spacing || 0) + (i * size), y, size, size);
    ctx.globalCompositeOperation = "darken";
    ctx.fillStyle = "green";
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.restore();
}

这是我发现的更好的方法:

  1. 使用符合 spritefont 图像尺寸的尺寸创建 canvas
  2. 在创建的 canvas
  3. 中保存上下文状态
  4. 为创建的 canvas 上下文设置 fillStyle spritefont 文本颜色(色调)
  5. 将创建的 canvas 上下文的 globalAlpha 设置为不透明度
  6. 使用 spritefont 文本颜色(色调)填充创建的 canvas 背景
  7. 在创建的 canvas 上下文中应用“destination-atop”复合模式
  8. 将创建的 canvas 上下文的 globalAlpha 重置为 1(默认)
  9. 将 spritefont 图像绘制到创建的 canvas
  10. 恢复创建的上下文状态canvas
  11. 然后,让默认的 canvas 上下文(不是创建的)从 spritefont 图像中绘制字符,所以我们让它绘制我们创建的 canvas 的一部分(注意 spritefont 图像填充所有创建的 canvas)
  12. 完成!
var size = 32;
var x = 200;
var y = 200;
var spacing = 0;
var opacity = 0.8;
var color = "green";
for (var i = 0; i < txt.length; i++) {
    var q = fonts[0].info[txt[i]];
    var c = document.createElement("canvas").getContext("2d");
    c.canvas.width = fonts[0].src.width;
    c.canvas.height = fonts[0].src.height;
    c.save();
    c.fillStyle = color;
    c.globalAlpha = opacity || 0.8;
    c.fillRect(0, 0, c.canvas.width, c.canvas.height);
    c.globalCompositeOperation = "destination-atop";
    c.globalAlpha = 1;
    c.drawImage(fonts[0].src, 0, 0);
    c.restore();
    if (q) ctx.drawImage(c.canvas, q.x, q.y, q.w, q.h, x + (i * (size + spacing)), y, size, size);
}