点动画画布动画中的低质量图像

时间:2014-02-07 21:22:22

标签: javascript html5 animation canvas

我正在使用一个jquery插件来实用画布来绘制点动画动画。(http://arena.palamago.com.ar/spotMotion/

我知道在这种情况下我可以使用动画GIF图像,但我将来使用的图像类型需要更高的质量和透明度。

如果你看下面的jsfiddle,你会看到图像不清晰,我在视网膜显示器上看起来更糟糕,原始图像是800px。由于某些未知原因,Canvas没有足够高地缩放图像。我对画布相当新,并且已经看到了一些扩展缩放的方法,但却没有获得更好的结果。

我查看了画布宽度和画布样式宽度

canvas.width = "200";
canvas.height = "200"; // allow 40 pixels for status bar on iOS
canvas.style.width = "100px";
canvas.style.height = "100px";

我还研究了css图像渲染技术

canvas { image-rendering:optimizeQuality;} 

http://jsfiddle.net/TsAzP/1/

另一种尝试,但我似乎无法将其与此插件整合。

function enhanceContext(canvas, context) {
var ratio = window.devicePixelRatio || 1,
    width = canvas.width,
    height = canvas.height;

   if (ratio > 1) {
    canvas.width = width * ratio;
    canvas.height = height * ratio;
    canvas.style.width = width + "px";
    canvas.style.height = height + "px";
    context.scale(ratio, ratio);
   }
} 

我已经看到一些非常复杂的方法,人们编写扩展算法,我只是不明白如何把它放在一起。如果有人知道如何提高图像质量,请给我一些时间。

谢谢

1 个答案:

答案 0 :(得分:2)

问题

原因是源图像太大而无法在单个缩小范围内缩小尺寸。

当涉及到canvas元素时,浏览器通常使用双向插值而不是双三次插值。

双线性插值分析2x2像素,而双三次使用4x4(在下采样中用作低通滤波器以创建平均像素)。如果图像尺寸减小太陡,则根本没有足够的像素来考虑平均,结果将部分“波动”或像素化。

解决方案

要解决此问题,您可以执行以下步骤之一:

  1. 在图像编辑器(例如Photoshop)中以较小的尺寸准备图像,并将图像缩放到您想要使用的目标尺寸(参见视网膜显示)。

  2. 在绘制之前在客户端处理图像,方法是创建一个离屏画布,然后按2-3步缩小图像。

  3. 由于各种原因,第一步可能是更好的解决方案,例如:

    • 客户端
    • 上不会处理图像(尺寸)
    • 生成图像的质量(更易于后处理)
    • 带宽减少(传输的数据减少)
    • 更快地处理客户端上的图像(正在使用中)
    • 节省电池电量(减少处理)

    至于第二步:小提琴中有太多代码(TL; TR),但原理如下(并不是那么复杂):

    /// create two temporary canvas elements
    var ocanvas = document.createElement('canvas'),  /// off-screen canvas
        tcanvas = document.createElement('canvas'),  /// temp canvas
        octx = ocanvas.getContext('2d'),
        tctx = ocanvas.getContext('2d');
    

    然后我们对图像进行第一次降压缩放 - 对于这个例子,我们将做两次这是所需的最小值。如果尺寸差异很大,你可能需要第三步(你通常可以通过使用log等功能来计算它,但我会把它留在um之外,这里的“等式”):

    /// use temp canvas (tcanvas) to scale for the first step
    tcanvas.width = img.width * 0.5;    /// 50% allow good result with bi-linear
    tcanvas.height = img.height * 0.5;
    
    /// draw image into canvas
    tctx.drawImage(img, 0, 0, tcanvas.width, tcanvas.height);
    

    下一步就像上面那样简单但绝对大小:

    /// set destination size
    ocanvas.width = 200;
    ocanvas.height = 200;
    
    /// draw temp canvas into canvas
    octx.drawImage(tcanvas, 0, 0, ocanvas.width, ocanvas.height);
    

    您现在可以在解决方案中使用ocanvas而不是img

    我们使用两个画布,因为我们希望稍后使用最终的ocanvas直接替换img以适当的大小。如果我们使用一个画布,我们将不得不在最后一步调整它,这意味着画布将被清除。

    如果您确实需要第三步,那么您可以重复使用其中一幅画布。

    这里的附加优势是浏览器在动画时无需缩放任何内容,从而减少了CPU / GPU的负担。

    我建议在函数内部执行此缩减操作,以便在使用后浏览器可以轻松地丢弃临时画布引用(您需要使用的pf课程除外)(GC /内存)明智)。

    希望这有帮助!