2014-06-24 4 views
5

Ich benutze Raphael, um ein Objekt zu zeichnen, dann übertrage es auf ein HTML-Canvas-Element mit Canvg, so dass ich toDataURL verwenden kann, um es als PNG zu speichern. Aber wenn ich canvg benutze, ist das resultierende Bild verschwommen. Der folgende Code, zum Beispiel erzeugt diesen (raphael oben, unten canvg):Canvas von canvg generiert ist verschwommen auf Retina-Bildschirm

enter image description here

<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> 

Die blurriness im PNG evident als auch durch toDataURL erstellt. Irgendeine Idee, was hier vor sich geht? Ich glaube nicht, dass das etwas mit der Größenanpassung zu tun hat. Ich habe versucht, ignoreDimensions: True und einige andere Dinge zu setzen.

Ein weiterer Datenpunkt. Wenn ich raphael verwende, um etwas Text auszugeben und dann canvg zu verwenden, ist es nicht nur verschwommen, sondern auch die falsche Schriftart!

enter image description here

Und hier die test.rect ist (0.5,0.5,50,50) vorgeschlagen. Noch verschwommen:

enter image description here

+0

Es scheint viel weniger verschwommen sein, wenn das Rechteck ziemlich groß ist. Ansonsten habe ich nicht viel herausgefunden. – AustinC

+0

Ohne irgendwelche Tests zu machen frage ich mich, was das Ergebnis ist, wenn die Strichbreite 2px ist. Ich wette, Sie haben es mit einem Problem mit einem halben Pixel zu tun. – ericjbasti

+0

Wie sieht der toDataURL-Code aus? Stellen Sie sicher, dass es nicht auf JPEG eingestellt ist. JPEGs saugen bei Strichzeichnungen. – ericjbasti

Antwort

9

So dauerte es eine Weile, aber dann dämmerte es mir. Alle Ihre Beispielbilder sind doppelt so groß, wie der Code angibt. Sie sind also am ehesten auf einer Art HDPI-Gerät (Retina MacBook Pro ect ...) SVG ist großartig, weil seine Auflösung unabhängig ist, Canvas auf der anderen Seite nicht. Das Problem, das Sie sehen, hat damit zu tun, wie Canvas rendert. Um dies zu beheben, müssen Sie die Zeichenfläche so vorbereiten, dass die Zeichnung mit der Auflösung Ihres Bildschirms erstellt wird.

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

sollte Dieses jsbin Beispiel auf jedem Bildschirm sehen toll aus.

Der Trick:

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; 

dies das Problem erklären sollten Sie haben, und Sie hoffentlich in einer guten Richtung zeigen, um es zu beheben.

+0

Danke für das schöne Beispiel Eric! – AustinC

3

Eine andere Lösung beschrieben in this article, ähnlich dem hier gepostet, außer es scale() mit und es ist unter Berücksichtigung der Pixelverhältnis des Sicherungsspeicher (Browser Speicherung der Leinwand Underlying):

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'; 
+0

Arbeitete wie ein Zauber, danke! –