小编典典

我应该如何使用jcrop在客户端裁剪图像并上传?

css

我正在开发一个具有文件上传HTML控件的组件,使用该控件选择图像后,该图像将呈现在HTML5 Canvas元素上

id = target 是jcrop图像目标
id = photograph 是文件上传控件
id =预览 是canvas元素
id = clear_selection 是一个可以清除画布的按钮

使用的第三方JS库:

<script src="./js/jquery.min.js"></script>
<script src="./js/jquery.Jcrop.js"></script>
<script src="./js/jquery.color.js"></script>

设置JCrop:

<script type="text/javascript">

jQuery(function($){

var api;

$('#target').Jcrop({
  // start off with jcrop-light class
  bgOpacity: 0.5,
  keySupport: false,
  bgColor: 'black',
  minSize:[240,320],
  maxSize:[480,640],
  onChange : updatePreview,
  onSelect : updatePreview, 
  height:160,
  width:120,
  addClass: 'jcrop-normal'
},function(){
  api = this;
  api.setSelect([0,0,240,320]);
  api.setOptions({ bgFade: true });
  api.ui.selection.addClass('jcrop-selection');
  });

});

清除画布按钮单击事件:

jQuery('#clear_selection').click(function(){
  $('#target').Jcrop({

      setSelect: [0,0,0,0],
    });
});

在jcrop面板上显示上传的图像

function readURL(input) {

    if (input.files && input.files[0]) {
        var reader = new FileReader();
        reader.onload = function (e) {
            $('#target').attr('src', e.target.result);
            setProperties();       
        }
        reader.readAsDataURL(input.files[0]);
    }
}

function setProperties(){
   $('#target').Jcrop({         
              setSelect: [0,0,240,320]
        }); 
}
$("#photograph").change(function(){
    readURL(this);     
});

我正在使用以下代码在画布上裁剪和渲染图像。

    function make_base() {
        console.log("make_base called");
        var base_image = new Image();
        base_image.src = '';
        base_image.onload = function () {
            context.drawImage(base_image, 0, 0);
        }
    }

    var canvas = document.getElementById('preview'),
    context = canvas.getContext('2d');

    make_base();
    function updatePreview(c) {
        console.log("called");
        if(parseInt(c.w) > 0) {
            // Show image preview
            var imageObj = $("#target")[0];
            var canvas = $("#preview")[0];
            var context = canvas.getContext("2d");
            context.drawImage(imageObj, c.x, c.y, c.w, c.h, 0, 0, canvas.width, canvas.height);
        }
    };

这是我在上述设置中面临的一系列问题:

  1. 在选择时不会调用updatePreview函数,因此不会渲染画布。
  2. 作物选择框不可拖动(我使用的是Bootstrap CSS,我怀疑是由于缺少/不匹配的依赖项)。
  3. Canvas是HTML5元素,这意味着最终用户必须具有HTML5兼容的浏览器,而我正在开发具有数百万用户的应用程序。强迫用户使用最新的浏览器不是一个可行的选择。这里的后备机制应该是什么?

阅读 434

收藏
2020-05-16

共1个答案

小编典典

Seahorsepip的答案很棒。我对非后备答案做了很多改进。

我建议您不要做一个奇怪的隐藏png事情,当一个Image对象也可以工作的时候(只要我们不支持后备)。

var jcrop_api;
var canvas;
var context;
var image;
var prefsize;

即使是这样,您最好还是从画布上移出该数据,而仅在最后将其放入该字段中。

function loadImage(input) {
  if (input.files && input.files[0]) {
    var reader = new FileReader();
    reader.onload = function(e) {
      image = new Image();
      image.src = e.target.result;
      validateImage();
    }
    reader.readAsDataURL(input.files[0]);
  }
}

但是,如果您想要的不仅仅是裁剪功能,我们还可以将jcrop附加到插入的画布上(在刷新时将使用jcrop销毁它)。我们可以轻松地完成我们可以使用画布执行的任何操作,然后再次执行validateImage()并使更新的图像可见。

function validateImage() {
  if (canvas != null) {
    image = new Image();
    image.src = canvas.toDataURL('image/png');
  }
  if (jcrop_api != null) {
    jcrop_api.destroy();
  }
  $("#views").empty();
  $("#views").append("<canvas id=\"canvas\">");
  canvas = $("#canvas")[0];
  context = canvas.getContext("2d");
  canvas.width = image.width;
  canvas.height = image.height;
  context.drawImage(image, 0, 0);
  $("#canvas").Jcrop({
    onSelect: selectcanvas,
    onRelease: clearcanvas,
    boxWidth: crop_max_width,
    boxHeight: crop_max_height
  }, function() {
    jcrop_api = this;
  });
  clearcanvas();
}

然后在提交时,我们提交任何未决的操作,例如applyCrop()或applyScale(),如果需要的话,将数据添加到备用字段的隐藏字段中。然后我们有了一个系统,我们可以轻松地以任何方式修改画布,然后在提交画布时正确发送数据。

function applyCrop() {
  canvas.width = prefsize.w;
  canvas.height = prefsize.h;
  context.drawImage(image, prefsize.x, prefsize.y, prefsize.w, prefsize.h, 0, 0, canvas.width, canvas.height);
  validateImage();
}

画布被添加到div视图中。

 <div id="views"></div>

为了捕获PHP(drupal)中的附件,我使用了类似的方法:

    function makeFileManaged() {
        if (!isset($_FILES['croppedfile']))
            return NULL;
        $path = $_FILES['croppedfile']['tmp_name'];
        if (!file_exists($path))
            return NULL;
        $result_filename = $_FILES['croppedfile']['name'];
        $uri = file_unmanaged_move($path, 'private://' . $result_filename, FILE_EXISTS_RENAME);
        if ($uri == FALSE)
            return NULL;
        $file = File::Create([
                    'uri' => $uri,
        ]);
        $file->save();
        return $file->id();
    }
2020-05-16