From b5f2f9dbb8313f77a65516034a1abb5e9e734507 Mon Sep 17 00:00:00 2001 From: guinotphil Date: Fri, 15 Nov 2013 16:02:35 +0100 Subject: [PATCH] Add a first implementation of toBuffered for ColorSeparation to handle CMYK pictures. The code has been tested with a CMYK picture, but I have not been able to test alpha picture. The code will probably also need to be improved to handle any kind of ColorSeparation picture. Though, it's a nice base for further developments. --- .../com/twelvemonkeys/image/MagickUtil.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/common/common-image/src/main/java/com/twelvemonkeys/image/MagickUtil.java b/common/common-image/src/main/java/com/twelvemonkeys/image/MagickUtil.java index 491fdaf1..2758aed3 100755 --- a/common/common-image/src/main/java/com/twelvemonkeys/image/MagickUtil.java +++ b/common/common-image/src/main/java/com/twelvemonkeys/image/MagickUtil.java @@ -32,6 +32,8 @@ import magick.*; import java.awt.*; import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; import java.awt.image.*; /** @@ -160,7 +162,11 @@ public final class MagickUtil { image = rgbToBuffered(pImage, true); break; case ImageType.ColorSeparationType: + image = cmykToBuffered(pImage, false); + break; case ImageType.ColorSeparationMatteType: + image = cmykToBuffered(pImage, true); // Not tested actually + break; case ImageType.OptimizeType: default: throw new IllegalArgumentException("Unknown JMagick image type: " + pImage.getImageType()); @@ -546,4 +552,62 @@ public final class MagickUtil { return new BufferedImage(pAlpha ? CM_COLOR_ALPHA : CM_COLOR_OPAQUE, raster, pAlpha, null); } + + + + + /** + * Converts an {@code MagickImage} to a {@code BufferedImage} which holds an CMYK ICC profile + * + * @param pImage the original {@code MagickImage} + * @param pAlpha keep alpha channel + * @return a new {@code BufferedImage} + * + * @throws MagickException if an exception occurs during conversion + * + * @see BufferedImage + */ + private static BufferedImage cmykToBuffered(MagickImage pImage, boolean pAlpha) throws MagickException { + final Dimension size = pImage.getDimension(); + final int length = size.width * size.height; + + // Retreive the ICC profile + final ICC_Profile profile = ICC_Profile.getInstance(pImage.getColorProfile().getInfo()); + final ColorSpace cs = new ICC_ColorSpace(profile); + + final int bands = cs.getNumComponents() + (pAlpha ? 1 : 0); + + final ColorModel cm; + final int[] bits = new int[bands]; + for (int i = 0; i < bands; i++) { + bits[i] = 8; + } + if (pAlpha) { + cm = new ComponentColorModel(cs, bits, true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + } else { + cm = new ComponentColorModel(cs, bits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + } + + final byte[] pixels = new byte[length * bands]; + + // TODO: If we do multiple dispatches (one per line, typically), we could provide listener + // feedback. But it's currently a lot slower than fetching all the pixels in one go. + // TODO: handle more generic cases if profile is not CMYK + // The "ACMYK" value has not been tested with an alpha picture actually... + pImage.dispatchImage(0, 0, size.width, size.height, pAlpha ? "ACMYK" : "CMYK", pixels); + + // Init databuffer with array, to avoid allocation of empty array + final DataBuffer buffer = new DataBufferByte(pixels, pixels.length); + + // TODO: build array from bands variable, here it just works for CMYK + // The values has not been tested with an alpha picture actually... + final int[] bandOffsets = pAlpha ? new int[] {0, 1, 2, 3, 4} : new int[] {0, 1, 2, 3}; + + final WritableRaster raster = + Raster.createInterleavedRaster(buffer, size.width, size.height, + size.width * bands, bands, bandOffsets, LOCATION_UPPER_LEFT); + + return new BufferedImage(cm, raster, pAlpha, null); + + } }