Los lienzos contaminados no se pueden exportar

187

Quiero guardar mi lienzo en un img. Tengo esta función:

function save() {
    document.getElementById("canvasimg").style.border = "2px solid";
    var dataURL = canvas.toDataURL();
    document.getElementById("canvasimg").src = dataURL;
    document.getElementById("canvasimg").style.display = "inline";
}

Me da error:

SecurityError no capturado: no se pudo ejecutar 'toDataURL' en 'HTMLCanvasElement': los lienzos contaminados no se pueden exportar.

¿Qué tengo que hacer?

usuario3465096
fuente
¿En que navegador? stackoverflow.com/a/21362569/476716 afirma que esto es un error.
OrangeDog
1
en Chrome y
Firefox

Respuestas:

180

Por razones de seguridad, su unidad local se declara como "otro dominio" y manchará el lienzo.

(¡Esto se debe a que su información más confidencial probablemente esté en su disco local!).

Durante las pruebas, pruebe estas soluciones alternativas:

  • Coloque todos los archivos relacionados con la página (.html, .jpg, .js, .css, etc.) en su escritorio (no en subcarpetas).

  • Publique sus imágenes en un sitio que admita el intercambio entre dominios (como dropbox.com). Asegúrese de poner sus imágenes en la carpeta pública de Dropbox y también establecer el indicador de origen cruzado al descargar la imagen (var img = new Image (); img.crossOrigin = "anónimo" ...)

  • Instale un servidor web en su computadora de desarrollo (los servidores web IIS y PHP tienen ediciones gratuitas que funcionan bien en una computadora local).

markE
fuente
16
¡Gracias, configurar la propiedad img.crossOrigin me ayudó!
zumek
55
@markE: cargué datos de imágenes de localStorage en lugar de cargarlos desde un archivo o cualquier url, luego le hice alguna manipulación, como agregar un texto. Luego trató de devolverlo a localStorage usando toDataURL (). Pero muestra "Error al ejecutar 'toDataURL' en 'HTMLCanvasElement': los lienzos contaminados no se pueden exportar". En este caso, no estoy usando ningún archivo exteranl o url para obtener un problema de dominio cruzado. Entonces, ¿por qué está causando este error?
Sajith
2
@Saijth: es posible que desee verificar la ruta utilizada para las imágenes. También tuve este problema porque estaba probando el acceso directo a mi servidor virtual local a través de su IP (127.0.xx /) pero algunas de las imágenes estaban vinculadas a través del dominio (localhost /). Una vez que usé el localhost en su lugar funcionó. Así que asegúrese de no encontrarse con algo así.
Victor D.
1
(1) Visualícelo desde el servidor web xampp, localhost / file en lugar de c: / localdisk / file; entonces Chrome no se quejará de Error de seguridad. (2) O use esta bandera al iniciar Chrome: --allow-file-access-from-files
mosh
1
Simplemente agregue otro posible problema: si está intentando exportar un lienzo que contiene un svg con un ForeignObject, algunos navegadores lo marcarán como contaminado.
HairyFotr
128

En la etiqueta img establezca crossorigin en Anónimo.

<img crossorigin="anonymous"></img>
Annia Martinez
fuente
61
Pero qué hacer en el caso de lienzo html5, no elementos img
graphics123
11
En el caso de un elemento de lienzo, la fuente del problema siempre es con alguna imagen (o imágenes) que está dibujando en él. Por lo tanto, solo necesita rastrear la imagen y establecer su atributo crossOrigin como se indica, antes de cargarla.
Fernando Echeverria
3
Esto me salvó el día!
Chang
1
Feliz de ayudar :)
Annia Martinez
9
su im 12 a.m. en el cargo y que esta respuesta es simple, esto es pura felicidad
Dheeraj
26

Si alguien ve mi respuesta, tal vez en esta condición:

1. Intentando obtener una captura de pantalla de mapa en lienzo usando capas abiertas (versión> = 3)
2. Y vimos el ejemplo de exportación de mapa
3. Usando ol.source.XYZ para representar la capa del mapa

¡Bingo!

Usando ol.source.XYZ.crossOrigin = 'Anónimo' para resolver su confusión. O como el siguiente código:

     var baseLayer = new ol.layer.Tile({
         name: 'basic',
         source: new ol.source.XYZ({
             url: options.baseMap.basic,
             crossOrigin: "Anonymous"
         })
     });
noche
fuente
1
fantástico. Útil para todas las fuentes, como TileImage y también.
Phil
Fatastic! Exactamente lo que estaba buscando, solución fácil para una demostración de OpenLayers que estoy haciendo.
Marc
Estoy usando capas de mosaicos vectoriales y después de agregar esta propiedad a la fuente, ¡pero tampoco funciona!
Mahdi n75
Exactamente lo que necesitaba :)
Ray
17

Si está utilizando la ctx.drawImage()función, puede hacer lo siguiente:

var img = loadImage('../yourimage.png', callback);

function loadImage(src, callback) {
    var img = new Image();

    img.onload = callback;
    img.setAttribute('crossorigin', 'anonymous'); // works for me

    img.src = src;

    return img;
}

Y en su devolución de llamada ahora puede usarlo ctx.drawImagey exportarlo usandotoDataURL

mehulmpt
fuente
66
Esto no funcionó para mí. Aún recibo el Tainted canvases may not be exported.mensaje de error.
Sam Sverko
1
esto funciona para mi. Gracias. @SamSverko asegúrese de establecer el atributo antes de img.src.
aijogja
14

En mi caso, estaba dibujando en una etiqueta de lienzo de un video. Para abordar el error del lienzo contaminado, tuve que hacer dos cosas:

<video id="video_source" crossorigin="anonymous">
    <source src="http://crossdomain.example.com/myfile.mp4">
</video>
  • Asegúrese de que el encabezado Access-Control-Allow-Origin esté configurado en la respuesta de la fuente de video (configuración adecuada de crossdomain.example.com)
  • Configure la etiqueta de video para que tenga crossorigin = "anónimo"
jdramer
fuente
5

Parece que está utilizando una imagen de una URL que no ha configurado el encabezado correcto de Access-Control-Allow-Origin y, por lo tanto, el problema. Puede obtener esa imagen de su servidor y obtenerla de su servidor para evitar problemas de CORS.

Prasanna Aarthi
fuente
¿Podría ser más preciso sobre su respuesta, porque realmente no conozco todo ese concepto? ¿Cómo obtengo esa imagen de mi servidor?
user3465096
¿desde dónde estás buscando esa imagen, es desde tu servidor o algún otro?
Prasanna Aarthi
Va así: loadImage ("ejemplo.jpg", 0, 0, 500, 300); Puedo poner url o imagen de imagen aleatoria en la misma carpeta en mi computadora, sigue siendo la misma
user3465096
Sí, pero yo sólo imagen creada en la pintura y todavía es el mismo
user3465096
1
Di Access-Control-Allow-Origin: * para el archivo, pero aún muestra el error
Harikrishnan
5

Resolví el problema usando la useCORS: trueopción

 html2canvas(document.getElementsByClassName("droppable-area")[0], { useCORS:true}).then(function (canvas){
        var imgBase64 = canvas.toDataURL();
        // console.log("imgBase64:", imgBase64);
        var imgURL = "data:image/" + imgBase64;
        var triggerDownload = $("<a>").attr("href", imgURL).attr("download", "layout_"+new Date().getTime()+".jpeg").appendTo("body");
        triggerDownload[0].click();
        triggerDownload.remove();
    });
Ahmad Zahabi
fuente
3

Echa un vistazo a [imagen habilitada CORS] [1] de MDN. Básicamente, debe tener un servidor que aloje imágenes con el encabezado apropiado Access-Control-Allow-Origin.

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>

Podrá guardar esas imágenes en el almacenamiento DOM como si se hubieran servido desde su dominio; de lo contrario, se encontrará con un problema de seguridad.

var img = new Image,
    canvas = document.createElement("canvas"),
    ctx = canvas.getContext("2d"),
    src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"; // insert image url here

img.crossOrigin = "Anonymous";

img.onload = function() {
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage( img, 0, 0 );
    localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// make sure the load event fires for cached images too
if ( img.complete || img.complete === undefined ) {
    img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    img.src = src;
}

BerlinaLi
fuente
Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden volverse inválidas si la página vinculada cambia. - De la opinión
Gowtham Shiva
Gracias por la noticia. Acabo de agregar el contenido del enlace de MDN :)
BerlinaLi
1

Solo como una compilación de la respuesta de @ markE, si desea crear un servidor local. No tendrá este error en un servidor local.

Si tienes PHP instalado en tu computadora:

  1. Abre tu terminal / cmd
  2. Navegue a la carpeta donde están los archivos de su sitio web
  3. Mientras está en esta carpeta, ejecute el comando php -S localhost:3000← Observe la 'S' mayúscula
  4. Abra su navegador y en la barra de URL vaya a localhost: 3000 . Su sitio web debería estar funcionando allí.

o

Si tiene Node.js instalado en su computadora:

  1. Abre tu terminal / cmd
  2. Navegue a la carpeta donde están los archivos de su sitio web
  3. Mientras esté en esta carpeta, ejecute el comando npm init -y
  4. Ejecutar npm install live-server -go sudo npm install live-server -gen una Mac
  5. Ejecute live-servery debería abrir automáticamente una nueva pestaña en el navegador con su sitio web abierto.

Nota: recuerde tener un archivo index.html en la raíz de su carpeta o de lo contrario podría tener algunos problemas.

Ludolfyn
fuente
0

También resolví este error agregando useCORS : true,mi código como -

html2canvas($("#chart-section")[0], {
        useCORS : true,
        allowTaint : true,
        scale : 0.98,
        dpi : 500,
        width: 1400, height: 900
    }).then();
Jeet
fuente