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>

  预览效果

    

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>

  预览
    

完整代码展示

  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)的更多相关文章

  1. HTML5裁剪图片并上传至服务器实现原理讲解

    HTML5裁剪图片并上传至服务器实现原理讲解   经常做项目需要本地上传图片裁剪并上传服务器,比如会议头像等功能,但以前实现这类需求都很复杂,往往需要先把图片上传到服务器,然后返回给用户,让用户确定裁 ...

  2. HTML5 本地裁剪图片并上传至服务器(转)

    很多情况下用户上传的图片都需要经过裁剪,比如头像啊什么的.但以前实现这类需求都很复杂,往往需要先把图片上传到服务器,然后返回给用户,让用户确定裁剪坐标,发送给服务器,服务器裁剪完再返回给用户,来回需要 ...

  3. 小程序踩坑记录-上传图片及canvas裁剪图片后上传至服务器

    最近在写微信小程序的上传图片功能,趟过了一些坑记录一下. 想要满足的需求是,从手机端上传图片至服务器,为了避免图片过大影响传输效率,需要把图片裁剪至适当大小后再传输 主要思路是,通过wx.choose ...

  4. HTML5 Canvas前台压缩图片并上传到服务器

    1.前台代码: <input id="fileOne" type="file" /> <input id="btnOne" ...

  5. js实现图片粘贴上传到服务器并展示

    最近看了一些有关于js实现图片粘贴上传的demo,实现如下: (这里只能检测到截图粘贴和图片右键复制之后粘贴) demo1: document.addEventListener('paste', fu ...

  6. jquery photoClip支持手机端,PC端 本地裁剪图片后上传插件

    支持手机,PC最好的是jquery photoClip插件,下载地址&示例:https://github.com/topoadmin/photoClip demo.html 代码: <! ...

  7. PHP裁剪图片并上传完整demo

    日前根据功能需求,要做一个图片裁剪上传的功能,在网上找了好久,找到了这位仁兄写的demo! 下载压缩包

  8. Web文件(图片)上传方法

    在开放Web应用程序的时候经常会遇到图片或者是文件上传的模块,这里就是该模块的实现的后台方法 上传图片方法 /// <summary> /// 功能:上传图片方法 /// </sum ...

  9. base64字符串转文件,以及ngImgCrop裁剪图片并上传保存到服务器示例

    base64字符串是包含文件格式的文件字符串,例如:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAgAElE ...

  10. cropper实现基本的裁剪图片并上传

    使用cropper之前需要先引用 cropper.css 和 cropper.js cropper 官网:https://fengyuanchen.github.io/cropper/ cropper ...

随机推荐

  1. hdu 5154 拓扑排序

    例题:hdu 5154 链接  http://acm.hdu.edu.cn/showproblem.php?pid=5154 题目意思是第一行先给出n和m表示有n件事,m个关系,接下来输入m行,每行有 ...

  2. PAT1066(AVL树)

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  3. 分布式处理框架MapReduce的深入简出

    1).MapReduce的概述 2).MapReduce 编程模型 3).MapReduce架构 4).MapReduce编程 Google MapReduce论文,论文发表于2004年 Hadoop ...

  4. Balanced Numbers (数位DP)

    Balanced Numbers https://vjudge.net/contest/287810#problem/K Balanced numbers have been used by math ...

  5. 关于viewport我自己的理解

    其实即使不在html中添加meta viewport标签,每个移动端浏览器都会有一个默认的viewport,只是这个viewport的宽度是980,然后做1:3或者1:2的自动缩放.所以当不在html ...

  6. polymorphism多态

    [概念] 方法名相同,具体操作根据类不同. eg 有open()方法的ebook, kindle 都会被打开 eg 动物叫声不同 inheritance:只有superclass subclass都有 ...

  7. [leetcode]128. Longest Consecutive Sequence最长连续序列

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. Y ...

  8. 36-2018 蓝桥杯Java B组试题及答案

    1:第几天2000年的1月1日,是那一年的第1天.那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数,不要填写任何多余内容. 用excel算,答案125. 2.标题:方格计数 ...

  9. 使用JFinal实现使用MVC获取表单中的数据并将提示信息返回给另一jsp页面。

    1.包结构 2.我们需要对web.xml进行配置: <?xml version="1.0" encoding="UTF-8"?> <web-a ...

  10. c# ?. 空值传播运算符

    当左侧为空时不执行右侧代码,避免出现为null的错误,同时也避免了判断是否为null,可以和??一起连用,省了好多事.举例如下: 以前:var res=obj==null?5:obj.a; 现在:va ...