2016-08-25 8 views
5

Ich habe eine HTML5-Leinwand, auf der ich ein Bild von einem Svg zeichne.JavaScript: toDataUrl() wirft "Sicherheitsfehler: Tainted Canvases können nicht exportiert werden."

HTML

<canvas id="canvas" width="600" height="320"></canvas> 

JavaScript

var DOMURL = window.URL || window.webkitURL || window; 

var data = '<svg xmlns="http://www.w3.org/2000/svg" width="600" height="320">'+ 
        '<foreignObject width="100%" height="100%">'+ 
         '<style>'+ 
          'foreignObject {'+ 
           'background-color: #000;'+ 
           'color: #fff'+ 
           'border-radius: 10px;'+ 
          '}'+ 
          'h1 {'+ 
           'color: #2acabd;'+ 
           'font: 25px arial;'+ 
           'font-weight: bold;'+ 
           'text-align: center;'+ 
          '}'+ 
          'h2 {'+ 
           'margin: 0;'+ 
           'color: #2acabd;'+ 
           'font: 15px arial;'+ 
          '}'+ 
          'p {'+ 
           'color: #fff;'+ 
          '}'+ 
         '</style>'+ 
         '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size: 40px;">'+ 
          '<h1>Heading</h1>'+ 
          '<div>'+ 
           '<div id="details-wrapper">'+ 
            '<h2>Full Name</h2>'+ 
            '<p>Alan Johnson</p>'+ 

            '<h2>Date of Birth</h2>'+ 
            '<p>7th November 1988</p>'+ 

            '<p><span id="user-id">34329483028493284093284432</span></p>'+ 
           '</div>'+ 
          '</div>'+ 
         '</div>'+ 
        '</foreignObject>'+ 
       '</svg>'; 


var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d"); 
img = new Image(); 
img.setAttribute("crossOrigin", "anonymous"); 
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'}); 
var url = DOMURL.createObjectURL(svg); 

img.onload = function() { 
    ctx.drawImage(img, 0, 0); 
    DOMURL.revokeObjectURL(url); 
    console.log(canvas.toDataURL()); 
} 
img.src = url; 

(JS Fiddle: https://jsfiddle.net/LondonAppDev/qnpcg8th/1/)

Als ich canvas.toDataURL() nennen, erhalte ich die Ausnahme:

012.351.
(index):98 Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. 

Ich habe die vielen anderen Fragen und Antworten zu Stack Overflow in Bezug auf diese Ausnahme gesehen. Mein Problem ist anders, weil ich (wie Sie sehen können) zu keinem Zeitpunkt irgendwelche Bilder von einer anderen Domain in meinem Svg oder Canvas aufnehmen.

Ich vermute das Problem ist, dass ich eine Objekt URL mit DOMURL.createObjectURL erstellen.

Ich bin mir bewusst, dass es Kompatibilitätsprobleme in verschiedenen Browsern gibt, jedoch muss diese App nur in Chrome ausgeführt werden. Auch das Zeichnen des Textes direkt auf die Leinwand ist keine Option, ich muss es über eine SVG tun.

Irgendwelche Ideen, wie ich dieses Problem umgehen und erfolgreich ein PNG meiner Leinwand bekommen kann?

+1

Haben Sie versucht, eine Daten-URL anstelle von createObjectURL zu verwenden? – Bergi

Antwort

12

Ich löste dies durch Umwandlung der Svg in eine Daten-URL anstelle von einem Blob.

entfernt I var url = DOMURL.createObjectURL(svg); und ersetzt img.src = url; mit diesem:

function buildSvgImageUrl(svg) { 
    b64 = window.btoa(svg); 
    return "data:image/svg+xml;base64," + b64; 
} 

img.src = buildSvgImageUrl(data); 

Jetzt funktioniert es einwandfrei.

+0

Oooooh danke !!!!! du hast meinen Tag gerettet ! –

+0

Ich habe gesucht und gesucht, endlich habe ich mich selbst "deine Lösung" erstellt und wollte "meine Idee" teilen, also nach einer Frage suchen und deine Antwort finden, verrückt :) –

1

Diese istwar für Sicherheit und Privatsphäre des Benutzers.
Um eine <foreignObject> auf einer Leinwand zu malen, können mehrere Informationen über Benutzer und bis dahin, Chrome-Team dachte, sie hatten nicht genug Sicherheitsmaßnahmen, dies zu verhindern, so dass sie die Leinwand verschmutzt.

Hier ist die chromium bug report über dieses Problem.

Aber wie OP herausgefunden hat, hatten sie einen Implementierungsfehler, der vergessen hat, diese Beschränkung für DataURI-Versionen zu setzen.
Ich habe diese bug report über die Tatsache, dass sie Canvas mit DataURIs nicht verschmutzen.

All dies führte zu der Hebelwirkung der früheren Beschränkungen, so dass wir in den nächsten Versionen von Chrom in der Lage sein sollten, <foreignObject> auf Leinwand zu malen, ohne es zu verunstalten, sogar mit BlobURIs.

Aber beachten Sie, dass Safari immer noch die gleiche Einschränkung hat (ohne den Implementierungsfehler, d.e der DataURI Hack funktioniert nicht dort), und dass IE < Edge <foreignObject> Element nicht unterstützt und die Canvas beschädigt, wenn eine SVG wurde darauf gemalt, und dass FF alle UserAgent und OS Stile entfernt (was führt zu andere Ergebnisse als die, die Sie erwarten konnten).

Eine echte Abhilfe dann ist das nicht verwenden hacken Ihre Elemente gemalt zu bekommen, aber ziehen alle Ihre HTML mit CanvasAPI Methoden zeichnen (wie html2canvas tut).

Verwandte Themen