在 Web 開發中,用戶頭像上傳與裁切是常見需求。本文將詳細介紹如何結合 JCrop(jQuery 圖片裁切插件)與 ajaxUpload(非同步文件上傳)實現圖片的選取、預覽、裁切與上傳全流程。文章包含前端頁面代碼、後端處理邏輯及圖片裁切工具類,幫助開發者快速落地該功能。
實現效果如下圖所示,用戶可上傳圖片、拖拽選取裁切區域、即時預覽,最後提交至後端進行裁切存儲。

相關 JS、CSS 及示例圖片可從百度網盤獲取:
鏈接:https://pan.baidu.com/s/1b8SI6M 密碼:59ct
頁面基於 JSP 編寫,引入 JCrop 樣式與腳本、ajaxfileupload.js 以及 jQuery。核心結構包含目標圖片區域、預覽面板、文件選擇按鈕與提交按鈕。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>用戶頭像剪裁</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<link rel="stylesheet" href="resources/Jcrop/css/jquery.Jcrop.css">
<link rel="stylesheet" href="resources/css/photo.css">
<script src="resources/js/jquery.min.js"></script>
<script src="resources/Jcrop/js/jquery.Jcrop.js"></script>
<script src="resources/js/ajaxfileupload.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="span12">
<div class="jc-demo-box">
<div class="page-header">
<h1>頭像剪裁</h1>
</div>
<img src="resources/img/test.jpg" id="target" />
<div id="preview-pane">
<div class="preview-container">
<img src="resources/img/test.jpg" class="jcrop-preview"/>
</div>
<div style='float:left;display:inline;'>
<a class='btn_addPic' href="javascript:void(0);">
<span><em>+</em>添加圖片</span>
<input id="upload_image" type="file" name="upimage" accept="image/*" class="filePrew"/>
</a>
</div>
<div style='float:right;display:inline;'>
<a class='btn_addPic' href="javascript:void(0);" onclick='submit()'>
<span>提交</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var global_api = "";
var boundx = "", boundy = "";
var tag = false;
$(function() {
var jcrop_api;
var $preview = $('#preview-pane');
var $pcnt = $('#preview-pane .preview-container');
var $pimg = $('#preview-pane .preview-container img');
var xsize = $pcnt.width();
var ysize = $pcnt.height();
$('#target').Jcrop({
onChange: updatePreview,
onSelect: updatePreview,
aspectRatio: xsize / ysize
}, function() {
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
jcrop_api = this;
$preview.appendTo(jcrop_api.ui.holder);
});
function updatePreview(c) {
if (parseInt(c.w) > 0) {
global_api = c;
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'
});
}
}
// 圖片選擇後即時預覽
$('#upload_image').change(function(event) {
var files = event.target.files;
if (files && files.length > 0) {
var file = files[0];
var URL = window.URL || window.webkitURL;
var imgURL = URL.createObjectURL(file);
$('.jcrop-holder img').attr('src', imgURL);
$('.preview-container img').attr('src', imgURL);
}
});
$("#upload_image").change(function() {
tag = true;
});
});
// 提交裁切請求
function submit() {
if (tag && global_api != "") {
ajaxFileUpload();
} else {
alert('請先選擇圖片並進行裁切!');
}
}
// 非同步文件上傳
function ajaxFileUpload() {
$.ajaxFileUpload({
url: 'uploadphoto',
secureuri: false,
fileElementId: 'upload_image',
dataType: 'json',
data: {
x: global_api.x,
y: global_api.y,
w: global_api.w,
h: global_api.h,
pw: boundx,
ph: boundy,
unid: 'test'
},
success: function(data) {
if (data.result) {
alert('上傳成功');
} else {
alert('上傳失敗');
}
window.location.reload();
}
});
}
</script>
</body>
</html>
Spring MVC 控制器接收上傳文件與裁切參數,調用工具類進行圖片裁切,並將裁切後的二進制數據存入數據庫。
@ResponseBody
@RequestMapping("uploadphoto")
public Map<String, Object> uploadPhoto(
@RequestParam("upimage") MultipartFile imageFile,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
Map<String, Object> result = new HashMap<>();
boolean success = false;
String unid = request.getParameter("unid");
int imageX = Integer.parseInt(request.getParameter("x"));
int imageY = Integer.parseInt(request.getParameter("y"));
int imageW = Integer.parseInt(request.getParameter("w"));
int imageH = Integer.parseInt(request.getParameter("h"));
int srcW = Integer.parseInt(request.getParameter("pw"));
int srcH = Integer.parseInt(request.getParameter("ph"));
try {
if (imageFile != null && FileUploadUtil.allowUpload(imageFile.getContentType())) {
byte[] croppedBytes = ImageCut.imgCut(
imageFile.getInputStream(),
imageX, imageY, imageW, imageH,
srcW, srcH
);
if (croppedBytes != null) {
User user = userService.selectByPrimaryKey(unid);
user.setPhoto(croppedBytes);
success = (userService.updateByPrimaryKeySelective(user) == 1);
}
}
} catch (Exception e) {
e.printStackTrace();
}
result.put("result", success);
return result;
}
使用 Java AWT 實現圖片縮放與裁切,輸出 JPEG 格式字節數組。
package com.ssm.demo.utils;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;
public class ImageCut {
/**
* 裁切圖片
* @param input 原圖輸入流
* @param x 裁切起始 X 坐標
* @param y 裁切起始 Y 坐標
* @param desWidth 裁切寬度
* @param desHeight 裁切高度
* @param srcWidth 頁面顯示寬度
* @param srcHeight 頁面顯示高度
* @return 裁切後的 JPEG 字節數組
*/
public static byte[] imgCut(InputStream input, int x, int y,
int desWidth, int desHeight,
int srcWidth, int srcHeight) {
try {
BufferedImage bi = ImageIO.read(input);
if (srcWidth >= desWidth && srcHeight >= desHeight) {
Image scaled = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
ImageFilter cropFilter = new CropImageFilter(x, y, desWidth, desHeight);
Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(scaled.getSource(), cropFilter));
BufferedImage tag = new BufferedImage(desWidth, desHeight, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(tag, "JPEG", out);
return out.toByteArray();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
本文完整展示了 JCrop + ajaxUpload 實現圖片裁切上傳的全流程代碼。關鍵點在於:前端通過 JCrop 獲取裁切坐標與縮放比例,配合 HTML5 File API 實現本地圖片預覽;後端根據接收到的參數對原圖進行等比縮放後裁切,最終存儲為二進制數據。開發者可根據業務需求調整裁切比例、輸出格式或存儲方式(如存文件系統而非數據庫)。