imageio.read() 读 png 丢透明通道因默认返回 type_int_rgb(无 alpha),需手动转为 type_int_argb;缩放应选 graphics2d.drawimage() 并开启抗锯齿;内存泄漏需调用 img.flush() 和 g.dispose();颜色偏差源于色彩空间不一致,输出前应统一转 srgb;dpi 信息 imageio 不暴露,需自行解析文件头。

为什么 ImageIO.read() 读 PNG 时透明通道总丢?
因为默认用 BufferedImage.TYPE_INT_ARGB 才保留 alpha,但 ImageIO.read() 返回的类型取决于原始图像元数据,PNG 常被读成 TYPE_INT_RGB——没 alpha 通道,透明区域直接变黑。
- 读取后立刻检查:
img.getType() == BufferedImage.TYPE_INT_ARGB,不是就手动转:new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB) - 别依赖
ImageIO.write()自动补 alpha:它只按目标BufferedImage类型写,源图没 alpha 就真没 - 特别注意 macOS 上 JDK 8 的
ImageIO对某些 PNG 解码有 bug,建议升级到 JDK 11+ 或加 fallback(比如用javax.imageio.plugins.jpeg.JPEGImageReader替代)
缩放用 Graphics2D.drawImage() 还是 RescaleOp?
日常批量缩放选 Graphics2D.drawImage(),简单、可控、支持抗锯齿;RescaleOp 只做像素级线性缩放,不插值,结果糊且失真,基本不用。
- 必须开启抗锯齿:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) - 记得关闭默认的「快速缩放」:
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY) - 缩放前调用
g.setComposite(AlphaComposite.Src),避免多次绘制叠加导致半透明区域变暗
批量处理时内存爆了,ImageIO.read() 和 dispose() 怎么配?
ImageIO.read() 返回的 BufferedImage 不自动释放底层 native 资源,尤其大图反复读写会 OOM;Graphics2D.dispose() 只清绘图上下文,不释放图像数据。
- 每张图处理完立刻调用
System.gc()不靠谱,改用img.flush()强制释放 native 图像缓冲区 - 读取后尽快把原始
BufferedImage设为null,尤其在循环里 - 别复用同一个
Graphics2D实例跨图操作——每次bufferedImage.createGraphics()后,用完必须g.dispose()
输出 JPEG 时颜色偏黄、PNG 透明变灰?
本质是色彩空间没对齐:ImageIO 默认走 sRGB,但某些 PNG 带 ICC profile,JPEG 输出又默认丢 profile,导致颜色计算错位。
- 输出 JPEG 前强制转 sRGB:
BufferedImage converted = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);再 drawImage 过去 - 输出 PNG 保留 alpha:确保目标
BufferedImage是TYPE_INT_ARGB,且写入时传"PNG"小写字符串(大小写敏感) - 别信
ImageIO.getWriterFormatNames()返回的列表顺序——不同 JVM 实现可能不同,硬编码格式名更稳
真正麻烦的是多 DPI 图片混批处理,ImageIO 完全不暴露 DPI 信息,缩放后物理尺寸会漂移,得自己解析 PNG/IHDR 或 JPEG/APP1 段。这个点大多数人一开始根本意识不到。










