Javascript canvas.toDataURL() 安全错误操作不安全

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25753754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 21:49:27  来源:igfitidea点击:

canvas.toDataURL() Security Error The operation is insecure

javascripthtmlvideocanvas

提问by Kemal

When I am trying to get a screenshot and save it as PNG before uploading video to server, I am having the following problem

当我尝试在将视频上传到服务器之前获取屏幕截图并将其保存为 PNG 时,我遇到了以下问题

enter image description here

在此处输入图片说明

I hope you can solve my problem ...

希望你能解决我的问题...

/*Output image show view*/
$('#file_browse').change(function(e){
    getVideo(this);
});

var capbtn = document.querySelector('#video_capture');
var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
var w, h, ratio;

video.addEventListener('loadedmetadata', function() {
    ratio = video.videoWidth / video.videoHeight;
    w = video.videoWidth - 100;
    h = parseInt(w / ratio, 10);
    canvas.width = w;
    canvas.height = h;           
}, false);

capbtn.addEventListener("click", function(){
    context.fillRect(0, 0, w, h);
    context.drawImage(video, 0, 0, w, h);
    var objImageData = canvas.toDataURL("data:image/png;");  
});

function getVideo(input) {
    if (input.files && input.files[0]) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var video = document.getElementsByTagName('video')[0];
            var sources = video.getElementsByTagName('source');
            sources[0].src = e.target.result;
            video.load();
            video.style.display="block";
        }
        reader.readAsDataURL(input.files[0]);
    }
}
<input id="video_capture" type="submit" value="Capture" />
<video id="video_view" controls>
    <source src="movie.mp4" type="video/mp4">
</video>
<canvas width="300" height="300"></canvas>

回答by StephenKC

Sounds like a CORS issue.

听起来像是 CORS 问题。

The Video is on a different origin than the web server.

视频与 Web 服务器位于不同的来源。

If you can get the video to include an "Access-Control-Allow-Origin: *" header in the response, and you can set video.crossorigin = "Anonymous", then you can probably pull this off.

如果您可以让视频在响应中包含“Access-Control-Allow-Origin: *”标头,并且您可以设置 video.crossorigin = "Anonymous",那么您可能可以将其关闭。

I used Charles Web Proxy to add the header to any image or video I wanted to work with.

我使用 Charles Web Proxy 将标题添加到我想要处理的任何图像或视频中。

See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image

请参阅https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image

See Also https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

另见https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

Here's a Fiddle working with an Image: http://jsfiddle.net/mcepc44p/2/

这是一个使用图像的小提琴:http: //jsfiddle.net/mcepc44p/2/

var canvas = document.getElementById("canvas").getContext("2d");

var button = document.getElementById("button");

var image = new Image();
image.crossOrigin = "anonymous";  // This enables CORS
image.onload = function (event) {
    try {
        canvas.drawImage(image, 0, 0, 200, 200);
        button.download = "cat.png";
        button.href = canvas.canvas.toDataURL();        
    } catch (e) {
        alert(e);
    }
};
image.src = "https://i.chzbgr.com/maxW500/1691290368/h07F7F378/"

Is this what you're looking for?

这是你要找的吗?

回答by tcooc

It's because of the Same Origin Policy. Basically, you're not allowed to access the video data of something loaded from another origin/site using a canvas.

这是因为同源策略。基本上,您不允许使用画布访问从另一个来源/站点加载的内容的视频数据。

Drawing video data on the canvas sets the origin-cleanflag to false, which stops you from getting the image data in any way.

在画布上绘制视频数据将origin-clean标志设置为 false,这会阻止您以任何方式获取图像数据。

See toDataURLfor more information.

有关更多信息,请参阅toDataURL

回答by Dotgreg

As well, took some experimentation to reach that conclusion, on iOS, looks the position .crossOrigin parameter position should be put before the .src

同样,通过一些实验得出了这个结论,在 iOS 上,看起来位置 .crossOrigin 参数位置应该放在 .src 之前

// Webkit will throw security error when image used on canvas and canvas.toDataUrl()

return new Promise((resolve, reject) => {
  let image = new Image();
  img.onload = () => {resolve(image)}
  img.src = `${url}?${Date.now()}`;
  img.crossOrigin = ""
})

// Webkit will not throw security error when image used on canvas and canvas.toDataUrl()

return new Promise((resolve, reject) => {
  let img = new Image()
  img.onload = () => {resolve(img)}
  img.crossOrigin = ''
  img.src = `${url}?${Date.now()}`
})

回答by Guilherme Nascimento

In docs toDataURL("data:image/png;")apparently not documented:

在文档中toDataURL("data:image/png;")显然没有记录:

Try replace .toDataURL("data:image/png;");by .toDataURL("image/png");

尝试取代.toDataURL("data:image/png;");.toDataURL("image/png");

回答by Henry Gabriel González Montejo

Hi i have the same problem, in a system where i show videos, my users have to create a thumb when they select a video, but then Security Error.

嗨,我有同样的问题,在我显示视频的系统中,我的用户在选择视频时必须创建一个拇指,然后是安全错误。

This solution only works if you can modify the server, then you can send the video or font or etc with CORS. So you have to edit httpd.conf( Apache configuration from the server where you pull the videos).

此解决方案仅在您可以修改服务器时才有效,然后您可以使用 CORS 发送视频或字体等。所以你必须编辑 httpd.conf(从你拉视频的服务器上的 Apache 配置)。

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(mp4)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>

and in your webpage or app, to the video tag add: crossOrigin="Anonymous"

并在您的网页或应用中,在视频标签中添加: crossOrigin="Anonymous"

This is a fragment of my code, after that all works again..

这是我的代码片段,之后一切又正常了..

document.getElementById('video_thumb').innerHTML =
             '<img src="'+data_uri+'"  width="250"
                        height="250px" crossOrigin="Anonymous">';       

With this, canvas.toDataURL()don't trow error

有了这个,canvas.toDataURL()不要犯错误

回答by codeymcgoo

In my case, the problem was related to the presence of icons that weren't coming from my site as well as the presence of a Select input. Your video container may contain the same items. To solve, I had to hide the select inputs and icons before the screenshot was taken, then show them again after the screenshot was taken. Then, the canvas.toDataURL worked perfectly and didn't throw that security error.

就我而言,问题与不是来自我网站的图标的存在以及 Select 输入的存在有关。您的视频容器可能包含相同的项目。为了解决这个问题,我必须在截取屏幕截图之前隐藏选择的输入和图标,然后在截取屏幕截图后再次显示它们。然后,canvas.toDataURL 工作得很好并且没有抛出那个安全错误。

Before Screenshot:

截图前:

$("select[name='example']").add(".external-icon").hide();

After Screenshot:

截图后:

$("select[name='example']").add(".external-icon").show();