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

Java ImageIO 圖片裁剪踩坑記:Not a JPEG file 錯誤根因分析與多種解決方案

     編輯:Java 綜合教學

Java ImageIO 圖片裁剪踩坑記

使用 ImageIO 實現圖片裁剪時遇到 Not a JPEG file: starts with 0xff 0xd9 錯誤,經多方嘗試最終定位根因並總結多種解決方案。

問題復現場景

  1. 先用 ImageIO.read(FileInputStream) 讀取圖片獲取寬高
  2. 再用 ImageIO.createImageInputStream(FileInputStream) 創建 ImageInputStream 進行裁剪
  3. 拋出 Not a JPEG file: starts with 0xff 0xd9 錯誤

錯誤代碼片段

File imageFile = new File(imageFileFullPath);
FileInputStream fis = new FileInputStream(imageFile);

// 步驟1:獲取寬高
BufferedImage bufferedImage = ImageIO.read(fis);
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();

// 步驟2:裁剪(同一輸入流已被讀取至末尾)
Iterator readers = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = readers.next();
ImageInputStream iis = ImageIO.createImageInputStream(fis); // 流指針已在末尾!
reader.setInput(iis, true);
// ... 裁剪邏輯

根因分析

FileInputStream 只能讀取一次,且指針不可重置。 第一次 ImageIO.read(fis) 讀取後,流指針移至文件末尾。第二次創建 ImageInputStream 時,讀取到的數據為空或殘留的 JPEG 結束標記 0xFF 0xD9,導致解析器誤判文件格式。

三種解決方案

方案一:使用 ImageReader 直接獲取尺寸(推薦)

避免創建第一個 BufferedImage,直接用 ImageReader 讀取元數據:

ImageInputStream iis = ImageIO.createImageInputStream(imageFile); // 直接用 File
Iterator readers = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = readers.next();
reader.setInput(iis, true);
int w = reader.getWidth(0);
int h = reader.getHeight(0);
// 後續裁剪邏輯...

方案二:BufferedImage.getSubimage() 簡單裁剪

若不需複雜參數控制,直接在內存中裁剪:

BufferedImage src = ImageIO.read(imageFile); // 用 File 而非流
int clipSize = Math.min(src.getWidth(), src.getHeight());
BufferedImage clipped = src.getSubimage(0, 0, clipSize, clipSize);
ImageIO.write(clipped, "jpg", outputStream);

方案三:修正流使用方式

若必須使用流,請對每次讀取創建獨立的 FileInputStream:

// 獲取寬高
try (FileInputStream fis1 = new FileInputStream(imageFile)) {
    BufferedImage bi = ImageIO.read(fis1);
    w = bi.getWidth(); h = bi.getHeight();
}

// 裁剪處理
try (FileInputStream fis2 = new FileInputStream(imageFile)) {
    ImageInputStream iis = ImageIO.createImageInputStream(fis2);
    // ... 裁剪邏輯
}

核心經驗總結

  • ImageIO.read(File) 內部自動管理流關閉,優先於 ImageIO.read(InputStream)
  • 輸入流不可重複使用,每次讀取需重新打開
  • BufferedImage.getSubimage() 共享數據數組,無需複製,效率極高
  • JPEG 文件結尾標記 0xFF 0xD9 被誤讀為開頭,是流位置錯誤的典型特徵

參考資源

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