Canvas.toDataURL()可能无法导出污染的画布 [英] Canvas.toDataURL() Tainted canvases may not be exported

查看:101
本文介绍了Canvas.toDataURL()可能无法导出污染的画布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用javascript,html,css创建一个页面,我可以通过在线链接调整图像的大小.但是,在调整大小时,我遇到了一个错误,即在使用 Canvas.toDataURL()时可能无法导出污染的画布.我已经在Google和此处搜索了此问题.有人建议将照片的跨域修改为匿名或"*".我尝试了两种方法,但对我不起作用.我想知道任何人都可以提供帮助.我的代码在下面的链接中.

https://jsfiddle.net/pangkachun/7axkq9pe/1/

  var min_img_width = 60;var min_img_height = 60;var max_img_width = 1000;var max_img_height = 1000;var resizeableImage = function(image_target){//一些变量和设置var $ container,orig_src = new Image(),image_target = $(image_target).get(0),event_state = {},约束=假,min_width = min_img_width,//根据需要更改min_height = min_img_height,max_width = max_img_width,//根据需要更改max_height = max_img_height,resize_canvas = document.createElement('canvas'),//-----------------将页面插入----------------------//初始化= function(){//调整大小时,我们将始终使用此原始副本作为基础orig_src.src = image_target.src;orig_src.crossorigin ='匿名';//用容器包装图像并添加调整大小手柄$(image_target).wrap('< div class ="resize-container"></div>').before('< span class ="resize-handle resize-handle-nw"></span&';)).before('< span class ="resize-handle resize-handle-ne"></span&';)).after('< span class ="resize-handle resize-handle-se"></span&';)).after('< span class ="resize-handle resize-handle-sw"></span&';));//将容器分配给变量$ container = $(image_target).parent('.resize-container');//添加事件(一个用于调整大小(调整大小的句柄),另一个用于移动-img)//addEventListenor->鼠标触地得分,调整大小手柄,resize_img$ container.on('mousedown touchstart','.resize-handle',startResize);};//------------------用于将页面插入的结束函数-------------------------////在触发事件时保存数据saveEventState = function(e){//保存初始事件的详细信息和容器状态event_state.container_width = $ container.width();event_state.container_height = $ container.height();event_state.container_left = $ container.offset().left;event_state.container_top = $ container.offset().top;event_state.mouse_x =(e.clientX || e.pageX || e.originalEvent.touches [0] .clientX)+ $(window).scrollLeft();event_state.mouse_y =(e.clientY || e.pageY || e.originalEvent.touches [0] .clientY)+ $(window).scrollTop();//这是针对移动Safari的修复程序//由于某种原因,它不允许直接复制touches属性if(typeof e.originalEvent.touches!=='undefined'){event_state.touches = [];$ .each(e.originalEvent.touches,function(i,ob){event_state.touches [i] = {};event_state.touches [i] .clientX = 0 + ob.clientX;event_state.touches [i] .clientY = 0 + ob.clientY;});}event_state.evnt = e;};//根据宽度和高度重新绘制图像的功能redrawImage =函数(宽度,高度){resize_canvas.width =宽度;resize_canvas.height =高度;resize_canvas.getContext('2d').drawImage(orig_src,0,0,width,height);$(image_target).attr('src',resize_canvas.toDataURL("image/png"));;};//------------------------调整大小功能启动----------------------------//startResize = function(e){e.preventDefault();e.stopPropagation();saveEventState(e);$(document).on('mousemove touchmove',调整大小);$(document).on('mouseup touchend',endResize);};endResize = function(e){e.preventDefault();$(document).off('mouseup touchend',endResize);$(document).off('mousemove touchmove',调整大小);};调整大小=函数(e){var mouse = {},宽度,高度,左侧,顶部,偏移量= $ container.offset();mouse.x =(e.clientX || e.pageX || e.originalEvent.touches [0] .clientX)+ $(window).scrollLeft();mouse.y =(e.clientY || e.pageY || e.originalEvent.touches [0] .clientY)+ $(window).scrollTop();//根据拖动的角和约束,图像的位置不同if($(event_state.evnt.target).hasClass('resize-handle-se')){宽度= mouse.x-event_state.container_left;高度= mouse.y-event_state.container_top;左= event_state.container_left;顶部= event_state.container_top;} else if($(event_state.evnt.target).hasClass('resize-handle-sw')){宽度= event_state.container_width-(mouse.x-event_state.container_left);高度= mouse.y-event_state.container_top;左= mouse.x;顶部= event_state.container_top;} else if($(event_state.evnt.target).hasClass('resize-handle-nw')){宽度= event_state.container_width-(mouse.x-event_state.container_left);高度= event_state.container_height-(mouse.y-event_state.container_top);左= mouse.x;顶部= mouse.y;if(constrain || e.shiftKey){顶部= mouse.y-((宽度/orig_src.width * orig_src.height)-高度);}} else if($(event_state.evnt.target).hasClass('resize-handle-ne')){宽度= mouse.x-event_state.container_left;高度= event_state.container_height-(mouse.y-event_state.container_top);左= event_state.container_left;顶部= mouse.y;}if(width> min_width&&> min_height&& width< max_width&&&< max_height){//为了提高性能,您可以限制调用resizeImage()的频率redrawImage(width,height);//如果没有此功能,Firefox将不会重新计算图像尺寸,直到拖动结束$ container.offset({'left':left,'top':top}));}}//------------------------调整functino的大小----------------------------//在里面();};resizeableImage($('.resize-image'));  

 < script src ="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js></script><!DOCTYPE html>< html lang ="zh-cn" class ="no-js">< head>< title>使用Canvas调整图像大小</title>< link rel ="stylesheet" type ="text/css" href ="css/component.css"/><!-[如果是IE]>< script src ="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-></head><身体>< div class ="container">< div class ="content">< header class ="codrops-header">< h1>图像调整大小& amp;用Canvas</span>/h1裁剪" span></header>< div class ="component">< div class ="overlay">< div class ="overlay-inner"></div></div>< img class ="resize-image" id ='test-img'crossorigin ="anonymous" src ="https://static-cdn.pixlr.com/images/image-design.png" alt =用于调整大小"</div></div><!-/content-></div><!-/容器->< script src ="js/jquery-2.1.1.min.js"></script>< script src ="js/component.js"></script></body></html>  

非常感谢.

解决方案

有几种方法可以解决此问题,但是所有这些方法至少都需要至少暂时将映像托管在您的服务器上.最简单的选择是编写一个简单的cgi脚本,该脚本将url作为参数,获取该url处的图像,然后将其发送到浏览器,就像它在服务器上一样.如果希望用户能够选择本地图像,也可以使用文件上传表单.

请注意,如果执行此操作,则要了解捕获用户选择的文件并将其提供给您的文件,就像它们在您自己的服务器上一样,对安全性有影响.您至少要确保文件是有效图像,而不是javascript文件(这可能会导致代码注入攻击).

不允许导出受污染的画布数据的原因是这是用户安全问题.远程站点可以将不同的图像发送给不同的用户,如果您的站点仅通过在画布上绘制就可以访问该图像,则可以使用该方法来窃取用户的私人数据.例如,亚马逊过去曾让网站所有者在自己的网站中嵌入图片,最终将其作为定制广告,包括问候语和最终用户的姓名.如果您可以将其绘制在画布上并导出数据,则可以将该数据发送回Web服务器并对其进行OCR,以了解最终用户的名称.

I am trying to use javascript, html, css to create a page that I can resize an image from an online link. However, when resized, I faced the error that Tainted canvases may not be exported while using Canvas.toDataURL(). I have searched the issue in google and here. Somebody suggested to amend the photo's crossorigin to anonymous or '*'. I tried both methods but it doesn't work for me. I wonder anyone can offer help. My code is in the below link.

https://jsfiddle.net/pangkachun/7axkq9pe/1/

var min_img_width = 60;
var min_img_height = 60;
var max_img_width = 1000;
var max_img_height = 1000;

var resizeableImage = function(image_target) {
  // Some variable and settings
  var $container,
      orig_src = new Image(),
      image_target = $(image_target).get(0),
      event_state = {},
      constrain = false,
      min_width = min_img_width, // Change as required
      min_height = min_img_height,
      max_width = max_img_width, // Change as required
      max_height = max_img_height,
      resize_canvas = document.createElement('canvas'),

  // ----------------- function to int the page ----------------------//
  init = function(){

    // When resizing, we will always use this copy of the original as the base
    orig_src.src = image_target.src;
    orig_src.crossorigin = 'anonymous';

    // Wrap the image with the container and add resize handles
    $(image_target).wrap('<div class="resize-container"></div>')
    .before('<span class="resize-handle resize-handle-nw"></span>')
    .before('<span class="resize-handle resize-handle-ne"></span>')
    .after('<span class="resize-handle resize-handle-se"></span>')
    .after('<span class="resize-handle resize-handle-sw"></span>');

    // Assign the container to a variable
    $container =  $(image_target).parent('.resize-container');

    // Add events (one for resize (resize handle) and one for moving - img)
    // addEventListenor -> mouse touchdown, resize handle, resize_img
    $container.on('mousedown touchstart', '.resize-handle', startResize);
  };
  // ------------------ end function to int the page -------------------------//


  // to save the data upon a event is fired
  saveEventState = function(e){
    // Save the initial event details and container state
    event_state.container_width = $container.width();
    event_state.container_height = $container.height();
    event_state.container_left = $container.offset().left;
    event_state.container_top = $container.offset().top;
    event_state.mouse_x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft();
    event_state.mouse_y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop();

    // This is a fix for mobile safari
    // For some reason it does not allow a direct copy of the touches property
    if(typeof e.originalEvent.touches !== 'undefined'){
        event_state.touches = [];
        $.each(e.originalEvent.touches, function(i, ob){
          event_state.touches[i] = {};
          event_state.touches[i].clientX = 0+ob.clientX;
          event_state.touches[i].clientY = 0+ob.clientY;
        });
    }
    event_state.evnt = e;
  };

  // function to redraw the image based on width and height
  redrawImage = function(width, height){
    resize_canvas.width = width;
    resize_canvas.height = height;
    resize_canvas.getContext('2d').drawImage(orig_src, 0, 0, width, height);
    $(image_target).attr('src', resize_canvas.toDataURL("image/png"));
  };

  //------------------------ resizing function starts ----------------------------//
  startResize = function(e){
    e.preventDefault();
    e.stopPropagation();
    saveEventState(e);
    $(document).on('mousemove touchmove', resizing);
    $(document).on('mouseup touchend', endResize);
  };

  endResize = function(e){
    e.preventDefault();
    $(document).off('mouseup touchend', endResize);
    $(document).off('mousemove touchmove', resizing);
  };

  resizing = function(e){
    var mouse = {}, width, height, left, top, offset=$container.offset();
    mouse.x = (e.clientX || e.pageX || e.originalEvent.touches[0].clientX) + $(window).scrollLeft();
    mouse.y = (e.clientY || e.pageY || e.originalEvent.touches[0].clientY) + $(window).scrollTop();

    // Position image differently depending on the corner dragged and constraints
    if( $(event_state.evnt.target).hasClass('resize-handle-se') ){
      width = mouse.x - event_state.container_left;
      height = mouse.y  - event_state.container_top;
      left = event_state.container_left;
      top = event_state.container_top;
    } else if($(event_state.evnt.target).hasClass('resize-handle-sw') ){
      width = event_state.container_width - (mouse.x - event_state.container_left);
      height = mouse.y  - event_state.container_top;
      left = mouse.x;
      top = event_state.container_top;
    } else if($(event_state.evnt.target).hasClass('resize-handle-nw') ){
      width = event_state.container_width - (mouse.x - event_state.container_left);
      height = event_state.container_height - (mouse.y - event_state.container_top);
      left = mouse.x;
      top = mouse.y;
      if(constrain || e.shiftKey){
        top = mouse.y - ((width / orig_src.width * orig_src.height) - height);
      }
    } else if($(event_state.evnt.target).hasClass('resize-handle-ne') ){
      width = mouse.x - event_state.container_left;
      height = event_state.container_height - (mouse.y - event_state.container_top);
      left = event_state.container_left;
      top = mouse.y;
    }

    if(width > min_width && height > min_height && width < max_width && height < max_height){
      // To improve performance you might limit how often resizeImage() is called
      redrawImage(width, height);
      // Without this Firefox will not re-calculate the the image dimensions until drag end
      $container.offset({'left': left, 'top': top});
      }
    }
    //------------------------ resizing functino end ----------------------------//

  init();
};

resizeableImage($('.resize-image'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en" class="no-js">
    <head>
        <title>Image Resizing with Canvas</title>
        <link rel="stylesheet" type="text/css" href="css/component.css" />
        <!--[if IE]>
        <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
    </head>
    <body>
        <div class="container">
            <div class="content">
                <header class="codrops-header">
                    <h1>Image Resizing &amp; Cropping <br /><span>with Canvas</span></h1>
                </header>
                <div class="component">
                    <div class="overlay">
                        <div class="overlay-inner">
                        </div>
                    </div>
                    <img class="resize-image" id='test-img'crossorigin="anonymous" src="https://static-cdn.pixlr.com/images/image-design.png" alt="image for resizing">
                </div>

            </div><!-- /content -->
        </div> <!-- /container -->
        <script src="js/jquery-2.1.1.min.js"></script>
        <script src="js/component.js"></script>
    </body>
</html>

Thanks a lot.

解决方案

There are a couple ways to get around this, but all of them will require at least temporarily hosting the image on your server. The simplest option would be to write a simple cgi script that takes an url as a parameter, fetches the image at that url, and sends it on to the browser as though it was on your server. You could also use a file upload form if you want the user to be able to select a local image.

Note that if you do this, you would want to be aware of the security implications of grabbing user-selected files and serving them as if they were on your own server. You would, at a minimum, want to make sure the files were valid images, and not, say, javascript files (which might lead to code injection attacks).

The reason exporting of tainted canvas data is disallowed is that it's a user security issue. Remote sites can send different images to different users, and if your site can gain access to that just by drawing it on a canvas, that method could be used to steal a user's private data. For example, Amazon used to let website owners embed an image in their site that would end up being a customized ad including a greeting and the end-user's name. If you could paint that on a canvas and export the data, you could send that data back to your webserver and OCR it to learn the name of the end-user.

这篇关于Canvas.toDataURL()可能无法导出污染的画布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆