为 Spritefonts 提供 canvas2d 图像色调

问题描述

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

WebGL spritefont tint

但在 canvas2d 上,我尝试通过 ctx.globalCompositeOperation 执行此操作,但显示如下

canvas2d spritefont tint problem

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

这是我的代码...

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,canvas.width,canvas.height);
    ctx.restore();
}

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

canvas2d image tint when using "darken" mode

我也试过 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,size);
        f = ctx.getimageData(x + (spacing || 0) + (i * 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,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,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,ctx.canvas.height);
    ctx.restore();
}
,

我发现这是更好的方法:

  1. 创建尺寸符合 spritefont 图像尺寸的画布
  2. 在创建的画布中保存上下文状态
  3. 使用 spritefont 文本颜色 (Tint) 设置创建的画布上下文的 fillStyle
  4. 将创建的画布上下文的 globalAlpha 设置为不透明度
  5. 使用 spritefont 文本颜色(色调)填充创建的画布背景
  6. 在创建的画布上下文中应用“destination-atop”复合模式
  7. 将创建的画布上下文的 globalAlpha 重置为 1(默认)
  8. 在创建的画布上绘制精灵字体图像
  9. 在创建的画布中恢复上下文状态
  10. 然后,让默认画布上下文(未创建)从 spritefont 图像中绘制字符,因此我们让它绘制我们创建的画布的一部分(注意 spritefont 图像填充了所有创建的画布)
  11. 完成!
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,c.canvas.width,c.canvas.height);
    c.globalCompositeOperation = "destination-atop";
    c.globalAlpha = 1;
    c.drawImage(fonts[0].src,0);
    c.restore();
    if (q) ctx.drawImage(c.canvas,x + (i * (size + spacing)),size);
}