核心縮放邏輯
public class ImageResizeUtil {
/**
* @param srcPath 源圖路徑
* @param destPath 目標路徑
* @param scale 縮放倍數(>1 放大,<1 縮小)
* @param quality JPEG 品質 0.0f~1.0f
*/
public static void resize(String srcPath, String destPath, double scale, float quality) throws IOException {
BufferedImage src = ImageIO.read(new File(srcPath));
int w = (int) (src.getWidth() * scale);
int h = (int) (src.getHeight() * scale);
BufferedImage dest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = dest.createGraphics();
// 高品質渲染提示
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(src, 0, 0, w, h, null);
g2.dispose();
// JPEG 輸出品質控制
try (FileOutputStream fos = new FileOutputStream(destPath)) {
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
writer.setOutput(ImageIO.createImageOutputStream(fos));
writer.write(null, new IIOImage(dest, null, null), param);
writer.dispose();
}
}
}
等比縮放(指定目標寬/高)
public static void resizeKeepRatio(String src, String dest, int maxW, int maxH, float quality) throws IOException {
BufferedImage img = ImageIO.read(new File(src));
double ratio = Math.min((double) maxW / img.getWidth(), (double) maxH / img.getHeight());
int w = (int) (img.getWidth() * ratio);
int h = (int) (img.getHeight() * ratio);
// 後續同 resize()...
}
關鍵渲染提示說明
| Hint Key | 推薦 Value | 作用 |
| KEY_INTERPOLATION | VALUE_INTERPOLATION_BILINEAR / BICUBIC | 雙線性/雙三次插值,縮放平滑度 |
| KEY_RENDERING | VALUE_RENDER_QUALITY | 優先品質而非速度 |
| KEY_ANTIALIASING | VALUE_ANTIALIAS_ON | 抗鋸齒 |
| KEY_ALPHA_INTERPOLATION | VALUE_ALPHA_INTERPOLATION_QUALITY | 透明度插值品質 |
格式支援與透明度處理
- PNG 透明背景:用
BufferedImage.TYPE_INT_ARGB,輸出 ImageIO.write(dest, "png", ...)
- JPEG 無透明:
TYPE_INT_RGB,白色填充透明區
- WebP:需引入
webp-imageio 插件
效能建議
- 大批量處理:線程池 +
BufferedImage 複用(同尺寸)
- 超大圖(>50MP):分塊處理或使用
ImageReader.read(param) 區域解碼
- 服務端無頭模式:啟動參數
-Djava.awt.headless=true
現代替代:Thumbnailator(一行代碼)
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.18</version>
</dependency>
// 等比縮放到 200x200 內,輸出品質 0.8
Thumbnails.of("src.jpg").size(200, 200).outputQuality(0.8).toFile("dest.jpg");