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

Posted

技术标签:

【中文标题】canvas.toDataURL() 安全错误 操作不安全【英文标题】:canvas.toDataURL() Security Error The operation is insecure 【发布时间】:2014-11-03 09:55:53 【问题描述】:

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

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

/*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  ></canvas>

【问题讨论】:

使用 windowURL.createObjectURL(input.files[0]) 会更流畅/更快,并且可能更慷慨。 【参考方案1】:

src 之前设置attribute 解决了我们的绘图应用程序的问题:https://www.trumpgraffitimemes.com/

useEffect(() => 
    const img = new Image();
    if (picdatanew.length !== 0) 
      img.setAttribute("crossorigin", "anonymous");
      img.src = picdatanew[picID].webformatURL;
    
      setCanvasSize(
        width: picdatanew[picID].webformatWidth,
        height: picdatanew[picID].webformatHeight,
      );
      setPicturedata(img);
      setWholedata([]);


      setTimeout(() => 
        contextRef.current.drawImage(
          img,
          0,
          0,
          picdatanew[picID].webformatWidth,
          picdatanew[picID].webformatHeight
        );
        var image = canvasRef.current.toDataURL("image/jpg");
        setMyImage(image);
      , 2000);
    
  , [picID, picdatanew]);

【讨论】:

【参考方案2】:

同样,做了一些实验得出这个结论,在 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()`
)

【讨论】:

【参考方案3】:

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

截图前:

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

截图后:

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

【讨论】:

【参考方案4】:

您好,我有同样的问题,在我显示视频的系统中,我的用户必须在选择视频时创建拇指,但随后出现安​​全错误。

此解决方案仅在您可以修改服务器时才有效,然后您可以使用 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>

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

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

document.getElementById('video_thumb').innerhtml =
             '<img src="'+data_uri+'"  
                         crossOrigin="Anonymous">';       

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

【讨论】:

谢谢!这也适用于视频标签:&lt;video src=... crossOrigin="anonymous"&gt;。这将允许在视频帧上调用toDataURL【参考方案5】:

这是因为Same Origin Policy。基本上,您不能使用画布访问从另一个来源/站点加载的内容的视频数据。

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

更多信息请参见toDataURL。

【讨论】:

那怎么办..? 所以基本上这不能用于不同来源的视频?【参考方案6】:

听起来像是 CORS 问题。

视频与网络服务器的来源不同。

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

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

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

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

这是一个使用图像的小提琴: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/"

这就是你要找的吗?

【讨论】:

这应该是公认的答案。来自 sn-p 的以下行使一切变得不同。 image.crossOrigin = "anonymous"; // This enables CORS 这不应该是公认的答案,因为它不适用于 OP 要求的视频 上帝保佑你,你救了我的命;) 对于像 i.chzbgr.com 这样具有完全许可 CORS 集的网站不需要此解决方法。您可以只使用&lt;img&gt; 标签。 ... 但是,对于 i.imgur.com,似乎需要这种解决方法,因为服务器将 CORS 方法限制为 GET, OPTIONS 它不适用于我的视频。我已经设置了 CORS 标头并使用 curl -I 确认标头确实已设置。我想从视频中提取一帧并将其显示在图像中。在视频帧上调用 toDataURL() 时出现错误。

以上是关于canvas.toDataURL() 安全错误 操作不安全的主要内容,如果未能解决你的问题,请参考以下文章

canvas.toDataURL() 在 IE 11 中给出“安全错误”

在画布上调用 toDataUrl 时 IE 引发安全错误

为啥 canvas.toDataURL() 会抛出安全异常?

canvas.toDataURL() 抛出安全异常,尽管图像是本地的

canvas.toDataURL()报错

为什么canvas.toDataURL获取图片是空白