Html2canvas: 「HTMLCanvasElement」で「toDataURL」の実行に失敗しました:汚染されたキャンバスはエクスポートされない可能性があります。

作成日 2018年08月02日  ·  12コメント  ·  ソース: 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');
});

バグレポート:

Uncaught(in promise)DOMException: 'HTMLCanvasElement'で 'toDataURL'を実行できませんでした:汚染されたキャンバスをエクスポートできない場合があります。

  • テストされたhtml2canvasバージョン:
  • Chrome 67.0.3396.99
  • ウィンドウズ10

最も参考になるコメント

私も同じ問題を抱えています。
解決策または回避策を見つけましたか?

全てのコメント12件

私も同じ問題を抱えています。
解決策または回避策を見つけましたか?

Firefox 61.0.2でも同じことをしていますが、allowTaintをtrueに設定しているにもかかわらず、SecurityErrorが発生します。

私の知る限り解決策はありませんが、回避策があります。すべての画像をbase64に変更します。 そうすれば、元々別のドメインからのものであっても、キャンバスでレンダリングできます。

これを見たことがありますか: CORS_enabled_image

外部コンテンツのソースがHTMLの場合要素、キャンバスのコンテンツを取得しようとすることは許可されていません。

CORSの承認なしに別のオリジンからロードされたデータをキャンバスに描画するとすぐに、キャンバスが汚染されます。

私は次のような構成オプションを使用します:

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

こんにちは、私たちは同じ問題に直面しました。 変換を行うプロキシURLがすでにあるため、 @ dorklord23の提案に従いました。

誰かがそれが役に立ったと思った場合の解決策は次のとおりです。

      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')}`);
      });

ヘルパー関数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 };

ちなみに、これはそのヘルパー関数のテストです(テストとmockFetchパッケージの作成にjestを使用しています):

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',
      });
    });
  });
});

Rubyバックエンドenpdoint:

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

誰かがこれがお役に立てば幸いです。 これを適切に修正するために私たちが行ったほど多くの時間を投資しないようにすることが誰かに役立つことを願っています。

改善が見られる場合は、提案してください。
よろしく。

あなたが以下が好きなら、何が起こりますか?

const TempImage = window.Image

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

解決策を見つけ、それは機能しています

  1. html2canvasを呼び出している間、useCORStrueを渡します
    html2canvas(selectorElement、 {useCORS:true} )。
    //何かをする
    });

  2. html2canvas.jsファイルを修正してください。 タイプミスがあります
    このifブロックで「anonymous」を「Anonymous」に変更します
    if(isInlineBase64Image(src)|| useCORS){
    img.crossOrigin = '匿名';
    }

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

バグレポート:

Uncaught(in promise)DOMException: 'HTMLCanvasElement'で 'toDataURL'を実行できませんでした:汚染されたキャンバスをエクスポートできない場合があります。

  • テストされたhtml2canvasバージョン:
  • Chrome 67.0.3396.99
  • ウィンドウズ10

プロパティ 'useCORS:true'のみを使用する必要があります。プロパティ 'allowTaint:true'を使用する場合は、パーミッションを与えて、キャンバスを汚染されたキャンバスに変換します。

これを使って:

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

これの代わりに:

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

こんにちは、html2canvasの素晴らしい仕事です。

悲しいことに、私は同じ問題に直面しています、誰かがこれを解決しましたか?
すでに@motarockとその前のすべてに加えて、組み合わせなどを試し

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..
      })
    });

前もって感謝します

私も同じ問題を抱えています。
誰でもこの問題を修正できますか?

:(同じ問題。ネストされたsvgを持つhtmlがあり、レンダリングされません

すでに@motarockとその前のすべてに加えて、組み合わせなどを試し

SSLを使用しない場合にこの問題が発生します。SSLを使用すると完全に機能します

このページは役に立ちましたか?
0 / 5 - 0 評価