您的位置:首页 > 运维架构

Jcrop插件+Canvas实现图片上传预览+图片裁剪上传

2017-12-09 09:16 791 查看

前言

想实现一个功能:用户点击上传按钮,选择图片后。图片显示在一个弹出框上,并可以对图片进行裁剪。裁剪后的图片显示在页面上。提交表单即可上传图片。

遇到问题

浏览器的安全设置不让用户获取上传的图片路径,实际获取的是c:\fakepath\a.jpg(假设图片是c盘下的a.jpg)

ajax如何异步上传图片?

Canvas画裁剪的图片时长宽不一样(本来想画100x100的图片,结果在画布上显示100x50)

Canvas上的图片怎么上传?

问题解决

选择图片后,触发input的onchange事件:发送异步请求将图片上传,返回图片的名称,然后弹框,将图片显示出来。

将表单封装为FormData类型,ajax进行一些设置即可,具体百度有说。

设置Canvas宽高我用的是style:width:100px;height:100px;,后来直接写Canvas的属性width=100px height=100px,问题就解决了。具体原因百度有说。

获取Canvas的图片流(实际上就是一段字符串),表单提交图片流。后台用Base64解析图片流成为byte数组,然后根据byte数组创建输入流,有了输入流,就能够写出一张图片了。

部分代码

<!-- 图片上传,openPhotoCut的功能是异步上传图片,显示图片并裁剪 -->
<form id="uploadForm" class="form-horizontal" role="form" enctype="multipart/form-data">
<div class="form-group namediv">

<label class="col-sm-2" for="photo" style="font-size: 15px;"><span style="color:red;">  </span>菜品图片</label>
<div class="col-sm-6">
<input type="file" class="photo" id="photo" name="photo" onchange="openPhotoCut();" />
</div>
</div>
</form>


// 打开图片裁剪框
function openPhotoCut() {
// ajax上传图片的关键
var formData = new FormData($("#uploadForm"));
var fileName;  // 上传文件名
// 在表单里面添加上传的图片
formData.append("photo", $(".photo").get(0).files[0]);
// 上传未裁剪的图片
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath }/business/product/getFileLocationAjax",
async: false,
data: formData,
// 以下两行不写可能会报错
contentType: false,
processData: false,
success: function(result) {
// 得到图片名称
fileName = result;
alert(fileName);
}
});
// 这里使用的是layer弹框插件,弹出图片裁剪框,显示上传的图片,并进行裁剪
layer.open({
title: '图片裁剪',
type: 1,
skin: 'layui-layer-rim', //加上边框
area: ['600px', '500px'], //宽高
// 这里纯粹是html内容,cutAndShow的功能是把刚才上传的图片删除,然后把裁剪的图片显示在Canvas上,并保存图片流在input中。
content: '<img id="prephoto" src="${pageContext.request.contextPath }/uploads/' + fileName + '"/>' +
'<button class="btn btn-primary" style="margin: 20px;" onclick="cutAndShow(\'' + fileName + '\');">裁剪</button>' +
'x轴:<input type="text" readonly id="x" name="x" value="0" style="width: 50px;" /> ' +
'y轴:<input type="text" readonly id="y" name="y" value="0" style="width: 50px;" /> ' +
'长度:<input type="text" readonly id="w" name="w" value="0" style="width: 50px;" /> ' +
'宽度:<input type="text" readonly id="h" name="h" value="0" style="width: 50px;" /> '
});
// 裁剪插件
$("#prephoto").Jcrop({
minSize: [ 80, 80 ],  // 最小尺寸
aspectRatio: 1,  // 等宽高
onSelect: updateCoords
});

}
// 及时更新裁剪区域坐标和尺寸
function updateCoords(c)
{
$('#x').val(c.x);
$('#y').val(c.y);
$('#w').val(c.w);
$('#h').val(c.h);
};
// 裁剪图片并显示在画布
function cutAndShow(fileName) {
// 删除未裁剪的图片
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath }/business/product/deleteImageAjax",
async: false,
data: {"fileName": fileName},
success: function(result) {
}
});
var x = $("#x").val();
var y = $("#y").val();
var w = $("#w").val();
var h = $("#h").val();
if (x == 0 || y == 0 || w == 0 || h == 0) {
alert("请裁剪图像");
}
var img = document.getElementById("prephoto");
var c=document.getElementById("oldConvas");
var ctx = c.getContext("2d");
ctx.drawImage(img, x, y, w, h,0,0,100,100);  // 画出图片,尺寸100x100
var newImg = c.toDataURL("image/jpeg");  // 获得图片流
$(".photoStream").val(newImg);  // 将图片字符流存储在input中
layer.closeAll();  // 关闭所有窗口
}


<!-- 这是另一个表单,用来上传图片和其他内容 -->
<form class="form-horizontal" role="form" method="post" onsubmit="return validate();" action="${pageContext.request.contextPath }/business/product/add.action">
<!-- 裁剪后的图片 -->
<div class="form-group namediv">
<label class="col-sm-2" for="name" style="font-size: 15px;"></label>
<div class="col-sm-6">
<span class="text text-danger">上传图片要求:格式jpg/jpeg/png/gif/bmp,大小<=2m,尺寸<=500x500,裁剪后图片尺寸为100x100</span>
<div style="width: 100px; height: 100px; border: 1px solid black;"><canvas id="oldConvas" width="100px" height="100px"></canvas></div>
<input type="hidden" class="photoStream" id="photoStream" name="photoStream" />
</div>
</div>
<!-- 其他表单内容,不写了 -->
</form>


/**
* 异步上传图片并返回图片名称
* @param model
* @param request
* @param response
* @param file 上传的图片
* @throws Exception
*/
@RequestMapping(value="getFileLocationAjax",method=RequestMethod.POST)
public void getFileLocationAjax(Model model, HttpServletRequest request, HttpServletResponse response, @RequestParam("photo") CommonsMultipartFile file) throws Exception  {
if (!file.isEmpty()) {
InputStream in = file.getInputStream();
String fileName = saveImage(request, in); // 调用保存图片方法
// 保存图片名,方便剪切后删除
model.addAttribute("fileName", fileName);
response.setContentType("html/text; charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.print(fileName);
}
}
/**
* 保存图片到上传路径的方法
* @param request
* @param in 图片输入流
* @throws Exception
* @return 返回文件名
*/
public String saveImage(HttpServletRequest request, InputStream in) throws Exception {
String fileName = UUIDUtils.getUUID() + ".jpg";  // 随机文件名
String savePath = request.getSession().getServletContext().getRealPath("/WEB-INF/uploads") + "/"; // 获得保存路径
File f = new File(savePath);
if (!f.exists()) {
f.mkdirs();
}
FileOutputStream fos = new FileOutputStream(savePath + fileName);
int b = 0;
while ((b = in.read()) != -1) {
fos.write(b);
}
fos.close();
in.close();
return fileName;
}


/**
* 异步删除上传的文件
* @param response
* @param request
* @param fileName 文件名
* @throws Exception
*/
@RequestMapping(value="/deleteImageAjax")
public void deleteImageAjax(HttpServletRequest request, String fileName) throws Exception {
System.out.println("图片名为:" + fileName);
String savePath = request.getSession().getServletContext().getRealPath("/WEB-INF/uploads") + "/"; // 获得保存路径
File file = new File(savePath + fileName);
boolean flag = false;
if (!file.exists()) {
System.out.println("文件不存在,无法删除");
} else {
if (file.isFile()) {
flag = file.delete();
}
}
}


/**
* 根据图片流保存图片
* @param request
* @param data 图片流
* @throws Exception
* @return 图片名称
*/
public String saveImageByStrem(HttpServletRequest request, String data) throws Exception {
Base64 base64 = new Base64();
// 获得图片流,实际图片数据从data:image/jpeg;base64开始
byte[] b = base64.decodeBase64(data.substring("data:image/jpeg;base64,".length()));
InputStream in = new ByteArrayInputStream(b);
String fileName = saveImage(request, in);  // 保存图片
return fileName;
}


心得

前端插件满天飞,经常造成选择困难症。遇到一个插件,觉得难用就放弃了,换一个插件,还是嫌麻烦,又换一个,结果进入了一个死循环。既浪费时间,又影响心情。插件是来简便开发的,不是来折腾的!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ajax canvas