在 Java 生态中,对现代图片格式 AVIF 的支持一直是个痛点。最近我通过 AI 助手 Kiro (Claude 4.5 opus) 辅助开发了 avif-imageio 项目,成功让 Java 能够原生读写 AVIF。这篇文章将记录我如何在高强度 AI 协作下,解决 JNI 跨平台构建、静态链接以及 Halo 插件兼容性等一系列难题。
起因是我在为 Halo 博客系统开发插件时,发现现有的 Java AVIF 方案要么操作极其复杂,要么需要用户在操作系统层面安装 C 库依赖。对于追求“开箱即用”的 Halo 用户来说,这简直是部署噩梦。
💡愿景:一个 JAR 包搞定所有
我的目标非常明确:通过 JNI 封装,将功能锁在一个 JAR 包里。用户无需额外配置任何环境,引入依赖后即可让 Java 的 ImageIO 模块直接识别并处理 AVIF 格式。
🤖Kiro 辅助:AI 驱动的底层开发流
作为一个不折腾 C/C++ 工具链与 Java 的开发者,面对 libavif、dav1d、aom 以及 libyuv 这些复杂的 C 库,Kiro 成为了我的“自动驾驶仪”。
1. 技术栈“拼图”
在 Kiro 的建议下,我最终选定了最优方案:
libavif:作为核心抽象层。
dav1d:负责极致的解码速度(Chrome 同款)。
aom:提供超高兼容性的编码能力。
libyuv:用于 RGB 与 YUV 之间的高性能色彩方案转换。
2. 构建方案的进化
为了实现“零依赖”,我决定采用静态链接。Kiro 帮我编写了极为复杂的 CMake 配置和 GitHub Actions 脚本,确保在 Windows (x64)、Linux (x64) 以及 macOS (arm64) 上都能自动化地将所有依赖打包进一个单一的本地库文件中。
🛠️ 深度踩坑与 AI 解法
在开发过程中,我遇到了几个技术深水区的难题,也是在 Kiro 的协助下逐一攻克的:
坑 1:aom 编码器的符号冲突
仅保留 aom 编码器以减小体积时出现了符号引用报错。
AI 解法:Kiro 识别并配置了特定的宏开关(-DAVIF_CODEC_AOM_DECODE=OFF),并精准裁剪了不必要的源码模块。
坑 2:Halo 插件环境下的类加载陷阱
由于 Halo 使用 PF4J 框架,每个插件都有独立的 ClassLoader,导致常规的 getResource() 无法定位 JAR 内的原生库。
AI 解法:我们改用 Thread.currentThread().getContextClassLoader(),完美适配了复杂的容器化插件环境。
坑 3:JitPack 构建闭环
JitPack 这种从源码动态构建的服务通常没有 C 编译环境。
AI 解法:编写 jitpack.yml 脚本,在构建时自动从 GitHub Release 中拉取预编译的原生产物,实现了极致的极速分发。
📂最终成果:Java 原生读写能力
通过 avif-imageio,Java 开发者现在可以像操作普通图片一样处理 AVIF:
基础读取与写入
// 解码读取
BufferedImage image = ImageIO.read(new File("input.avif"));
// 编码写入
ImageIO.write(image, "avif", new File("output.avif"));精细化编码控制
ImageWriter writer = ImageIO.getImageWritersByFormatName("avif").next();
AvifWriteParam param = (AvifWriteParam) writer.getDefaultWriteParam();
param.setQuality(80); // 质量调节
param.setSpeed(6); // 编码速度优化
param.setLossless(false); // 有损/无损切换
try (ImageOutputStream ios = ImageIO.createImageOutputStream(new File("output.avif"))) {
writer.setOutput(ios);
writer.write(null, new IIOImage(image, null, null), param);
}✨总结
avif-imageio 的诞生,不仅填补了 Java 生态在现代图片格式支持上的空白,也展示了在 Kiro等 AI 助手加持下,开发者跨越语言藩篱、处理底层系统依赖的高效路径。
本项目目前已完美支持主流的三大操作系统,且极致优化了 JAR 包体积。如果你正苦于 Halo 插件或 Java 项目的图片体积优化,欢迎尝试!