html5-canvaswebgltintspritefont

Providing canvas2d image tint for Spritefonts


I'm doing Spritefonts and currently implemented tint for it on WebGL!

WebGL spritefont tint

But on canvas2d i tried to do it via ctx.globalCompositeOperation but it shows following

canvas2d spritefont tint problem

As you see, Black pixels are also filled...

Here is my code...

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();
}

When trying with "darken" mode instead, It fills correctly but also it fills background (Which i don't want this...)

canvas2d image tint when using "darken" mode

I also tried with ctx.getImageData() and ctx.putImageData() but letters not shown

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);
    }
}               

The image i'm using is from here


Solution

  • This is better way i found:

    1. Create canvas with dimensions that complies with spritefont image dimensions
    2. Save context state in the created canvas
    3. Set fillStyle of the created canvas context with spritefont text color (Tint)
    4. Set globalAlpha of created canvas context to opacity
    5. Fill created canvas background with spritefont text color (Tint)
    6. Apply "destination-atop" composite mode in created canvas context
    7. Reset globalAlpha of created canvas context to 1 (Default)
    8. Draw spritefont image onto created canvas
    9. Restore context state in created canvas
    10. Then, Let default canvas context (Not created one) draw characters from spritefont image, So we let it draw part of canvas we created (Note that spritefont image fills all created canvas)
    11. Done!
    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);
    }