BufferedImage сообщает о неверном типе цветовой модели
Я использую некоторые сторонние программы для преобразования изображений в PDF, и я заметил некоторые завышенные размеры файлов. Немного покопавшись, я убедился, что цветовая модель для снимков не сохранилась. Черно-белые (1 бит) изображения преобразовывались в цветовые модели RGB.
Копание в библиотеке показывает некоторое обнаружение цветовой модели:
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);
}
}
}
Тест blackAndWhiteImage всегда терпит неудачу. Тип цветового пространства-5 (RGB). Это ошибка в JDK или я упускаю что-то фундаментальное здесь?
Тестовые изображения:
Цветовое пространство: 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
2 ответа:
Я вижу, что у вас уже есть приемлемый ответ, но я все равно попытаюсь объяснить это.. Это не ошибка. Но я согласен, иногда это противоречит интуиции.
Ваш тест использует цветовое пространство декодированного представления изображения в памяти и сравнивает его с ожидаемым цветовым пространством из закодированного файла. Когда файл декодируется (используяImageIO.readв вашем примере), плагинImageReaderобычно преобразует изображение в представление в памяти, которое быстро рисуется на экране. Этот может сильно отличаться от представления, которое наиболее эффективно при хранении на диске. Например, изображение в оттенках серого, использующее менее 8 бит на образец, обычно преобразуется вIndexColorModel, Даже если файл PNG не содержит фрагментаPLTE. И,IndexColorModelвсегда использует цветовое пространство sRGB (тип RGB), даже если оно содержит только серые значения. Это не имеет значения для отображаемых пикселей, которые будут черно-белыми независимо, но это имеет значение для вашего теста.Это так можно получить цветовое пространство, которое было фактически закодировано в файле, используя API
ImageIO: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 }Я пропустил чтение фактических значений, поскольку оно становится довольно многословным,но это довольно прямолинейно. Все значения равны
Strings. см.IIOMetadataдокументация класса для деталей.Метаданные для файла
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>Стандартные" плагин-нейтральные " метаданные (пропуск нерелевантные значения):
<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>Если ваши реальные изображения представляют собой TIFF или несколько других форматов, вероятно, лучше всего использовать стандартный формат метаданных, получив имя
ColorSpaceTypeиз узлаChroma.
Я думаю, что это исходит из вашего файла
bw.png. Как я понимаю, 1-битные PNG - это либо оттенки серого, либо индексированные (палитра), и индексированные будут использовать пространство RGB, поэтому у вас будет 2 цвета (#000000и#ffffff). Проверьте, какой инструмент вы используете для создания PNG, и посмотрите, дает ли он вам выбор между оттенками серого и индексированными. Вы также можете посмотреть на фрагменты PNG, чтобы убедиться, что файл создан так, как вы ожидаете.Это может быть полезно: TweakPNG