--- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Mon Mar 16 11:46:26 2009 -0700
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Fri Mar 20 20:05:22 2009 +0300
@@ -30,6 +30,41 @@
#include "Disposer.h"
#include "lcms.h"
+
+#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary
+
+#ifdef USE_BIG_ENDIAN
+#define AdjustEndianess32(a)
+#else
+
+static
+void AdjustEndianess32(LPBYTE pByte)
+{
+ BYTE temp1;
+ BYTE temp2;
+
+ temp1 = *pByte++;
+ temp2 = *pByte++;
+ *(pByte-1) = *pByte;
+ *pByte++ = temp2;
+ *(pByte-3) = *pByte;
+ *pByte = temp1;
+}
+
+#endif
+
+// Transports to properly encoded values - note that icc profiles does use
+// big endian notation.
+
+static
+icInt32Number TransportValue32(icInt32Number Value)
+{
+ icInt32Number Temp = Value;
+
+ AdjustEndianess32((LPBYTE) &Temp);
+ return Temp;
+}
+
#define SigMake(a,b,c,d) \
( ( ((int) ((unsigned char) (a))) << 24) | \
( ((int) ((unsigned char) (b))) << 16) | \
@@ -182,6 +217,8 @@
sProf.pf = cmsOpenProfileFromMem((LPVOID)dataArray, (DWORD) dataSize);
+ (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
if (sProf.pf == NULL) {
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
}
@@ -345,7 +382,23 @@
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData
(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
- fprintf(stderr, "setTagData operation is not implemented");
+ cmsHPROFILE profile;
+ storeID_t sProf;
+ jbyte* dataArray;
+ int tagSize;
+
+ if (tagSig == SigHead) {
+ J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_setTagData on icSigHead not "
+ "permitted");
+ return;
+ }
+
+ sProf.j = id;
+ profile = (cmsHPROFILE) sProf.pf;
+ dataArray = (*env)->GetByteArrayElements(env, data, 0);
+ tagSize =(*env)->GetArrayLength(env, data);
+ _cmsModifyTagData(profile, (icTagSignature) tagSig, dataArray, tagSize);
+ (*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
}
void* getILData (JNIEnv *env, jobject img, jint* pDataType,
@@ -507,3 +560,174 @@
PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
}
+
+BOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig,
+ void *data, size_t size)
+{
+ BOOL isNew;
+ int i, idx, delta, count;
+ LPBYTE padChars[3] = {0, 0, 0};
+ LPBYTE beforeBuf, afterBuf, ptr;
+ size_t beforeSize, afterSize;
+ icUInt32Number profileSize, temp;
+ LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
+
+ isNew = FALSE;
+ idx = _cmsSearchTag(Icc, sig, FALSE);
+ if (idx < 0) {
+ isNew = TRUE;
+ idx = Icc->TagCount++;
+ if (Icc->TagCount >= MAX_TABLE_TAG) {
+ J2dRlsTraceLn1(J2D_TRACE_ERROR, "_cmsModifyTagData: Too many tags "
+ "(%d)\n", Icc->TagCount);
+ Icc->TagCount = MAX_TABLE_TAG-1;
+ return FALSE;
+ }
+ }
+
+ /* Read in size from header */
+ Icc->Seek(Icc, 0);
+ Icc->Read(&profileSize, sizeof(icUInt32Number), 1, Icc);
+ AdjustEndianess32((LPBYTE) &profileSize);
+
+ /* Compute the change in profile size */
+ if (isNew) {
+ delta = sizeof(icTag) + ALIGNLONG(size);
+ } else {
+ delta = ALIGNLONG(size) - ALIGNLONG(Icc->TagSizes[idx]);
+ }
+ /* Add tag to internal structures */
+ ptr = malloc(size);
+ if (ptr == NULL) {
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ J2dRlsTraceLn(J2D_TRACE_ERROR, "_cmsModifyTagData: ptr == NULL");
+ return FALSE;
+ }
+
+ if (!Icc->Grow(Icc, delta)) {
+ free(ptr);
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "_cmsModifyTagData: Icc->Grow() == FALSE");
+ return FALSE;
+ }
+
+ /* Compute size of tag data before/after the modified tag */
+ beforeSize = ((isNew)?profileSize:Icc->TagOffsets[idx]) -
+ Icc->TagOffsets[0];
+ if (Icc->TagCount == (idx + 1)) {
+ afterSize = 0;
+ } else {
+ afterSize = profileSize - Icc->TagOffsets[idx+1];
+ }
+ /* Make copies of the data before/after the modified tag */
+ if (beforeSize > 0) {
+ beforeBuf = malloc(beforeSize);
+ if (!beforeBuf) {
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ free(ptr);
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "_cmsModifyTagData: beforeBuf == NULL");
+ return FALSE;
+ }
+ Icc->Seek(Icc, Icc->TagOffsets[0]);
+ Icc->Read(beforeBuf, beforeSize, 1, Icc);
+ }
+
+ if (afterSize > 0) {
+ afterBuf = malloc(afterSize);
+ if (!afterBuf) {
+ free(ptr);
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ if (beforeSize > 0) {
+ free(beforeBuf);
+ }
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "_cmsModifyTagData: afterBuf == NULL");
+ return FALSE;
+ }
+ Icc->Seek(Icc, Icc->TagOffsets[idx+1]);
+ Icc->Read(afterBuf, afterSize, 1, Icc);
+ }
+
+ CopyMemory(ptr, data, size);
+ Icc->TagSizes[idx] = size;
+ Icc->TagNames[idx] = sig;
+ if (Icc->TagPtrs[idx]) {
+ free(Icc->TagPtrs[idx]);
+ }
+ Icc->TagPtrs[idx] = ptr;
+ if (isNew) {
+ Icc->TagOffsets[idx] = profileSize;
+ }
+
+
+ /* Update the profile size in the header */
+ profileSize += delta;
+ Icc->Seek(Icc, 0);
+ temp = TransportValue32(profileSize);
+ Icc->Write(Icc, sizeof(icUInt32Number), &temp);
+
+
+ /* Adjust tag offsets: if the tag is new, we must account
+ for the new tag table entry; otherwise, only those tags after
+ the modified tag are changed (by delta) */
+ if (isNew) {
+ for (i = 0; i < Icc->TagCount; ++i) {
+ Icc->TagOffsets[i] += sizeof(icTag);
+ }
+ } else {
+ for (i = idx+1; i < Icc->TagCount; ++i) {
+ Icc->TagOffsets[i] += delta;
+ }
+ }
+
+ /* Write out a new tag table */
+ count = 0;
+ for (i = 0; i < Icc->TagCount; ++i) {
+ if (Icc->TagNames[i] != 0) {
+ ++count;
+ }
+ }
+ Icc->Seek(Icc, sizeof(icHeader));
+ temp = TransportValue32(count);
+ Icc->Write(Icc, sizeof(icUInt32Number), &temp);
+
+ for (i = 0; i < Icc->TagCount; ++i) {
+ if (Icc->TagNames[i] != 0) {
+ icTag tag;
+ tag.sig = TransportValue32(Icc->TagNames[i]);
+ tag.offset = TransportValue32((icInt32Number) Icc->TagOffsets[i]);
+ tag.size = TransportValue32((icInt32Number) Icc->TagSizes[i]);
+ Icc->Write(Icc, sizeof(icTag), &tag);
+ }
+ }
+
+ /* Write unchanged data before the modified tag */
+ if (beforeSize > 0) {
+ Icc->Write(Icc, beforeSize, beforeBuf);
+ free(beforeBuf);
+ }
+
+ /* Write modified tag data */
+ Icc->Write(Icc, size, data);
+ if (size % 4) {
+ Icc->Write(Icc, 4 - (size % 4), padChars);
+ }
+
+ /* Write unchanged data after the modified tag */
+ if (afterSize > 0) {
+ Icc->Write(Icc, afterSize, afterBuf);
+ free(afterBuf);
+ }
+
+ return TRUE;
+}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c Mon Mar 16 11:46:26 2009 -0700
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c Fri Mar 20 20:05:22 2009 +0300
@@ -157,8 +157,9 @@
if (size == 0) return TRUE;
if (ResData != NULL)
- CopyMemory(ResData ->Block + Icc ->UsedSpace, Ptr, size);
+ CopyMemory(ResData ->Block + ResData ->Pointer, Ptr, size);
+ ResData->Pointer += size;
Icc->UsedSpace += size;
return TRUE;
@@ -166,6 +167,22 @@
static
+BOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size)
+{
+ FILEMEM* ResData = (FILEMEM*) Icc->stream;
+
+ void* newBlock = realloc(ResData->Block, ResData->Size + size);
+
+ if (!newBlock) {
+ return FALSE;
+ }
+ ResData->Block = newBlock;
+ ResData->Size += size;
+ return TRUE;
+}
+
+
+static
BOOL MemoryClose(struct _lcms_iccprofile_struct* Icc)
{
FILEMEM* ResData = (FILEMEM*) Icc ->stream;
@@ -239,6 +256,13 @@
static
+BOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size)
+{
+ return TRUE;
+}
+
+
+static
BOOL FileClose(struct _lcms_iccprofile_struct* Icc)
{
return fclose((FILE*) Icc ->stream);
@@ -382,6 +406,7 @@
NewIcc ->Seek = FileSeek;
NewIcc ->Tell = FileTell;
NewIcc ->Close = FileClose;
+ NewIcc ->Grow = FileGrow;
NewIcc ->Write = NULL;
NewIcc ->IsWrite = FALSE;
@@ -419,7 +444,8 @@
NewIcc ->Seek = MemorySeek;
NewIcc ->Tell = MemoryTell;
NewIcc ->Close = MemoryClose;
- NewIcc ->Write = NULL;
+ NewIcc ->Grow = MemoryGrow;
+ NewIcc ->Write = MemoryWrite;
NewIcc ->IsWrite = FALSE;
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h Mon Mar 16 11:46:26 2009 -0700
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h Fri Mar 20 20:05:22 2009 +0300
@@ -1838,6 +1838,7 @@
BOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset);
BOOL (* Close)(struct _lcms_iccprofile_struct* Icc);
size_t (* Tell)(struct _lcms_iccprofile_struct* Icc);
+ BOOL (* Grow)(struct _lcms_iccprofile_struct* Icc, size_t amount);
// Writting
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java Fri Mar 20 20:05:22 2009 +0300
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6476665 6523403 6733501
+ * @summary Verifies reading and writing profiles and tags of the standard color
+ * spaces
+ * @run main ReadWriteProfileTest
+ */
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.util.*;
+import java.nio.*;
+import java.util.Hashtable;
+
+public class ReadWriteProfileTest implements Runnable {
+ /* Location of the tag sig counter in 4-byte words */
+ final static int TAG_COUNT_OFFSET = 32;
+
+ /* Location of the tag sig table in 4-byte words */
+ final static int TAG_ELEM_OFFSET = 33;
+
+ static byte[][] profiles;
+ static int [][] tagSigs;
+ static Hashtable<Integer,byte[]> [] tags;
+
+ static int [] cspaces = {ColorSpace.CS_sRGB, ColorSpace.CS_PYCC,
+ ColorSpace.CS_LINEAR_RGB, ColorSpace.CS_CIEXYZ,
+ ColorSpace.CS_GRAY};
+
+ static String [] csNames = {"sRGB", "PYCC", "LINEAR_RGB", "CIEXYZ", "GRAY"};
+
+ static void getProfileTags(byte [] data, Hashtable tags) {
+ ByteBuffer byteBuf = ByteBuffer.wrap(data);
+ IntBuffer intBuf = byteBuf.asIntBuffer();
+ int tagCount = intBuf.get(TAG_COUNT_OFFSET);
+ intBuf.position(TAG_ELEM_OFFSET);
+ for (int i = 0; i < tagCount; i++) {
+ int tagSig = intBuf.get();
+ int tagDataOff = intBuf.get();
+ int tagSize = intBuf.get();
+
+ byte [] tagData = new byte[tagSize];
+ byteBuf.position(tagDataOff);
+ byteBuf.get(tagData);
+ tags.put(tagSig, tagData);
+ }
+ }
+
+ static {
+ profiles = new byte[cspaces.length][];
+ tags = new Hashtable[cspaces.length];
+
+ for (int i = 0; i < cspaces.length; i++) {
+ ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]);
+ profiles[i] = pf.getData();
+ tags[i] = new Hashtable();
+ getProfileTags(profiles[i], tags[i]);
+ }
+ }
+
+ public void run() {
+ for (int i = 0; i < cspaces.length; i++) {
+ ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]);
+ byte [] data = pf.getData();
+ pf = ICC_Profile.getInstance(data);
+ if (!Arrays.equals(data, profiles[i])) {
+ System.err.println("Incorrect result of getData() " + "with " +
+ csNames[i] + " profile");
+ throw new RuntimeException("Incorrect result of getData()");
+ }
+
+ for (int tagSig : tags[i].keySet()) {
+ byte [] tagData = pf.getData(tagSig);
+ byte [] empty = new byte[tagData.length];
+ pf.setData(tagSig, empty);
+ pf.setData(tagSig, tagData);
+
+ byte [] tagData1 = pf.getData(tagSig);
+
+ if (!Arrays.equals(tagData1, tags[i].get(tagSig)))
+ {
+ System.err.println("Incorrect result of getData(int) with" +
+ " tag " +
+ Integer.toHexString(tagSig) +
+ " of " + csNames[i] + " profile");
+
+ throw new RuntimeException("Incorrect result of " +
+ "getData(int)");
+ }
+ }
+ }
+ }
+
+ public static void main(String [] args) {
+ ReadWriteProfileTest test = new ReadWriteProfileTest();
+ test.run();
+ }
+}