【问题标题】:Canvas generated by canvg is blurry on retina screen由canvg生成的画布在视网膜屏幕上模糊
【发布时间】:2014-08-15 05:08:15
【问题描述】:

我正在使用 Raphael 绘制一个对象,然后使用 canvg 将其传输到 HTML 画布元素,以便我可以使用 toDataURL 将其保存为 PNG。但是当我使用canvg时,生成的图像是模糊的。例如,下面的代码会生成这个(顶部是 raphael,底部是 canvg):

<html>
    <head>
        <script src="lib/raphael-min.js"></script>
        <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script> 
        <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/StackBlur.js"></script>
        <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script> 
        <script src="lib/raphael.export.js"></script>
    </head>
    <body>

    <div id="raph_canvas"></div><br> 
    <canvas id="html_canvas" width="50px" height="50px"></canvas>

    <script language="JavaScript">
    var test=Raphael("raph_canvas",50,50);
    var rect=test.rect(0,0,50,50);
    rect.attr({fill: '#fff000', 'fill-opacity':1, 'stroke-width':1})

    window.onload = function() {
        var canvas_svg = test.toSVG();
        canvg('html_canvas',canvas_svg);
        var canvas_html = document.getElementById("html_canvas");
    }

    </script>
    </body>
</html>

toDataURL 创建的 png 中的模糊也很明显。知道这里发生了什么吗?我认为这与重新调整大小无关。我试过设置 ignoreDimensions: True 和其他一些东西。

另一个数据点。如果我用raphael输出一些文字再用canvg,不仅模糊而且字体不对!

这里是建议的 test.rect(0.5,0.5,50,50)。仍然模糊:

【问题讨论】:

  • 如果矩形很大,它似乎不那么模糊。除此之外,我没有发现太多。
  • 不做任何测试我想知道当笔画宽度为2px时结果是什么。我打赌你正在处理半像素问题。
  • toDataURL 代码是什么样的?确保它没有设置为 JPEG。 JPEG 不擅长线条艺术。
  • 我无法为你提供这个 canvg 库(在这个问题之前从未听说过它).. 但在这里你可以看到它通常不是问题。 jsbin.com/liquxiyi/2
  • 嘿,您在使用 Retina 设备吗?

标签: javascript canvas svg raphael canvg


【解决方案1】:

所以我花了一段时间,但后来我恍然大悟。您所有的示例图像都是代码声称的大小的两倍。因此,您很可能在某种 HDPI 设备(Retina MacBook Pro 等)上使用 SVG 非常棒,因为它独立于分辨率,而另一方面却不是画布。您看到的问题与画布的渲染方式有关。要解决此问题,您需要准备画布,以便以屏幕分辨率完成绘图。

http://jsbin.com/liquxiyi/3/edit?html,js,output

这个 jsbin 示例在任何屏幕上都应该看起来很棒。

诀窍:

var cv = document.getElementById('box');
var ctx = cv.getContext("2d");

// SVG is resolution independent. Canvas is not. We need to make our canvas 
// High Resolution.

// lets get the resolution of our device.
var pixelRatio = window.devicePixelRatio || 1;

// lets scale the canvas and change its CSS width/height to make it high res.
cv.style.width = cv.width +'px';
cv.style.height = cv.height +'px';
cv.width *= pixelRatio;
cv.height *= pixelRatio;

// Now that its high res we need to compensate so our images can be drawn as 
//normal, by scaling everything up by the pixelRatio.
ctx.setTransform(pixelRatio,0,0,pixelRatio,0,0);


// lets draw a box
// or in your case some parsed SVG
ctx.strokeRect(20.5,20.5,80,80);

// lets convert that into a dataURL
var ur = cv.toDataURL();

// result should look exactly like the canvas when using PNG (default)
var result = document.getElementById('result');
result.src=ur;

// we need our image to match the resolution of the canvas
result.style.width = cv.style.width;
result.style.height = cv.style.height;

这应该可以解释您遇到的问题,并希望为您指明解决问题的好方向。

【讨论】:

  • 感谢 Eric 的好例子!
  • 此响应中没有 canvg。或者 svg 真的。我的最佳猜测与您的答案相结合会产生相同质量的图像
【解决方案2】:

另一个解决方案描述了in this article,与此处发布的类似,除了它使用scale() 并且它考虑了后备存储的像素比(画布的浏览器底层存储):

var devicePixelRatio = window.devicePixelRatio || 1,
    backingStoreRatio = context.webkitBackingStorePixelRatio ||
                        context.mozBackingStorePixelRatio ||
                        context.msBackingStorePixelRatio ||
                        context.oBackingStorePixelRatio ||
                        context.backingStorePixelRatio || 1,

    ratio = devicePixelRatio / backingStoreRatio;

// upscale the canvas if the two ratios don't match
if(devicePixelRatio !== backingStoreRatio){

   // adjust the original width and height of the canvas
   canvas.width = originalWidth * ratio;
   canvas.height = originalHeight * ratio;

   // scale the context to reflect the changes above
   context.scale(ratio, ratio);
}

// ...do the drawing here...

// use CSS to bring the entire thing back to the original size
canvas.style.width = originalWidth + 'px';
canvas.style.height = originalHeight + 'px';

【讨论】:

  • 为什么,使用 CSS 将整个东西恢复到原来的大小?
猜你喜欢
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-13
  • 2015-05-15
  • 2012-11-01
相关资源
最近更新 更多