As noted in another thread, bitmaps with 1bpp (or generally speaking:
bitmaps with less than 8 bits per pixels) should be represented in
memory using the IndexColorModel, i.e. a color lookup table. That way
the pixels don't have to be extended to their full color values. The
problem with the CMYK color space is that java.awt.image.IndexColorModel
only supports sRGB. So you may end up with implementing a new ColorModel
subclass which can represent non-sRGB colors. Of course, you could also
map the CMYK colors to sRGB and still use IndexColorModel but if someone
came an wanted a CMYK TIFF representation of a PDF, you'd have two color
conversions involved which could have all sorts of side-effects. But
that is certainly advanced stuff that could probably be handled at some
later point.
Here's an example of an IndexColorModel for an RGB-based 1bpp image:
byte[] map = new byte[] {(byte)0x00, (byte)0xff};
ColorModel cm = new IndexColorModel(1, 2, map, map, map);
That's just the color model with the lookup table. The other key element
is the DataBuffer instance (on which the Raster instance will operate) with
the correct SampleModel. For 1bpp, this should in the end be a
java.awt.image.MultiPixelPackedSampleModel, for example:
MultiPixelPackedSampleModel packedSampleModel = new MultiPixelPackedSampleModel(
DataBuffer.TYPE_BYTE, img.getWidth(), img.getHeight(), 1);
AFAICT, the approach with creating a ColorModel instance in the
PDColorSpace subclass is probably wrong if you want to get an optimized
in-memory representation, since the color model just interprets the
colors. It doesn't know how the pixels are represented (SampleModel).
Only the XObject itself knows how many bits represent a pixel.
HTH
On 29.04.2009 03:16:37 Daniel Wilson wrote:
> Given a bpc = 1 and a DeviceCMYK color space:
>
> byte[] array = getPDStream().getByteArray();
>
> creates an array with width*height / 8 bytes.
>
> PDColorSpace colorspace = getColorSpace();
> ColorModel cm = colorspace.createColorModel( bpc );
> WritableRaster raster = cm.createCompatibleWritableRaster( width, height );
> DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
> byte[] bufferData = buffer.getData();
>
> cm is a ColorModel reporting 32 pixelBits.
> bufferData now has width*height * 4 bytes -- or 32 times as many as array.
>
>
> System.arraycopy( array, 0,bufferData, 0,
> (array.length<bufferData.length?array.length: bufferData.length) );
> The ternary in there saves us from a buffer overflow ... but that's still
> the wrong answer.
> Just copying a 1-bit/pixel buffer into a 32-bit/pixel buffer cannot be the
> right answer.
>
> Am I to read each BIT of the source array and convert it to a 32-bit integer
> to write? So 0 becomes 0x00000000 and 1 becomes 0xFFFFFFFF ?
>
> Or is colorspace.CreateColorModel creating the wrong one? This looks right
> ...
>
> logger().info("testing Sector9's implementation");
>
> int[] nbBits = { bpc, bpc, bpc, bpc };
> ComponentColorModel componentColorModel =
> new ComponentColorModel( createColorSpace(),
> nbBits,
> false,
> false,
> Transparency.OPAQUE,
> DataBuffer.TYPE_BYTE );
>
> Thanks for your ideas!
>
> Daniel Wilson
Jeremias Maerki