圖片裁剪是圖像處理常見需求。本文基於 Java 原生 ImageIO API 實現無損圖片裁剪,支援 JPG/PNG 格式,採用流式處理避免大圖載入記憶體溢出,通過 ImageReadParam 設置源區域實現高效解碼裁剪。
封裝裁剪參數 (x, y, width, height)、源/目標路徑、格式常量。提供構造器與 Getter/Setter,主方法演示裁剪 (134,0) 起點、366x366 區域。
public class ImageCut {
private String srcpath = "e:/poool.jpg";
private String subpath = "e:/pool_end";
private static final String IMAGE_FORM_OF_JPG = "jpg";
private static final String IMAGE_FORM_OF_PNG = "png";
private int x, y, width, height;
public ImageCut() {}
public ImageCut(int x, int y, int width, int height) {
this.x = x; this.y = y; this.width = width; this.height = height;
}
public static void main(String[] args) throws Exception {
ImageCut imageCut = new ImageCut(134, 0, 366, 366);
imageCut.cut(imageCut.getSrcpath(), imageCut.getSubpath());
}
// ...
}
根據文件後綴動態選擇 ImageReader,支援擴展更多格式 (BMP, TIFF, GIF 等)。
public Iterator<ImageReader> getImageReadersByFormatName(String postFix) {
switch (postFix.toLowerCase()) {
case IMAGE_FORM_OF_JPG:
return ImageIO.getImageReadersByFormatName("jpeg"); // 標準格式名
case IMAGE_FORM_OF_PNG:
return ImageIO.getImageReadersByFormatName("png");
default:
return ImageIO.getImageReadersByFormatName("jpeg");
}
}
關鍵步驟:創建輸入流 → 獲取後綴 → 獲取 Reader → 創建 ImageInputStream → 設置輸入源 (僅向前搜索) → 獲取默認 ReadParam → 設置源區域 Rectangle → 讀取裁剪區域 → 寫入目標文件 (帶時間戳避免衝突)。
public void cut(String srcpath, String subpath) throws IOException {
FileInputStream is = null;
ImageInputStream iis = null;
try {
is = new FileInputStream(srcpath);
String postFix = getPostfix(srcpath);
System.out.println("圖片格式為:" + postFix);
Iterator<ImageReader> it = getImageReadersByFormatName(postFix);
ImageReader reader = it.next();
iis = ImageIO.createImageInputStream(is);
reader.setInput(iis, true); // 僅向前搜索,優化記憶體
ImageReadParam param = reader.getDefaultReadParam();
Rectangle rect = new Rectangle(x, y, width, height);
param.setSourceRegion(rect); // 核心:設置裁剪區域
BufferedImage bi = reader.read(0, param); // 讀取第0幀並應用參數
// 保存:目標路徑_時間戳.後綴
String outputPath = subpath + "_" + new Date().getTime() + "." + postFix;
ImageIO.write(bi, postFix, new File(outputPath));
} finally {
if (is != null) is.close();
if (iis != null) iis.close();
}
}
public String getPostfix(String inputFilePath) {
return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1);
}
| 組件/類 | 作用 | 關鍵配置 |
|---|---|---|
| ImageIO | 統一圖像 I/O 入口 | createImageInputStream、getImageReadersByFormatName、write |
| ImageReader | 特定格式解碼器 | setInput(輸入流, 僅向前)、read(索引, ReadParam) |
| ImageReadParam | 解碼參數控制 | setSourceRegion(Rectangle) 設置裁剪區域 |
| Rectangle | 矩形區域定義 | (x, y, width, height) 坐標原點左上角 |
| ImageInputStream | 隨機訪問輸入流 | 支援標記/重置、僅向前模式節省緩衝 |
在 getImageReadersByFormatName 中添加 case 分支即可,常見格式名對應:
| 問題 | 原因 | 解決 |
|---|---|---|
| 裁剪結果空白/全黑 | 坐標超出圖片範圍 | 裁剪前讀取圖片寬高驗證 Rectangle 邊界 |
| 輸出圖片失真 | JPG 重複壓縮質量損失 | 設置 ImageWriteParam 壓縮質量 0.9+ 或輸出 PNG |
| PNG 透明背景變黑 | 未正確處理 Alpha 通道 | 確保 BufferedImage 類型為 TYPE_INT_ARGB |
| 大圖 OOM | 完整解碼載入堆內存 | 使用 setInput(..., true) 僅向前模式 + 增加堆內存 |
| 格式不支援 | 無對應 ImageReader 插件 | 引入 TwelveMonkeys ImageIO 插件庫擴展格式支援 |