--- old/make/sun/cmm/lcms/Makefile Fri Feb 1 12:51:21 2013 +++ new/make/sun/cmm/lcms/Makefile Fri Feb 1 12:51:20 2013 @@ -28,6 +28,9 @@ LIBRARY = lcms PRODUCT = sun +# Use highest level of optimization on this library +OPTIMIZATION_LEVEL = HIGHEST + include $(BUILDDIR)/common/Defs.gmk # --- old/make/sun/cmm/lcms/mapfile-vers Fri Feb 1 12:51:23 2013 +++ new/make/sun/cmm/lcms/mapfile-vers Fri Feb 1 12:51:22 2013 @@ -27,13 +27,12 @@ SUNWprivate_1.1 { global: - Java_sun_java2d_cmm_lcms_LCMS_loadProfile; - Java_sun_java2d_cmm_lcms_LCMS_freeProfile; + Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative; + Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative; Java_sun_java2d_cmm_lcms_LCMS_getProfileSize; Java_sun_java2d_cmm_lcms_LCMS_getProfileData; - Java_sun_java2d_cmm_lcms_LCMS_getTagSize; - Java_sun_java2d_cmm_lcms_LCMS_getTagData; - Java_sun_java2d_cmm_lcms_LCMS_setTagData; + Java_sun_java2d_cmm_lcms_LCMS_getTagNative; + Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative; Java_sun_java2d_cmm_lcms_LCMS_colorConvert; Java_sun_java2d_cmm_lcms_LCMS_getProfileID; Java_sun_java2d_cmm_lcms_LCMS_initLCMS; --- old/makefiles/CompileNativeLibraries.gmk Fri Feb 1 12:51:26 2013 +++ new/makefiles/CompileNativeLibraries.gmk Fri Feb 1 12:51:25 2013 @@ -1218,7 +1218,7 @@ OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\ SRC:=$(JDK_TOPDIR)/src/share/native/sun/java2d/cmm/lcms,\ LANG:=C,\ - OPTIMIZATION:=LOW, \ + OPTIMIZATION:=HIGHEST, \ CFLAGS:=$(filter-out -xc99=%none,$(CFLAGS_JDKLIB)) \ $(SHARED_LIBRARY_FLAGS) \ -I$(JDK_TOPDIR)/src/share/native/sun/java2d \ --- old/makefiles/mapfiles/liblcms/mapfile-vers Fri Feb 1 12:51:28 2013 +++ new/makefiles/mapfiles/liblcms/mapfile-vers Fri Feb 1 12:51:27 2013 @@ -27,13 +27,12 @@ SUNWprivate_1.1 { global: - Java_sun_java2d_cmm_lcms_LCMS_loadProfile; - Java_sun_java2d_cmm_lcms_LCMS_freeProfile; + Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative; + Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative; Java_sun_java2d_cmm_lcms_LCMS_getProfileSize; Java_sun_java2d_cmm_lcms_LCMS_getProfileData; - Java_sun_java2d_cmm_lcms_LCMS_getTagSize; - Java_sun_java2d_cmm_lcms_LCMS_getTagData; - Java_sun_java2d_cmm_lcms_LCMS_setTagData; + Java_sun_java2d_cmm_lcms_LCMS_getTagNative; + Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative; Java_sun_java2d_cmm_lcms_LCMS_colorConvert; Java_sun_java2d_cmm_lcms_LCMS_getProfileID; Java_sun_java2d_cmm_lcms_LCMS_initLCMS; --- old/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Fri Feb 1 12:51:30 2013 +++ new/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Fri Feb 1 12:51:29 2013 @@ -25,30 +25,92 @@ package sun.java2d.cmm.lcms; -import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; -import java.awt.color.CMMException; +import java.util.Arrays; +import java.util.HashMap; import sun.java2d.cmm.ColorTransform; import sun.java2d.cmm.PCMM; -import sun.java2d.cmm.lcms.LCMS; -import sun.java2d.cmm.lcms.LCMSTransform; public class LCMS implements PCMM { /* methods invoked from ICC_Profile */ - public native long loadProfile(byte[] data); + @Override + public long loadProfile(byte[] data) { + long id = loadProfileNative(data); - public native void freeProfile(long profileID); + if (id != 0L) { + if (profiles == null) { + profiles = new HashMap<>(); + } + profiles.put(id, new TagCache(id)); + } + return id; + } + private native long loadProfileNative(byte[] data); + + @Override + public void freeProfile(long profileID) { + TagCache c = profiles.remove(profileID); + if (c != null) { + c.clear(); + } + if (profiles.isEmpty()) { + profiles = null; + } + freeProfileNative(profileID); + } + + private native void freeProfileNative(long profileID); + public native synchronized int getProfileSize(long profileID); public native synchronized void getProfileData(long profileID, byte[] data); - public native synchronized int getTagSize(long profileID, int tagSignature); - public native synchronized void getTagData(long profileID, int tagSignature, + @Override + public synchronized int getTagSize(long profileID, int tagSignature) { + TagCache cache = profiles.get(profileID); + + if (cache == null) { + cache = new TagCache(profileID); + profiles.put(profileID, cache); + } + + TagData t = cache.getTag(tagSignature); + return t == null ? 0 : t.getSize(); + } + + private static native byte[] getTagNative(long profileID, int signature); + + @Override + public synchronized void getTagData(long profileID, int tagSignature, + byte[] data) + { + TagCache cache = profiles.get(profileID); + + if (cache == null) { + cache = new TagCache(profileID); + profiles.put(profileID, cache); + } + + TagData t = cache.getTag(tagSignature); + if (t != null) { + t.copyDataTo(data); + } + } + + @Override + public synchronized void setTagData(long profileID, int tagSignature, byte[] data) { + TagCache cache = profiles.get(profileID); + + if (cache != null) { + cache.clear(); + } + setTagDataNative(profileID, tagSignature, data); + } + + private native synchronized void setTagDataNative(long profileID, int tagSignature, byte[] data); - public native synchronized void setTagData(long profileID, int tagSignature, - byte[] data); public static native long getProfileID(ICC_Profile profile); @@ -103,4 +165,59 @@ initLCMS(LCMSTransform.class, LCMSImageLayout.class, ICC_Profile.class); } + + private static class TagData { + private int signature; + private byte[] data; + + TagData(int sig, byte[] data) { + this.signature = sig; + this.data = data; + } + + int getSize() { + return data.length; + } + + byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + void copyDataTo(byte[] dst) { + System.arraycopy(data, 0, dst, 0, data.length); + } + + int getSignature() { + return signature; + } + } + + private static class TagCache { + private long profileID; + private HashMap tags; + + TagCache(long id) { + profileID = id; + + tags = new HashMap<>(); + } + + TagData getTag(int sig) { + TagData t = tags.get(sig); + if (t == null) { + byte[] tagData = getTagNative(profileID, sig); + if (tagData != null) { + t = new TagData(sig, tagData); + tags.put(sig, t); + } + } + return t; + } + + void clear() { + tags.clear(); + } + } + + private static HashMap profiles; } --- old/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Fri Feb 1 12:51:32 2013 +++ new/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Fri Feb 1 12:51:32 2013 @@ -22,26 +22,19 @@ * 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) { @@ -49,47 +42,34 @@ } 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); - + CHANNELS_SH(3) | BYTES_SH(1); public static final int PT_GRAY_8 = - CHANNELS_SH(1) | BYTES_SH(1); - + CHANNELS_SH(1) | BYTES_SH(1); public static final int PT_GRAY_16 = - CHANNELS_SH(1) | BYTES_SH(2); - + CHANNELS_SH(1) | BYTES_SH(2); public static final int PT_RGBA_8 = - EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); - + 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; - + EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST; public static final int PT_BGR_8 = - DOSWAP | CHANNELS_SH(3) | BYTES_SH(1); - + 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 DT_BYTE = 0; - public static final int DT_SHORT = 1; - public static final int DT_INT = 2; - public static final int DT_DOUBLE = 3; - - + 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 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; @@ -98,25 +78,30 @@ 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) { + 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; @@ -135,102 +120,218 @@ 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; + } + } + + return createImageLayout(image.getRaster()); + + } + return null; } - width = image.getWidth(); - height = image.getHeight(); + 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(); - int firstBand = image.getSampleModel().getNumBands() - 1; - offset = byteRaster.getDataOffset(firstBand); - dataArray = byteRaster.getDataStorage(); - dataType = DT_BYTE; + do { + ByteComponentRaster byteRaster = (ByteComponentRaster) + image.getRaster(); + l.nextRowOffset = byteRaster.getScanlineStride(); + int firstBand = image.getSampleModel().getNumBands() - 1; + 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; } - return false; } + + 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 null; + } } --- old/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Fri Feb 1 12:51:35 2013 +++ new/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Fri Feb 1 12:51:34 2013 @@ -161,13 +161,18 @@ } public void colorConvert(BufferedImage src, BufferedImage dst) { - if (LCMSImageLayout.isSupported(src) && - LCMSImageLayout.isSupported(dst)) - { - doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst)); - return; - } LCMSImageLayout srcIL, dstIL; + + dstIL = LCMSImageLayout.createImageLayout(dst); + + if (dstIL != null) { + srcIL = LCMSImageLayout.createImageLayout(src); + if (srcIL != null) { + doTransform(srcIL, dstIL); + return; + } + } + Raster srcRas = src.getRaster(); WritableRaster dstRas = dst.getRaster(); ColorModel srcCM = src.getColorModel(); @@ -439,6 +444,14 @@ public void colorConvert(Raster src, WritableRaster dst) { LCMSImageLayout srcIL, dstIL; + dstIL = LCMSImageLayout.createImageLayout(dst); + if (dstIL != null) { + srcIL = LCMSImageLayout.createImageLayout(src); + if (srcIL != null) { + doTransform(srcIL, dstIL); + return; + } + } // Can't pass src and dst directly to CMM, so process per scanline SampleModel srcSM = src.getSampleModel(); SampleModel dstSM = dst.getSampleModel(); --- old/src/share/demo/java2d/J2DBench/build.xml Fri Feb 1 12:51:37 2013 +++ new/src/share/demo/java2d/J2DBench/build.xml Fri Feb 1 12:51:36 2013 @@ -52,7 +52,7 @@ - - + + + + - @@ -95,7 +99,7 @@ - --- old/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java Fri Feb 1 12:51:39 2013 +++ new/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java Fri Feb 1 12:51:38 2013 @@ -51,6 +51,7 @@ DataConversionTests.init(); ColorConvertOpTests.init(); + EmbeddedProfileTests.init(); } protected ColorConversionTests(Group parent, String nodeName, String description) { --- old/src/share/native/sun/java2d/cmm/lcms/LCMS.c Fri Feb 1 12:51:41 2013 +++ new/src/share/native/sun/java2d/cmm/lcms/LCMS.c Fri Feb 1 12:51:40 2013 @@ -117,6 +117,7 @@ static jfieldID IL_nextRowOffset_fID; static jfieldID IL_width_fID; static jfieldID IL_height_fID; +static jfieldID IL_imageAtOnce_fID; static jfieldID PF_ID_fID; JavaVM *javaVM; @@ -237,7 +238,7 @@ * Method: loadProfile * Signature: ([B)J */ -JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile +JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative (JNIEnv *env, jobject obj, jbyteArray data) { jbyte* dataArray; @@ -284,7 +285,7 @@ * Method: freeProfile * Signature: (J)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfile +JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative (JNIEnv *env, jobject obj, jlong id) { storeID_t sProf; @@ -369,48 +370,22 @@ static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size); -/* - * Class: sun_java2d_cmm_lcms_LCMS - * Method: getTagSize - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize - (JNIEnv *env, jobject obj, jlong id, jint tagSig) -{ - storeID_t sProf; - TagSignature_t sig; - jint result = -1; - sProf.j = id; - sig.j = tagSig; - - if (tagSig == SigHead) { - result = sizeof(cmsICCHeader); - } else { - if (cmsIsTag(sProf.pf, sig.cms)) { - result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); - } else { - JNU_ThrowByName(env, "java/awt/color/CMMException", - "ICC profile tag not found"); - } - } - - return result; -} - /* * Class: sun_java2d_cmm_lcms_LCMS * Method: getTagData * Signature: (JI[B)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData - (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) +JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative + (JNIEnv *env, jobject obj, jlong id, jint tagSig) { storeID_t sProf; TagSignature_t sig; cmsInt32Number tagSize; - jbyte* dataArray; + jbyte* dataArray = NULL; + jbyteArray data = NULL; + jint bufSize; sProf.j = id; @@ -419,12 +394,14 @@ if (tagSig == SigHead) { cmsBool status; - bufSize =(*env)->GetArrayLength(env, data); + // allocate java array + bufSize = sizeof(cmsICCHeader); + data = (*env)->NewByteArray(env, bufSize); - if (bufSize < sizeof(cmsICCHeader)) { - JNU_ThrowByName(env, "java/awt/color/CMMException", - "Insufficient buffer capacity"); - return; + if (data == NULL) { + JNU_ThrowByName(env, "java/awt/color/CMMException", + "Unable to allocate buffer"); + return NULL; } dataArray = (*env)->GetByteArrayElements (env, data, 0); @@ -432,7 +409,7 @@ if (dataArray == NULL) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Unable to get buffer"); - return; + return NULL; } status = _getHeaderInfo(sProf.pf, dataArray, bufSize); @@ -442,9 +419,10 @@ if (!status) { JNU_ThrowByName(env, "java/awt/color/CMMException", "ICC Profile header not found"); + return NULL; } - return; + return data; } if (cmsIsTag(sProf.pf, sig.cms)) { @@ -452,16 +430,15 @@ } else { JNU_ThrowByName(env, "java/awt/color/CMMException", "ICC profile tag not found"); - return; + return NULL; } - // verify data buffer capacity - bufSize = (*env)->GetArrayLength(env, data); - - if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) { + // allocate java array + data = (*env)->NewByteArray(env, tagSize); + if (data == NULL) { JNU_ThrowByName(env, "java/awt/color/CMMException", - "Insufficient buffer capacity."); - return; + "Unable to allocate buffer"); + return NULL; } dataArray = (*env)->GetByteArrayElements (env, data, 0); @@ -469,7 +446,7 @@ if (dataArray == NULL) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Unable to get buffer"); - return; + return NULL; } bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize); @@ -479,8 +456,9 @@ if (bufSize != tagSize) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Can not get tag data."); + return NULL; } - return; + return data; } /* @@ -488,7 +466,7 @@ * Method: setTagData * Signature: (JI[B)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData +JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) { storeID_t sProf; @@ -586,6 +564,7 @@ char* inputRow; char* outputRow; jobject srcData, dstData; + jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE; srcOffset = (*env)->GetIntField (env, src, IL_offset_fID); srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID); @@ -594,6 +573,9 @@ width = (*env)->GetIntField (env, src, IL_width_fID); height = (*env)->GetIntField (env, src, IL_height_fID); + srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID); + dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID); + sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID); if (sTrans.xf == NULL) { @@ -625,10 +607,14 @@ inputRow = (char*)inputBuffer + srcOffset; outputRow = (char*)outputBuffer + dstOffset; - for (i = 0; i < height; i++) { - cmsDoTransform(sTrans.xf, inputRow, outputRow, width); - inputRow += srcNextRowOffset; - outputRow += dstNextRowOffset; + if (srcAtOnce && dstAtOnce) { + cmsDoTransform(sTrans.xf, inputRow, outputRow, width * height); + } else { + for (i = 0; i < height; i++) { + cmsDoTransform(sTrans.xf, inputRow, outputRow, width); + inputRow += srcNextRowOffset; + outputRow += dstNextRowOffset; + } } releaseILData(env, inputBuffer, srcDType, srcData); @@ -670,6 +656,7 @@ IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I"); IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I"); IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); + IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z"); IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); --- /dev/null Fri Feb 1 12:51:44 2013 +++ new/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java Fri Feb 1 12:51:43 2013 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +package j2dbench.tests.cmm; + +import j2dbench.Group; +import j2dbench.Option; +import j2dbench.Result; +import j2dbench.TestEnvironment; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +/* This benchmark verifies how changes in cmm library affects image decoding */ +public class EmbeddedProfileTests extends ColorConversionTests { + + protected static Group grpRoot; + protected static Group grpOptionsRoot; + + protected static Option inputImages; + + public static void init() { + grpRoot = new Group(colorConvRoot, "embed", "Embedded Profile Tests"); + + grpOptionsRoot = new Group(grpRoot, "embedOptions", "Options"); + + inputImages = createImageList(); + + new ReadImageTest(); + } + + private static enum IccImageResource { + SMALL("images/img_icc_small.jpg", "512x512", "Small: 512x512"), + MEDIUM("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048"), + LARGE("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096"); + + private IccImageResource(String file, String name, String description) { + this.url = CMMTests.class.getResource(file); + this.abbrev = name; + this.description = description; + } + + public final URL url; + public final String abbrev; + public final String description; + } + + private static Option createImageList() { + IccImageResource[] images = IccImageResource.values(); + + int num = images.length; + + String[] names = new String[num]; + String[] abbrev = new String[num]; + String[] descr = new String[num]; + + for (int i = 0; i < num; i++) { + names[i] = images[i].toString(); + abbrev[i] = images[i].abbrev; + descr[i] = images[i].description; + } + + Option list = new Option.ObjectList(grpOptionsRoot, + "Images", "Input Images", + names, images, abbrev, descr, 1); + + return list; + } + + public EmbeddedProfileTests(Group parent, String nodeName, String description) { + super(parent, nodeName, description); + addDependencies(grpOptionsRoot, true); + } + + private static class Context { + URL input; + + public Context(TestEnvironment env, Result res) { + + IccImageResource icc_input = (IccImageResource) + env.getModifier(inputImages); + + input = icc_input.url; + } + } + + public Object initTest(TestEnvironment env, Result res) { + return new Context(env, res); + } + + public void cleanupTest(TestEnvironment env, Object o) { + Context ctx = (Context)o; + ctx.input = null; + } + + private static class ReadImageTest extends EmbeddedProfileTests { + public ReadImageTest() { + super(grpRoot, "embd_img_read", "ImageReader.read()"); + } + + public void runTest(Object octx, int numReps) { + final Context ctx = (Context)octx; + final URL url = ctx.input; + ImageInputStream iis = null; + ImageReader reader = null; + + try { + iis = ImageIO.createImageInputStream(url.openStream()); + reader = ImageIO.getImageReaders(iis).next(); + } catch (IOException e) { + throw new RuntimeException("Unable to run the becnhmark", e); + } + + do { + try { + reader.setInput(iis); + BufferedImage img = reader.read(0); + reader.reset(); + + iis = ImageIO.createImageInputStream(url.openStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } while (--numReps >= 0); + } + } +} Binary files /tmp/dtCaODV and new/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_large.jpg differ Binary files /tmp/dZ_aGIV and new/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_medium.jpg differ Binary files /tmp/dXIayNV and new/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_small.jpg differ