lukechilds / merge-images

Easily compose images together without messing around with canvas
MIT License
1.68k stars 163 forks source link

DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. #114

Open dcts opened 2 years ago

dcts commented 2 years ago

I wanted to test merging images inside the browser with this code:

index.html

<h1>Testing MergeImages</h1>
<script src="https://unpkg.com/merge-images"></script>
<script>
  window.addEventListener("DOMContentLoaded", () => {
    console.log("Dom + mergeImages loaded ✅");
    console.log(mergeImages);

    const images = [
      "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F0_bg.png?alt=media&token=53eb4b7e-73b7-419b-83c0-32b4d6810e46",
      "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F1_body.png?alt=media&token=7c9e7214-fa87-40d5-a4ad-686a66ee3511",
      "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F2_face.png?alt=media&token=8c728305-664b-4435-8b41-1c7b01530265",
    ];

    mergeImages(images).then(b64 => console.log(b64));
  })
</script>

But I get this error:

DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

My environment:

Did I use the repo wrong or is this a bug? Thanks for any help! :)

melearntodie commented 2 years ago

Hi Have you solved this problem yet?

dcts commented 2 years ago

melearntodie no, this library seems not really up to date.

I used another method to merge images (with vanilla javascript and canvas operations), maybe its usefull to you?

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Merge Images</title>
</head>

<body>
  <h1>Merge Images</h1>
  <canvas id="canvas" width="600" height="600"></canvas>
</body>
</html>

<script>
  let imagesLoaded = 0;
  let canvas, ctx;
  let images;

  // add images you want to overlay
  const imageUrls = [
    "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F0_bg.png?alt=media&token=53eb4b7e-73b7-419b-83c0-32b4d6810e46",
    "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F1_body.png?alt=media&token=7c9e7214-fa87-40d5-a4ad-686a66ee3511",
    "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F2_face.png?alt=media&token=8c728305-664b-4435-8b41-1c7b01530265",
  ];

  document.addEventListener("DOMContentLoaded",() => {
    console.log("DOM LOADED");
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
    images = imageUrls.map(imageUrl => loadImage(imageUrl, drawCanvas))
  });

  function drawCanvas() {
    imagesLoaded += 1;
    if (imagesLoaded === images.length) {
      images.map(image => {
        ctx.drawImage(image, 0, 0, 600, 600);
      })
    }
  }

  function loadImage(src, onload) {
    const img = new Image();
    img.onload = onload;
    img.src = src;
    return img;
  }
</script>

Result

Bildschirmfoto vom 2022-04-05 11-01-19

melearntodie commented 2 years ago

melearntodie no, this library seems not really up to date.

I used another method to merge images (with vanilla javascript and canvas operations), maybe its usefull to you?

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Merge Images</title>
</head>

<body>
  <h1>Merge Images</h1>
  <canvas id="canvas" width="600" height="600"></canvas>
</body>
</html>

<script>
  let imagesLoaded = 0;
  let canvas, ctx;
  let images;

  // add images you want to overlay
  const imageUrls = [
    "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F0_bg.png?alt=media&token=53eb4b7e-73b7-419b-83c0-32b4d6810e46",
    "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F1_body.png?alt=media&token=7c9e7214-fa87-40d5-a4ad-686a66ee3511",
    "https://firebasestorage.googleapis.com/v0/b/homeboard-5d28b.appspot.com/o/smiles.wtf.testing%2F2_face.png?alt=media&token=8c728305-664b-4435-8b41-1c7b01530265",
  ];

  document.addEventListener("DOMContentLoaded",() => {
    console.log("DOM LOADED");
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
    images = imageUrls.map(imageUrl => loadImage(imageUrl, drawCanvas))
  });

  function drawCanvas() {
    imagesLoaded += 1;
    if (imagesLoaded === images.length) {
      images.map(image => {
        ctx.drawImage(image, 0, 0, 600, 600);
      })
    }
  }

  function loadImage(src, onload) {
    const img = new Image();
    img.onload = onload;
    img.src = src;
    return img;
  }
</script>

Result

Bildschirmfoto vom 2022-04-05 11-01-19

cool good solution . thank for shared

stritti commented 2 years ago

I think you have to add crossorigin param to the method because the images are from other domain:

        mergeImages(toMerge, {
            [...]
            crossOrigin: "Anonymous"
          })

See also: https://github.com/lukechilds/merge-images#optionscrossorigin