【问题标题】:Low Quality Images in spot motion canvas animation点运动画布动画中的低质量图像
【发布时间】:2014-03-05 11:14:25
【问题描述】:

我正在使用一个 jquery 插件,该插件利用画布绘制点运动动画。(http://arena.palamago.com.ar/spotMotion/)

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

如果您查看下面的 jsfiddle,您会发现图像不清晰,我在视网膜显示器上,它们看起来更糟,原始图像是 800 像素。由于某些未知原因,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);
   }
} 

我见过一些非常复杂的方法,人们编写放大算法,我只是不明白如何将它们组合在一起。如果有人知道如何提高图像质量,请给我一些时间。

谢谢

【问题讨论】:

  • SVG + CSS 动画?
  • 可行,但我想将其应用于更详细的动画,例如人物行走或树木生长金钱。卡通之类的东西,我认为这超出了 SVG 范围?请记住,我也可以使用 GIF 来执行此操作,但这更多是我想要放大画布绘制图像的原则。
  • SVG 可能很复杂。 Google 将所有孩子的图像显示为 svg。 Cool list
  • 这么复杂? goo.gl/zskws2
  • 是的,为什么不呢?只是一堆渐变、贝塞尔曲线和路径。

标签: javascript html animation canvas


【解决方案1】:

问题

原因是源图像太大,无法单次缩小尺寸。

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

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

解决方案

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

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

  2. 在绘制图像之前在客户端处理图像,方法是创建一个屏幕外画布并按 2-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 等函数来计算,但我将把它排除在外,“方程式”):

/// 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/内存明智的)。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 2014-04-12
    • 2017-03-09
    • 1970-01-01
    • 2021-02-07
    相关资源
    最近更新 更多