从评论中的额外信息中,我们发现该应用程序在 Glassfish 服务器中运行,并且安装了两个 ImageIO 插件,都能够读取 DICOM 图像。该问题与读取无关,但有时将解码后的图像写入 JPEG 会失败。
上述插件的服务提供者是org.dcm4cheri.imageio.plugins.DcmImageReaderSpi
and
,但似乎org.dcm4che2.imageioimpl.plugins.dcm.DicomImageReaderSpi
只有后者 ( ) 有效。DicomImageReaderSpi
这是因为它为每个样本生成一个 8 位BufferedImage
,这JPEGImageWriter
是能够写入的(DcmImageReaderSpi
每个样本图像创建一个 16 位,它不能写为 JFIF JPEG,因此不受 JPEG 支持JPEGImageWriter
)。
由于 ImageIO 插件的(默认)未指定(读取:不可预测)顺序,结果是有时您会获得 8 bps 版本,有时是 16 位版本的图像,最终结果是有时转换不会'不工作。
现在,好消息是我们可以 设置 ImageIO 插件的显式顺序,或者我们可以在运行时取消注册插件,以获得稳定的可预测结果。这些选项中哪个更好,取决于您的服务器上是否有其他代码依赖于不需要的插件。如果您不需要它,请取消注册。
下面的代码显示了上述两个选项:
// Get the global registry
IIORegistry registry = IIORegistry.getDefaultInstance();
// Lookup the known providers
ImageReaderSpi goodProvider = lookupProviderByName(registry, "org.dcm4che2.imageioimpl.plugins.dcm.DicomImageReaderSpi");
ImageReaderSpi badProvider = lookupProviderByName(registry, "org.dcm4cheri.imageio.plugins.DcmImageReaderSpi");
if (goodProvider != null && badProvider != null) {
// If both are found, EITHER
// order the good provider BEFORE the bad one
registry.setOrdering(ImageReaderSpi.class, goodProvider, badProvider);
// OR
// un-register the bad provider
registry.deregisterServiceProvider(badProvider);
}
// New and improved (shorter) version. :-)
private static <T> T lookupProviderByName(final ServiceRegistry registry, final String providerClassName) {
try {
return (T) registry.getServiceProviderByClass(Class.forName(providerClassName));
}
catch (ClassNotFoundException ignore) {
return null;
}
}
您还应该确保只运行此代码一次,对于基于容器的应用程序,最好的时机是在应用程序上下文启动时。
使用上述解决方案,ImageIO.read(...)
将始终使用好的插件,并按ImageIO.write(...)
预期工作。