简体   繁体   English

HTML5 Canvas drawImage大小调整问题

[英]HTML5 Canvas drawImage resizing issues

When I resize an image that I pull from a specific location on a spritesheet using drawImage, it appears as if drawImage will sometimes pull outside the source x + source y / swidth + sheight boundaries. 当我使用drawImage 调整从Spritesheet上的特定位置拉出的图像的大小时 ,似乎drawImage有时会拉出源x +源y /宽度+高度边界。

The following jfiddle illustrates what is happening: https://jsfiddle.net/cxuxyLj2/ 以下jfiddle说明了正在发生的事情: https ://jsfiddle.net/cxuxyLj2/

The pertinent code is as follows: 相关代码如下:

drawingSurface.drawImage(heroSprite, 0, 64, 32, 64, 20, 144, 32, 64);
drawingSurface.drawImage(heroSprite, 0, 64, 32, 64, 20+50, 144, 32*2, 64*2);

There are lines that show above the RESIZED sprite's head (probably pulling the shoe of the same character on the first row), but not the original sprite's head. 在RESIZED Sprite的头部上方显示了一些线(可能在第一行中拖动了具有相同角色的鞋子),但没有显示原始Sprite的头部。

My question is - can it be confirmed that this is a legitimate drawImage error, or am I doing something wrong? 我的问题是-是否可以确认这是合法的drawImage错误,还是我做错了什么?

It's actually because of the anti-alias when rescaling your sprite. 实际上,这是因为调整精灵大小时的抗锯齿功能。
Because you do draw in a loop, without ever clearing the context, the anti-alias artifacts becomes bigger and bigger : 因为您确实是在循环中绘制,而不需要清除上下文,所以抗锯齿工件变得越来越大:

 var canvas = document.querySelector("canvas"); var drawingSurface = canvas.getContext("2d"); var heroSprite = new Image(); heroSprite.src = "http://gopus.xepher.net/game/gfx/herosprite7.png"; render(); function render () { setTimeout(render, 1000); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 20, 25, 32, 64); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 20+50, 25, 32*2, 64*2); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 150.6666687774, 25.33333222227, 32,64); } 
 <canvas width="400" height="400" style="border:1px solid #000"></canvas> 

You could avoid it by setting the imageSmoothingEnabled flag to false but it wasn't supported in IE prior to 10 ... 您可以通过将imageSmoothingEnabled标志设置为false来避免这种情况,但是在IE 10之前的版本中不支持它...

 var canvas = document.querySelector("canvas"); var drawingSurface = canvas.getContext("2d"); drawingSurface.mozImageSmoothingEnabled = false; drawingSurface.webkitImageSmoothingEnabled = false; drawingSurface.msImageSmoothingEnabled = false; drawingSurface.imageSmoothingEnabled = false; var heroSprite = new Image(); heroSprite.src = "http://gopus.xepher.net/game/gfx/herosprite7.png"; render(); function render() { setTimeout(render, 16); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 20, 25, 32, 64); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 20 + 50, 25, 32 * 2, 64 * 2); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 150.6666687774, 25.33333222227, 32, 64); } 
 <canvas width="400" height="400" style="border:1px solid #000"></canvas> 

...or by clearing the canvas at each call, you may avoid the artifacts to grow, but there will still be natural ones... ...或通过在每次调用时清除画布,可以避免工件增长,但是仍然会出现自然现象...

 var canvas = document.querySelector("canvas"); var drawingSurface = canvas.getContext("2d"); var heroSprite = new Image(); heroSprite.src = "http://gopus.xepher.net/game/gfx/herosprite7.png"; render(); function render() { setTimeout(render, 16); drawingSurface.clearRect(0,0,canvas.width, canvas.height); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 20, 25, 32, 64); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 20 + 50, 25, 32 * 2, 64 * 2); drawingSurface.drawImage(heroSprite, 0, 32, 32, 64, 150.6666687774, 25.33333222227, 32, 64); } 
 <canvas width="400" height="400" style="border:1px solid #000"></canvas> 

... so a final solution would be to use a buffer canvas, to only draw your sprite at normal scale (less anti-aliasing possible), then redraw this buffer canvas at the wanted scale, you will keep in-image's anti-aliasing artifacts, but won't eat the border's of the cropped area anymore : ...所以最后的解决方案是使用缓冲画布,仅以正常比例绘制精灵(可能减少抗锯齿),然后以所需比例重新绘制此缓冲画布,您将保持图像中的抗锯齿文物,但不会再吃掉裁剪区域的边界了:

 var canvas = document.querySelector("canvas"); var drawingSurface = canvas.getContext("2d"); var heroSprite = new Image(); heroSprite.src = "http://gopus.xepher.net/game/gfx/herosprite7.png"; var spriteCanvas = document.createElement('canvas'); var spriteCtx = spriteCanvas.getContext('2d'); var croppedSprite = function(x, y, width, height){ spriteCanvas.width = width; spriteCanvas.height = height; spriteCtx.drawImage(heroSprite, x, y, width, height, 0,0, width, height); return spriteCanvas; } render(); function render() { setTimeout(render, 16); drawingSurface.drawImage(croppedSprite(0, 64, 32, 64), 20, 25, 32, 64); drawingSurface.drawImage(croppedSprite(0, 64, 32, 64), 20 + 50, 25, 32 * 2, 64 * 2); drawingSurface.drawImage(croppedSprite(0, 64, 32, 64), 150.6666687774, 25.33333222227, 32, 64); } 
 <canvas width="400" height="400" style="border:1px solid #000"></canvas> 

Also, you should definitely add more space between your sprites. 另外,您绝对应该在子画面之间添加更多空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM