ImageIO 不支持的图像类型 - 修复后的 TwelveMonkeys 插件不起作用?

ImageIO Unsupported Image Type - TwelveMonkeys Plugin with fix not working?

由于使用 com.sun.imageio.plugins.jpeg.JPEGImageReader 的颜色配置文件不兼容,我遇到了不支持的图像类型错误。后来我发现 TwelveMonkeys 插件被证明可以解决这个问题,并在我的项目类路径中引用了相关的 .jars。我从 TwelveMonkeys github 存储库下载了它们。请注意,我使用的是 3.0.2 版,因为我 运行 在 Java 6 上使用 JDK 1.6.0_45。这些是我添加到项目中的 .jars:

common-lang-3.0.2.jar
common-io-3.0.2.jar
common-image-3.0.2.jar
imageio-core-3.0.2.jar
imageio-metadata-3.0.2.jar
imageio-jpeg-3.0.2.jar

我能够使用以下测试测试库是否已安装并正常工作:

Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
while (readers.hasNext()) {
    System.out.println("reader: " + readers.next());
}

输出:

reader: com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader@4102799c
reader: com.sun.imageio.plugins.jpeg.JPEGImageReader@33d6f122

当我 运行 我的代码时,它仍在尝试使用 com.sun.imageio.plugins.jpeg.JPEGImageReader 读取 JPEG 并继续抛出 IIOException。有什么想法吗?

更新: 它看起来像 iTextPDF 导致了问题,这是项目使用的库。我设置了一个准系统测试应用程序,将 CMYK JPEG 转换为 BufferedImage,然后调用 ImageIO.read(img),它工作正常。我正在努力寻找 iText 在同一项目和类路径中调用 ImageIO.read(img) 时找不到 TwelveMonkeys 插件的原因,但这可能是由于我的知识有限。我还应该补充一点,我正在处理的应用程序是 Web 服务的一部分 API。

通常情况下,当网络应用程序 run-time 未使用 ImageIO 插件时,原因是找不到服务提供者,因为 ImageIO 已经初始化,并在 Web 应用程序的库可用于 JVM 之前调用了 scanForPlugins()

来自 Deploying [ImageIO] plugins in a web app:

Because the ImageIO plugin registry (the IIORegistry) is "VM global", it doesn't by default work well with servlet contexts. This is especially evident if you load plugins from the WEB-INF/lib or classes folder. Unless you add ImageIO.scanForPlugins() somewhere in your code, the plugins might never be available at all.

In addition, servlet contexts dynamically loads and unloads classes (using a new class loader per context). If you restart your application, old classes will by default remain in memory forever (because the next time scanForPlugins is called, it's another ClassLoader that scans/loads classes, and thus they will be new instances in the registry). If a read is attempted using one of the remaining "old" readers, weird exceptions (like NullPointerExceptions when accessing static final initialized fields or NoClassDefFoundErrors for uninitialized inner classes) may occur.

To work around both the discovery problem and the resource leak, it is strongly recommended to use the IIOProviderContextListener that implements dynamic loading and unloading of ImageIO plugins for web applications.

IIOProviderContextListener 包含在 twelvemonkeys-servlet.jar 中,并且必须在您的应用程序的 web.xml 中注册(如果使用 Spring 或其他框架,则类似)。详见上文link

使用上下文侦听器的另一个安全替代方法是将 JAR 文件放在应用程序服务器的共享或公共 lib 文件夹中,而不是 Web 应用程序中的 WEB-INF/lib 文件夹。

PS:以上problem/solution一般适用于ImageIO插件,而不仅仅是TwelveMonkeys插件。因此,上下文侦听器不依赖于 TwelveMonkeys ImageIO 插件,也可以与 JAI ImageIO 或其他 ImageIO 插件一起使用。

对于 Spring 没有 web.xml 的引导应用程序,您需要在 @SpringBootApplication class 中注册 IIOProviderContextListener ,它应该扩展 SpringBootServletInitializer:

@Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        // Register the listener from Twelvemonkeys to support CMYK image handling with ImageIO
        servletContext.addListener(IIOProviderContextListener.class);
    }

另请参阅 this issue,其中对此进行了更详细的解释。