光栅图像的 sRGB IEC61966-2.1 ColorModel
sRGB IEC61966-2.1 ColorModel for Raster image
我需要将客户提供的 JPG 图片转换为 sRGB 格式 (sRGB IEC61966-2.1) 以便为网页做好准备。
我可以用ImageIO
和BufferedImage
成功,但是这个操作真的很慢:
val srgbSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB)
val colorConversionOperation = new ColorConvertOp(srgbSpace, null)
val converted = colorConversionOperation.filter(inputImage, null)
(已经尝试向 ColorConvertOp
提供 RenderingHints
- 它没有帮助)
据我所知,罪魁祸首是 BufferedImage
,我需要 Raster
秒来加快速度:
val iccProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB)
val iccColorSpace = new ICC_ColorSpace(iccProfile)
val sourceColorSpace = inputImage.getColorModel.getColorSpace
val colorConversionOperation = new ColorConvertOp(sourceColorSpace, iccColorSpace, null)
val converted = colorConversionOperation.filter(inputImage.getRaster, null)
这确实带来了巨大的性能提升,但我不知道如何保存 Raster
以便最终图像包含适当的颜色 Space 和颜色配置文件信息。
目前我通过以下方式从 Raster
创建 BufferedImage
:
val outImage = new BufferedImage(ColorModel.getRGBdefault, converted, false, null);
当我使用 BufferedImage
时,最终的 JPG 保存为:
Color space: RGB
Color profile: sRGB IEC61966-2.1
在这种情况下是正确的。
当我使用 Raster
s 时,最终的 JPG 保存为:
Color space: RGB
这意味着我丢失了 Color profile
信息。我认为这是因为我在将 Raster
转换为 BufferedImage
时执行 ColorModel.getRGBdefault
但我不知道如何为 sRGB IEC61966-2.1 获取 ColorModel
的实例。
这是一个 "short" 示例代码,展示了如何 "force" JPEGImageWriter
在输出 JPEG 文件中输出 ICC 配置文件片段,即使图像是 sRGB 颜色 space(如果图像不是 sRGB 颜色 space,它会自动发生,正如您从测试中看到的那样)。
public class ICCTest {
public static void main(String[] args) throws IOException {
// Fist let's assume this isn't already in sRGB (it is...)
BufferedImage inputImage = new BufferedImage(10, 10, BufferedImage.TYPE_3BYTE_BGR);
// Conversion similar to yours
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
WritableRaster raster = new ColorConvertOp(inputImage.getColorModel().getColorSpace(), sRGB, null)
.filter(inputImage.getRaster(), null);
ComponentColorModel cm = new ComponentColorModel(sRGB, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
BufferedImage converted = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
// Just for comparison
ImageIO.write(converted, "JPEG", new File("converted.jpg"));
// Write image with forced ICC profile
ImageWriter writer = ImageIO.getImageWritersByFormatName("JPEG").next();
try (ImageOutputStream out = ImageIO.createImageOutputStream(new File("converted_icc.jpg"))) {
writer.setOutput(out);
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(converted2), param);
metadata.mergeTree("javax_imageio_jpeg_image_1.0", createICCTree((ICC_ColorSpace) sRGB));
writer.write(null, new IIOImage(converted, null, metadata), param);
}
writer.dispose();
}
// Create a minimal IIOMetadata tree, containing an ICC profile
private static IIOMetadataNode createICCTree(ColorSpace cs) {
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_jpeg_image_1.0");
IIOMetadataNode jpegVariety = new IIOMetadataNode("JPEGvariety");
root.appendChild(jpegVariety);
root.appendChild(new IIOMetadataNode("markerSequence")); // Must be present, even if empty...
IIOMetadataNode app0JFIF = new IIOMetadataNode("app0JFIF");
jpegVariety.appendChild(app0JFIF);
IIOMetadataNode icc = new IIOMetadataNode("app2ICC");
app0JFIF.appendChild(icc);
icc.setUserObject(cs.getProfile());
return root;
}
}
您可以在文档中阅读有关 JPEG metadata format 的更多信息。
PS:我认为大多数现代网络浏览器会将没有配置文件的 JPEG 视为已经在 sRGB 中(尽管根据 JFIF 规范这是错误的)。所以可能你不需要实际输出ICC配置文件,只要你进行colorspace转换即可。
我需要将客户提供的 JPG 图片转换为 sRGB 格式 (sRGB IEC61966-2.1) 以便为网页做好准备。
我可以用ImageIO
和BufferedImage
成功,但是这个操作真的很慢:
val srgbSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB)
val colorConversionOperation = new ColorConvertOp(srgbSpace, null)
val converted = colorConversionOperation.filter(inputImage, null)
(已经尝试向 ColorConvertOp
提供 RenderingHints
- 它没有帮助)
据我所知,罪魁祸首是 BufferedImage
,我需要 Raster
秒来加快速度:
val iccProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB)
val iccColorSpace = new ICC_ColorSpace(iccProfile)
val sourceColorSpace = inputImage.getColorModel.getColorSpace
val colorConversionOperation = new ColorConvertOp(sourceColorSpace, iccColorSpace, null)
val converted = colorConversionOperation.filter(inputImage.getRaster, null)
这确实带来了巨大的性能提升,但我不知道如何保存 Raster
以便最终图像包含适当的颜色 Space 和颜色配置文件信息。
目前我通过以下方式从 Raster
创建 BufferedImage
:
val outImage = new BufferedImage(ColorModel.getRGBdefault, converted, false, null);
当我使用 BufferedImage
时,最终的 JPG 保存为:
Color space: RGB
Color profile: sRGB IEC61966-2.1
在这种情况下是正确的。
当我使用 Raster
s 时,最终的 JPG 保存为:
Color space: RGB
这意味着我丢失了 Color profile
信息。我认为这是因为我在将 Raster
转换为 BufferedImage
时执行 ColorModel.getRGBdefault
但我不知道如何为 sRGB IEC61966-2.1 获取 ColorModel
的实例。
这是一个 "short" 示例代码,展示了如何 "force" JPEGImageWriter
在输出 JPEG 文件中输出 ICC 配置文件片段,即使图像是 sRGB 颜色 space(如果图像不是 sRGB 颜色 space,它会自动发生,正如您从测试中看到的那样)。
public class ICCTest {
public static void main(String[] args) throws IOException {
// Fist let's assume this isn't already in sRGB (it is...)
BufferedImage inputImage = new BufferedImage(10, 10, BufferedImage.TYPE_3BYTE_BGR);
// Conversion similar to yours
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
WritableRaster raster = new ColorConvertOp(inputImage.getColorModel().getColorSpace(), sRGB, null)
.filter(inputImage.getRaster(), null);
ComponentColorModel cm = new ComponentColorModel(sRGB, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
BufferedImage converted = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
// Just for comparison
ImageIO.write(converted, "JPEG", new File("converted.jpg"));
// Write image with forced ICC profile
ImageWriter writer = ImageIO.getImageWritersByFormatName("JPEG").next();
try (ImageOutputStream out = ImageIO.createImageOutputStream(new File("converted_icc.jpg"))) {
writer.setOutput(out);
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(converted2), param);
metadata.mergeTree("javax_imageio_jpeg_image_1.0", createICCTree((ICC_ColorSpace) sRGB));
writer.write(null, new IIOImage(converted, null, metadata), param);
}
writer.dispose();
}
// Create a minimal IIOMetadata tree, containing an ICC profile
private static IIOMetadataNode createICCTree(ColorSpace cs) {
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_jpeg_image_1.0");
IIOMetadataNode jpegVariety = new IIOMetadataNode("JPEGvariety");
root.appendChild(jpegVariety);
root.appendChild(new IIOMetadataNode("markerSequence")); // Must be present, even if empty...
IIOMetadataNode app0JFIF = new IIOMetadataNode("app0JFIF");
jpegVariety.appendChild(app0JFIF);
IIOMetadataNode icc = new IIOMetadataNode("app2ICC");
app0JFIF.appendChild(icc);
icc.setUserObject(cs.getProfile());
return root;
}
}
您可以在文档中阅读有关 JPEG metadata format 的更多信息。
PS:我认为大多数现代网络浏览器会将没有配置文件的 JPEG 视为已经在 sRGB 中(尽管根据 JFIF 规范这是错误的)。所以可能你不需要实际输出ICC配置文件,只要你进行colorspace转换即可。