为什么在相同 canvas 上有些图像模糊而其他图像清晰?

Why are some images blurry and others crisp on the same canvas?

在我正在处理的 canvas 项目中,我有一个基于图块的网格,以及一个选项面板。我已经做好了一切工作,所有图像都很清晰,考虑了屏幕大小调整,没有抗锯齿等。一切(图形方面)都很完美,问题是有时我需要更改行数和列,这会改变 canvas 的整体尺寸。由于其他一些问题,我在 editor class 中使用了 buffer canvas,它被渲染到主 canvas.

这是我的编辑器代码(只有图形):

export class Editor{
    constructor(spritesheet, toolImages){
        this.spritesheet = spritesheet;
        this.toolImages = toolImages;

        this.rows = 25;
        this.cols = 25;
        this.size = 16;

        this.extra = this.size *3;//extra on the bottom

        this.w = this.cols * this.size;
        this.h = this.rows * this.size + this.extra;


        this.buffer = document.createElement('canvas').getContext('2d', { alpha:false, desynchronized:true });
        this.buffer.imageSmoothingEnabled = false;
        this.buffer.canvas.width = this.cols * this.size;
        this.buffer.canvas.height = this.rows * this.size + this.extra;
        this.buffer.canvas.style.imageRendering =  'pixelated'
        this.buffer.imageSmoothingEnabled = false;

        this.map = [];//2d map object, not important
        
    }
    addRow(){
        this.rows++;
        this.h = this.rows * this.size + this.extra;
        this.map[this.rows-1] = [];
        for(let i = 0; i < this.rows; i++){
            this.map[this.rows-1][i] = 'blank';
        }
        this.buffer.canvas.height = this.rows * this.size + this.extra;
        console.log('adding: ' + this.rows);
    };
    delRow(){
        this.rows--;
        this.h = this.rows * this.size + this.extra;
        this.buffer.canvas.height = this.rows * this.size + this.extra;

        delete this.map[this.rows];
        console.log('deleting: ' + this.rows);
    };

    drawToBuffer(cutx, cuty, pasteX, pasteY, mult = 1){
        this.buffer.drawImage(this.spritesheet, cutx, cuty, this.size, this.size, pasteX, pasteY, this.size * mult, this.size * mult);
        
    }
    prepare(){
        this.buffer.clearRect(0,0,this.buffer.canvas.width,this.buffer.canvas.height);
        this.buffer.fillStyle = '#00131B';
        this.buffer.fillRect(0,0,this.buffer.canvas.width,this.buffer.canvas.height);
        this.buffer.fillStyle = '#000000';
        this.buffer.fillRect(0, this.buffer.canvas.height - this.extra + 1, this.buffer.canvas.width, this.size-2);

        let amount = Math.floor(this.buffer.canvas.width/6);

        let Y = this.size * (this.rows +1);
        let S;
        this.buffer.fillStyle = '#555555';
        switch(this.editorShow){
        //there are more tabs, but they all look like this one:

            case 'walls':
                S = (this.w - this.size*2)/4;
                this.drawToBuffer(0, 25*this.size,  0, Y, 2);
                this.drawToBuffer(0, 27*this.size,  S, Y, 2);
                this.drawToBuffer(0, 28*this.size,S*2, Y, 2);
                this.drawToBuffer(0, 29*this.size,S*3, Y, 2);
                this.drawToBuffer(0, 30*this.size,S*4, Y, 2);
            break;
        }
//toolbar images
        this.buffer.drawImage(this.toolImages[0], 3, this.buffer.canvas.height - this.extra);
        this.buffer.drawImage(this.toolImages[1], amount+3, this.buffer.canvas.height - this.extra);
        this.buffer.drawImage(this.toolImages[2], amount*2+3, this.buffer.canvas.height - this.extra);
        this.buffer.drawImage(this.toolImages[3], amount*3+3, this.buffer.canvas.height - this.extra);
        this.buffer.drawImage(this.toolImages[4], amount*4+3, this.buffer.canvas.height - this.extra);
        this.buffer.drawImage(this.toolImages[5], amount*5+3, this.buffer.canvas.height - this.extra);

    }
    render(context){
        context.drawImage(this.buffer.canvas,0,0);
    }

}

这是主要代码(即浏览器中的运行):

const context = document.querySelector('canvas').getContext('2d');


window.setInterval(()=>{
   context.clearRect(0,0,context.canvas.width,context.canvas.height);
   context.canvas.style.imageRendering = 'pixelated';
   context.canvas.width = currentEditor.w;
   context.canvas.height = currentEditor.h;
   currentEditor.prepare();
   currentEditor.render(context);
   resizeLevel(currentEditor.w, currentEditor.h);
}, 1000/60);

//the resize function
function resizeLevel(w,h) {

    // Get the height and width of the window
    var height = document.documentElement.clientHeight;
    var width  = document.documentElement.clientWidth;

    let width_height_ratio = w / h;
    // This makes sure the DISPLAY canvas is resized in a way that maintains the MAP's width / height ratio.
    if (width / height < width_height_ratio) height = Math.floor(width  / width_height_ratio);
    else                                         width  = Math.floor(height * width_height_ratio);

    // This sets the CSS of the DISPLAY canvas to resize it to the scaled height and width.
    context.canvas.style.height = height + 'px';
    context.canvas.style.width  = width  + 'px';
    //this centers the canvas
    context.canvas.style.marginTop = (innerHeight/2 - height/2) + 'px';
    context.canvas.style.marginLeft = (innerWidth/2 - width/2) + 'px';
   
}

所有图像一开始都很清晰,但每当我添加或减去行或列时,所有缩放 2 (this.drawToBuffer(w, x , y, z, 2)) 的图像都会变得模糊,即使我添加一行并删除一行。

之前:

之后:

我希望图像像第一个一样,清晰且像素化,无论我尝试什么,放大后的图像看起来都不清晰,我确保它们都是整数,设置缓冲区的图像渲染为 pixelated,并关闭 imageSmothingEnabled.

这是完整的网站:http://labyrinth-sweeper.herokuapp.com/
这是完整的代码:https://github.com/Hello-World25/Amaze-V2

如何让这些缩放后的图像看起来清晰?

只要调整 canvas 的大小时,它的上下文就会被重置,这意味着 imageSmoothingEnabled 回到默认值 true。确保在调整大小后和下一次 drawImage 调用之前将其设置回 false