0N/A/*
2362N/A * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.imageio.plugins.common;
0N/A
0N/Aimport java.awt.Point;
0N/Aimport java.awt.Rectangle;
0N/Aimport java.awt.Transparency;
0N/Aimport java.awt.color.ColorSpace;
0N/Aimport java.awt.image.BufferedImage;
0N/Aimport java.awt.image.ColorModel;
0N/Aimport java.awt.image.ComponentColorModel;
0N/Aimport java.awt.image.ComponentSampleModel;
0N/Aimport java.awt.image.DataBuffer;
0N/Aimport java.awt.image.DataBufferByte;
0N/Aimport java.awt.image.DataBufferInt;
0N/Aimport java.awt.image.DataBufferShort;
0N/Aimport java.awt.image.DataBufferUShort;
0N/Aimport java.awt.image.DirectColorModel;
0N/Aimport java.awt.image.IndexColorModel;
0N/Aimport java.awt.image.MultiPixelPackedSampleModel;
0N/Aimport java.awt.image.Raster;
0N/Aimport java.awt.image.RenderedImage;
0N/Aimport java.awt.image.SampleModel;
0N/Aimport java.awt.image.SinglePixelPackedSampleModel;
0N/Aimport java.awt.image.WritableRaster;
0N/Aimport java.util.Arrays;
0N/A
0N/A//import javax.imageio.ImageTypeSpecifier;
0N/A
0N/Aimport javax.imageio.IIOException;
0N/Aimport javax.imageio.IIOImage;
0N/Aimport javax.imageio.ImageTypeSpecifier;
0N/Aimport javax.imageio.ImageWriter;
0N/Aimport javax.imageio.spi.ImageWriterSpi;
0N/A
0N/Apublic class ImageUtil {
0N/A /* XXX testing only
0N/A public static void main(String[] args) {
0N/A ImageTypeSpecifier bilevel =
0N/A ImageTypeSpecifier.createIndexed(new byte[] {(byte)0, (byte)255},
0N/A new byte[] {(byte)0, (byte)255},
0N/A new byte[] {(byte)0, (byte)255},
0N/A null, 1,
0N/A DataBuffer.TYPE_BYTE);
0N/A ImageTypeSpecifier gray =
0N/A ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false);
0N/A ImageTypeSpecifier grayAlpha =
0N/A ImageTypeSpecifier.createGrayscale(8, DataBuffer.TYPE_BYTE, false,
0N/A false);
0N/A ImageTypeSpecifier rgb =
0N/A ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
0N/A new int[] {0, 1, 2},
0N/A DataBuffer.TYPE_BYTE,
0N/A false,
0N/A false);
0N/A ImageTypeSpecifier rgba =
0N/A ImageTypeSpecifier.createInterleaved(ColorSpace.getInstance(ColorSpace.CS_sRGB),
0N/A new int[] {0, 1, 2, 3},
0N/A DataBuffer.TYPE_BYTE,
0N/A true,
0N/A false);
0N/A ImageTypeSpecifier packed =
0N/A ImageTypeSpecifier.createPacked(ColorSpace.getInstance(ColorSpace.CS_sRGB),
0N/A 0xff000000,
0N/A 0x00ff0000,
0N/A 0x0000ff00,
0N/A 0x000000ff,
0N/A DataBuffer.TYPE_BYTE,
0N/A false);
0N/A
0N/A SampleModel bandedSM =
0N/A new java.awt.image.BandedSampleModel(DataBuffer.TYPE_BYTE,
0N/A 1, 1, 15);
0N/A
0N/A System.out.println(createColorModel(bilevel.getSampleModel()));
0N/A System.out.println(createColorModel(gray.getSampleModel()));
0N/A System.out.println(createColorModel(grayAlpha.getSampleModel()));
0N/A System.out.println(createColorModel(rgb.getSampleModel()));
0N/A System.out.println(createColorModel(rgba.getSampleModel()));
0N/A System.out.println(createColorModel(packed.getSampleModel()));
0N/A System.out.println(createColorModel(bandedSM));
0N/A }
0N/A */
0N/A
0N/A /**
0N/A * Creates a <code>ColorModel</code> that may be used with the
0N/A * specified <code>SampleModel</code>. If a suitable
0N/A * <code>ColorModel</code> cannot be found, this method returns
0N/A * <code>null</code>.
0N/A *
0N/A * <p> Suitable <code>ColorModel</code>s are guaranteed to exist
0N/A * for all instances of <code>ComponentSampleModel</code>.
0N/A * For 1- and 3- banded <code>SampleModel</code>s, the returned
0N/A * <code>ColorModel</code> will be opaque. For 2- and 4-banded
0N/A * <code>SampleModel</code>s, the output will use alpha transparency
0N/A * which is not premultiplied. 1- and 2-banded data will use a
0N/A * grayscale <code>ColorSpace</code>, and 3- and 4-banded data a sRGB
0N/A * <code>ColorSpace</code>. Data with 5 or more bands will have a
0N/A * <code>BogusColorSpace</code>.</p>
0N/A *
0N/A * <p>An instance of <code>DirectColorModel</code> will be created for
0N/A * instances of <code>SinglePixelPackedSampleModel</code> with no more
0N/A * than 4 bands.</p>
0N/A *
0N/A * <p>An instance of <code>IndexColorModel</code> will be created for
0N/A * instances of <code>MultiPixelPackedSampleModel</code>. The colormap
0N/A * will be a grayscale ramp with <code>1&nbsp;<<&nbsp;numberOfBits</code>
0N/A * entries ranging from zero to at most 255.</p>
0N/A *
0N/A * @return An instance of <code>ColorModel</code> that is suitable for
0N/A * the supplied <code>SampleModel</code>, or <code>null</code>.
0N/A *
0N/A * @throws IllegalArgumentException If <code>sampleModel</code> is
0N/A * <code>null</code>.
0N/A */
0N/A public static final ColorModel createColorModel(SampleModel sampleModel) {
0N/A // Check the parameter.
0N/A if(sampleModel == null) {
0N/A throw new IllegalArgumentException("sampleModel == null!");
0N/A }
0N/A
0N/A // Get the data type.
0N/A int dataType = sampleModel.getDataType();
0N/A
0N/A // Check the data type
0N/A switch(dataType) {
0N/A case DataBuffer.TYPE_BYTE:
0N/A case DataBuffer.TYPE_USHORT:
0N/A case DataBuffer.TYPE_SHORT:
0N/A case DataBuffer.TYPE_INT:
0N/A case DataBuffer.TYPE_FLOAT:
0N/A case DataBuffer.TYPE_DOUBLE:
0N/A break;
0N/A default:
0N/A // Return null for other types.
0N/A return null;
0N/A }
0N/A
0N/A // The return variable.
0N/A ColorModel colorModel = null;
0N/A
0N/A // Get the sample size.
0N/A int[] sampleSize = sampleModel.getSampleSize();
0N/A
0N/A // Create a Component ColorModel.
0N/A if(sampleModel instanceof ComponentSampleModel) {
0N/A // Get the number of bands.
0N/A int numBands = sampleModel.getNumBands();
0N/A
0N/A // Determine the color space.
0N/A ColorSpace colorSpace = null;
0N/A if(numBands <= 2) {
0N/A colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
0N/A } else if(numBands <= 4) {
0N/A colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0N/A } else {
0N/A colorSpace = new BogusColorSpace(numBands);
0N/A }
0N/A
0N/A boolean hasAlpha = (numBands == 2) || (numBands == 4);
0N/A boolean isAlphaPremultiplied = false;
0N/A int transparency = hasAlpha ?
0N/A Transparency.TRANSLUCENT : Transparency.OPAQUE;
0N/A
0N/A colorModel = new ComponentColorModel(colorSpace,
0N/A sampleSize,
0N/A hasAlpha,
0N/A isAlphaPremultiplied,
0N/A transparency,
0N/A dataType);
0N/A } else if (sampleModel.getNumBands() <= 4 &&
0N/A sampleModel instanceof SinglePixelPackedSampleModel) {
0N/A SinglePixelPackedSampleModel sppsm =
0N/A (SinglePixelPackedSampleModel)sampleModel;
0N/A
0N/A int[] bitMasks = sppsm.getBitMasks();
0N/A int rmask = 0;
0N/A int gmask = 0;
0N/A int bmask = 0;
0N/A int amask = 0;
0N/A
0N/A int numBands = bitMasks.length;
0N/A if (numBands <= 2) {
0N/A rmask = gmask = bmask = bitMasks[0];
0N/A if (numBands == 2) {
0N/A amask = bitMasks[1];
0N/A }
0N/A } else {
0N/A rmask = bitMasks[0];
0N/A gmask = bitMasks[1];
0N/A bmask = bitMasks[2];
0N/A if (numBands == 4) {
0N/A amask = bitMasks[3];
0N/A }
0N/A }
0N/A
0N/A int bits = 0;
0N/A for (int i = 0; i < sampleSize.length; i++) {
0N/A bits += sampleSize[i];
0N/A }
0N/A
0N/A return new DirectColorModel(bits, rmask, gmask, bmask, amask);
0N/A
0N/A } else if(sampleModel instanceof MultiPixelPackedSampleModel) {
0N/A // Load the colormap with a ramp.
0N/A int bitsPerSample = sampleSize[0];
0N/A int numEntries = 1 << bitsPerSample;
0N/A byte[] map = new byte[numEntries];
0N/A for (int i = 0; i < numEntries; i++) {
0N/A map[i] = (byte)(i*255/(numEntries - 1));
0N/A }
0N/A
0N/A colorModel = new IndexColorModel(bitsPerSample, numEntries,
0N/A map, map, map);
0N/A
0N/A }
0N/A
0N/A return colorModel;
0N/A }
0N/A
0N/A /**
0N/A * For the case of binary data (<code>isBinary()</code> returns
0N/A * <code>true</code>), return the binary data as a packed byte array.
0N/A * The data will be packed as eight bits per byte with no bit offset,
0N/A * i.e., the first bit in each image line will be the left-most of the
0N/A * first byte of the line. The line stride in bytes will be
0N/A * <code>(int)((getWidth()+7)/8)</code>. The length of the returned
0N/A * array will be the line stride multiplied by <code>getHeight()</code>
0N/A *
0N/A * @return the binary data as a packed array of bytes with zero offset
0N/A * of <code>null</code> if the data are not binary.
0N/A * @throws IllegalArgumentException if <code>isBinary()</code> returns
0N/A * <code>false</code> with the <code>SampleModel</code> of the
0N/A * supplied <code>Raster</code> as argument.
0N/A */
0N/A public static byte[] getPackedBinaryData(Raster raster,
0N/A Rectangle rect) {
0N/A SampleModel sm = raster.getSampleModel();
0N/A if(!isBinary(sm)) {
0N/A throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
0N/A }
0N/A
0N/A int rectX = rect.x;
0N/A int rectY = rect.y;
0N/A int rectWidth = rect.width;
0N/A int rectHeight = rect.height;
0N/A
0N/A DataBuffer dataBuffer = raster.getDataBuffer();
0N/A
0N/A int dx = rectX - raster.getSampleModelTranslateX();
0N/A int dy = rectY - raster.getSampleModelTranslateY();
0N/A
0N/A MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
0N/A int lineStride = mpp.getScanlineStride();
0N/A int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
0N/A int bitOffset = mpp.getBitOffset(dx);
0N/A
0N/A int numBytesPerRow = (rectWidth + 7)/8;
0N/A if(dataBuffer instanceof DataBufferByte &&
0N/A eltOffset == 0 && bitOffset == 0 &&
0N/A numBytesPerRow == lineStride &&
0N/A ((DataBufferByte)dataBuffer).getData().length ==
0N/A numBytesPerRow*rectHeight) {
0N/A return ((DataBufferByte)dataBuffer).getData();
0N/A }
0N/A
0N/A byte[] binaryDataArray = new byte[numBytesPerRow*rectHeight];
0N/A
0N/A int b = 0;
0N/A
0N/A if(bitOffset == 0) {
0N/A if(dataBuffer instanceof DataBufferByte) {
0N/A byte[] data = ((DataBufferByte)dataBuffer).getData();
0N/A int stride = numBytesPerRow;
0N/A int offset = 0;
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A System.arraycopy(data, eltOffset,
0N/A binaryDataArray, offset,
0N/A stride);
0N/A offset += stride;
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferShort ||
0N/A dataBuffer instanceof DataBufferUShort) {
0N/A short[] data = dataBuffer instanceof DataBufferShort ?
0N/A ((DataBufferShort)dataBuffer).getData() :
0N/A ((DataBufferUShort)dataBuffer).getData();
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int xRemaining = rectWidth;
0N/A int i = eltOffset;
0N/A while(xRemaining > 8) {
0N/A short datum = data[i++];
0N/A binaryDataArray[b++] = (byte)((datum >>> 8) & 0xFF);
0N/A binaryDataArray[b++] = (byte)(datum & 0xFF);
0N/A xRemaining -= 16;
0N/A }
0N/A if(xRemaining > 0) {
0N/A binaryDataArray[b++] = (byte)((data[i] >>> 8) & 0XFF);
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferInt) {
0N/A int[] data = ((DataBufferInt)dataBuffer).getData();
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int xRemaining = rectWidth;
0N/A int i = eltOffset;
0N/A while(xRemaining > 24) {
0N/A int datum = data[i++];
0N/A binaryDataArray[b++] = (byte)((datum >>> 24) & 0xFF);
0N/A binaryDataArray[b++] = (byte)((datum >>> 16) & 0xFF);
0N/A binaryDataArray[b++] = (byte)((datum >>> 8) & 0xFF);
0N/A binaryDataArray[b++] = (byte)(datum & 0xFF);
0N/A xRemaining -= 32;
0N/A }
0N/A int shift = 24;
0N/A while(xRemaining > 0) {
0N/A binaryDataArray[b++] =
0N/A (byte)((data[i] >>> shift) & 0xFF);
0N/A shift -= 8;
0N/A xRemaining -= 8;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A } else { // bitOffset != 0
0N/A if(dataBuffer instanceof DataBufferByte) {
0N/A byte[] data = ((DataBufferByte)dataBuffer).getData();
0N/A
0N/A if((bitOffset & 7) == 0) {
0N/A int stride = numBytesPerRow;
0N/A int offset = 0;
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A System.arraycopy(data, eltOffset,
0N/A binaryDataArray, offset,
0N/A stride);
0N/A offset += stride;
0N/A eltOffset += lineStride;
0N/A }
0N/A } else { // bitOffset % 8 != 0
0N/A int leftShift = bitOffset & 7;
0N/A int rightShift = 8 - leftShift;
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int i = eltOffset;
0N/A int xRemaining = rectWidth;
0N/A while(xRemaining > 0) {
0N/A if(xRemaining > rightShift) {
0N/A binaryDataArray[b++] =
0N/A (byte)(((data[i++]&0xFF) << leftShift) |
0N/A ((data[i]&0xFF) >>> rightShift));
0N/A } else {
0N/A binaryDataArray[b++] =
0N/A (byte)((data[i]&0xFF) << leftShift);
0N/A }
0N/A xRemaining -= 8;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferShort ||
0N/A dataBuffer instanceof DataBufferUShort) {
0N/A short[] data = dataBuffer instanceof DataBufferShort ?
0N/A ((DataBufferShort)dataBuffer).getData() :
0N/A ((DataBufferUShort)dataBuffer).getData();
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = bitOffset;
0N/A for(int x = 0; x < rectWidth; x += 8, bOffset += 8) {
0N/A int i = eltOffset + bOffset/16;
0N/A int mod = bOffset % 16;
0N/A int left = data[i] & 0xFFFF;
0N/A if(mod <= 8) {
0N/A binaryDataArray[b++] = (byte)(left >>> (8 - mod));
0N/A } else {
0N/A int delta = mod - 8;
0N/A int right = data[i+1] & 0xFFFF;
0N/A binaryDataArray[b++] =
0N/A (byte)((left << delta) |
0N/A (right >>> (16 - delta)));
0N/A }
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferInt) {
0N/A int[] data = ((DataBufferInt)dataBuffer).getData();
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = bitOffset;
0N/A for(int x = 0; x < rectWidth; x += 8, bOffset += 8) {
0N/A int i = eltOffset + bOffset/32;
0N/A int mod = bOffset % 32;
0N/A int left = data[i];
0N/A if(mod <= 24) {
0N/A binaryDataArray[b++] =
0N/A (byte)(left >>> (24 - mod));
0N/A } else {
0N/A int delta = mod - 24;
0N/A int right = data[i+1];
0N/A binaryDataArray[b++] =
0N/A (byte)((left << delta) |
0N/A (right >>> (32 - delta)));
0N/A }
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A }
0N/A
0N/A return binaryDataArray;
0N/A }
0N/A
0N/A /**
0N/A * Returns the binary data unpacked into an array of bytes.
0N/A * The line stride will be the width of the <code>Raster</code>.
0N/A *
0N/A * @throws IllegalArgumentException if <code>isBinary()</code> returns
0N/A * <code>false</code> with the <code>SampleModel</code> of the
0N/A * supplied <code>Raster</code> as argument.
0N/A */
0N/A public static byte[] getUnpackedBinaryData(Raster raster,
0N/A Rectangle rect) {
0N/A SampleModel sm = raster.getSampleModel();
0N/A if(!isBinary(sm)) {
0N/A throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
0N/A }
0N/A
0N/A int rectX = rect.x;
0N/A int rectY = rect.y;
0N/A int rectWidth = rect.width;
0N/A int rectHeight = rect.height;
0N/A
0N/A DataBuffer dataBuffer = raster.getDataBuffer();
0N/A
0N/A int dx = rectX - raster.getSampleModelTranslateX();
0N/A int dy = rectY - raster.getSampleModelTranslateY();
0N/A
0N/A MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
0N/A int lineStride = mpp.getScanlineStride();
0N/A int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
0N/A int bitOffset = mpp.getBitOffset(dx);
0N/A
0N/A byte[] bdata = new byte[rectWidth*rectHeight];
0N/A int maxY = rectY + rectHeight;
0N/A int maxX = rectX + rectWidth;
0N/A int k = 0;
0N/A
0N/A if(dataBuffer instanceof DataBufferByte) {
0N/A byte[] data = ((DataBufferByte)dataBuffer).getData();
0N/A for(int y = rectY; y < maxY; y++) {
0N/A int bOffset = eltOffset*8 + bitOffset;
0N/A for(int x = rectX; x < maxX; x++) {
0N/A byte b = data[bOffset/8];
0N/A bdata[k++] =
0N/A (byte)((b >>> (7 - bOffset & 7)) & 0x0000001);
0N/A bOffset++;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferShort ||
0N/A dataBuffer instanceof DataBufferUShort) {
0N/A short[] data = dataBuffer instanceof DataBufferShort ?
0N/A ((DataBufferShort)dataBuffer).getData() :
0N/A ((DataBufferUShort)dataBuffer).getData();
0N/A for(int y = rectY; y < maxY; y++) {
0N/A int bOffset = eltOffset*16 + bitOffset;
0N/A for(int x = rectX; x < maxX; x++) {
0N/A short s = data[bOffset/16];
0N/A bdata[k++] =
0N/A (byte)((s >>> (15 - bOffset % 16)) &
0N/A 0x0000001);
0N/A bOffset++;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferInt) {
0N/A int[] data = ((DataBufferInt)dataBuffer).getData();
0N/A for(int y = rectY; y < maxY; y++) {
0N/A int bOffset = eltOffset*32 + bitOffset;
0N/A for(int x = rectX; x < maxX; x++) {
0N/A int i = data[bOffset/32];
0N/A bdata[k++] =
0N/A (byte)((i >>> (31 - bOffset % 32)) &
0N/A 0x0000001);
0N/A bOffset++;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A
0N/A return bdata;
0N/A }
0N/A
0N/A /**
0N/A * Sets the supplied <code>Raster</code>'s data from an array
0N/A * of packed binary data of the form returned by
0N/A * <code>getPackedBinaryData()</code>.
0N/A *
0N/A * @throws IllegalArgumentException if <code>isBinary()</code> returns
0N/A * <code>false</code> with the <code>SampleModel</code> of the
0N/A * supplied <code>Raster</code> as argument.
0N/A */
0N/A public static void setPackedBinaryData(byte[] binaryDataArray,
0N/A WritableRaster raster,
0N/A Rectangle rect) {
0N/A SampleModel sm = raster.getSampleModel();
0N/A if(!isBinary(sm)) {
0N/A throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
0N/A }
0N/A
0N/A int rectX = rect.x;
0N/A int rectY = rect.y;
0N/A int rectWidth = rect.width;
0N/A int rectHeight = rect.height;
0N/A
0N/A DataBuffer dataBuffer = raster.getDataBuffer();
0N/A
0N/A int dx = rectX - raster.getSampleModelTranslateX();
0N/A int dy = rectY - raster.getSampleModelTranslateY();
0N/A
0N/A MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
0N/A int lineStride = mpp.getScanlineStride();
0N/A int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
0N/A int bitOffset = mpp.getBitOffset(dx);
0N/A
0N/A int b = 0;
0N/A
0N/A if(bitOffset == 0) {
0N/A if(dataBuffer instanceof DataBufferByte) {
0N/A byte[] data = ((DataBufferByte)dataBuffer).getData();
0N/A if(data == binaryDataArray) {
0N/A // Optimal case: simply return.
0N/A return;
0N/A }
0N/A int stride = (rectWidth + 7)/8;
0N/A int offset = 0;
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A System.arraycopy(binaryDataArray, offset,
0N/A data, eltOffset,
0N/A stride);
0N/A offset += stride;
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferShort ||
0N/A dataBuffer instanceof DataBufferUShort) {
0N/A short[] data = dataBuffer instanceof DataBufferShort ?
0N/A ((DataBufferShort)dataBuffer).getData() :
0N/A ((DataBufferUShort)dataBuffer).getData();
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int xRemaining = rectWidth;
0N/A int i = eltOffset;
0N/A while(xRemaining > 8) {
0N/A data[i++] =
0N/A (short)(((binaryDataArray[b++] & 0xFF) << 8) |
0N/A (binaryDataArray[b++] & 0xFF));
0N/A xRemaining -= 16;
0N/A }
0N/A if(xRemaining > 0) {
0N/A data[i++] =
0N/A (short)((binaryDataArray[b++] & 0xFF) << 8);
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferInt) {
0N/A int[] data = ((DataBufferInt)dataBuffer).getData();
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int xRemaining = rectWidth;
0N/A int i = eltOffset;
0N/A while(xRemaining > 24) {
0N/A data[i++] =
0N/A (int)(((binaryDataArray[b++] & 0xFF) << 24) |
0N/A ((binaryDataArray[b++] & 0xFF) << 16) |
0N/A ((binaryDataArray[b++] & 0xFF) << 8) |
0N/A (binaryDataArray[b++] & 0xFF));
0N/A xRemaining -= 32;
0N/A }
0N/A int shift = 24;
0N/A while(xRemaining > 0) {
0N/A data[i] |=
0N/A (int)((binaryDataArray[b++] & 0xFF) << shift);
0N/A shift -= 8;
0N/A xRemaining -= 8;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A } else { // bitOffset != 0
0N/A int stride = (rectWidth + 7)/8;
0N/A int offset = 0;
0N/A if(dataBuffer instanceof DataBufferByte) {
0N/A byte[] data = ((DataBufferByte)dataBuffer).getData();
0N/A
0N/A if((bitOffset & 7) == 0) {
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A System.arraycopy(binaryDataArray, offset,
0N/A data, eltOffset,
0N/A stride);
0N/A offset += stride;
0N/A eltOffset += lineStride;
0N/A }
0N/A } else { // bitOffset % 8 != 0
0N/A int rightShift = bitOffset & 7;
0N/A int leftShift = 8 - rightShift;
0N/A int leftShift8 = 8 + leftShift;
0N/A int mask = (byte)(255<<leftShift);
0N/A int mask1 = (byte)~mask;
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int i = eltOffset;
0N/A int xRemaining = rectWidth;
0N/A while(xRemaining > 0) {
0N/A byte datum = binaryDataArray[b++];
0N/A
0N/A if (xRemaining > leftShift8) {
0N/A // when all the bits in this BYTE will be set
0N/A // into the data buffer.
0N/A data[i] = (byte)((data[i] & mask ) |
0N/A ((datum&0xFF) >>> rightShift));
0N/A data[++i] = (byte)((datum & 0xFF) << leftShift);
0N/A } else if (xRemaining > leftShift) {
0N/A // All the "leftShift" high bits will be set
0N/A // into the data buffer. But not all the
0N/A // "rightShift" low bits will be set.
0N/A data[i] = (byte)((data[i] & mask ) |
0N/A ((datum&0xFF) >>> rightShift));
0N/A i++;
0N/A data[i] =
0N/A (byte)((data[i] & mask1) | ((datum & 0xFF) << leftShift));
0N/A }
0N/A else {
0N/A // Less than "leftShift" high bits will be set.
0N/A int remainMask = (1 << leftShift - xRemaining) - 1;
0N/A data[i] =
0N/A (byte)((data[i] & (mask | remainMask)) |
0N/A (datum&0xFF) >>> rightShift & ~remainMask);
0N/A }
0N/A xRemaining -= 8;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferShort ||
0N/A dataBuffer instanceof DataBufferUShort) {
0N/A short[] data = dataBuffer instanceof DataBufferShort ?
0N/A ((DataBufferShort)dataBuffer).getData() :
0N/A ((DataBufferUShort)dataBuffer).getData();
0N/A
0N/A int rightShift = bitOffset & 7;
0N/A int leftShift = 8 - rightShift;
0N/A int leftShift16 = 16 + leftShift;
0N/A int mask = (short)(~(255 << leftShift));
0N/A int mask1 = (short)(65535 << leftShift);
0N/A int mask2 = (short)~mask1;
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = bitOffset;
0N/A int xRemaining = rectWidth;
0N/A for(int x = 0; x < rectWidth;
0N/A x += 8, bOffset += 8, xRemaining -= 8) {
0N/A int i = eltOffset + (bOffset >> 4);
0N/A int mod = bOffset & 15;
0N/A int datum = binaryDataArray[b++] & 0xFF;
0N/A if(mod <= 8) {
0N/A // This BYTE is set into one SHORT
0N/A if (xRemaining < 8) {
0N/A // Mask the bits to be set.
0N/A datum &= 255 << 8 - xRemaining;
0N/A }
0N/A data[i] = (short)((data[i] & mask) | (datum << leftShift));
0N/A } else if (xRemaining > leftShift16) {
0N/A // This BYTE will be set into two SHORTs
0N/A data[i] = (short)((data[i] & mask1) | ((datum >>> rightShift)&0xFFFF));
0N/A data[++i] =
0N/A (short)((datum << leftShift)&0xFFFF);
0N/A } else if (xRemaining > leftShift) {
0N/A // This BYTE will be set into two SHORTs;
0N/A // But not all the low bits will be set into SHORT
0N/A data[i] = (short)((data[i] & mask1) | ((datum >>> rightShift)&0xFFFF));
0N/A i++;
0N/A data[i] =
0N/A (short)((data[i] & mask2) | ((datum << leftShift)&0xFFFF));
0N/A } else {
0N/A // Only some of the high bits will be set into
0N/A // SHORTs
0N/A int remainMask = (1 << leftShift - xRemaining) - 1;
0N/A data[i] = (short)((data[i] & (mask1 | remainMask)) |
0N/A ((datum >>> rightShift)&0xFFFF & ~remainMask));
0N/A }
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferInt) {
0N/A int[] data = ((DataBufferInt)dataBuffer).getData();
0N/A int rightShift = bitOffset & 7;
0N/A int leftShift = 8 - rightShift;
0N/A int leftShift32 = 32 + leftShift;
0N/A int mask = 0xFFFFFFFF << leftShift;
0N/A int mask1 = ~mask;
0N/A
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = bitOffset;
0N/A int xRemaining = rectWidth;
0N/A for(int x = 0; x < rectWidth;
0N/A x += 8, bOffset += 8, xRemaining -= 8) {
0N/A int i = eltOffset + (bOffset >> 5);
0N/A int mod = bOffset & 31;
0N/A int datum = binaryDataArray[b++] & 0xFF;
0N/A if(mod <= 24) {
0N/A // This BYTE is set into one INT
0N/A int shift = 24 - mod;
0N/A if (xRemaining < 8) {
0N/A // Mask the bits to be set.
0N/A datum &= 255 << 8 - xRemaining;
0N/A }
0N/A data[i] = (data[i] & (~(255 << shift))) | (datum << shift);
0N/A } else if (xRemaining > leftShift32) {
0N/A // All the bits of this BYTE will be set into two INTs
0N/A data[i] = (data[i] & mask) | (datum >>> rightShift);
0N/A data[++i] = datum << leftShift;
0N/A } else if (xRemaining > leftShift) {
0N/A // This BYTE will be set into two INTs;
0N/A // But not all the low bits will be set into INT
0N/A data[i] = (data[i] & mask) | (datum >>> rightShift);
0N/A i++;
0N/A data[i] = (data[i] & mask1) | (datum << leftShift);
0N/A } else {
0N/A // Only some of the high bits will be set into INT
0N/A int remainMask = (1 << leftShift - xRemaining) - 1;
0N/A data[i] = (data[i] & (mask | remainMask)) |
0N/A (datum >>> rightShift & ~remainMask);
0N/A }
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Copies data into the packed array of the <code>Raster</code>
0N/A * from an array of unpacked data of the form returned by
0N/A * <code>getUnpackedBinaryData()</code>.
0N/A *
0N/A * <p> If the data are binary, then the target bit will be set if
0N/A * and only if the corresponding byte is non-zero.
0N/A *
0N/A * @throws IllegalArgumentException if <code>isBinary()</code> returns
0N/A * <code>false</code> with the <code>SampleModel</code> of the
0N/A * supplied <code>Raster</code> as argument.
0N/A */
0N/A public static void setUnpackedBinaryData(byte[] bdata,
0N/A WritableRaster raster,
0N/A Rectangle rect) {
0N/A SampleModel sm = raster.getSampleModel();
0N/A if(!isBinary(sm)) {
0N/A throw new IllegalArgumentException(I18N.getString("ImageUtil0"));
0N/A }
0N/A
0N/A int rectX = rect.x;
0N/A int rectY = rect.y;
0N/A int rectWidth = rect.width;
0N/A int rectHeight = rect.height;
0N/A
0N/A DataBuffer dataBuffer = raster.getDataBuffer();
0N/A
0N/A int dx = rectX - raster.getSampleModelTranslateX();
0N/A int dy = rectY - raster.getSampleModelTranslateY();
0N/A
0N/A MultiPixelPackedSampleModel mpp = (MultiPixelPackedSampleModel)sm;
0N/A int lineStride = mpp.getScanlineStride();
0N/A int eltOffset = dataBuffer.getOffset() + mpp.getOffset(dx, dy);
0N/A int bitOffset = mpp.getBitOffset(dx);
0N/A
0N/A int k = 0;
0N/A
0N/A if(dataBuffer instanceof DataBufferByte) {
0N/A byte[] data = ((DataBufferByte)dataBuffer).getData();
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = eltOffset*8 + bitOffset;
0N/A for(int x = 0; x < rectWidth; x++) {
0N/A if(bdata[k++] != (byte)0) {
0N/A data[bOffset/8] |=
0N/A (byte)(0x00000001 << (7 - bOffset & 7));
0N/A }
0N/A bOffset++;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferShort ||
0N/A dataBuffer instanceof DataBufferUShort) {
0N/A short[] data = dataBuffer instanceof DataBufferShort ?
0N/A ((DataBufferShort)dataBuffer).getData() :
0N/A ((DataBufferUShort)dataBuffer).getData();
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = eltOffset*16 + bitOffset;
0N/A for(int x = 0; x < rectWidth; x++) {
0N/A if(bdata[k++] != (byte)0) {
0N/A data[bOffset/16] |=
0N/A (short)(0x00000001 <<
0N/A (15 - bOffset % 16));
0N/A }
0N/A bOffset++;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A } else if(dataBuffer instanceof DataBufferInt) {
0N/A int[] data = ((DataBufferInt)dataBuffer).getData();
0N/A for(int y = 0; y < rectHeight; y++) {
0N/A int bOffset = eltOffset*32 + bitOffset;
0N/A for(int x = 0; x < rectWidth; x++) {
0N/A if(bdata[k++] != (byte)0) {
0N/A data[bOffset/32] |=
0N/A (int)(0x00000001 <<
0N/A (31 - bOffset % 32));
0N/A }
0N/A bOffset++;
0N/A }
0N/A eltOffset += lineStride;
0N/A }
0N/A }
0N/A }
0N/A
0N/A public static boolean isBinary(SampleModel sm) {
0N/A return sm instanceof MultiPixelPackedSampleModel &&
0N/A ((MultiPixelPackedSampleModel)sm).getPixelBitStride() == 1 &&
0N/A sm.getNumBands() == 1;
0N/A }
0N/A
0N/A public static ColorModel createColorModel(ColorSpace colorSpace,
0N/A SampleModel sampleModel) {
0N/A ColorModel colorModel = null;
0N/A
0N/A if(sampleModel == null) {
0N/A throw new IllegalArgumentException(I18N.getString("ImageUtil1"));
0N/A }
0N/A
0N/A int numBands = sampleModel.getNumBands();
0N/A if (numBands < 1 || numBands > 4) {
0N/A return null;
0N/A }
0N/A
0N/A int dataType = sampleModel.getDataType();
0N/A if (sampleModel instanceof ComponentSampleModel) {
0N/A if (dataType < DataBuffer.TYPE_BYTE ||
0N/A //dataType == DataBuffer.TYPE_SHORT ||
0N/A dataType > DataBuffer.TYPE_DOUBLE) {
0N/A return null;
0N/A }
0N/A
0N/A if (colorSpace == null)
0N/A colorSpace =
0N/A numBands <= 2 ?
0N/A ColorSpace.getInstance(ColorSpace.CS_GRAY) :
0N/A ColorSpace.getInstance(ColorSpace.CS_sRGB);
0N/A
0N/A boolean useAlpha = (numBands == 2) || (numBands == 4);
0N/A int transparency = useAlpha ?
0N/A Transparency.TRANSLUCENT : Transparency.OPAQUE;
0N/A
0N/A boolean premultiplied = false;
0N/A
0N/A int dataTypeSize = DataBuffer.getDataTypeSize(dataType);
0N/A int[] bits = new int[numBands];
0N/A for (int i = 0; i < numBands; i++) {
0N/A bits[i] = dataTypeSize;
0N/A }
0N/A
0N/A colorModel = new ComponentColorModel(colorSpace,
0N/A bits,
0N/A useAlpha,
0N/A premultiplied,
0N/A transparency,
0N/A dataType);
0N/A } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
0N/A SinglePixelPackedSampleModel sppsm =
0N/A (SinglePixelPackedSampleModel)sampleModel;
0N/A
0N/A int[] bitMasks = sppsm.getBitMasks();
0N/A int rmask = 0;
0N/A int gmask = 0;
0N/A int bmask = 0;
0N/A int amask = 0;
0N/A
0N/A numBands = bitMasks.length;
0N/A if (numBands <= 2) {
0N/A rmask = gmask = bmask = bitMasks[0];
0N/A if (numBands == 2) {
0N/A amask = bitMasks[1];
0N/A }
0N/A } else {
0N/A rmask = bitMasks[0];
0N/A gmask = bitMasks[1];
0N/A bmask = bitMasks[2];
0N/A if (numBands == 4) {
0N/A amask = bitMasks[3];
0N/A }
0N/A }
0N/A
0N/A int[] sampleSize = sppsm.getSampleSize();
0N/A int bits = 0;
0N/A for (int i = 0; i < sampleSize.length; i++) {
0N/A bits += sampleSize[i];
0N/A }
0N/A
0N/A if (colorSpace == null)
0N/A colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
0N/A
0N/A colorModel =
0N/A new DirectColorModel(colorSpace,
0N/A bits, rmask, gmask, bmask, amask,
0N/A false,
0N/A sampleModel.getDataType());
0N/A } else if (sampleModel instanceof MultiPixelPackedSampleModel) {
0N/A int bits =
0N/A ((MultiPixelPackedSampleModel)sampleModel).getPixelBitStride();
0N/A int size = 1 << bits;
0N/A byte[] comp = new byte[size];
0N/A
0N/A for (int i = 0; i < size; i++)
0N/A comp[i] = (byte)(255 * i / (size - 1));
0N/A
0N/A colorModel = new IndexColorModel(bits, size, comp, comp, comp);
0N/A }
0N/A
0N/A return colorModel;
0N/A }
0N/A
0N/A public static int getElementSize(SampleModel sm) {
0N/A int elementSize = DataBuffer.getDataTypeSize(sm.getDataType());
0N/A
0N/A if (sm instanceof MultiPixelPackedSampleModel) {
0N/A MultiPixelPackedSampleModel mppsm =
0N/A (MultiPixelPackedSampleModel)sm;
0N/A return mppsm.getSampleSize(0) * mppsm.getNumBands();
0N/A } else if (sm instanceof ComponentSampleModel) {
0N/A return sm.getNumBands() * elementSize;
0N/A } else if (sm instanceof SinglePixelPackedSampleModel) {
0N/A return elementSize;
0N/A }
0N/A
0N/A return elementSize * sm.getNumBands();
0N/A
0N/A }
0N/A
0N/A public static long getTileSize(SampleModel sm) {
0N/A int elementSize = DataBuffer.getDataTypeSize(sm.getDataType());
0N/A
0N/A if (sm instanceof MultiPixelPackedSampleModel) {
0N/A MultiPixelPackedSampleModel mppsm =
0N/A (MultiPixelPackedSampleModel)sm;
0N/A return (mppsm.getScanlineStride() * mppsm.getHeight() +
0N/A (mppsm.getDataBitOffset() + elementSize -1) / elementSize) *
0N/A ((elementSize + 7) / 8);
0N/A } else if (sm instanceof ComponentSampleModel) {
0N/A ComponentSampleModel csm = (ComponentSampleModel)sm;
0N/A int[] bandOffsets = csm.getBandOffsets();
0N/A int maxBandOff = bandOffsets[0];
0N/A for (int i=1; i<bandOffsets.length; i++)
0N/A maxBandOff = Math.max(maxBandOff, bandOffsets[i]);
0N/A
0N/A long size = 0;
0N/A int pixelStride = csm.getPixelStride();
0N/A int scanlineStride = csm.getScanlineStride();
0N/A if (maxBandOff >= 0)
0N/A size += maxBandOff + 1;
0N/A if (pixelStride > 0)
0N/A size += pixelStride * (sm.getWidth() - 1);
0N/A if (scanlineStride > 0)
0N/A size += scanlineStride * (sm.getHeight() - 1);
0N/A
0N/A int[] bankIndices = csm.getBankIndices();
0N/A maxBandOff = bankIndices[0];
0N/A for (int i=1; i<bankIndices.length; i++)
0N/A maxBandOff = Math.max(maxBandOff, bankIndices[i]);
0N/A return size * (maxBandOff + 1) * ((elementSize + 7) / 8);
0N/A } else if (sm instanceof SinglePixelPackedSampleModel) {
0N/A SinglePixelPackedSampleModel sppsm =
0N/A (SinglePixelPackedSampleModel)sm;
0N/A long size = sppsm.getScanlineStride() * (sppsm.getHeight() - 1) +
0N/A sppsm.getWidth();
0N/A return size * ((elementSize + 7) / 8);
0N/A }
0N/A
0N/A return 0;
0N/A }
0N/A
0N/A public static long getBandSize(SampleModel sm) {
0N/A int elementSize = DataBuffer.getDataTypeSize(sm.getDataType());
0N/A
0N/A if (sm instanceof ComponentSampleModel) {
0N/A ComponentSampleModel csm = (ComponentSampleModel)sm;
0N/A int pixelStride = csm.getPixelStride();
0N/A int scanlineStride = csm.getScanlineStride();
0N/A long size = Math.min(pixelStride, scanlineStride);
0N/A
0N/A if (pixelStride > 0)
0N/A size += pixelStride * (sm.getWidth() - 1);
0N/A if (scanlineStride > 0)
0N/A size += scanlineStride * (sm.getHeight() - 1);
0N/A return size * ((elementSize + 7) / 8);
0N/A } else
0N/A return getTileSize(sm);
0N/A }
0N/A /**
0N/A * Tests whether the color indices represent a gray-scale image.
0N/A *
0N/A * @param r The red channel color indices.
0N/A * @param g The green channel color indices.
0N/A * @param b The blue channel color indices.
0N/A * @return If all the indices have 256 entries, and are identical mappings,
0N/A * return <code>true</code>; otherwise, return <code>false</code>.
0N/A */
0N/A public static boolean isIndicesForGrayscale(byte[] r, byte[] g, byte[] b) {
0N/A if (r.length != g.length || r.length != b.length)
0N/A return false;
0N/A
0N/A int size = r.length;
0N/A
0N/A if (size != 256)
0N/A return false;
0N/A
0N/A for (int i = 0; i < size; i++) {
0N/A byte temp = (byte) i;
0N/A
0N/A if (r[i] != temp || g[i] != temp || b[i] != temp)
0N/A return false;
0N/A }
0N/A
0N/A return true;
0N/A }
0N/A
0N/A /** Converts the provided object to <code>String</code> */
0N/A public static String convertObjectToString(Object obj) {
0N/A if (obj == null)
0N/A return "";
0N/A
0N/A String s = "";
0N/A if (obj instanceof byte[]) {
0N/A byte[] bArray = (byte[])obj;
0N/A for (int i = 0; i < bArray.length; i++)
0N/A s += bArray[i] + " ";
0N/A return s;
0N/A }
0N/A
0N/A if (obj instanceof int[]) {
0N/A int[] iArray = (int[])obj;
0N/A for (int i = 0; i < iArray.length; i++)
0N/A s += iArray[i] + " " ;
0N/A return s;
0N/A }
0N/A
0N/A if (obj instanceof short[]) {
0N/A short[] sArray = (short[])obj;
0N/A for (int i = 0; i < sArray.length; i++)
0N/A s += sArray[i] + " " ;
0N/A return s;
0N/A }
0N/A
0N/A return obj.toString();
0N/A
0N/A }
0N/A
0N/A /** Checks that the provided <code>ImageWriter</code> can encode
0N/A * the provided <code>ImageTypeSpecifier</code> or not. If not, an
0N/A * <code>IIOException</code> will be thrown.
0N/A * @param writer The provided <code>ImageWriter</code>.
0N/A * @param type The image to be tested.
0N/A * @throws IIOException If the writer cannot encoded the provided image.
0N/A */
0N/A public static final void canEncodeImage(ImageWriter writer,
0N/A ImageTypeSpecifier type)
0N/A throws IIOException {
0N/A ImageWriterSpi spi = writer.getOriginatingProvider();
0N/A
0N/A if(type != null && spi != null && !spi.canEncodeImage(type)) {
0N/A throw new IIOException(I18N.getString("ImageUtil2")+" "+
0N/A writer.getClass().getName());
0N/A }
0N/A }
0N/A
0N/A /** Checks that the provided <code>ImageWriter</code> can encode
0N/A * the provided <code>ColorModel</code> and <code>SampleModel</code>.
0N/A * If not, an <code>IIOException</code> will be thrown.
0N/A * @param writer The provided <code>ImageWriter</code>.
0N/A * @param colorModel The provided <code>ColorModel</code>.
0N/A * @param sampleModel The provided <code>SampleModel</code>.
0N/A * @throws IIOException If the writer cannot encoded the provided image.
0N/A */
0N/A public static final void canEncodeImage(ImageWriter writer,
0N/A ColorModel colorModel,
0N/A SampleModel sampleModel)
0N/A throws IIOException {
0N/A ImageTypeSpecifier type = null;
0N/A if (colorModel != null && sampleModel != null)
0N/A type = new ImageTypeSpecifier(colorModel, sampleModel);
0N/A canEncodeImage(writer, type);
0N/A }
0N/A
0N/A /**
0N/A * Returns whether the image has contiguous data across rows.
0N/A */
0N/A public static final boolean imageIsContiguous(RenderedImage image) {
0N/A SampleModel sm;
0N/A if(image instanceof BufferedImage) {
0N/A WritableRaster ras = ((BufferedImage)image).getRaster();
0N/A sm = ras.getSampleModel();
0N/A } else {
0N/A sm = image.getSampleModel();
0N/A }
0N/A
0N/A if (sm instanceof ComponentSampleModel) {
0N/A // Ensure image rows samples are stored contiguously
0N/A // in a single bank.
0N/A ComponentSampleModel csm = (ComponentSampleModel)sm;
0N/A
0N/A if (csm.getPixelStride() != csm.getNumBands()) {
0N/A return false;
0N/A }
0N/A
0N/A int[] bandOffsets = csm.getBandOffsets();
0N/A for (int i = 0; i < bandOffsets.length; i++) {
0N/A if (bandOffsets[i] != i) {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A int[] bankIndices = csm.getBankIndices();
0N/A for (int i = 0; i < bandOffsets.length; i++) {
0N/A if (bankIndices[i] != 0) {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A return true;
0N/A }
0N/A
0N/A // Otherwise true if and only if it's a bilevel image with
0N/A // a MultiPixelPackedSampleModel, 1 bit per pixel, and 1 bit
0N/A // pixel stride.
0N/A return ImageUtil.isBinary(sm);
0N/A }
0N/A}