早期方案依賴 com.sun.image.codec.jpeg.JPEGImageEncoder,屬於 Sun 內部 API,Java 7+ 已移除,編譯報錯。標準替代方案:javax.imageio.ImageIO + BufferedImage + Graphics2D,純標準庫、無依賴、跨平台。
ImageHelperpublic class ImageHelper {
private static ImageHelper instance;
public static ImageHelper getInstance() {
return instance == null ? instance = new ImageHelper() : instance;
}
/** 按比例縮放 */
public static void scaleImage(String srcPath, String destPath, double scale, String format) {
try {
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 g = dest.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(src.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, null);
g.dispose();
ImageIO.write(dest, format, new File(destPath));
} catch (IOException e) { e.printStackTrace(); }
}
/** 指定寬高縮放(可選保持比例) */
public static void scaleImageWithParams(String srcPath, String destPath,
int targetW, int targetH, boolean keepRatio, String format) {
try {
BufferedImage src = ImageIO.read(new File(srcPath));
if (keepRatio) {
int[] wh = calcAutoSize(src, targetW, targetH);
targetW = wh[0]; targetH = wh[1];
}
BufferedImage dest = new BufferedImage(targetW, targetH, BufferedImage.TYPE_INT_RGB);
Graphics2D g = dest.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(src.getScaledInstance(targetW, targetH, Image.SCALE_SMOOTH), 0, 0, null);
g.dispose();
ImageIO.write(dest, format, new File(destPath));
} catch (IOException e) { e.printStackTrace(); }
}
/** 計算保持比例下的目標尺寸 */
private static int[] calcAutoSize(BufferedImage src, int maxW, int maxH) {
double scaleW = (double) maxW / src.getWidth();
double scaleH = (double) maxH / src.getHeight();
double scale = Math.min(scaleW, scaleH);
return new int[] { (int) (src.getWidth() * scale), (int) (src.getHeight() * scale) };
}
// 高精度除法輔助(保留 3 位小數)
private static double div(int a, int b) {
return new BigDecimal(a).divide(new BigDecimal(b), 4, RoundingMode.HALF_UP).doubleValue();
}
}
RenderingHints.KEY_INTERPOLATION 設置 VALUE_INTERPOLATION_BILINEAR(雙線性插值)或 BICUBIC(雙三次),大幅提升縮放質量。Image.getScaledInstance(w, h, Image.SCALE_SMOOTH) 選用平滑縮放算法,比 SCALE_FAST/SCALE_DEFAULT 效果好。ImageIO.write(image, "jpg/png/bmp/gif", out) 支持主流格式,JPEG 可通過 ImageWriteParam 設置壓縮質量(0.0-1.0)。Graphics2D.dispose() 及時釋放圖形上下文資源。ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.85f); // 0-1,推薦 0.8-0.9
writer.setOutput(new FileImageOutputStream(new File(destPath)));
writer.write(null, new IIOImage(dest, null, null), param);
writer.dispose();
基於標準 ImageIO 的縮放方案完全替代內部 API,代碼簡潔、質量可控、支持任意目標尺寸與保持比例,生產環境穩定可靠。若需極致性能(如批量處理),可考慮 TwelveMonkeys ImageIO 插件或 JNI 綁定 libjpeg-turbo。