功能需求 “在上传照片的时候能进行裁剪”
Jcrop是一个jQuery插件,它能为你的WEB应用程序快速简单地提供图片裁剪的功能。Jcrop官网,以下是Jcrop的一些特性:
引入插件
引入Jcrop的CSS样式
例如想要实现如下效果,效果图:
html:基本结构
<%-- 裁剪图片布局 --%>
编辑图片
js:当点击上传图片时,弹出图片选择框,选择图片之后会替换掉裁剪框内容。这里利用change方法,监听imgFile改变事件。
var width; // 裁剪框的宽度
var height; // 裁剪框的高度
var x; // 裁剪框的起点x
var y; // 裁剪框的起点y
var jcrop_api;
var xsize = $('#preview-pane .preview-container').width(); // 获取预览窗格相关信息
var ysize = $('#preview-pane .preview-container').height();
var $pimg = $('#preview-pane .preview-container img');
var $preview = $('#preview-pane');
var boundx;
var boundy;
$('#imgFile').change(function(event) {
// 根据这个 获取文件的 HTML5 js对象
var files = event.target.files, file;
if (files && files.length > 0) {
// 获取目前上传的文件
file = files[0];
// Judge file type
var fileName = file.name;
var fileType = fileName.substr(fileName.lastIndexOf(".")).toUpperCase();
if (fileType != ".BMP" && fileType != ".PNG" && fileType != ".JPG" && fileType != ".JPEG") {
alert("please select image!");
return false;
}
// 获取window的 URL工具
var URL = window.URL || window.webkitURL;
// 通过 file生成目标 url
var imgURL = URL.createObjectURL(file);
if (jcrop_api) {
jcrop_api.destroy();
}
$('#JcropImage').attr('src', imgURL);
$('#JcropPreviewImage').attr('src', imgURL);
$('#JcropImage').Jcrop({
setSelect: [ 0, 0, 2000, 2000 ],
allowResize: true,
allowSelect: false,
onChange : updatePreview,
onSelect : updatePreview,
aspectRatio : xsize / ysize,
boxWidth: 348,
boxHeight: 324
}, function() {
// 使用API来获得真实的图像大小
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
jcrop_api = this;
// 预览进入jcrop容器css定位
$preview.appendTo(jcrop_api.ui.holder);
updatePreview();
});
}
});
function updatePreview(c) {
var jcropImage = $('#JcropImage').attr('src');
var jcropPreviewImage = $('#JcropPreviewImage').attr('src');
if (jcropImage != jcropPreviewImage) {
$('#JcropPreviewImage').attr('src', jcropImage);
$('#JcropPreviewImage').css('width', xsize);
$('#JcropPreviewImage').css('height', '');
}
if (c != undefined){
if (parseInt(c.w) > 0) {
var rx = xsize / c.w;
var ry = ysize / c.h;
$pimg.css({
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'
});
}
x = Math.round(c.x);
y = Math.round(c.y);
width = Math.round(c.w);
height = Math.round(c.h);
}
};
$('.cut').off('click').on('click', function() {
var formData = new FormData();
formData.append(nameSpace + 'file', $('#imgFile')[0].files[0]);
formData.append(nameSpace + 'startX', x);
formData.append(nameSpace + 'startY', y);
formData.append(nameSpace + 'width', width);
formData.append(nameSpace + 'height', height);
formData.append(nameSpace + 'realW', Math.round(boundx));
formData.append(nameSpace + 'realH', Math.round(boundy));
$.ajax({
// send ajax request
})
});
.dialog-mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
outline: 0;
-webkit-overflow-scrolling: touch;
background-color: rgb(0, 0, 0);
filter: alpha(opacity=60);
background-color: rgba(0, 0, 0, 0.6);
z-index: 1001;
width: 150%;
display: none;
}
.jcrop_warpper {
width: 148%;
height: 148%;
position: fixed;
z-index: 1002;
left: 14%;
top: 18%;
padding: 0% 77% 0% 0%;
display: none;
}
#crop_image {
float: left;
width: 100%;
background-color: #333;
user-select: none;
border: 1px solid #DEDEDE;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
display: none;
}
#crop_image_top,#crop_image_bottom {
float: left;
width: 100%;
padding: 2%;
background-color: white;
}
#crop_image_bottom {
text-align: right;
}
#crop_image_bottom input {
height: 30px;
padding: 5px 15px;
border-radius: 3px;
border: none;
margin-left: 20px;
outline: none;
}
#submitBtn {
color: white;
cursor: pointer;
}
#crop_image_top h4 {
margin: 0;
padding: 0;
font-weight: normal;
}
#crop_image_content {
float: left;
position: relative;
text-align: center;
width: 100%;
margin: 3%;
min-height: 200px;
max-height: 400px;
}
.jcrop-holder {
left: 23px;
}
.jcrop-holder #preview-pane {
display: block;
position: absolute;
z-index: 2000;
top: 0px;
left: 475px;
padding: 6px;
border: 1px rgba(0, 0, 0, .4) solid;
background-color: white;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
}
/* The Javascript code will set the aspect ratio of the crop
area based on the size of the thumbnail preview,
specified here */
#preview-pane .preview-container {
width: 348px;
height: 162px;
overflow: hidden;
}
#JcropPreviewImage {
width: 348px;
}
后台:
public void cutImageAndImport(ResourceRequest request, ResourceResponse response) {
//获取前台参数
int x = *******;
int y = *******;
int width = *******;
int height = *******;
int realW = *******;
int realH = *******;
//将file对象转换成流
InputStream in = uploadPortletRequest.getFileAsStream(Constants.FILE);
//存储路径处理
String fileName = this.postProcessFileNameBeforeSave(origionFileName);
String filePath = httpServletRequest.getSession().getServletContext().getRealPath(Constants.UPLOAD_PATH);
String imagePath = filePath + StringPool.FORWARD_SLASH + fileName;
File file =new File(filePath);
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
File imageFile = new File(filePath, fileName);
//Cut image
Boolean cutResult = OperateImageUtil.cutImage(imagePath, in, x, y, width, height, realW, realH);
}
//图片裁剪类
public class OperateImageUtil {
public static Boolean cutImage(String imagePath, InputStream in, int x, int y, int width, int height, int realW, int realH) {
Boolean result = Boolean.TRUE;
try {
BufferedImage bi = ImageIO.read(in);
// Get image zoom out ratio, and calculate real cut size
// 解决使用Jcrop剪切图片因图片太大导致精准度丢失的解决办法
Double fileX = bi.getWidth() / (double) realW;
Double fileY = bi.getHeight() / (double) realH;
int newX =(int) (x * fileX);
int newY =(int) (y * fileY);
int newW =(int) (width * fileX);
int newH =(int) (height * fileY);
int srcWidth = bi.getWidth();
int srcHeight = bi.getHeight();
if (srcWidth > 0 && srcHeight > 0) {
Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
ImageFilter cropFilter = new CropImageFilter(newX, newY, newW, newH);
Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropFilter));
BufferedImage tag = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(img, 0, 0, newW, newH, null);
g.dispose();
ImageIO.write(tag, Constants.PNG, new File(imagePath));
}
} catch (Exception e) {
result = Boolean.FALSE;
}
return result;
}
}
//如果要下载裁剪后的图片
public void downloadImage(ResourceRequest request, ResourceResponse response) {
// Step1: Gets parameters.
String fileName = ParamUtil.getString(request, "fileName", StringPool.BLANK);
HttpServletRequest httpServletRequest = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(request));
HttpServletResponse httpServletResponse = PortalUtil.getHttpServletResponse(response);
//设置http response header "Content-Disposition" 为 attachment,浏览器会自动下载文件
httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + fileName);
String filePath = httpServletRequest.getSession().getServletContext().getRealPath("/upload");
String imagePath = filePath + "/" + fileName;
File file = new File(imagePath);
// 使用Outputstream返回文件流
byte[] buff = new byte[1024];
BufferedInputStream bis = null;
OutputStream os = null;
try {
os = httpServletResponse.getOutputStream();
bis = new BufferedInputStream(new FileInputStream(file));
int i = 0;
while ((i = bis.read(buff)) != -1) {
os.write(buff, 0, i);
os.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}