使用 ImageIO 實現圖片裁剪時遇到 Not a JPEG file: starts with 0xff 0xd9 錯誤,經多方嘗試最終定位根因並總結多種解決方案。
ImageIO.read(FileInputStream) 讀取圖片獲取寬高ImageIO.createImageInputStream(FileInputStream) 創建 ImageInputStream 進行裁剪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:裁剪(同一輸入流已被讀取至末尾) Iteratorreaders = ImageIO.getImageReadersByFormatName("jpg"); ImageReader reader = readers.next(); ImageInputStream iis = ImageIO.createImageInputStream(fis); // 流指針已在末尾! reader.setInput(iis, true); // ... 裁剪邏輯
FileInputStream 只能讀取一次,且指針不可重置。 第一次 ImageIO.read(fis) 讀取後,流指針移至文件末尾。第二次創建 ImageInputStream 時,讀取到的數據為空或殘留的 JPEG 結束標記 0xFF 0xD9,導致解析器誤判文件格式。
避免創建第一個 BufferedImage,直接用 ImageReader 讀取元數據:
ImageInputStream iis = ImageIO.createImageInputStream(imageFile); // 直接用 File Iteratorreaders = ImageIO.getImageReadersByFormatName("jpg"); ImageReader reader = readers.next(); reader.setInput(iis, true); int w = reader.getWidth(0); int h = reader.getHeight(0); // 後續裁剪邏輯...
若不需複雜參數控制,直接在內存中裁剪:
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(InputStream)BufferedImage.getSubimage() 共享數據數組,無需複製,效率極高0xFF 0xD9 被誤讀為開頭,是流位置錯誤的典型特徵