# HG changeset patch # User bae # Date 1361261188 -14400 # Node ID 0fb15205acb69fca7cfec9891a71dbe159f9a58c # Parent f3368a3fc023cbc1e8cb1e4c36d42cd6319aec09 8007675: Improve color conversion Reviewed-by: prr, mschoene, jgodinez diff -r f3368a3fc023 -r 0fb15205acb6 src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java --- a/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Tue Mar 05 17:18:55 2013 +0400 +++ b/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); + } + } } diff -r f3368a3fc023 -r 0fb15205acb6 src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java --- a/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Tue Mar 05 17:18:55 2013 +0400 +++ b/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"); + } } }