8007675: Improve color conversion
authorbae
Tue, 19 Feb 2013 12:06:28 +0400
changeset 16899 666a37b19844
parent 15973 ea0278a3c432
child 16900 5e0400ee2917
8007675: Improve color conversion Reviewed-by: prr, mschoene, jgodinez
jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java
jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Tue Feb 19 12:06:28 2013 +0400
@@ -99,50 +99,75 @@
     int offset;
 
     Object dataArray;
-    private LCMSImageLayout(int np, int pixelType, int pixelSize) {
+    private int dataArrayLength; /* in bytes */
+
+    private LCMSImageLayout(int np, int pixelType, int pixelSize)
+            throws ImageLayoutException
+    {
         this.pixelType = pixelType;
         width = np;
         height = 1;
-        nextRowOffset = np*pixelSize;
+        nextRowOffset = safeMult(pixelSize, np);
         offset = 0;
     }
 
     private LCMSImageLayout(int width, int height, int pixelType,
-                            int pixelSize) {
+                            int pixelSize)
+            throws ImageLayoutException
+    {
         this.pixelType = pixelType;
         this.width = width;
         this.height = height;
-        nextRowOffset = width*pixelSize;
+        nextRowOffset = safeMult(pixelSize, width);
         offset = 0;
     }
 
 
-    public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
+    public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize)
+            throws ImageLayoutException
+    {
         this(np, pixelType, pixelSize);
         dataType = DT_BYTE;
         dataArray = data;
+        dataArrayLength = data.length;
+
+        verify();
     }
 
-    public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) {
+    public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize)
+            throws ImageLayoutException
+    {
         this(np, pixelType, pixelSize);
         dataType = DT_SHORT;
         dataArray = data;
+        dataArrayLength = 2 * data.length;
+
+        verify();
     }
 
-    public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) {
+    public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize)
+            throws ImageLayoutException
+    {
         this(np, pixelType, pixelSize);
         dataType = DT_INT;
         dataArray = data;
+        dataArrayLength = 4 * data.length;
+
+        verify();
     }
 
     public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
+            throws ImageLayoutException
     {
         this(np, pixelType, pixelSize);
         dataType = DT_DOUBLE;
         dataArray = data;
+        dataArrayLength = 8 * data.length;
+
+        verify();
     }
 
-    public LCMSImageLayout(BufferedImage image) {
+    public LCMSImageLayout(BufferedImage image) throws ImageLayoutException {
         ShortComponentRaster shortRaster;
         IntegerComponentRaster intRaster;
         ByteComponentRaster byteRaster;
@@ -186,9 +211,13 @@
             case BufferedImage.TYPE_INT_ARGB:
             case BufferedImage.TYPE_INT_BGR:
                 intRaster = (IntegerComponentRaster)image.getRaster();
-                nextRowOffset = intRaster.getScanlineStride()*4;
-                offset = intRaster.getDataOffset(0)*4;
+
+                nextRowOffset = safeMult(4, intRaster.getScanlineStride());
+
+                offset = safeMult(4, intRaster.getDataOffset(0));
+
                 dataArray = intRaster.getDataStorage();
+                dataArrayLength = 4 * intRaster.getDataStorage().length;
                 dataType = DT_INT;
                 break;
 
@@ -199,6 +228,7 @@
                 int firstBand = image.getSampleModel().getNumBands() - 1;
                 offset = byteRaster.getDataOffset(firstBand);
                 dataArray = byteRaster.getDataStorage();
+                dataArrayLength = byteRaster.getDataStorage().length;
                 dataType = DT_BYTE;
                 break;
 
@@ -207,17 +237,20 @@
                 nextRowOffset = byteRaster.getScanlineStride();
                 offset = byteRaster.getDataOffset(0);
                 dataArray = byteRaster.getDataStorage();
+                dataArrayLength = byteRaster.getDataStorage().length;
                 dataType = DT_BYTE;
                 break;
 
             case BufferedImage.TYPE_USHORT_GRAY:
                 shortRaster = (ShortComponentRaster)image.getRaster();
-                nextRowOffset = shortRaster.getScanlineStride()*2;
-                offset = shortRaster.getDataOffset(0) * 2;
+                nextRowOffset = safeMult(2, shortRaster.getScanlineStride());
+                offset = safeMult(2, shortRaster.getDataOffset(0));
                 dataArray = shortRaster.getDataStorage();
+                dataArrayLength = 2 * shortRaster.getDataStorage().length;
                 dataType = DT_SHORT;
                 break;
         }
+        verify();
     }
 
     public static boolean isSupported(BufferedImage image) {
@@ -233,4 +266,45 @@
         }
         return false;
     }
+
+    private void verify() throws ImageLayoutException {
+
+        if (offset < 0 || offset >= dataArrayLength) {
+            throw new ImageLayoutException("Invalid image layout");
+        }
+
+        int lastPixelOffset = safeMult(nextRowOffset, (height - 1));
+
+        lastPixelOffset = safeAdd(lastPixelOffset, (width - 1));
+
+        int off = safeAdd(offset, lastPixelOffset);
+
+        if (off < 0 || off >= dataArrayLength) {
+            throw new ImageLayoutException("Invalid image layout");
+        }
+    }
+
+    static int safeAdd(int a, int b) throws ImageLayoutException {
+        long res = a;
+        res += b;
+        if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
+            throw new ImageLayoutException("Invalid image layout");
+        }
+        return (int)res;
+    }
+
+    static int safeMult(int a, int b) throws ImageLayoutException {
+        long res = a;
+        res *= b;
+        if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
+            throw new ImageLayoutException("Invalid image layout");
+        }
+        return (int)res;
+    }
+
+    public static class ImageLayoutException extends Exception {
+        public ImageLayoutException(String message) {
+            super(message);
+        }
+    }
 }
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Tue Feb 19 12:06:28 2013 +0400
@@ -51,6 +51,7 @@
 import java.awt.image.ComponentSampleModel;
 import sun.java2d.cmm.*;
 import sun.java2d.cmm.lcms.*;
+import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException;
 
 
 public class LCMSTransform implements ColorTransform {
@@ -164,8 +165,12 @@
         if (LCMSImageLayout.isSupported(src) &&
             LCMSImageLayout.isSupported(dst))
         {
-            doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
-            return;
+            try {
+                doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
+                return;
+            } catch (ImageLayoutException e) {
+                throw new CMMException("Unable to convert images");
+            }
         }
         LCMSImageLayout srcIL, dstIL;
         Raster srcRas = src.getRaster();
@@ -223,14 +228,18 @@
             }
             int idx;
             // TODO check for src npixels = dst npixels
-            srcIL = new LCMSImageLayout(
-                srcLine, srcLine.length/getNumInComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-                LCMSImageLayout.BYTES_SH(1), getNumInComponents());
-            dstIL = new LCMSImageLayout(
-                dstLine, dstLine.length/getNumOutComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-                LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+            try {
+                srcIL = new LCMSImageLayout(
+                        srcLine, srcLine.length/getNumInComponents(),
+                        LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                        LCMSImageLayout.BYTES_SH(1), getNumInComponents());
+                dstIL = new LCMSImageLayout(
+                        dstLine, dstLine.length/getNumOutComponents(),
+                        LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                        LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+            } catch (ImageLayoutException e) {
+                throw new CMMException("Unable to convert images");
+            }
             // process each scanline
             for (int y = 0; y < h; y++) {
                 // convert src scanline
@@ -279,16 +288,19 @@
                 alpha = new float[w];
             }
             int idx;
-            srcIL = new LCMSImageLayout(
-                srcLine, srcLine.length/getNumInComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-                LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+            try {
+                srcIL = new LCMSImageLayout(
+                    srcLine, srcLine.length/getNumInComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                    LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
 
-            dstIL = new LCMSImageLayout(
-                dstLine, dstLine.length/getNumOutComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-                LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
-
+                dstIL = new LCMSImageLayout(
+                    dstLine, dstLine.length/getNumOutComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                    LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+            } catch (ImageLayoutException e) {
+                throw new CMMException("Unable to convert images");
+            }
             // process each scanline
             for (int y = 0; y < h; y++) {
                 // convert src scanline
@@ -397,16 +409,19 @@
         short[] srcLine = new short[w * srcNumBands];
         short[] dstLine = new short[w * dstNumBands];
         int idx;
-        srcIL = new LCMSImageLayout(
-            srcLine, srcLine.length/getNumInComponents(),
-            LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-            LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+        try {
+            srcIL = new LCMSImageLayout(
+                    srcLine, srcLine.length/getNumInComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                    LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
 
-        dstIL = new LCMSImageLayout(
-            dstLine, dstLine.length/getNumOutComponents(),
-            LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-            LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
-
+            dstIL = new LCMSImageLayout(
+                    dstLine, dstLine.length/getNumOutComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                    LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+        } catch (ImageLayoutException e) {
+            throw new CMMException("Unable to convert rasters");
+        }
         // process each scanline
         for (int y = 0; y < h; y++, ys++, yd++) {
             // get src scanline
@@ -489,15 +504,18 @@
             byte[] dstLine = new byte[w * dstNumBands];
             int idx;
             // TODO check for src npixels = dst npixels
-            srcIL = new LCMSImageLayout(
-                srcLine, srcLine.length/getNumInComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-                LCMSImageLayout.BYTES_SH(1), getNumInComponents());
-            dstIL = new LCMSImageLayout(
-                dstLine, dstLine.length/getNumOutComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-                LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
-
+            try {
+                srcIL = new LCMSImageLayout(
+                        srcLine, srcLine.length/getNumInComponents(),
+                        LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                        LCMSImageLayout.BYTES_SH(1), getNumInComponents());
+                dstIL = new LCMSImageLayout(
+                        dstLine, dstLine.length/getNumOutComponents(),
+                        LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                        LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+            } catch (ImageLayoutException e) {
+                throw new CMMException("Unable to convert rasters");
+            }
             // process each scanline
             for (int y = 0; y < h; y++, ys++, yd++) {
                 // get src scanline
@@ -529,16 +547,20 @@
             short[] srcLine = new short[w * srcNumBands];
             short[] dstLine = new short[w * dstNumBands];
             int idx;
-            srcIL = new LCMSImageLayout(
-                srcLine, srcLine.length/getNumInComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-                LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+
+            try {
+                srcIL = new LCMSImageLayout(
+                        srcLine, srcLine.length/getNumInComponents(),
+                        LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                        LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
 
-            dstIL = new LCMSImageLayout(
-                dstLine, dstLine.length/getNumOutComponents(),
-                LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-                LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
-
+                dstIL = new LCMSImageLayout(
+                        dstLine, dstLine.length/getNumOutComponents(),
+                        LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                        LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+            } catch (ImageLayoutException e) {
+                throw new CMMException("Unable to convert rasters");
+            }
             // process each scanline
             for (int y = 0; y < h; y++, ys++, yd++) {
                 // get src scanline
@@ -579,19 +601,23 @@
             dst = new short [(src.length/getNumInComponents())*getNumOutComponents()];
         }
 
-        LCMSImageLayout srcIL = new LCMSImageLayout(
-            src, src.length/getNumInComponents(),
-            LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-            LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+        try {
+            LCMSImageLayout srcIL = new LCMSImageLayout(
+                    src, src.length/getNumInComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                    LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
 
-        LCMSImageLayout dstIL = new LCMSImageLayout(
-            dst, dst.length/getNumOutComponents(),
-            LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-            LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+            LCMSImageLayout dstIL = new LCMSImageLayout(
+                    dst, dst.length/getNumOutComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                    LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
 
-        doTransform(srcIL, dstIL);
+            doTransform(srcIL, dstIL);
 
-        return dst;
+            return dst;
+        } catch (ImageLayoutException e) {
+            throw new CMMException("Unable to convert data");
+        }
     }
 
     public byte[] colorConvert(byte[] src, byte[] dst) {
@@ -599,18 +625,22 @@
             dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()];
         }
 
-        LCMSImageLayout srcIL = new LCMSImageLayout(
-            src, src.length/getNumInComponents(),
-            LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
-            LCMSImageLayout.BYTES_SH(1), getNumInComponents());
+        try {
+            LCMSImageLayout srcIL = new LCMSImageLayout(
+                    src, src.length/getNumInComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+                    LCMSImageLayout.BYTES_SH(1), getNumInComponents());
 
-        LCMSImageLayout dstIL = new LCMSImageLayout(
-            dst, dst.length/getNumOutComponents(),
-            LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
-            LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+            LCMSImageLayout dstIL = new LCMSImageLayout(
+                    dst, dst.length/getNumOutComponents(),
+                    LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+                    LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
 
-        doTransform(srcIL, dstIL);
+            doTransform(srcIL, dstIL);
 
-        return dst;
+            return dst;
+        } catch (ImageLayoutException e) {
+            throw new CMMException("Unable to convert data");
+        }
     }
 }