首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 圖片裁剪實戰:ImageIO + ImageReadParam 實現無損區域截取完整指南

     編輯:Java 程式設計入門

專案概述

本範例展示如何使用 Java 標準庫 javax.imageio 套件,針對 JPEG/PNG 圖片實現無解碼全圖的區域裁剪。核心在於 ImageReadParam.setSourceRegion(Rectangle),讓解碼器僅讀取指定矩形區域的像素資料,大幅降低記憶體佔用與處理時間,適合大圖縮圖、人臉截取、文件區域擷取等場景。

核心類別結構

public class ImageCut {
    private String srcpath = "e:/poool.jpg";   // 來源圖片
    private String subpath = "e:/pool_end";    // 輸出目錄(自動加時間戳+副檔名)
    private int x, y, width, height;           // 裁剪矩形

    public static void main(String[] args) throws Exception {
        new ImageCut(134, 0, 366, 366).cut(srcpath, subpath);
    }
    // ... 建構子、Getter/Setter
}

關鍵裁剪流程

public void cut(String srcpath, String subpath) throws IOException {
    FileInputStream fis = null;
    ImageInputStream iis = null;
    try {
        // 1. 開啟檔案輸入流
        fis = new FileInputStream(srcpath);

        // 2. 取得副檔名,決定格式
        String postFix = getPostfix(srcpath); // "jpg" 或 "png"

        // 3. 獲取對應格式的 ImageReader
        Iterator<ImageReader> it = getImageReadersByFormatName(postFix);
        ImageReader reader = it.next();

        // 4. 建立 ImageInputStream(標記唯向前讀取,節省緩衝)
        iis = ImageIO.createImageInputStream(fis);
        reader.setInput(iis, true); // true = seekForwardOnly

        // 5. 獲取預設讀取參數並設定來源區域
        ImageReadParam param = reader.getDefaultReadParam();
        Rectangle rect = new Rectangle(x, y, width, height);
        param.setSourceRegion(rect); // 核心:僅解碼此矩形區域

        // 6. 讀取第 0 張圖(單幀),返回裁剪後的 BufferedImage
        BufferedImage bi = reader.read(0, param);

        // 7. 寫入新檔案(保持原格式)
        String outName = subpath + "_" + System.currentTimeMillis() + "." + postFix;
        ImageIO.write(bi, postFix, new File(outName));
    } finally {
        if (fis != null) fis.close();
        if (iis != null) iis.close();
    }
}

輔助方法

// 根據副檔名獲取 Reader 迭代器
public Iterator<ImageReader> getImageReadersByFormatName(String postFix) {
    switch (postFix.toLowerCase()) {
        case "jpg": case "jpeg": return ImageIO.getImageReadersByFormatName("jpeg");
        case "png": return ImageIO.getImageReadersByFormatName("png");
        default: return ImageIO.getImageReadersByFormatName("jpeg");
    }
}

// 取得副檔名
public String getPostfix(String path) {
    return path.substring(path.lastIndexOf(".") + 1);
}

技術細節深度解析

類別/方法角色關鍵參數/行為
ImageIO.getImageReadersByFormatName()查找已註冊的解碼器格式名:"jpeg"、"png"、"bmp"、"wbmp"、"gif"
ImageIO.createImageInputStream()統一輸入源介面支援 File、InputStream、URL、byte[]、RandomAccessFile
reader.setInput(iis, true)設定輸入源seekForwardOnly=true:僅向前讀取,允許解碼器丟棄已讀資料,節省記憶體
ImageReadParam控制解碼行為來源區域、子採樣、目標 BufferedImage、進度監聽
param.setSourceRegion(Rectangle)指定裁剪區域座標相對原圖左上角 (0,0),超出邊界會拋異常
reader.read(0, param)執行解碼索引 0 表示第一幀(多幀格式如 GIF/TIFF 可讀後續幀)
ImageIO.write(bi, format, File)編碼寫入自動尋找對應 ImageWriter,支援品質參數需用 ImageWriteParam

進階應用場景

  • 縮圖生成:param.setSourceSubsampling(2, 2, 0, 0) 每 2 像素取 1,配合裁剪區域實現縮略圖。
  • 大圖分塊處理:循環調整 Rectangle,逐塊讀取、處理、寫入,記憶體常數級。
  • 格式轉換:讀取 PNG → 裁剪 → 寫入 JPEG(指定壓縮品質)。
  • 多幀提取:GIF/TIFF 循環 reader.read(i, param) 提取特定幀區域。

常見問題與避坑

  • 座標超出邊界:裁剪前先 ImageReader.getWidth(0)/getHeight(0) 取得原圖尺寸驗證。
  • CMYK JPEG 不支援:標準 JPEG 解碼器僅支援 YCbCr/灰階,CMYK 需用 TwelveMonkeys ImageIO 外掛。
  • 記憶體洩漏:ImageInputStream、ImageReader 需在 finally 區塊關閉(reader.dispose())。
  • 副檔名大小寫:getPostfix() 應 .toLowerCase() 後再 switch。
  • Alpha 通道:PNG 裁剪保留透明度,JPEG 輸出會填白底(無 Alpha)。

現代化替代:TwelveMonkeys ImageIO

標準 JDK ImageIO 格式支援有限(無 WebP、HEIC、AVIF、CMYK JPEG、多頁 TIFF 進階功能)。引入 TwelveMonkeys ImageIO 即可無縫擴充:

<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-jpeg</artifactId>
    <version>3.9.4</version>
</dependency>
<!-- 自動註冊額外格式,原有代碼零修改 -->

總結

ImageReadParam.setSourceRegion() 是 Java 標準庫中「隱藏的寶石」,實現解碼層級裁剪,避免將完整大圖載入記憶體再 getSubimage()。掌握此技術,能優雅解決大圖處理、縮圖生成、區域 OCR 前處理等高效能圖像處理需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved