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

我想要做的是使用html fileupload控件选择图像,使用jcrop裁剪选择,在客户端裁剪图像并上传图像。 这里是小提琴链接https://jsfiddle.net/govi20/spmc7ymp/

Id在代码中使用:

jcrop图像的目标
照片文件上传控件
预览canvas预览
clear_selection按钮清除所选区域

设置jcrop。

 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); }); 

裁剪图像并将其分配给canvas(从stackoverflow上的一个线程获取此图像)

 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(cw) > 0) { // Show image preview var imageObj = $("#target")[0]; var canvas = $("#preview")[0]; var context = canvas.getContext("2d"); context.drawImage(imageObj, cx, cy, cw, ch, 0, 0, canvas.width, canvas.height); } }; 

我面临的问题:

  1. updatePreview函数未在选择时调用,因此没有可见的canvas。
  2. 裁剪选择不可拖动(我使用bootstrap css)。
  3. Canvas是HTML5元素,这意味着客户端应该具有html5兼容的浏览器,所以我该如何删除这个条件。

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

http://jsfiddle.net/w1Lh4w2t/

我建议不要做那个奇怪的隐藏的png事情,当Image对象也能正常工作时(只要我们不支持回退)。

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

虽然即便如此,你最好还是将这些数据最终从canvas中取出,然后只在最后将它放在那个字段中。

 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]); } } 

但是,如果你想要更多的function而不仅仅是裁剪,如果我们将jcrop附加到插入的canvas(我们在刷新时使用jcrop销毁)。 我们可以轻松地使用canvas执行任何操作,然后再次validationvalidateImage()并使更新后的图像可见。

 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 = $("#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(),如果我们需要那些东西,则将数据添加到隐藏字段中以用于后备内容。 然后我们有一个系统,我们可以轻松地以任何方式修改canvas,然后当我们提交canvas时,数据被正确发送。

 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(); } 

canvas将添加到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(); } 

这是基本的html 5代码:

https://jsfiddle.net/zm7e0jev/

此代码裁剪图像,显示预览并将输入元素的值设置为base64编码的裁剪图像。

您可以通过以下方式在php中获取图像文件:

 //File destination $destination = "/folder/cropped_image.png"; //Get convertable base64 image string $image_base64 = $_POST["png"]; $image_base64 = str_replace("data:image/png;base64,", "", $image_base64); $image_base64 = str_replace(" ", "+", $image_base64); //Convert base64 string to image data $image = base64_decode($image_base64); //Save image to final destination file_put_contents($destination, $image); 

将base64图像字符串作为post变量提交具有服务器发布大小限制和base64编码使得裁剪后的图像文件大小更大(~33%),然后裁剪图像的原始数据将使上载花费更长时间。

设置post大小限制: post请求的大小限制是多少?

请记住,例如,DoS攻击可能会滥用增加的邮件大小限制。

相反,我建议将base64裁剪图像转换为数据blob,然后将其作为文件提交到表单中:

https://jsfiddle.net/g3ysk6sf/

然后你可以通过以下方式在php中获取图像文件:

 //File destination $destination = "/folder/cropped_image.png"; //Get uploaded image file it's temporary name $image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0]; //Move temporary file to final destination move_uploaded_file($image_tmp_name, $destination); 

更新:

FormData()仅在IE10中得到部分支持,在旧版本的IE中不受支持

所以我建议发送base64字符串作为后备,但这会导致更大的图像出现问题,因此需要检查文件大小并在图像高于特定大小时显示错误弹出窗口。

当我使用它时,我将使用下面的回退代码发布更新。

更新2:

我为IE10及以下版本添加了一个后备:

https://jsfiddle.net/oupxo3pu/

唯一的限制是使用IE10及以下时可以提交的图像大小,如果图像大小太大,js代码将引发错误。 每个服务器之间的post值的最大大小是不同的,js代码有一个变量来设置最大大小。

下面的PHP代码适用于上述后备:

 //File destination $destination = "/folder/cropped_image.png"; if($_POST["png"]) {//IE10 and below //Get convertable base64 image string $image_base64 = $_POST["png"]; $image_base64 = str_replace("data:image/png;base64,", "", $image_base64); $image_base64 = str_replace(" ", "+", $image_base64); //Convert base64 string to image data $image = base64_decode($image_base64); //Save image to final destination file_put_contents($destination, $image); } else if($_FILES["cropped_image"]) {//IE11+ and modern browsers //Get uploaded image file it's temporary name $image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0]; //Move temporary file to final destination move_uploaded_file($image_tmp_name, $destination); } 

还没有canvas元素的回退代码,我正在研究它。

旧版浏览器后备版中的post大小限制是我自己放弃对旧浏览器的支持的原因之一。

更新3:

我推荐IE8中canvas元素的后备:

http://flashcanvas.net/

它支持裁剪代码所需的所有canvas函数。

请记住,它需要闪光灯。 有一个canvas后备(explorercanvas)不需要闪存,但它不支持我们需要保存裁剪图像的函数toDataURL()。