画布图像跨平台不安全错误

时间:2016-01-12 12:41:28

标签: javascript canvas

我有这个代码用于从不同的服务器URL创建画布图像

function getBase64Image(imageUri) { 
    var canvas = document.createElement("canvas");
    ctx = canvas.getContext("2d"); 
    var img = new Image();
    img.src = imageUri;
    img.crossOrigin = "Anonymous";
    img.onload = function() {
       canvas.width = this.width;
       canvas.height = this.height;
       ctx.drawImage(img, 0, 0, this.width, this.height);
       var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
       var dataURL = canvas.toDataURL("image/png");
       document.getElementById("dummyhiddenField").value = dataURL;
   };
}

我试图从服务器获取图像并将其设置为隐藏字段的画布网址 但它只与当地形象合作

根据stackoverflow的其他答案,我设置了crossOrigin = "Anonymous",它不能正常工作 从服务器访问源,必须从localscript管理所有的东西

由于

1 个答案:

答案 0 :(得分:14)

使用跨域内容更新了Html5 Canvas。

以下是跨域内容如何影响html5画布以及如何在适用于跨域内容的安全限制内工作的更新视图

今天(2016年1月)更新很有用,因为有几种新的(ish)方法可以将跨域图像绘制到画布而不会污染画布。

在html5画布上绘制跨域内容会导致它被污染"

您可以在画布上从另一个域绘制图像,它将显示在画布上。从另一个域访问资源被称为"跨源资源共享" - 通常被称为" CORS"简而言之。

绘制CORS内容(f.ex:图像)将导致画布被污染"出于安全原因。

如果画布受到污染,则无法使用这些画布和画布。上下文方法:

  • context.getImageData获取画布上的像素数据
  • canvas.toDataURL将画布导出为图像

你不能"欺骗"画布违反了其CORS安全限制 - 希望你甚至不想尝试!但您可以通过满足CORS安全限制来绘制跨源图像而不会污染画布。

"通常" (也是最简单的)处理图像的方式,这样他们就不会弄乱画布:

将您的图片放在与网页相同的中。您可以使用多个物理服务器提供内容,但图像必须与创建画布的html代码(或javascript代码)相同。 CORS限制得到满足,画布没有受到污染。

在您自己的计算机上开发时有关CORS的说明

解决方案#1(!):您可以在开发计算机上安装Web服务器,同时提供网页文件(.html,.js等)和图像文件(.png) ,.jpg等,来自一个域名。

您的开发计算机的文件夹被声明为不同的域。因此,从本地磁盘上的子目录中绘制图像将违反CORS限制,因为不同的本地文件夹是不同的域。

解决方案#2:在进行开发时,您可以将网页文件和图像文件放在桌面上,图像将声明在同一个域中,而您的画布将不会污点。

当图像位于不同的域时,满足CORS限制

解决方案#3:可以在画布上使用跨域图像而不会污染它。为此,您必须满足以下要求:

  • Clientside:图像对象必须设置crossOrigin属性以允许跨源内容。可以在html元素标记内或javascript中设置此属性。启用设置是"匿名"和" use-credentials"。

  • Serverside:必须将服务器配置为返回表示响应包含授权内容的标头。

根据配置,可能需要多个响应标头:

Access-Control-Allow-Origin将返回匿名授权(*)或根据请求返回特定授权。

如果身份验证需要其他信息(如Cookie),则需要

Access-Control-Allow-Credentials

Access-Control-Expose-Headers使客户可以访问其他响应信息。

在服务器上启用跨域请求可能很复杂,尤其是在提供基于客户端角色授权的内容时。有关启动配置的其他信息,请访问:http://enable-cors.org/index.html

使用允许匿名访问其图片的跨域图片主机

解决方案#4:一些公共图像主机允许您上传以CORS兼容方式提供给客户端的图像。几个例子是:imgurdropbox。 Stackoverflow图像托管在Imgur上。

以下是如何以符合CORS标准的方式在Dropbox.com上投放图片的示例:

  1. 注册Dropbox Account
  2. 您将获得几个默认文件夹。将图像上传到特殊的" Public"夹。这是Dropbox提供符合CORS标准的匿名访问的文件夹。
  3. 右键点击要投放的图片,然后选择"复制公共链接"。您的剪贴板将包含指向符合CORS标准的图像的链接。
  4. 使用img标记或javascript将图像加载到您的页面上。
  5. 这是使用javascript从Dropbox获取符合CORS的图像对象的示例代码:

    var img=new Image();
    img.crossOrigin='anonymous';
    img.src="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";
    img.onload=start;
    function start(){
        context.drawImage(img,0,0);
        // The canvas is not tainted so 
        // the following both work without errors
        var url=canvas.toDataURL();
        var imageData=context.getImageData(0,0,100,100);
    }
    

    新(ish):通过让客户端用户同意来满足CORS

    CORS安全限制旨在阻止坏人秘密接收您的信息,同时让您不知情。

    直到最近,浏览器还依赖客户端 - 服务器配置来满足安全要求。最近,如果用户肯定参与决定使用的内容,浏览器已经开始允许跨源内容。

    解决方案#5: Chrome和Firefox现在允许客户端用户right click the canvas & save the canvas as an image。这相当于使用canvas.toDataURL创建图像对象并将该图像对象保存到本地驱动器。 CORS很满意,因为用户决定画布内容是否适合保存到本地驱动器,并且肯定地右键单击以启动下载过程。

    解决方案#6:您可以使用input element, type='file'让客户端用户选择图像。用户甚至可以选择互联网URL(http://..。)。同样,CORS很满意,因为用户参与了选择过程。

    以下示例代码显示如何使用输入监听用户选择图像:

    
    
    // canvas vars
    var canvas=document.createElement("canvas");
    var ctx=canvas.getContext("2d");
    
    // define max resulting image width,height (after resizing)
    var maxW=100;
    var maxH=100;
    
    // listen for user to select files
    var input = document.getElementById('input');
    input.addEventListener('change', handleFiles);
    
    function handleFiles(e) {
      var img = new Image;
      img.onload = function(){
        var iw=img.width;
        var ih=img.height;
        // scale down, if necessary
        if(iw>maxW || ih>maxH){
          var scale=Math.min((maxW/iw),(maxH/ih));
          iw*=scale;
          ih*=scale
        }
        // set canvas width/height to scaled size
        canvas.width=iw;
        canvas.height=ih;
        // draw+scale the img onto the canvas
        ctx.drawImage(img,0,0,iw,ih);
        // create a jpeg URL (with medium quality to save "weight") 
        var jpg=canvas.toDataURL('image/jpeg',0.60);
        // In Demo: add the jpg to the window
        // In production, accumulate jpg's & send to server
        $('<img />',{src:jpg}).appendTo('body');
      }
      // In Demo: Just process the first selected file 
      // In production: process all selected files 
      img.src = URL.createObjectURL(e.target.files[0]);
    }
    &#13;
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <h4>You can even enter a web URI (http://...)</h4>
    <input type="file" id="input"/><br>
    &#13;
    &#13;
    &#13;

    解决方案#7:您可以使用新的(ish)FileReader让用户选择要在画布上绘制的图像。

    &#13;
    &#13;
    // dropDiv event handlers
    var dropDiv=document.getElementById("dropDiv");
    dropDiv.addEventListener("dragenter", handleDragEnter, false);
    dropDiv.addEventListener("dragover", handleDragOver, false);
    dropDiv.addEventListener("drop", handleDrop, false);
    //
    function handleDragEnter(e) {
      e.stopPropagation();
      e.preventDefault();
    }
    //
    function handleDragOver(e) {
      e.stopPropagation();
      e.preventDefault();
    }
    //
    function handleDrop(e) {
      e.stopPropagation();
      e.preventDefault();
    
      var dt = e.dataTransfer;
      var files = dt.files;
    
      handleFiles(files);
    }
    
    //
    function handleFiles(files) {
    
      for (var i=0;i<files.length;i++) {
        var file = files[i];
        var imageType = /image.*/;
    
        if (!file.type.match(imageType)) {
          continue;
        }
    
        var img = document.createElement("img");
        img.classList.add("obj");
        img.file = file;
        preview.appendChild(img);
    
        var reader=new FileReader();
        reader.onload=(function(aImg){
          return function(e) {
            aImg.onload=function(){
              var canvas=document.createElement("canvas");
              var ctx=canvas.getContext("2d");
              canvas.width=aImg.width;
              canvas.height=aImg.height;
              ctx.drawImage(aImg,0,0);
              document.body.appendChild(canvas);
            }
            // e.target.result is a dataURL for the image
            aImg.src = e.target.result;
          }; 
        })(img);
        reader.readAsDataURL(file);
    
      } // end for
    
    } // end handleFiles
    
    function calcNewAspect(imgWidth, imgHeight, maxWidth, maxHeight) {
      var ratio = Math.min(maxWidth/imgWidth,maxHeight/imgHeight);
      return {width:imgWidth*ratio,height:imgHeight*ratio };
    }
    &#13;
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    #dropDiv{border:1px solid blue; width:300px;height:300px;}
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <h4>Drag 1+ image(s) from desktop to blue dropDiv.</h4>
    <div id="dropDiv"></div>
    <div id="preview"></div>
    &#13;
    &#13;
    &#13;

    继续......

    此更新中可能需要包含更多信息位。请随时评论我的心不在焉,我会继续更新。 : - )