在画布上逐像素绘制文本

4
我有一个画布,我使用“fillText”和一个字符串,比如“stackoverflow”。然后我读取画布的imagedata,以便挑选出该文本的每个像素。
我想从像素中挑选以下内容:x位置、y位置和其颜色。然后我想循环遍历该数组与这些像素,以便逐像素地绘制回文本,这样我就可以完全控制每个像素,并且可以对它们进行动画处理。
但是,我的效果不够平滑。看一下我附上的图像,你会看到顶部文本和使用fillRect绘制每个像素的文本之间的差异。请问如何使新文本看起来像“fillText”文本呢?
谢谢
更新:添加了我的代码
var _particles = [];
var _canvas, _ctx, _width, _height;

(function(){
    init();
})();

function init(){
    setupParticles(getTextCanvasData());
}

function getTextCanvasData(){
    // var w = 300, h = 150, ratio = 2;

    _canvas = document.getElementById("textCanvas");
    // _canvas.width = w * ratio;
    // _canvas.height = h * ratio;
    // _canvas.style.width = w + "px";
    // _canvas.style.height = h + "px";

    _ctx = _canvas.getContext("2d");
    _ctx.fillStyle = "rgb(0, 154, 253)";
    // _ctx.setTransform(ratio, 0, 0, ratio, 0, 0);

    var str = "stackoverflow";
    _ctx.font = "32px EB Garamond";
    _ctx.fillText(str,0,23);

    _width = _canvas.width;
    _height = _canvas.height;

    var data32 = new Uint32Array(_ctx.getImageData(0, 0, _width, _height).data.buffer);
    var positions = [];

    for(i = 0; i < data32.length; i++) {

        if (data32[i] & 0xffff0000) {
            positions.push({
                x: (i % _width),
                y: ((i / _width)|0),
            });
        }
    }

    return positions;
}

function setupParticles(positions){
    var i = positions.length;
    var particles = [];
    while(i--){
        var p = new Particle();
        p.init(positions[i]);
        _particles.push(p);

        drawParticle(p);
    }
}

function drawParticle(particle){
    var x = particle.x;
    var y = particle.y;

    _ctx.beginPath();
    _ctx.fillRect(x, y, 1, 1);
    _ctx.fillStyle = 'green';
}

function Particle(){
    this.init = function(pos){
        this.x = pos.x;
        this.y = pos.y + 30;
        this.x0 = this.x;
        this.y0 = this.y;
        this.xDelta = 0;
        this.yDelta = 0;
    }
}

My current result


我猜画布正在使用抗锯齿技术。边界上的像素既不是蓝色也不是粉色-它们介于两者之间。当你绘制时,你对所有“非粉色”部分都使用绿色,因此你的绘图会变得更大、更粗糙。 - SQL Hacks
@SQLHacks 是的,但我能画出alpha颜色以使其更平滑吗?现在我使用绿色填充fillRect,所以在可能需要alpha值的地方,它现在是绿色的? - nickelman
@nickelman 请发布你的代码。除了颜色之外,您很可能需要读取每个像素的 alpha 值,并在绘制时使用它。 - Gabriele Petrioli
@GabyakaG.Petrioli 当然可以!帖子已经更新。 - nickelman
1个回答

4

这里给你的代码更新了,它重复使用每个像素的 alpha 组件。由于我们没有保留像素的抗锯齿特性(实际上会改变打印的实际颜色),所以仍然会有一些细节丢失,但对于这个例子,alpha 已足够。

var _particles = [];
var _canvas, _ctx, _width, _height;

(function(){
    init();
})();

function init(){
    setupParticles(getTextCanvasData());
}

function getTextCanvasData(){
    // var w = 300, h = 150, ratio = 2;

    _canvas = document.getElementById("textCanvas");
    // _canvas.width = w * ratio;
    // _canvas.height = h * ratio;
    // _canvas.style.width = w + "px";
    // _canvas.style.height = h + "px";

    _ctx = _canvas.getContext("2d");
    _ctx.imageSmoothingEnabled= false;
    _ctx.fillStyle = "rgb(0, 154, 253)";
    // _ctx.setTransform(ratio, 0, 0, ratio, 0, 0);

    var str = "stackoverflow";
    _ctx.font = "32px EB Garamond";
    _ctx.fillText(str,0,23);

    _width = _canvas.width;
    _height = _canvas.height;

    var pixels = _ctx.getImageData(0, 0, _width, _height).data;
    var data32 = new Uint32Array(pixels.buffer);
    var positions = [];
        for(i = 0; i < data32.length; i++) {
        if (data32[i] & 0xffff0000) {
            positions.push({
                x: (i % _width),
                y: ((i / _width)|0),
                a: pixels[i*4 + 3] / 255
            });
        }
    }

    return positions;
}

function setupParticles(positions){
    var i = positions.length;
    var particles = [];
    while(i--){
        var p = new Particle();
        p.init(positions[i]);
        _particles.push(p);

        drawParticle(p);
    }
}

function drawParticle(particle){
    var x = particle.x;
    var y = particle.y;

    _ctx.beginPath();
    _ctx.fillStyle = `rgba(0,128,0,${particle.alpha})`;
    
    _ctx.fillRect(x, y, 1, 1);
}

function Particle(){
    this.init = function(pos){
        this.x = pos.x;
        this.y = pos.y + 30;
        this.x0 = this.x;
        this.y0 = this.y;
        this.xDelta = 0;
        this.yDelta = 0;
        this.alpha = pos.a;
    }
}
<canvas id="textCanvas"></canvas>


太棒了,看起来很不错。谢谢! - nickelman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接