canvas.toDataURL()SecurityError


76

所以我正在使用谷歌地图,我得到的照片看起来像这样

<img id="staticMap"
        src="http://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=13&size=600x300&maptype=roadmap
&markers=color:blue%7Clabel:S%7C40.702147,-74.015794&markers=color:green%7Clabel:G%7C40.711614,-74.012318
&markers=color:red%7Ccolor:red%7Clabel:C%7C40.718217,-73.998284&sensor=false">

我需要保存它。我发现了这一点:

function getBase64FromImageUrl(URL) {
    var img = new Image();
    img.src = URL;
    img.onload = function() {

        var canvas = document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        var ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);

        var dataURL = canvas.toDataURL("image/png");

        alert(dataURL.replace(/^data:image\/(png|jpg);base64,/, ""));

    };
}

但是我遇到了这个问题:

未捕获到的SecurityError:无法在“ HTMLCanvasElement”上执行“ toDataURL”:受污染的画布可能无法导出。

我搜索了修复程序。我在这里找到了如何使用CORS的示例,但仍然无法将这两段代码捆绑在一起以使其正常工作。也许我做错了方法,并且有一种更简单的方法?我正在尝试保存此图片,以便可以将数据传输到我的服务器。因此,也许有人做了这样的事情,并且知道如何根据.toDataURL()需要进行工作?

Answers:


99

除非Google使用正确的Access-Control-Allow-Origin标题提供此图片,否则您将无法在画布中使用其图片。这是由于未获得CORS批准。您可以在此处阅读有关此内容的更多信息,但这实际上意味着:

尽管您可以在画布中使用未经CORS批准的图像,但这样做会污染画布。画布污染后,您将无法再将数据拉出画布。例如,您将无法再使用画布的toBlob(),toDataURL()或getImageData()方法。这样做会引发安全错误。

通过使用图像未经许可而从远程网站提取信息,可以保护用户免于暴露私人数据。

我建议仅将URL传递到您的服务器端语言,然后使用curl来下载图像。不过要小心消毒!

编辑:

由于此答案仍然是公认的答案,因此您应该查看@shadyshrif的答案,该答案可以使用:

var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;

当您具有正确的权限时,此方法有效,但至少将允许您执行所需的操作。


1
我会进一步考虑@Prisoner提供的远程替代建议,并建议将其作为默认行为。服务器几乎肯定可以接收img.src,然后wget * / * cURL图像比客户端可以对本地图像进行编码并将其发布到服务器更快。也许,只有在需要客户端身份验证的情况下(即,服务器的尝试以结束403),您才可以回退使用canvas.toDataURL(img),以希望它的来源与页面相同。此默认行为也会导致产生原始文件(EXIF等)
Alastair 2014年

4
我已将Google Cloud Storage存储桶设置为“ Access-Control-Allow-Origin:*”,但是在尝试使用toDataURL()方法时仍然出现此安全错误。图片通过“ getImageServingUrl”生成的URL投放到Canvas
Mr Pablo

1
有解决方案吗?这个答案很打击。
叶芝2015年

太好了!非常感谢您的回答!
凯文·文森特

4
TIL:crossOrigin在设置之前设置属性至关重要img.src
horstwilhelm

56

只需使用该crossOrigin属性并将其'anonymous'作为第二个参数传递

var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;

6
需要说明的是,这对于直接不让资源给您的服务器不起作用。这意味着,这仅适用于公共资源或配置错误的服务器。
m3nda 2015年

3
我还必须向图像URL添加时间戳,以避免存储服务器在没有Access-Control-Allow-Origin标头的情况下以304响应。这样img.src = url + '?' + new Date().getTime();
Kirby 2015年

在IE11中对我不起作用,图像使用了使用数据URL源
AlexM,

4

此方法将防止您从所访问的服务器获取“ Access-Control-Allow-Origin”错误。

var img = new Image();
var timestamp = new Date().getTime();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url + '?' + timestamp;

3

尝试下面的代码...

<img crossOrigin="anonymous"
     id="imgpicture" 
     fall-back="images/penang realty,Apartment,house,condominium,terrace house,semi d,detached,
                bungalow,high end luxury properties,landed properties,gated guarded house.png" 
     ng-src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" 
     height="220"
     width="200"
     class="watermark">

2
fall-back属性毫无意义的原因是什么?
y.bregey

0

就我而言,我使用的是WebBrowser控件(强制IE 11),但我无法越过该错误。切换到使用Chrome的CefSharp可以解决我的问题。


0

我有同样的错误信息。我将文件保存在一个简单的.html中,当我将该文件传递给Apache中的php时,它可以正常工作

html2canvas(document.querySelector('#toPrint')).then(canvas => {
            let pdf = new jsPDF('p', 'mm', 'a4');
            pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, 0, 211, 298);
            pdf.save(filename);
        });

-3

通过使用fabric js,我们可以解决IE中的此安全错误问题。

    function getBase64FromImageUrl(URL) {
        var canvas  = new fabric.Canvas('c');
        var img = new Image();
        img.onload = function() {
            var canvas1 = document.createElement("canvas");
            canvas1.width = this.width;
            canvas1.height = this.height;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(this, 0, 0);
            var dataURL = canvas.toDataURL({format: "png"});
        };
        img.src = URL;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.