为什么在相同 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
。
在我正在处理的 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
。