5

我正在尝试创建一个 Grails 应用程序,它可以显示 TIFF 文件和其他图像的预览。

背景

这些图像是从一个 SOAP 服务构造的,该服务为我提供了图像的字节。在服务方法中,我获取 byte[],从中构造一个 ByteArrayInputStream,然后从中创建一个 BufferedImage。

def inputStream = new ByteArrayInputStream(bytes)
BufferedImage originalImage = ImageIO.read(inputStream)
ImageIO.write(originalImage, 'png', response.outputStream)

对于 JPG,我可以通过这种方式轻松地将图像作为 img 标签的 src 流式传输到浏览器。但是,TIFF 需要将图像转换为其他格式(最好是 JPG 或 PNG),以使它们成为标签的 src。

问题

我知道我需要 JAI 才能读取 TIFF 文件。jai_core.jar、jai_codec.jar 文件在我的类路径中。事实上,因为我在 Mac OSX 上,它们是自动安装的。但是,当我运行 grails 应用程序并尝试从从 SOAP 服务接收到的字节构造 TIFF 图像时,我收到此错误:

| Error 2013-06-18 15:23:38,135 [http-bio-8080-exec-10] ERROR errors.GrailsExceptionResolver  - IllegalArgumentException occurred when processing request: [GET] /BDMPlugin/BDMPlugin/displayImageFromRef - parameters:
pageRef: 28:22072FBCA0A8889D9C041D76A588BCF4DCB40376A23B5FD5C301378C8E66EB9F4933A5DFCA46365F927D9E91B337B6E1E980FB4406644801
type: TIFF
im == null!. Stacktrace follows:
Message: im == null!
    Line | Method
->> 1457 | write                in javax.imageio.ImageIO
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   1571 | write                in     ''
|     28 | writeImageToResponse in edu.missouristate.bdmplugin.ImageService
|     44 | bytesToPng           in     ''
|     39 | displayImageFromRef  in edu.missouristate.bdmplugin.BDMPluginController
|    895 | runTask              in java.util.concurrent.ThreadPoolExecutor$Worker
|    918 | run . . . . . . . .  in     ''
^    680 | run                  in java.lang.Thread

我尝试了以下脚本来确定安装了哪些图像阅读器:

IIORegistry reg = IIORegistry.getDefaultInstance();
Iterator spIt = reg.getServiceProviders(ImageReaderSpi.class, false);
spIt.each(){
println it.getVendorName() << " | " << it.getVersion() << " | "<< it.getDescription() ;
}

这将输出以下内容:

Sun Microsystems, Inc. | 1.0 | Standard BMP Image Reader
Sun Microsystems, Inc. | 1.0 | Standard GIF image reader
Sun Microsystems, Inc. | 1.0 | Standard WBMP Image Reader
Sun Microsystems, Inc. | 1.0 | Standard PNG image reader
Sun Microsystems, Inc. | 0.5 | Standard JPEG Image Reader

但是,如果我在 Groovy 控制台中运行相同的 Groovy 脚本,我会得到以下输出:

Sun Microsystems, Inc. | 0.5 | Standard JPEG Image Reader
Sun Microsystems, Inc. | 1.0 | Standard BMP Image Reader
Sun Microsystems, Inc. | 1.0 | Standard WBMP Image Reader
Sun Microsystems, Inc. | 1.0 | Standard PNG image reader
Sun Microsystems, Inc. | 1.0 | Standard GIF image reader
Apple computer Inc. | 1.0 | Standard TIFF image reader

相同的阅读器集,但还包括 Apple 的 TIFF 阅读器。为什么 GroovyConsole 能够找到它而不是我的 Grails 环境,即使它们都使用相同的 JRE?有没有一种方法可以通过导入com.sun.media.jai或导入来手动添加 TIFF 阅读器com.sun.media.imageio.plugins.tiff

我尝试将 TIFFImageReaderSpi 的手动注册添加到我的服务方法中:

import com.sun.imageio.plugins.tiff.TIFFImageReaderSpi
...
IIORegistry reg = IIORegistry.getDefaultInstance()
reg.registerServiceProvider(new TIFFImageReaderSpi())

originalImage 变量仍然返回 null。

4

3 回答 3

6

所以这个问题似乎有几个层面。

首先,import com.sun.imageio.plugins.tiff.TIFFImageReaderSpi声明是导入 Apple TIFF 阅读器,这显然不能胜任阅读我的 TIFF 的工作。

真正需要的是import com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi,但这给我带来了几个不同的错误;别担心,我能够修复它们。:)

首先,导入没有解决。为了获得 com.sun.media.imageioimpl 包,我从https://github.com/stain/jai-imageio-core获得了捆绑 JAI 的源代码。我将它导入 Eclipse,然后使用 Eclipse 的导出工具构建了一个 JAR。我把它放在我项目的 lib 文件夹中,但导入仍然没有解决。我必须手动将该 jar 添加到我的项目的类路径中,然后导入将解决。

其次,当我运行该应用程序时,我会收到此错误:

| Error 2013-06-19 11:15:27,665 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver  - IllegalArgumentException occurred when processing request: [GET] /pluginproject/Controller/action - parameters:
vendorName == null!. Stacktrace follows:
Message: vendorName == null!
   Line | Method
->>  59 | <init>              in javax.imageio.spi.IIOServiceProvider
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   214 | <init>              in javax.imageio.spi.ImageReaderWriterSpi
|   192 | <init> . . . . . .  in javax.imageio.spi.ImageReaderSpi
|    88 | <init>              in com.sun.media.imageioimpl.plugins.tiff.TIFFImageReaderSpi
|    31 | bytesToPng . . . .  in edu.mystateu.pluginproject.ImageService

供应商名称 == 空?幸运的是,我找到了这个问题/答案

在为 jai-imageio-core 创建 jar 文件时,我必须手动指定清单文件的位置,而不是让 Eclipse 生成一个新的空白文件。清单文件位于 /jai-imageio-core/src/main/resources/META-INF/MANIFEST.MF 中,一旦我指定使用该文件,导入的库就会解析并读取我的图像。

最后,服务方法的代码非常好。我只需要真正将 JAI 正确导入到我的项目中。非常感谢@haraldK,他的反馈让我走上了正轨。

于 2013-06-19T16:50:09.797 回答
4

我遇到了同样的问题,虽然可以手动注册单个插件,但还有一种方法可以注册类路径中可用的所有插件,这可能更干净一些:

ImageIO.scanForPlugins();
于 2014-01-02T16:29:18.380 回答
3

一种可行的解决方案是创建一个文件

/META-INF/services/ImageReaderSpi

包含一行

com.sun.imageio.plugins.tiff.TIFFImageReaderSpi

并将其放在类路径上。

这应确保提供程序已正确注册。

但是,请注意 Apple 提供的 TIFFImageReader 与 JAI 提供的不同,即使包/类名称相同。

如果您想使用 JAI TIFF ImageReader,您将需要 jai-imageio.jar。正如您所指出的,该项目目前被甲骨文搁置。

如果您出于任何原因不喜欢使用 JAI,我已经为 ImageIO 创建了一个纯 Java TIFF 插件,可在 GitHub 上找到:Twelvemonkeys TIFF 插件。该插件可在商业友好的开源许可证 (BSD) 下使用。

于 2013-06-19T08:15:35.367 回答