GIF 图像仅部分显示

GIF image only partially displayed

我在 Java 中遇到了 GIF 图片的奇怪问题。该图像由 XML API 作为 Base64 编码字符串提供。为了解码 Base64,我使用了 1.13 版本的 commons-codec 库。

当我解码 Base64 字符串并将字节写入文件时,图像在浏览器和 MS Paint 中正确显示(此处没有其他要测试的内容)。

final String base64Gif = "[Base64 as provided by API]";
final byte[] sigImg = Base64.decodeBase64(base64Gif);
File sigGif = new File("C:/Temp/pod_1Z12345E5991872040.org.gif");
try (FileOutputStream fos = new FileOutputStream()) {
    fos.write(sigImg);
    fos.flush();
}

在 MS Paint 中打开的结果文件:

但是当我现在开始使用 Java 使用此文件时(例如使用 openhtmltopdf 库从 HTML 创建 PDF 文档),它已损坏并且无法正确显示。

final String htmlLetterStr = "[HTML as provided by API]";
final Document doc = Jsoup.parse(htmlLetterStr);

try (FileOutputStream fos = new FileOutputStream(new File("C:/Temp/letter_1Z12345E5991872040.pdf"))) {
    PdfRendererBuilder builder = new PdfRendererBuilder();

    builder.useFastMode();
    builder.withW3cDocument(new W3CDom().fromJsoup(doc), "file:///C:/Temp/");
    builder.toStream(fos);
    builder.useDefaultPageSize(210, 297, BaseRendererBuilder.PageSizeUnits.MM);
    builder.run();

    fos.flush();
}

当我现在打开生成的 PDF 时,上面创建的图像如下所示。似乎只打印了第一个像素线,某些层丢失了,或者类似的东西。

如果我再次使用 ImageIO 读取图像并尝试将其转换为 PNG,也会发生同样的情况。生成的 PNG 看起来与 PDF 文档中打印的图像完全一样。

如何让图像在 PDF 文档中正确显示?

编辑: Link 到 API 提供的原始 GIF Base64:https://pastebin.com/sYJv6j0h

正如@haraldK 在评论中指出的那样,XML API 提供的 GIF 文件不符合 GIF 标准,因此无法被 Java 解析ImageIO API.

由于似乎不存在用于修复文件的纯 Java 工具,我现在想到的解决方法是通过 Java 的进程 API 使用 ImageMagick .使用 -coalesce 选项调用 convert 命令将解析损坏的 GIF 并创建一个符合 GIF 标准的新 GIF。

// Decode broken GIF image and write to disk
final String base64Gif = "[Base64 as provided by API]";
final byte[] sigImg = Base64.decodeBase64(base64Gif);
Path gifPath = Paths.get("C:/Temp/pod_1Z12345E5991872040.tmp.gif");
if (!Files.exists(gifPath)) {
    Files.createFile(gifPath);
}
Files.write(gifPath, sigImg, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);

// Use the Java Process API to call ImageMagick (on Linux you would use the 'convert' binary)
ProcessBuilder procBuild = new ProcessBuilder();
procBuild.command("C:\Program Files\ImageMagick-7.0.9-Q16\magick.exe", "C:\Temp\pod_1Z12345E5991872040.tmp.gif", "-coalesce", "C:\Temp\pod_1Z12345E5991872040.gif");
Process proc = procBuild.start();

// Wait for ImageMagick to complete its work
proc.waitFor();

新创建的文件可以被 Java 的 ImageIO API 读取并按预期使用。