【问题标题】:Write image in java with CMYK color space使用 CMYK 颜色空间在 java 中编写图像
【发布时间】:2017-09-07 19:49:13
【问题描述】:

我想在 java 中使用 CMYK 色彩空间写一个图像,如下所示:

BufferedImage image= new BufferedImage(path.getBounds().width, 
path.getBounds().height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
color c = new Color(ColorSpaces.getDeviceCMYKColorSpace(), new float[] 
{1.0f,1.0f,1.0f,1.0f}, 1.0f)
g2d.setPaint(c);
g2d.fill(path);     
g2d.draw(path);
g2d.dispose();

然后我使用imageIO将图像写入JPEG,但是结果图像在转换为PDF时没有我在代码中提供的CMYK颜色,而是如下

我的问题是:

  1. 能否使用 BufferedImage 写入具有 CMYK 色彩空间的图像?
  2. 例如,如果组件值为 0,0,0,1.0 且 alpha 为 1,我如何使用 CMYK 颜色空间编写图像

请注意,我已经尝试过 EPS 并且效果很好,但是,在我的项目的这个阶段,我对使用 EPS 感到不舒服。

【问题讨论】:

    标签: java swing bufferedimage graphics2d cmyk


    【解决方案1】:
    1. 是的,你可以。您需要在 CMYK 颜色空间中创建一个BufferedImage。然后在上面画。您不能使用任何标准的BufferedImage.TYPE_* 类型,因为它们都是灰色或RGB。请参阅下面的代码。

    2. 您可以使用 ImageIO 编写 CMYK JPEG。但是,您需要向元数据添加一些额外的细节并稍微调整像素数据以执行此操作,否则图像将被写入为 RGBA 或反转 CMYK。同样,请参阅下面的代码。

    这是一个完整的、可运行的概念验证代码示例:

    public class CMYKTest {
    
        public static final String JAVAX_IMAGEIO_JPEG_IMAGE_1_0 = "javax_imageio_jpeg_image_1.0";
    
        public static void main(String[] args) throws IOException {
            // I'm using my own TwelveMonkeys ImageIO library for this, 
            // but I think you can use the one you used above, like:
            // ColorSpace cmykCS = ColorSpaces.getDeviceCMYKColorSpace()
            ColorSpace cmykCS = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
    
            // Create CMYK color model, raster and image
            ColorModel colorModel = new ComponentColorModel(cmykCS, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
            BufferedImage image = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(100, 100), colorModel.isAlphaPremultiplied(), null);
    
            // Paint some sample rectangles on it
            Graphics2D g = image.createGraphics();
            try {
                g.setColor(new Color(cmykCS, new float[] {0, 0, 0, 0}, 1.0f)); // All 0 (White)
                g.fillRect(0, 0, 25, 50);
                g.setColor(new Color(cmykCS, new float[] {0, 0, 0, 1}, 1.0f)); // Key (Black)
                g.fillRect(25, 0, 25, 50);
                g.setColor(new Color(cmykCS, new float[] {1, 0, 0, 0}, 1.0f)); // Cyan
                g.fillRect(50, 0, 50, 50);
                g.setColor(new Color(cmykCS, new float[] {0, 1, 0, 0}, 1.0f)); // Magenta
                g.fillRect(0, 50, 50, 50);
                g.setColor(new Color(cmykCS, new float[] {0, 0, 1, 0}, 1.0f)); // Yellow
                g.fillRect(50, 50, 50, 50);
            }
            finally {
                g.dispose();
            }
    
            // Write it as a JPEG, using ImageIO    
            try (ImageOutputStream stream = ImageIO.createImageOutputStream(new File("cmyk.jpg"))) {
                ImageWriter writer = ImageIO.getImageWritersByFormatName("JPEG").next();
                writer.setOutput(stream);
    
                // We need to massage the image metadata a little to be able to write CMYK
                ImageWriteParam param = writer.getDefaultWriteParam();
                IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
    
                IIOMetadataNode jpegMeta = new IIOMetadataNode(JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
                jpegMeta.appendChild(new IIOMetadataNode("JPEGVariety")); // Just leave as default
    
                IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence");
                jpegMeta.appendChild(markerSequence);
    
                // The APP14 "Adobe" marker acts as a trigger for decoders, to
                // specify 4 channels as CMYK or YCCK (instead of RGBA or YCCA).
                IIOMetadataNode app14Adobe = new IIOMetadataNode("app14Adobe");
                app14Adobe.setAttribute("transform", "0"); // 0 means "unknown"
                markerSequence.appendChild(app14Adobe);
    
                // You could also append an ICC profile as part of the JPEG metadata
                // if you feel adventurous...
    
                // Merge with metadata from the writer
                metadata.mergeTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0, jpegMeta);
    
                // Also, we need to massage the raster a little, as CMYK data is
                // written in "inverse" form. 
                // We could use image.getRaster() here to get better performance
                // if you don't mind the image being inverted in memory too. 
                // image.getData() creates a copy, and is safe from this side effect.
                Raster raster = image.getData(); 
                byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
                // Inverse the pixel data
                for (int i = 0; i < data.length; i++) {
                    data[i] = (byte) (255 - data[i]);
                }
    
                // Finally, write it all
                writer.write(null, new IIOImage(raster, null, metadata), param);
            }
        }
    }
    

    使用 ImageIO 读取 CMYK JPEG 图像的注意事项

    上述代码将写入标准JPEGImageReader 无法读取的JPEG 图像(通过readRaster() 方法除外)。

    为了更好/更轻松地支持 CMYK JPEG,我建议使用 TwelveMonkeys ImageIO JPEG 插件(我是这个插件的作者)。

    关于 CMYK 和透明度的小字体

    您还可以创建具有透明度(alpha 通道)的 CMYK 颜色模型/图像,如下所示:

    ColorModel colorModel = new ComponentColorModel(cmykCS, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
    BufferedImage image = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(100, 100), colorModel.isAlphaPremultiplied(), null);
    

    但不幸的是,JPEGImageWriter 不能处理超过 4 个通道的数据。我在一个有注释的数组中得到一个IndexArrayOutOfBoundsException(IJG 是独立 JPEG 组,开发 libjpeg):

    /** IJG can handle up to 4-channel JPEGs */
    

    因此,不幸的是,没有简单的解决方法。

    【讨论】:

    • 太棒了,非常感谢!,小问题,我可以将背景设置为透明吗?我在 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR)); 之前使用过这段代码g2d.fillRect(0, 0, w, h); // 重置复合 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));另一件事,我有颜色值 c=1,m=1,y=1,k=1 的元素,输出颜色是 c=0,y=0.m=0,k =1,知道为什么吗?
    • 我添加了关于透明度的部分。不幸的是,这并不容易修复。但是,如果您想在 CMYK+A 中构图,然后最后将透明部分替换为全白,则可以使用它。如果您需要透明度,请使用其他格式,例如 TIFF。
    • 在 CMYK 中,k=1 被认为是 100% 黑色。添加更多颜色,它仍然是100%黑色......所以没关系............用于屏幕显示。我知道打印过程使用黑色 + 彩色来产生“浓黑”,但我不确定这是如何在软件中实现的。
    猜你喜欢
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2011-05-01
    • 2011-06-17
    • 2013-12-21
    相关资源
    最近更新 更多