在圖庫、電商、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() + " 張圖片。");
}
舊代碼使用 com.sun.image.codec.jpeg.* 內部 API,JDK 9+ 模組化後默認禁止訪問。解決:改用標準 javax.imageio.ImageIO 配合 ImageWriteParam 設置壓縮質量,或直接用 ImageIO.write(img, "jpg", out)(默認質量較高)。本文代碼已全面遷移至標準 API。
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);
讀取超大圖片(如 5000x5000+)直接載入堆內存易溢出。建議:
ImageReader 讀取縮略圖元數據(若格式支持)。本文提供的 ImageResizer 工具類功能完整、API 清晰、無內部 API 依賴,可直接集成到項目中。實際生產中,若涉及高併發圖片處理、雲存儲集成、多種格式轉換等進階需求,建議引入 Thumbnailator 或 TwelveMonkeys ImageIO 等成熟開源庫,獲得更好的效能與兼容性。