You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用TwelveMonkeys保存带DPI信息的TIF文件偶发字符串索引越界异常

异常成因
  • 首先是依赖冲突:你的项目中同时存在TwelveMonkeys的TIFF实现和JAI ImageIO的TIFF实现,ImageIO的ImageWriter加载顺序不固定,随机返回两种实现的实例:
    • 返回TwelveMonkeys的TIFFWriter时,和你代码中构造的TwelveMonkeys原生TIFFImageMetadata、Rational类型匹配,运行正常
    • 返回JAI的TIFFWriter时,无法识别TwelveMonkeys的元数据格式,就会触发异常
  • 具体异常触发逻辑:JAI处理TIFF_RATIONAL类型的元数据时,要求对应值的字符串格式为分子/分母,你传入的TwelveMonkeys的new Rational(200)生成的字符串仅为200,没有分隔符/,导致indexOf("/")返回-1,调用substring时触发下标越界。
  • 异常后需要重启的原因:ImageIO的组件注册是JVM全局生效的,异常发生后注册的writer状态异常,只有重启JVM才能重置注册状态。
解决方案(保留DPI设置)

方案1:排除JAI ImageIO TIFF依赖(最推荐)

直接从项目依赖中移除com.github.jaiimageio:imageio-tiff相关组件,保证仅保留TwelveMonkeys的TIFF实现,从根源解决类冲突问题,原有代码不需要修改即可正常运行。

方案2:强制使用TwelveMonkeys的TIFFWriter

如果无法移除JAI依赖,不要通过ImageIO.getImageWritersByFormatName获取writer,直接实例化TwelveMonkeys的原生writer,避免拿到JAI的实现:

// 替换原有迭代器获取writer的逻辑
ImageWriter writer = new com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriter();

方案3:使用writer原生元数据模板构造DPI信息(兼容所有TIFFWriter实现)

如果需要兼容两种实现,可以通过当前writer的默认元数据模板设置DPI,避免直接构造厂商专属的元数据对象:

public static void saveImage(BufferedImage image, File destFile) throws IOException {
    String format = "tif";
    ImageWriter writer = ImageIO.getImageWritersByFormatName(format).next();
    ImageWriteParam writeParam = writer.getDefaultWriteParam();
    ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromRenderedImage(image);
    // 获取当前writer原生支持的元数据对象
    IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);

    // 设置200DPI
    int dpi = 200;
    TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata);
    // 显式传入分子分母,保证序列化格式为200/1,适配JAI解析逻辑
    dir.addTIFFEntry(new TIFFEntry(TIFF.TAG_X_RESOLUTION, TIFF.TIFF_RATIONAL, new Rational(dpi, 1)));
    dir.addTIFFEntry(new TIFFEntry(TIFF.TAG_Y_RESOLUTION, TIFF.TIFF_RATIONAL, new Rational(dpi, 1)));
    metadata = dir.getAsMetadata();

    try (ImageOutputStream output = ImageIO.createImageOutputStream(destFile)) {
        writer.setOutput(output);
        writer.write(new IIOImage(image, null, metadata));
    } finally {
        writer.dispose();
    }
}

内容的提问来源于stack exchange,提问作者HarleyDavidson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 01:54:04