【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

时间:2023-03-09 01:06:15
【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

  web网站中常常有的功能:上传头像、上传封面等;一般图片都有一定的比例限制,所以需要前端在上传图片时,进行裁剪,并把裁剪后的图片进行上传。

  本例采用Jcrop插件实现裁剪效果,canvas裁剪图片,并把base64位的toDataURL图片转换成blob(二进制数据),最后使用XMLHttpRequest上传到服务器。

  Jcrop演示及下载地址:http://code.ciaoca.com/jquery/jcrop/demo/

Jcrop的使用

  本例做Jcrop的简单预览功能(同理可以实现网页的放大镜功能)

  • 载入 CSS 文件
     <link rel="stylesheet" href="jquery.Jcrop.css">
  • 载入 JavaScript 文件
     <script src="jquery.js"></script>
    <script src="jquery.Jcrop.js"></script>
  • 给 IMG 标签加上 ID
     <img id="element_id" src="pic.jpg">
  • 调用 Jcrop
     $('#element_id').Jcrop();

实例代码

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图像裁剪-Jcrop</title>
<link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
<style>
img {
border: 0px;
}
* {
margin: 0;
padding: 0;
}
.head {
width: 600px;
height: 600px;
background-color: gray;
}
#target{
max-width: 600px;
max-height: 600px;
} #preview-pane {
position: fixed;
top: 0;
right: 0;
width: 300px;
height: 300px;
overflow: hidden;
border: 1px solid purple;
}
#preview-pane .preview-container {
width: 100%;
height: 100%;
}
#preview-pane .preview-container img{
max-width: 100%;
max-height: 100%; }
</style>
</head>
<body> <!-- 头像 -->
<div class="head" >
<img src="data:images/IMG_0109.JPG" id="target" alt="[Jcrop Example]" />
</div> <!-- 预览盒子 -->
<div id="preview-pane">
<div class="preview-container">
<img src="data:images/IMG_0109.JPG" class="jcrop-preview" alt="Preview" id="Preview"/>
</div>
</div> <script src="js/jquery.min.js"></script>
<script src="js/jquery.Jcrop.js"></script>
<script type="text/javascript"> // 定义一些使用的变量
var jcrop_api,//jcrop对象
boundx,//图片实际显示宽度
boundy,//图片实际显示高度
realWidth,// 真实图片宽度
realHeight, //真实图片高度 // 使用的jquery对象
$target = $('#target'),
$preview = $('#preview-pane'),
$pcnt = $('#preview-pane .preview-container'),
$pimg = $('#preview-pane .preview-container img'), xsize = $pcnt.width(),
ysize = $pcnt.height(); //初始化Jcrop插件
function initJcrop(){ console.log('init',[xsize,ysize]);
$target.removeAttr("style");//清空上一次初始化设置的样式
$target.Jcrop({
onChange: updatePreview,
onSelect: updatePreview,
aspectRatio: xsize / ysize
},function(){
//初始化后回调函数
// 获取图片实际显示的大小
var bounds = this.getBounds();
boundx = bounds[0];//图片实际显示宽度
boundy = bounds[1];//图片实际显示高度 // 保存jcrop_api变量
jcrop_api = this; });
} //更新显示预览内容
function updatePreview(c){
if (parseInt(c.w) > 0)
{
var rx = xsize / c.w;
var ry = ysize / c.h; $pimg.css({
maxWidth: Math.round(rx * boundx) + 'px',
maxHeight: Math.round(ry * boundy) + 'px',
width: Math.round(rx * boundx) + 'px',
height: Math.round(ry * boundy) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
});
}
} window.onload = function () {
initJcrop();
}; </script>
</body>
</html>

  预览效果

    【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

Canvas的使用

  定义:<canvas> 标签定义图形,比如图表和其他图像。

  注意:canvas标签的宽高与标签样式的宽高问题,把Canvas 比作是一个画板和一张画纸,标签宽高相当于画板,样式宽高相当于画纸。

  canvas裁剪图片,准备上传

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图像裁剪-Jcrop</title>
<link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
<style>
img {
border: 0px;
}
* {
margin: 0;
padding: 0;
}
.head {
width: 600px;
height: 600px;
background-color: gray;
}
#target{
max-width: 600px;
max-height: 600px;
}
canvas {
position: fixed;
top: 0;
right: 0;
border: 1px solid red;
width: 200px;
height: 200px;
}
</style> </head>
<body> <!-- 头像 -->
<div class="head" >
<img src="data:images/IMG_0109.JPG" id="target" alt="[Jcrop Example]" />
</div> <!-- 画板 -->
<canvas id="myCan" width="200" height="200"></canvas> <script src="js/jquery.min.js"></script>
<script type="text/javascript"> initCanvas(); //初始化canvas画板内容
function initCanvas(){
//更新canvas画板内容
var img= document.getElementById("target");
var ct= document.getElementById("myCan");
var ctx = ct.getContext("2d"); //清空画板
ctx.clearRect(0,0, ct.width, ct.height);
//.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
//矩形框[150,150,200,200]--原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度
ctx.drawImage(img, 150, 150, 200, 200, 0,0, ct.width , ct.height);
} </script>
</body>
</html>

  预览
    【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

完整代码展示

  html代码

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图像裁剪-Jcrop</title>
<link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
<style>
img {
border: 0px;
}
* {
margin: 0;
padding: 0;
}
.head {
width: 600px;
height: 600px;
background-color: gray;
}
#target{
max-width: 600px;
max-height: 600px;
} #preview-pane {
position: fixed;
top: 0;
right: 0;
width: 300px;
height: 300px;
overflow: hidden;
border: 1px solid purple;
}
#preview-pane .preview-container {
width: 100%;
height: 100%; } canvas {
position: fixed;
top: 400px;
right: 0;
border: 1px solid red;
width: 200px;
height: 200px;
}
</style> </head>
<body> <!-- 头像 -->
<div class="head" >
<img src="" id="target" alt="[Jcrop Example]" />
<input type="file" id="file" onchange="changeFile()" style="display: none;"/>
</div>
<button onClick="openBrowse()">上传图片</button>
<button onClick="uploadFile()">确认</button> <!-- 预览盒子 -->
<div id="preview-pane">
<div class="preview-container">
<img src="" class="jcrop-preview" alt="Preview" id="Preview"/>
</div>
</div> <!-- 画板 -->
<canvas id="myCan" width="200" height="200"></canvas> <script src="js/jquery.min.js"></script>
<script src="js/jquery.Jcrop.js"></script>
<script type="text/javascript"> // 定义一些使用的变量
var jcrop_api,//jcrop对象
boundx,//图片实际显示宽度
boundy,//图片实际显示高度
realWidth,// 真实图片宽度
realHeight, //真实图片高度 // 使用的jquery对象
$target = $('#target'),
$preview = $('#preview-pane'),
$pcnt = $('#preview-pane .preview-container'),
$pimg = $('#preview-pane .preview-container img'), xsize = $pcnt.width(),
ysize = $pcnt.height(); //1、打开浏览器
function openBrowse(){
var ie=navigator.appName=="Microsoft Internet Explorer" ? true : false;
if(ie){
document.getElementById("file").click();
}else{
var a=document.createEvent("MouseEvents");
a.initEvent("click", true, true);
document.getElementById("file").dispatchEvent(a);
}
} //2、从 file 域获取 本地图片 url
function getFileUrl(sourceId) {
var url;
if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
url = document.getElementById(sourceId).value;
} else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
} else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
} else if(navigator.userAgent.indexOf("Safari")>0) { // Chrome
url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
}
return url;
}
//选择文件事件
function changeFile() {
var url = getFileUrl("file");//根据id获取文件路径
preImg(url);
return false;
} //3、将本地图片 显示到浏览器上
function preImg(url) { console.log('url===' + url);
//图片裁剪逻辑
if(jcrop_api)//判断jcrop_api是否被初始化过
{
jcrop_api.destroy();
} //初始化预览div内容
initPreview();
var p = document.getElementById('Preview');
p.src = url; //初始化图片
initTarget();
var image = document.getElementById('target');
image.onload=function(){//图片加载是一个异步的过程
//获取图片文件真实宽度和大小
var img = new Image();
img.onload=function(){
realWidth = img.width;
realHeight = img.height; //获取图片真实高度之后
initJcrop();//初始化Jcrop插件
initCanvas();//初始化Canvas内容
};
img.src = url;
};
image.src = url;
} //初始化Jcrop插件
function initJcrop(){ console.log('init',[xsize,ysize]);
$target.removeAttr("style");//清空上一次初始化设置的样式
$target.Jcrop({
onChange: updatePreview,
onSelect: updatePreview,
aspectRatio: xsize / ysize
},function(){
//初始化后回调函数
// 获取图片实际显示的大小
var bounds = this.getBounds();
boundx = bounds[0];//图片实际显示宽度
boundy = bounds[1];//图片实际显示高度 // 保存jcrop_api变量
jcrop_api = this; });
} //更新显示预览内容
function updatePreview(c){
if (parseInt(c.w) > 0)
{
var rx = xsize / c.w;
var ry = ysize / c.h; $pimg.css({
maxWidth: Math.round(rx * boundx) + 'px',
maxHeight: Math.round(ry * boundy) + 'px',
width: Math.round(rx * boundx) + 'px',
height: Math.round(ry * boundy) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
}); //更新canvas画板内容
var img=document.getElementById("target");
var ct=document.getElementById("myCan");
var ctx=ct.getContext("2d");
//清空画板
ctx.clearRect(0,0, ct.width, ct.height);
//.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
ctx.drawImage(img, c.x/boundx * realWidth,c.y/boundy * realHeight, c.w/boundx * realWidth, c.h/boundy * realHeight,0,0, ct.width, ct.height);
}
} //初始化预览div内容
function initTarget(){
$target.removeAttr("style");//清空上一次初始化设置的样式
$target.css({
maxWidth: '100%',
maxHeight: '100%'
});
}
//初始化预览div内容
function initPreview(){
$pimg.removeAttr("style");//清空上一次初始化设置的样式
$pimg.css({
maxWidth: xsize + 'px',
maxHeight: ysize + 'px'
});
} //初始化canvas画板内容
function initCanvas(){
//更新canvas画板内容
var img= document.getElementById("target");
var ct= document.getElementById("myCan");
var ctx = ct.getContext("2d"); var myCanWidth = $('#myCan').width();
var myCanHeight = $('#myCan').height(); //清空画板
ctx.clearRect(0,0, ct.width, ct.height); //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
var dWidth = realWidth;//绘制实际宽度
var dHeight = realHeight;//绘制实际高度
if(dWidth > myCanWidth)
{
dHeight = myCanWidth / dWidth * dHeight;
dWidth = myCanWidth;
}
if(dHeight > myCanHeight)
{
dWidth = myCanHeight / dHeight * dWidth ;
dHeight = myCanHeight;
}
ctx.drawImage(img,0,0, realWidth, realHeight, 0,0, dWidth, dHeight);
} //文件上传
function uploadFile(){
//获取裁剪完后的base64图片url,转换为blob
var data=document.getElementById("myCan").toDataURL();
var formData=new FormData();
formData.append("imageName",dataURLtoBlob(data));
var httprequest= null;
if (window.XMLHttpRequest) {
httprequest = new XMLHttpRequest();
} else {
httprequest = new ActiveXObject('MicroSoft.XMLHTTP');
}
var apiurl= ""; //上传图片的api接口,自行填写
httprequest.open('POST',apiurl,true);
httprequest.send(formData);
httprequest.onreadystatechange= function () { if(httprequest.readyState == 4 ){ if(httprequest.status == 200)
{
var json=JSON.parse(httprequest.responseText);
console.log(json); }else
{
alert('获取数据错误,错误代码:' + httprequest.status + '错误信息:' + httprequest.statusText);
}
}
};
} //把base64位的toDataURL图片转换成blob
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
} window.onload = function () {
//初始化图片
preImg('images/IMG_0109.JPG');
}; </script>
</body>
</html>

   图片上传接口可以参照:【Java】JavaWeb文件上传和下载

  注意:canvas在裁剪图片的时候有跨域的问题,如果裁剪网络图片,会报异常:Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

  本例服务端采用的方法是:服务器转发网络图片,进行图片访问。

    页面*问:<img src="img/getImg?imgUrl=http://test.example.net/a/b/c/123456.jpg"/>

    服务端JAVA代码:

 @RequestMapping(value = "/getImg")
public void getImg(HttpServletRequest request, HttpServletResponse response, String imgUrl) throws Exception
{
// 统一资源
URL url = new URL(imgUrl);
// 连接类的父类,抽象类
URLConnection urlConnection = url.openConnection();
// http的连接类
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
// 设定请求的方法,默认是GET
httpURLConnection.setRequestMethod("POST");
// 设置字符编码
httpURLConnection.setRequestProperty("Charset", "UTF-8");
// 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。
httpURLConnection.connect(); BufferedInputStream bin = new BufferedInputStream(httpURLConnection.getInputStream());
ServletOutputStream outputStream = response.getOutputStream(); int size = 0;
byte[] buf = new byte[1024*10];
while ((size = bin.read(buf)) != -1) {
outputStream.write(buf, 0, size);
}
bin.close();
outputStream.close();
}

  预览效果

    【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)