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

Java 圖片縮略圖生成實戰:單張與批量處理完整方案

     編輯:Java 相關知識

前言

在圖庫、電商、CMS 等系統中,圖片上傳後通常需要生成多種尺寸的縮略圖以適配不同展示場景(列表圖、詳情圖、移動端適配等)。本文提供基於 java.awt.image.BufferedImage 的完整實現,涵蓋按比例縮放、固定尺寸縮放、高質量 JPEG 輸出、批量處理目錄等核心功能,並解決 com.sun.image.codec 內部 API 編譯警告問題。

核心工具類設計

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 圖片縮放與輸出工具類
 * 

功能:按比例縮放、指定尺寸縮放、高質量 JPEG 輸出、批量目錄處理

*/ public class ImageResizer { /** * 按縮放倍數縮小圖片(倍數 > 1 表示縮小) * @param src 源圖片 * @param scaleTimes 縮放倍數,如 2.0 表示縮小為原圖 1/2 * @return 縮放後的 BufferedImage */ public BufferedImage resizeImage(BufferedImage src, float scaleTimes) { int srcW = src.getWidth(); int srcH = src.getHeight(); int targetW = (int) (srcW / scaleTimes); int targetH = (int) (srcH / scaleTimes); return scaleImage(src, targetW, targetH); } /** * 按縮放比例縮放圖片(0 < ratio ≤ 1 為縮小,>1 為放大) * @param src 源圖片 * @param ratio 縮放比例,如 0.5 表示縮小一半 * @return 縮放後的 BufferedImage */ public BufferedImage zoomImage(BufferedImage src, float ratio) { int srcW = src.getWidth(); int srcH = src.getHeight(); int targetW = (int) (srcW * ratio); int targetH = (int) (srcH * ratio); return scaleImage(src, targetW, targetH); } /** * 通用縮放實現:使用 SCALE_SMOOTH 保證質量 */ private BufferedImage scaleImage(BufferedImage src, int targetW, int targetH) { BufferedImage result = new BufferedImage(targetW, targetH, BufferedImage.TYPE_INT_RGB); result.getGraphics().drawImage( src.getScaledInstance(targetW, targetH, Image.SCALE_SMOOTH), 0, 0, null ); return result; } /** * 高質量 JPEG 輸出(質量 1.0,無損壓縮) * @param img 待寫入圖片 * @param destPath 目標完整路徑(含文件名) * @return 是否成功 */ public boolean writeHighQuality(BufferedImage img, String destPath) { try (FileOutputStream fos = new FileOutputStream(destPath)) { // 使用標準 ImageIO 替代內部 com.sun.image.codec API return ImageIO.write(img, "jpg", fos); } catch (IOException e) { e.printStackTrace(); return false; } } /** * 批量讀取目錄下指定後綴的圖片 * @param dirPath 目錄路徑 * @param extensions 允許的後綴(不含點),如 "jpg", "png" * @return 圖片列表 */ public List readImagesFromDir(String dirPath, String[] extensions) throws IOException { Map extMap = new HashMap<>(); for (String ext : extensions) extMap.put(ext.toLowerCase(), true); List list = new ArrayList<>(); File dir = new File(dirPath); File[] files = dir.listFiles(); if (files == null) return list; for (File f : files) { if (f.length() == 0) continue; String ext = getExtension(f.getName()); if (ext != null && extMap.containsKey(ext.toLowerCase())) { list.add(ImageIO.read(f)); } } return list; } /** * 將圖片寫入磁盤(保留原格式) */ public boolean writeImage(BufferedImage img, String dirPath, String fileName) { String ext = getExtension(fileName); if (ext == null) return false; File out = new File(dirPath, fileName); try { return ImageIO.write(img, ext, out); } catch (IOException e) { return false; } } private String getExtension(String fileName) { int dot = fileName.lastIndexOf('.'); return (dot > 0 && dot < fileName.length() - 1) ? fileName.substring(dot + 1) : null; } }

單張處理示例

public static void main(String[] args) throws Exception {
    String srcPath = "F:/pic/Chrysanthemum1.jpg";
    String destDir = "F:/picNew/";
    float scaleRatio = 0.25f; // 縮小為原圖 1/4

    ImageResizer resizer = new ImageResizer();
    BufferedImage src = ImageIO.read(new File(srcPath));
    BufferedImage thumb = resizer.zoomImage(src, scaleRatio);

    String outName = "thumb_" + System.currentTimeMillis() + ".jpg";
    resizer.writeHighQuality(thumb, destDir + outName);
    System.out.println("單張縮略圖生成完成:" + outName);
}

批量處理示例

public static void batchProcess() throws Exception {
    String srcDir = "F:/pic/";
    String destDir = "F:/picNew/";
    float scaleRatio = 0.25f;

    ImageResizer resizer = new ImageResizer();
    List images = resizer.readImagesFromDir(srcDir, new String[]{"jpg", "png", "bmp"});

    for (int i = 0; i < images.size(); i++) {
        BufferedImage thumb = resizer.zoomImage(images.get(i), scaleRatio);
        String outName = "batch_" + i + "_" + System.currentTimeMillis() + ".jpg";
        resizer.writeHighQuality(thumb, destDir + outName);
    }
    System.out.println("批量處理完成,共 " + images.size() + " 張圖片。");
}

常見問題與解決方案

1. 編譯警告:Forbidden reference to com.sun.image.codec

舊代碼使用 com.sun.image.codec.jpeg.* 內部 API,JDK 9+ 模組化後默認禁止訪問。解決:改用標準 javax.imageio.ImageIO 配合 ImageWriteParam 設置壓縮質量,或直接用 ImageIO.write(img, "jpg", out)(默認質量較高)。本文代碼已全面遷移至標準 API。

2. 透明背景圖片(PNG/GIF)變黑

BufferedImage.TYPE_INT_RGB 不支持透明通道。處理透明圖片請用 TYPE_INT_ARGB,並根據原圖類型動態選擇:

int type = src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage result = new BufferedImage(targetW, targetH, type);

3. 大圖 OOM

讀取超大圖片(如 5000x5000+)直接載入堆內存易溢出。建議:

  • 使用 ImageReader 讀取縮略圖元數據(若格式支持)。
  • 或引入 Thumbnailator 等成熟庫,內部優化了內存管理。

總結

本文提供的 ImageResizer 工具類功能完整、API 清晰、無內部 API 依賴,可直接集成到項目中。實際生產中,若涉及高併發圖片處理、雲存儲集成、多種格式轉換等進階需求,建議引入 Thumbnailator 或 TwelveMonkeys ImageIO 等成熟開源庫,獲得更好的效能與兼容性。

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