Java BuffereImage报告的颜色模型类型不正确
我正在使用一些第三方软件将图像转换为PDF,我注意到一些文件大小过大。经过一些挖掘,我确认图像的颜色模型没有保留下来。黑白(1bit)图像正在转换为RGB颜色模型 在库中挖掘会显示一些颜色模型检测:Java BuffereImage报告的颜色模型类型不正确,java,javax.imageio,Java,Javax.imageio,我正在使用一些第三方软件将图像转换为PDF,我注意到一些文件大小过大。经过一些挖掘,我确认图像的颜色模型没有保留下来。黑白(1bit)图像正在转换为RGB颜色模型 在库中挖掘会显示一些颜色模型检测: switch (awtColorSpace.getType()) { case ColorSpace.TYPE_RGB: return PDDeviceRGB.INSTANCE; case ColorSpace.TYPE_GRAY: return PD
switch (awtColorSpace.getType()) {
case ColorSpace.TYPE_RGB:
return PDDeviceRGB.INSTANCE;
case ColorSpace.TYPE_GRAY:
return PDDeviceGray.INSTANCE;
case ColorSpace.TYPE_CMYK:
return PDDeviceCMYK.INSTANCE;
default:
throw new UnsupportedOperationException("color space not implemented: "
+ awtColorSpace.getType());
}
这些图像总是以RGB的形式返回。我决定写一些测试,它们似乎证实了这一点:
package com.acme;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import static org.junit.Assert.*;
public class ImageColorDetectionTest {
@Test
public void colorImage() throws Exception {
// Colorspace: sRGB, Depth: 8-bit, Channel depth: Red: 8-bit Green: 8-bit Blue: 8-bit
BufferedImage image = readImage("/color.png");
assertEquals(ColorSpace.TYPE_RGB, image.getColorModel().getColorSpace().getType());
}
@Test
public void greyscaleImage() throws Exception {
// Colorspace: Gray, Depth: 8-bit, Channel depth: Gray: 8-bit
BufferedImage image = readImage("/greyscale.png");
assertEquals(ColorSpace.TYPE_GRAY, image.getColorModel().getColorSpace().getType());
}
@Test
public void blackAndWhiteImage() throws Exception {
// Colorspace: Gray, Depth: 8/1-bit, Channel depth: Gray: 1-bit
BufferedImage image = readImage("/bw.png");
assertEquals(ColorSpace.TYPE_GRAY, image.getColorModel().getColorSpace().getType());
}
protected BufferedImage readImage(String path) throws IOException {
try (InputStream content = this.getClass().getResourceAsStream(path)) {
return ImageIO.read(content);
}
}
}
黑白图像测试总是失败。颜色空间类型为5(RGB)。这是JDK中的一个bug还是我缺少了一些基本的东西
测试图像:
颜色空间:sRGB,深度:8位,通道深度:红色:8位绿色:8位蓝色:8位
颜色空间:灰色,深度:8位,通道深度:灰色:8位
颜色空间:灰色,深度:8/1位,通道深度:灰色:1位
Imagemagick标识:
magick identify -verbose bw.png
Image: bw.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: PseudoClass
Geometry: 329x247+0+0
Units: Undefined
Type: Bilevel
Base type: Palette
Endianess: Undefined
Colorspace: Gray
Depth: 8/1-bit
Channel depth:
Gray: 1-bit
Channel statistics:
Pixels: 81263
Gray:
min: 0 (0)
max: 255 (1)
mean: 110.66 (0.433961)
standard deviation: 126.384 (0.495623)
kurtosis: -1.92901
skewness: 0.266484
entropy: 0.98738
Colors: 2
Histogram:
45998: ( 0, 0, 0) #000000 gray(0)
35265: (255,255,255) #FFFFFF gray(255)
Colormap entries: 2
Colormap:
0: ( 0, 0, 0,255) #000000FF graya(0,1)
1: (255,255,255,255) #FFFFFFFF graya(255,1)
Rendering intent: Undefined
Gamma: 0.45455
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 329x247+0+0
Dispose: Undefined
Iterations: 0
Compression: Zip
Orientation: Undefined
Properties:
date:create: 2017-06-22T09:33:09-05:00
date:modify: 2017-06-22T09:33:09-05:00
png:bKGD: chunk was found (see Background color, above)
png:cHRM: chunk was found (see Chromaticity, above)
png:gAMA: gamma=0.45455 (See Gamma, above)
png:IHDR.bit-depth-orig: 1
png:IHDR.bit_depth: 1
png:IHDR.color-type-orig: 0
png:IHDR.color_type: 0 (Grayscale)
png:IHDR.interlace_method: 0 (Not interlaced)
png:IHDR.width,height: 329, 247
png:text: 2 tEXt/zTXt/iTXt chunks were found
png:tIME: 2017-06-21T10:12:36Z
signature: 689d59f57ef9b4d58011f92e26f937d9d58cf1ca1ccbcaad6bad7bdd0552fcfa
Artifacts:
verbose: true
Tainted: False
Filesize: 3.69KB
Number pixels: 81.3K
User time: 0.000u
Elapsed time: 0:01.000
Version: ImageMagick 7.0.5-4 Q16 x86_64 2017-03-25 http://www.imagemagick.org
我想这是来自你的
bw.png
文件。据我所知,1位PNG是灰度或索引(调色板),索引将使用RGB空间,因此您将有2种颜色(\000000
和\ffffff
)。检查用于创建PNG的任何工具,看看它是否为您提供了灰度和索引之间的选择。您可能还希望查看PNG块,以验证文件是否按预期方式创建
这可能很有用:我知道你已经有了一个公认的答案,但我还是会尝试解释一下。。这不是一个bug。但我同意,这有时是违反直觉的 测试使用图像的解码内存表示的颜色空间,并将其与编码文件中的预期颜色空间进行比较。解码文件时(在您的示例中使用
ImageIO.read
),ImageReader
插件通常会将图像转换为内存中的表示形式,以便在屏幕上快速绘制。这可能与存储在磁盘上时最节省空间的表示方式大不相同
例如,即使PNG文件不包含PLTE
区块,每个样本使用少于8位的灰度图像通常也会转换为IndexColorModel
。而且,IndexColorModel
始终使用sRGB颜色空间(RGB类型),即使它只包含灰度值。这对于显示的像素并不重要,不管它们是黑白的,但对于您的测试来说确实很重要
可以使用ImageIO
API获取文件中实际编码的颜色空间:
try (ImageInputStream content = ImageIO.createImageInputStream(this.getClass().getResourceAsStream(path))) {
ImageReader reader = ImageIO.getImageReaders(input).next(); // Assumes PNGImageReader is always there
reader.setInput(input);
IIOMetadata metadata = reader.getImageMetadata(0);
Node nativeTree = metadata.getAsTree(metadata.getNativeMetadataFormatName());
Node standardTree = metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
// ... Get color space information as needed using DOM traversal
}
我跳过了实际值的阅读,因为它变得非常冗长,但它非常直截了当。所有值都是String
s。有关详细信息,请参阅类文档
bw.png
文件的元数据包含以下两种不同的输出表示形式
本机元数据:
<javax_imageio_png_1.0>
<IHDR width="329" height="247" bitDepth="1" colorType="Grayscale" compressionMethod="deflate" filterMethod="adaptive" interlaceMethod="none"/>
<bKGD>
<bKGD_Grayscale gray="1"/>
</bKGD>
<cHRM whitePointX="31270" whitePointY="32900" redX="64000" redY="33000" greenX="30000" greenY="60000" blueX="15000" blueY="6000"/>
<gAMA value="45455"/>
<tIME year="2017" month="6" day="21" hour="10" minute="12" second="36"/>
</javax_imageio_png_1.0>
标准的“插件中立”元数据(跳过不相关的值):
如果您的实际图像是TIFF或多种其他格式,最好使用标准元数据格式,从
Chroma
节点获取ColorSpaceType
名称。不幸的是,我无法控制图像的创建方式。我刚刚使用imagemagick为这个特定的测试创建了这些。大多数图像实际上都是tiff,但它们可以是任何东西。嗯,也许它确实与png格式有关。我不确定如何检查调色板类型(为上面的图像转储imagemagick标识)。我无法使用您引用的TweakPNG应用程序,因为我没有windows计算机,但我确实使用tiff/jpg重新创建了它,它通过了。我想我需要回到我原来的问题,找出为什么它与这个测试不一致。ImageMagick的输出与我使用TweakPNG看到的非常接近。我注意到第三个(b/w)文件中存在cHRM
块。它不存在于彩色或灰色文件中。另外,请查看Unix/Linux的pngtools
(有Ubuntu和Debian的软件包)。更好的答案是。我一直在关注这个问题,因为我也曾多次成为膨胀的BufferedImage
的牺牲品。。。谢谢你,哈拉尔德!这是我在编程中遇到的最令人沮丧的障碍之一。。。问题太过详细,无法尝试寻找答案@这应该是公认的答案。非常感谢您的详细解释。这肯定会把事情弄清楚。我将看看是否可以向我们的PDF API提交一个补丁,以改进其颜色模型检测。
<javax_imageio_1.0>
<Chroma>
<ColorSpaceType name="GRAY"/>
<NumChannels value="1"/>
<Gamma value="0.45455"/>
<BlackIsZero value="TRUE"/>
<BackgroundColor red="1" green="1" blue="1"/>
</Chroma>
<Compression ... />
<Data>
<PlanarConfiguration value="PixelInterleaved"/>
<SampleFormat value="UnsignedIntegral"/>
<BitsPerSample value="1"/>
</Data>
<Dimension ... />
<Document ... />
<Transparency>
<Alpha value="none"/>
</Transparency>
</javax_imageio_1.0>