# HG changeset patch # User bae # Date 1361431543 -14400 # Node ID b130c8cfecfc552614047b3244d5d94439827fcd # Parent 0dcf8ad3e63dfa4bb929bf2de99b95f18f5ea1c8 8007675: Improve color conversion Reviewed-by: prr, jgodinez --- jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Thu Feb 14 19:51:51 2013 +0400 +++ jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Thu Feb 21 11:25:43 2013 +0400 @@ -99,50 +99,75 @@ class LCMSImageLayout { 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; - } - - public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { + dataArrayLength = data.length; + + verify(); + } + + public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) + throws ImageLayoutException + { this(np, pixelType, pixelSize); dataType = DT_SHORT; dataArray = data; - } - - public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { + dataArrayLength = 2 * data.length; + + verify(); + } + + 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; - } - - public LCMSImageLayout(BufferedImage image) { + dataArrayLength = 8 * data.length; + + verify(); + } + + public LCMSImageLayout(BufferedImage image) throws ImageLayoutException { ShortComponentRaster shortRaster; IntegerComponentRaster intRaster; ByteComponentRaster byteRaster; @@ -186,9 +211,13 @@ class LCMSImageLayout { 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; @@ -196,8 +225,10 @@ class LCMSImageLayout { case BufferedImage.TYPE_4BYTE_ABGR: byteRaster = (ByteComponentRaster)image.getRaster(); nextRowOffset = byteRaster.getScanlineStride(); - offset = byteRaster.getDataOffset(0); + int firstBand = image.getSampleModel().getNumBands() - 1; + offset = byteRaster.getDataOffset(firstBand); dataArray = byteRaster.getDataStorage(); + dataArrayLength = byteRaster.getDataStorage().length; dataType = DT_BYTE; break; @@ -206,17 +237,20 @@ class LCMSImageLayout { 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) { @@ -232,4 +266,45 @@ class LCMSImageLayout { } 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); + } + } } --- jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Fri Oct 26 14:32:40 2012 -0700 +++ jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Mon Mar 04 19:22:10 2013 +0100 @@ -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 { @@ -111,15 +112,26 @@ return profiles[profiles.length - 1].getNumComponents(); } + private synchronized void doTransform(LCMSImageLayout in, + LCMSImageLayout out) { + // update native transfrom if needed + if (ID == 0L) { + ID = LCMS.createNativeTransform(profileIDs, renderType, + disposerReferent); + } + LCMS.colorConvert(this, in, out); + } + public void colorConvert(BufferedImage src, BufferedImage dst) { if (LCMSImageLayout.isSupported(src) && LCMSImageLayout.isSupported(dst)) { - synchronized(this) { - LCMS.colorConvert(this, new LCMSImageLayout(src), - new LCMSImageLayout(dst)); + try { + doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst)); + return; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert images"); } - return; } LCMSImageLayout srcIL, dstIL; Raster srcRas = src.getRaster(); @@ -177,14 +189,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 @@ -204,9 +220,8 @@ } } // color convert srcLine to dstLine - synchronized (this) { - LCMS.colorConvert(this, srcIL, dstIL); - } + doTransform(srcIL, dstIL); + // convert dst scanline pixel = null; idx = 0; @@ -234,16 +249,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 @@ -263,9 +281,8 @@ } } // color convert srcLine to dstLine - synchronized(this) { - LCMS.colorConvert(this, srcIL, dstIL); - } + doTransform(srcIL, dstIL); + // convert dst scanline pixel = null; idx = 0; @@ -353,16 +370,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 @@ -377,9 +397,7 @@ } // color convert srcLine to dstLine - synchronized(this) { - LCMS.colorConvert(this, srcIL, dstIL); - } + doTransform(srcIL, dstIL); // store dst scanline xd = dst.getMinX(); @@ -447,15 +465,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 @@ -470,9 +491,7 @@ } // color convert srcLine to dstLine - synchronized(this) { - LCMS.colorConvert(this, srcIL, dstIL); - } + doTransform(srcIL, dstIL); // store dst scanline xd = dst.getMinX(); @@ -489,16 +508,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); - dstIL = new LCMSImageLayout( - dstLine, dstLine.length/getNumOutComponents(), - LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | - LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*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); + } 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 @@ -513,9 +536,8 @@ } // color convert srcLine to dstLine - synchronized(this) { - LCMS.colorConvert(this, srcIL, dstIL); - } + doTransform(srcIL, dstIL); + // store dst scanline xd = dst.getMinX(); idx = 0; @@ -540,21 +562,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); - synchronized(this) { - LCMS.colorConvert(this, srcIL, dstIL); + doTransform(srcIL, dstIL); + + return dst; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert data"); } - - return dst; } public byte[] colorConvert(byte[] src, byte[] dst) { @@ -562,20 +586,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()); - synchronized(this) { - LCMS.colorConvert(this, srcIL, dstIL); + doTransform(srcIL, dstIL); + + return dst; + } catch (ImageLayoutException e) { + throw new CMMException("Unable to convert data"); } - - return dst; } }