src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java

Print this page

        

@@ -23,22 +23,16 @@
  * 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.SampleModel;
 import sun.awt.image.ByteComponentRaster;
 import sun.awt.image.ShortComponentRaster;
 import sun.awt.image.IntegerComponentRaster;
 
 

@@ -96,10 +90,16 @@
     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;

@@ -140,97 +140,163 @@
         this(np, pixelType, pixelSize);
         dataType = DT_DOUBLE;
         dataArray = data;
     }
 
-    public LCMSImageLayout(BufferedImage image) {
+    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();
+
         ShortComponentRaster shortRaster;
         IntegerComponentRaster intRaster;
         ByteComponentRaster byteRaster;
         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;
+                        }
+                    }
+
+                    /* Make sure that band order in the raster
+                     * is the natural color order for image's color space.
+                     */
+                    SampleModel sm = image.getSampleModel();
+                    if (sm instanceof ComponentSampleModel) {
+                        ComponentSampleModel csm = (ComponentSampleModel) sm;
+
+                        if (csm.getTransferType() != DataBuffer.TYPE_BYTE) {
+                            // We may consider to support other data types later.
+                            return null;
+                        }
+                        int[] bandOffsets = csm.getBandOffsets();
+                        for (int i = 0; i < bandOffsets.length; i++) {
+                            /* Now we accept only natural order of color bands,
+                             * but the reversed  order also can be handled with
+                             * SWAP flag in the pixel format descriptor.
+                             */
+                            if (bandOffsets[i] != i) {
+                                return null;
+                            }
+                        }
+                    }
+                    l.pixelType = CHANNELS_SH(cs.length) | BYTES_SH(1);
+                    byteRaster = (ByteComponentRaster) image.getRaster();
+                    l.nextRowOffset = byteRaster.getScanlineStride();
+                    l.offset = byteRaster.getDataOffset(0);
+                    l.dataArray = byteRaster.getDataStorage();
+                    l.dataType = DT_BYTE;
+
+                    l.width = image.getWidth();
+                    l.height = image.getHeight();
+
+                    if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
+                        l.imageAtOnce = true;
         }
 
-        width = image.getWidth();
-        height = image.getHeight();
+                    return l;
+
+                } else {
+                    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;
+                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;
+                }
                 break;
 
             case BufferedImage.TYPE_3BYTE_BGR:
             case BufferedImage.TYPE_4BYTE_ABGR:
-                byteRaster = (ByteComponentRaster)image.getRaster();
-                nextRowOffset = byteRaster.getScanlineStride();
+                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;
+                }
                 break;
 
             case BufferedImage.TYPE_BYTE_GRAY:
                 byteRaster = (ByteComponentRaster)image.getRaster();
-                nextRowOffset = byteRaster.getScanlineStride();
-                offset = byteRaster.getDataOffset(0);
-                dataArray = byteRaster.getDataStorage();
-                dataType = DT_BYTE;
+                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;
+                }
                 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;
-                break;
-        }
-    }
+                l.nextRowOffset = shortRaster.getScanlineStride()*2;
+                l.offset = shortRaster.getDataOffset(0) * 2;
+                l.dataArray = shortRaster.getDataStorage();
+                l.dataType = DT_SHORT;
 
-    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;
+                if (l.nextRowOffset == l.width * 2 *shortRaster.getPixelStride()) {
+                    l.imageAtOnce = true;
+                }
+                break;
+            default:
+                return null;
         }
-        return false;
+        return l;
     }
 }