1

I am building an Ionic App and I am getting this error when I try to convert to base64 an image from an URL.

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

My code is the following:

public getBase64Image(imgUrl: string): Promise<string> {
    if (!imgUrl.includes("http")) {
      return;
    }

    return new Promise<string>(resolve => {
      let img = new Image();

      img.src = imgUrl;
      img.crossOrigin = "anonymous"
      img.onload = (() => {
        let canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;
        let ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        let dataURL = canvas.toDataURL("image/png");
        resolve(dataURL);
      });
    });
  }

I've read other questions where setting anonymous in crossOrigin was the solution, but I already have it.

Hope you can help me, thanks.

EDIT 1

As a note, I don't get this the first time that I convert an image to base64 but I get it in the following times I try to edit an image.

Wrong
  • 1,195
  • 2
  • 14
  • 38
  • 1
    Tou may like to read this: [Tainted canvases may not be exported](https://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported) – enxaneta Jan 09 '19 at 11:13
  • I tried that also but not working @enxaneta . I did an edit on the first post – Wrong Jan 09 '19 at 11:18
  • try this plugin: https://ionicframework.com/docs/native/base64/ – Najam Us Saqib Jan 09 '19 at 11:55
  • `ctx.drawImage` is an asynchronus function. Maybe you try to convert it to base64 while its drawing on the canvas. Maybe thats why a conflict happen. You need to be sure, that the context is rendered done. – Jonathan Jan 09 '19 at 12:00
  • @Jonathan here it says it's void, doesn't return a promise https://developer.mozilla.org/es/docs/Web/API/CanvasRenderingContext2D/drawImage – Wrong Jan 09 '19 at 12:06
  • that doesn't work @Najamussaqib , it returns an empty string – Wrong Jan 09 '19 at 12:12
  • Did you try this: https://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported ? – Jonathan Jan 09 '19 at 12:13
  • May this could help you too: https://ourcodeworld.com/articles/read/182/the-canvas-has-been-tainted-by-cross-origin-data-and-tainted-canvases-may-not-be-exported – Jonathan Jan 09 '19 at 12:14
  • @Jonathan Yes but I have no access over the server side – Wrong Jan 09 '19 at 12:18
  • When you say *"but I get it in the following times I try to edit an image"*, you mean you already did load it without the crossOrigin attribute? Then it's a cache issue (and while Chrome guys don not agree, a Chrome bug...). This could happen because your server don't send the proper Allow-Origin:vary headers when no crossOrigin is set, and that the browser will then keep using this resource from cache even when the attribute is set. The solution is to always require your images with the crossOrigin attribute, ir to set up your server correctly (but AWS S3 for one can't be set up in this way) – Kaiido Jan 09 '19 at 13:35
  • @Kaiido I always require it (I think) with the code above. What I don't understand is what you say, why I can do it once without any error but then on the next times I try to download it I get the error. It's an Ionic App, idk how much it's related to Chrome. I've solved it with a different approach on my answer but I'd like to know why this happens. – Wrong Jan 09 '19 at 13:55
  • That may not be what I understood then. You mean that you can load 'img1.jpg', and export it to a dataURL once, but when you try to load again that same 'img1.jpg' it will throw? I actually can't see a reason... [Here is what I thought you were facing](https://stackoverflow.com/questions/49503171/the-image-tag-with-crossorigin-anonymous-cant-load-success-from-s3/49503414#49503414) (don't hesitate to read the linked answer @serverfault, it's worth it). Oh and if in your answer you are talking about [that post](https://stackoverflow.com/a/42916772), then don't be afraid of dropping an upvote ;-) – Kaiido Jan 09 '19 at 14:16
  • Yes, thats what's happening, I get the error if I try to download the same image again. Sadl I don't have control over the server side. This post is what I used https://stackoverflow.com/questions/18650168/convert-blob-to-base64 sry :/ – Wrong Jan 09 '19 at 14:38

1 Answers1

0

Instead of the approach in the first post, I've switched to downloading the image using Angular's HttpClient and then getting its base64.

Code:

public getBase64Image(imgUrl: string): Observable<string> {
    return new Observable(observer => {
      this.http.get(imgUrl, { responseType: 'blob' }).subscribe(data => {
        var reader = new FileReader();
        reader.readAsDataURL(data);
        reader.onloadend = () => {
          observer.next(reader.result.toString().replace(":application/octet-stream;", ":image/png;"));
          observer.complete();
        }
      });
    });
  }
Wrong
  • 1,195
  • 2
  • 14
  • 38