src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java
Print this page
@@ -20,105 +20,90 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package sun.java2d.cmm.lcms;
-import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
-import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.DataBufferUShort;
-import java.awt.image.DataBufferInt;
import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
import sun.awt.image.ByteComponentRaster;
import sun.awt.image.ShortComponentRaster;
import sun.awt.image.IntegerComponentRaster;
-
class LCMSImageLayout {
public static int BYTES_SH(int x) {
return x;
}
public static int EXTRA_SH(int x) {
- return x<<7;
+ return x << 7;
}
public static int CHANNELS_SH(int x) {
- return x<<3;
+ return x << 3;
}
-
- public static final int SWAPFIRST = 1<<14;
-
- public static final int DOSWAP = 1<<10;
-
+ public static final int SWAPFIRST = 1 << 14;
+ public static final int DOSWAP = 1 << 10;
public static final int PT_RGB_8 =
CHANNELS_SH(3) | BYTES_SH(1);
-
public static final int PT_GRAY_8 =
CHANNELS_SH(1) | BYTES_SH(1);
-
public static final int PT_GRAY_16 =
CHANNELS_SH(1) | BYTES_SH(2);
-
public static final int PT_RGBA_8 =
EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
-
public static final int PT_ARGB_8 =
EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST;
-
public static final int PT_BGR_8 =
DOSWAP | CHANNELS_SH(3) | BYTES_SH(1);
-
public static final int PT_ABGR_8 =
DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
-
- public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) |
- BYTES_SH(1) | DOSWAP | SWAPFIRST;
-
+ public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3)
+ | BYTES_SH(1) | DOSWAP | SWAPFIRST;
public static final int DT_BYTE = 0;
public static final int DT_SHORT = 1;
public static final int DT_INT = 2;
public static final int DT_DOUBLE = 3;
-
-
boolean isIntPacked = false;
int pixelType;
int dataType;
int width;
int height;
int nextRowOffset;
int offset;
+ /* This flag indicates whether the image can be processed
+ * at once by doTransfrom() native call. Otherwise, the
+ * image is processed scan by scan.
+ */
+ private boolean imageAtOnce = false;
Object dataArray;
+
private LCMSImageLayout(int np, int pixelType, int pixelSize) {
this.pixelType = pixelType;
width = np;
height = 1;
- nextRowOffset = np*pixelSize;
+ nextRowOffset = np * pixelSize;
offset = 0;
}
private LCMSImageLayout(int width, int height, int pixelType,
int pixelSize) {
this.pixelType = pixelType;
this.width = width;
this.height = height;
- nextRowOffset = width*pixelSize;
+ nextRowOffset = width * pixelSize;
offset = 0;
}
-
public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
this(np, pixelType, pixelSize);
dataType = DT_BYTE;
dataArray = data;
}
@@ -133,104 +118,220 @@
this(np, pixelType, pixelSize);
dataType = DT_INT;
dataArray = data;
}
- public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
- {
+ public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) {
this(np, pixelType, pixelSize);
dataType = DT_DOUBLE;
dataArray = data;
}
- public LCMSImageLayout(BufferedImage image) {
- ShortComponentRaster shortRaster;
- IntegerComponentRaster intRaster;
- ByteComponentRaster byteRaster;
+ private LCMSImageLayout() {
+ }
+
+ /* This method creates a layout object for given image.
+ * Returns null if the image is not supported by current implementation.
+ */
+ public static LCMSImageLayout createImageLayout(BufferedImage image) {
+ LCMSImageLayout l = new LCMSImageLayout();
+
switch (image.getType()) {
case BufferedImage.TYPE_INT_RGB:
- pixelType = PT_ARGB_8;
- isIntPacked = true;
+ l.pixelType = PT_ARGB_8;
+ l.isIntPacked = true;
break;
case BufferedImage.TYPE_INT_ARGB:
- pixelType = PT_ARGB_8;
- isIntPacked = true;
+ l.pixelType = PT_ARGB_8;
+ l.isIntPacked = true;
break;
case BufferedImage.TYPE_INT_BGR:
- pixelType = PT_ABGR_8;
- isIntPacked = true;
+ l.pixelType = PT_ABGR_8;
+ l.isIntPacked = true;
break;
case BufferedImage.TYPE_3BYTE_BGR:
- pixelType = PT_BGR_8;
+ l.pixelType = PT_BGR_8;
break;
case BufferedImage.TYPE_4BYTE_ABGR:
- pixelType = PT_ABGR_8;
+ l.pixelType = PT_ABGR_8;
break;
case BufferedImage.TYPE_BYTE_GRAY:
- pixelType = PT_GRAY_8;
+ l.pixelType = PT_GRAY_8;
break;
case BufferedImage.TYPE_USHORT_GRAY:
- pixelType = PT_GRAY_16;
+ l.pixelType = PT_GRAY_16;
break;
default:
- // TODO: Add support for some images having
- // SinglePixelPackedModel and ComponentSampleModel
- throw new IllegalArgumentException(
- "CMMImageLayout - bad image type passed to constructor");
+ /* ColorConvertOp creates component images as
+ * default destination, so this kind of images
+ * has to be supported.
+ */
+ ColorModel cm = image.getColorModel();
+ if (cm instanceof ComponentColorModel) {
+ ComponentColorModel ccm = (ComponentColorModel) cm;
+
+ // verify whether the component size is fine
+ int[] cs = ccm.getComponentSize();
+ for (int s : cs) {
+ if (s != 8) {
+ return null;
+ }
}
- width = image.getWidth();
- height = image.getHeight();
+ return createImageLayout(image.getRaster());
+
+ }
+ return null;
+ }
+
+ l.width = image.getWidth();
+ l.height = image.getHeight();
switch (image.getType()) {
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_BGR:
- intRaster = (IntegerComponentRaster)image.getRaster();
- nextRowOffset = intRaster.getScanlineStride()*4;
- offset = intRaster.getDataOffset(0)*4;
- dataArray = intRaster.getDataStorage();
- dataType = DT_INT;
+ do {
+ IntegerComponentRaster intRaster = (IntegerComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = intRaster.getScanlineStride() * 4;
+ l.offset = intRaster.getDataOffset(0) * 4;
+ l.dataArray = intRaster.getDataStorage();
+ l.dataType = DT_INT;
+
+ if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
case BufferedImage.TYPE_3BYTE_BGR:
case BufferedImage.TYPE_4BYTE_ABGR:
- byteRaster = (ByteComponentRaster)image.getRaster();
- nextRowOffset = byteRaster.getScanlineStride();
+ do {
+ ByteComponentRaster byteRaster = (ByteComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = byteRaster.getScanlineStride();
int firstBand = image.getSampleModel().getNumBands() - 1;
- offset = byteRaster.getDataOffset(firstBand);
- dataArray = byteRaster.getDataStorage();
- dataType = DT_BYTE;
+ l.offset = byteRaster.getDataOffset(firstBand);
+ l.dataArray = byteRaster.getDataStorage();
+ l.dataType = DT_BYTE;
+ if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
case BufferedImage.TYPE_BYTE_GRAY:
- byteRaster = (ByteComponentRaster)image.getRaster();
- nextRowOffset = byteRaster.getScanlineStride();
- offset = byteRaster.getDataOffset(0);
- dataArray = byteRaster.getDataStorage();
- dataType = DT_BYTE;
+ do {
+ ByteComponentRaster byteRaster = (ByteComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = byteRaster.getScanlineStride();
+ l.offset = byteRaster.getDataOffset(0);
+ l.dataArray = byteRaster.getDataStorage();
+ l.dataType = DT_BYTE;
+
+ if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
case BufferedImage.TYPE_USHORT_GRAY:
- shortRaster = (ShortComponentRaster)image.getRaster();
- nextRowOffset = shortRaster.getScanlineStride()*2;
- offset = shortRaster.getDataOffset(0) * 2;
- dataArray = shortRaster.getDataStorage();
- dataType = DT_SHORT;
+ do {
+ ShortComponentRaster shortRaster = (ShortComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = shortRaster.getScanlineStride() * 2;
+ l.offset = shortRaster.getDataOffset(0) * 2;
+ l.dataArray = shortRaster.getDataStorage();
+ l.dataType = DT_SHORT;
+
+ if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
+ default:
+ return null;
}
+ return l;
}
- public static boolean isSupported(BufferedImage image) {
- switch (image.getType()) {
- case BufferedImage.TYPE_INT_RGB:
- case BufferedImage.TYPE_INT_ARGB:
- case BufferedImage.TYPE_INT_BGR:
- case BufferedImage.TYPE_3BYTE_BGR:
- case BufferedImage.TYPE_4BYTE_ABGR:
- case BufferedImage.TYPE_BYTE_GRAY:
- case BufferedImage.TYPE_USHORT_GRAY:
- return true;
+ private static enum BandOrder {
+ DIRECT,
+ INVERTED,
+ ARBITRARY,
+ UNKNOWN;
+
+ public static BandOrder getBandOrder(int[] bandOffsets) {
+ BandOrder order = UNKNOWN;
+
+ int numBands = bandOffsets.length;
+
+ for (int i = 0; (order != ARBITRARY) && (i < bandOffsets.length); i++) {
+ switch (order) {
+ case UNKNOWN:
+ if (bandOffsets[i] == i) {
+ order = DIRECT;
+ } else if (bandOffsets[i] == (numBands - 1 - i)) {
+ order = INVERTED;
+ } else {
+ order = ARBITRARY;
+ }
+ break;
+ case DIRECT:
+ if (bandOffsets[i] != i) {
+ order = ARBITRARY;
+ }
+ break;
+ case INVERTED:
+ if (bandOffsets[i] != (numBands - 1 - i)) {
+ order = ARBITRARY;
+ }
+ break;
+ }
+ }
+ return order;
+ }
+ }
+
+ public static LCMSImageLayout createImageLayout(Raster r) {
+ LCMSImageLayout l = new LCMSImageLayout();
+ if (r instanceof ByteComponentRaster) {
+ ByteComponentRaster br = (ByteComponentRaster)r;
+
+ ComponentSampleModel csm = (ComponentSampleModel)r.getSampleModel();
+
+ l.pixelType = CHANNELS_SH(br.getNumBands()) | BYTES_SH(1);
+
+ int[] bandOffsets = csm.getBandOffsets();
+ BandOrder order = BandOrder.getBandOrder(bandOffsets);
+
+ int firstBand = 0;
+ switch (order) {
+ case INVERTED:
+ l.pixelType |= DOSWAP;
+ firstBand = csm.getNumBands() - 1;
+ break;
+ case DIRECT:
+ // do nothing
+ break;
+ default:
+ // unable to create the image layout;
+ return null;
+ }
+
+ l.nextRowOffset = br.getScanlineStride();
+ l.offset = br.getDataOffset(firstBand);
+ l.dataArray = br.getDataStorage();
+ l.dataType = DT_BYTE;
+
+ l.width = br.getWidth();
+ l.height = br.getHeight();
+
+ if (l.nextRowOffset == l.width * br.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ return l;
}
- return false;
+ return null;
}
}