我想使用CMYK颜色空间在java中编写一个图像:
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颜色,而是具有以下内容
我的问题是:
请注意我已经尝试过EPS并且工作正常,但是,在我的项目的这个阶段,我不习惯使用EPS。
答案 0 :(得分:5)
是的,你可以。您需要在CMYK颜色空间中创建BufferedImage
。然后画上那个。您不能使用任何标准BufferedImage.TYPE_*
类型,因为它们都是灰色或RGB。请参阅以下代码。
您可以使用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是开发libjpeg的Independent JPEG Group):
/** IJG can handle up to 4-channel JPEGs */
所以,不幸的是,没有简单的解决办法。