Ad

Putting Facebook Photos On Canvas, Taint Canvas When Trying To Send It ToDataURL. Can I Set Facebook's Header For CORS?

I am adding facebook photos to a Konva canvas (more or less identical to a HTML5 canvas) and when I try to export the canvas using toDataURL I am given a warning stating the canvas is tainted (specific error below). I know this has to do with trying to export a photo with a different origin than the server but I am curious if I can set the Facebook header to allow cross origins? I haven't seen anything else regarding this in Facebook documentation or from other stackoverflow questions. I feel like it must be doable since other Facebook programs have photo manipulation like this. Does anyone know? Thanks.

Error: "Konva warning: Unable to get data URL. Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported."

Ad

Answer

I've been struggling with this as well. In reading the Mozilla article on CORS (https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image) it seemed like if I did what was suggested by Kaiido above and set the image's crossorigin attribute to "anonymous" that I'd be fine. I had written Javascript to pull down the image from the Facebook-provided URL and stuff it into the canvas. I had great hopes that this would work but I was slapped down by the canvas.

Here's a jsFiddle.net project I did to do a basic test of pulling in images to the canvas where 1 image taints the canvas while the other does not: https://jsfiddle.net/brettjcohen/gdr8wpd0/1/

In reality though I was trying to pull down a Facebook image. I wrote an ASPX page to accept the URL of the Facebook image, pull down the image, turn the image into a base64 encoded string, and return that data to the page. On the page with the canvas I wrote some JavaScript to use AJAX to call the ASPX page and then load the results into an Image object which i could then stuff into the canvas without tainting it.

My ASPX code follows as does a snippet of my JavaScript. The ASPX page was written entirely in the .ASPX page - I deleted the code behind and the designer file.

getimagedata.aspx

<%
    Dim rv As New Dictionary(Of String, Object) From {{"service", "GetImageData"}}
    Try
        Dim url As String = Request.Params("image_url").Trim
        rv.Add("url", url)
        System.Net.ServicePointManager.ServerCertificateValidationCallback = New System.Net.Security.RemoteCertificateValidationCallback(Function(sender As Object, cert As System.Security.Cryptography.X509Certificates.X509Certificate, chain As System.Security.Cryptography.X509Certificates.X509Chain, [error] As System.Net.Security.SslPolicyErrors) True)
        Dim web As New System.Net.WebClient
        'web.Headers.Add("Connection", "Keep-Alive")
        Dim results As Byte() = web.DownloadData(url)
        'rv.Add("downloaded bytes", results.Length)
        'rv.Add("downloaded data", results)
        Dim imgStream As New System.IO.MemoryStream(results)
        Dim img As New System.Drawing.Bitmap(imgStream)
        Dim mimeType As String = "image/unknown"
        For Each codec In System.Drawing.Imaging.ImageCodecInfo.GetImageDecoders
            If codec.FormatID = img.RawFormat.Guid Then
                mimeType = codec.MimeType
                Exit For
            End If
        Next
        Dim dataUrl As String
        'if the mime type is not known, convert the image to a PNG
        If mimeType <> "image/png" AndAlso mimeType <> "image/jpg" AndAlso mimeType <> "image/jpeg" AndAlso mimeType <> "image/svg" Then
            Dim formattedImgStream As New System.IO.MemoryStream()
            img.Save(formattedImgStream, System.Drawing.Imaging.ImageFormat.Png)
            formattedImgStream.Position = 0
            Dim buffer(formattedImgStream.Length) As Byte
            formattedImgStream.Read(buffer, 0, formattedImgStream.Length)
            dataUrl = "data:image/png;base64," + Convert.ToBase64String(buffer)
        Else
            dataUrl = "data:" + mimeType + ";base64," + Convert.ToBase64String(results)
        End If
        'return the data
        rv.Add("image_src", dataUrl)
    Catch ex As Exception
        'return the error
        rv.Add("error", ex.Message)
        rv.Add("stack_trace", ex.StackTrace)
    End Try
    Dim ser As New System.Web.Script.Serialization.JavaScriptSerializer()
    Response.Write(ser.Serialize(rv))
%>

JavaScript on my page:

...
...
var ajaxSettings = {url: '/tools/getimagedata.aspx',
                    method: 'POST',
                    dataType: 'json',
                    data: {}};
ajaxSettings.data.image_url = ***FACEBOOK IMAGE URL HERE***; 
ajaxSettings.success = function(data) {
  if(data && data.error == undefined) {
    var img = new Image();
    img.onload = function() {
        //add the image to the canvas
    };
    // getimagedata.aspx returns the base64 encoded image data as image_src
    img.src = data.image_src; 
  } else {
    // error calling the ASPX page
  }
};
//perform the ajax request
$.ajax(ajaxSettings).fail(function(e) {
  //error calling the AJAX
});
Ad
source: stackoverflow.com
Ad