核心需求場景
- 用戶上傳頭像/附件,需限制檔案大小與尺寸
- 生成縮圖用於列表展示,節省頻寬與載入時間
- 批量處理圖片存儲,控制磁碟佔用
ImageProcess 工具類設計
public class ImageProcess {
private Image img;
private int width, height;
private String imageFormat;
public ImageProcess(InputStream in, String fileName) throws Exception {
img = ImageIO.read(in);
width = img.getWidth(null);
height = img.getHeight(null);
imageFormat = fileName.substring(fileName.lastIndexOf(".") + 1);
}
/** 智能壓縮:根據長寬比自動選擇以寬或高為基準 */
public byte[] resizeFix(int maxW, int maxH) throws IOException {
return (width * 1.0 / height > maxW * 1.0 / maxH)
? resizeByWidth(maxW) : resizeByHeight(maxH);
}
/** 以寬度為基準等比縮放 */
public byte[] resizeByWidth(int w) throws IOException {
int h = (int) (height * w / (double) width);
return resize(w, h);
}
/** 以高度為基準等比縮放 */
public byte[] resizeByHeight(int h) throws IOException {
int w = (int) (width * h / (double) height);
return resize(w, h);
}
/** 強制縮放至固定尺寸(可能變形) */
public byte[] resize(int w, int h) throws IOException {
BufferedImage target = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
target.getGraphics().drawImage(img, 0, 0, w, h, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(target, imageFormat, baos);
return baos.toByteArray();
}
}
關鍵技術點解析
- BufferedImage.TYPE_INT_RGB:標準 RGB 模型,適合 JPEG 輸出。若需透明背景請用
TYPE_INT_ARGB。
Graphics.drawImage(img, 0, 0, w, h, null):核心縮放繪製,SCALE_SMOOTH 隱含於 ImageIO.write 編碼器中。
ByteArrayOutputStream:內存流輸出,避免臨時文件 I/O,適合 Web 上傳直傳對象存儲。
- 格式保持:自動從原文件名解析副檔名(jpg/png/gif/bmp),保持原格式輸出。
進階優化建議
- 質量控制:JPEG 輸出時可用
ImageWriteParam 設置壓縮質量(0.7-0.9 平衡點)
- 大圖分塊處理:超大圖(>5000px)建議使用
ImageReader 分塊讀取,避免 OOM
- 並發處理:配合
CompletableFuture 或線程池批量壓縮
- 第三方庫:
Thumbnailator、TwelveMonkeys ImageIO 提供更豐富的格式支援與元數據保留
使用示例
// Controller 層
@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam MultipartFile file) {
try (InputStream in = file.getInputStream()) {
ImageProcess processor = new ImageProcess(in, file.getOriginalFilename());
byte[] compressed = processor.resizeFix(800, 600); // 限制長邊 800px
// 上傳至 OSS / 保存至資料庫 BLOB
return ResponseEntity.ok("success");
} catch (Exception e) {
return ResponseEntity.status(500).body("圖片處理失敗");
}
}