Html2canvas: Échec de l'exécution de 'toDataURL' sur 'HTMLCanvasElement' : les canevas contaminés ne peuvent pas être exportés.

Créé le 2 août 2018  ·  12Commentaires  ·  Source: niklasvh/html2canvas

var canvasPromise  = html2canvas(document.body, {
                allowTaint: true,
                useCORS: true
            });
canvasPromise.then(function(canvas) {
    document.body.appendChild(canvas);
    console.log(canvas);
    canvas.toDataURL('image/png');
});

Rapports de bogues :

Uncaught (en promesse) DOMException : échec de l'exécution de 'toDataURL' sur 'HTMLCanvasElement' : les canevas contaminés ne peuvent pas être exportés.

  • version html2canvas testée avec :
  • Chrome 67.0.3396.99
  • Windows 10

Commentaire le plus utile

J'ai aussi les mêmes problèmes.
Avez-vous trouvé une solution ou un contournement ?

Tous les 12 commentaires

J'ai aussi les mêmes problèmes.
Avez-vous trouvé une solution ou un contournement ?

je fais la même chose dans Firefox 61.0.2 et j'obtiens une erreur de sécurité malgré la définition de allowTaint sur true

Pas de solution à ma connaissance, mais j'ai une solution de contournement : changez chaque image en base64. De cette façon, vous pouvez le rendre dans le canevas même s'il provient d'un domaine différent.

Avez-vous vu ceci : CORS_enabled_image

Si la source du contenu étranger est un HTML élément, tenter de récupérer le contenu du canevas n'est pas autorisé.

Dès que vous dessinez dans un canevas des données qui ont été chargées à partir d'une autre origine sans l'approbation de CORS, le canevas devient corrompu.

J'utilise les options de configuration comme ceci :

html2canvas(document.body, {
    allowTaint: true,
    foreignObjectRendering: true
});

Bonjour, nous avons rencontré le même problème. Nous avons suivi la suggestion de @dorklord23 car nous avions déjà une URL proxy qui a effectué la conversion.

Si quelqu'un l'a trouvé utile, la solution était :

      html2canvas(document.body, {
        proxy: this._proxyURL,
        allowTaint: true,
        onclone: (cloned) => convertAllImagesToBase64(this._proxyURL, cloned),
      }).then((canvas) => {
        this._postmessageChannel.send(`get.screenshot:${canvas.toDataURL('image/png')}`);
      });

Où se trouve la fonction d'assistance convertAllImagesToBase64 :

const convertAllImagesToBase64 = (proxyURL, cloned) => {
  const pendingImagesPromises = [];
  const pendingPromisesData = [];

  const images = cloned.getElementsByTagName('img');

  for (let i = 0; i < images.length; i += 1) {
    // First we create an empty promise for each image
    const promise = new Promise((resolve, reject) => {
      pendingPromisesData.push({
        index: i, resolve, reject,
      });
    });
    // We save the promise for later resolve them
    pendingImagesPromises.push(promise);
  }

  for (let i = 0; i < images.length; i += 1) {
    // We fetch the current image
    fetch(`${proxyURL}?url=${images[i].src}`)
      .then((response) => response.json())
      .then((data) => {
        const pending = pendingPromisesData.find((p) => p.index === i);
        images[i].src = data;
        pending.resolve(data);
      })
      .catch((e) => {
        const pending = pendingPromisesData.find((p) => p.index === i);
        pending.reject(e);
      });
  }

  // This will resolve only when all the promises resolve
  return Promise.all(pendingImagesPromises);
};

export { convertAllImagesToBase64 };

Soit dit en passant, voici les tests pour cette fonction d'assistance (nous utilisons jest pour écrire les packages test et mockFetch):

import { convertAllImagesToBase64 } from '../images';

fetch.resetMocks();

// Mock fetch to respond different for each image so we can assert that the image return the correct response
// Also make one of the response be delayed (2 seconds) to simulate the response is not in the same order we do the call (network latency, image size, etc)
fetch.mockImplementation((url) => {
  if (url.includes('imagesrc1')) {
    return Promise.resolve(new Response(JSON.stringify('data:image/png;base64,1')));
  } else if (url.includes('imagesrc2')) {
    return new Promise((resolve) => setTimeout(resolve(new Response(JSON.stringify('data:image/png;base64,2'))), 2000));
  } else if (url.includes('imagesrc3')) {
    return Promise.resolve(new Response(JSON.stringify('data:image/png;base64,3')));
  }
  return Promise.resolve(new Response(JSON.stringify('')));
});

const mocksImages = [
  { id: 1, src: 'imagesrc1' },
  { id: 2, src: 'imagesrc2' },
  { id: 3, src: 'imagesrc3' },
];

const mockClone = {
  getElementsByTagName: jest.fn(() => mocksImages),
};

describe('utils/images', () => {  
  it('convertAllImagesToBase64. Expect to call 3 times to the correct enpoint using the image source', async () => {
    const allPromises = convertAllImagesToBase64('http://localhost/fake_proxy', mockClone);

    // Expect the clone elements gets all the image tags
    expect(mockClone.getElementsByTagName).toBeCalledWith('img');

    allPromises.then(() => {
      // Expect to have done the 3 fetch calls and with the correct params
      expect(fetch).toBeCalledTimes(3);
      expect(fetch).toHaveBeenNthCalledWith(1, 'http://localhost/fake_proxy?url=imagesrc1');
      expect(fetch).toHaveBeenNthCalledWith(2, 'http://localhost/fake_proxy?url=imagesrc2');
      expect(fetch).toHaveBeenNthCalledWith(3, 'http://localhost/fake_proxy?url=imagesrc3');

      // Expect that our images where updated properly
      expect(mocksImages).toContainEqual({
        id: 1, src: 'data:image/png;base64,1',
      });
      expect(mocksImages).toContainEqual({
        id: 2, src: 'data:image/png;base64,2',
      });
      expect(mocksImages).toContainEqual({
        id: 3, src: 'data:image/png;base64,3',
      });
    });
  });
});

Point d'accès principal Ruby :

require 'base64'
require 'net/http'

module Api
  module V1
    class ImageProxyController < ApiController
      def index
        url   = URI.parse(params[:url])
        image = Net::HTTP.get_response(url)

        render json: data_url(image).to_json, callback: params[:callback]
      end

      private

        def data_url(image)
          "data:#{image.content_type};base64,#{Base64.encode64(image.body)}"
        end

    end
  end
end

J'espère que quelqu'un trouvera cela utile. J'espère que cela aidera quelqu'un à ne pas investir autant de temps que nous pour résoudre ce problème correctement.

Si vous pouvez voir une amélioration, veuillez suggérer.
Salutations.

Si vous aimez ci-dessous, que se passera-t-il ?

const TempImage = window.Image

 const Image = function() {
        const img = new TempImage()
        img.crossOrigin = 'anonymous'
        return img
 }

J'ai trouvé une solution et ça marche

  1. Lors de l'appel de html2canvas, passez useCORS true
    html2canvas(selectorElement, {useCORS:true} ).then(canvas => {
    //faire quelque chose
    });

  2. Corrigez le fichier html2canvas.js. Il y a une faute de frappe
    Remplacez "anonyme" par "Anonyme" dans ce bloc if
    if (isInlineBase64Image(src) || ​​useCORS) {
    img.crossOrigin = 'Anonyme';
    }

var canvasPromise  = html2canvas(document.body, {
                allowTaint: true,
                useCORS: true
            });
canvasPromise.then(function(canvas) {
    document.body.appendChild(canvas);
    console.log(canvas);
    canvas.toDataURL('image/png');
});

Rapports de bogues :

Uncaught (en promesse) DOMException : échec de l'exécution de 'toDataURL' sur 'HTMLCanvasElement' : les canevas contaminés ne peuvent pas être exportés.

  • version html2canvas testée avec :
  • Chrome 67.0.3396.99
  • Windows 10

Vous devrez utiliser uniquement la propriété 'useCORS: true', si vous utilisez la propriété 'allowTaint: true' vous autorisez à transformer votre toile en une toile contaminée

UTILISEZ CECI:

var canvasPromise  = html2canvas(document.body, {
                useCORS: true
            });
canvasPromise.then(function(canvas) {
    document.body.appendChild(canvas);
    console.log(canvas);
    canvas.toDataURL('image/png');
});

AU LIEU DE CELA:

var canvasPromise  = html2canvas(document.body, {
                allowTaint: true,
                useCORS: true
            });
canvasPromise.then(function(canvas) {
    document.body.appendChild(canvas);
    console.log(canvas);
    canvas.toDataURL('image/png');
});

Bonjour, beau travail pour html2canvas.

Je suis malheureusement confronté au même problème, est-ce que quelqu'un a résolu ce problème ?
Déjà essayé @motarock et tout avant cela, plus des combinaisons, etc. L'image est blanche sans rien peint.

downloadQRCode = (fileName) => {
    html2canvas(document.getElementById('generated-qr-code'), {
      useCORS: true,
      // allowTaint: false,
      // logging: true,
    }).then((canvas) => {
      // document.body.appendChild(canvas); // checking
      const data = canvas.toDataURL('image/jpeg');
      const element = document.createElement('a');
      element.setAttribute('href', data);
      element.setAttribute('download', fileName + '.jpeg');
      document.body.appendChild(element);
      element.click();
      // document.body.removeChild(element);
      console.log("%c data", "font-size:2em;", data, fileName);
      console.log("%c canvas", "font-size:2em;", canvas );
      this.setState({
        imageSrc: data // setting the src of a img tag to check the result. Nothing in it either..
      })
    });

Merci d'avance

J'ai aussi les mêmes problèmes.
Quelqu'un peut-il résoudre ce problème ?

:( même problème. nous avons html avec svg imbriqué et il ne sera pas rendu

Déjà essayé @motarock et tout avant cela, plus des combinaisons, etc. L'image est blanche sans rien peint.

J'ai ce problème lorsque je n'utilise pas SSL, avec SSL fonctionne parfaitement

Cette page vous a été utile?
0 / 5 - 0 notes