--- a/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk Thu Sep 16 11:15:07 2010 -0700
@@ -25,7 +25,6 @@
FILES_c = \
cmscam02.c \
- cmscam97.c \
cmscgats.c \
cmscnvrt.c \
cmserr.c \
@@ -35,13 +34,17 @@
cmsio0.c \
cmsio1.c \
cmslut.c \
- cmsmatsh.c \
+ cmsmd5.c \
cmsmtrx.c \
cmsnamed.c \
+ cmsopt.c \
cmspack.c \
cmspcs.c \
+ cmsplugin.c \
cmsps2.c \
cmssamp.c \
+ cmssm.c \
+ cmstypes.c \
cmsvirt.c \
cmswtpnt.c \
cmsxform.c \
--- a/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk Thu Sep 16 11:15:07 2010 -0700
@@ -25,7 +25,6 @@
FILES_c = \
cmscam02.c \
- cmscam97.c \
cmscgats.c \
cmscnvrt.c \
cmserr.c \
@@ -35,13 +34,17 @@
cmsio0.c \
cmsio1.c \
cmslut.c \
- cmsmatsh.c \
+ cmsmd5.c \
cmsmtrx.c \
cmsnamed.c \
+ cmsopt.c \
cmspack.c \
cmspcs.c \
+ cmsplugin.c \
cmsps2.c \
cmssamp.c \
+ cmssm.c \
+ cmstypes.c \
cmsvirt.c \
cmswtpnt.c \
cmsxform.c \
--- a/jdk/make/sun/cmm/lcms/Makefile Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/make/sun/cmm/lcms/Makefile Thu Sep 16 11:15:07 2010 -0700
@@ -80,8 +80,8 @@
vpath %.c $(SHARE_SRC)/native/sun/java2d
ifeq ($(PLATFORM), windows)
-
-OTHER_LDLIBS = user32.lib version.lib $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib
+OTHER_CFLAGS += -DCMS_IS_WINDOWS_ -Dsqrtf=sqrt
+OTHER_LDLIBS = $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib
OTHER_INCLUDES += -I$(SHARE_SRC)/native/sun/java2d \
-I$(SHARE_SRC)/native/sun/awt/debug
--- a/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java Thu Sep 16 11:15:07 2010 -0700
@@ -100,12 +100,12 @@
public long loadProfile(byte[] data) {
System.err.print(cName + ".loadProfile");
long profileID = tcmm.loadProfile(data);
- System.err.println("(ID=" + profileID + ")");
+ System.err.printf("(ID=%x)\n", profileID);
return profileID;
}
public void freeProfile(long profileID) {
- System.err.println(cName + ".freeProfile(ID=" + profileID + ")");
+ System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID);
tcmm.freeProfile(profileID);
}
@@ -123,8 +123,8 @@
}
public int getTagSize(long profileID, int tagSignature) {
- System.err.print(cName + ".getTagSize(ID=" + profileID +
- ", TagSig=" + tagSignature + ")");
+ System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)",
+ profileID, signatureToString(tagSignature));
int size = tcmm.getTagSize(profileID, tagSignature);
System.err.println("=" + size);
return size;
@@ -132,8 +132,8 @@
public void getTagData(long profileID, int tagSignature,
byte[] data) {
- System.err.print(cName + ".getTagData(ID=" + profileID +
- ", TagSig=" + tagSignature + ")");
+ System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)",
+ profileID, signatureToString(tagSignature));
System.err.println(" requested " + data.length + " byte(s)");
tcmm.getTagData(profileID, tagSignature, data);
}
@@ -158,5 +158,13 @@
System.err.println(cName + ".createTransform(ColorTransform[])");
return tcmm.createTransform(transforms);
}
+
+ private static String signatureToString(int sig) {
+ return String.format("%c%c%c%c",
+ (char)(0xff & (sig >> 24)),
+ (char)(0xff & (sig >> 16)),
+ (char)(0xff & (sig >> 8)),
+ (char)(0xff & (sig )));
+ }
}
}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Thu Sep 16 11:15:07 2010 -0700
@@ -53,7 +53,8 @@
public static native long getProfileID(ICC_Profile profile);
public static native long createNativeTransform(
- long[] profileIDs, int renderType, Object disposerRef);
+ long[] profileIDs, int renderType, int inFormatter, int outFormatter,
+ Object disposerRef);
/**
* Constructs ColorTransform object corresponding to an ICC_profile
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Thu Sep 16 11:15:07 2010 -0700
@@ -55,11 +55,17 @@
public class LCMSTransform implements ColorTransform {
long ID;
+ private int inFormatter;
+ private int outFormatter;
+
ICC_Profile[] profiles;
long [] profileIDs;
int renderType;
int transformType;
+ private int numInComponents = -1;
+ private int numOutComponents = -1;
+
private Object disposerReferent = new Object();
/* the class initializer */
@@ -80,6 +86,14 @@
this.renderType = (renderType == ColorTransform.Any)?
ICC_Profile.icPerceptual : renderType;
this.transformType = transformType;
+
+ /* Note that ICC_Profile.getNumComponents() is quite expensive
+ * (it may results in a reading of the profile header).
+ * So, here we cache the number of components of input and
+ * output profiles for further usage.
+ */
+ numInComponents = profiles[0].getNumComponents();
+ numOutComponents = profiles[profiles.length - 1].getNumComponents();
}
public LCMSTransform (ColorTransform[] transforms) {
@@ -99,26 +113,51 @@
j += curTrans.profiles.length;
}
renderType = ((LCMSTransform)transforms[0]).renderType;
- ID = LCMS.createNativeTransform(profileIDs, renderType,
- disposerReferent);
+
+ /* Note that ICC_Profile.getNumComponents() is quite expensive
+ * (it may results in a reading of the profile header).
+ * So, here we cache the number of components of input and
+ * output profiles for further usage.
+ */
+ numInComponents = profiles[0].getNumComponents();
+ numOutComponents = profiles[profiles.length - 1].getNumComponents();
}
public int getNumInComponents() {
- return profiles[0].getNumComponents();
+ return numInComponents;
}
public int getNumOutComponents() {
- return profiles[profiles.length - 1].getNumComponents();
+ return numOutComponents;
+ }
+
+ private synchronized void doTransform(LCMSImageLayout in,
+ LCMSImageLayout out) {
+ // update native transfrom if needed
+ if (ID == 0L ||
+ inFormatter != in.pixelType ||
+ outFormatter != out.pixelType) {
+
+ if (ID != 0L) {
+ // Disposer will destroy forgotten transform
+ disposerReferent = new Object();
+ }
+ inFormatter = in.pixelType;
+ outFormatter = out.pixelType;
+
+ ID = LCMS.createNativeTransform(profileIDs, renderType,
+ inFormatter, outFormatter,
+ 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));
- }
+ doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
return;
}
LCMSImageLayout srcIL, dstIL;
@@ -204,9 +243,8 @@
}
}
// color convert srcLine to dstLine
- synchronized (this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
+
// convert dst scanline
pixel = null;
idx = 0;
@@ -263,9 +301,8 @@
}
}
// color convert srcLine to dstLine
- synchronized(this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
+
// convert dst scanline
pixel = null;
idx = 0;
@@ -377,9 +414,7 @@
}
// color convert srcLine to dstLine
- synchronized(this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
// store dst scanline
xd = dst.getMinX();
@@ -470,9 +505,7 @@
}
// color convert srcLine to dstLine
- synchronized(this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
// store dst scanline
xd = dst.getMinX();
@@ -513,9 +546,8 @@
}
// color convert srcLine to dstLine
- synchronized(this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
+
// store dst scanline
xd = dst.getMinX();
idx = 0;
@@ -550,9 +582,7 @@
LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
- synchronized(this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
return dst;
}
@@ -572,9 +602,7 @@
LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
- synchronized(this) {
- LCMS.colorConvert(this, srcIL, dstIL);
- }
+ doTransform(srcIL, dstIL);
return dst;
}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Thu Sep 16 11:15:07 2010 -0700
@@ -24,11 +24,13 @@
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
#include "sun_java2d_cmm_lcms_LCMS.h"
#include "jni_util.h"
#include "Trace.h"
#include "Disposer.h"
-#include "lcms.h"
+#include "lcms2.h"
#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary
@@ -38,10 +40,10 @@
#else
static
-void AdjustEndianess32(LPBYTE pByte)
+void AdjustEndianess32(cmsUInt8Number *pByte)
{
- BYTE temp1;
- BYTE temp2;
+ cmsUInt8Number temp1;
+ cmsUInt8Number temp2;
temp1 = *pByte++;
temp2 = *pByte++;
@@ -57,11 +59,11 @@
// big endian notation.
static
-icInt32Number TransportValue32(icInt32Number Value)
+cmsInt32Number TransportValue32(cmsInt32Number Value)
{
- icInt32Number Temp = Value;
+ cmsInt32Number Temp = Value;
- AdjustEndianess32((LPBYTE) &Temp);
+ AdjustEndianess32((cmsUInt8Number*) &Temp);
return Temp;
}
@@ -84,7 +86,13 @@
/* Default temp profile list size */
#define DF_ICC_BUF_SIZE 32
-#define ERR_MSG_SIZE 20
+#define ERR_MSG_SIZE 256
+
+#ifdef _MSC_VER
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+#endif
typedef union storeID_s { /* store SProfile stuff in a Java Long */
cmsHPROFILE pf;
@@ -93,6 +101,11 @@
jlong j;
} storeID_t, *storeID_p;
+typedef union {
+ cmsTagSignature cms;
+ jint j;
+} TagSignature_t, *TagSignature_p;
+
static jfieldID Trans_profileIDs_fID;
static jfieldID Trans_renderType_fID;
static jfieldID Trans_ID_fID;
@@ -108,21 +121,26 @@
JavaVM *javaVM;
-int errorHandler(int errorCode, const char *errorText) {
+void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode,
+ const char *errorText) {
JNIEnv *env;
char errMsg[ERR_MSG_SIZE];
- /* We can safely use sprintf here because error message has limited size */
- sprintf(errMsg, "LCMS error %d", errorCode);
+
+ int count = snprintf(errMsg, ERR_MSG_SIZE,
+ "LCMS error %d: %s", errorCode, errorText);
+ if (count < 0 || count >= ERR_MSG_SIZE) {
+ count = ERR_MSG_SIZE - 1;
+ }
+ errMsg[count] = 0;
(*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);
JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg);
- return 1;
}
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
javaVM = jvm;
- cmsSetErrorHandler(errorHandler);
+ cmsSetLogErrorHandler(errorHandler);
return JNI_VERSION_1_6;
}
@@ -141,11 +159,10 @@
*/
JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
(JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType,
- jobject disposerRef)
+ jint inFormatter, jint outFormatter, jobject disposerRef)
{
- LPLCMSICCPROFILE _iccArray[DF_ICC_BUF_SIZE];
- LPLCMSICCPROFILE *iccArray = &_iccArray[0];
- cmsHTRANSFORM transform;
+ cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];
+ cmsHPROFILE *iccArray = &_iccArray[0];
storeID_t sTrans;
int i, j, size;
jlong* ids;
@@ -154,17 +171,19 @@
ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0);
if (DF_ICC_BUF_SIZE < size*2) {
- iccArray = (LPLCMSICCPROFILE*) malloc(
- size*2*sizeof(LPLCMSICCPROFILE));
+ iccArray = (cmsHPROFILE*) malloc(
+ size*2*sizeof(cmsHPROFILE));
if (iccArray == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
- return NULL;
+ return 0L;
}
}
j = 0;
for (i = 0; i < size; i++) {
- LPLCMSICCPROFILE icc;
+ cmsHPROFILE icc;
+ cmsColorSpaceSignature cs;
+
sTrans.j = ids[i];
icc = sTrans.pf;
iccArray[j++] = icc;
@@ -172,16 +191,17 @@
/* Middle non-abstract profiles should be doubled before passing to
* the cmsCreateMultiprofileTransform function
*/
+
+ cs = cmsGetColorSpace(icc);
if (size > 2 && i != 0 && i != size - 1 &&
- icc->ColorSpace != icSigXYZData &&
- icc->ColorSpace != icSigLabData)
+ cs != cmsSigXYZData && cs != cmsSigLabData)
{
iccArray[j++] = icc;
}
}
sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j,
- 0, 0, renderType, 0);
+ inFormatter, outFormatter, renderType, 0);
(*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0);
@@ -190,12 +210,13 @@
"sTrans.xf == NULL");
JNU_ThrowByName(env, "java/awt/color/CMMException",
"Cannot get color transform");
+ } else {
+ Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
}
if (iccArray != &_iccArray[0]) {
free(iccArray);
}
- Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
return sTrans.j;
}
@@ -215,7 +236,8 @@
dataArray = (*env)->GetByteArrayElements (env, data, 0);
dataSize = (*env)->GetArrayLength (env, data);
- sProf.pf = cmsOpenProfileFromMem((LPVOID)dataArray, (DWORD) dataSize);
+ sProf.pf = cmsOpenProfileFromMem((const void *)dataArray,
+ (cmsUInt32Number) dataSize);
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
@@ -254,20 +276,17 @@
JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize
(JNIEnv *env, jobject obj, jlong id)
{
- LPLCMSICCPROFILE Icc;
storeID_t sProf;
- unsigned char pfSize[4];
-
+ cmsUInt32Number pfSize = 0;
sProf.j = id;
- Icc = (LPLCMSICCPROFILE) sProf.pf;
- Icc -> Seek(Icc, 0);
- Icc -> Read(pfSize, 4, 1, Icc);
- /* TODO: It's a correct but non-optimal for BE machines code, so should
- * be special cased for them
- */
- return (pfSize[0]<<24) | (pfSize[1]<<16) | (pfSize[2]<<8) |
- pfSize[3];
+ if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
+ return (jint)pfSize;
+ } else {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Can not access specified profile.");
+ return -1;
+ }
}
/*
@@ -278,29 +297,46 @@
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData
(JNIEnv *env, jobject obj, jlong id, jbyteArray data)
{
- LPLCMSICCPROFILE Icc;
storeID_t sProf;
- unsigned char pfSize[4];
jint size;
jbyte* dataArray;
+ cmsUInt32Number pfSize = 0;
+ cmsBool status;
sProf.j = id;
- Icc = (LPLCMSICCPROFILE) sProf.pf;
- Icc -> Seek(Icc, 0);
- Icc -> Read(pfSize, 4, 1, Icc);
+
+ // determine actual profile size
+ if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Can not access specified profile.");
+ return;
+ }
+
+ // verify java buffer capacity
+ size = (*env)->GetArrayLength(env, data);
+ if (0 >= size || pfSize > (cmsUInt32Number)size) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Insufficient buffer capacity.");
+ return;
+ }
dataArray = (*env)->GetByteArrayElements (env, data, 0);
- Icc->Seek(Icc, 0);
+
+ status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize);
+
+ (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
- /* TODO: It's a correct but non-optimal for BE machines code, so should
- * be special cased for them
- */
- Icc->Read(dataArray, 1,
- (pfSize[0]<<24) | (pfSize[1]<<16) | (pfSize[2]<<8) | pfSize[3],
- Icc);
- (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+ if (!status) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Can not access specified profile.");
+ return;
+ }
}
+/* Get profile header info */
+cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
+cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
+
/*
* Class: sun_java2d_cmm_lcms_LCMS
* Method: getTagSize
@@ -309,24 +345,21 @@
JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize
(JNIEnv *env, jobject obj, jlong id, jint tagSig)
{
- LPLCMSICCPROFILE Icc;
storeID_t sProf;
- int i;
- jint result;
+ TagSignature_t sig;
+ jint result = -1;
sProf.j = id;
- Icc = (LPLCMSICCPROFILE) sProf.pf;
+ sig.j = tagSig;
if (tagSig == SigHead) {
- result = sizeof(icHeader);
+ result = sizeof(cmsICCHeader);
} else {
- i = _cmsSearchTag(Icc, tagSig, FALSE);
- if (i >= 0) {
- result = Icc->TagSizes[i];
+ 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");
- result = -1;
}
}
@@ -341,43 +374,83 @@
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData
(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
- LPLCMSICCPROFILE Icc;
storeID_t sProf;
+ TagSignature_t sig;
+ cmsInt32Number tagSize;
+
jbyte* dataArray;
- int i, tagSize;
+ jint bufSize;
sProf.j = id;
- Icc = (LPLCMSICCPROFILE) sProf.pf;
+ sig.j = tagSig;
if (tagSig == SigHead) {
+ cmsBool status;
+
+ bufSize =(*env)->GetArrayLength(env, data);
+
+ if (bufSize < sizeof(cmsICCHeader)) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Insufficient buffer capacity");
+ return;
+ }
+
dataArray = (*env)->GetByteArrayElements (env, data, 0);
- tagSize =(*env)->GetArrayLength(env, data);
- Icc -> Seek(Icc, 0);
- Icc -> Read(dataArray, sizeof(icHeader), 1, Icc);
+
+ if (dataArray == NULL) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Unable to get buffer");
+ return;
+ }
+
+ status = _getHeaderInfo(sProf.pf, dataArray, bufSize);
+
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
+ if (!status) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "ICC Profile header not found");
+ }
+
return;
}
+ if (cmsIsTag(sProf.pf, sig.cms)) {
+ tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
+ } else {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "ICC profile tag not found");
+ return;
+ }
- i = _cmsSearchTag(Icc, tagSig, FALSE);
- if (i >=0) {
- tagSize = Icc->TagSizes[i];
- dataArray = (*env)->GetByteArrayElements (env, data, 0);
- Icc->Seek(Icc, Icc->TagOffsets[i]);
- Icc->Read(dataArray, 1, tagSize, Icc);
- (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+ // verify data buffer capacity
+ bufSize = (*env)->GetArrayLength(env, data);
+
+ if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Insufficient buffer capacity.");
return;
}
- JNU_ThrowByName(env, "java/awt/color/CMMException",
- "ICC profile tag not found");
+ dataArray = (*env)->GetByteArrayElements (env, data, 0);
+
+ if (dataArray == NULL) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Unable to get buffer");
+ return;
+ }
+
+ bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);
+
+ (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
+ if (bufSize != tagSize) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Can not get tag data.");
+ }
return;
}
-// Modify data for a tag in a profile
-LCMSBOOL LCMSEXPORT _cmsModifyTagData(cmsHPROFILE hProfile,
- icTagSignature sig, void *data, size_t size);
-
/*
* Class: sun_java2d_cmm_lcms_LCMS
* Method: setTagData
@@ -386,23 +459,32 @@
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData
(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
- cmsHPROFILE profile;
storeID_t sProf;
+ TagSignature_t sig;
+ cmsBool status;
jbyte* dataArray;
int tagSize;
+ sProf.j = id;
+ sig.j = tagSig;
+
+
+ tagSize =(*env)->GetArrayLength(env, data);
+
+ dataArray = (*env)->GetByteArrayElements(env, data, 0);
+
if (tagSig == SigHead) {
- J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_setTagData on icSigHead not "
- "permitted");
- return;
+ status = _setHeaderInfo(sProf.pf, dataArray, tagSize);
+ } else {
+ status = cmsWriteRawTag(sProf.pf, sig.cms, dataArray, tagSize);
}
- 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);
+
+ if (!status) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Can not write tag data.");
+ }
}
void* getILData (JNIEnv *env, jobject img, jint* pDataType,
@@ -456,7 +538,7 @@
(JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst)
{
storeID_t sTrans;
- int size, inFmt, outFmt, srcDType, dstDType, outSize, renderType;
+ int inFmt, outFmt, srcDType, dstDType;
int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;
int width, height, i;
void* inputBuffer;
@@ -483,8 +565,6 @@
}
#endif
sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID);
- cmsChangeBuffersFormat(sTrans.xf, inFmt, outFmt);
-
if (sTrans.xf == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
@@ -565,190 +645,54 @@
PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
}
-LCMSBOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig,
- void *data, size_t size)
+cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
{
- LCMSBOOL 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);
+ cmsUInt32Number pfSize = 0;
+ cmsUInt8Number* pfBuffer = NULL;
+ cmsBool status = FALSE;
- /* 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 (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
+ pfSize < sizeof(cmsICCHeader) ||
+ bufferSize < sizeof(cmsICCHeader))
+ {
+ return FALSE;
+ }
- /* We change the size of Icc here only if we know it'll actually
- * grow: if Icc is about to shrink we must wait until we've read
- * the previous data. */
- if (delta > 0) {
- 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);
- }
+ pfBuffer = malloc(pfSize);
+ if (pfBuffer == NULL) {
+ return FALSE;
+ }
- 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);
- }
+ // load raw profile data into the buffer
+ if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {
+ memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));
+ status = TRUE;
+ }
+ free(pfBuffer);
+ return status;
+}
- 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;
- }
-
+cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
+{
+ cmsICCHeader pfHeader = { 0 };
- /* Update the profile size in the header */
- profileSize += delta;
- Icc->Seek(Icc, 0);
- temp = TransportValue32(profileSize);
- Icc->Write(Icc, sizeof(icUInt32Number), &temp);
-
- /* Shrink Icc, if needed. */
- if (delta < 0) {
- if (!Icc->Grow(Icc, delta)) {
- free(ptr);
- if(isNew) {
- Icc->TagCount--;
- }
- J2dRlsTraceLn(J2D_TRACE_ERROR,
- "_cmsModifyTagData: Icc->Grow() == FALSE");
- return FALSE;
- }
- }
+ if (pBuffer == NULL || bufferSize < sizeof(cmsICCHeader)) {
+ return FALSE;
+ }
- /* 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);
+ memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader));
- 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);
- }
- }
+ // now set header fields, which we can access using the lcms2 public API
+ cmsSetHeaderFlags(pf, pfHeader.flags);
+ cmsSetHeaderManufacturer(pf, pfHeader.manufacturer);
+ cmsSetHeaderModel(pf, pfHeader.model);
+ cmsSetHeaderAttributes(pf, pfHeader.attributes);
+ cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID));
+ cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent);
+ cmsSetPCS(pf, pfHeader.pcs);
+ cmsSetColorSpace(pf, pfHeader.colorSpace);
+ cmsSetDeviceClass(pf, pfHeader.deviceClass);
+ cmsSetEncodedICCversion(pf, pfHeader.version);
- /* 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;
+ return TRUE;
}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,69 +49,65 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
-
+#include "lcms2_internal.h"
// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging.
-#include "lcms.h"
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC);
-LCMSAPI void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel);
-LCMSAPI void LCMSEXPORT cmsCIECAM02Forward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut);
-
-
// ---------- Implementation --------------------------------------------
typedef struct {
- double XYZ[3];
- double RGB[3];
- double RGBc[3];
- double RGBp[3];
- double RGBpa[3];
- double a, b, h, e, H, A, J, Q, s, t, C, M;
- double abC[2];
- double abs[2];
- double abM[2];
+ cmsFloat64Number XYZ[3];
+ cmsFloat64Number RGB[3];
+ cmsFloat64Number RGBc[3];
+ cmsFloat64Number RGBp[3];
+ cmsFloat64Number RGBpa[3];
+ cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M;
+ cmsFloat64Number abC[2];
+ cmsFloat64Number abs[2];
+ cmsFloat64Number abM[2];
-} CAM02COLOR, *LPCAM02COLOR;
+} CAM02COLOR;
typedef struct {
CAM02COLOR adoptedWhite;
- double LA, Yb;
- double F, c, Nc;
- int surround;
- double n, Nbb, Ncb, z, FL, D;
+ cmsFloat64Number LA, Yb;
+ cmsFloat64Number F, c, Nc;
+ cmsUInt32Number surround;
+ cmsFloat64Number n, Nbb, Ncb, z, FL, D;
-} cmsCIECAM02, *LPcmsCIECAM02;
+ cmsContext ContextID;
+
+} cmsCIECAM02;
static
-double compute_n(LPcmsCIECAM02 pMod)
+cmsFloat64Number compute_n(cmsCIECAM02* pMod)
{
- return(pMod -> Yb / pMod -> adoptedWhite.XYZ[1]);
+ return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]);
}
static
-double compute_z(LPcmsCIECAM02 pMod)
+cmsFloat64Number compute_z(cmsCIECAM02* pMod)
{
- return(1.48 + pow(pMod -> n, 0.5));
+ return (1.48 + pow(pMod -> n, 0.5));
}
static
-double computeNbb(LPcmsCIECAM02 pMod)
+cmsFloat64Number computeNbb(cmsCIECAM02* pMod)
{
- return(0.725 * pow((1.0 / pMod -> n), 0.2));
+ return (0.725 * pow((1.0 / pMod -> n), 0.2));
}
static
-double computeFL(LPcmsCIECAM02 pMod)
+cmsFloat64Number computeFL(cmsCIECAM02* pMod)
{
- double k, FL;
+ cmsFloat64Number k, FL;
k = 1.0 / ((5.0 * pMod->LA) + 1.0);
FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 *
@@ -121,9 +118,9 @@
}
static
-double computeD(LPcmsCIECAM02 pMod)
+cmsFloat64Number computeD(cmsCIECAM02* pMod)
{
- double D;
+ cmsFloat64Number D;
D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0)));
@@ -142,9 +139,10 @@
}
static
-CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
{
- int i;
+ cmsUInt32Number i;
+
for (i = 0; i < 3; i++) {
clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] *
(pMod->D / pMod -> adoptedWhite.RGB[i])) +
@@ -156,11 +154,9 @@
static
-CAM02COLOR CAT02toHPE (CAM02COLOR clr)
+CAM02COLOR CAT02toHPE(CAM02COLOR clr)
{
-
- double M[9];
-
+ cmsFloat64Number M[9];
M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628));
M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698));
@@ -180,10 +176,10 @@
}
static
-CAM02COLOR NonlinearCompression(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod)
{
- int i;
- double temp;
+ cmsUInt32Number i;
+ cmsFloat64Number temp;
for (i = 0; i < 3; i++) {
if (clr.RGBp[i] < 0) {
@@ -204,9 +200,9 @@
}
static
-CAM02COLOR ComputeCorrelates(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
{
- double a, b, temp, e, t, r2d, d2r;
+ cmsFloat64Number a, b, temp, e, t, r2d, d2r;
a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0);
b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0;
@@ -274,10 +270,10 @@
static
-CAM02COLOR InverseCorrelates(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
{
- double t, e, p1, p2, p3, p4, p5, hr, d2r;
+ cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r;
d2r = 3.141592654 / 180.0;
t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) *
@@ -327,10 +323,10 @@
}
static
-CAM02COLOR InverseNonlinearity(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod)
{
- int i;
- double c1;
+ cmsUInt32Number i;
+ cmsFloat64Number c1;
for (i = 0; i < 3; i++) {
if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1;
@@ -347,7 +343,7 @@
static
CAM02COLOR HPEtoCAT02(CAM02COLOR clr)
{
- double M[9];
+ cmsFloat64Number M[9];
M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950));
M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054));
@@ -362,19 +358,19 @@
clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]);
clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]);
clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]);
- return (clr);
+ return clr;
}
static
-CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
{
- int i;
+ cmsUInt32Number i;
for (i = 0; i < 3; i++) {
clr.RGB[i] = clr.RGBc[i] /
((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D);
}
- return(clr);
+ return clr;
}
@@ -385,23 +381,21 @@
clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098);
clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326);
- return(clr);
+ return clr;
}
-
-
-LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC)
+cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC)
{
- LPcmsCIECAM02 lpMod;
-
+ cmsCIECAM02* lpMod;
- if((lpMod = (LPcmsCIECAM02) _cmsMalloc(sizeof(cmsCIECAM02))) == NULL) {
- return (LCMSHANDLE) NULL;
+ _cmsAssert(pVC != NULL);
+
+ if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) {
+ return NULL;
}
-
- ZeroMemory(lpMod, sizeof(cmsCIECAM02));
+ lpMod ->ContextID = ContextID;
lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X;
lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y;
@@ -414,36 +408,30 @@
switch (lpMod -> surround) {
- case AVG_SURROUND_4:
- lpMod->F = 1.0; // Not included in CAM02
- lpMod->c = 0.69;
- lpMod->Nc = 1.0;
- break;
- case CUTSHEET_SURROUND:
- lpMod->F = 0.8;
- lpMod->c = 0.41;
- lpMod->Nc = 0.8;
- break;
+ case CUTSHEET_SURROUND:
+ lpMod->F = 0.8;
+ lpMod->c = 0.41;
+ lpMod->Nc = 0.8;
+ break;
- case DARK_SURROUND:
- lpMod -> F = 0.8;
- lpMod -> c = 0.525;
- lpMod -> Nc = 0.8;
- break;
-
+ case DARK_SURROUND:
+ lpMod -> F = 0.8;
+ lpMod -> c = 0.525;
+ lpMod -> Nc = 0.8;
+ break;
- case DIM_SURROUND:
- lpMod -> F = 0.9;
- lpMod -> c = 0.59;
- lpMod -> Nc = 0.95;
- break;
+ case DIM_SURROUND:
+ lpMod -> F = 0.9;
+ lpMod -> c = 0.59;
+ lpMod -> Nc = 0.95;
+ break;
- default:
- // Average surround
- lpMod -> F = 1.0;
- lpMod -> c = 0.69;
- lpMod -> Nc = 1.0;
+ default:
+ // Average surround
+ lpMod -> F = 1.0;
+ lpMod -> c = 0.69;
+ lpMod -> Nc = 1.0;
}
lpMod -> n = compute_n(lpMod);
@@ -451,10 +439,8 @@
lpMod -> Nbb = computeNbb(lpMod);
lpMod -> FL = computeFL(lpMod);
- if (lpMod -> D == D_CALCULATE ||
- lpMod -> D == D_CALCULATE_DISCOUNT) {
-
- lpMod -> D = computeD(lpMod);
+ if (lpMod -> D == D_CALCULATE) {
+ lpMod -> D = computeD(lpMod);
}
lpMod -> Ncb = lpMod -> Nbb;
@@ -464,21 +450,26 @@
lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite);
lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod);
- return (LCMSHANDLE) lpMod;
+ return (cmsHANDLE) lpMod;
}
-void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel)
+void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel)
{
- LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel;
- if (lpMod) _cmsFree(lpMod);
+ cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
+
+ if (lpMod) _cmsFree(lpMod ->ContextID, lpMod);
}
-void LCMSEXPORT cmsCIECAM02Forward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut)
+void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut)
{
CAM02COLOR clr;
- LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel;
+ cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
+
+ _cmsAssert(lpMod != NULL);
+ _cmsAssert(pIn != NULL);
+ _cmsAssert(pOut != NULL);
clr.XYZ[0] = pIn ->X;
clr.XYZ[1] = pIn ->Y;
@@ -495,11 +486,14 @@
pOut ->h = clr.h;
}
-void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut)
+void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut)
{
CAM02COLOR clr;
- LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel;
+ cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
+ _cmsAssert(lpMod != NULL);
+ _cmsAssert(pIn != NULL);
+ _cmsAssert(pOut != NULL);
clr.J = pIn -> J;
clr.C = pIn -> C;
@@ -514,6 +508,5 @@
pOut ->X = clr.XYZ[0];
pOut ->Y = clr.XYZ[1];
pOut ->Z = clr.XYZ[2];
-
}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam97.c Wed Jul 05 17:21:58 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,750 +0,0 @@
-/*
- * 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// This file is available under and governed by the GNU General Public
-// License version 2 only, as published by the Free Software Foundation.
-// However, the following notice accompanied the original version of this
-// file:
-//
-//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software
-// is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-
-/*
-typedef struct {
- double J;
- double C;
- double h;
-
- } cmsJCh, FAR* LPcmsJCh;
-
-
-#define AVG_SURROUND_4 0
-#define AVG_SURROUND 1
-#define DIM_SURROUND 2
-#define DARK_SURROUND 3
-#define CUTSHEET_SURROUND 4
-
-
-typedef struct {
-
- cmsCIEXYZ whitePoint;
- double Yb;
- double La;
- int surround;
- double D_value;
-
- } cmsViewingConditions, FAR* LPcmsViewingConditions;
-
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC);
-LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel);
-LCMSAPI void LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut);
-
-*/
-
-// ---------- Implementation --------------------------------------------
-
-// #define USE_CIECAM97s2 1
-
-#ifdef USE_CIECAM97s2
-
-# define NOISE_CONSTANT 3.05
-#else
-# define NOISE_CONSTANT 2.05
-#endif
-
-
-/*
- The model input data are the adapting field luminance in cd/m2
- (normally taken to be 20% of the luminance of white in the adapting field),
- LA , the relative tristimulus values of the stimulus, XYZ, the relative
- tristimulus values of white in the same viewing conditions, Xw Yw Zw ,
- and the relative luminance of the background, Yb . Relative tristimulus
- values should be expressed on a scale from Y = 0 for a perfect black
- to Y = 100 for a perfect reflecting diffuser. Additionally, the
- parameters c, for the impact of surround, Nc , a chromatic induction factor,
- and F, a factor for degree of adaptation, must be selected according to the
- guidelines in table
-
- All CIE tristimulus values are obtained using the CIE 1931
- Standard Colorimetric Observer (2°).
-
-*/
-
-typedef struct {
-
- cmsCIEXYZ WP;
- int surround;
- int calculate_D;
-
- double Yb; // rel. luminance of background
-
- cmsCIEXYZ RefWhite;
-
- double La; // The adapting field luminance in cd/m2
-
- double c; // Impact of surround
- double Nc; // Chromatic induction factor
- double Fll; // Lightness contrast factor (Removed on rev 2)
- double F; // Degree of adaptation
-
-
- double k;
- double Fl;
-
- double Nbb; // The background and chromatic brightness induction factors.
- double Ncb;
- double z; // base exponential nonlinearity
- double n; // background induction factor
- double D;
-
- MAT3 MlamRigg;
- MAT3 MlamRigg_1;
-
- MAT3 Mhunt;
- MAT3 Mhunt_1;
-
- MAT3 Mhunt_x_MlamRigg_1;
- MAT3 MlamRigg_x_Mhunt_1;
-
-
- VEC3 RGB_subw;
- VEC3 RGB_subw_prime;
-
- double p;
-
- VEC3 RGB_subwc;
-
- VEC3 RGB_subaw_prime;
- double A_subw;
- double Q_subw;
-
- } cmsCIECAM97s,FAR *LPcmsCIECAM97s;
-
-
-
-// Free model structure
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel)
-{
- LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
- if (lpMod) _cmsFree(lpMod);
-}
-
-// Partial discounting for adaptation degree computation
-
-static
-double discount(double d, double chan)
-{
- return (d * chan + 1 - d);
-}
-
-
-// This routine does model exponential nonlinearity on the short wavelenght
-// sensitive channel. On CIECAM97s rev 2 this has been reverted to linear.
-
-static
-void FwAdaptationDegree(LPcmsCIECAM97s lpMod, LPVEC3 RGBc, LPVEC3 RGB)
-{
-
-
-#ifdef USE_CIECAM97s2
- RGBc->n[0] = RGB->n[0]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[0]);
- RGBc->n[1] = RGB->n[1]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[1]);
- RGBc->n[2] = RGB->n[2]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[2]);
-#else
-
- RGBc->n[0] = RGB->n[0]* discount(lpMod->D, 1.0/lpMod->RGB_subw.n[0]);
- RGBc->n[1] = RGB->n[1]* discount(lpMod->D, 1.0/lpMod->RGB_subw.n[1]);
-
- RGBc->n[2] = pow(fabs(RGB->n[2]), lpMod ->p) * discount(lpMod->D, (1.0/pow(lpMod->RGB_subw.n[2], lpMod->p)));
-
- // If B happens to be negative, Then Bc is also set to be negative
-
- if (RGB->n[2] < 0)
- RGBc->n[2] = -RGBc->n[2];
-#endif
-}
-
-
-static
-void RvAdaptationDegree(LPcmsCIECAM97s lpMod, LPVEC3 RGBc, LPVEC3 RGB)
-{
-
-
-#ifdef USE_CIECAM97s2
- RGBc->n[0] = RGB->n[0]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[0]);
- RGBc->n[1] = RGB->n[1]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[1]);
- RGBc->n[2] = RGB->n[2]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[2]);
-#else
-
- RGBc->n[0] = RGB->n[0]/discount(lpMod->D, 1.0/lpMod->RGB_subw.n[0]);
- RGBc->n[1] = RGB->n[1]/discount(lpMod->D, 1.0/lpMod->RGB_subw.n[1]);
- RGBc->n[2] = pow(fabs(RGB->n[2]), 1.0/lpMod->p)/pow(discount(lpMod->D, 1.0/pow(lpMod->RGB_subw.n[2], lpMod->p)), 1.0/lpMod->p);
- if (RGB->n[2] < 0)
- RGBc->n[2] = -RGBc->n[2];
-#endif
-}
-
-
-
-static
-void PostAdaptationConeResponses(LPcmsCIECAM97s lpMod, LPVEC3 RGBa_prime, LPVEC3 RGBprime)
-{
- if (RGBprime->n[0]>=0.0) {
-
- RGBa_prime->n[0]=((40.0*pow(lpMod -> Fl * RGBprime->n[0]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[0]/100.0, 0.73)+2))+1;
- }
- else
- {
- RGBa_prime->n[0]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[0])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[0])/100.0, 0.73)+2))+1;
- }
-
- if (RGBprime->n[1]>=0.0)
- {
- RGBa_prime->n[1]=((40.0*pow(lpMod -> Fl * RGBprime->n[1]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[1]/100.0, 0.73)+2))+1;
- }
- else
- {
- RGBa_prime->n[1]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[1])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[1])/100.0, 0.73)+2))+1;
- }
-
- if (RGBprime->n[2]>=0.0)
- {
- RGBa_prime->n[2]=((40.0*pow(lpMod -> Fl * RGBprime->n[2]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[2]/100.0, 0.73)+2))+1;
- }
- else
- {
- RGBa_prime->n[2]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[2])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[2])/100.0, 0.73)+2))+1;
- }
-}
-
-
-// Compute hue quadrature, eccentricity factor, e
-
-static
-void ComputeHueQuadrature(double h, double* H, double* e)
-{
-
-
-#define IRED 0
-#define IYELLOW 1
-#define IGREEN 2
-#define IBLUE 3
-
- double e_tab[] = {0.8, 0.7, 1.0, 1.2};
- double H_tab[] = { 0, 100, 200, 300};
- int p1, p2;
- double e1, e2, h1, h2;
-
-
- if (h >= 20.14 && h < 90.0) { // Red
-
- p1 = IRED;
- p2 = IYELLOW;
- }
- else
- if (h >= 90.0 && h < 164.25) { // Yellow
-
- p1 = IYELLOW;
- p2 = IGREEN;
- }
- else
- if (h >= 164.25 && h < 237.53) { // Green
-
- p1 = IGREEN;
- p2 = IBLUE; }
- else { // Blue
-
- p1 = IBLUE;
- p2 = IRED;
- }
-
- e1 = e_tab[p1]; e2 = e_tab[p2];
- h1 = H_tab[p1]; h2 = H_tab[p2];
-
-
-
- *e = e1 + ((e2-e1)*(h-h1)/(h2 - h1));
- *H = h1 + (100. * (h - h1) / e1) / ((h - h1)/e1 + (h2 - h) / e2);
-
-#undef IRED
-#undef IYELLOW
-#undef IGREEN
-#undef IBLUE
-
-}
-
-
-
-
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC)
-{
- LPcmsCIECAM97s lpMod;
- VEC3 tmp;
-
- if((lpMod = (LPcmsCIECAM97s) _cmsMalloc(sizeof(cmsCIECAM97s))) == NULL) {
- return (LCMSHANDLE) NULL;
- }
-
-
- lpMod->WP.X = pVC->whitePoint.X;
- lpMod->WP.Y = pVC->whitePoint.Y;
- lpMod->WP.Z = pVC->whitePoint.Z;
-
- lpMod->Yb = pVC->Yb;
- lpMod->La = pVC->La;
-
- lpMod->surround = pVC->surround;
-
- lpMod->RefWhite.X = 100.0;
- lpMod->RefWhite.Y = 100.0;
- lpMod->RefWhite.Z = 100.0;
-
-#ifdef USE_CIECAM97s2
-
- VEC3init(&lpMod->MlamRigg.v[0], 0.8562, 0.3372, -0.1934);
- VEC3init(&lpMod->MlamRigg.v[1], -0.8360, 1.8327, 0.0033);
- VEC3init(&lpMod->MlamRigg.v[2], 0.0357,-0.0469, 1.0112);
-
- VEC3init(&lpMod->MlamRigg_1.v[0], 0.9874, -0.1768, 0.1894);
- VEC3init(&lpMod->MlamRigg_1.v[1], 0.4504, 0.4649, 0.0846);
- VEC3init(&lpMod->MlamRigg_1.v[2],-0.0139, 0.0278, 0.9861);
-
-#else
- // Bradford transform: Lam-Rigg cone responses
- VEC3init(&lpMod->MlamRigg.v[0], 0.8951, 0.2664, -0.1614);
- VEC3init(&lpMod->MlamRigg.v[1], -0.7502, 1.7135, 0.0367);
- VEC3init(&lpMod->MlamRigg.v[2], 0.0389, -0.0685, 1.0296);
-
-
- // Inverse of Lam-Rigg
- VEC3init(&lpMod->MlamRigg_1.v[0], 0.98699, -0.14705, 0.15996);
- VEC3init(&lpMod->MlamRigg_1.v[1], 0.43231, 0.51836, 0.04929);
- VEC3init(&lpMod->MlamRigg_1.v[2], -0.00853, 0.04004, 0.96849);
-
-#endif
-
- // Hunt-Pointer-Estevez cone responses
- VEC3init(&lpMod->Mhunt.v[0], 0.38971, 0.68898, -0.07868);
- VEC3init(&lpMod->Mhunt.v[1], -0.22981, 1.18340, 0.04641);
- VEC3init(&lpMod->Mhunt.v[2], 0.0, 0.0, 1.0);
-
- // Inverse of Hunt-Pointer-Estevez
- VEC3init(&lpMod->Mhunt_1.v[0], 1.91019, -1.11214, 0.20195);
- VEC3init(&lpMod->Mhunt_1.v[1], 0.37095, 0.62905, 0.0);
- VEC3init(&lpMod->Mhunt_1.v[2], 0.0, 0.0, 1.0);
-
-
- if (pVC->D_value == -1.0)
- lpMod->calculate_D = 1;
- else
- if (pVC->D_value == -2.0)
- lpMod->calculate_D = 2;
- else {
- lpMod->calculate_D = 0;
- lpMod->D = pVC->D_value;
- }
-
- // Table I (revised)
-
- switch (lpMod->surround) {
-
- case AVG_SURROUND_4:
- lpMod->F = 1.0;
- lpMod->c = 0.69;
- lpMod->Fll = 0.0; // Not included on Rev 2
- lpMod->Nc = 1.0;
- break;
- case AVG_SURROUND:
- lpMod->F = 1.0;
- lpMod->c = 0.69;
- lpMod->Fll = 1.0;
- lpMod->Nc = 1.0;
- break;
- case DIM_SURROUND:
- lpMod->F = 0.99;
- lpMod->c = 0.59;
- lpMod->Fll = 1.0;
- lpMod->Nc = 0.95;
- break;
- case DARK_SURROUND:
- lpMod->F = 0.9;
- lpMod->c = 0.525;
- lpMod->Fll = 1.0;
- lpMod->Nc = 0.8;
- break;
- case CUTSHEET_SURROUND:
- lpMod->F = 0.9;
- lpMod->c = 0.41;
- lpMod->Fll = 1.0;
- lpMod->Nc = 0.8;
- break;
- default:
- lpMod->F = 1.0;
- lpMod->c = 0.69;
- lpMod->Fll = 1.0;
- lpMod->Nc = 1.0;
- break;
- }
-
- lpMod->k = 1 / (5 * lpMod->La + 1);
- lpMod->Fl = lpMod->La * pow(lpMod->k, 4) + 0.1*pow(1 - pow(lpMod->k, 4), 2.0) * pow(5*lpMod->La, 1.0/3.0);
-
- if (lpMod->calculate_D > 0) {
-
- lpMod->D = lpMod->F * (1 - 1 / (1 + 2*pow(lpMod->La, 0.25) + pow(lpMod->La, 2)/300.0));
- if (lpMod->calculate_D > 1)
- lpMod->D = (lpMod->D + 1.0) / 2;
- }
-
-
- // RGB_subw = [MlamRigg][WP/YWp]
-#ifdef USE_CIECAM97s2
- MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &lpMod -> WP);
-#else
- VEC3divK(&tmp, (LPVEC3) &lpMod -> WP, lpMod->WP.Y);
- MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &tmp);
-#endif
-
-
-
- MAT3per(&lpMod -> Mhunt_x_MlamRigg_1, &lpMod -> Mhunt, &lpMod->MlamRigg_1 );
- MAT3per(&lpMod -> MlamRigg_x_Mhunt_1, &lpMod -> MlamRigg, &lpMod -> Mhunt_1 );
-
- // p is used on forward model
- lpMod->p = pow(lpMod->RGB_subw.n[2], 0.0834);
-
- FwAdaptationDegree(lpMod, &lpMod->RGB_subwc, &lpMod->RGB_subw);
-
-#if USE_CIECAM97s2
- MAT3eval(&lpMod->RGB_subw_prime, &lpMod->Mhunt_x_MlamRigg_1, &lpMod -> RGB_subwc);
-#else
- VEC3perK(&tmp, &lpMod -> RGB_subwc, lpMod->WP.Y);
- MAT3eval(&lpMod->RGB_subw_prime, &lpMod->Mhunt_x_MlamRigg_1, &tmp);
-#endif
-
- lpMod->n = lpMod-> Yb / lpMod-> WP.Y;
-
- lpMod->z = 1 + lpMod->Fll * sqrt(lpMod->n);
- lpMod->Nbb = lpMod->Ncb = 0.725 / pow(lpMod->n, 0.2);
-
- PostAdaptationConeResponses(lpMod, &lpMod->RGB_subaw_prime, &lpMod->RGB_subw_prime);
-
- lpMod->A_subw=lpMod->Nbb*(2.0*lpMod->RGB_subaw_prime.n[0]+lpMod->RGB_subaw_prime.n[1]+lpMod->RGB_subaw_prime.n[2]/20.0-NOISE_CONSTANT);
-
- return (LCMSHANDLE) lpMod;
-}
-
-
-
-
-//
-// The forward model: XYZ -> JCh
-//
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ inPtr, LPcmsJCh outPtr)
-{
-
- LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
- double a, b, h, s, H1val, es, A;
- VEC3 In, RGB, RGBc, RGBprime, RGBa_prime;
-
- if (inPtr -> Y <= 0.0) {
-
- outPtr -> J = outPtr -> C = outPtr -> h = 0.0;
- return;
- }
-
- // An initial chromatic adaptation transform is used to go from the source
- // viewing conditions to corresponding colours under the equal-energy-illuminant
- // reference viewing conditions. This is handled differently on rev 2
-
- VEC3init(&In, inPtr -> X, inPtr -> Y, inPtr -> Z); // 2.1
-
-#ifdef USE_CIECAM97s2
- // Since the chromatic adaptation transform has been linearized, it
- // is no longer required to divide the stimulus tristimulus values
- // by their own Y tristimulus value prior to the chromatic adaptation.
-#else
- VEC3divK(&In, &In, inPtr -> Y);
-#endif
-
- MAT3eval(&RGB, &lpMod -> MlamRigg, &In); // 2.2
-
- FwAdaptationDegree(lpMod, &RGBc, &RGB);
-
- // The post-adaptation signals for both the sample and the white are then
- // transformed from the sharpened cone responses to the Hunt-Pointer-Estevez
- // cone responses.
-#ifdef USE_CIECAM97s2
-#else
- VEC3perK(&RGBc, &RGBc, inPtr->Y);
-#endif
-
- MAT3eval(&RGBprime, &lpMod->Mhunt_x_MlamRigg_1, &RGBc);
-
- // The post-adaptation cone responses (for both the stimulus and the white)
- // are then calculated.
-
- PostAdaptationConeResponses(lpMod, &RGBa_prime, &RGBprime);
-
- // Preliminary red-green and yellow-blue opponent dimensions are calculated
-
- a = RGBa_prime.n[0] - (12.0 * RGBa_prime.n[1] / 11.0) + RGBa_prime.n[2]/11.0;
- b = (RGBa_prime.n[0] + RGBa_prime.n[1] - 2.0 * RGBa_prime.n[2]) / 9.0;
-
-
- // The CIECAM97s hue angle, h, is then calculated
- h = (180.0/M_PI)*(atan2(b, a));
-
-
- while (h < 0)
- h += 360.0;
-
- outPtr->h = h;
-
- // hue quadrature and eccentricity factors, e, are calculated
-
- ComputeHueQuadrature(h, &H1val, &es);
-
- // ComputeHueQuadrature(h, &H1val, &h1, &e1, &h2, &e2, &es);
-
-
- // The achromatic response A
- A = lpMod->Nbb * (2.0 * RGBa_prime.n[0] + RGBa_prime.n[1] + RGBa_prime.n[2]/20.0 - NOISE_CONSTANT);
-
- // CIECAM97s Lightness J
- outPtr -> J = 100.0 * pow(A / lpMod->A_subw, lpMod->c * lpMod->z);
-
- // CIECAM97s saturation s
- s = (50 * hypot (a, b) * 100 * es * (10.0/13.0) * lpMod-> Nc * lpMod->Ncb) / (RGBa_prime.n[0] + RGBa_prime.n[1] + 1.05 * RGBa_prime.n[2]);
-
- // CIECAM97s Chroma C
-
-#ifdef USE_CIECAM97s2
- // Eq. 26 has been modified to allow accurate prediction of the Munsell chroma scales.
- outPtr->C = 0.7487 * pow(s, 0.973) * pow(outPtr->J/100.0, 0.945 * lpMod->n) * (1.64 - pow(0.29, lpMod->n));
-
-#else
- outPtr->C = 2.44 * pow(s, 0.69) * pow(outPtr->J/100.0, 0.67 * lpMod->n) * (1.64 - pow(0.29, lpMod->n));
-#endif
-}
-
-
-//
-// The reverse model JCh -> XYZ
-//
-
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh inPtr, LPcmsCIEXYZ outPtr)
-{
- LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
- double J, C, h, A, H1val, es, s, a, b;
- double tan_h, sec_h;
- double R_suba_prime, G_suba_prime, B_suba_prime;
- double R_prime, G_prime, B_prime;
- double Y_subc, Y_prime, B_term;
- VEC3 tmp;
- VEC3 RGB_prime, RGB_subc_Y;
- VEC3 Y_over_Y_subc_RGB;
- VEC3 XYZ_primeprime_over_Y_subc;
-#ifdef USE_CIECAM92s2
- VEC3 RGBY;
- VEC3 Out;
-#endif
-
- J = inPtr->J;
- h = inPtr->h;
- C = inPtr->C;
-
- if (J <= 0) {
-
- outPtr->X = 0.0;
- outPtr->Y = 0.0;
- outPtr->Z = 0.0;
- return;
- }
-
-
-
- // (2) From J Obtain A
-
- A = pow(J/100.0, 1/(lpMod->c * lpMod->z)) * lpMod->A_subw;
-
-
- // (3), (4), (5) Using H Determine h1, h2, e1, e2
- // e1 and h1 are the values of e and h for the unique hue having the
- // nearest lower valur of h and e2 and h2 are the values of e and h for
- // the unique hue having the nearest higher value of h.
-
-
- ComputeHueQuadrature(h, &H1val, &es);
-
- // (7) Calculate s
-
- s = pow(C / (2.44 * pow(J/100.0, 0.67*lpMod->n) * (1.64 - pow(0.29, lpMod->n))) , (1./0.69));
-
-
- // (8) Calculate a and b.
- // NOTE: sqrt(1 + tan^2) == sec(h)
-
- tan_h = tan ((M_PI/180.)*(h));
- sec_h = sqrt(1 + tan_h * tan_h);
-
- if ((h > 90) && (h < 270))
- sec_h = -sec_h;
-
- a = s * ( A/lpMod->Nbb + NOISE_CONSTANT) / ( sec_h * 50000.0 * es * lpMod->Nc * lpMod->Ncb/ 13.0 +
- s * (11.0 / 23.0 + (108.0/23.0) * tan_h));
-
- b = a * tan_h;
-
- //(9) Calculate R'a G'a and B'a
-
- R_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) + (41.0/61.0) * (11.0/23.0) * a + (288.0/61.0) / 23.0 * b;
- G_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) - (81.0/61.0) * (11.0/23.0) * a - (261.0/61.0) / 23.0 * b;
- B_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) - (20.0/61.0) * (11.0/23.0) * a - (20.0/61.0) * (315.0/23.0) * b;
-
- // (10) Calculate R', G' and B'
-
- if ((R_suba_prime - 1) < 0) {
-
- R_prime = -100.0 * pow((2.0 - 2.0 * R_suba_prime) /
- (39.0 + R_suba_prime), 1.0/0.73);
- }
- else
- {
- R_prime = 100.0 * pow((2.0 * R_suba_prime - 2.0) /
- (41.0 - R_suba_prime), 1.0/0.73);
- }
-
- if ((G_suba_prime - 1) < 0)
- {
- G_prime = -100.0 * pow((2.0 - 2.0 * G_suba_prime) /
- (39.0 + G_suba_prime), 1.0/0.73);
- }
- else
- {
- G_prime = 100.0 * pow((2.0 * G_suba_prime - 2.0) /
- (41.0 - G_suba_prime), 1.0/0.73);
- }
-
- if ((B_suba_prime - 1) < 0)
- {
- B_prime = -100.0 * pow((2.0 - 2.0 * B_suba_prime) /
- (39.0 + B_suba_prime), 1.0/0.73);
- }
- else
- {
- B_prime = 100.0 * pow((2.0 * B_suba_prime - 2.0) /
- (41.0 - B_suba_prime), 1.0/0.73);
- }
-
-
- // (11) Calculate RcY, GcY and BcY
-
- VEC3init(&RGB_prime, R_prime, G_prime, B_prime);
- VEC3divK(&tmp, &RGB_prime, lpMod -> Fl);
-
- MAT3eval(&RGB_subc_Y, &lpMod->MlamRigg_x_Mhunt_1, &tmp);
-
-
-
-
-#ifdef USE_CIECAM97s2
-
- // (12)
-
-
- RvAdaptationDegree(lpMod, &RGBY, &RGB_subc_Y);
- MAT3eval(&Out, &lpMod->MlamRigg_1, &RGBY);
-
- outPtr -> X = Out.n[0];
- outPtr -> Y = Out.n[1];
- outPtr -> Z = Out.n[2];
-
-#else
-
- // (12) Calculate Yc
-
- Y_subc = 0.43231*RGB_subc_Y.n[0]+0.51836*RGB_subc_Y.n[1]+0.04929*RGB_subc_Y.n[2];
-
- // (13) Calculate (Y/Yc)R, (Y/Yc)G and (Y/Yc)B
-
- VEC3divK(&RGB_subc_Y, &RGB_subc_Y, Y_subc);
- RvAdaptationDegree(lpMod, &Y_over_Y_subc_RGB, &RGB_subc_Y);
-
- // (14) Calculate Y'
- Y_prime = 0.43231*(Y_over_Y_subc_RGB.n[0]*Y_subc) + 0.51836*(Y_over_Y_subc_RGB.n[1]*Y_subc) + 0.04929 * (Y_over_Y_subc_RGB.n[2]*Y_subc);
-
- if (Y_prime < 0 || Y_subc < 0)
- {
- // Discard to near black point
-
- outPtr -> X = 0;
- outPtr -> Y = 0;
- outPtr -> Z = 0;
- return;
- }
-
- B_term = pow(Y_prime / Y_subc, (1.0 / lpMod->p) - 1);
-
- // (15) Calculate X'', Y'' and Z''
- Y_over_Y_subc_RGB.n[2] /= B_term;
- MAT3eval(&XYZ_primeprime_over_Y_subc, &lpMod->MlamRigg_1, &Y_over_Y_subc_RGB);
-
- outPtr->X = XYZ_primeprime_over_Y_subc.n[0] * Y_subc;
- outPtr->Y = XYZ_primeprime_over_Y_subc.n[1] * Y_subc;
- outPtr->Z = XYZ_primeprime_over_Y_subc.n[2] * Y_subc;
-#endif
-
-}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -49,104 +50,30 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// IT8.7 / CGATS.17-200x handling
-
-#include "lcms.h"
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void);
-LCMSAPI void LCMSEXPORT cmsIT8Free(LCMSHANDLE IT8);
-
-// Tables
-
-LCMSAPI int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE IT8);
-LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable);
-
-// Persistence
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName);
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName);
-
-// Properties
-LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer);
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp);
-LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp);
-LCMSAPI const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp);
-LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, const char ***PropertyNames);
-LCMSAPI int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames);
-
-// Datasets
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer);
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col);
-LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int col, int row);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col,
- const char* Val);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col,
- double Val);
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample);
-
-
-LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch,
- const char* cSample,
- const char *Val);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch,
- const char* cSample,
- double Val);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample);
-LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames);
-
-LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter);
-
-LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet,
- const char* cField,
- const char* ExpectedType);
-
-// ------------------------------------------------------------- Implementation
-
-
-#define SIZEOFLONGMINUS1 (sizeof(long)-1)
-#define ALIGNLONG(x) (((x)+SIZEOFLONGMINUS1) & ~(SIZEOFLONGMINUS1))
-
-// #define STRICT_CGATS 1
-
-#define MAXID 128 // Max lenght of identifier
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+
+// IT8.7 / CGATS.17-200x handling -----------------------------------------------------------------------------
+
+
+#define MAXID 128 // Max lenght of identifier
#define MAXSTR 1024 // Max lenght of string
-#define MAXTABLES 255 // Max Number of tables in a single stream
-#define MAXINCLUDE 20 // Max number of nested includes
+#define MAXTABLES 255 // Max Number of tables in a single stream
+#define MAXINCLUDE 20 // Max number of nested includes
#define DEFAULT_DBL_FORMAT "%.10g" // Double formatting
-#include <ctype.h>
-#include <limits.h>
-
-#ifndef NON_WINDOWS
-#include <io.h>
-#define DIR_CHAR '\\'
+#ifdef CMS_IS_WINDOWS_
+# include <io.h>
+# define DIR_CHAR '\\'
#else
-#define DIR_CHAR '/'
+# define DIR_CHAR '/'
#endif
// Symbols
-
typedef enum {
SNONE,
@@ -173,8 +100,8 @@
// How to write the value
-
typedef enum {
+
WRITE_UNCOOKED,
WRITE_STRINGIFY,
WRITE_HEXADECIMAL,
@@ -184,7 +111,6 @@
} WRITEMODE;
// Linked list of variable names
-
typedef struct _KeyVal {
struct _KeyVal* Next;
@@ -194,108 +120,101 @@
char* Value; // Points to value
WRITEMODE WriteAs; // How to write the value
- } KEYVALUE, *LPKEYVALUE;
+ } KEYVALUE;
// Linked list of memory chunks (Memory sink)
-
typedef struct _OwnedMem {
struct _OwnedMem* Next;
void * Ptr; // Point to value
- } OWNEDMEM, *LPOWNEDMEM;
+ } OWNEDMEM;
// Suballocator
-
typedef struct _SubAllocator {
- LPBYTE Block;
- size_t BlockSize;
- size_t Used;
-
- } SUBALLOCATOR, *LPSUBALLOCATOR;
+ cmsUInt8Number* Block;
+ cmsUInt32Number BlockSize;
+ cmsUInt32Number Used;
+
+ } SUBALLOCATOR;
// Table. Each individual table can hold properties and rows & cols
-
typedef struct _Table {
int nSamples, nPatches; // Cols, Rows
int SampleID; // Pos of ID
- LPKEYVALUE HeaderList; // The properties
+ KEYVALUE* HeaderList; // The properties
char** DataFormat; // The binary stream descriptor
char** Data; // The binary stream
- } TABLE, *LPTABLE;
+ } TABLE;
// File stream being parsed
-
typedef struct _FileContext {
- char FileName[MAX_PATH]; // File name if being readed from file
- FILE* Stream; // File stream or NULL if holded in memory
- } FILECTX, *LPFILECTX;
-
-// This struct hold all information about an openened
-// IT8 handler. Only one dataset is allowed.
-
+ char FileName[cmsMAX_PATH]; // File name if being readed from file
+ FILE* Stream; // File stream or NULL if holded in memory
+ } FILECTX;
+
+// This struct hold all information about an open IT8 handler.
typedef struct {
- char SheetType[MAXSTR];
-
- int TablesCount; // How many tables in this stream
- int nTable; // The actual table
+ char SheetType[MAXSTR]; // The first row of the IT8 (the type)
+
+ cmsUInt32Number TablesCount; // How many tables in this stream
+ cmsUInt32Number nTable; // The actual table
TABLE Tab[MAXTABLES];
// Memory management
-
- LPOWNEDMEM MemorySink; // The storage backend
+ OWNEDMEM* MemorySink; // The storage backend
SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast
// Parser state machine
-
SYMBOL sy; // Current symbol
int ch; // Current character
int inum; // integer value
- double dnum; // real value
+ cmsFloat64Number dnum; // real value
char id[MAXID]; // identifier
char str[MAXSTR]; // string
// Allowed keywords & datasets. They have visibility on whole stream
-
- LPKEYVALUE ValidKeywords;
- LPKEYVALUE ValidSampleID;
+ KEYVALUE* ValidKeywords;
+ KEYVALUE* ValidSampleID;
char* Source; // Points to loc. being parsed
int lineno; // line counter for error reporting
- LPFILECTX FileStack[MAXINCLUDE]; // Stack of files being parsed
+ FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed
int IncludeSP; // Include Stack Pointer
char* MemoryBlock; // The stream if holded in memory
- char DoubleFormatter[MAXID]; // Printf-like 'double' formatter
-
- } IT8, *LPIT8;
-
-
-
+ char DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter
+
+ cmsContext ContextID; // The threading context
+
+ } cmsIT8;
+
+
+// The stream for save operations
typedef struct {
FILE* stream; // For save-to-file behaviour
- LPBYTE Base;
- LPBYTE Ptr; // For save-to-mem behaviour
- size_t Used;
- size_t Max;
-
- } SAVESTREAM, FAR* LPSAVESTREAM;
-
-
-// ------------------------------------------------------ IT8 parsing routines
+ cmsUInt8Number* Base;
+ cmsUInt8Number* Ptr; // For save-to-mem behaviour
+ cmsUInt32Number Used;
+ cmsUInt32Number Max;
+
+ } SAVESTREAM;
+
+
+// ------------------------------------------------------ cmsIT8 parsing routines
// A keyword
@@ -309,14 +228,15 @@
// The keyword->symbol translation table. Sorting is required.
static const KEYWORD TabKeys[] = {
- {"$INCLUDE", SINCLUDE},
- {".INCLUDE", SINCLUDE},
- {"BEGIN_DATA", SBEGIN_DATA },
- {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT },
+ {"$INCLUDE", SINCLUDE}, // This is an extension!
+ {".INCLUDE", SINCLUDE}, // This is an extension!
+
+ {"BEGIN_DATA", SBEGIN_DATA },
+ {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT },
{"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID},
- {"END_DATA", SEND_DATA},
- {"END_DATA_FORMAT", SEND_DATA_FORMAT},
- {"KEYWORD", SKEYWORD}
+ {"END_DATA", SEND_DATA},
+ {"END_DATA_FORMAT", SEND_DATA_FORMAT},
+ {"KEYWORD", SKEYWORD}
};
#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
@@ -325,8 +245,8 @@
// A property
typedef struct {
- const char *id;
- WRITEMODE as;
+ const char *id; // The identifier
+ WRITEMODE as; // How is supposed to be written
} PROPERTY;
static PROPERTY PredefinedProperties[] = {
@@ -366,7 +286,8 @@
{"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic
-// new in recent specs:
+ // below properties are new in recent specs:
+
{"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated
// along with details of the geometry and the aperture size and shape. For example,
// for transmission measurements it is important to identify 0/diffuse, diffuse/0,
@@ -438,9 +359,9 @@
"LAB_B", // b* component of Lab data
"LAB_C", // C*ab component of Lab data
"LAB_H", // hab component of Lab data
- "LAB_DE", // CIE dE
- "LAB_DE_94", // CIE dE using CIE 94
- "LAB_DE_CMC", // dE using CMC
+ "LAB_DE", // CIE dE
+ "LAB_DE_94", // CIE dE using CIE 94
+ "LAB_DE_CMC", // dE using CMC
"LAB_DE_2000", // CIE dE using CIE DE 2000
"MEAN_DE", // Mean Delta E (LAB_DE) of samples compared to batch average
// (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets)
@@ -458,84 +379,94 @@
#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *))
//Forward declaration of some internal functions
-static
-void* AllocChunk(LPIT8 it8, size_t size);
+static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size);
// Checks if c is a separator
static
-LCMSBOOL isseparator(int c)
+cmsBool isseparator(int c)
{
return (c == ' ') || (c == '\t') || (c == '\r');
}
// Checks whatever if c is a valid identifier char
static
-LCMSBOOL ismiddle(int c)
+cmsBool ismiddle(int c)
{
return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127));
}
// Checks whatsever if c is a valid identifier middle char.
static
-LCMSBOOL isidchar(int c)
+cmsBool isidchar(int c)
{
return isalnum(c) || ismiddle(c);
}
// Checks whatsever if c is a valid identifier first char.
static
-LCMSBOOL isfirstidchar(int c)
+cmsBool isfirstidchar(int c)
{
return !isdigit(c) && ismiddle(c);
}
-// checks whether the supplied path looks like an absolute path
-// NOTE: this function doesn't checks if the path exists or even if it's legal
+// Guess whether the supplied path looks like an absolute path
static
-LCMSBOOL isabsolutepath(const char *path)
+cmsBool isabsolutepath(const char *path)
{
+ char ThreeChars[4];
+
if(path == NULL)
return FALSE;
-
- if(path[0] == DIR_CHAR)
+ if (path[0] == 0)
+ return FALSE;
+
+ strncpy(ThreeChars, path, 3);
+ ThreeChars[3] = 0;
+
+ if(ThreeChars[0] == DIR_CHAR)
return TRUE;
-#ifndef NON_WINDOWS
- if(isalpha(path[0]) && path[1] == ':')
+#ifdef CMS_IS_WINDOWS_
+ if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':')
return TRUE;
#endif
return FALSE;
}
// Makes a file path based on a given reference path
-// NOTE: buffer is assumed to point to at least MAX_PATH bytes
-// NOTE: both relPath and basePath are assumed to be no more than MAX_PATH characters long (including the null terminator!)
// NOTE: this function doesn't check if the path exists or even if it's legal
static
-LCMSBOOL _cmsMakePath(const char *relPath, const char *basePath, char *buffer)
+cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen)
{
- if (!isabsolutepath(relPath)) {
-
- char *tail;
-
- strncpy(buffer, basePath, MAX_PATH-1);
- tail = strrchr(buffer, DIR_CHAR);
- if (tail != NULL) {
-
- size_t len = tail - buffer;
- strncpy(tail + 1, relPath, MAX_PATH - len -1);
- // TODO: if combined path is longer than MAX_PATH, this should return FALSE!
- return TRUE;
- }
+ char *tail;
+ cmsUInt32Number len;
+
+ // Already absolute?
+ if (isabsolutepath(relPath)) {
+
+ strncpy(buffer, relPath, MaxLen);
+ buffer[MaxLen-1] = 0;
+ return TRUE;
}
- strncpy(buffer, relPath, MAX_PATH - 1);
- buffer[MAX_PATH-1] = 0;
+
+ // No, search for last
+ strncpy(buffer, basePath, MaxLen);
+ buffer[MaxLen-1] = 0;
+
+ tail = strrchr(buffer, DIR_CHAR);
+ if (tail == NULL) return FALSE; // Is not absolute and has no separators??
+
+ len = (cmsUInt32Number) (tail - buffer);
+ if (len >= MaxLen) return FALSE;
+
+ // No need to assure zero terminator over here
+ strncpy(tail + 1, relPath, MaxLen - len);
+
return TRUE;
}
// Make sure no exploit is being even tried
-
static
const char* NoMeta(const char* str)
{
@@ -545,40 +476,37 @@
return str;
}
-
// Syntax error
static
-LCMSBOOL SynError(LPIT8 it8, const char *Txt, ...)
+cmsBool SynError(cmsIT8* it8, const char *Txt, ...)
{
- char Buffer[256], ErrMsg[1024];
- va_list args;
-
- va_start(args, Txt);
- vsnprintf(Buffer, 255, Txt, args);
- Buffer[255] = 0;
- va_end(args);
-
- snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer);
- ErrMsg[1023] = 0;
- it8->sy = SSYNERROR;
- cmsSignalError(LCMS_ERRC_ABORTED, "%s", ErrMsg);
- return FALSE;
+ char Buffer[256], ErrMsg[1024];
+ va_list args;
+
+ va_start(args, Txt);
+ vsnprintf(Buffer, 255, Txt, args);
+ Buffer[255] = 0;
+ va_end(args);
+
+ snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer);
+ ErrMsg[1023] = 0;
+ it8->sy = SSYNERROR;
+ cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg);
+ return FALSE;
}
// Check if current symbol is same as specified. issue an error else.
static
-LCMSBOOL Check(LPIT8 it8, SYMBOL sy, const char* Err)
+cmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err)
{
if (it8 -> sy != sy)
return SynError(it8, NoMeta(Err));
return TRUE;
}
-
-
// Read Next character from stream
static
-void NextCh(LPIT8 it8)
+void NextCh(cmsIT8* it8)
{
if (it8 -> FileStack[it8 ->IncludeSP]->Stream) {
@@ -594,9 +522,6 @@
} else
it8 ->ch = 0; // EOF
}
-
-
-
}
else {
it8->ch = *it8->Source;
@@ -609,100 +534,98 @@
static
SYMBOL BinSrchKey(const char *id)
{
- int l = 1;
- int r = NUMKEYS;
- int x, res;
-
- while (r >= l)
- {
- x = (l+r)/2;
- res = stricmp(id, TabKeys[x-1].id);
- if (res == 0) return TabKeys[x-1].sy;
- if (res < 0) r = x - 1;
- else l = x + 1;
- }
-
- return SNONE;
+ int l = 1;
+ int r = NUMKEYS;
+ int x, res;
+
+ while (r >= l)
+ {
+ x = (l+r)/2;
+ res = cmsstrcasecmp(id, TabKeys[x-1].id);
+ if (res == 0) return TabKeys[x-1].sy;
+ if (res < 0) r = x - 1;
+ else l = x + 1;
+ }
+
+ return SNONE;
}
// 10 ^n
static
-double xpow10(int n)
+cmsFloat64Number xpow10(int n)
{
- return pow(10, (double) n);
+ return pow(10, (cmsFloat64Number) n);
}
// Reads a Real number, tries to follow from integer number
static
-void ReadReal(LPIT8 it8, int inum)
+void ReadReal(cmsIT8* it8, int inum)
{
- it8->dnum = (double) inum;
-
- while (isdigit(it8->ch)) {
+ it8->dnum = (cmsFloat64Number) inum;
+
+ while (isdigit(it8->ch)) {
it8->dnum = it8->dnum * 10.0 + (it8->ch - '0');
NextCh(it8);
- }
-
- if (it8->ch == '.') { // Decimal point
-
- double frac = 0.0; // fraction
- int prec = 0; // precission
-
- NextCh(it8); // Eats dec. point
-
- while (isdigit(it8->ch)) {
-
- frac = frac * 10.0 + (it8->ch - '0');
- prec++;
- NextCh(it8);
- }
-
- it8->dnum = it8->dnum + (frac / xpow10(prec));
+ }
+
+ if (it8->ch == '.') { // Decimal point
+
+ cmsFloat64Number frac = 0.0; // fraction
+ int prec = 0; // precision
+
+ NextCh(it8); // Eats dec. point
+
+ while (isdigit(it8->ch)) {
+
+ frac = frac * 10.0 + (it8->ch - '0');
+ prec++;
+ NextCh(it8);
}
- // Exponent, example 34.00E+20
- if (toupper(it8->ch) == 'E') {
-
- int e;
- int sgn;
-
- NextCh(it8); sgn = 1;
-
- if (it8->ch == '-') {
-
- sgn = -1; NextCh(it8);
- }
- else
- if (it8->ch == '+') {
-
- sgn = +1;
- NextCh(it8);
- }
-
-
- e = 0;
- while (isdigit(it8->ch)) {
-
- if ((double) e * 10L < INT_MAX)
- e = e * 10 + (it8->ch - '0');
-
- NextCh(it8);
- }
-
- e = sgn*e;
-
- it8 -> dnum = it8 -> dnum * xpow10(e);
+ it8->dnum = it8->dnum + (frac / xpow10(prec));
+ }
+
+ // Exponent, example 34.00E+20
+ if (toupper(it8->ch) == 'E') {
+
+ int e;
+ int sgn;
+
+ NextCh(it8); sgn = 1;
+
+ if (it8->ch == '-') {
+
+ sgn = -1; NextCh(it8);
}
+ else
+ if (it8->ch == '+') {
+
+ sgn = +1;
+ NextCh(it8);
+ }
+
+ e = 0;
+ while (isdigit(it8->ch)) {
+
+ if ((cmsFloat64Number) e * 10L < INT_MAX)
+ e = e * 10 + (it8->ch - '0');
+
+ NextCh(it8);
+ }
+
+ e = sgn*e;
+ it8 -> dnum = it8 -> dnum * xpow10(e);
+ }
}
// Reads next symbol
static
-void InSymbol(LPIT8 it8)
+void InSymbol(cmsIT8* it8)
{
register char *idptr;
register int k;
@@ -716,7 +639,6 @@
if (isfirstidchar(it8->ch)) { // Identifier
-
k = 0;
idptr = it8->id;
@@ -845,7 +767,6 @@
} while (isidchar(it8->ch));
*idptr = '\0';
-
it8->sy = SIDENT;
}
return;
@@ -860,7 +781,6 @@
break;
// Eof stream markers
-
case 0:
case -1:
it8->sy = SEOF;
@@ -868,7 +788,6 @@
// Next line
-
case '\n':
NextCh(it8);
it8->sy = SEOLN;
@@ -876,7 +795,6 @@
break;
// Comment
-
case '#':
NextCh(it8);
while (it8->ch && it8->ch != '\n')
@@ -885,8 +803,7 @@
it8->sy = SCOMMENT;
break;
- // String.
-
+ // String.
case '\'':
case '\"':
idptr = it8->str;
@@ -921,10 +838,10 @@
if (it8 -> sy == SINCLUDE) {
- LPFILECTX FileNest;
-
- if(it8 -> IncludeSP >= (MAXINCLUDE-1))
- {
+ FILECTX* FileNest;
+
+ if(it8 -> IncludeSP >= (MAXINCLUDE-1)) {
+
SynError(it8, "Too many recursion levels");
return;
}
@@ -933,15 +850,16 @@
if (!Check(it8, SSTRING, "Filename expected")) return;
FileNest = it8 -> FileStack[it8 -> IncludeSP + 1];
- if(FileNest == NULL)
- {
- FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX));
+ if(FileNest == NULL) {
+
+ FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
//if(FileNest == NULL)
- // TODO: how to manage out-of-memory conditions?
+ // TODO: how to manage out-of-memory conditions?
}
- if(_cmsMakePath(it8->str, it8->FileStack[it8->IncludeSP]->FileName, FileNest->FileName) == FALSE)
- {
+ if (BuildAbsolutePath(it8->str,
+ it8->FileStack[it8->IncludeSP]->FileName,
+ FileNest->FileName, cmsMAX_PATH-1) == FALSE) {
SynError(it8, "File path too long");
return;
}
@@ -962,7 +880,7 @@
// Checks end of line separator
static
-LCMSBOOL CheckEOLN(LPIT8 it8)
+cmsBool CheckEOLN(cmsIT8* it8)
{
if (!Check(it8, SEOLN, "Expected separator")) return FALSE;
while (it8 -> sy == SEOLN)
@@ -974,7 +892,7 @@
// Skip a symbol
static
-void Skip(LPIT8 it8, SYMBOL sy)
+void Skip(cmsIT8* it8, SYMBOL sy)
{
if (it8->sy == sy && it8->sy != SEOF)
InSymbol(it8);
@@ -983,7 +901,7 @@
// Skip multiple EOLN
static
-void SkipEOLN(LPIT8 it8)
+void SkipEOLN(cmsIT8* it8)
{
while (it8->sy == SEOLN) {
InSymbol(it8);
@@ -993,7 +911,7 @@
// Returns a string holding current value
static
-LCMSBOOL GetVal(LPIT8 it8, char* Buffer, size_t max, const char* ErrorTitle)
+cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle)
{
switch (it8->sy) {
@@ -1018,9 +936,9 @@
// ---------------------------------------------------------- Table
static
-LPTABLE GetTable(LPIT8 it8)
+TABLE* GetTable(cmsIT8* it8)
{
- if ((it8 -> nTable >= it8 ->TablesCount) || (it8 -> nTable < 0)) {
+ if ((it8 -> nTable >= it8 ->TablesCount)) {
SynError(it8, "Table %d out of sequence", it8 -> nTable);
return it8 -> Tab;
@@ -1032,75 +950,70 @@
// ---------------------------------------------------------- Memory management
-
// Frees an allocator and owned memory
-void LCMSEXPORT cmsIT8Free(LCMSHANDLE hIT8)
+void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
if (it8 == NULL)
return;
-
if (it8->MemorySink) {
- LPOWNEDMEM p;
- LPOWNEDMEM n;
+ OWNEDMEM* p;
+ OWNEDMEM* n;
for (p = it8->MemorySink; p != NULL; p = n) {
n = p->Next;
- if (p->Ptr) _cmsFree(p->Ptr);
- _cmsFree(p);
+ if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr);
+ _cmsFree(it8 ->ContextID, p);
}
}
if (it8->MemoryBlock)
- _cmsFree(it8->MemoryBlock);
-
- _cmsFree(it8);
+ _cmsFree(it8 ->ContextID, it8->MemoryBlock);
+
+ _cmsFree(it8 ->ContextID, it8);
}
// Allocates a chunk of data, keep linked list
static
-void* AllocBigBlock(LPIT8 it8, size_t size)
+void* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size)
{
- LPOWNEDMEM ptr1;
- void* ptr = _cmsMalloc(size);
-
- if (ptr) {
-
- ZeroMemory(ptr, size);
- ptr1 = (LPOWNEDMEM) _cmsMalloc(sizeof(OWNEDMEM));
-
- if (ptr1 == NULL) {
-
- _cmsFree(ptr);
- return NULL;
- }
-
- ZeroMemory(ptr1, sizeof(OWNEDMEM));
-
- ptr1-> Ptr = ptr;
- ptr1-> Next = it8 -> MemorySink;
- it8 -> MemorySink = ptr1;
+ OWNEDMEM* ptr1;
+ void* ptr = _cmsMallocZero(it8->ContextID, size);
+
+ if (ptr != NULL) {
+
+ ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM));
+
+ if (ptr1 == NULL) {
+
+ _cmsFree(it8 ->ContextID, ptr);
+ return NULL;
}
- return ptr;
+ ptr1-> Ptr = ptr;
+ ptr1-> Next = it8 -> MemorySink;
+ it8 -> MemorySink = ptr1;
+ }
+
+ return ptr;
}
// Suballocator.
static
-void* AllocChunk(LPIT8 it8, size_t size)
+void* AllocChunk(cmsIT8* it8, cmsUInt32Number size)
{
- size_t free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used;
- LPBYTE ptr;
-
- size = ALIGNLONG(size);
-
- if (size > free) {
+ cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used;
+ cmsUInt8Number* ptr;
+
+ size = _cmsALIGNLONG(size);
+
+ if (size > Free) {
if (it8 -> Allocator.BlockSize == 0)
@@ -1112,7 +1025,7 @@
it8 ->Allocator.BlockSize = size;
it8 ->Allocator.Used = 0;
- it8 ->Allocator.Block = (LPBYTE) AllocBigBlock(it8, it8 ->Allocator.BlockSize);
+ it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize);
}
ptr = it8 ->Allocator.Block + it8 ->Allocator.Used;
@@ -1125,9 +1038,9 @@
// Allocates a string
static
-char *AllocString(LPIT8 it8, const char* str)
+char *AllocString(cmsIT8* it8, const char* str)
{
- size_t Size = strlen(str)+1;
+ cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1;
char *ptr;
@@ -1140,7 +1053,7 @@
// Searches through linked list
static
-LCMSBOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, const char* Subkey, LPKEYVALUE* LastPtr)
+cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr)
{
if (LastPtr) *LastPtr = p;
@@ -1150,7 +1063,7 @@
if (*Key != '#') { // Comments are ignored
- if (stricmp(Key, p->Keyword) == 0)
+ if (cmsstrcasecmp(Key, p->Keyword) == 0)
break;
}
}
@@ -1165,9 +1078,9 @@
if (LastPtr) *LastPtr = p;
- if (stricmp(Subkey, p->Subkey) == 0)
- return TRUE;
- }
+ if (cmsstrcasecmp(Subkey, p->Subkey) == 0)
+ return TRUE;
+ }
return FALSE;
}
@@ -1176,55 +1089,62 @@
// Add a property into a linked list
static
-LPKEYVALUE AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
+KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
{
- LPKEYVALUE p;
-
- // Check if property is already in list (this is an error)
+ KEYVALUE* p;
+ KEYVALUE* last;
+
+
+ // Check if property is already in list
if (IsAvailableOnList(*Head, Key, Subkey, &p)) {
- // This may work for editing properties
+ // This may work for editing properties
// return SynError(it8, "duplicate key <%s>", Key);
}
else {
- LPKEYVALUE last = p;
-
- // Allocate the container
- p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE));
- if (p == NULL)
- {
+
+ last = p;
+
+ // Allocate the container
+ p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE));
+ if (p == NULL)
+ {
SynError(it8, "AddToList: out of memory");
return NULL;
- }
-
- // Store name and value
- p->Keyword = AllocString(it8, Key);
+ }
+
+ // Store name and value
+ p->Keyword = AllocString(it8, Key);
p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
// Keep the container in our list
- if (*Head == NULL)
+ if (*Head == NULL) {
*Head = p;
+ }
else
{
- if(Subkey != 0 && last != 0) {
+ if (Subkey != NULL && last != NULL) {
+
last->NextSubkey = p;
// If Subkey is not null, then last is the last property with the same key,
// but not necessarily is the last property in the list, so we need to move
// to the actual list end
- while(last->Next != 0)
- last = last->Next;
- }
- last->Next = p;
- }
-
- p->Next = NULL;
+ while (last->Next != NULL)
+ last = last->Next;
+ }
+
+ if (last != NULL) last->Next = p;
+ }
+
+ p->Next = NULL;
p->NextSubkey = NULL;
}
p->WriteAs = WriteAs;
+
if (xValue != NULL) {
p->Value = AllocString(it8, xValue);
@@ -1237,23 +1157,23 @@
}
static
-LPKEYVALUE AddAvailableProperty(LPIT8 it8, const char* Key, WRITEMODE as)
+KEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as)
{
- return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as);
+ return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as);
}
static
-LPKEYVALUE AddAvailableSampleID(LPIT8 it8, const char* Key)
+KEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key)
{
- return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED);
+ return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED);
}
static
-void AllocTable(LPIT8 it8)
+void AllocTable(cmsIT8* it8)
{
- LPTABLE t;
+ TABLE* t;
t = it8 ->Tab + it8 ->TablesCount;
@@ -1265,9 +1185,9 @@
}
-int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable)
+cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable)
{
- LPIT8 it8 = (LPIT8) IT8;
+ cmsIT8* it8 = (cmsIT8*) IT8;
if (nTable >= it8 ->TablesCount) {
@@ -1289,16 +1209,14 @@
// Init an empty container
-LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void)
+cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
{
- LPIT8 it8;
+ cmsIT8* it8;
int i;
- it8 = (LPIT8) malloc(sizeof(IT8));
+ it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8));
if (it8 == NULL) return NULL;
- ZeroMemory(it8, sizeof(IT8));
-
AllocTable(it8);
it8->MemoryBlock = NULL;
@@ -1306,6 +1224,7 @@
it8 ->nTable = 0;
+ it8->ContextID = ContextID;
it8->Allocator.Used = 0;
it8->Allocator.Block = NULL;
it8->Allocator.BlockSize = 0;
@@ -1319,7 +1238,7 @@
it8 -> inum = 0;
it8 -> dnum = 0.0;
- it8->FileStack[0] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX));
+ it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
it8->IncludeSP = 0;
it8 -> lineno = 1;
@@ -1335,30 +1254,30 @@
AddAvailableSampleID(it8, PredefinedSampleID[i]);
- return (LCMSHANDLE) it8;
+ return (cmsHANDLE) it8;
}
-const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8)
+const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
return it8 ->SheetType;
}
-LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type)
+cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
strncpy(it8 ->SheetType, Type, MAXSTR-1);
it8 ->SheetType[MAXSTR-1] = 0;
return TRUE;
}
-LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* Val)
+cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
if (!Val) return FALSE;
if (!*Val) return FALSE;
@@ -1369,9 +1288,9 @@
// Sets a property
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* Key, const char *Val)
+cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
if (!Val) return FALSE;
if (!*Val) return FALSE;
@@ -1380,9 +1299,9 @@
}
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val)
+cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
char Buffer[1024];
sprintf(Buffer, it8->DoubleFormatter, Val);
@@ -1390,9 +1309,9 @@
return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL;
}
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val)
+cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
char Buffer[1024];
sprintf(Buffer, "%d", Val);
@@ -1400,25 +1319,25 @@
return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL;
}
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer)
+cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL;
}
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer)
+cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL;
}
// Gets a property
-const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* Key)
+const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key)
{
- LPIT8 it8 = (LPIT8) hIT8;
- LPKEYVALUE p;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ KEYVALUE* p;
if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p))
{
@@ -1428,7 +1347,7 @@
}
-double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp)
+cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp)
{
const char *v = cmsIT8GetProperty(hIT8, cProp);
@@ -1436,13 +1355,12 @@
else return 0.0;
}
-const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char *SubKey)
+const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey)
{
- LPIT8 it8 = (LPIT8) hIT8;
- LPKEYVALUE p;
-
- if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p))
- {
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ KEYVALUE* p;
+
+ if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) {
return p -> Value;
}
return NULL;
@@ -1452,9 +1370,9 @@
static
-void AllocateDataFormat(LPIT8 it8)
+void AllocateDataFormat(cmsIT8* it8)
{
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
if (t -> DataFormat) return; // Already allocated
@@ -1467,17 +1385,17 @@
}
t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *));
- if (t->DataFormat == NULL)
- {
+ if (t->DataFormat == NULL) {
+
SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array");
}
}
static
-const char *GetDataFormat(LPIT8 it8, int n)
+const char *GetDataFormat(cmsIT8* it8, int n)
{
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
if (t->DataFormat)
return t->DataFormat[n];
@@ -1486,16 +1404,9 @@
}
static
-LCMSBOOL SetDataFormat(LPIT8 it8, int n, const char *label)
+cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label)
{
- LPTABLE t = GetTable(it8);
-
-#ifdef STRICT_CGATS
- if (!IsAvailableOnList(it8-> ValidSampleID, label, NULL, NULL)) {
- SynError(it8, "Invalid data format '%s'.", label);
- return FALSE;
- }
-#endif
+ TABLE* t = GetTable(it8);
if (!t->DataFormat)
AllocateDataFormat(it8);
@@ -1505,7 +1416,6 @@
return FALSE;
}
-
if (t->DataFormat) {
t->DataFormat[n] = AllocString(it8, label);
}
@@ -1514,16 +1424,16 @@
}
-LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample)
+cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample)
{
- LPIT8 it8 = (LPIT8) h;
+ cmsIT8* it8 = (cmsIT8*) h;
return SetDataFormat(it8, n, Sample);
}
static
-void AllocateDataSet(LPIT8 it8)
+void AllocateDataSet(cmsIT8* it8)
{
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
if (t -> Data) return; // Already allocated
@@ -1531,21 +1441,20 @@
t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*));
- if (t->Data == NULL)
- {
+ if (t->Data == NULL) {
+
SynError(it8, "AllocateDataSet: Unable to allocate data array");
}
}
static
-char* GetData(LPIT8 it8, int nSet, int nField)
+char* GetData(cmsIT8* it8, int nSet, int nField)
{
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
int nSamples = t -> nSamples;
int nPatches = t -> nPatches;
-
if (nSet >= nPatches || nField >= nSamples)
return NULL;
@@ -1554,17 +1463,15 @@
}
static
-LCMSBOOL SetData(LPIT8 it8, int nSet, int nField, const char *Val)
+cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val)
{
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
if (!t->Data)
AllocateDataSet(it8);
if (!t->Data) return FALSE;
-
-
if (nSet > t -> nPatches || nSet < 0) {
return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches);
@@ -1575,7 +1482,6 @@
}
-
t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val);
return TRUE;
}
@@ -1586,38 +1492,38 @@
// Writes a string to file
static
-void WriteStr(LPSAVESTREAM f, const char *str)
+void WriteStr(SAVESTREAM* f, const char *str)
{
-
- size_t len;
+ cmsUInt32Number len;
if (str == NULL)
str = " ";
// Lenghth to write
- len = strlen(str);
+ len = (cmsUInt32Number) strlen(str);
f ->Used += len;
if (f ->stream) { // Should I write it to a file?
- fwrite(str, 1, len, f->stream);
+ if (fwrite(str, 1, len, f->stream) != len) {
+ cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser");
+ return;
+ }
}
else { // Or to a memory block?
-
if (f ->Base) { // Am I just counting the bytes?
if (f ->Used > f ->Max) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Write to memory overflows in CGATS parser");
- return;
+ cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser");
+ return;
}
- CopyMemory(f ->Ptr, str, len);
+ memmove(f ->Ptr, str, len);
f->Ptr += len;
-
}
}
@@ -1627,7 +1533,7 @@
// Write formatted
static
-void Writef(LPSAVESTREAM f, const char* frm, ...)
+void Writef(SAVESTREAM* f, const char* frm, ...)
{
char Buffer[4096];
va_list args;
@@ -1642,10 +1548,10 @@
// Writes full header
static
-void WriteHeader(LPIT8 it8, LPSAVESTREAM fp)
+void WriteHeader(cmsIT8* it8, SAVESTREAM* fp)
{
- LPKEYVALUE p;
- LPTABLE t = GetTable(it8);
+ KEYVALUE* p;
+ TABLE* t = GetTable(it8);
for (p = t->HeaderList; (p != NULL); p = p->Next)
@@ -1672,14 +1578,13 @@
if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) {
-#ifdef STRICT_CGATS
+#ifdef CMS_STRICT_CGATS
WriteStr(fp, "KEYWORD\t\"");
WriteStr(fp, p->Keyword);
WriteStr(fp, "\"\n");
#endif
AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED);
-
}
WriteStr(fp, p->Keyword);
@@ -1720,10 +1625,10 @@
// Writes the data format
static
-void WriteDataFormat(LPSAVESTREAM fp, LPIT8 it8)
+void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
{
int i, nSamples;
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
if (!t -> DataFormat) return;
@@ -1743,10 +1648,10 @@
// Writes data array
static
-void WriteData(LPSAVESTREAM fp, LPIT8 it8)
+void WriteData(SAVESTREAM* fp, cmsIT8* it8)
{
int i, j;
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
if (!t->Data) return;
@@ -1785,13 +1690,13 @@
// Saves whole file
-LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName)
+cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
{
SAVESTREAM sd;
- int i;
- LPIT8 it8 = (LPIT8) hIT8;
-
- ZeroMemory(&sd, sizeof(SAVESTREAM));
+ cmsUInt32Number i;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ memset(&sd, 0, sizeof(sd));
sd.stream = fopen(cFileName, "wt");
if (!sd.stream) return FALSE;
@@ -1806,23 +1711,23 @@
WriteData(&sd, it8);
}
- fclose(sd.stream);
+ if (fclose(sd.stream) != 0) return FALSE;
return TRUE;
}
// Saves to memory
-LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded)
+cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded)
{
SAVESTREAM sd;
- int i;
- LPIT8 it8 = (LPIT8) hIT8;
-
- ZeroMemory(&sd, sizeof(SAVESTREAM));
+ cmsUInt32Number i;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ memset(&sd, 0, sizeof(sd));
sd.stream = NULL;
- sd.Base = (LPBYTE) MemPtr;
+ sd.Base = (cmsUInt8Number*) MemPtr;
sd.Ptr = sd.Base;
sd.Used = 0;
@@ -1856,10 +1761,10 @@
// -------------------------------------------------------------- Higer level parsing
static
-LCMSBOOL DataFormatSection(LPIT8 it8)
+cmsBool DataFormatSection(cmsIT8* it8)
{
int iField = 0;
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
InSymbol(it8); // Eats "BEGIN_DATA_FORMAT"
CheckEOLN(it8);
@@ -1897,12 +1802,12 @@
static
-LCMSBOOL DataSection (LPIT8 it8)
+cmsBool DataSection (cmsIT8* it8)
{
int iField = 0;
int iSet = 0;
- char Buffer[MAXSTR];
- LPTABLE t = GetTable(it8);
+ char Buffer[256];
+ TABLE* t = GetTable(it8);
InSymbol(it8); // Eats "BEGIN_DATA"
CheckEOLN(it8);
@@ -1949,11 +1854,11 @@
static
-LCMSBOOL HeaderSection(LPIT8 it8)
+cmsBool HeaderSection(cmsIT8* it8)
{
char VarName[MAXID];
char Buffer[MAXSTR];
- LPKEYVALUE Key;
+ KEYVALUE* Key;
while (it8->sy != SEOF &&
it8->sy != SSYNERROR &&
@@ -1985,7 +1890,7 @@
if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) {
-#ifdef STRICT_CGATS
+#ifdef CMS_STRICT_CGATS
return SynError(it8, "Undefined keyword '%s'", VarName);
#else
Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED);
@@ -2007,7 +1912,7 @@
return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
// chop the string as a list of "subkey, value" pairs, using ';' as a separator
- for(Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
+ for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
{
char *Value, *temp;
@@ -2058,7 +1963,7 @@
static
-LCMSBOOL ParseIT8(LPIT8 it8, LCMSBOOL nosheet)
+cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
{
char* SheetTypePtr = it8 ->SheetType;
@@ -2119,33 +2024,32 @@
// Init usefull pointers
static
-void CookPointers(LPIT8 it8)
+void CookPointers(cmsIT8* it8)
{
int idField, i;
char* Fld;
- int j;
- int nOldTable = it8 ->nTable;
+ cmsUInt32Number j;
+ cmsUInt32Number nOldTable = it8 ->nTable;
for (j=0; j < it8 ->TablesCount; j++) {
- LPTABLE t = it8 ->Tab + j;
+ TABLE* t = it8 ->Tab + j;
t -> SampleID = 0;
it8 ->nTable = j;
for (idField = 0; idField < t -> nSamples; idField++)
{
- if (t ->DataFormat == NULL) {
- SynError(it8, "Undefined DATA_FORMAT");
- return;
-
+ if (t ->DataFormat == NULL){
+ SynError(it8, "Undefined DATA_FORMAT");
+ return;
}
Fld = t->DataFormat[idField];
if (!Fld) continue;
- if (stricmp(Fld, "SAMPLE_ID") == 0) {
+ if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
t -> SampleID = idField;
@@ -2170,7 +2074,7 @@
// "LABEL" is an extension. It keeps references to forward tables
- if ((stricmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) {
+ if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) {
// Search for table references...
for (i=0; i < t -> nPatches; i++) {
@@ -2179,15 +2083,15 @@
if (Label) {
- int k;
+ cmsUInt32Number k;
// This is the label, search for a table containing
// this property
for (k=0; k < it8 ->TablesCount; k++) {
- LPTABLE Table = it8 ->Tab + k;
- LPKEYVALUE p;
+ TABLE* Table = it8 ->Tab + k;
+ KEYVALUE* p;
if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
@@ -2221,10 +2125,10 @@
// that should be something like some printable characters plus a \n
static
-int IsMyBlock(LPBYTE Buffer, size_t n)
+int IsMyBlock(cmsUInt8Number* Buffer, int n)
{
int cols = 1, space = 0, quot = 0;
- size_t i;
+ int i;
if (n < 10) return FALSE; // Too small
@@ -2261,20 +2165,22 @@
static
-int IsMyFile(const char* FileName)
+cmsBool IsMyFile(const char* FileName)
{
FILE *fp;
- size_t Size;
- BYTE Ptr[133];
+ cmsUInt32Number Size;
+ cmsUInt8Number Ptr[133];
fp = fopen(FileName, "rt");
if (!fp) {
- cmsSignalError(LCMS_ERRC_ABORTED, "File '%s' not found", FileName);
+ cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName);
return FALSE;
}
- Size = fread(Ptr, 1, 132, fp);
- fclose(fp);
+ Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp);
+
+ if (fclose(fp) != 0)
+ return FALSE;
Ptr[Size] = '\0';
@@ -2284,24 +2190,28 @@
// ---------------------------------------------------------- Exported routines
-LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len)
+cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len)
{
- LCMSHANDLE hIT8;
- LPIT8 it8;
-
- int type = IsMyBlock((LPBYTE) Ptr, len);
+ cmsHANDLE hIT8;
+ cmsIT8* it8;
+ int type;
+
+ _cmsAssert(Ptr != NULL);
+ _cmsAssert(len != 0);
+
+ type = IsMyBlock((cmsUInt8Number*)Ptr, len);
if (type == 0) return NULL;
- hIT8 = cmsIT8Alloc();
+ hIT8 = cmsIT8Alloc(ContextID);
if (!hIT8) return NULL;
- it8 = (LPIT8) hIT8;
- it8 ->MemoryBlock = (char*) _cmsMalloc(len + 1);
+ it8 = (cmsIT8*) hIT8;
+ it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1);
strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
it8 ->MemoryBlock[len] = 0;
- strncpy(it8->FileStack[0]->FileName, "", MAX_PATH-1);
+ strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1);
it8-> Source = it8 -> MemoryBlock;
if (!ParseIT8(it8, type-1)) {
@@ -2313,7 +2223,7 @@
CookPointers(it8);
it8 ->nTable = 0;
- _cmsFree(it8->MemoryBlock);
+ _cmsFree(ContextID, it8->MemoryBlock);
it8 -> MemoryBlock = NULL;
return hIT8;
@@ -2322,17 +2232,20 @@
}
-LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName)
+cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName)
{
- LCMSHANDLE hIT8;
- LPIT8 it8;
-
- int type = IsMyFile(cFileName);
+ cmsHANDLE hIT8;
+ cmsIT8* it8;
+ int type;
+
+ _cmsAssert(cFileName != NULL);
+
+ type = IsMyFile(cFileName);
if (type == 0) return NULL;
- hIT8 = cmsIT8Alloc();
- it8 = (LPIT8) hIT8;
+ hIT8 = cmsIT8Alloc(ContextID);
+ it8 = (cmsIT8*) hIT8;
if (!hIT8) return NULL;
@@ -2344,8 +2257,8 @@
}
- strncpy(it8->FileStack[0]->FileName, cFileName, MAX_PATH-1);
- it8->FileStack[0]->FileName[MAX_PATH-1] = 0;
+ strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1);
+ it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0;
if (!ParseIT8(it8, type-1)) {
@@ -2357,28 +2270,41 @@
CookPointers(it8);
it8 ->nTable = 0;
- fclose(it8 ->FileStack[0]->Stream);
+ if (fclose(it8 ->FileStack[0]->Stream)!= 0) {
+ cmsIT8Free(hIT8);
+ return NULL;
+ }
+
return hIT8;
}
-int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE hIT8, char ***SampleNames)
+int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames)
{
- LPIT8 it8 = (LPIT8) hIT8;
- LPTABLE t = GetTable(it8);
-
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ TABLE* t;
+
+ _cmsAssert(hIT8 != NULL);
+
+ t = GetTable(it8);
+
+ if (SampleNames)
*SampleNames = t -> DataFormat;
- return t -> nSamples;
+ return t -> nSamples;
}
-int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames)
+cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames)
{
- LPIT8 it8 = (LPIT8) hIT8;
- LPKEYVALUE p;
- int n;
- const char **Props;
- LPTABLE t = GetTable(it8);
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ KEYVALUE* p;
+ cmsUInt32Number n;
+ char **Props;
+ TABLE* t;
+
+ _cmsAssert(hIT8 != NULL);
+
+ t = GetTable(it8);
// Pass#1 - count properties
@@ -2388,7 +2314,7 @@
}
- Props = (const char **) AllocChunk(it8, sizeof(char *) * n);
+ Props = (char **) AllocChunk(it8, sizeof(char *) * n);
// Pass#2 - Fill pointers
n = 0;
@@ -2400,13 +2326,18 @@
return n;
}
-int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
+cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
{
- LPIT8 it8 = (LPIT8) hIT8;
- LPKEYVALUE p, tmp;
- int n;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ KEYVALUE *p, *tmp;
+ cmsUInt32Number n;
const char **Props;
- LPTABLE t = GetTable(it8);
+ TABLE* t;
+
+ _cmsAssert(hIT8 != NULL);
+
+
+ t = GetTable(it8);
if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) {
*SubpropertyNames = 0;
@@ -2436,11 +2367,11 @@
}
static
-int LocatePatch(LPIT8 it8, const char* cPatch)
+int LocatePatch(cmsIT8* it8, const char* cPatch)
{
int i;
const char *data;
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
for (i=0; i < t-> nPatches; i++) {
@@ -2448,7 +2379,7 @@
if (data != NULL) {
- if (stricmp(data, cPatch) == 0)
+ if (cmsstrcasecmp(data, cPatch) == 0)
return i;
}
}
@@ -2459,62 +2390,65 @@
static
-int LocateEmptyPatch(LPIT8 it8)
+int LocateEmptyPatch(cmsIT8* it8)
{
int i;
const char *data;
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
for (i=0; i < t-> nPatches; i++) {
data = GetData(it8, i, t->SampleID);
if (data == NULL)
- return i;
-
- }
-
- return -1;
+ return i;
+
+ }
+
+ return -1;
}
static
-int LocateSample(LPIT8 it8, const char* cSample)
+int LocateSample(cmsIT8* it8, const char* cSample)
{
int i;
const char *fld;
- LPTABLE t = GetTable(it8);
+ TABLE* t = GetTable(it8);
for (i=0; i < t->nSamples; i++) {
fld = GetDataFormat(it8, i);
- if (stricmp(fld, cSample) == 0)
+ if (cmsstrcasecmp(fld, cSample) == 0)
return i;
}
-
- // SynError(it8, "Couldn't find data field %s\n", cSample);
return -1;
}
-int LCMSEXPORT cmsIT8GetDataFormat(LCMSHANDLE hIT8, const char* cSample)
+int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ _cmsAssert(hIT8 != NULL);
+
return LocateSample(it8, cSample);
}
-const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE hIT8, int row, int col)
+const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ _cmsAssert(hIT8 != NULL);
return GetData(it8, row, col);
}
-double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE hIT8, int row, int col)
+cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col)
{
const char* Buffer;
@@ -2530,19 +2464,23 @@
}
-LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val)
+cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ _cmsAssert(hIT8 != NULL);
return SetData(it8, row, col, Val);
}
-LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val)
+cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
char Buff[256];
+ _cmsAssert(hIT8 != NULL);
+
sprintf(Buff, it8->DoubleFormatter, Val);
return SetData(it8, row, col, Buff);
@@ -2550,18 +2488,18 @@
-const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE hIT8, const char* cPatch, const char* cSample)
+const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
int iField, iSet;
+ _cmsAssert(hIT8 != NULL);
iField = LocateSample(it8, cSample);
if (iField < 0) {
return NULL;
}
-
iSet = LocatePatch(it8, cPatch);
if (iSet < 0) {
return NULL;
@@ -2571,7 +2509,7 @@
}
-double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE it8, const char* cPatch, const char* cSample)
+cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* cSample)
{
const char* Buffer;
@@ -2589,100 +2527,109 @@
-LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch,
- const char* cSample,
- const char *Val)
+cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
int iField, iSet;
- LPTABLE t = GetTable(it8);
-
+ TABLE* t;
+
+ _cmsAssert(hIT8 != NULL);
+
+ t = GetTable(it8);
iField = LocateSample(it8, cSample);
if (iField < 0)
return FALSE;
-
-
- if (t-> nPatches == 0) {
-
- AllocateDataFormat(it8);
- AllocateDataSet(it8);
- CookPointers(it8);
- }
-
-
- if (stricmp(cSample, "SAMPLE_ID") == 0)
- {
-
- iSet = LocateEmptyPatch(it8);
- if (iSet < 0) {
- return SynError(it8, "Couldn't add more patches '%s'\n", cPatch);
- }
-
- iField = t -> SampleID;
+ if (t-> nPatches == 0) {
+
+ AllocateDataFormat(it8);
+ AllocateDataSet(it8);
+ CookPointers(it8);
+ }
+
+ if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) {
+
+ iSet = LocateEmptyPatch(it8);
+ if (iSet < 0) {
+ return SynError(it8, "Couldn't add more patches '%s'\n", cPatch);
}
- else {
- iSet = LocatePatch(it8, cPatch);
- if (iSet < 0) {
- return FALSE;
- }
+
+ iField = t -> SampleID;
+ }
+ else {
+ iSet = LocatePatch(it8, cPatch);
+ if (iSet < 0) {
+ return FALSE;
}
-
- return SetData(it8, iSet, iField, Val);
+ }
+
+ return SetData(it8, iSet, iField, Val);
}
-LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch,
- const char* cSample,
- double Val)
+cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch,
+ const char* cSample,
+ cmsFloat64Number Val)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
char Buff[256];
- snprintf(Buff, 255, it8->DoubleFormatter, Val);
- return cmsIT8SetData(hIT8, cPatch, cSample, Buff);
-
+ _cmsAssert(hIT8 != NULL);
+
+ snprintf(Buff, 255, it8->DoubleFormatter, Val);
+ return cmsIT8SetData(hIT8, cPatch, cSample, Buff);
}
// Buffer should get MAXSTR at least
-const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer)
+const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer)
{
- LPIT8 it8 = (LPIT8) hIT8;
- LPTABLE t = GetTable(it8);
- char* Data = GetData(it8, nPatch, t->SampleID);
-
- if (!Data) return NULL;
- if (!buffer) return Data;
-
- strncpy(buffer, Data, MAXSTR-1);
- buffer[MAXSTR-1] = 0;
- return buffer;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ TABLE* t;
+ char* Data;
+
+ _cmsAssert(hIT8 != NULL);
+
+ t = GetTable(it8);
+ Data = GetData(it8, nPatch, t->SampleID);
+
+ if (!Data) return NULL;
+ if (!buffer) return Data;
+
+ strncpy(buffer, Data, MAXSTR-1);
+ buffer[MAXSTR-1] = 0;
+ return buffer;
}
-int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cPatch)
+int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch)
{
- return LocatePatch((LPIT8)hIT8, cPatch);
+ _cmsAssert(hIT8 != NULL);
+
+ return LocatePatch((cmsIT8*)hIT8, cPatch);
}
-int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE hIT8)
+cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8)
{
- LPIT8 it8 = (LPIT8) hIT8;
-
- return it8 ->TablesCount;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ _cmsAssert(hIT8 != NULL);
+
+ return it8 ->TablesCount;
}
// This handles the "LABEL" extension.
// Label, nTable, Type
-int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType)
+int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType)
{
const char* cLabelFld;
char Type[256], Label[256];
int nTable;
+ _cmsAssert(hIT8 != NULL);
+
if (cField != NULL && *cField == 0)
cField = "LABEL";
@@ -2700,18 +2647,21 @@
if (ExpectedType) {
- if (stricmp(Type, ExpectedType) != 0) return -1;
+ if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1;
}
return cmsIT8SetTable(hIT8, nTable);
}
-LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample)
+cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample)
{
- LPIT8 it8 = (LPIT8) hIT8;
-
- int pos = LocateSample(it8, cSample);
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+ int pos;
+
+ _cmsAssert(hIT8 != NULL);
+
+ pos = LocateSample(it8, cSample);
if(pos == -1)
return FALSE;
@@ -2720,9 +2670,11 @@
}
-void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE hIT8, const char* Formatter)
+void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
{
- LPIT8 it8 = (LPIT8) hIT8;
+ cmsIT8* it8 = (cmsIT8*) hIT8;
+
+ _cmsAssert(hIT8 != NULL);
if (Formatter == NULL)
strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,178 +49,117 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-#include "lcms.h"
-
-
-
-
-/*
- This module provides conversion stages for handling intents.
-
-The chain of evaluation in a transform is:
-
- PCS1 PCS2 PCS3 PCS4
-
-|From | |From | |Conversion | |Preview | |Gamut | |Conversion | |To | |To |
-|Input|->|Device|->|Stage 1 |->|handling|->|Checking|->|Stage 2 |->|Device|->|output |
-
--------- ------- ------------- --------- ---------- ------------- ------- ---------
-
- AToB0 prew0 gamut BToA0
-Formatting LUT Adjusting LUT LUT Adjusting LUT Formatting
- Intent Intent 1 intent intent Intent 2 Intent
-
-
-Some of these LUT may be missing
-
-There are two intents involved here, the intent of the transform itself, and the
-intent the proof is being done, if is the case. Since the first intent is to be
-applied to preview, is the proofing intent. The second intent identifies the
-transform intent. Input data of any stage is taked as relative colorimetric
-always.
-
-
-NOTES: V4 states than perceptual & saturation intents between mixed v2 & v4 profiles should
-scale PCS from a black point equal to ZERO in v2 profiles to the reference media black of
-perceptual v4 PCS. Since I found many v2 profiles to be using a perceptual intent with black
-point not zero at all, I'm implementing that as a black point compensation from whatever
-black from perceptal intent to the reference media black for v4 profiles.
-
-*/
-
+//
+//---------------------------------------------------------------------------------
+//
-
-
-int cdecl cmsChooseCnvrt(int Absolute,
- int Phase1, LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPMAT3 ChromaticAdaptationMatrixIn,
-
- int Phase2, LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 ChromaticAdaptationMatrixOut,
-
- int DoBlackPointCompensation,
- double AdaptationState,
- _cmsADJFN *fn1,
- LPWMAT3 wm, LPWVEC3 wof);
-
-
-// -------------------------------------------------------------------------
-
-// D50 - Widely used
-
-LCMSAPI LPcmsCIEXYZ LCMSEXPORT cmsD50_XYZ(void)
-{
- static cmsCIEXYZ D50XYZ = {D50X, D50Y, D50Z};
-
- return &D50XYZ;
-}
-
-LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void)
-{
- static cmsCIExyY D50xyY;
- cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
-
- return &D50xyY;
-}
-
-
-// ---------------- From LUT to LUT --------------------------
+#include "lcms2_internal.h"
-// Calculate m, offset Relativ -> Absolute undoing any chromatic
-// adaptation done by the profile.
+// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point
+// compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS
+// after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1)
+cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number Intents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
-#ifdef _MSC_VER
-#pragma warning(disable : 4100 4505)
-#endif
-
-
+//---------------------------------------------------------------------------------
-// join scalings to obtain:
-// relative input to absolute and then to relative output
-
+// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin.
+// Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric
static
-void Rel2RelStepAbsCoefs(double AdaptationState,
+cmsPipeline* DefaultICCintents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number Intents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
- LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPMAT3 ChromaticAdaptationMatrixIn,
+//---------------------------------------------------------------------------------
- LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 ChromaticAdaptationMatrixOut,
+// This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile
+// to do the trick (no devicelinks allowed at that position)
+static
+cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number Intents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
- LPMAT3 m, LPVEC3 of)
-{
+//---------------------------------------------------------------------------------
- VEC3 WtPtIn, WtPtInAdapted;
- VEC3 WtPtOut, WtPtOutAdapted;
- MAT3 Scale, m1, m2, m3;
-
- VEC3init(&WtPtIn, WhitePointIn->X, WhitePointIn->Y, WhitePointIn->Z);
- MAT3eval(&WtPtInAdapted, ChromaticAdaptationMatrixIn, &WtPtIn);
+// This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile
+// to do the trick (no devicelinks allowed at that position)
+static
+cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number Intents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
- VEC3init(&WtPtOut, WhitePointOut->X, WhitePointOut->Y, WhitePointOut->Z);
- MAT3eval(&WtPtOutAdapted, ChromaticAdaptationMatrixOut, &WtPtOut);
-
- VEC3init(&Scale.v[0], WtPtInAdapted.n[0] / WtPtOutAdapted.n[0], 0, 0);
- VEC3init(&Scale.v[1], 0, WtPtInAdapted.n[1] / WtPtOutAdapted.n[1], 0);
- VEC3init(&Scale.v[2], 0, 0, WtPtInAdapted.n[2] / WtPtOutAdapted.n[2]);
+//---------------------------------------------------------------------------------
- // Adaptation state
-
- if (AdaptationState == 1.0) {
-
- // Observer is fully adapted. Keep chromatic adaptation
-
- CopyMemory(m, &Scale, sizeof(MAT3));
+// This is a structure holding implementations for all supported intents.
+typedef struct _cms_intents_list {
- }
- else {
+ cmsUInt32Number Intent;
+ char Description[256];
+ cmsIntentFn Link;
+ struct _cms_intents_list* Next;
- // Observer is not adapted, undo the chromatic adaptation
- m1 = *ChromaticAdaptationMatrixIn;
- MAT3inverse(&m1, &m2);
-
- MAT3per(&m3, &m2, &Scale);
- MAT3per(m, &m3, ChromaticAdaptationMatrixOut);
- }
+} cmsIntentsList;
- VEC3init(of, 0.0, 0.0, 0.0);
+// Built-in intents
+static cmsIntentsList DefaultIntents[] = {
-}
+ { INTENT_PERCEPTUAL, "Perceptual", DefaultICCintents, &DefaultIntents[1] },
+ { INTENT_RELATIVE_COLORIMETRIC, "Relative colorimetric", DefaultICCintents, &DefaultIntents[2] },
+ { INTENT_SATURATION, "Saturation", DefaultICCintents, &DefaultIntents[3] },
+ { INTENT_ABSOLUTE_COLORIMETRIC, "Absolute colorimetric", DefaultICCintents, &DefaultIntents[4] },
+ { INTENT_PRESERVE_K_ONLY_PERCEPTUAL, "Perceptual preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[5] },
+ { INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC, "Relative colorimetric preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[6] },
+ { INTENT_PRESERVE_K_ONLY_SATURATION, "Saturation preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[7] },
+ { INTENT_PRESERVE_K_PLANE_PERCEPTUAL, "Perceptual preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[8] },
+ { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] },
+ { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL }
+};
-// The (in)famous black point compensation. Right now implemented as
-// a linear scaling in XYZ
+// A pointer to the begining of the list
+static cmsIntentsList *Intents = DefaultIntents;
+// Search the list for a suitable intent. Returns NULL if not found
static
-void ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 m, LPVEC3 of)
+cmsIntentsList* SearchIntent(cmsUInt32Number Intent)
{
+ cmsIntentsList* pt;
+
+ for (pt = Intents; pt != NULL; pt = pt -> Next)
+ if (pt ->Intent == Intent) return pt;
+
+ return NULL;
+}
-
- cmsCIEXYZ RelativeBlackPointIn, RelativeBlackPointOut;
- double ax, ay, az, bx, by, bz, tx, ty, tz;
-
- // At first, convert both black points to relative.
-
- cmsAdaptToIlluminant(&RelativeBlackPointIn, WhitePointIn, IlluminantIn, BlackPointIn);
- cmsAdaptToIlluminant(&RelativeBlackPointOut, WhitePointOut, IlluminantOut, BlackPointOut);
+// Black point compensation. Implemented as a linear scaling in XYZ. Black points
+// should come relative to the white point. Fills an matrix/offset element m
+// which is organized as a 4x4 matrix.
+static
+void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn,
+ const cmsCIEXYZ* BlackPointOut,
+ cmsMAT3* m, cmsVEC3* off)
+{
+ cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz;
// Now we need to compute a matrix plus an offset m and of such of
// [m]*bpin + off = bpout
@@ -229,438 +169,900 @@
// a = (bpout - D50) / (bpin - D50)
// b = - D50* (bpout - bpin) / (bpin - D50)
+ tx = BlackPointIn->X - cmsD50_XYZ()->X;
+ ty = BlackPointIn->Y - cmsD50_XYZ()->Y;
+ tz = BlackPointIn->Z - cmsD50_XYZ()->Z;
- tx = RelativeBlackPointIn.X - IlluminantIn ->X;
- ty = RelativeBlackPointIn.Y - IlluminantIn ->Y;
- tz = RelativeBlackPointIn.Z - IlluminantIn ->Z;
+ ax = (BlackPointOut->X - cmsD50_XYZ()->X) / tx;
+ ay = (BlackPointOut->Y - cmsD50_XYZ()->Y) / ty;
+ az = (BlackPointOut->Z - cmsD50_XYZ()->Z) / tz;
- ax = (RelativeBlackPointOut.X - IlluminantOut ->X) / tx;
- ay = (RelativeBlackPointOut.Y - IlluminantOut ->Y) / ty;
- az = (RelativeBlackPointOut.Z - IlluminantOut ->Z) / tz;
+ bx = - cmsD50_XYZ()-> X * (BlackPointOut->X - BlackPointIn->X) / tx;
+ by = - cmsD50_XYZ()-> Y * (BlackPointOut->Y - BlackPointIn->Y) / ty;
+ bz = - cmsD50_XYZ()-> Z * (BlackPointOut->Z - BlackPointIn->Z) / tz;
- bx = - IlluminantOut -> X * (RelativeBlackPointOut.X - RelativeBlackPointIn.X) / tx;
- by = - IlluminantOut -> Y * (RelativeBlackPointOut.Y - RelativeBlackPointIn.Y) / ty;
- bz = - IlluminantOut -> Z * (RelativeBlackPointOut.Z - RelativeBlackPointIn.Z) / tz;
+ _cmsVEC3init(&m ->v[0], ax, 0, 0);
+ _cmsVEC3init(&m ->v[1], 0, ay, 0);
+ _cmsVEC3init(&m ->v[2], 0, 0, az);
+ _cmsVEC3init(off, bx, by, bz);
+
+}
- MAT3identity(m);
+// Approximate a blackbody illuminant based on CHAD information
+static
+cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad)
+{
+ // Convert D50 across CHAD to get the absolute white point
+ cmsVEC3 d, s;
+ cmsCIEXYZ Dest;
+ cmsCIExyY DestChromaticity;
+ cmsFloat64Number TempK;
+
+ s.n[VX] = cmsD50_XYZ() -> X;
+ s.n[VY] = cmsD50_XYZ() -> Y;
+ s.n[VZ] = cmsD50_XYZ() -> Z;
+
+ _cmsMAT3eval(&d, Chad, &s);
+
+ Dest.X = d.n[VX];
+ Dest.Y = d.n[VY];
+ Dest.Z = d.n[VZ];
+
+ cmsXYZ2xyY(&DestChromaticity, &Dest);
+
+ if (!cmsTempFromWhitePoint(&TempK, &DestChromaticity))
+ return -1.0;
+
+ return TempK;
+}
+
+// Compute a CHAD based on a given temperature
+static
+void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
+{
+ cmsCIEXYZ White;
+ cmsCIExyY ChromaticityOfWhite;
+
+ cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp);
+ cmsxyY2XYZ(&White, &ChromaticityOfWhite);
+ _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White);
+
+}
+
+// Join scalings to obtain relative input to absolute and then to relative output.
+// Result is stored in a 3x3 matrix
+static
+cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState,
+ const cmsCIEXYZ* WhitePointIn,
+ const cmsMAT3* ChromaticAdaptationMatrixIn,
+ const cmsCIEXYZ* WhitePointOut,
+ const cmsMAT3* ChromaticAdaptationMatrixOut,
+ cmsMAT3* m)
+{
+ cmsMAT3 Scale, m1, m2, m3;
- m->v[VX].n[0] = ax;
- m->v[VY].n[1] = ay;
- m->v[VZ].n[2] = az;
+ // Adaptation state
+ if (AdaptationState == 1.0) {
+
+ // Observer is fully adapted. Keep chromatic adaptation.
+ // That is the standard V4 behaviour
+ _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0);
+ _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0);
+ _cmsVEC3init(&m->v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z);
+
+ }
+ else {
+
+ // Incomplete adaptation. This is an advanced feature.
+ _cmsVEC3init(&Scale.v[0], WhitePointIn->X / WhitePointOut->X, 0, 0);
+ _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0);
+ _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z);
+
+ m1 = *ChromaticAdaptationMatrixIn;
+ if (!_cmsMAT3inverse(&m1, &m2)) return FALSE;
+ _cmsMAT3per(&m3, &m2, &Scale);
+
+ // m3 holds CHAD from input white to D50 times abs. col. scaling
+ if (AdaptationState == 0.0) {
+
+ // Observer is not adapted, undo the chromatic adaptation
+ _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut);
- VEC3init(of, bx, by, bz);
+ } else {
+
+ cmsMAT3 MixedCHAD;
+ cmsFloat64Number TempSrc, TempDest, Temp;
+
+ TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); // K for source white
+ TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white
+
+ if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong
+
+ if (_cmsMAT3isIdentity(&Scale) && fabs(TempSrc - TempDest) < 0.01) {
+
+ _cmsMAT3identity(m);
+ return TRUE;
+ }
+
+ Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest;
+
+ // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD
+ Temp2CHAD(&MixedCHAD, Temp);
+
+ _cmsMAT3per(m, &m3, &MixedCHAD);
+ }
+
+ }
+ return TRUE;
}
-// Return TRUE if both m and of are empy -- "m" being identity and "of" being 0
+// Just to see if m matrix should be applied
+static
+cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off)
+{
+ cmsFloat64Number diff = 0;
+ cmsMAT3 Ident;
+ int i;
+
+ if (m == NULL && off == NULL) return TRUE; // NULL is allowed as an empty layer
+ if (m == NULL && off != NULL) return FALSE; // This is an internal error
+
+ _cmsMAT3identity(&Ident);
+
+ for (i=0; i < 3*3; i++)
+ diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]);
+ for (i=0; i < 3; i++)
+ diff += fabs(((cmsFloat64Number*)off)[i]);
+
+
+ return (diff < 0.002);
+}
+
+
+// Compute the conversion layer
static
-LCMSBOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of)
+cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[],
+ cmsUInt32Number Intent,
+ cmsBool BPC,
+ cmsFloat64Number AdaptationState,
+ cmsMAT3* m, cmsVEC3* off)
{
- WVEC3 wv0;
+
+ int k;
+
+ // m and off are set to identity and this is detected latter on
+ _cmsMAT3identity(m);
+ _cmsVEC3init(off, 0, 0, 0);
+
+ // If intent is abs. colorimetric,
+ if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) {
+
+ cmsCIEXYZ WhitePointIn, WhitePointOut;
+ cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut;
+
+ _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]);
+ _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]);
+
+ _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]);
+ _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]);
+
+ if (!ComputeAbsoluteIntent(AdaptationState,
+ &WhitePointIn, &ChromaticAdaptationMatrixIn,
+ &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE;
+
+ }
+ else {
+ // Rest of intents may apply BPC.
+
+ if (BPC) {
+
+ cmsCIEXYZ BlackPointIn, BlackPointOut;
+
+ cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0);
+ cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0);
+
+ // If black points are equal, then do nothing
+ if (BlackPointIn.X != BlackPointOut.X ||
+ BlackPointIn.Y != BlackPointOut.Y ||
+ BlackPointIn.Z != BlackPointOut.Z)
+ ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off);
+ }
+ }
+
+ // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0,
+ // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so
+ // we have first to convert from encoded to XYZ and then convert back to encoded.
+ // y = Mx + Off
+ // x = x'c
+ // y = M x'c + Off
+ // y = y'c; y' = y / c
+ // y' = (Mx'c + Off) /c = Mx' + (Off / c)
+
+ for (k=0; k < 3; k++) {
+ off ->n[k] /= MAX_ENCODEABLE_XYZ;
+ }
+
+ return TRUE;
+}
+
- VEC3initF(&wv0, 0, 0, 0);
+// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space
+static
+cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off)
+{
+ cmsFloat64Number* m_as_dbl = (cmsFloat64Number*) m;
+ cmsFloat64Number* off_as_dbl = (cmsFloat64Number*) off;
+
+ // Handle PCS mismatches. A specialized stage is added to the LUT in such case
+ switch (InPCS) {
+
+ case cmsSigXYZData: // Input profile operates in XYZ
+
+ switch (OutPCS) {
+
+ case cmsSigXYZData: // XYZ -> XYZ
+ if (!IsEmptyLayer(m, off))
+ cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+ break;
+
+ case cmsSigLabData: // XYZ -> Lab
+ if (!IsEmptyLayer(m, off))
+ cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+ cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
+ break;
+
+ default:
+ return FALSE; // Colorspace mismatch
+ }
+ break;
+
- if (!MAT3isIdentity(m, 0.00001)) return FALSE;
- if (!VEC3equal(of, &wv0, 0.00001)) return FALSE;
+ case cmsSigLabData: // Input profile operates in Lab
+
+ switch (OutPCS) {
+
+ case cmsSigXYZData: // Lab -> XYZ
+
+ cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID));
+ if (!IsEmptyLayer(m, off))
+ cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+ break;
+
+ case cmsSigLabData: // Lab -> Lab
+
+ if (!IsEmptyLayer(m, off)) {
+ cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID));
+ cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+ cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
+ }
+ break;
+
+ default:
+ return FALSE; // Mismatch
+ }
+ break;
+
+
+ // On colorspaces other than PCS, check for same space
+ default:
+ if (InPCS != OutPCS) return FALSE;
+ break;
+ }
return TRUE;
}
-
-
-// ----------------------------------------- Inter PCS conversions
-
-// XYZ to XYZ linear scaling. Aso used on Black point compensation
-
+// Is a given space compatible with another?
static
-void XYZ2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature b)
{
+ // If they are same, they are compatible.
+ if (a == b) return TRUE;
- WVEC3 a, r;
-
- a.n[0] = In[0] << 1;
- a.n[1] = In[1] << 1;
- a.n[2] = In[2] << 1;
+ // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other.
+ if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE;
+ if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE;
- MAT3evalW(&r, m, &a);
-
- Out[0] = _cmsClampWord((r.n[VX] + of->n[VX]) >> 1);
- Out[1] = _cmsClampWord((r.n[VY] + of->n[VY]) >> 1);
- Out[2] = _cmsClampWord((r.n[VZ] + of->n[VZ]) >> 1);
+ return FALSE;
}
-// XYZ to Lab, scaling first
-
+// Default handler for ICC-style intents
static
-void XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+cmsPipeline* DefaultICCintents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number TheIntents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
{
- WORD XYZ[3];
-
- XYZ2XYZ(In, XYZ, m, of);
- cmsXYZ2LabEncoded(XYZ, Out);
-}
-
-// Lab to XYZ, then scalling
-
-static
-void Lab2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
-{
- WORD XYZ[3];
-
- cmsLab2XYZEncoded(In, XYZ);
- XYZ2XYZ(XYZ, Out, m, of);
-}
+ cmsPipeline* Lut, *Result;
+ cmsHPROFILE hProfile;
+ cmsMAT3 m;
+ cmsVEC3 off;
+ cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace;
+ cmsProfileClassSignature ClassSig;
+ cmsUInt32Number i, Intent;
-// Lab to XYZ, scalling and then, back to Lab
+ // For safety
+ if (nProfiles == 0) return NULL;
-static
-void Lab2XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
-{
- WORD XYZ[3], XYZ2[3];
+ // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined'
+ Result = cmsPipelineAlloc(ContextID, 0, 0);
+ if (Result == NULL) return NULL;
- cmsLab2XYZEncoded(In, XYZ);
- XYZ2XYZ(XYZ, XYZ2, m, of);
- cmsXYZ2LabEncoded(XYZ2, Out);
-}
+ CurrentColorSpace = cmsGetColorSpace(hProfiles[0]);
-// ------------------------------------------------------------------
+ for (i=0; i < nProfiles; i++) {
-// Dispatcher for XYZ Relative LUT
+ cmsBool lIsDeviceLink, lIsInput;
-static
-int FromXYZRelLUT(int Absolute,
- LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPMAT3 ChromaticAdaptationMatrixIn,
+ hProfile = hProfiles[i];
+ ClassSig = cmsGetDeviceClass(hProfile);
+ lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass );
- int Phase2, LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 ChromaticAdaptationMatrixOut,
-
- int DoBlackPointCompensation,
- double AdaptationState,
- _cmsADJFN *fn1,
- LPMAT3 m, LPVEC3 of)
+ // First profile is used as input unless devicelink or abstract
+ if ((i == 0) && !lIsDeviceLink) {
+ lIsInput = TRUE;
+ }
+ else {
+ // Else use profile in the input direction if current space is not PCS
+ lIsInput = (CurrentColorSpace != cmsSigXYZData) &&
+ (CurrentColorSpace != cmsSigLabData);
+ }
-{
- switch (Phase2) {
+ Intent = TheIntents[i];
- // From relative XYZ to Relative XYZ.
+ if (lIsInput || lIsDeviceLink) {
- case XYZRel:
+ ColorSpaceIn = cmsGetColorSpace(hProfile);
+ ColorSpaceOut = cmsGetPCS(hProfile);
+ }
+ else {
- if (Absolute)
- {
- // From input relative to absolute, and then
- // back to output relative
+ ColorSpaceIn = cmsGetPCS(hProfile);
+ ColorSpaceOut = cmsGetColorSpace(hProfile);
+ }
- Rel2RelStepAbsCoefs(AdaptationState,
- BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- ChromaticAdaptationMatrixIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- ChromaticAdaptationMatrixOut,
- m, of);
- *fn1 = XYZ2XYZ;
+ if (!ColorSpaceIsCompatible(ColorSpaceIn, CurrentColorSpace)) {
+
+ cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "ColorSpace mismatch");
+ goto Error;
+ }
+
+ // If devicelink is found, then no custom intent is allowed and we can
+ // read the LUT to be applied. Settings don't apply here.
+ if (lIsDeviceLink) {
- }
- else
- {
- // XYZ Relative to XYZ relative, no op required
- *fn1 = NULL;
- if (DoBlackPointCompensation) {
+ // Get the involved LUT from the profile
+ Lut = _cmsReadDevicelinkLUT(hProfile, Intent);
+ if (Lut == NULL) goto Error;
- *fn1 = XYZ2XYZ;
- ComputeBlackPointCompensationFactors(BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- m, of);
-
- }
- }
- break;
+ // What about abstract profiles?
+ if (ClassSig == cmsSigAbstractClass && i > 0) {
+ if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error;
+ }
+ else {
+ _cmsMAT3identity(&m);
+ _cmsVEC3init(&off, 0, 0, 0);
+ }
- // From relative XYZ to Relative Lab
-
- case LabRel:
-
- // First pass XYZ to absolute, then to relative and
- // finally to Lab. I use here D50 for output in order
- // to prepare the "to Lab" conversion.
-
- if (Absolute)
- {
+ if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error;
- Rel2RelStepAbsCoefs(AdaptationState,
- BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- ChromaticAdaptationMatrixIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- ChromaticAdaptationMatrixOut,
- m, of);
+ }
+ else {
- *fn1 = XYZ2Lab;
-
- }
- else
- {
- // Just Convert to Lab
-
- MAT3identity(m);
- VEC3init(of, 0, 0, 0);
- *fn1 = XYZ2Lab;
+ if (lIsInput) {
+ // Input direction means non-pcs connection, so proceed like devicelinks
+ Lut = _cmsReadInputLUT(hProfile, Intent);
+ if (Lut == NULL) goto Error;
+ }
+ else {
- if (DoBlackPointCompensation) {
-
- ComputeBlackPointCompensationFactors(BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- m, of);
- }
- }
- break;
+ // Output direction means PCS connection. Intent may apply here
+ Lut = _cmsReadOutputLUT(hProfile, Intent);
+ if (Lut == NULL) goto Error;
- default: return FALSE;
- }
+ if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error;
+ if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error;
+
+ }
+ }
+
+ // Concatenate to the output LUT
+ cmsPipelineCat(Result, Lut);
+ cmsPipelineFree(Lut);
- return TRUE;
+ // Update current space
+ CurrentColorSpace = ColorSpaceOut;
+ }
+
+ return Result;
+
+Error:
+
+ if (Result != NULL) cmsPipelineFree(Result);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(dwFlags);
}
+// Wrapper for DLL calling convention
+cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number TheIntents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ return DefaultICCintents(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags);
+}
+
+// Black preserving intents ---------------------------------------------------------------------------------------------
+
+// Translate black-preserving intents to ICC ones
+static
+int TranslateNonICCIntents(int Intent)
+{
+ switch (Intent) {
+ case INTENT_PRESERVE_K_ONLY_PERCEPTUAL:
+ case INTENT_PRESERVE_K_PLANE_PERCEPTUAL:
+ return INTENT_PERCEPTUAL;
+
+ case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC:
+ case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC:
+ return INTENT_RELATIVE_COLORIMETRIC;
+
+ case INTENT_PRESERVE_K_ONLY_SATURATION:
+ case INTENT_PRESERVE_K_PLANE_SATURATION:
+ return INTENT_SATURATION;
+
+ default: return Intent;
+ }
+}
+
+// Sampler for Black-only preserving CMYK->CMYK transforms
+
+typedef struct {
+ cmsPipeline* cmyk2cmyk; // The original transform
+ cmsToneCurve* KTone; // Black-to-black tone curve
+
+} GrayOnlyParams;
+
+
+// Preserve black only if that is the only ink used
+static
+int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+{
+ GrayOnlyParams* bp = (GrayOnlyParams*) Cargo;
+
+ // If going across black only, keep black only
+ if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
+
+ // TAC does not apply because it is black ink!
+ Out[0] = Out[1] = Out[2] = 0;
+ Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]);
+ return TRUE;
+ }
+
+ // Keep normal transform for other colors
+ bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data);
+ return TRUE;
+}
+
+// This is the entry for black-preserving K-only intents, which are non-ICC
+static
+cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number TheIntents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ GrayOnlyParams bp;
+ cmsPipeline* Result;
+ cmsUInt32Number ICCIntents[256];
+ cmsStage* CLUT;
+ cmsUInt32Number i, nGridPoints;
-// From Lab Relative type LUT
+ // Sanity check
+ if (nProfiles < 1 || nProfiles > 255) return NULL;
-static
-int FromLabRelLUT(int Absolute,
- LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPMAT3 ChromaticAdaptationMatrixIn,
-
- int Phase2, LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 ChromaticAdaptationMatrixOut,
+ // Translate black-preserving intents to ICC ones
+ for (i=0; i < nProfiles; i++)
+ ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]);
- int DoBlackPointCompensation,
- double AdaptationState,
-
- _cmsADJFN *fn1,
- LPMAT3 m, LPVEC3 of)
-{
-
- switch (Phase2) {
+ // Check for non-cmyk profiles
+ if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+ cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData)
+ return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
- // From Lab Relative to XYZ Relative, very usual case
-
- case XYZRel:
+ memset(&bp, 0, sizeof(bp));
- if (Absolute) { // Absolute intent
-
- // From lab relative, to XYZ absolute, and then,
- // back to XYZ relative
+ // Allocate an empty LUT for holding the result
+ Result = cmsPipelineAlloc(ContextID, 4, 4);
+ if (Result == NULL) return NULL;
- Rel2RelStepAbsCoefs(AdaptationState,
- BlackPointIn,
- WhitePointIn,
- cmsD50_XYZ(),
- ChromaticAdaptationMatrixIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- ChromaticAdaptationMatrixOut,
- m, of);
+ // Create a LUT holding normal ICC transform
+ bp.cmyk2cmyk = DefaultICCintents(ContextID,
+ nProfiles,
+ ICCIntents,
+ hProfiles,
+ BPC,
+ AdaptationStates,
+ dwFlags);
- *fn1 = Lab2XYZ;
+ if (bp.cmyk2cmyk == NULL) goto Error;
- }
- else
- {
- // From Lab relative, to XYZ relative.
-
- *fn1 = Lab2XYZ;
- if (DoBlackPointCompensation) {
+ // Now, compute the tone curve
+ bp.KTone = _cmsBuildKToneCurve(ContextID,
+ 4096,
+ nProfiles,
+ ICCIntents,
+ hProfiles,
+ BPC,
+ AdaptationStates,
+ dwFlags);
- ComputeBlackPointCompensationFactors(BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- m, of);
-
- }
- }
- break;
+ if (bp.KTone == NULL) goto Error;
+ // How many gridpoints are we going to use?
+ nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags);
- case LabRel:
+ // Create the CLUT. 16 bits
+ CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL);
+ if (CLUT == NULL) goto Error;
+
+ // This is the one and only MPE in this LUT
+ cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT);
- if (Absolute) {
+ // Sample it. We cannot afford pre/post linearization this time.
+ if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0))
+ goto Error;
- // First pass to XYZ using the input illuminant
- // * InIlluminant / D50, then to absolute. Then
- // to relative, but for input
+ // Get rid of xform and tone curve
+ cmsPipelineFree(bp.cmyk2cmyk);
+ cmsFreeToneCurve(bp.KTone);
+
+ return Result;
- Rel2RelStepAbsCoefs(AdaptationState,
- BlackPointIn,
- WhitePointIn, IlluminantIn,
- ChromaticAdaptationMatrixIn,
- BlackPointOut,
- WhitePointOut, cmsD50_XYZ(),
- ChromaticAdaptationMatrixOut,
- m, of);
- *fn1 = Lab2XYZ2Lab;
- }
- else
- { // Lab -> Lab relative don't need any adjust unless
- // black point compensation
+Error:
+
+ if (bp.cmyk2cmyk != NULL) cmsPipelineFree(bp.cmyk2cmyk);
+ if (bp.KTone != NULL) cmsFreeToneCurve(bp.KTone);
+ if (Result != NULL) cmsPipelineFree(Result);
+ return NULL;
+
+}
+
+// K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------
- *fn1 = NULL;
- if (DoBlackPointCompensation) {
+typedef struct {
- *fn1 = Lab2XYZ2Lab;
- ComputeBlackPointCompensationFactors(BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- m, of);
+ cmsPipeline* cmyk2cmyk; // The original transform
+ cmsHTRANSFORM hProofOutput; // Output CMYK to Lab (last profile)
+ cmsHTRANSFORM cmyk2Lab; // The input chain
+ cmsToneCurve* KTone; // Black-to-black tone curve
+ cmsPipeline* LabK2cmyk; // The output profile
+ cmsFloat64Number MaxError;
+
+ cmsHTRANSFORM hRoundTrip;
+ cmsFloat64Number MaxTAC;
- }
- }
- break;
+} PreserveKPlaneParams;
- default: return FALSE;
- }
+// The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision
+static
+int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+{
+ int i;
+ cmsFloat32Number Inf[4], Outf[4];
+ cmsFloat32Number LabK[4];
+ cmsFloat64Number SumCMY, SumCMYK, Error, Ratio;
+ cmsCIELab ColorimetricLab, BlackPreservingLab;
+ PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo;
+
+ // Convert from 16 bits to floating point
+ for (i=0; i < 4; i++)
+ Inf[i] = (cmsFloat32Number) (In[i] / 65535.0);
+
+ // Get the K across Tone curve
+ LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]);
+
+ // If going across black only, keep black only
+ if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
+
+ Out[0] = Out[1] = Out[2] = 0;
+ Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0);
+ return TRUE;
+ }
+
+ // Try the original transform,
+ cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk);
+
+ // Store a copy of the floating point result into 16-bit
+ for (i=0; i < 4; i++)
+ Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0);
+
+ // Maybe K is already ok (mostly on K=0)
+ if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) {
+ return TRUE;
+ }
+
+ // K differ, mesure and keep Lab measurement for further usage
+ // this is done in relative colorimetric intent
+ cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1);
- return TRUE;
+ // Is not black only and the transform doesn't keep black.
+ // Obtain the Lab of output CMYK. After that we have Lab + K
+ cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1);
+
+ // Obtain the corresponding CMY using reverse interpolation
+ // (K is fixed in LabK[3])
+ if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) {
+
+ // Cannot find a suitable value, so use colorimetric xform
+ // which is already stored in Out[]
+ return TRUE;
+ }
+
+ // Make sure to pass thru K (which now is fixed)
+ Outf[3] = LabK[3];
+
+ // Apply TAC if needed
+ SumCMY = Outf[0] + Outf[1] + Outf[2];
+ SumCMYK = SumCMY + Outf[3];
+
+ if (SumCMYK > bp ->MaxTAC) {
+
+ Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY);
+ if (Ratio < 0)
+ Ratio = 0;
+ }
+ else
+ Ratio = 1.0;
+
+ Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C
+ Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M
+ Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y
+ Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0);
+
+ // Estimate the error (this goes 16 bits to Lab DBL)
+ cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1);
+ Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab);
+ if (Error > bp -> MaxError)
+ bp->MaxError = Error;
+
+ return TRUE;
}
+// This is the entry for black-plane preserving, which are non-ICC
+static
+cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number TheIntents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ PreserveKPlaneParams bp;
+ cmsPipeline* Result = NULL;
+ cmsUInt32Number ICCIntents[256];
+ cmsStage* CLUT;
+ cmsUInt32Number i, nGridPoints;
+ cmsHPROFILE hLab;
-// This function does calculate the necessary conversion operations
-// needed from transpassing data from a LUT to a LUT. The conversion
-// is modeled as a pointer of function and two coefficients, a and b
-// The function is actually called only if not null pointer is provided,
-// and the two paramaters are passed in. There are several types of
-// conversions, but basically they do a linear scalling and a interchange
+ // Sanity check
+ if (nProfiles < 1 || nProfiles > 255) return NULL;
+
+ // Translate black-preserving intents to ICC ones
+ for (i=0; i < nProfiles; i++)
+ ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]);
+ // Check for non-cmyk profiles
+ if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+ cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData)
+ return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
+
+ // Allocate an empty LUT for holding the result
+ Result = cmsPipelineAlloc(ContextID, 4, 4);
+ if (Result == NULL) return NULL;
-// Main dispatcher
+ memset(&bp, 0, sizeof(bp));
-int cmsChooseCnvrt(int Absolute,
- int Phase1, LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPMAT3 ChromaticAdaptationMatrixIn,
+ // We need the input LUT of the last profile, assuming this one is responsible of
+ // black generation. This LUT will be seached in inverse order.
+ bp.LabK2cmyk = _cmsReadInputLUT(hProfiles[nProfiles-1], INTENT_RELATIVE_COLORIMETRIC);
+ if (bp.LabK2cmyk == NULL) goto Cleanup;
+
+ // Get total area coverage (in 0..1 domain)
+ bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0;
- int Phase2, LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 ChromaticAdaptationMatrixOut,
+ // Create a LUT holding normal ICC transform
+ bp.cmyk2cmyk = DefaultICCintents(ContextID,
+ nProfiles,
+ ICCIntents,
+ hProfiles,
+ BPC,
+ AdaptationStates,
+ dwFlags);
- int DoBlackPointCompensation,
- double AdaptationState,
- _cmsADJFN *fn1,
- LPWMAT3 wm, LPWVEC3 wof)
-{
-
- int rc;
- MAT3 m;
- VEC3 of;
+ // Now the tone curve
+ bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles,
+ ICCIntents,
+ hProfiles,
+ BPC,
+ AdaptationStates,
+ dwFlags);
- MAT3identity(&m);
- VEC3init(&of, 0, 0, 0);
-
- switch (Phase1) {
-
- // Input LUT is giving XYZ relative values.
+ // To measure the output, Last profile to Lab
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
+ CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL,
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
- case XYZRel: rc = FromXYZRelLUT(Absolute,
- BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- ChromaticAdaptationMatrixIn,
- Phase2,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- ChromaticAdaptationMatrixOut,
- DoBlackPointCompensation,
- AdaptationState,
- fn1, &m, &of);
- break;
+ // Same as anterior, but lab in the 0..1 range
+ bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
+ FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab,
+ FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4),
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
+ cmsCloseProfile(hLab);
+ // Error estimation (for debug only)
+ bp.MaxError = 0;
+
+ // How many gridpoints are we going to use?
+ nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags);
- // Input LUT is giving Lab relative values
+ CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL);
+ if (CLUT == NULL) goto Cleanup;
- case LabRel: rc = FromLabRelLUT(Absolute,
- BlackPointIn,
- WhitePointIn,
- IlluminantIn,
- ChromaticAdaptationMatrixIn,
- Phase2,
- BlackPointOut,
- WhitePointOut,
- IlluminantOut,
- ChromaticAdaptationMatrixOut,
- DoBlackPointCompensation,
- AdaptationState,
- fn1, &m, &of);
- break;
+ cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT);
+ cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0);
-
+Cleanup:
- // Unrecognized combination
-
- default: cmsSignalError(LCMS_ERRC_ABORTED, "(internal) Phase error");
- return FALSE;
-
- }
-
- MAT3toFix(wm, &m);
- VEC3toFix(wof, &of);
+ if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk);
+ if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab);
+ if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput);
- // Do some optimization -- discard conversion if identity parameters.
-
- if (*fn1 == XYZ2XYZ || *fn1 == Lab2XYZ2Lab) {
+ if (bp.KTone) cmsFreeToneCurve(bp.KTone);
+ if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk);
- if (IdentityParameters(wm, wof))
- *fn1 = NULL;
- }
-
-
- return rc;
+ return Result;
}
+// Link routines ------------------------------------------------------------------------------------------------------
+// Chain several profiles into a single LUT. It just checks the parameters and then calls the handler
+// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the
+// rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable.
+cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number TheIntents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ cmsUInt32Number i;
+ cmsIntentsList* Intent;
+ // Make sure a reasonable number of profiles is provided
+ if (nProfiles <= 0 || nProfiles > 255) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't link '%d' profiles", nProfiles);
+ return NULL;
+ }
+
+ for (i=0; i < nProfiles; i++) {
+
+ // Check if black point is really needed or allowed. Note that
+ // following Adobe's document:
+ // BPC does not apply to devicelink profiles, nor to abs colorimetric,
+ // and applies always on V4 perceptual and saturation.
+
+ if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC)
+ BPC[i] = FALSE;
+
+ if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) {
+
+ // Force BPC for V4 profiles in perceptual and saturation
+ if (cmsGetProfileVersion(hProfiles[i]) >= 4.0)
+ BPC[i] = TRUE;
+ }
+ }
+
+ // Search for a handler. The first intent in the chain defines the handler. That would
+ // prevent using multiple custom intents in a multiintent chain, but the behaviour of
+ // this case would present some issues if the custom intent tries to do things like
+ // preserve primaries. This solution is not perfect, but works well on most cases.
+
+ Intent = SearchIntent(TheIntents[0]);
+ if (Intent == NULL) {
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]);
+ return NULL;
+ }
+
+ // Call the handler
+ return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// Get information about available intents. nMax is the maximum space for the supplied "Codes"
+// and "Descriptions" the function returns the total number of intents, which may be greater
+// than nMax, although the matrices are not populated beyond this level.
+cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
+{
+ cmsIntentsList* pt;
+ cmsUInt32Number nIntents;
+
+ for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next)
+ {
+ if (nIntents < nMax) {
+ if (Codes != NULL)
+ Codes[nIntents] = pt ->Intent;
+
+ if (Descriptions != NULL)
+ Descriptions[nIntents] = pt ->Description;
+ }
+
+ nIntents++;
+ }
+
+ return nIntents;
+}
+
+// The plug-in registration. User can add new intents or override default routines
+cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data)
+{
+ cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data;
+ cmsIntentsList* fl;
+
+ // Do we have to reset the intents?
+ if (Data == NULL) {
+
+ Intents = DefaultIntents;
+ return TRUE;
+ }
+
+ fl = SearchIntent(Plugin ->Intent);
+
+ if (fl == NULL) {
+ fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList));
+ if (fl == NULL) return FALSE;
+ }
+
+ fl ->Intent = Plugin ->Intent;
+ strncpy(fl ->Description, Plugin ->Description, 255);
+ fl ->Description[255] = 0;
+
+ fl ->Link = Plugin ->Link;
+
+ fl ->Next = Intents;
+ Intents = fl;
+
+ return TRUE;
+}
+
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,92 +49,399 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+#include "lcms2_internal.h"
+
+// I am so tired about incompatibilities on those functions that here are some replacements
+// that hopefully would be fully portable.
+
+// compare two strings ignoring case
+int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)
+{
+ register const unsigned char *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
-#include "lcms.h"
+ while (toupper(*us1) == toupper(*us2++))
+ if (*us1++ == '\0')
+ return (0);
+ return (toupper(*us1) - toupper(*--us2));
+}
+// long int because C99 specifies ftell in such way (7.19.9.2)
+long int CMSEXPORT cmsfilelength(FILE* f)
+{
+ long int n;
+
+ if (fseek(f, 0, SEEK_END) != 0) {
+ return -1;
+ }
+ n = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ return n;
+}
-// As a rule, only the functions visible from API can signal
-// errors.
+// Memory handling ------------------------------------------------------------------
+//
+// This is the interface to low-level memory management routines. By default a simple
+// wrapping to malloc/free/realloc is provided, although there is a limit on the max
+// amount of memoy that can be reclaimed. This is mostly as a safety feature to
+// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms
+// would never need.
+
+#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
+
+// User may override this behaviour by using a memory plug-in, which basically replaces
+// the default memory management functions. In this case, no check is performed and it
+// is up to the plug-in writter to keep in the safe side. There are only three functions
+// required to be implemented: malloc, realloc and free, although the user may want to
+// replace the optional mallocZero, calloc and dup as well.
+
+cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
+
+// *********************************************************************************
-void cdecl cmsSignalError(int ErrorCode, const char *ErrorText, ...);
+// This is the default memory allocation function. It does a very coarse
+// check of amout of memory, just to prevent exploits
+static
+void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
+{
+ if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum
+
+ return (void*) malloc(size);
-int LCMSEXPORT cmsErrorAction(int lAbort);
-void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn);
+ cmsUNUSED_PARAMETER(ContextID);
+}
+
+// Generic allocate & zero
+static
+void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size)
+{
+ void *pt = _cmsMalloc(ContextID, size);
+ if (pt == NULL) return NULL;
+
+ memset(pt, 0, size);
+ return pt;
+}
-// ******************************************************************
-
-static int nDoAbort = LCMS_ERROR_ABORT;
-static cmsErrorHandlerFunction UserErrorHandler = (cmsErrorHandlerFunction) NULL;
-
+// The default free function. The only check proformed is against NULL pointers
+static
+void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)
+{
+ // free(NULL) is defined a no-op by C99, therefore it is safe to
+ // avoid the check, but it is here just in case...
-int LCMSEXPORT cmsErrorAction(int nAction)
-{
- int nOld = nDoAbort;
- nDoAbort = nAction;
+ if (Ptr) free(Ptr);
- return nOld;
+ cmsUNUSED_PARAMETER(ContextID);
}
-void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn)
+// The default realloc function. Again it check for exploits. If Ptr is NULL,
+// realloc behaves the same way as malloc and allocates a new block of size bytes.
+static
+void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
{
- UserErrorHandler = Fn;
+
+ if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb
+
+ return realloc(Ptr, size);
+
+ cmsUNUSED_PARAMETER(ContextID);
}
-// Default error handler
+// The default calloc function. Allocates an array of num elements, each one of size bytes
+// all memory is initialized to zero.
+static
+void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
+{
+ cmsUInt32Number Total = num * size;
+
+ // Check for overflow
+ if (Total < num || Total < size) {
+ return NULL;
+ }
+
+ if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb
+
+ return _cmsMallocZero(ContextID, Total);
+}
+
+// Generic block duplication
+static
+void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size)
+{
+ void* mem;
+
+ if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb
+
+ mem = _cmsMalloc(ContextID, size);
+
+ if (mem != NULL && Org != NULL)
+ memmove(mem, Org, size);
+
+ return mem;
+}
+
+// Pointers to malloc and _cmsFree functions in current environment
+static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn;
+static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn;
+static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn;
+static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn;
+static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn;
+static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn;
+
+// Plug-in replacement entry
+cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data)
+{
+ cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;
+
+ // NULL forces to reset to defaults
+ if (Data == NULL) {
+
+ MallocPtr = _cmsMallocDefaultFn;
+ MallocZeroPtr= _cmsMallocZeroDefaultFn;
+ FreePtr = _cmsFreeDefaultFn;
+ ReallocPtr = _cmsReallocDefaultFn;
+ CallocPtr = _cmsCallocDefaultFn;
+ DupPtr = _cmsDupDefaultFn;
+ return TRUE;
+ }
+
+ // Check for required callbacks
+ if (Plugin -> MallocPtr == NULL ||
+ Plugin -> FreePtr == NULL ||
+ Plugin -> ReallocPtr == NULL) return FALSE;
+
+ // Set replacement functions
+ MallocPtr = Plugin -> MallocPtr;
+ FreePtr = Plugin -> FreePtr;
+ ReallocPtr = Plugin -> ReallocPtr;
+
+ if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr;
+ if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr;
+ if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr;
+
+ return TRUE;
+}
+
+// Generic allocate
+void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)
+{
+ return MallocPtr(ContextID, size);
+}
+
+// Generic allocate & zero
+void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)
+{
+ return MallocZeroPtr(ContextID, size);
+}
+
+// Generic calloc
+void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
+{
+ return CallocPtr(ContextID, num, size);
+}
+
+// Generic reallocate
+void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
+{
+ return ReallocPtr(ContextID, Ptr, size);
+}
+
+// Generic free memory
+void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr)
+{
+ if (Ptr != NULL) FreePtr(ContextID, Ptr);
+}
+
+// Generic block duplication
+void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)
+{
+ return DupPtr(ContextID, Org, size);
+}
+
+// ********************************************************************************************
+
+// Sub allocation takes care of many pointers of small size. The memory allocated in
+// this way have be freed at once. Next function allocates a single chunk for linked list
+// I prefer this method over realloc due to the big inpact on xput realloc may have if
+// memory is being swapped to disk. This approach is safer (although thats not true on any platform)
+static
+_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
+{
+ _cmsSubAllocator_chunk* chunk;
+
+ // Create the container
+ chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk));
+ if (chunk == NULL) return NULL;
+
+ // Initialize values
+ chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial);
+ if (chunk ->Block == NULL) {
+
+ // Something went wrong
+ _cmsFree(ContextID, chunk);
+ return NULL;
+ }
+
+ // 20K by default
+ if (Initial == 0)
+ Initial = 20*1024;
+
+ chunk ->BlockSize = Initial;
+ chunk ->Used = 0;
+ chunk ->next = NULL;
+
+ return chunk;
+}
+
+// The suballocated is nothing but a pointer to the first element in the list. We also keep
+// the thread ID in this structure.
+_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial)
+{
+ _cmsSubAllocator* sub;
+
+ // Create the container
+ sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator));
+ if (sub == NULL) return NULL;
+
+ sub ->ContextID = ContextID;
+
+ sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial);
+ if (sub ->h == NULL) {
+ _cmsFree(ContextID, sub);
+ return NULL;
+ }
+
+ return sub;
+}
-void cmsSignalError(int ErrorCode, const char *ErrorText, ...)
+// Get rid of whole linked list
+void _cmsSubAllocDestroy(_cmsSubAllocator* sub)
{
- va_list args;
+ _cmsSubAllocator_chunk *chunk, *n;
+
+ for (chunk = sub ->h; chunk != NULL; chunk = n) {
+
+ n = chunk->next;
+ if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block);
+ _cmsFree(sub ->ContextID, chunk);
+ }
- if (nDoAbort == LCMS_ERROR_IGNORE) return;
+ // Free the header
+ _cmsFree(sub ->ContextID, sub);
+}
+
- va_start(args, ErrorText);
+// Get a pointer to small memory block.
+void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)
+{
+ cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used;
+ cmsUInt8Number* ptr;
- if (UserErrorHandler != NULL) {
+ size = _cmsALIGNLONG(size);
+
+ // Check for memory. If there is no room, allocate a new chunk of double memory size.
+ if (size > Free) {
- char Buffer[1024];
+ _cmsSubAllocator_chunk* chunk;
+ cmsUInt32Number newSize;
+
+ newSize = sub -> h ->BlockSize * 2;
+ if (newSize < size) newSize = size;
- vsnprintf(Buffer, 1023, ErrorText, args);
- va_end(args);
+ chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize);
+ if (chunk == NULL) return NULL;
+
+ // Link list
+ chunk ->next = sub ->h;
+ sub ->h = chunk;
+
+ }
- if (UserErrorHandler(ErrorCode, Buffer)) {
+ ptr = sub -> h ->Block + sub -> h ->Used;
+ sub -> h -> Used += size;
+
+ return (void*) ptr;
+}
+
+// Error logging ******************************************************************
- return;
- }
- }
-
-#if defined( __CONSOLE__ ) || defined( NON_WINDOWS )
+// There is no error handling at all. When a funtion fails, it returns proper value.
+// For example, all create functions does return NULL on failure. Other return FALSE
+// It may be interesting, for the developer, to know why the function is failing.
+// for that reason, lcms2 does offer a logging function. This function does recive
+// a ENGLISH string with some clues on what is going wrong. You can show this
+// info to the end user, or just create some sort of log.
+// The logging function should NOT terminate the program, as this obviously can leave
+// resources. It is the programmer's responsability to check each function return code
+// to make sure it didn't fail.
- fprintf(stderr, "lcms: Error #%d; ", ErrorCode);
- vfprintf(stderr, ErrorText, args);
- fprintf(stderr, "\n");
- va_end(args);
+// Error messages are limited to MAX_ERROR_MESSAGE_LEN
+
+#define MAX_ERROR_MESSAGE_LEN 1024
+
+// ---------------------------------------------------------------------------------------------------------
+
+// This is our default log error
+static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
+
+// The current handler in actual environment
+static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction;
- if (nDoAbort == LCMS_ERROR_ABORT) exit(1);
-#else
- {
- char Buffer1[1024];
- char Buffer2[256];
+// The default error logger does nothing.
+static
+void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
+{
+ // fprintf(stderr, "[lcms]: %s\n", Text);
+ // fflush(stderr);
+
+ cmsUNUSED_PARAMETER(ContextID);
+ cmsUNUSED_PARAMETER(ErrorCode);
+ cmsUNUSED_PARAMETER(Text);
+}
- snprintf(Buffer1, 767, "Error #%x; ", ErrorCode);
- vsnprintf(Buffer2, 255, ErrorText, args);
- strcat(Buffer1, Buffer2);
- MessageBox(NULL, Buffer1, "Little cms",
- MB_OK|MB_ICONSTOP|MB_TASKMODAL);
- va_end(args);
+// Change log error
+void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn)
+{
+ if (Fn == NULL)
+ LogErrorHandler = DefaultLogErrorHandlerFunction;
+ else
+ LogErrorHandler = Fn;
+}
- if (nDoAbort == LCMS_ERROR_ABORT) {
+// Log an error
+// ErrorText is a text holding an english description of error.
+void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...)
+{
+ va_list args;
+ char Buffer[MAX_ERROR_MESSAGE_LEN];
+
+ va_start(args, ErrorText);
+ vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);
+ va_end(args);
-#ifdef __BORLANDC__
- _cexit();
-#endif
+ // Call handler
+ LogErrorHandler(ContextID, ErrorCode, Buffer);
+}
+
+// Utility function to print signatures
+void _cmsTagSignature2String(char String[5], cmsTagSignature sig)
+{
+ cmsUInt32Number be;
- FatalAppExit(0, "lcms is terminating application");
- }
- }
-#endif
+ // Convert to big endian
+ be = _cmsAdjustEndianess32((cmsUInt32Number) sig);
+
+ // Move chars
+ memmove(String, &be, 4);
+
+ // Make sure of terminator
+ String[4] = 0;
}
+
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,448 +49,851 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+//
+//---------------------------------------------------------------------------------
+//
+#include "lcms2_internal.h"
-#include "lcms.h"
-
-// Gamma handling.
+// Tone curves are powerful constructs that can contain curves specified in diverse ways.
+// The curve is stored in segments, where each segment can be sampled or specified by parameters.
+// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation,
+// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes,
+// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function,
+// the plug-in should provide the type id, how many parameters each type has, and a pointer to
+// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will
+// be called with the type id as a negative value, and a sampled version of the reversed curve
+// will be built.
-LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries);
-void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma);
-void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3]);
-LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma);
-LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src);
-LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma);
-LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]);
-LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma);
-LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints);
-LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda);
+// ----------------------------------------------------------------- Implementation
+// Maxim number of nodes
+#define MAX_NODES_IN_CURVE 4097
+#define MINUS_INF (-1E22F)
+#define PLUS_INF (+1E22F)
+
+// The list of supported parametric curves
+typedef struct _cmsParametricCurvesCollection_st {
-LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints);
+ int nFunctions; // Number of supported functions in this chunk
+ int FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types
+ int ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function
+ cmsParametricCurveEvaluator Evaluator; // The evaluator
+
+ struct _cmsParametricCurvesCollection_st* Next; // Next in list
+
+} _cmsParametricCurvesCollection;
-// Sampled curves
+// This is the default (built-in) evaluator
+static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R);
-LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems);
-void cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p);
-void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max);
-void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max);
-LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda);
-void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints);
+// The built-in list
+static _cmsParametricCurvesCollection DefaultCurves = {
+ 9, // # of curve types
+ { 1, 2, 3, 4, 5, 6, 7, 8, 108 }, // Parametric curve ID
+ { 1, 3, 4, 5, 7, 4, 5, 5, 1 }, // Parameters by type
+ DefaultEvalParametricFn, // Evaluator
+ NULL // Next in chain
+};
+
+// The linked list head
+static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves;
+
+// As a way to install new parametric curves
+cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data)
+{
+ cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data;
+ _cmsParametricCurvesCollection* fl;
+
+ if (Data == NULL) {
-LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints);
+ ParametricCurves = &DefaultCurves;
+ return TRUE;
+ }
-double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t);
-double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double Thereshold);
+ fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(sizeof(_cmsParametricCurvesCollection));
+ if (fl == NULL) return FALSE;
+
+ // Copy the parameters
+ fl ->Evaluator = Plugin ->Evaluator;
+ fl ->nFunctions = Plugin ->nFunctions;
-// ----------------------------------------------------------------------------------------
+ // Make sure no mem overwrites
+ if (fl ->nFunctions > MAX_TYPES_IN_LCMS_PLUGIN)
+ fl ->nFunctions = MAX_TYPES_IN_LCMS_PLUGIN;
+ // Copy the data
+ memmove(fl->FunctionTypes, Plugin ->FunctionTypes, fl->nFunctions * sizeof(cmsUInt32Number));
+ memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number));
-#define MAX_KNOTS 4096
-typedef float vec[MAX_KNOTS+1];
+ // Keep linked list
+ fl ->Next = ParametricCurves;
+ ParametricCurves = fl;
+
+ // All is ok
+ return TRUE;
+}
-// Ciclic-redundant-check for assuring table is a true representation of parametric curve
-
-// The usual polynomial, which is used for AAL5, FDDI, and probably Ethernet
-#define QUOTIENT 0x04c11db7
-
+// Search in type list, return position or -1 if not found
static
-unsigned int Crc32(unsigned int result, LPVOID ptr, int len)
+int IsInSet(int Type, _cmsParametricCurvesCollection* c)
{
- int i,j;
- BYTE octet;
- LPBYTE data = (LPBYTE) ptr;
+ int i;
- for (i=0; i < len; i++) {
+ for (i=0; i < c ->nFunctions; i++)
+ if (abs(Type) == c ->FunctionTypes[i]) return i;
+
+ return -1;
+}
+
- octet = *data++;
-
- for (j=0; j < 8; j++) {
-
- if (result & 0x80000000) {
+// Search for the collection which contains a specific type
+static
+_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index)
+{
+ _cmsParametricCurvesCollection* c;
+ int Position;
- result = (result << 1) ^ QUOTIENT ^ (octet >> 7);
- }
- else
- {
- result = (result << 1) ^ (octet >> 7);
- }
- octet <<= 1;
+ for (c = ParametricCurves; c != NULL; c = c ->Next) {
+
+ Position = IsInSet(Type, c);
+
+ if (Position != -1) {
+ if (index != NULL)
+ *index = Position;
+ return c;
}
}
- return result;
+ return NULL;
}
-// Get CRC of gamma table
+// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case
+// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the
+// optimization curve is given. Both features simultaneously is an error
+static
+cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries,
+ cmsInt32Number nSegments, const cmsCurveSegment* Segments,
+ const cmsUInt16Number* Values)
+{
+ cmsToneCurve* p;
+ int i;
+
+ // We allow huge tables, which are then restricted for smoothing operations
+ if (nEntries > 65530 || nEntries < 0) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries");
+ return NULL;
+ }
-unsigned int _cmsCrc32OfGammaTable(LPGAMMATABLE Table)
-{
- unsigned int crc = ~0U;
+ if (nEntries <= 0 && nSegments <= 0) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table");
+ return NULL;
+ }
+
+ // Allocate all required pointers, etc.
+ p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve));
+ if (!p) return NULL;
+
+ // In this case, there are no segments
+ if (nSegments <= 0) {
+ p ->Segments = NULL;
+ p ->Evals = NULL;
+ }
+ else {
+ p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment));
+ if (p ->Segments == NULL) goto Error;
+
+ p ->Evals = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator));
+ if (p ->Evals == NULL) goto Error;
+ }
+
+ p -> nSegments = nSegments;
- crc = Crc32(crc, &Table -> Seed.Type, sizeof(int));
- crc = Crc32(crc, Table ->Seed.Params, sizeof(double)*10);
- crc = Crc32(crc, &Table ->nEntries, sizeof(int));
- crc = Crc32(crc, Table ->GammaTable, sizeof(WORD) * Table -> nEntries);
+ // This 16-bit table contains a limited precision representation of the whole curve and is kept for
+ // increasing xput on certain operations.
+ if (nEntries <= 0) {
+ p ->Table16 = NULL;
+ }
+ else {
+ p ->Table16 = (cmsUInt16Number*) _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number));
+ if (p ->Table16 == NULL) goto Error;
+ }
+
+ p -> nEntries = nEntries;
+
+ // Initialize members if requested
+ if (Values != NULL && (nEntries > 0)) {
+
+ for (i=0; i < nEntries; i++)
+ p ->Table16[i] = Values[i];
+ }
+
+ // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it
+ // is placed in advance to maximize performance.
+ if (Segments != NULL && (nSegments > 0)) {
+
+ _cmsParametricCurvesCollection *c;
+
+ p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*));
+ if (p ->SegInterp == NULL) goto Error;
- return ~crc;
+ for (i=0; i< nSegments; i++) {
+
+ // Type 0 is a special marker for table-based curves
+ if (Segments[i].Type == 0)
+ p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT);
+
+ memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment));
+
+ if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL)
+ p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints);
+ else
+ p ->Segments[i].SampledPoints = NULL;
+
+ c = GetParametricCurveByType(Segments[i].Type, NULL);
+ if (c != NULL)
+ p ->Evals[i] = c ->Evaluator;
+ }
+ }
+
+ p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS);
+ return p;
+
+Error:
+ if (p -> Segments) _cmsFree(ContextID, p ->Segments);
+ if (p -> Evals) _cmsFree(ContextID, p -> Evals);
+ if (p ->Table16) _cmsFree(ContextID, p ->Table16);
+ _cmsFree(ContextID, p);
+ return NULL;
}
-LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries)
+// Parametric Fn using floating point
+static
+cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R)
{
- LPGAMMATABLE p;
- size_t size;
+ cmsFloat64Number e, Val, disc;
+
+ switch (Type) {
+
+ // X = Y ^ Gamma
+ case 1:
+ if (R < 0)
+ Val = 0;
+ else
+ Val = pow(R, Params[0]);
+ break;
+
+ // Type 1 Reversed: X = Y ^1/gamma
+ case -1:
+ if (R < 0)
+ Val = 0;
+ else
+ Val = pow(R, 1/Params[0]);
+ break;
+
+ // CIE 122-1966
+ // Y = (aX + b)^Gamma | X >= -b/a
+ // Y = 0 | else
+ case 2:
+ disc = -Params[2] / Params[1];
+
+ if (R >= disc ) {
+
+ e = Params[1]*R + Params[2];
+
+ if (e > 0)
+ Val = pow(e, Params[0]);
+ else
+ Val = 0;
+ }
+ else
+ Val = 0;
+ break;
+
+ // Type 2 Reversed
+ // X = (Y ^1/g - b) / a
+ case -2:
+ if (R < 0)
+ Val = 0;
+ else
+ Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
+
+ if (Val < 0)
+ Val = 0;
+ break;
+
- if (nEntries > 65530 || nEntries <= 0) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't create gammatable of more than 65530 entries");
- return NULL;
- }
+ // IEC 61966-3
+ // Y = (aX + b)^Gamma | X <= -b/a
+ // Y = c | else
+ case 3:
+ disc = -Params[2] / Params[1];
+ if (disc < 0)
+ disc = 0;
+
+ if (R >= disc) {
+
+ e = Params[1]*R + Params[2];
+
+ if (e > 0)
+ Val = pow(e, Params[0]) + Params[3];
+ else
+ Val = 0;
+ }
+ else
+ Val = Params[3];
+ break;
+
+
+ // Type 3 reversed
+ // X=((Y-c)^1/g - b)/a | (Y>=c)
+ // X=-b/a | (Y<c)
+ case -3:
+ if (R >= Params[3]) {
+
+ e = R - Params[3];
+
+ if (e > 0)
+ Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1];
+ else
+ Val = 0;
+ }
+ else {
+ Val = -Params[2] / Params[1];
+ }
+ break;
+
+
+ // IEC 61966-2.1 (sRGB)
+ // Y = (aX + b)^Gamma | X >= d
+ // Y = cX | X < d
+ case 4:
+ if (R >= Params[4]) {
+
+ e = Params[1]*R + Params[2];
+
+ if (e > 0)
+ Val = pow(e, Params[0]);
+ else
+ Val = 0;
+ }
+ else
+ Val = R * Params[3];
+ break;
+
+ // Type 4 reversed
+ // X=((Y^1/g-b)/a) | Y >= (ad+b)^g
+ // X=Y/c | Y< (ad+b)^g
+ case -4:
+ e = Params[1] * Params[4] + Params[2];
+ if (e < 0)
+ disc = 0;
+ else
+ disc = pow(e, Params[0]);
- size = sizeof(GAMMATABLE) + (sizeof(WORD) * (nEntries-1));
+ if (R >= disc) {
+
+ Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
+ }
+ else {
+ Val = R / Params[3];
+ }
+ break;
+
+
+ // Y = (aX + b)^Gamma + e | X >= d
+ // Y = cX + f | X < d
+ case 5:
+ if (R >= Params[4]) {
+
+ e = Params[1]*R + Params[2];
+
+ if (e > 0)
+ Val = pow(e, Params[0]) + Params[5];
+ else
+ Val = 0;
+ }
+ else
+ Val = R*Params[3] + Params[6];
+ break;
+
- p = (LPGAMMATABLE) _cmsMalloc(size);
- if (!p) return NULL;
+ // Reversed type 5
+ // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f
+ // X=(Y-f)/c | else
+ case -5:
+
+ disc = Params[3] * Params[4] + Params[6];
+ if (R >= disc) {
+
+ e = R - Params[5];
+ if (e < 0)
+ Val = 0;
+ else
+ Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1];
+ }
+ else {
+ Val = (R - Params[6]) / Params[3];
+ }
+ break;
+
+
+ // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf
+ // Type 6 is basically identical to type 5 without d
+
+ // Y = (a * X + b) ^ Gamma + c
+ case 6:
+ e = Params[1]*R + Params[2];
+
+ if (e < 0)
+ Val = 0;
+ else
+ Val = pow(e, Params[0]) + Params[3];
+ break;
- ZeroMemory(p, size);
+ // ((Y - c) ^1/Gamma - b) / a
+ case -6:
+ e = R - Params[3];
+ if (e < 0)
+ Val = 0;
+ else
+ Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1];
+ break;
+
+
+ // Y = a * log (b * X^Gamma + c) + d
+ case 7:
+
+ e = Params[2] * pow(R, Params[0]) + Params[3];
+ if (e <= 0)
+ Val = 0;
+ else
+ Val = Params[1]*log10(e) + Params[4];
+ break;
+
+ // (Y - d) / a = log(b * X ^Gamma + c)
+ // pow(10, (Y-d) / a) = b * X ^Gamma + c
+ // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X
+ case -7:
+ Val = pow((pow(10.0, (R-Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]);
+ break;
+
- p -> Seed.Type = 0;
- p -> nEntries = nEntries;
+ //Y = a * b^(c*X+d) + e
+ case 8:
+ Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]);
+ break;
+
+
+ // Y = (log((y-e) / a) / log(b) - d ) / c
+ // a=0, b=1, c=2, d=3, e=4,
+ case -8:
+
+ disc = R - Params[4];
+ if (disc < 0) Val = 0;
+ else
+ Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2];
+ break;
- return p;
+ // S-Shaped: (1 - (1-x)^1/g)^1/g
+ case 108:
+ Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]);
+ break;
+
+ // y = (1 - (1-x)^1/g)^1/g
+ // y^g = (1 - (1-x)^1/g)
+ // 1 - y^g = (1-x)^1/g
+ // (1 - y^g)^g = 1 - x
+ // 1 - (1 - y^g)^g
+ case -108:
+ Val = 1 - pow(1 - pow(R, Params[0]), Params[0]);
+ break;
+
+ default:
+ // Unsupported parametric curve. Should never reach here
+ return 0;
+ }
+
+ return Val;
}
-void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma)
+// Evaluate a segmented funtion for a single value. Return -1 if no valid segment found .
+// If fn type is 0, perform an interpolation on the table
+static
+cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
{
- if (Gamma) _cmsFree(Gamma);
-}
-
-
+ int i;
-void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3])
-{
- cmsFreeGamma(Gamma[0]);
- cmsFreeGamma(Gamma[1]);
- cmsFreeGamma(Gamma[2]);
- Gamma[0] = Gamma[1] = Gamma[2] = NULL;
-}
+ for (i = g ->nSegments-1; i >= 0 ; --i) {
+ // Check for domain
+ if ((R > g ->Segments[i].x0) && (R <= g ->Segments[i].x1)) {
+
+ // Type == 0 means segment is sampled
+ if (g ->Segments[i].Type == 0) {
-
-// Duplicate a gamma table
+ cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0);
+ cmsFloat32Number Out;
-LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE In)
-{
- LPGAMMATABLE Ptr;
- size_t size;
+ // Setup the table (TODO: clean that)
+ g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints;
+
+ g ->SegInterp[i] -> Interpolation.LerpFloat(&R1, &Out, g ->SegInterp[i]);
- Ptr = cmsAllocGamma(In -> nEntries);
- if (Ptr == NULL) return NULL;
+ return Out;
+ }
+ else
+ return g ->Evals[i](g->Segments[i].Type, g ->Segments[i].Params, R);
+ }
+ }
- size = sizeof(GAMMATABLE) + (sizeof(WORD) * (In -> nEntries-1));
-
- CopyMemory(Ptr, In, size);
- return Ptr;
+ return MINUS_INF;
}
-// Handle gamma using interpolation tables. The resulting curves can become
-// very stange, but are pleasent to eye.
-
-LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma,
- LPGAMMATABLE OutGamma)
+// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
+// floating point description empty.
+cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number Values[])
{
- register int i;
- L16PARAMS L16In, L16Out;
- LPWORD InPtr, OutPtr;
- LPGAMMATABLE p;
-
- p = cmsAllocGamma(256);
- if (!p) return NULL;
+ return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values);
+}
- cmsCalcL16Params(InGamma -> nEntries, &L16In);
- InPtr = InGamma -> GammaTable;
-
- cmsCalcL16Params(OutGamma -> nEntries, &L16Out);
- OutPtr = OutGamma-> GammaTable;
-
- for (i=0; i < 256; i++)
- {
- WORD wValIn, wValOut;
-
- wValIn = cmsLinearInterpLUT16(RGB_8_TO_16(i), InPtr, &L16In);
- wValOut = cmsReverseLinearInterpLUT16(wValIn, OutPtr, &L16Out);
-
- p -> GammaTable[i] = wValOut;
- }
-
- return p;
+static
+int EntriesByGamma(cmsFloat64Number Gamma)
+{
+ if (fabs(Gamma - 1.0) < 0.001) return 2;
+ return 4096;
}
+// Create a segmented gamma, fill the table
+cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
+ cmsInt32Number nSegments, const cmsCurveSegment Segments[])
+{
+ int i;
+ cmsFloat64Number R, Val;
+ cmsToneCurve* g;
+ int nGridPoints = 4096;
-// New method, using smoothed parametric curves. This works FAR better.
-// We want to get
-//
-// y = f(g^-1(x)) ; f = ingamma, g = outgamma
-//
-// And this can be parametrized as
-//
-// y = f(t)
-// x = g(t)
+ _cmsAssert(Segments != NULL);
+
+ // Optimizatin for identity curves.
+ if (nSegments == 1 && Segments[0].Type == 1) {
+
+ nGridPoints = EntriesByGamma(Segments[0].Params[0]);
+ }
+
+ g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL);
+ if (g == NULL) return NULL;
+
+ // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries
+ // for performance reasons. This table would normally not be used except on 8/16 bits transforms.
+ for (i=0; i < nGridPoints; i++) {
+
+ R = (cmsFloat64Number) i / (nGridPoints-1);
+ Val = EvalSegmentedFn(g, R);
-LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma,
- LPGAMMATABLE OutGamma, int nPoints)
+ // Round and saturate
+ g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0);
+ }
+
+ return g;
+}
+
+// Use a segmented curve to store the floating point table
+cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[])
{
+ cmsCurveSegment Seg[2];
+
+ // Initialize segmented curve part up to 0
+ Seg[0].x0 = -1;
+ Seg[0].x1 = 0;
+ Seg[0].Type = 6;
- LPSAMPLEDCURVE x, y, r;
- LPGAMMATABLE res;
+ Seg[0].Params[0] = 1;
+ Seg[0].Params[1] = 0;
+ Seg[0].Params[2] = 0;
+ Seg[0].Params[3] = 0;
+ Seg[0].Params[4] = 0;
- x = cmsConvertGammaToSampledCurve(InGamma, nPoints);
- y = cmsConvertGammaToSampledCurve(OutGamma, nPoints);
- r = cmsJoinSampledCurves(y, x, nPoints);
+ // From zero to any
+ Seg[1].x0 = 0;
+ Seg[1].x1 = 1.0;
+ Seg[1].Type = 0;
- // Does clean "hair"
- cmsSmoothSampledCurve(r, 0.001);
+ Seg[1].nGridPoints = nEntries;
+ Seg[1].SampledPoints = (cmsFloat32Number*) values;
+
+ return cmsBuildSegmentedToneCurve(ContextID, 2, Seg);
+}
- cmsClampSampledCurve(r, 0.0, 65535.0);
+// Parametric curves
+//
+// Parameters goes as: Curve, a, b, c, d, e, f
+// Type is the ICC type +1
+// if type is negative, then the curve is analyticaly inverted
+cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[])
+{
+ cmsCurveSegment Seg0;
+ int Pos = 0;
+ cmsUInt32Number size;
+ _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos);
- cmsFreeSampledCurve(x);
- cmsFreeSampledCurve(y);
+ _cmsAssert(Params != NULL);
- res = cmsConvertSampledCurveToGamma(r, 65535.0);
- cmsFreeSampledCurve(r);
+ if (c == NULL) {
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
+ return NULL;
+ }
+
+ memset(&Seg0, 0, sizeof(Seg0));
- return res;
+ Seg0.x0 = MINUS_INF;
+ Seg0.x1 = PLUS_INF;
+ Seg0.Type = Type;
+
+ size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number);
+ memmove(Seg0.Params, Params, size);
+
+ return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0);
}
-// Reverse a gamma table
-
-LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma)
+// Build a gamma table based on gamma constant
+cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma)
{
- register int i;
- L16PARAMS L16In;
- LPWORD InPtr;
- LPGAMMATABLE p;
-
- // Try to reverse it analytically whatever possible
- if (InGamma -> Seed.Type > 0 && InGamma -> Seed.Type <= 5 &&
- _cmsCrc32OfGammaTable(InGamma) == InGamma -> Seed.Crc32) {
-
- return cmsBuildParametricGamma(nResultSamples, -(InGamma -> Seed.Type), InGamma ->Seed.Params);
- }
+ return cmsBuildParametricToneCurve(ContextID, 1, &Gamma);
+}
- // Nope, reverse the table
- p = cmsAllocGamma(nResultSamples);
- if (!p) return NULL;
+// Free all memory taken by the gamma curve
+void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve)
+{
+ cmsContext ContextID;
+
+ if (Curve == NULL) return;
+
+ ContextID = Curve ->InterpParams->ContextID;
+
+ _cmsFreeInterpParams(Curve ->InterpParams);
- cmsCalcL16Params(InGamma -> nEntries, &L16In);
- InPtr = InGamma -> GammaTable;
+ if (Curve -> Table16)
+ _cmsFree(ContextID, Curve ->Table16);
+
+ if (Curve ->Segments) {
+
+ cmsUInt32Number i;
+
+ for (i=0; i < Curve ->nSegments; i++) {
+
+ if (Curve ->Segments[i].SampledPoints) {
+ _cmsFree(ContextID, Curve ->Segments[i].SampledPoints);
+ }
- for (i=0; i < nResultSamples; i++)
- {
- WORD wValIn, wValOut;
+ if (Curve ->SegInterp[i] != 0)
+ _cmsFreeInterpParams(Curve->SegInterp[i]);
+ }
+
+ _cmsFree(ContextID, Curve ->Segments);
+ _cmsFree(ContextID, Curve ->SegInterp);
+ }
+
+ if (Curve -> Evals)
+ _cmsFree(ContextID, Curve -> Evals);
- wValIn = _cmsQuantizeVal(i, nResultSamples);
- wValOut = cmsReverseLinearInterpLUT16(wValIn, InPtr, &L16In);
- p -> GammaTable[i] = wValOut;
- }
+ if (Curve) _cmsFree(ContextID, Curve);
+}
+
+// Utility function, free 3 gamma tables
+void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3])
+{
+
+ _cmsAssert(Curve != NULL);
+
+ if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]);
+ if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]);
+ if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]);
+
+ Curve[0] = Curve[1] = Curve[2] = NULL;
+}
- return p;
+// Duplicate a gamma table
+cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In)
+{
+ if (In == NULL) return NULL;
+
+ return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16);
+}
+
+// Joins two curves for X and Y. Curves should be monotonic.
+// We want to get
+//
+// y = Y^-1(X(t))
+//
+cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID,
+ const cmsToneCurve* X,
+ const cmsToneCurve* Y, cmsUInt32Number nResultingPoints)
+{
+ cmsToneCurve* out = NULL;
+ cmsToneCurve* Yreversed = NULL;
+ cmsFloat32Number t, x;
+ cmsFloat32Number* Res = NULL;
+ cmsUInt32Number i;
+
+
+ _cmsAssert(X != NULL);
+ _cmsAssert(Y != NULL);
+
+ Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y);
+ if (Yreversed == NULL) goto Error;
+
+ Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number));
+ if (Res == NULL) goto Error;
+
+ //Iterate
+ for (i=0; i < nResultingPoints; i++) {
+
+ t = (cmsFloat32Number) i / (nResultingPoints-1);
+ x = cmsEvalToneCurveFloat(X, t);
+ Res[i] = cmsEvalToneCurveFloat(Yreversed, x);
+ }
+
+ // Allocate space for output
+ out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res);
+
+Error:
+
+ if (Res != NULL) _cmsFree(ContextID, Res);
+ if (Yreversed != NULL) cmsFreeToneCurve(Yreversed);
+
+ return out;
}
-// Parametric curves
-//
-// Parameters goes as: Gamma, a, b, c, d, e, f
-// Type is the ICC type +1
-// if type is negative, then the curve is analyticaly inverted
-
-LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[])
+// Get the surrounding nodes. This is tricky on non-monotonic tables
+static
+int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p)
{
- LPGAMMATABLE Table;
- double R, Val, dval, e;
- int i;
- int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
-
- Table = cmsAllocGamma(nEntries);
- if (NULL == Table) return NULL;
-
- Table -> Seed.Type = Type;
+ int i;
+ int y0, y1;
- CopyMemory(Table ->Seed.Params, Params, ParamsByType[abs(Type)] * sizeof(double));
-
+ // A 1 point table is not allowed
+ if (p -> Domain[0] < 1) return -1;
- for (i=0; i < nEntries; i++) {
-
- R = (double) i / (nEntries-1);
-
- switch (Type) {
+ // Let's see if ascending or descending.
+ if (LutTable[0] < LutTable[p ->Domain[0]]) {
- // X = Y ^ Gamma
- case 1:
- Val = pow(R, Params[0]);
- break;
+ // Table is overall ascending
+ for (i=p->Domain[0]-1; i >=0; --i) {
- // Type 1 Reversed: X = Y ^1/gamma
- case -1:
- Val = pow(R, 1/Params[0]);
- break;
+ y0 = LutTable[i];
+ y1 = LutTable[i+1];
- // CIE 122-1966
- // Y = (aX + b)^Gamma | X >= -b/a
- // Y = 0 | else
- case 2:
- if (R >= -Params[2] / Params[1]) {
-
- e = Params[1]*R + Params[2];
-
- if (e > 0)
- Val = pow(e, Params[0]);
- else
- Val = 0;
- }
- else
- Val = 0;
- break;
-
- // Type 2 Reversed
- // X = (Y ^1/g - b) / a
- case -2:
+ if (y0 <= y1) { // Increasing
+ if (In >= y0 && In <= y1) return i;
+ }
+ else
+ if (y1 < y0) { // Decreasing
+ if (In >= y1 && In <= y0) return i;
+ }
+ }
+ }
+ else {
+ // Table is overall descending
+ for (i=0; i < (int) p -> Domain[0]; i++) {
- Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
- if (Val < 0)
- Val = 0;
- break;
-
-
- // IEC 61966-3
- // Y = (aX + b)^Gamma | X <= -b/a
- // Y = c | else
- case 3:
- if (R >= -Params[2] / Params[1]) {
+ y0 = LutTable[i];
+ y1 = LutTable[i+1];
- e = Params[1]*R + Params[2];
- Val = pow(e, Params[0]) + Params[3];
- }
- else
- Val = Params[3];
- break;
+ if (y0 <= y1) { // Increasing
+ if (In >= y0 && In <= y1) return i;
+ }
+ else
+ if (y1 < y0) { // Decreasing
+ if (In >= y1 && In <= y0) return i;
+ }
+ }
+ }
-
- // Type 3 reversed
- // X=((Y-c)^1/g - b)/a | (Y>=c)
- // X=-b/a | (Y<c)
+ return -1;
+}
- case -3:
- if (R >= Params[3]) {
- e = R - Params[3];
- Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1];
- if (Val < 0) Val = 0;
- }
- else {
- Val = -Params[2] / Params[1];
- }
- break;
+// Reverse a gamma table
+cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve)
+{
+ cmsToneCurve *out;
+ cmsFloat64Number a = 1, b = 0, y, x1, y1, x2, y2;
+ int i, j;
+ int Ascending;
+ _cmsAssert(InCurve != NULL);
- // IEC 61966-2.1 (sRGB)
- // Y = (aX + b)^Gamma | X >= d
- // Y = cX | X < d
- case 4:
- if (R >= Params[4]) {
+ // Try to reverse it analytically whatever possible
+ if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) {
- e = Params[1]*R + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]);
- else
- Val = 0;
- }
- else
- Val = R * Params[3];
- break;
+ return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID,
+ -(InCurve -> Segments[0].Type),
+ InCurve -> Segments[0].Params);
+ }
- // Type 4 reversed
- // X=((Y^1/g-b)/a) | Y >= (ad+b)^g
- // X=Y/c | Y< (ad+b)^g
-
- case -4:
- if (R >= pow(Params[1] * Params[4] + Params[2], Params[0])) {
+ // Nope, reverse the table.
+ out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL);
+ if (out == NULL)
+ return NULL;
- Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
- }
- else {
- Val = R / Params[3];
- }
- break;
-
+ // We want to know if this is an ascending or descending table
+ Ascending = !cmsIsToneCurveDescending(InCurve);
+ // Iterate across Y axis
+ for (i=0; i < nResultSamples; i++) {
- // Y = (aX + b)^Gamma + e | X <= d
- // Y = cX + f | else
- case 5:
- if (R >= Params[4]) {
+ y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1);
- e = Params[1]*R + Params[2];
- Val = pow(e, Params[0]) + Params[5];
- }
- else
- Val = R*Params[3] + Params[6];
- break;
+ // Find interval in which y is within.
+ j = GetInterval(y, InCurve->Table16, InCurve->InterpParams);
+ if (j >= 0) {
-
- // Reversed type 5
- // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e)
- // X=(Y-f)/c | else
- case -5:
-
- if (R >= pow(Params[1] * Params[4], Params[0]) + Params[5]) {
+ // Get limits of interval
+ x1 = InCurve ->Table16[j];
+ x2 = InCurve ->Table16[j+1];
- Val = pow(R - Params[5], 1/Params[0]) - Params[2] / Params[1];
- }
- else {
- Val = (R - Params[6]) / Params[3];
- }
- break;
+ y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1);
+ y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1);
+
+ // If collapsed, then use any
+ if (x1 == x2) {
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Unsupported parametric curve type=%d", abs(Type)-1);
- cmsFreeGamma(Table);
- return NULL;
- }
+ out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1);
+ continue;
+ } else {
- // Saturate
-
- dval = Val * 65535.0 + .5;
- if (dval > 65535.) dval = 65535.0;
- if (dval < 0) dval = 0;
-
- Table->GammaTable[i] = (WORD) floor(dval);
+ // Interpolate
+ a = (y2 - y1) / (x2 - x1);
+ b = y2 - a * x2;
+ }
}
- Table -> Seed.Crc32 = _cmsCrc32OfGammaTable(Table);
+ out ->Table16[i] = _cmsQuickSaturateWord(a* y + b);
+ }
- return Table;
+ return out;
}
-// Build a gamma table based on gamma constant
-
-LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma)
+// Reverse a gamma table
+cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma)
{
- return cmsBuildParametricGamma(nEntries, 1, &Gamma);
+ _cmsAssert(InGamma != NULL);
+
+ return cmsReverseToneCurveEx(InGamma -> nEntries, InGamma);
}
-
-
// From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite
// differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press.
//
@@ -499,485 +903,264 @@
// Input: smoothing parameter (lambda), length (m).
// Output: smoothed vector (z): vector from 1 to m.
-
static
-void smooth2(vec w, vec y, vec z, float lambda, int m)
+cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[], cmsFloat32Number z[], cmsFloat32Number lambda, int m)
{
- int i, i1, i2;
- vec c, d, e;
- d[1] = w[1] + lambda;
- c[1] = -2 * lambda / d[1];
- e[1] = lambda /d[1];
- z[1] = w[1] * y[1];
- d[2] = w[2] + 5 * lambda - d[1] * c[1] * c[1];
- c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2];
- e[2] = lambda / d[2];
- z[2] = w[2] * y[2] - c[1] * z[1];
- for (i = 3; i < m - 1; i++) {
- i1 = i - 1; i2 = i - 2;
- d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
- c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i];
- e[i] = lambda / d[i];
- z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2];
- }
- i1 = m - 2; i2 = m - 3;
- d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
- c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1];
- z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2];
- i1 = m - 1; i2 = m - 2;
- d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
- z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m];
- z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m];
- for (i = m - 2; 1<= i; i--)
- z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2];
+ int i, i1, i2;
+ cmsFloat32Number *c, *d, *e;
+ cmsBool st;
+
+
+ c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
+ d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
+ e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
+
+ if (c != NULL && d != NULL && e != NULL) {
+
+
+ d[1] = w[1] + lambda;
+ c[1] = -2 * lambda / d[1];
+ e[1] = lambda /d[1];
+ z[1] = w[1] * y[1];
+ d[2] = w[2] + 5 * lambda - d[1] * c[1] * c[1];
+ c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2];
+ e[2] = lambda / d[2];
+ z[2] = w[2] * y[2] - c[1] * z[1];
+
+ for (i = 3; i < m - 1; i++) {
+ i1 = i - 1; i2 = i - 2;
+ d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
+ c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i];
+ e[i] = lambda / d[i];
+ z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2];
+ }
+
+ i1 = m - 2; i2 = m - 3;
+
+ d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
+ c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1];
+ z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2];
+ i1 = m - 1; i2 = m - 2;
+
+ d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
+ z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m];
+ z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m];
+
+ for (i = m - 2; 1<= i; i--)
+ z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2];
+
+ st = TRUE;
+ }
+ else st = FALSE;
+
+ if (c != NULL) _cmsFree(ContextID, c);
+ if (d != NULL) _cmsFree(ContextID, d);
+ if (e != NULL) _cmsFree(ContextID, e);
+
+ return st;
}
-
-
-// Smooths a curve sampled at regular intervals
-
-LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda)
-
+// Smooths a curve sampled at regular intervals.
+cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda)
{
- vec w, y, z;
+ cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE];
int i, nItems, Zeros, Poles;
+ if (Tab == NULL) return FALSE;
- if (cmsIsLinear(Tab->GammaTable, Tab->nEntries)) return FALSE; // Nothing to do
+ if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do
nItems = Tab -> nEntries;
- if (nItems > MAX_KNOTS) {
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsSmoothGamma: too many points.");
- return FALSE;
- }
+ if (nItems >= MAX_NODES_IN_CURVE) {
+ cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: too many points.");
+ return FALSE;
+ }
- ZeroMemory(w, nItems * sizeof(float));
- ZeroMemory(y, nItems * sizeof(float));
- ZeroMemory(z, nItems * sizeof(float));
+ memset(w, 0, nItems * sizeof(cmsFloat32Number));
+ memset(y, 0, nItems * sizeof(cmsFloat32Number));
+ memset(z, 0, nItems * sizeof(cmsFloat32Number));
for (i=0; i < nItems; i++)
{
- y[i+1] = (float) Tab -> GammaTable[i];
+ y[i+1] = (cmsFloat32Number) Tab -> Table16[i];
w[i+1] = 1.0;
}
- smooth2(w, y, z, (float) lambda, nItems);
+ if (!smooth2(Tab ->InterpParams->ContextID, w, y, z, (cmsFloat32Number) lambda, nItems)) return FALSE;
// Do some reality - checking...
Zeros = Poles = 0;
for (i=nItems; i > 1; --i) {
- if (z[i] == 0.) Zeros++;
- if (z[i] >= 65535.) Poles++;
- if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
+ if (z[i] == 0.) Zeros++;
+ if (z[i] >= 65535.) Poles++;
+ if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
}
if (Zeros > (nItems / 3)) return FALSE; // Degenerated, mostly zeros
if (Poles > (nItems / 3)) return FALSE; // Degenerated, mostly poles
// Seems ok
-
for (i=0; i < nItems; i++) {
- // Clamp to WORD
+ // Clamp to cmsUInt16Number
+ Tab -> Table16[i] = _cmsQuickSaturateWord(z[i+1]);
+ }
+
+ return TRUE;
+}
- float v = z[i+1];
+// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting
+// in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases.
+cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
+{
+ cmsUInt32Number i;
+ int diff;
+
+ _cmsAssert(Curve != NULL);
+
+ for (i=0; i < Curve ->nEntries; i++) {
+
+ diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries));
+ if (diff > 0x0f)
+ return FALSE;
+ }
- if (v < 0) v = 0;
- if (v > 65535.) v = 65535.;
+ return TRUE;
+}
+
+// Same, but for monotonicity
+cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
+{
+ int n;
+ int i, last;
+
+ _cmsAssert(t != NULL);
- Tab -> GammaTable[i] = (WORD) floor(v + .5);
- }
+ n = t ->nEntries;
+ last = t ->Table16[n-1];
+
+ for (i = n-2; i >= 0; --i) {
+
+ if (t ->Table16[i] > last)
+
+ return FALSE;
+ else
+ last = t ->Table16[i];
+
+ }
return TRUE;
}
+// Same, but for descending tables
+cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t)
+{
+ _cmsAssert(t != NULL);
-// Check if curve is exponential, return gamma if so.
+ return t ->Table16[0] > t ->Table16[t ->nEntries-1];
+}
+
+
+// Another info fn: is out gamma table multisegment?
+cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t)
+{
+ _cmsAssert(t != NULL);
+
+ return t -> nSegments > 1;
+}
+
+cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t)
+{
+ _cmsAssert(t != NULL);
+
+ if (t -> nSegments != 1) return 0;
+ return t ->Segments[0].Type;
+}
+
+// We need accuracy this time
+cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v)
+{
+ _cmsAssert(Curve != NULL);
+
+ // Check for 16 bits table. If so, this is a limited-precision tone curve
+ if (Curve ->nSegments == 0) {
+
+ cmsUInt16Number In, Out;
+
+ In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0);
+ Out = cmsEvalToneCurve16(Curve, In);
-double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double Thereshold)
+ return (cmsFloat32Number) (Out / 65535.0);
+ }
+
+ return (cmsFloat32Number) EvalSegmentedFn(Curve, v);
+}
+
+// We need xput over here
+cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v)
{
- double gamma, sum, sum2;
- double n, x, y, Std;
- int i;
+ cmsUInt16Number out;
+
+ _cmsAssert(Curve != NULL);
+
+ Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams);
+ return out;
+}
+
+
+// Least squares fitting.
+// A mathematical procedure for finding the best-fitting curve to a given set of points by
+// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve.
+// The sum of the squares of the offsets is used instead of the offset absolute values because
+// this allows the residuals to be treated as a continuous differentiable quantity.
+//
+// y = f(x) = x ^ g
+//
+// R = (yi - (xi^g))
+// R2 = (yi - (xi^g))2
+// SUM R2 = SUM (yi - (xi^g))2
+//
+// dR2/dg = -2 SUM x^g log(x)(y - x^g)
+// solving for dR2/dg = 0
+//
+// g = 1/n * SUM(log(y) / log(x))
+
+cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision)
+{
+ cmsFloat64Number gamma, sum, sum2;
+ cmsFloat64Number n, x, y, Std;
+ cmsUInt32Number i;
+
+ _cmsAssert(t != NULL);
sum = sum2 = n = 0;
- // Does exclude endpoints
- for (i=1; i < nEntries - 1; i++) {
+ // Excluding endpoints
+ for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) {
- x = (double) i / (nEntries - 1);
- y = (double) GammaTable[i] / 65535.;
+ x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1);
+ y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x);
- // Avoid 7% on lower part to prevent
- // artifacts due to linear ramps
+ // Avoid 7% on lower part to prevent
+ // artifacts due to linear ramps
- if (y > 0. && y < 1. && x > 0.07) {
+ if (y > 0. && y < 1. && x > 0.07) {
gamma = log(y) / log(x);
sum += gamma;
sum2 += gamma * gamma;
n++;
- }
-
+ }
}
// Take a look on SD to see if gamma isn't exponential at all
Std = sqrt((n * sum2 - sum * sum) / (n*(n-1)));
-
- if (Std > Thereshold)
+ if (Std > Precision)
return -1.0;
return (sum / n); // The mean
}
-
-double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t)
-{
- return cmsEstimateGammaEx(t->GammaTable, t->nEntries, 0.7);
-}
-
-
-// -----------------------------------------------------------------Sampled curves
-
-// Allocate a empty curve
-
-LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems)
-{
- LPSAMPLEDCURVE pOut;
-
- pOut = (LPSAMPLEDCURVE) _cmsMalloc(sizeof(SAMPLEDCURVE));
- if (pOut == NULL)
- return NULL;
-
- if((pOut->Values = (double *) _cmsMalloc(nItems * sizeof(double))) == NULL)
- {
- _cmsFree(pOut);
- return NULL;
- }
-
- pOut->nItems = nItems;
- ZeroMemory(pOut->Values, nItems * sizeof(double));
-
- return pOut;
-}
-
-
-void cmsFreeSampledCurve(LPSAMPLEDCURVE p)
-{
- _cmsFree((LPVOID) p -> Values);
- _cmsFree((LPVOID) p);
-}
-
-
-
-// Does duplicate a sampled curve
-
-LPSAMPLEDCURVE cmsDupSampledCurve(LPSAMPLEDCURVE p)
-{
- LPSAMPLEDCURVE out;
-
- out = cmsAllocSampledCurve(p -> nItems);
- if (!out) return NULL;
-
- CopyMemory(out ->Values, p ->Values, p->nItems * sizeof(double));
-
- return out;
-}
-
-
-// Take min, max of curve
-
-void cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max)
-{
- int i;
-
- *Min = 65536.;
- *Max = 0.;
-
- for (i=0; i < p -> nItems; i++) {
-
- double v = p -> Values[i];
-
- if (v < *Min)
- *Min = v;
-
- if (v > *Max)
- *Max = v;
- }
-
- if (*Min < 0) *Min = 0;
- if (*Max > 65535.0) *Max = 65535.0;
-}
-
-// Clamps to Min, Max
-
-void cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max)
-{
-
- int i;
-
- for (i=0; i < p -> nItems; i++) {
-
- double v = p -> Values[i];
-
- if (v < Min)
- v = Min;
-
- if (v > Max)
- v = Max;
-
- p -> Values[i] = v;
-
- }
-
-}
-
-
-
-// Smooths a curve sampled at regular intervals
-
-LCMSBOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda)
-{
- vec w, y, z;
- int i, nItems;
-
- nItems = Tab -> nItems;
-
- if (nItems > MAX_KNOTS) {
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsSmoothSampledCurve: too many points.");
- return FALSE;
- }
-
- ZeroMemory(w, nItems * sizeof(float));
- ZeroMemory(y, nItems * sizeof(float));
- ZeroMemory(z, nItems * sizeof(float));
-
- for (i=0; i < nItems; i++)
- {
- float value = (float) Tab -> Values[i];
-
- y[i+1] = value;
- w[i+1] = (float) ((value < 0.0) ? 0 : 1);
- }
-
-
- smooth2(w, y, z, (float) lambda, nItems);
-
- for (i=0; i < nItems; i++) {
-
- Tab -> Values[i] = z[i+1];;
- }
-
- return TRUE;
-
-}
-
-
-// Scale a value v, within domain Min .. Max
-// to a domain 0..(nPoints-1)
-
-static
-double ScaleVal(double v, double Min, double Max, int nPoints)
-{
-
- double a, b;
-
- if (v <= Min) return 0;
- if (v >= Max) return (nPoints-1);
-
- a = (double) (nPoints - 1) / (Max - Min);
- b = a * Min;
-
- return (a * v) - b;
-
-}
-
-
-// Does rescale a sampled curve to fit in a 0..(nPoints-1) domain
-
-void cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints)
-{
-
- int i;
-
- for (i=0; i < p -> nItems; i++) {
-
- double v = p -> Values[i];
-
- p -> Values[i] = ScaleVal(v, Min, Max, nPoints);
- }
-
-}
-
-
-// Joins two sampled curves for X and Y. Curves should be sorted.
-
-LPSAMPLEDCURVE cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints)
-{
- int i, j;
- LPSAMPLEDCURVE out;
- double MinX, MinY, MaxX, MaxY;
- double x, y, x1, y1, x2, y2, a, b;
-
- out = cmsAllocSampledCurve(nResultingPoints);
- if (out == NULL)
- return NULL;
-
- if (X -> nItems != Y -> nItems) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsJoinSampledCurves: invalid curve.");
- cmsFreeSampledCurve(out);
- return NULL;
- }
-
- // Get endpoints of sampled curves
- cmsEndpointsOfSampledCurve(X, &MinX, &MaxX);
- cmsEndpointsOfSampledCurve(Y, &MinY, &MaxY);
-
-
- // Set our points
- out ->Values[0] = MinY;
- for (i=1; i < nResultingPoints; i++) {
-
- // Scale t to x domain
- x = (i * (MaxX - MinX) / (nResultingPoints-1)) + MinX;
-
- // Find interval in which j is within (always up,
- // since fn should be monotonic at all)
-
- j = 1;
- while ((j < X ->nItems - 1) && X ->Values[j] < x)
- j++;
-
- // Now x is within X[j-1], X[j]
- x1 = X ->Values[j-1]; x2 = X ->Values[j];
- y1 = Y ->Values[j-1]; y2 = Y ->Values[j];
-
- // Interpolate the value
- a = (y1 - y2) / (x1 - x2);
- b = y1 - a * x1;
- y = a* x + b;
-
- out ->Values[i] = y;
- }
-
-
- cmsClampSampledCurve(out, MinY, MaxY);
- return out;
-}
-
-
-
-// Convert between curve types
-
-LPGAMMATABLE cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, double Max)
-{
- LPGAMMATABLE Gamma;
- int i, nPoints;
-
-
- nPoints = Sampled ->nItems;
-
- Gamma = cmsAllocGamma(nPoints);
- for (i=0; i < nPoints; i++) {
-
- Gamma->GammaTable[i] = (WORD) floor(ScaleVal(Sampled ->Values[i], 0, Max, 65536) + .5);
- }
-
- return Gamma;
-
-}
-
-// Inverse of anterior
-
-LPSAMPLEDCURVE cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints)
-{
- LPSAMPLEDCURVE Sampled;
- L16PARAMS L16;
- int i;
- WORD wQuant, wValIn;
-
- if (nPoints > 4096) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsConvertGammaToSampledCurve: too many points (max=4096)");
- return NULL;
- }
-
- cmsCalcL16Params(Gamma -> nEntries, &L16);
-
- Sampled = cmsAllocSampledCurve(nPoints);
- for (i=0; i < nPoints; i++) {
- wQuant = _cmsQuantizeVal(i, nPoints);
- wValIn = cmsLinearInterpLUT16(wQuant, Gamma ->GammaTable, &L16);
- Sampled ->Values[i] = (float) wValIn;
- }
-
- return Sampled;
-}
-
-
-
-
-// Smooth endpoints (used in Black/White compensation)
-
-LCMSBOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries)
-{
- vec w, y, z;
- int i, Zeros, Poles;
-
-
-
- if (cmsIsLinear(Table, nEntries)) return FALSE; // Nothing to do
-
-
- if (nEntries > MAX_KNOTS) {
- cmsSignalError(LCMS_ERRC_ABORTED, "_cmsSmoothEndpoints: too many points.");
- return FALSE;
- }
-
- ZeroMemory(w, nEntries * sizeof(float));
- ZeroMemory(y, nEntries * sizeof(float));
- ZeroMemory(z, nEntries * sizeof(float));
-
- for (i=0; i < nEntries; i++)
- {
- y[i+1] = (float) Table[i];
- w[i+1] = 1.0;
- }
-
- w[1] = 65535.0;
- w[nEntries] = 65535.0;
-
- smooth2(w, y, z, (float) nEntries, nEntries);
-
- // Do some reality - checking...
- Zeros = Poles = 0;
- for (i=nEntries; i > 1; --i) {
-
- if (z[i] == 0.) Zeros++;
- if (z[i] >= 65535.) Poles++;
- if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
- }
-
- if (Zeros > (nEntries / 3)) return FALSE; // Degenerated, mostly zeros
- if (Poles > (nEntries / 3)) return FALSE; // Degenerated, mostly poles
-
- // Seems ok
-
- for (i=0; i < nEntries; i++) {
-
- // Clamp to WORD
-
- float v = z[i+1];
-
- if (v < 0) v = 0;
- if (v > 65535.) v = 65535.;
-
- Table[i] = (WORD) floor(v + .5);
- }
-
- return TRUE;
-}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,871 +49,383 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-/*
-Gamut check by default is a catching of 0xFFFF/0xFFFF/0xFFFF PCS values, used
-internally by lcms to hold invalid values. Matrix LUT's, operates in a way that
-unencodeable values are marked as this combination, if PCS is XYZ, this is a very
-high value since encoding is a 1.15 fixed point, something like 1.9997, 1.9997, 1.9997
-not a very common color after all. Lab PCS is not to be a problem, since L>100 are truely
-undefined. There is a posibility than ICC comitee defines L>100 as a valid means
-to use highlights, then it will be lost.
-
-(1.10 - Actually ICC did it, so this should be checked for full ICC 4.0 support)
-
-*/
-
-
-LCMSBOOL _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black,
- int *nOutputs)
-{
- // Only most common spaces
-
- static WORD RGBblack[4] = { 0, 0, 0 };
- static WORD RGBwhite[4] = { 0xffff, 0xffff, 0xffff };
- static WORD CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink
- static WORD CMYKwhite[4] = { 0, 0, 0, 0 };
- static WORD LABblack[4] = { 0, 0x8000, 0x8000 };
- static WORD LABwhite[4] = { 0xFF00, 0x8000, 0x8000 };
- static WORD CMYblack[4] = { 0xffff, 0xffff, 0xffff };
- static WORD CMYwhite[4] = { 0, 0, 0 };
- static WORD Grayblack[4] = { 0 };
- static WORD GrayWhite[4] = { 0xffff };
-
- switch (Space) {
-
- case icSigGrayData: if (White) *White = GrayWhite;
- if (Black) *Black = Grayblack;
- if (nOutputs) *nOutputs = 1;
- return TRUE;
-
- case icSigRgbData: if (White) *White = RGBwhite;
- if (Black) *Black = RGBblack;
- if (nOutputs) *nOutputs = 3;
- return TRUE;
-
- case icSigLabData: if (White) *White = LABwhite;
- if (Black) *Black = LABblack;
- if (nOutputs) *nOutputs = 3;
- return TRUE;
-
- case icSigCmykData: if (White) *White = CMYKwhite;
- if (Black) *Black = CMYKblack;
- if (nOutputs) *nOutputs = 4;
- return TRUE;
-
- case icSigCmyData: if (White) *White = CMYwhite;
- if (Black) *Black = CMYblack;
- if (nOutputs) *nOutputs = 3;
- return TRUE;
-
- default:;
- }
+//
+//---------------------------------------------------------------------------------
+//
- return FALSE;
-}
-
-
-WORD *_cmsWhiteBySpace(icColorSpaceSignature Space)
-{
- WORD *White= NULL, *Black = NULL;
- int Dummy;
- static WORD Default[MAXCHANNELS];
-
- if (_cmsEndPointsBySpace(Space, &White, &Black, &Dummy))
- return White;
-
- return Default;
-
-}
-
-
-
-
-WORD Clamp_L(Fixed32 in)
-{
- if (in == 0xFFFF) return 0xFFFFU; // Marker
-
- if (in > 0xFF00) return 0xFF00U; // L* = 100.0
- return (WORD) in;
-}
-
-
-#define ENCODE_AB(x) (WORD) (((x) + 128.0) * 256.0 + 0.5)
-
-WORD Clamp_ab(Fixed32 in)
-{
- if (in == 0xFFFF) return 0xFFFFU; // Marker
-
- if (in < 0) return ENCODE_AB(-128.0); // Max negative number
- if (in > 0xFFFF) return ENCODE_AB(+127.9961); // Max positive number
- return (WORD) in;
-}
-
-
-
-// Returns dE on two Lab values
-
-double LCMSEXPORT cmsDeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
- double dL, da, db;
-
- if (Lab1 -> L < 0 ||
- Lab2 -> L < 0) return 65536.;
-
- if (Lab1 -> a < -200 || Lab1 -> a > 200) return 65536.;
- if (Lab1 -> b < -200 || Lab1 -> b > 200) return 65536.;
-
- if (Lab2 -> a < -200 || Lab2 -> a > 200) return 65536.;
- if (Lab2 -> b < -200 || Lab2 -> b > 200) return 65536.;
-
- if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
- dL = fabs(Lab1 -> L - Lab2 -> L);
- da = fabs(Lab1 -> a - Lab2 -> a);
- db = fabs(Lab1 -> b - Lab2 -> b);
-
- return pow(dL*dL + da * da + db * db, 0.5);
-
-}
+#include "lcms2_internal.h"
-// Square
-static
-double Sqr(double v)
-{
- return v * v;
-}
-
-// Return the CIE94 Delta E
-double LCMSEXPORT cmsCIE94DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
+// Auxiliar: append a Lab identity after the given sequence of profiles
+// and return the transform. Lab profile is closed, rest of profiles are kept open.
+cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
{
- cmsCIELCh LCh1, LCh2;
- double dE, dL, dC, dh, dhsq;
- double c12, sc, sh;
-
- if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
- dL = fabs(Lab1 ->L - Lab2 ->L);
-
- cmsLab2LCh(&LCh1, Lab1);
- cmsLab2LCh(&LCh2, Lab2);
-
- dC = fabs(LCh1.C - LCh2.C);
- dE = cmsDeltaE(Lab1, Lab2);
-
- dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC);
- if (dhsq < 0)
- dh = 0;
- else
- dh = pow(dhsq, 0.5);
-
- c12 = sqrt(LCh1.C * LCh2.C);
-
- sc = 1.0 + (0.048 * c12);
- sh = 1.0 + (0.014 * c12);
-
- return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh));
-}
-
-
-// Auxiliary
+ cmsHTRANSFORM xform;
+ cmsHPROFILE hLab;
+ cmsHPROFILE ProfileList[256];
+ cmsBool BPCList[256];
+ cmsFloat64Number AdaptationList[256];
+ cmsUInt32Number IntentList[256];
+ cmsUInt32Number i;
-static
-double ComputeLBFD(LPcmsCIELab Lab)
-{
- double yt;
-
- if (Lab->L > 7.996969)
- yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100;
- else
- yt = 100 * (Lab->L / 903.3);
-
- return (54.6 * (LOGE * (log(yt + 1.5))) - 9.6);
-}
-
-
-
-// bfd - gets BFD(1:1) difference between Lab1, Lab2
-double LCMSEXPORT cmsBFDdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
- double lbfd1,lbfd2,AveC,Aveh,dE,deltaL,
- deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd;
- cmsCIELCh LCh1, LCh2;
+ // This is a rather big number and there is no need of dynamic memory
+ // since we are adding a profile, 254 + 1 = 255 and this is the limit
+ if (nProfiles > 254) return NULL;
-
- if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
- lbfd1 = ComputeLBFD(Lab1);
- lbfd2 = ComputeLBFD(Lab2);
- deltaL = lbfd2 - lbfd1;
-
- cmsLab2LCh(&LCh1, Lab1);
- cmsLab2LCh(&LCh2, Lab2);
-
- deltaC = LCh2.C - LCh1.C;
- AveC = (LCh1.C+LCh2.C)/2;
- Aveh = (LCh1.h+LCh2.h)/2;
-
- dE = cmsDeltaE(Lab1, Lab2);
-
- if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC)))
- deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC));
- else
- deltah =0;
-
+ // The output space
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) return NULL;
- dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521;
- g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000));
- t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))-
- 0.040*cos((2*Aveh-136)/(180/M_PI))+
- 0.070*cos((3*Aveh-31)/(180/M_PI))+
- 0.049*cos((4*Aveh+114)/(180/M_PI))-
- 0.015*cos((5*Aveh-103)/(180/M_PI)));
-
- dh = dc*(g*t+1-g);
- rh = -0.260*cos((Aveh-308)/(180/M_PI))-
- 0.379*cos((2*Aveh-160)/(180/M_PI))-
- 0.636*cos((3*Aveh+254)/(180/M_PI))+
- 0.226*cos((4*Aveh+140)/(180/M_PI))-
- 0.194*cos((5*Aveh+280)/(180/M_PI));
-
- rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000));
- rt = rh*rc;
-
- bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh)));
+ // Create a copy of parameters
+ for (i=0; i < nProfiles; i++) {
- return bfd;
-}
-
-
-// cmc - CMC(1:1) difference between Lab1, Lab2
-double LCMSEXPORT cmsCMCdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
- double dE,dL,dC,dh,sl,sc,sh,t,f,cmc;
- cmsCIELCh LCh1, LCh2;
-
- if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
- cmsLab2LCh(&LCh1, Lab1);
- cmsLab2LCh(&LCh2, Lab2);
-
-
- dL = Lab2->L-Lab1->L;
- dC = LCh2.C-LCh1.C;
-
- dE = cmsDeltaE(Lab1, Lab2);
- if (Sqr(dE)>(Sqr(dL)+Sqr(dC)))
- dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC));
- else
- dh =0;
+ ProfileList[i] = hProfiles[i];
+ BPCList[i] = BPC[i];
+ AdaptationList[i] = AdaptationStates[i];
+ IntentList[i] = Intents[i];
+ }
- if ((LCh1.h > 164) && (LCh1.h<345))
- t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI))));
- else
- t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI))));
-
- sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638;
- sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L);
-
- if (Lab1->L<16)
- sl = 0.511;
-
- f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900));
- sh = sc*(t*f+1-f);
- cmc = sqrt(Sqr(dL/sl)+Sqr(dC/sc)+Sqr(dh/sh));
-
- return cmc;
-}
-
-
+ // Place Lab identity at chain's end.
+ ProfileList[nProfiles] = hLab;
+ BPCList[nProfiles] = 0;
+ AdaptationList[nProfiles] = 1.0;
+ IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC;
-static
-double atan2deg(double b, double a)
-{
- double h;
-
- if (a == 0 && b == 0)
- h = 0;
- else
- h = atan2(a, b);
-
- h *= (180. / M_PI);
+ // Create the transform
+ xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList,
+ BPCList,
+ IntentList,
+ AdaptationList,
+ NULL, 0,
+ InputFormat,
+ OutputFormat,
+ dwFlags);
- while (h > 360.)
- h -= 360.;
-
- while ( h < 0)
- h += 360.;
-
- return h;
+ cmsCloseProfile(hLab);
-}
-
-
-static
-double RADIANES(double deg)
-{
- return (deg * M_PI) / 180.;
+ return xform;
}
-// dE2000 The weightings KL, KC and KH can be modified to reflect the relative
-// importance of lightness, chroma and hue in different industrial applications
-
-double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2,
- double Kl, double Kc, double Kh)
+// Compute K -> L* relationship. Flags may include black point compensation. In this case,
+// the relationship is assumed from the profile with BPC to a black point zero.
+static
+cmsToneCurve* ComputeKToLstar(cmsContext ContextID,
+ cmsUInt32Number nPoints,
+ cmsUInt32Number nProfiles,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
{
- double L1 = Lab1->L;
- double a1 = Lab1->a;
- double b1 = Lab1->b;
- double C = sqrt( Sqr(a1) + Sqr(b1) );
-
- double Ls = Lab2 ->L;
- double as = Lab2 ->a;
- double bs = Lab2 ->b;
- double Cs = sqrt( Sqr(as) + Sqr(bs) );
+ cmsToneCurve* out = NULL;
+ cmsUInt32Number i;
+ cmsHTRANSFORM xform;
+ cmsCIELab Lab;
+ cmsFloat32Number cmyk[4];
+ cmsFloat32Number* SampledPoints;
- double G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) ));
-
- double a_p = (1 + G ) * a1;
- double b_p = b1;
- double C_p = sqrt( Sqr(a_p) + Sqr(b_p));
- double h_p = atan2deg(a_p, b_p);
-
-
- double a_ps = (1 + G) * as;
- double b_ps = bs;
- double C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps));
- double h_ps = atan2deg(a_ps, b_ps);
-
- double meanC_p =(C_p + C_ps) / 2;
-
- double hps_plus_hp = h_ps + h_p;
- double hps_minus_hp = h_ps - h_p;
+ xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+ if (xform == NULL) return NULL;
- double meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 :
- (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 :
- (hps_plus_hp - 360)/2;
+ SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number));
+ if (SampledPoints == NULL) goto Error;
+
+ for (i=0; i < nPoints; i++) {
- double delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) :
- (hps_minus_hp) > 180 ? (hps_minus_hp - 360) :
- (hps_minus_hp);
- double delta_L = (Ls - L1);
- double delta_C = (C_ps - C_p );
-
-
- double delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANES(delta_h) / 2);
-
- double T = 1 - 0.17 * cos(RADIANES(meanh_p-30))
- + 0.24 * cos(RADIANES(2*meanh_p))
- + 0.32 * cos(RADIANES(3*meanh_p + 6))
- - 0.2 * cos(RADIANES(4*meanh_p - 63));
+ cmyk[0] = 0;
+ cmyk[1] = 0;
+ cmyk[2] = 0;
+ cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1));
- double Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) );
+ cmsDoTransform(xform, cmyk, &Lab, 1);
+ SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation
+ }
- double Sc = 1 + 0.045 * (C_p + C_ps)/2;
- double Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T;
-
- double delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25)));
-
- double Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0)));
+ out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints);
- double Rt = -sin(2 * RADIANES(delta_ro)) * Rc;
+Error:
- double deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) +
- Sqr(delta_C/(Sc * Kc)) +
- Sqr(delta_H/(Sh * Kh)) +
- Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh)));
+ cmsDeleteTransform(xform);
+ if (SampledPoints) _cmsFree(ContextID, SampledPoints);
- return deltaE00;
+ return out;
}
-
-// Carefully, clamp on CIELab space.
-
-void LCMSEXPORT cmsClampLab(LPcmsCIELab Lab, double amax, double amin,
- double bmax, double bmin)
+// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
+// using the proof direction on both profiles to find K->L* relationship
+// then joining both curves. dwFlags may include black point compensation.
+cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
+ cmsUInt32Number nPoints,
+ cmsUInt32Number nProfiles,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
{
-
- // Whole Luma surface to zero
-
- if (Lab -> L < 0) {
-
- Lab-> L = Lab->a = Lab-> b = 0.0;
- return;
- }
+ cmsToneCurve *in, *out, *KTone;
- // Clamp white, DISCARD HIGHLIGHTS. This is done
- // in such way because icc spec doesn't allow the
- // use of L>100 as a highlight means.
-
- if (Lab->L > 100)
- Lab -> L = 100;
-
- // Check out gamut prism, on a, b faces
-
- if (Lab -> a < amin || Lab->a > amax||
- Lab -> b < bmin || Lab->b > bmax) {
-
- cmsCIELCh LCh;
- double h, slope;
-
- // Falls outside a, b limits. Transports to LCh space,
- // and then do the clipping
+ // Make sure CMYK -> CMYK
+ if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+ cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL;
- if (Lab -> a == 0.0) { // Is hue exactly 90?
-
- // atan will not work, so clamp here
- Lab -> b = Lab->b < 0 ? bmin : bmax;
- return;
- }
+ // Make sure last is an output profile
+ if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL;
- cmsLab2LCh(&LCh, Lab);
-
- slope = Lab -> b / Lab -> a;
- h = LCh.h;
-
- // There are 4 zones
-
- if ((h >= 0. && h < 45.) ||
- (h >= 315 && h <= 360.)) {
+ // Create individual curves. BPC works also as each K to L* is
+ // computed as a BPC to zero black point in case of L*
+ in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+ if (in == NULL) return NULL;
- // clip by amax
- Lab -> a = amax;
- Lab -> b = amax * slope;
- }
- else
- if (h >= 45. && h < 135)
- {
- // clip by bmax
- Lab -> b = bmax;
- Lab -> a = bmax / slope;
- }
- else
- if (h >= 135 && h < 225) {
- // clip by amin
- Lab -> a = amin;
- Lab -> b = amin * slope;
+ out = ComputeKToLstar(ContextID, nPoints, 1,
+ Intents + (nProfiles - 1),
+ hProfiles + (nProfiles - 1),
+ BPC + (nProfiles - 1),
+ AdaptationStates + (nProfiles - 1),
+ dwFlags);
+ if (out == NULL) {
+ cmsFreeToneCurve(in);
+ return NULL;
+ }
- }
- else
- if (h >= 225 && h < 315) {
- // clip by bmin
- Lab -> b = bmin;
- Lab -> a = bmin / slope;
- }
- else
- cmsSignalError(LCMS_ERRC_ABORTED, "Invalid angle");
+ // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but
+ // since this is used on black-preserving LUTs, we are not loosing accuracy in any case
+ KTone = cmsJoinToneCurve(ContextID, in, out, nPoints);
- }
-}
-
-// Several utilities -------------------------------------------------------
-
-// Translate from our colorspace to ICC representation
-
-icColorSpaceSignature LCMSEXPORT _cmsICCcolorSpace(int OurNotation)
-{
- switch (OurNotation) {
-
- case 1:
- case PT_GRAY: return icSigGrayData;
+ // Get rid of components
+ cmsFreeToneCurve(in); cmsFreeToneCurve(out);
- case 2:
- case PT_RGB: return icSigRgbData;
+ // Something went wrong...
+ if (KTone == NULL) return NULL;
+
+ // Make sure it is monotonic
+ if (!cmsIsToneCurveMonotonic(KTone)) {
- case PT_CMY: return icSigCmyData;
- case PT_CMYK: return icSigCmykData;
- case PT_YCbCr:return icSigYCbCrData;
- case PT_YUV: return icSigLuvData;
- case PT_XYZ: return icSigXYZData;
- case PT_Lab: return icSigLabData;
- case PT_YUVK: return icSigLuvKData;
- case PT_HSV: return icSigHsvData;
- case PT_HLS: return icSigHlsData;
- case PT_Yxy: return icSigYxyData;
- case PT_HiFi: return icSigHexachromeData;
- case PT_HiFi7: return icSigHeptachromeData;
- case PT_HiFi8: return icSigOctachromeData;
+ cmsFreeToneCurve(KTone);
+ return NULL;
+ }
- case PT_HiFi9: return icSigMCH9Data;
- case PT_HiFi10: return icSigMCHAData;
- case PT_HiFi11: return icSigMCHBData;
- case PT_HiFi12: return icSigMCHCData;
- case PT_HiFi13: return icSigMCHDData;
- case PT_HiFi14: return icSigMCHEData;
- case PT_HiFi15: return icSigMCHFData;
-
- default: return icMaxEnumData;
- }
+ return KTone;
}
-int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace)
-{
- switch (ProfileSpace) {
-
- case icSigGrayData: return PT_GRAY;
- case icSigRgbData: return PT_RGB;
- case icSigCmyData: return PT_CMY;
- case icSigCmykData: return PT_CMYK;
- case icSigYCbCrData:return PT_YCbCr;
- case icSigLuvData: return PT_YUV;
- case icSigXYZData: return PT_XYZ;
- case icSigLabData: return PT_Lab;
- case icSigLuvKData: return PT_YUVK;
- case icSigHsvData: return PT_HSV;
- case icSigHlsData: return PT_HLS;
- case icSigYxyData: return PT_Yxy;
-
- case icSig6colorData:
- case icSigHexachromeData: return PT_HiFi;
-
- case icSigHeptachromeData:
- case icSig7colorData: return PT_HiFi7;
-
- case icSigOctachromeData:
- case icSig8colorData: return PT_HiFi8;
-
- case icSigMCH9Data:
- case icSig9colorData: return PT_HiFi9;
-
- case icSigMCHAData:
- case icSig10colorData: return PT_HiFi10;
-
- case icSigMCHBData:
- case icSig11colorData: return PT_HiFi11;
-
- case icSigMCHCData:
- case icSig12colorData: return PT_HiFi12;
-
- case icSigMCHDData:
- case icSig13colorData: return PT_HiFi13;
-
- case icSigMCHEData:
- case icSig14colorData: return PT_HiFi14;
-
- case icSigMCHFData:
- case icSig15colorData: return PT_HiFi15;
-
- default: return icMaxEnumData;
- }
-}
-
-
-int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace)
-{
-
- switch (ColorSpace) {
-
- case icSigGrayData: return 1;
-
- case icSig2colorData: return 2;
-
- case icSigXYZData:
- case icSigLabData:
- case icSigLuvData:
- case icSigYCbCrData:
- case icSigYxyData:
- case icSigRgbData:
- case icSigHsvData:
- case icSigHlsData:
- case icSigCmyData:
- case icSig3colorData: return 3;
-
- case icSigLuvKData:
- case icSigCmykData:
- case icSig4colorData: return 4;
-
- case icSigMCH5Data:
- case icSig5colorData: return 5;
-
- case icSigHexachromeData:
- case icSig6colorData: return 6;
-
- case icSigHeptachromeData:
- case icSig7colorData: return 7;
-
- case icSigOctachromeData:
- case icSig8colorData: return 8;
-
- case icSigMCH9Data:
- case icSig9colorData: return 9;
-
- case icSigMCHAData:
- case icSig10colorData: return 10;
-
- case icSigMCHBData:
- case icSig11colorData: return 11;
-
- case icSigMCHCData:
- case icSig12colorData: return 12;
-
- case icSigMCHDData:
- case icSig13colorData: return 13;
-
- case icSigMCHEData:
- case icSig14colorData: return 14;
-
- case icSigMCHFData:
- case icSig15colorData: return 15;
-
- default: return 3;
- }
-
-}
-
-
-// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable
-// number of gridpoints that would make exact match. However, a
-// prelinearization of 258 entries, would map 0xFF00 on entry 257.
-// This is almost what we need, unfortunately, the rest of entries
-// should be scaled by (255*257/256) and this is not exact.
-//
-// An intermediate solution would be to use 257 entries. This does not
-// map 0xFF00 exactly on a node, but so close that the dE induced is
-// negligible. AND the rest of curve is exact.
-
-static
-void CreateLabPrelinearization(LPGAMMATABLE LabTable[])
-{
- int i;
-
- LabTable[0] = cmsAllocGamma(257);
- LabTable[1] = cmsBuildGamma(257, 1.0);
- LabTable[2] = cmsBuildGamma(257, 1.0);
-
- // L* uses 257 entries. Entry 256 holds 0xFFFF, so, the effective range
- // is 0..0xFF00. Last entry (257) is also collapsed to 0xFFFF
-
- // From 0 to 0xFF00
- for (i=0; i < 256; i++)
- LabTable[0]->GammaTable[i] = RGB_8_TO_16(i);
-
- // Repeat last for 0xFFFF
- LabTable[0] ->GammaTable[256] = 0xFFFF;
-}
-
+// Gamut LUT Creation -----------------------------------------------------------------------------------------
// Used by gamut & softproofing
typedef struct {
- cmsHTRANSFORM hInput; // From whatever input color space. NULL for Lab
+ cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL
cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back
- double Thereshold; // The thereshold after which is considered out of gamut
+ cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut
- } GAMUTCHAIN,FAR* LPGAMUTCHAIN;
+ } GAMUTCHAIN;
// This sampler does compute gamut boundaries by comparing original
// values with a transform going back and forth. Values above ERR_THERESHOLD
// of maximum are considered out of gamut.
-
#define ERR_THERESHOLD 5
static
-int GamutSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
- LPGAMUTCHAIN t = (LPGAMUTCHAIN) Cargo;
- WORD Proof[MAXCHANNELS], Check[MAXCHANNELS];
- WORD Proof2[MAXCHANNELS], Check2[MAXCHANNELS];
+ GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo;
cmsCIELab LabIn1, LabOut1;
cmsCIELab LabIn2, LabOut2;
- double dE1, dE2, ErrorRatio;
+ cmsFloat32Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
+ cmsFloat64Number dE1, dE2, ErrorRatio;
// Assume in-gamut by default.
dE1 = 0.;
dE2 = 0;
ErrorRatio = 1.0;
-
- // Any input space? I can use In[] no matter channels
- // because is just one pixel
-
- if (t -> hInput != NULL) cmsDoTransform(t -> hInput, In, In, 1);
+ // Convert input to Lab
+ if (t -> hInput != NULL)
+ cmsDoTransform(t -> hInput, In, &LabIn1, 1);
// converts from PCS to colorant. This always
// does return in-gamut values,
- cmsDoTransform(t -> hForward, In, Proof, 1);
+ cmsDoTransform(t -> hForward, &LabIn1, Proof, 1);
// Now, do the inverse, from colorant to PCS.
- cmsDoTransform(t -> hReverse, Proof, Check, 1);
+ cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1);
+ memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
// Try again, but this time taking Check as input
- cmsDoTransform(t -> hForward, Check, Proof2, 1);
- cmsDoTransform(t -> hReverse, Proof2, Check2, 1);
+ cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
+ cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
+ // Take difference of direct value
+ dE1 = cmsDeltaE(&LabIn1, &LabOut1);
+
+ // Take difference of converted value
+ dE2 = cmsDeltaE(&LabIn2, &LabOut2);
- // Does the transform returns out-of-gamut?
- if (Check[0] == 0xFFFF &&
- Check[1] == 0xFFFF &&
- Check[2] == 0xFFFF)
-
- Out[0] = 0xFF00; // Out of gamut!
+ // if dE1 is small and dE2 is small, value is likely to be in gamut
+ if (dE1 < t->Thereshold && dE2 < t->Thereshold)
+ Out[0] = 0;
else {
- // Transport encoded values
- cmsLabEncoded2Float(&LabIn1, In);
- cmsLabEncoded2Float(&LabOut1, Check);
-
- // Take difference of direct value
- dE1 = cmsDeltaE(&LabIn1, &LabOut1);
-
- cmsLabEncoded2Float(&LabIn2, Check);
- cmsLabEncoded2Float(&LabOut2, Check2);
-
- // Take difference of converted value
- dE2 = cmsDeltaE(&LabIn2, &LabOut2);
-
-
- // if dE1 is small and dE2 is small, value is likely to be in gamut
- if (dE1 < t->Thereshold && dE2 < t->Thereshold)
+ // if dE1 is small and dE2 is big, undefined. Assume in gamut
+ if (dE1 < t->Thereshold && dE2 > t->Thereshold)
Out[0] = 0;
else
- // if dE1 is small and dE2 is big, undefined. Assume in gamut
- if (dE1 < t->Thereshold && dE2 > t->Thereshold)
- Out[0] = 0;
- else
- // dE1 is big and dE2 is small, clearly out of gamut
- if (dE1 > t->Thereshold && dE2 < t->Thereshold)
- Out[0] = (WORD) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
- else {
+ // dE1 is big and dE2 is small, clearly out of gamut
+ if (dE1 > t->Thereshold && dE2 < t->Thereshold)
+ Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
+ else {
- // dE1 is big and dE2 is also big, could be due to perceptual mapping
- // so take error ratio
- if (dE2 == 0.0)
- ErrorRatio = dE1;
- else
- ErrorRatio = dE1 / dE2;
+ // dE1 is big and dE2 is also big, could be due to perceptual mapping
+ // so take error ratio
+ if (dE2 == 0.0)
+ ErrorRatio = dE1;
+ else
+ ErrorRatio = dE1 / dE2;
- if (ErrorRatio > t->Thereshold)
- Out[0] = (WORD) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
- else
- Out[0] = 0;
- }
+ if (ErrorRatio > t->Thereshold)
+ Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
+ else
+ Out[0] = 0;
+ }
+ }
- }
return TRUE;
}
-
-// Does compute a gamut LUT going back and forth across
-// pcs -> relativ. colorimetric intent -> pcs
-// the dE obtained is then annotated on the LUT.
-// values truely out of gamut, are clipped to dE = 0xFFFE
-// and values changed are supposed to be handled by
-// any gamut remapping, so, are out of gamut as well.
+// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs
+// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE
+// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well.
//
-// **WARNING: This algorithm does assume that gamut
-// remapping algorithms does NOT move in-gamut colors,
-// of course, many perceptual and saturation intents does
-// not work in such way, but relativ. ones should.
+// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors,
+// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should.
-static
-LPLUT ComputeGamutWithInput(cmsHPROFILE hInput, cmsHPROFILE hProfile, int Intent)
+cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsUInt32Number Intents[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number nGamutPCSposition,
+ cmsHPROFILE hGamut)
{
cmsHPROFILE hLab;
- LPLUT Gamut;
- DWORD dwFormat;
+ cmsPipeline* Gamut;
+ cmsStage* CLUT;
+ cmsUInt32Number dwFormat;
GAMUTCHAIN Chain;
- int nErrState, nChannels, nGridpoints;
- LPGAMMATABLE Trans[3];
- icColorSpaceSignature ColorSpace;
+ int nChannels, nGridpoints;
+ cmsColorSpaceSignature ColorSpace;
+ cmsUInt32Number i;
+ cmsHPROFILE ProfileList[256];
+ cmsBool BPCList[256];
+ cmsFloat64Number AdaptationList[256];
+ cmsUInt32Number IntentList[256];
+
+ memset(&Chain, 0, sizeof(GAMUTCHAIN));
- ZeroMemory(&Chain, sizeof(GAMUTCHAIN));
+ if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition);
+ return NULL;
+ }
- hLab = cmsCreateLabProfile(NULL);
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) return NULL;
- // Safeguard against early abortion
- nErrState = cmsErrorAction(LCMS_ERROR_IGNORE);
// The figure of merit. On matrix-shaper profiles, should be almost zero as
// the conversion is pretty exact. On LUT based profiles, different resolutions
// of input and output CLUT may result in differences.
- if (!cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) &&
- !cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_OUTPUT))
+ if (cmsIsMatrixShaper(hGamut)) {
Chain.Thereshold = 1.0;
- else
+ }
+ else {
Chain.Thereshold = ERR_THERESHOLD;
-
- ColorSpace = cmsGetColorSpace(hProfile);
-
- // If input profile specified, create a transform from such profile to Lab
- if (hInput != NULL) {
-
- nChannels = _cmsChannelsOf(ColorSpace);
- nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
- dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
-
- Chain.hInput = cmsCreateTransform(hInput, dwFormat,
- hLab, TYPE_Lab_16,
- Intent,
- cmsFLAGS_NOTPRECALC);
- }
- else {
- // Input transform=NULL (Lab) Used to compute the gamut tag
- // This table will take 53 points to give some accurancy,
- // 53 * 53 * 53 * 2 = 291K
-
- nChannels = 3; // For Lab
- nGridpoints = 53;
- Chain.hInput = NULL;
- dwFormat = (CHANNELS_SH(_cmsChannelsOf(ColorSpace))|BYTES_SH(2));
}
- // Does create the forward step
- Chain.hForward = cmsCreateTransform(hLab, TYPE_Lab_16,
- hProfile, dwFormat,
- INTENT_RELATIVE_COLORIMETRIC,
- cmsFLAGS_NOTPRECALC);
+ // Create a copy of parameters
+ for (i=0; i < nGamutPCSposition; i++) {
+ ProfileList[i] = hProfiles[i];
+ BPCList[i] = BPC[i];
+ AdaptationList[i] = AdaptationStates[i];
+ IntentList[i] = Intents[i];
+ }
+
+ // Fill Lab identity
+ ProfileList[nGamutPCSposition] = hLab;
+ BPCList[nGamutPCSposition] = 0;
+ AdaptationList[nGamutPCSposition] = 1.0;
+ Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
+
+
+ ColorSpace = cmsGetColorSpace(hGamut);
+
+ nChannels = cmsChannelsOf(ColorSpace);
+ nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
+ dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
+
+ // 16 bits to Lab double
+ Chain.hInput = cmsCreateExtendedTransform(ContextID,
+ nGamutPCSposition + 1,
+ ProfileList,
+ BPCList,
+ Intents,
+ AdaptationList,
+ NULL, 0,
+ dwFormat, TYPE_Lab_DBL,
+ cmsFLAGS_NOCACHE);
+
+
+ // Does create the forward step. Lab double to cmsFloat32Number
+ dwFormat = (FLOAT_SH(1)|CHANNELS_SH(nChannels)|BYTES_SH(4));
+ Chain.hForward = cmsCreateTransformTHR(ContextID,
+ hLab, TYPE_Lab_DBL,
+ hGamut, dwFormat,
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE);
// Does create the backwards step
- Chain.hReverse = cmsCreateTransform(hProfile, dwFormat,
- hLab, TYPE_Lab_16,
- INTENT_RELATIVE_COLORIMETRIC,
- cmsFLAGS_NOTPRECALC);
-
- // Restores error handler previous state
- cmsErrorAction(nErrState);
+ Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat,
+ hLab, TYPE_Lab_DBL,
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE);
// All ok?
if (Chain.hForward && Chain.hReverse) {
- // Go on, try to compute gamut LUT from PCS.
- // This consist on a single channel containing
- // dE when doing a transform back and forth on
- // the colorimetric intent.
+ // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing
+ // dE when doing a transform back and forth on the colorimetric intent.
- Gamut = cmsAllocLUT();
- Gamut = cmsAlloc3DGrid(Gamut, nGridpoints, nChannels, 1);
+ Gamut = cmsPipelineAlloc(ContextID, 3, 1);
- // If no input, then this is a gamut tag operated by Lab,
- // so include pertinent prelinearization
- if (hInput == NULL) {
+ if (Gamut != NULL) {
- CreateLabPrelinearization(Trans);
- cmsAllocLinearTable(Gamut, Trans, 1);
- cmsFreeGammaTriple(Trans);
- }
+ CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
+ cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT);
-
- cmsSample3DGrid(Gamut, GamutSampler, (LPVOID) &Chain, Gamut ->wFlags);
+ cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
+ }
}
else
Gamut = NULL; // Didn't work...
@@ -921,352 +434,187 @@
if (Chain.hInput) cmsDeleteTransform(Chain.hInput);
if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
-
- cmsCloseProfile(hLab);
+ if (hLab) cmsCloseProfile(hLab);
// And return computed hull
return Gamut;
}
-
-// Wrapper
+// Total Area Coverage estimation ----------------------------------------------------------------
-LPLUT _cmsComputeGamutLUT(cmsHPROFILE hProfile, int Intent)
-{
- return ComputeGamutWithInput(NULL, hProfile, Intent);
-}
+typedef struct {
+ cmsUInt32Number nOutputChans;
+ cmsHTRANSFORM hRoundTrip;
+ cmsFloat32Number MaxTAC;
+ cmsFloat32Number MaxInput[cmsMAXCHANNELS];
+
+} cmsTACestimator;
-// This routine does compute the gamut check CLUT. This CLUT goes from whatever
-// input space to the 0 or != 0 gamut check.
+// This callback just accounts the maximum ink dropped in the given node. It does not populate any
+// memory, as the destination table is NULL. Its only purpose it to know the global maximum.
+static
+int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo)
+{
+ cmsTACestimator* bp = (cmsTACestimator*) Cargo;
+ cmsFloat32Number RoundTrip[cmsMAXCHANNELS];
+ cmsUInt32Number i;
+ cmsFloat32Number Sum;
+
+
+ // Evaluate the xform
+ cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1);
-LPLUT _cmsPrecalculateGamutCheck(cmsHTRANSFORM h)
-{
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) h;
+ // All all amounts of ink
+ for (Sum=0, i=0; i < bp ->nOutputChans; i++)
+ Sum += RoundTrip[i];
+
+ // If above maximum, keep track of input values
+ if (Sum > bp ->MaxTAC) {
+
+ bp ->MaxTAC = Sum;
- return ComputeGamutWithInput(p->InputProfile, p ->PreviewProfile, p->Intent);
+ for (i=0; i < bp ->nOutputChans; i++) {
+ bp ->MaxInput[i] = In[i];
+ }
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(Out);
}
-// SoftProofing. Convert from Lab to device, then back to Lab,
-// any gamut remapping is applied
-
-static
-int SoftProofSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+// Detect Total area coverage of the profile
+cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile)
{
- LPGAMUTCHAIN t = (LPGAMUTCHAIN) Cargo;
- WORD Colorant[MAXCHANNELS];
+ cmsTACestimator bp;
+ cmsUInt32Number dwFormatter;
+ cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS];
+ cmsHPROFILE hLab;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
- // From pcs to colorant
- cmsDoTransform(t -> hForward, In, Colorant, 1);
+ // TAC only works on output profiles
+ if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) {
+ return 0;
+ }
+
+ // Create a fake formatter for result
+ dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE);
- // Now, do the inverse, from colorant to pcs.
- cmsDoTransform(t -> hReverse, Colorant, Out, 1);
+ bp.nOutputChans = T_CHANNELS(dwFormatter);
+ bp.MaxTAC = 0; // Initial TAC is 0
- return TRUE;
-}
-
-// Does return Softproofing LUT on desired intent
+ // for safety
+ if (bp.nOutputChans >= cmsMAXCHANNELS) return 0;
-LPLUT _cmsComputeSoftProofLUT(cmsHPROFILE hProfile, int nIntent)
-{
- cmsHPROFILE hLab;
- LPLUT SoftProof;
- DWORD dwFormat;
- GAMUTCHAIN Chain;
- int nErrState;
- LPGAMMATABLE Trans[3];
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) return 0;
+ // Setup a roundtrip on perceptual intent in output profile for TAC estimation
+ bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16,
+ hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
+
+ cmsCloseProfile(hLab);
+ if (bp.hRoundTrip == NULL) return 0;
+
+ // For L* we only need black and white. For C* we need many points
+ GridPoints[0] = 6;
+ GridPoints[1] = 74;
+ GridPoints[2] = 74;
- // LUTs are never abs. colorimetric, is the transform who
- // is responsible of generating white point displacement
- if (nIntent == INTENT_ABSOLUTE_COLORIMETRIC)
- nIntent = INTENT_RELATIVE_COLORIMETRIC;
-
- ZeroMemory(&Chain, sizeof(GAMUTCHAIN));
-
- hLab = cmsCreateLabProfile(NULL);
-
- // ONLY 4 channels
- dwFormat = (CHANNELS_SH(4)|BYTES_SH(2));
-
- // Safeguard against early abortion
- nErrState = cmsErrorAction(LCMS_ERROR_IGNORE);
-
- // Does create the first step
- Chain.hForward = cmsCreateTransform(hLab, TYPE_Lab_16,
- hProfile, dwFormat,
- nIntent,
- cmsFLAGS_NOTPRECALC);
-
- // Does create the last step
- Chain.hReverse = cmsCreateTransform(hProfile, dwFormat,
- hLab, TYPE_Lab_16,
- INTENT_RELATIVE_COLORIMETRIC,
- cmsFLAGS_NOTPRECALC);
+ if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
+ bp.MaxTAC = 0;
+ }
- // Restores error handler previous state
- cmsErrorAction(nErrState);
-
- // All ok?
- if (Chain.hForward && Chain.hReverse) {
-
- // This is Lab -> Lab, so 33 point should hold anything
- SoftProof = cmsAllocLUT();
- SoftProof = cmsAlloc3DGrid(SoftProof, 33, 3, 3);
+ cmsDeleteTransform(bp.hRoundTrip);
- CreateLabPrelinearization(Trans);
- cmsAllocLinearTable(SoftProof, Trans, 1);
- cmsFreeGammaTriple(Trans);
-
- cmsSample3DGrid(SoftProof, SoftProofSampler, (LPVOID) &Chain, SoftProof->wFlags);
- }
- else
- SoftProof = NULL; // Didn't work...
-
- // Free all needed stuff.
- if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
- if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
-
- cmsCloseProfile(hLab);
-
- return SoftProof;
+ // Results in %
+ return bp.MaxTAC;
}
-static
-int MostlyLinear(WORD Table[], int nEntries)
+// Carefully, clamp on CIELab space.
+
+cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
+ double amax, double amin,
+ double bmax, double bmin)
{
- register int i;
- int diff;
+
+ // Whole Luma surface to zero
- for (i=5; i < nEntries; i++) {
+ if (Lab -> L < 0) {
+
+ Lab-> L = Lab->a = Lab-> b = 0.0;
+ return FALSE;
+ }
- diff = abs((int) Table[i] - (int) _cmsQuantizeVal(i, nEntries));
- if (diff > 0x0300)
- return 0;
- }
+ // Clamp white, DISCARD HIGHLIGHTS. This is done
+ // in such way because icc spec doesn't allow the
+ // use of L>100 as a highlight means.
+
+ if (Lab->L > 100)
+ Lab -> L = 100;
+
+ // Check out gamut prism, on a, b faces
- return 1;
-}
+ if (Lab -> a < amin || Lab->a > amax||
+ Lab -> b < bmin || Lab->b > bmax) {
+
+ cmsCIELCh LCh;
+ double h, slope;
+
+ // Falls outside a, b limits. Transports to LCh space,
+ // and then do the clipping
-static
-void SlopeLimiting(WORD Table[], int nEntries)
-{
- int At = (int) floor((double) nEntries * 0.02 + 0.5); // Cutoff at 2%
- double Val, Slope;
- int i;
+ if (Lab -> a == 0.0) { // Is hue exactly 90?
+
+ // atan will not work, so clamp here
+ Lab -> b = Lab->b < 0 ? bmin : bmax;
+ return TRUE;
+ }
- Val = Table[At];
- Slope = Val / At;
+ cmsLab2LCh(&LCh, Lab);
+
+ slope = Lab -> b / Lab -> a;
+ h = LCh.h;
- for (i=0; i < At; i++)
- Table[i] = (WORD) floor(i * Slope + 0.5);
+ // There are 4 zones
-}
-
+ if ((h >= 0. && h < 45.) ||
+ (h >= 315 && h <= 360.)) {
-// Check for monotonicity.
-
-static
-LCMSBOOL IsMonotonic(LPGAMMATABLE t)
-{
- int n = t -> nEntries;
- int i, last;
+ // clip by amax
+ Lab -> a = amax;
+ Lab -> b = amax * slope;
+ }
+ else
+ if (h >= 45. && h < 135.)
+ {
+ // clip by bmax
+ Lab -> b = bmax;
+ Lab -> a = bmax / slope;
+ }
+ else
+ if (h >= 135. && h < 225.) {
+ // clip by amin
+ Lab -> a = amin;
+ Lab -> b = amin * slope;
- last = t ->GammaTable[n-1];
-
- for (i = n-2; i >= 0; --i) {
-
- if (t ->GammaTable[i] > last)
-
- return FALSE;
- else
- last = t ->GammaTable[i];
+ }
+ else
+ if (h >= 225. && h < 315.) {
+ // clip by bmin
+ Lab -> b = bmin;
+ Lab -> a = bmin / slope;
+ }
+ else {
+ cmsSignalError(0, cmsERROR_RANGE, "Invalid angle");
+ return FALSE;
+ }
}
return TRUE;
}
-
-// Check for endpoints
-
-static
-LCMSBOOL HasProperEndpoints(LPGAMMATABLE t)
-{
- if (t ->GammaTable[0] != 0) return FALSE;
- if (t ->GammaTable[t ->nEntries-1] != 0xFFFF) return FALSE;
-
- return TRUE;
-}
-
-
-
-#define PRELINEARIZATION_POINTS 4096
-
-// Fixes the gamma balancing of transform. Thanks to Mike Chaney
-// for pointing this subtle bug.
-
-void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransforms, LPLUT Grid)
-{
- LPGAMMATABLE Trans[MAXCHANNELS];
- unsigned int t, i, v;
- int j;
- WORD In[MAXCHANNELS], Out[MAXCHANNELS];
- LCMSBOOL lIsSuitable;
- _LPcmsTRANSFORM InputXForm = (_LPcmsTRANSFORM) h[0];
- _LPcmsTRANSFORM OutputXForm = (_LPcmsTRANSFORM) h[nTransforms-1];
-
-
- // First space is *Lab, use our specialized curves for v2 Lab
-
- if (InputXForm ->EntryColorSpace == icSigLabData &&
- OutputXForm->ExitColorSpace != icSigLabData) {
-
- CreateLabPrelinearization(Trans);
- cmsAllocLinearTable(Grid, Trans, 1);
- cmsFreeGammaTriple(Trans);
- return;
- }
-
-
- // Do nothing on all but Gray/RGB to Gray/RGB transforms
-
- if (((InputXForm ->EntryColorSpace != icSigRgbData) && (InputXForm ->EntryColorSpace != icSigGrayData)) ||
- ((OutputXForm->ExitColorSpace != icSigRgbData) && (OutputXForm->ExitColorSpace != icSigGrayData))) return;
-
-
- for (t = 0; t < Grid -> InputChan; t++)
- Trans[t] = cmsAllocGamma(PRELINEARIZATION_POINTS);
-
- for (i=0; i < PRELINEARIZATION_POINTS; i++) {
-
- v = _cmsQuantizeVal(i, PRELINEARIZATION_POINTS);
-
- for (t=0; t < Grid -> InputChan; t++)
- In[t] = (WORD) v;
-
- cmsDoTransform(h[0], In, Out, 1);
- for (j=1; j < nTransforms; j++)
- cmsDoTransform(h[j], Out, Out, 1);
-
- for (t=0; t < Grid -> InputChan; t++)
- Trans[t] ->GammaTable[i] = Out[t];
-
- }
-
-
- // Check transfer curves
- lIsSuitable = TRUE;
- for (t=0; (lIsSuitable && (t < Grid->InputChan)); t++) {
-
-
- // Exclude if already linear
- if (MostlyLinear(Trans[t]->GammaTable, PRELINEARIZATION_POINTS))
- lIsSuitable = FALSE;
-
- // Exclude if non-monotonic
- if (!IsMonotonic(Trans[t]))
- lIsSuitable = FALSE;
-
- // Exclude if weird endpoints
- if (!HasProperEndpoints(Trans[t]))
- lIsSuitable = FALSE;
-
- /*
- // Exclude if transfer function is not smooth enough
- // to be modelled as a gamma function, or the gamma is reversed
-
- if (cmsEstimateGamma(Trans[t]) < 1.0)
- lIsSuitable = FALSE;
- */
-
- }
-
- if (lIsSuitable) {
-
- for (t = 0; t < Grid ->InputChan; t++)
- SlopeLimiting(Trans[t]->GammaTable, Trans[t]->nEntries);
- }
-
- if (lIsSuitable) cmsAllocLinearTable(Grid, Trans, 1);
-
-
- for (t = 0; t < Grid ->InputChan; t++)
- cmsFreeGamma(Trans[t]);
-
-
-}
-
-
-// Compute K -> L* relationship. Flags may include black point compensation. In this case,
-// the relationship is assumed from the profile with BPC to a black point zero.
-static
-LPGAMMATABLE ComputeKToLstar(cmsHPROFILE hProfile, int nPoints, int Intent, DWORD dwFlags)
-{
- LPGAMMATABLE out;
- int i;
- WORD cmyk[4], wLab[3];
- cmsHPROFILE hLab = cmsCreateLabProfile(NULL);
- cmsHTRANSFORM xform = cmsCreateTransform(hProfile, TYPE_CMYK_16,
- hLab, TYPE_Lab_16,
- Intent, (dwFlags|cmsFLAGS_NOTPRECALC));
-
-
- out = cmsAllocGamma(nPoints);
- for (i=0; i < nPoints; i++) {
-
- cmyk[0] = 0;
- cmyk[1] = 0;
- cmyk[2] = 0;
- cmyk[3] = _cmsQuantizeVal(i, nPoints);
-
- cmsDoTransform(xform, cmyk, wLab, 1);
- out->GammaTable[i] = (WORD) (0xFFFF - wLab[0]);
- }
-
- cmsDeleteTransform(xform);
- cmsCloseProfile(hLab);
-
- return out;
-}
-
-
-
-// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
-// using the proof direction on both profiles to find K->L* relationship
-// then joining both curves. dwFlags may include black point compensation.
-
-LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints)
-{
- LPGAMMATABLE in, out;
- LPGAMMATABLE KTone;
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) hCMYK2CMYK;
-
-
- // Make sure CMYK -> CMYK
- if (p -> EntryColorSpace != icSigCmykData ||
- p -> ExitColorSpace != icSigCmykData) return NULL;
-
- // Create individual curves. BPC works also as each K to L* is
- // computed as a BPC to zero black point in case of L*
- in = ComputeKToLstar(p ->InputProfile, nPoints, p->Intent, p -> dwOriginalFlags);
- out = ComputeKToLstar(p ->OutputProfile, nPoints, p->Intent, p -> dwOriginalFlags);
-
- // Build the relationship
- KTone = cmsJoinGamma(in, out);
-
- cmsFreeGamma(in); cmsFreeGamma(out);
-
- // Make sure it is monotonic
-
- if (!IsMonotonic(KTone)) {
-
- cmsFreeGamma(KTone);
- return NULL;
- }
-
-
- return KTone;
-}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,667 +49,341 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
-// Interpolation
-
-#include "lcms.h"
+#include "lcms2_internal.h"
-void cmsCalcL16Params(int nSamples, LPL16PARAMS p)
-{
- p -> nSamples = nSamples;
- p -> Domain = (WORD) (nSamples - 1);
- p -> nInputs = p -> nOutputs = 1;
+// This module incorporates several interpolation routines, for 1, 3, 4, 5, 6, 7 and 8 channels on input and
+// up to 65535 channels on output. The user may change those by using the interpolation plug-in
-}
+// Interpolation routines by default
+static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
+// This is the default factory
+static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory;
-// Eval gray LUT having only one input channel
+// Main plug-in entry
+cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data)
+{
+ cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
-static
-void Eval1Input(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
- Fixed32 fk;
- Fixed32 k0, k1, rk, K0, K1;
- int OutChan;
+ if (Data == NULL) {
- fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
- k0 = FIXED_TO_INT(fk);
- rk = (WORD) FIXED_REST_TO_INT(fk);
-
- k1 = k0 + (StageABC[0] != 0xFFFFU ? 1 : 0);
+ Interpolators = DefaultInterpolatorsFactory;
+ return TRUE;
+ }
- K0 = p16 -> opta1 * k0;
- K1 = p16 -> opta1 * k1;
-
- for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
-
- StageLMN[OutChan] = (WORD) FixedLERP(rk, LutTable[K0+OutChan],
- LutTable[K1+OutChan]);
- }
+ // Set replacement functions
+ Interpolators = Plugin ->InterpolatorsFactory;
+ return TRUE;
}
-
-// For more that 3 inputs (i.e., CMYK)
-// evaluate two 3-dimensional interpolations and then linearly interpolate between them.
+// Set the interpolation method
static
-void Eval4Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
+cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
{
- Fixed32 fk;
- Fixed32 k0, rk;
- int K0, K1;
- LPWORD T;
- int i;
- WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
- fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
- k0 = FIXED_TO_INT(fk);
- rk = FIXED_REST_TO_INT(fk);
-
- K0 = p16 -> opta4 * k0;
- K1 = p16 -> opta4 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
- p16 -> nInputs = 3;
-
- T = LutTable + K0;
-
- cmsTetrahedralInterp16(StageABC + 1, Tmp1, T, p16);
-
-
- T = LutTable + K1;
-
- cmsTetrahedralInterp16(StageABC + 1, Tmp2, T, p16);
-
-
- p16 -> nInputs = 4;
- for (i=0; i < p16 -> nOutputs; i++)
- {
- StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
+ // Invoke factory, possibly in the Plug-in
+ p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
- }
-
-}
-
-
-static
-void Eval5Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
- Fixed32 fk;
- Fixed32 k0, rk;
- int K0, K1;
- LPWORD T;
- int i;
- WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
- fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
- k0 = FIXED_TO_INT(fk);
- rk = FIXED_REST_TO_INT(fk);
+ // If unsupported by the plug-in, go for the LittleCMS default.
+ // If happens only if an extern plug-in is being used
+ if (p ->Interpolation.Lerp16 == NULL)
+ p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);
- K0 = p16 -> opta5 * k0;
- K1 = p16 -> opta5 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
- p16 -> nInputs = 4;
-
- T = LutTable + K0;
-
- Eval4Inputs(StageABC + 1, Tmp1, T, p16);
-
- T = LutTable + K1;
-
- Eval4Inputs(StageABC + 1, Tmp2, T, p16);
-
- p16 -> nInputs = 5;
- for (i=0; i < p16 -> nOutputs; i++)
- {
- StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
-
- }
-
+ // Check for valid interpolator (we just check one member of the union)
+ if (p ->Interpolation.Lerp16 == NULL) {
+ return FALSE;
+ }
+ return TRUE;
}
-static
-void Eval6Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
+// This function precalculates as many parameters as possible to speed up the interpolation.
+cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
+ const cmsUInt32Number nSamples[],
+ int InputChan, int OutputChan,
+ const void *Table,
+ cmsUInt32Number dwFlags)
{
- Fixed32 fk;
- Fixed32 k0, rk;
- int K0, K1;
- LPWORD T;
- int i;
- WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
+ cmsInterpParams* p;
+ int i;
- fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
- k0 = FIXED_TO_INT(fk);
- rk = FIXED_REST_TO_INT(fk);
-
- K0 = p16 -> opta6 * k0;
- K1 = p16 -> opta6 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
- p16 -> nInputs = 5;
-
- T = LutTable + K0;
+ // Check for maximum inputs
+ if (InputChan > MAX_INPUT_DIMENSIONS) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS);
+ return NULL;
+ }
- Eval5Inputs(StageABC + 1, Tmp1, T, p16);
-
- T = LutTable + K1;
-
- Eval5Inputs(StageABC + 1, Tmp2, T, p16);
+ // Creates an empty object
+ p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));
+ if (p == NULL) return NULL;
- p16 -> nInputs = 6;
- for (i=0; i < p16 -> nOutputs; i++)
- {
- StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
- }
+ // Keep original parameters
+ p -> dwFlags = dwFlags;
+ p -> nInputs = InputChan;
+ p -> nOutputs = OutputChan;
+ p ->Table = Table;
+ p ->ContextID = ContextID;
-}
+ // Fill samples per input direction and domain (which is number of nodes minus one)
+ for (i=0; i < InputChan; i++) {
-static
-void Eval7Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
- Fixed32 fk;
- Fixed32 k0, rk;
- int K0, K1;
- LPWORD T;
- int i;
- WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
+ p -> nSamples[i] = nSamples[i];
+ p -> Domain[i] = nSamples[i] - 1;
+ }
+
+ // Compute factors to apply to each component to index the grid array
+ p -> opta[0] = p -> nOutputs;
+ for (i=1; i < InputChan; i++)
+ p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
- fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
- k0 = FIXED_TO_INT(fk);
- rk = FIXED_REST_TO_INT(fk);
-
- K0 = p16 -> opta7 * k0;
- K1 = p16 -> opta7 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
- p16 -> nInputs = 6;
-
- T = LutTable + K0;
+ if (!_cmsSetInterpolationRoutine(p)) {
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
+ _cmsFree(ContextID, p);
+ return NULL;
+ }
- Eval6Inputs(StageABC + 1, Tmp1, T, p16);
-
- T = LutTable + K1;
-
- Eval6Inputs(StageABC + 1, Tmp2, T, p16);
-
- p16 -> nInputs = 7;
- for (i=0; i < p16 -> nOutputs; i++)
- {
- StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
- }
-
+ // All seems ok
+ return p;
}
-static
-void Eval8Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
+
+// This one is a wrapper on the anterior, but assuming all directions have same number of nodes
+cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags)
{
- Fixed32 fk;
- Fixed32 k0, rk;
- int K0, K1;
- LPWORD T;
- int i;
- WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
- fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
- k0 = FIXED_TO_INT(fk);
- rk = FIXED_REST_TO_INT(fk);
+ int i;
+ cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
- K0 = p16 -> opta8 * k0;
- K1 = p16 -> opta8 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
- p16 -> nInputs = 7;
-
- T = LutTable + K0;
-
- Eval7Inputs(StageABC + 1, Tmp1, T, p16);
+ // Fill the auxiliar array
+ for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
+ Samples[i] = nSamples;
- T = LutTable + K1;
-
- Eval7Inputs(StageABC + 1, Tmp2, T, p16);
-
- p16 -> nInputs = 8;
- for (i=0; i < p16 -> nOutputs; i++)
- {
- StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
- }
-
+ // Call the extended function
+ return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
}
-// Fills optimization parameters
-
-void cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan,
- LCMSBOOL lUseTetrahedral, LPL16PARAMS p)
+// Free all associated memory
+void _cmsFreeInterpParams(cmsInterpParams* p)
{
- int clutPoints;
-
- cmsCalcL16Params(nSamples, p);
-
- p -> nInputs = InputChan;
- p -> nOutputs = OutputChan;
-
- clutPoints = p -> Domain + 1;
-
- p -> opta1 = p -> nOutputs; // Z
- p -> opta2 = p -> opta1 * clutPoints; // Y
- p -> opta3 = p -> opta2 * clutPoints; // X
- p -> opta4 = p -> opta3 * clutPoints; // Used only in 4 inputs LUT
- p -> opta5 = p -> opta4 * clutPoints; // Used only in 5 inputs LUT
- p -> opta6 = p -> opta5 * clutPoints; // Used only on 6 inputs LUT
- p -> opta7 = p -> opta6 * clutPoints; // Used only on 7 inputs LUT
- p -> opta8 = p -> opta7 * clutPoints; // Used only on 8 inputs LUT
-
-
- switch (InputChan) {
+ if (p != NULL) _cmsFree(p ->ContextID, p);
+}
- case 1: // Gray LUT
-
- p ->Interp3D = Eval1Input;
- break;
-
- case 3: // RGB et al
- if (lUseTetrahedral) {
- p ->Interp3D = cmsTetrahedralInterp16;
- }
- else
- p ->Interp3D = cmsTrilinearInterp16;
- break;
-
- case 4: // CMYK LUT
- p ->Interp3D = Eval4Inputs;
- break;
-
- case 5: // 5 Inks
- p ->Interp3D = Eval5Inputs;
- break;
-
- case 6: // 6 Inks
- p -> Interp3D = Eval6Inputs;
- break;
-
- case 7: // 7 inks
- p ->Interp3D = Eval7Inputs;
- break;
-
- case 8: // 8 inks
- p ->Interp3D = Eval8Inputs;
- break;
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Unsupported restoration (%d channels)", InputChan);
- }
-
+// Inline fixed point interpolation
+cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
+{
+ cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
+ dif = (dif >> 16) + l;
+ return (cmsUInt16Number) (dif);
}
-void cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p)
+// Linear interpolation (Fixed-point optimized)
+static
+void LinLerp1D(register const cmsUInt16Number Value[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p)
{
- cmsCalcCLUT16ParamsEx(nSamples, InputChan, OutputChan, FALSE, p);
+ cmsUInt16Number y1, y0;
+ int cell0, rest;
+ int val3;
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
+
+ // if last value...
+ if (Value[0] == 0xffff) {
+
+ Output[0] = LutTable[p -> Domain[0]];
+ return;
+ }
+
+ val3 = p -> Domain[0] * Value[0];
+ val3 = _cmsToFixedDomain(val3); // To fixed 15.16
+
+ cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
+ rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits
+
+ y0 = LutTable[cell0];
+ y1 = LutTable[cell0+1];
+
+
+ Output[0] = LinearInterp(rest, y0, y1);
}
-
-#ifdef USE_FLOAT
-
-
-// Floating-point version
-
-WORD cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p)
+// Floating-point version of 1D interpolation
+static
+void LinLerp1Dfloat(const cmsFloat32Number Value[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
{
- double y1, y0;
- double y;
- double val2, rest;
+ cmsFloat32Number y1, y0;
+ cmsFloat32Number val2, rest;
int cell0, cell1;
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
// if last value...
+ if (Value[0] == 1.0) {
+ Output[0] = LutTable[p -> Domain[0]];
+ return;
+ }
- if (Value == 0xffff) return LutTable[p -> Domain];
-
- val2 = p -> Domain * ((double) Value / 65535.0);
+ val2 = p -> Domain[0] * Value[0];
cell0 = (int) floor(val2);
cell1 = (int) ceil(val2);
// Rest is 16 LSB bits
-
rest = val2 - cell0;
y0 = LutTable[cell0] ;
y1 = LutTable[cell1] ;
- y = y0 + (y1 - y0) * rest;
-
-
- return (WORD) floor(y+.5);
-}
-
-#endif
-
-
-//
-// Linear interpolation (Fixed-point optimized, but C source)
-//
-
-
-#ifdef USE_C
-
-WORD cmsLinearInterpLUT16(WORD Value1, WORD LutTable[], LPL16PARAMS p)
-{
- WORD y1, y0;
- WORD y;
- int dif, a1;
- int cell0, rest;
- int val3, Value;
-
- // if last value...
-
-
- Value = Value1;
- if (Value == 0xffff) return LutTable[p -> Domain];
-
- val3 = p -> Domain * Value;
- val3 = ToFixedDomain(val3); // To fixed 15.16
-
- cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
- rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits
-
- y0 = LutTable[cell0] ;
- y1 = LutTable[cell0+1] ;
-
- dif = (int) y1 - y0; // dif is in domain -ffff ... ffff
-
- if (dif >= 0)
- {
- a1 = ToFixedDomain(dif * rest);
- a1 += 0x8000;
- }
- else
- {
- a1 = ToFixedDomain((- dif) * rest);
- a1 -= 0x8000;
- a1 = -a1;
- }
-
- y = (WORD) (y0 + FIXED_TO_INT(a1));
-
- return y;
-}
-
-#endif
-
-// Linear interpolation (asm by hand optimized)
-
-#ifdef USE_ASSEMBLER
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4033)
-#pragma warning(disable : 4035)
-#endif
-
-WORD cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p)
-{
- int xDomain = p -> Domain;
-
-
- if (Value == 0xffff) return LutTable[p -> Domain];
- else
- ASM {
- xor eax, eax
- mov ax, word ptr ss:Value
- mov edx, ss:xDomain
- mul edx // val3 = p -> Domain * Value;
- shld edx, eax, 16 // Convert it to fixed 15.16
- shl eax, 16 // * 65536 / 65535
- mov ebx, 0x0000ffff
- div ebx
- mov ecx, eax
- sar ecx, 16 // ecx = cell0
- mov edx, eax // rest = (val2 & 0xFFFFU)
- and edx, 0x0000ffff // edx = rest
- mov ebx, ss:LutTable
- lea eax, dword ptr [ebx+2*ecx] // Ptr to LUT
- xor ebx, ebx
- mov bx, word ptr [eax] // EBX = y0
- movzx eax, word ptr [eax+2] // EAX = y1
- sub eax, ebx // EAX = y1-y0
- js IsNegative
- mul edx // EAX = EAX * rest
- shld edx, eax, 16 // Pass it to fixed
- sal eax, 16 // * 65536 / 65535
- mov ecx, 0x0000ffff
- div ecx
- add eax, 0x8000 // Rounding
- sar eax, 16
- add eax, ebx // Done!
- }
-
- RET((WORD) _EAX);
-
- IsNegative:
-
- ASM {
- neg eax
- mul edx // EAX = EAX * rest
- shld edx, eax, 16 // Pass it to fixed
- sal eax, 16 // * 65536 / 65535
- mov ecx, 0x0000ffff
- div ecx
- sub eax, 0x8000
- neg eax
- sar eax, 16
- add eax, ebx // Done!
- }
-
- RET((WORD) _EAX);
-}
-
-#ifdef _MSC_VER
-#pragma warning(default : 4033)
-#pragma warning(default : 4035)
-#endif
-
-#endif
-
-Fixed32 cmsLinearInterpFixed(WORD Value1, WORD LutTable[], LPL16PARAMS p)
-{
- Fixed32 y1, y0;
- int cell0;
- int val3, Value;
-
- // if last value...
-
-
- Value = Value1;
- if (Value == 0xffffU) return LutTable[p -> Domain];
-
- val3 = p -> Domain * Value;
- val3 = ToFixedDomain(val3); // To fixed 15.16
-
- cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
-
- y0 = LutTable[cell0] ;
- y1 = LutTable[cell0+1] ;
-
-
- return y0 + FixedMul((y1 - y0), (val3 & 0xFFFFL));
+ Output[0] = y0 + (y1 - y0) * rest;
}
-// Reverse Lineal interpolation (16 bits)
-// Im using a sort of binary search here, this is not a time-critical function
-WORD cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p)
+// Eval gray LUT having only one input channel
+static
+void Eval1Input(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p16)
{
- register int l = 1;
- register int r = 0x10000;
- register int x = 0, res; // 'int' Give spacing for negative values
- int NumZeroes, NumPoles;
- int cell0, cell1;
- double val2;
- double y0, y1, x0, x1;
- double a, b, f;
-
- // July/27 2001 - Expanded to handle degenerated curves with an arbitrary
- // number of elements containing 0 at the begining of the table (Zeroes)
- // and another arbitrary number of poles (FFFFh) at the end.
- // First the zero and pole extents are computed, then value is compared.
-
- NumZeroes = 0;
- while (LutTable[NumZeroes] == 0 && NumZeroes < p -> Domain)
- NumZeroes++;
-
- // There are no zeros at the beginning and we are trying to find a zero, so
- // return anything. It seems zero would be the less destructive choice
-
- if (NumZeroes == 0 && Value == 0)
- return 0;
-
- NumPoles = 0;
- while (LutTable[p -> Domain - NumPoles] == 0xFFFF && NumPoles < p -> Domain)
- NumPoles++;
-
- // Does the curve belong to this case?
- if (NumZeroes > 1 || NumPoles > 1)
- {
- int a, b;
-
- // Identify if value fall downto 0 or FFFF zone
- if (Value == 0) return 0;
- // if (Value == 0xFFFF) return 0xFFFF;
-
- // else restrict to valid zone
-
- a = ((NumZeroes-1) * 0xFFFF) / p->Domain;
- b = ((p -> Domain - NumPoles) * 0xFFFF) / p ->Domain;
-
- l = a - 1;
- r = b + 1;
- }
+ cmsS15Fixed16Number fk;
+ cmsS15Fixed16Number k0, k1, rk, K0, K1;
+ int v;
+ cmsUInt32Number OutChan;
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
-
- // Seems not a degenerated case... apply binary search
-
- while (r > l) {
-
- x = (l + r) / 2;
-
- res = (int) cmsLinearInterpLUT16((WORD) (x - 1), LutTable, p);
-
- if (res == Value) {
+ v = Input[0] * p16 -> Domain[0];
+ fk = _cmsToFixedDomain(v);
- // Found exact match.
-
- return (WORD) (x - 1);
- }
+ k0 = FIXED_TO_INT(fk);
+ rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
- if (res > Value) r = x - 1;
- else l = x + 1;
- }
-
- // Not found, should we interpolate?
-
-
- // Get surrounding nodes
+ k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
- val2 = p -> Domain * ((double) (x - 1) / 65535.0);
-
- cell0 = (int) floor(val2);
- cell1 = (int) ceil(val2);
-
- if (cell0 == cell1) return (WORD) x;
-
- y0 = LutTable[cell0] ;
- x0 = (65535.0 * cell0) / p ->Domain;
-
- y1 = LutTable[cell1] ;
- x1 = (65535.0 * cell1) / p ->Domain;
+ K0 = p16 -> opta[0] * k0;
+ K1 = p16 -> opta[0] * k1;
- a = (y1 - y0) / (x1 - x0);
- b = y0 - a * x0;
-
- if (fabs(a) < 0.01) return (WORD) x;
+ for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
- f = ((Value - b) / a);
-
- if (f < 0.0) return (WORD) 0;
- if (f >= 65535.0) return (WORD) 0xFFFF;
-
- return (WORD) floor(f + 0.5);
-
+ Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
+ }
}
+// Eval gray LUT having only one input channel
+static
+void Eval1InputFloat(const cmsFloat32Number Value[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
+{
+ cmsFloat32Number y1, y0;
+ cmsFloat32Number val2, rest;
+ int cell0, cell1;
+ cmsUInt32Number OutChan;
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
-// Trilinear interpolation (16 bits) - float version
+ // if last value...
+ if (Value[0] == 1.0) {
+ Output[0] = LutTable[p -> Domain[0]];
+ return;
+ }
-#ifdef USE_FLOAT
-void cmsTrilinearInterp16(WORD Input[], WORD Output[],
- WORD LutTable[], LPL16PARAMS p)
+ val2 = p -> Domain[0] * Value[0];
+
+ cell0 = (int) floor(val2);
+ cell1 = (int) ceil(val2);
+
+ // Rest is 16 LSB bits
+ rest = val2 - cell0;
-{
-# define LERP(a,l,h) (double) ((l)+(((h)-(l))*(a)))
-# define DENS(X, Y, Z) (double) (LutTable[TotalOut*((Z)+clutPoints*((Y)+clutPoints*(X)))+OutChan])
+ cell0 *= p -> opta[0];
+ cell1 *= p -> opta[0];
+
+ for (OutChan=0; OutChan < p->nOutputs; OutChan++) {
+
+ y0 = LutTable[cell0 + OutChan] ;
+ y1 = LutTable[cell1 + OutChan] ;
+
+ Output[OutChan] = y0 + (y1 - y0) * rest;
+ }
+}
- double px, py, pz;
+// Trilinear interpolation (16 bits) - cmsFloat32Number version
+static
+void TrilinearInterpFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
+
+{
+# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
+# define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
+
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
+ cmsFloat32Number px, py, pz;
int x0, y0, z0,
- x1, y1, z1;
- int clutPoints, TotalOut, OutChan;
- double fx, fy, fz,
- d000, d001, d010, d011,
- d100, d101, d110, d111,
- dx00, dx01, dx10, dx11,
- dxy0, dxy1, dxyz;
+ X0, Y0, Z0, X1, Y1, Z1;
+ int TotalOut, OutChan;
+ cmsFloat32Number fx, fy, fz,
+ d000, d001, d010, d011,
+ d100, d101, d110, d111,
+ dx00, dx01, dx10, dx11,
+ dxy0, dxy1, dxyz;
-
- clutPoints = p -> Domain + 1;
TotalOut = p -> nOutputs;
- px = ((double) Input[0] * (p->Domain)) / 65535.0;
- py = ((double) Input[1] * (p->Domain)) / 65535.0;
- pz = ((double) Input[2] * (p->Domain)) / 65535.0;
+ px = Input[0] * p->Domain[0];
+ py = Input[1] * p->Domain[1];
+ pz = Input[2] * p->Domain[2];
+
+ x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
+ y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
+ z0 = (int) _cmsQuickFloor(pz); fz = pz - (cmsFloat32Number) z0;
+
+ X0 = p -> opta[2] * x0;
+ X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]);
+
+ Y0 = p -> opta[1] * y0;
+ Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]);
- x0 = (int) _cmsQuickFloor(px); fx = px - (double) x0;
- y0 = (int) _cmsQuickFloor(py); fy = py - (double) y0;
- z0 = (int) _cmsQuickFloor(pz); fz = pz - (double) z0;
+ Z0 = p -> opta[0] * z0;
+ Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]);
+
+ for (OutChan = 0; OutChan < TotalOut; OutChan++) {
- x1 = x0 + (Input[0] != 0xFFFFU ? 1 : 0);
- y1 = y0 + (Input[1] != 0xFFFFU ? 1 : 0);
- z1 = z0 + (Input[2] != 0xFFFFU ? 1 : 0);
+ d000 = DENS(X0, Y0, Z0);
+ d001 = DENS(X0, Y0, Z1);
+ d010 = DENS(X0, Y1, Z0);
+ d011 = DENS(X0, Y1, Z1);
+
+ d100 = DENS(X1, Y0, Z0);
+ d101 = DENS(X1, Y0, Z1);
+ d110 = DENS(X1, Y1, Z0);
+ d111 = DENS(X1, Y1, Z1);
- for (OutChan = 0; OutChan < TotalOut; OutChan++)
- {
-
- d000 = DENS(x0, y0, z0);
- d001 = DENS(x0, y0, z1);
- d010 = DENS(x0, y1, z0);
- d011 = DENS(x0, y1, z1);
-
- d100 = DENS(x1, y0, z0);
- d101 = DENS(x1, y0, z1);
- d110 = DENS(x1, y1, z0);
- d111 = DENS(x1, y1, z1);
+ dx00 = LERP(fx, d000, d100);
+ dx01 = LERP(fx, d001, d101);
+ dx10 = LERP(fx, d010, d110);
+ dx11 = LERP(fx, d011, d111);
-
- dx00 = LERP(fx, d000, d100);
- dx01 = LERP(fx, d001, d101);
- dx10 = LERP(fx, d010, d110);
- dx11 = LERP(fx, d011, d111);
+ dxy0 = LERP(fy, dx00, dx10);
+ dxy1 = LERP(fy, dx01, dx11);
- dxy0 = LERP(fy, dx00, dx10);
- dxy1 = LERP(fy, dx01, dx11);
+ dxyz = LERP(fz, dxy0, dxy1);
- dxyz = LERP(fz, dxy0, dxy1);
-
- Output[OutChan] = (WORD) floor(dxyz + .5);
+ Output[OutChan] = dxyz;
}
@@ -716,24 +391,19 @@
# undef DENS
}
-
-#endif
-
-
-#ifndef USE_FLOAT
-
// Trilinear interpolation (16 bits) - optimized version
-
-void cmsTrilinearInterp16(WORD Input[], WORD Output[],
- WORD LutTable[], LPL16PARAMS p)
+static
+void TrilinearInterp16(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p)
{
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
-#define LERP(a,l,h) (WORD) (l+ ROUND_FIXED_TO_INT(((h-l)*a)))
-
+#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
int OutChan, TotalOut;
- Fixed32 fx, fy, fz;
+ cmsS15Fixed16Number fx, fy, fz;
register int rx, ry, rz;
int x0, y0, z0;
register int X0, X1, Y0, Y1, Z0, Z1;
@@ -742,37 +412,32 @@
dx00, dx01, dx10, dx11,
dxy0, dxy1, dxyz;
-
TotalOut = p -> nOutputs;
- fx = ToFixedDomain((int) Input[0] * p -> Domain);
+ fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
x0 = FIXED_TO_INT(fx);
rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
- fy = ToFixedDomain((int) Input[1] * p -> Domain);
+ fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
y0 = FIXED_TO_INT(fy);
ry = FIXED_REST_TO_INT(fy);
- fz = ToFixedDomain((int) Input[2] * p -> Domain);
+ fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
z0 = FIXED_TO_INT(fz);
rz = FIXED_REST_TO_INT(fz);
-
- X0 = p -> opta3 * x0;
- X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3);
-
- Y0 = p -> opta2 * y0;
- Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2);
+ X0 = p -> opta[2] * x0;
+ X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
- Z0 = p -> opta1 * z0;
- Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta1);
-
+ Y0 = p -> opta[1] * y0;
+ Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
+ Z0 = p -> opta[0] * z0;
+ Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
- for (OutChan = 0; OutChan < TotalOut; OutChan++)
- {
+ for (OutChan = 0; OutChan < TotalOut; OutChan++) {
d000 = DENS(X0, Y0, Z0);
d001 = DENS(X0, Y0, Z1);
@@ -795,7 +460,7 @@
dxyz = LERP(rz, dxy0, dxy1);
- Output[OutChan] = (WORD) dxyz;
+ Output[OutChan] = (cmsUInt16Number) dxyz;
}
@@ -803,133 +468,128 @@
# undef DENS
}
-#endif
-
-
-#ifdef USE_FLOAT
-
-#define DENS(X, Y, Z) (double) (LutTable[TotalOut*((Z)+clutPoints*((Y)+clutPoints*(X)))+OutChan])
-
// Tetrahedral interpolation, using Sakamoto algorithm.
-
-void cmsTetrahedralInterp16(WORD Input[],
- WORD Output[],
- WORD LutTable[],
- LPL16PARAMS p)
+#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
+static
+void TetrahedralInterpFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
{
- double px, py, pz;
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
+ cmsFloat32Number px, py, pz;
int x0, y0, z0,
- x1, y1, z1;
- double fx, fy, fz;
- double c1=0, c2=0, c3=0;
- int clutPoints, OutChan, TotalOut;
+ X0, Y0, Z0, X1, Y1, Z1;
+ cmsFloat32Number rx, ry, rz;
+ cmsFloat32Number c0, c1=0, c2=0, c3=0;
+ int OutChan, TotalOut;
-
- clutPoints = p -> Domain + 1;
TotalOut = p -> nOutputs;
+ px = Input[0] * p->Domain[0];
+ py = Input[1] * p->Domain[1];
+ pz = Input[2] * p->Domain[2];
- px = ((double) Input[0] * p->Domain) / 65535.0;
- py = ((double) Input[1] * p->Domain) / 65535.0;
- pz = ((double) Input[2] * p->Domain) / 65535.0;
-
- x0 = (int) _cmsQuickFloor(px); fx = (px - (double) x0);
- y0 = (int) _cmsQuickFloor(py); fy = (py - (double) y0);
- z0 = (int) _cmsQuickFloor(pz); fz = (pz - (double) z0);
+ x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0);
+ y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0);
+ z0 = (int) _cmsQuickFloor(pz); rz = (pz - (cmsFloat32Number) z0);
- x1 = x0 + (Input[0] != 0xFFFFU ? 1 : 0);
- y1 = y0 + (Input[1] != 0xFFFFU ? 1 : 0);
- z1 = z0 + (Input[2] != 0xFFFFU ? 1 : 0);
+ X0 = p -> opta[2] * x0;
+ X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]);
+ Y0 = p -> opta[1] * y0;
+ Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]);
- for (OutChan=0; OutChan < TotalOut; OutChan++)
- {
+ Z0 = p -> opta[0] * z0;
+ Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]);
+
+ for (OutChan=0; OutChan < TotalOut; OutChan++) {
// These are the 6 Tetrahedral
- if (fx >= fy && fy >= fz)
- {
- c1 = DENS(x1, y0, z0) - DENS(x0, y0, z0);
- c2 = DENS(x1, y1, z0) - DENS(x1, y0, z0);
- c3 = DENS(x1, y1, z1) - DENS(x1, y1, z0);
- }
- else
- if (fx >= fz && fz >= fy)
- {
- c1 = DENS(x1, y0, z0) - DENS(x0, y0, z0);
- c2 = DENS(x1, y1, z1) - DENS(x1, y0, z1);
- c3 = DENS(x1, y0, z1) - DENS(x1, y0, z0);
- }
- else
- if (fz >= fx && fx >= fy)
- {
- c1 = DENS(x1, y0, z1) - DENS(x0, y0, z1);
- c2 = DENS(x1, y1, z1) - DENS(x1, y0, z1);
- c3 = DENS(x0, y0, z1) - DENS(x0, y0, z0);
- }
- else
- if (fy >= fx && fx >= fz)
- {
- c1 = DENS(x1, y1, z0) - DENS(x0, y1, z0);
- c2 = DENS(x0, y1, z0) - DENS(x0, y0, z0);
- c3 = DENS(x1, y1, z1) - DENS(x1, y1, z0);
+ c0 = DENS(X0, Y0, Z0);
+
+ if (rx >= ry && ry >= rz) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (rx >= rz && rz >= ry) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+
+ }
+ else
+ if (rz >= rx && rx >= ry) {
+
+ c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
- }
- else
- if (fy >= fz && fz >= fx)
- {
- c1 = DENS(x1, y1, z1) - DENS(x0, y1, z1);
- c2 = DENS(x0, y1, z0) - DENS(x0, y0, z0);
- c3 = DENS(x0, y1, z1) - DENS(x0, y1, z0);
- }
- else
- if (fz >= fy && fy >= fx)
- {
- c1 = DENS(x1, y1, z1) - DENS(x0, y1, z1);
- c2 = DENS(x0, y1, z1) - DENS(x0, y0, z1);
- c3 = DENS(x0, y0, z1) - DENS(x0, y0, z0);
- }
- else
- {
- c1 = c2 = c3 = 0;
- // assert(FALSE);
- }
+ }
+ else
+ if (ry >= rx && rx >= rz) {
+
+ c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (ry >= rz && rz >= rx) {
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
- Output[OutChan] = (WORD) floor((double) DENS(x0,y0,z0) + c1 * fx + c2 * fy + c3 * fz + .5);
+ }
+ else
+ if (rz >= ry && ry >= rx) {
+
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else {
+ c1 = c2 = c3 = 0;
+ }
+
+ Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
}
}
#undef DENS
-#else
+
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
-
-void cmsTetrahedralInterp16(WORD Input[],
- WORD Output[],
- WORD LutTable1[],
- LPL16PARAMS p)
+static
+void TetrahedralInterp16(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p)
{
-
- Fixed32 fx, fy, fz;
- Fixed32 rx, ry, rz;
- int x0, y0, z0;
- Fixed32 c0, c1, c2, c3, Rest;
- int OutChan;
- Fixed32 X0, X1, Y0, Y1, Z0, Z1;
- int TotalOut = p -> nOutputs;
- register LPWORD LutTable = LutTable1;
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
+ cmsS15Fixed16Number fx, fy, fz;
+ cmsS15Fixed16Number rx, ry, rz;
+ int x0, y0, z0;
+ cmsS15Fixed16Number c0, c1, c2, c3, Rest;
+ cmsUInt32Number OutChan;
+ cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+ cmsUInt32Number TotalOut = p -> nOutputs;
-
- fx = ToFixedDomain((int) Input[0] * p -> Domain);
- fy = ToFixedDomain((int) Input[1] * p -> Domain);
- fz = ToFixedDomain((int) Input[2] * p -> Domain);
+ fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
+ fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
+ fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
x0 = FIXED_TO_INT(fx);
y0 = FIXED_TO_INT(fy);
@@ -939,196 +599,754 @@
ry = FIXED_REST_TO_INT(fy);
rz = FIXED_REST_TO_INT(fz);
- X0 = p -> opta3 * x0;
- X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3);
+ X0 = p -> opta[2] * x0;
+ X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
- Y0 = p -> opta2 * y0;
- Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2);
+ Y0 = p -> opta[1] * y0;
+ Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
- Z0 = p -> opta1 * z0;
- Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta1);
-
-
+ Z0 = p -> opta[0] * z0;
+ Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
// These are the 6 Tetrahedral
for (OutChan=0; OutChan < TotalOut; OutChan++) {
- c0 = DENS(X0, Y0, Z0);
+ c0 = DENS(X0, Y0, Z0);
+
+ if (rx >= ry && ry >= rz) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (rx >= rz && rz >= ry) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+
+ }
+ else
+ if (rz >= rx && rx >= ry) {
+
+ c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else
+ if (ry >= rx && rx >= rz) {
- if (rx >= ry && ry >= rz) {
+ c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (ry >= rz && rz >= rx) {
+
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
+
+ }
+ else
+ if (rz >= ry && ry >= rx) {
+
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else {
+ c1 = c2 = c3 = 0;
+ }
+
+ Rest = c1 * rx + c2 * ry + c3 * rz;
+
+ Output[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
+ }
+
+}
+#undef DENS
+
- c1 = DENS(X1, Y0, Z0) - c0;
- c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
- c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
+static
+void Eval4Inputs(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p16)
+{
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
+ cmsS15Fixed16Number fk;
+ cmsS15Fixed16Number k0, rk;
+ int K0, K1;
+ cmsS15Fixed16Number fx, fy, fz;
+ cmsS15Fixed16Number rx, ry, rz;
+ int x0, y0, z0;
+ cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+ cmsUInt32Number i;
+ cmsS15Fixed16Number c0, c1, c2, c3, Rest;
+ cmsUInt32Number OutChan;
+ cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+
+
+ fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
+ fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
+ fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
+ fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
+
+ k0 = FIXED_TO_INT(fk);
+ x0 = FIXED_TO_INT(fx);
+ y0 = FIXED_TO_INT(fy);
+ z0 = FIXED_TO_INT(fz);
+
+ rk = FIXED_REST_TO_INT(fk);
+ rx = FIXED_REST_TO_INT(fx);
+ ry = FIXED_REST_TO_INT(fy);
+ rz = FIXED_REST_TO_INT(fz);
+
+ K0 = p16 -> opta[3] * k0;
+ K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);
- }
- else
- if (rx >= rz && rz >= ry) {
+ X0 = p16 -> opta[2] * x0;
+ X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);
+
+ Y0 = p16 -> opta[1] * y0;
+ Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);
+
+ Z0 = p16 -> opta[0] * z0;
+ Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);
+
+ LutTable = (cmsUInt16Number*) p16 -> Table;
+ LutTable += K0;
+
+ for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
+
+ c0 = DENS(X0, Y0, Z0);
+
+ if (rx >= ry && ry >= rz) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (rx >= rz && rz >= ry) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+
+ }
+ else
+ if (rz >= rx && rx >= ry) {
+
+ c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else
+ if (ry >= rx && rx >= rz) {
- c1 = DENS(X1, Y0, Z0) - c0;
- c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
- c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+ c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (ry >= rz && rz >= rx) {
+
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
+
+ }
+ else
+ if (rz >= ry && ry >= rx) {
+
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else {
+ c1 = c2 = c3 = 0;
+ }
+
+ Rest = c1 * rx + c2 * ry + c3 * rz;
+
+ Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
+ }
+
+
+ LutTable = (cmsUInt16Number*) p16 -> Table;
+ LutTable += K1;
+
+ for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
+
+ c0 = DENS(X0, Y0, Z0);
+
+ if (rx >= ry && ry >= rz) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (rx >= rz && rz >= ry) {
+
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+
+ }
+ else
+ if (rz >= rx && rx >= ry) {
+
+ c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else
+ if (ry >= rx && rx >= rz) {
+
+ c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+
+ }
+ else
+ if (ry >= rz && rz >= rx) {
- }
- else
- if (rz >= rx && rx >= ry) {
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
+
+ }
+ else
+ if (rz >= ry && ry >= rx) {
+
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+
+ }
+ else {
+ c1 = c2 = c3 = 0;
+ }
+
+ Rest = c1 * rx + c2 * ry + c3 * rz;
+
+ Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
+ }
+
+
+
+ for (i=0; i < p16 -> nOutputs; i++) {
+ Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
+ }
+}
+#undef DENS
+
+
+// For more that 3 inputs (i.e., CMYK)
+// evaluate two 3-dimensional interpolations and then linearly interpolate between them.
+
- c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
- c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
- c3 = DENS(X0, Y0, Z1) - c0;
+static
+void Eval4InputsFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
+{
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
+ cmsFloat32Number rest;
+ cmsFloat32Number pk;
+ int k0, K0, K1;
+ const cmsFloat32Number* T;
+ cmsUInt32Number i;
+ cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
+
+
+ pk = Input[0] * p->Domain[0];
+ k0 = _cmsQuickFloor(pk);
+ rest = pk - (cmsFloat32Number) k0;
+ K0 = p -> opta[3] * k0;
+ K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[3]);
+
+ p1 = *p;
+ memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ TetrahedralInterpFloat(Input + 1, Tmp1, &p1);
+
+ T = LutTable + K1;
+ p1.Table = T;
+ TetrahedralInterpFloat(Input + 1, Tmp2, &p1);
+
+ for (i=0; i < p -> nOutputs; i++)
+ {
+ cmsFloat32Number y0 = Tmp1[i];
+ cmsFloat32Number y1 = Tmp2[i];
+
+ Output[i] = y0 + (y1 - y0) * rest;
}
- else
- if (ry >= rx && rx >= rz) {
+}
+
+
+static
+void Eval5Inputs(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
- c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
- c2 = DENS(X0, Y1, Z0) - c0;
- c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+ register const cmsInterpParams* p16)
+{
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
+ cmsS15Fixed16Number fk;
+ cmsS15Fixed16Number k0, rk;
+ int K0, K1;
+ const cmsUInt16Number* T;
+ cmsUInt32Number i;
+ cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
- }
- else
- if (ry >= rz && rz >= rx) {
- c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
- c2 = DENS(X0, Y1, Z0) - c0;
- c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
+ fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
+ k0 = FIXED_TO_INT(fk);
+ rk = FIXED_REST_TO_INT(fk);
- }
- else
- if (rz >= ry && ry >= rx) {
+ K0 = p16 -> opta[4] * k0;
+ K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
+
+ p1 = *p16;
+ memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));
- c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
- c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
- c3 = DENS(X0, Y0, Z1) - c0;
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval4Inputs(Input + 1, Tmp1, &p1);
- }
- else {
- c1 = c2 = c3 = 0;
- // assert(FALSE);
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval4Inputs(Input + 1, Tmp2, &p1);
+
+ for (i=0; i < p16 -> nOutputs; i++) {
+
+ Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
}
- Rest = c1 * rx + c2 * ry + c3 * rz;
+}
+
+
+static
+void Eval5InputsFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
+{
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
+ cmsFloat32Number rest;
+ cmsFloat32Number pk;
+ int k0, K0, K1;
+ const cmsFloat32Number* T;
+ cmsUInt32Number i;
+ cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
+
+ pk = Input[0] * p->Domain[0];
+ k0 = _cmsQuickFloor(pk);
+ rest = pk - (cmsFloat32Number) k0;
- // There is a lot of math hidden in this expression. The rest is in fixed domain
- // and the result in 0..ffff domain. So the complete expression should be
- // ROUND_FIXED_TO_INT(ToFixedDomain(Rest)) But that can be optimized as (Rest + 0x7FFF) / 0xFFFF
+ K0 = p -> opta[4] * k0;
+ K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[4]);
+
+ p1 = *p;
+ memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval4InputsFloat(Input + 1, Tmp1, &p1);
- Output[OutChan] = (WORD) (c0 + ((Rest + 0x7FFF) / 0xFFFF));
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval4InputsFloat(Input + 1, Tmp2, &p1);
- }
+ for (i=0; i < p -> nOutputs; i++) {
+ cmsFloat32Number y0 = Tmp1[i];
+ cmsFloat32Number y1 = Tmp2[i];
+
+ Output[i] = y0 + (y1 - y0) * rest;
+ }
}
-#undef DENS
+static
+void Eval6Inputs(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p16)
+{
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
+ cmsS15Fixed16Number fk;
+ cmsS15Fixed16Number k0, rk;
+ int K0, K1;
+ const cmsUInt16Number* T;
+ cmsUInt32Number i;
+ cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
+
+ fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
+ k0 = FIXED_TO_INT(fk);
+ rk = FIXED_REST_TO_INT(fk);
+
+ K0 = p16 -> opta[5] * k0;
+ K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
+
+ p1 = *p16;
+ memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval5Inputs(Input + 1, Tmp1, &p1);
+
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval5Inputs(Input + 1, Tmp2, &p1);
+
+ for (i=0; i < p16 -> nOutputs; i++) {
+
+ Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
+ }
+
+}
+
-#endif
+static
+void Eval6InputsFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
+{
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
+ cmsFloat32Number rest;
+ cmsFloat32Number pk;
+ int k0, K0, K1;
+ const cmsFloat32Number* T;
+ cmsUInt32Number i;
+ cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
+
+ pk = Input[0] * p->Domain[0];
+ k0 = _cmsQuickFloor(pk);
+ rest = pk - (cmsFloat32Number) k0;
+
+ K0 = p -> opta[5] * k0;
+ K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[5]);
+
+ p1 = *p;
+ memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval5InputsFloat(Input + 1, Tmp1, &p1);
+
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval5InputsFloat(Input + 1, Tmp2, &p1);
+
+ for (i=0; i < p -> nOutputs; i++) {
+
+ cmsFloat32Number y0 = Tmp1[i];
+ cmsFloat32Number y1 = Tmp2[i];
+
+ Output[i] = y0 + (y1 - y0) * rest;
+ }
+}
+
+
+static
+void Eval7Inputs(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p16)
+{
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
+ cmsS15Fixed16Number fk;
+ cmsS15Fixed16Number k0, rk;
+ int K0, K1;
+ const cmsUInt16Number* T;
+ cmsUInt32Number i;
+ cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
-// A optimized interpolation for 8-bit input.
+ fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
+ k0 = FIXED_TO_INT(fk);
+ rk = FIXED_REST_TO_INT(fk);
+
+ K0 = p16 -> opta[6] * k0;
+ K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
-#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
+ p1 = *p16;
+ memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval6Inputs(Input + 1, Tmp1, &p1);
-void cmsTetrahedralInterp8(WORD Input[],
- WORD Output[],
- WORD LutTable[],
- LPL16PARAMS p)
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval6Inputs(Input + 1, Tmp2, &p1);
+
+ for (i=0; i < p16 -> nOutputs; i++) {
+ Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
+ }
+}
+
+
+static
+void Eval7InputsFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
{
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
+ cmsFloat32Number rest;
+ cmsFloat32Number pk;
+ int k0, K0, K1;
+ const cmsFloat32Number* T;
+ cmsUInt32Number i;
+ cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
- int r, g, b;
- Fixed32 rx, ry, rz;
- Fixed32 c1, c2, c3, Rest;
- int OutChan;
- register Fixed32 X0, X1, Y0, Y1, Z0, Z1;
- int TotalOut = p -> nOutputs;
- register LPL8PARAMS p8 = p ->p8;
+ pk = Input[0] * p->Domain[0];
+ k0 = _cmsQuickFloor(pk);
+ rest = pk - (cmsFloat32Number) k0;
+
+ K0 = p -> opta[6] * k0;
+ K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[6]);
+
+ p1 = *p;
+ memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval6InputsFloat(Input + 1, Tmp1, &p1);
+
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval6InputsFloat(Input + 1, Tmp2, &p1);
+
+
+ for (i=0; i < p -> nOutputs; i++) {
+
+ cmsFloat32Number y0 = Tmp1[i];
+ cmsFloat32Number y1 = Tmp2[i];
+
+ Output[i] = y0 + (y1 - y0) * rest;
+
+ }
+}
+
+static
+void Eval8Inputs(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const cmsInterpParams* p16)
+{
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
+ cmsS15Fixed16Number fk;
+ cmsS15Fixed16Number k0, rk;
+ int K0, K1;
+ const cmsUInt16Number* T;
+ cmsUInt32Number i;
+ cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
+
+ fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
+ k0 = FIXED_TO_INT(fk);
+ rk = FIXED_REST_TO_INT(fk);
+
+ K0 = p16 -> opta[7] * k0;
+ K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
+
+ p1 = *p16;
+ memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));
+
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval7Inputs(Input + 1, Tmp1, &p1);
+
+ T = LutTable + K1;
+ p1.Table = T;
+ Eval7Inputs(Input + 1, Tmp2, &p1);
+
+ for (i=0; i < p16 -> nOutputs; i++) {
+ Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
+ }
+}
- r = Input[0] >> 8;
- g = Input[1] >> 8;
- b = Input[2] >> 8;
-
- X0 = X1 = p8->X0[r];
- Y0 = Y1 = p8->Y0[g];
- Z0 = Z1 = p8->Z0[b];
+static
+void Eval8InputsFloat(const cmsFloat32Number Input[],
+ cmsFloat32Number Output[],
+ const cmsInterpParams* p)
+{
+ const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
+ cmsFloat32Number rest;
+ cmsFloat32Number pk;
+ int k0, K0, K1;
+ const cmsFloat32Number* T;
+ cmsUInt32Number i;
+ cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
+ cmsInterpParams p1;
- X1 += (r == 255) ? 0 : p ->opta3;
- Y1 += (g == 255) ? 0 : p ->opta2;
- Z1 += (b == 255) ? 0 : p ->opta1;
+ pk = Input[0] * p->Domain[0];
+ k0 = _cmsQuickFloor(pk);
+ rest = pk - (cmsFloat32Number) k0;
+
+ K0 = p -> opta[7] * k0;
+ K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[7]);
+
+ p1 = *p;
+ memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number));
- rx = p8 ->rx[r];
- ry = p8 ->ry[g];
- rz = p8 ->rz[b];
+ T = LutTable + K0;
+ p1.Table = T;
+
+ Eval7InputsFloat(Input + 1, Tmp1, &p1);
+
+ T = LutTable + K1;
+ p1.Table = T;
+
+ Eval7InputsFloat(Input + 1, Tmp2, &p1);
- // These are the 6 Tetrahedral
- for (OutChan=0; OutChan < TotalOut; OutChan++) {
-
- if (rx >= ry && ry >= rz)
- {
-
- c1 = DENS(X1, Y0, Z0) - DENS(X0, Y0, Z0);
- c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
- c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+ for (i=0; i < p -> nOutputs; i++) {
- }
- else
- if (rx >= rz && rz >= ry)
- {
- c1 = DENS(X1, Y0, Z0) - DENS(X0, Y0, Z0);
- c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
- c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+ cmsFloat32Number y0 = Tmp1[i];
+ cmsFloat32Number y1 = Tmp2[i];
- }
- else
- if (rz >= rx && rx >= ry)
- {
-
- c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
- c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
- c3 = DENS(X0, Y0, Z1) - DENS(X0, Y0, Z0);
-
+ Output[i] = y0 + (y1 - y0) * rest;
}
- else
- if (ry >= rx && rx >= rz)
- {
+}
+
+// The default factory
+static
+cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags)
+{
- c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
- c2 = DENS(X0, Y1, Z0) - DENS(X0, Y0, Z0);
- c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+ cmsInterpFunction Interpolation;
+ cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT);
+ cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);
+
+ memset(&Interpolation, 0, sizeof(Interpolation));
- }
- else
- if (ry >= rz && rz >= rx)
- {
+ // Safety check
+ if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)
+ return Interpolation;
+
+ switch (nInputChannels) {
- c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
- c2 = DENS(X0, Y1, Z0) - DENS(X0, Y0, Z0);
- c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
+ case 1: // Gray LUT / linear
+
+ if (nOutputChannels == 1) {
+
+ if (IsFloat)
+ Interpolation.LerpFloat = LinLerp1Dfloat;
+ else
+ Interpolation.Lerp16 = LinLerp1D;
- }
- else
- if (rz >= ry && ry >= rx)
- {
- c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
- c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
- c3 = DENS(X0, Y0, Z1) - DENS(X0, Y0, Z0);
+ }
+ else {
- }
- else {
- c1 = c2 = c3 = 0;
- // assert(FALSE);
- }
+ if (IsFloat)
+ Interpolation.LerpFloat = Eval1InputFloat;
+ else
+ Interpolation.Lerp16 = Eval1Input;
+ }
+ break;
- Rest = c1 * rx + c2 * ry + c3 * rz;
+ case 3: // RGB et al
+
+ if (IsTrilinear) {
+
+ if (IsFloat)
+ Interpolation.LerpFloat = TrilinearInterpFloat;
+ else
+ Interpolation.Lerp16 = TrilinearInterp16;
+ }
+ else {
+
+ if (IsFloat)
+ Interpolation.LerpFloat = TetrahedralInterpFloat;
+ else {
+
+ Interpolation.Lerp16 = TetrahedralInterp16;
+ }
+ }
+ break;
+
+ case 4: // CMYK lut
+
+ if (IsFloat)
+ Interpolation.LerpFloat = Eval4InputsFloat;
+ else
+ Interpolation.Lerp16 = Eval4Inputs;
+ break;
- Output[OutChan] = (WORD) (DENS(X0,Y0,Z0) + ((Rest + 0x7FFF) / 0xFFFF));
+ case 5: // 5 Inks
+ if (IsFloat)
+ Interpolation.LerpFloat = Eval5InputsFloat;
+ else
+ Interpolation.Lerp16 = Eval5Inputs;
+ break;
+
+ case 6: // 6 Inks
+ if (IsFloat)
+ Interpolation.LerpFloat = Eval6InputsFloat;
+ else
+ Interpolation.Lerp16 = Eval6Inputs;
+ break;
+
+ case 7: // 7 inks
+ if (IsFloat)
+ Interpolation.LerpFloat = Eval7InputsFloat;
+ else
+ Interpolation.Lerp16 = Eval7Inputs;
+ break;
+
+ case 8: // 8 inks
+ if (IsFloat)
+ Interpolation.LerpFloat = Eval8InputsFloat;
+ else
+ Interpolation.Lerp16 = Eval8Inputs;
+ break;
+
+ break;
+
+ default:
+ Interpolation.Lerp16 = NULL;
}
+ return Interpolation;
}
-
-#undef DENS
-
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -49,748 +50,1640 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
// Generic I/O, tag dictionary management, profile struct
-
+// IOhandlers are abstractions used by littleCMS to read from whatever file, stream,
+// memory block or any storage. Each IOhandler provides implementations for read,
+// write, seek and tell functions. LittleCMS code deals with IO across those objects.
+// In this way, is easier to add support for new storage media.
-#include "lcms.h"
+// NULL stream, for taking care of used space -------------------------------------
-
-// Memory-based stream ---------------------------------------------------
+// NULL IOhandler basically does nothing but keep track on how many bytes have been
+// written. This is handy when creating profiles, where the file size is needed in the
+// header. Then, whole profile is serialized across NULL IOhandler and a second pass
+// writes the bytes to the pertinent IOhandler.
typedef struct {
- LPBYTE Block; // Points to allocated memory
- size_t Size; // Size of allocated memory
- size_t Pointer; // Points to current location
- int FreeBlockOnClose; // As title
+ cmsUInt32Number Pointer; // Points to current location
+} FILENULL;
+
+static
+cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
+{
+ FILENULL* ResData = (FILENULL*) iohandler ->stream;
+
+ cmsUInt32Number len = size * count;
+ ResData -> Pointer += len;
+ return count;
+
+ cmsUNUSED_PARAMETER(Buffer);
+}
- } FILEMEM;
+static
+cmsBool NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
+{
+ FILENULL* ResData = (FILENULL*) iohandler ->stream;
+
+ ResData ->Pointer = offset;
+ return TRUE;
+}
+
+static
+cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler)
+{
+ FILENULL* ResData = (FILENULL*) iohandler ->stream;
+ return ResData -> Pointer;
+}
static
-LPVOID MemoryOpen(LPBYTE Block, size_t Size, char Mode)
+cmsBool NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Ptr)
{
- FILEMEM* fm = (FILEMEM*) _cmsMalloc(sizeof(FILEMEM));
- if (fm == NULL) return NULL;
+ FILENULL* ResData = (FILENULL*) iohandler ->stream;
+
+ ResData ->Pointer += size;
+ if (ResData ->Pointer > iohandler->UsedSpace)
+ iohandler->UsedSpace = ResData ->Pointer;
+
+ return TRUE;
- ZeroMemory(fm, sizeof(FILEMEM));
+ cmsUNUSED_PARAMETER(Ptr);
+}
- if (Mode == 'r') {
+static
+cmsBool NULLClose(cmsIOHANDLER* iohandler)
+{
+ FILENULL* ResData = (FILENULL*) iohandler ->stream;
- fm ->Block = (LPBYTE) _cmsMalloc(Size);
- if (fm ->Block == NULL) {
- _cmsFree(fm);
- return NULL;
- }
+ _cmsFree(iohandler ->ContextID, ResData);
+ _cmsFree(iohandler ->ContextID, iohandler);
+ return TRUE;
+}
- CopyMemory(fm->Block, Block, Size);
- fm ->FreeBlockOnClose = TRUE;
- }
- else {
- fm ->Block = Block;
- fm ->FreeBlockOnClose = FALSE;
- }
+// The NULL IOhandler creator
+cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID)
+{
+ struct _cms_io_handler* iohandler = NULL;
+ FILENULL* fm = NULL;
- fm ->Size = Size;
+ iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler));
+ if (iohandler == NULL) return NULL;
+
+ fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL));
+ if (fm == NULL) goto Error;
+
fm ->Pointer = 0;
- return (LPVOID) fm;
+ iohandler ->ContextID = ContextID;
+ iohandler ->stream = (void*) fm;
+ iohandler ->UsedSpace = 0;
+ iohandler ->PhysicalFile[0] = 0;
+
+ iohandler ->Read = NULLRead;
+ iohandler ->Seek = NULLSeek;
+ iohandler ->Close = NULLClose;
+ iohandler ->Tell = NULLTell;
+ iohandler ->Write = NULLWrite;
+
+ return iohandler;
+
+Error:
+ if (fm) _cmsFree(ContextID, fm);
+ if (iohandler) _cmsFree(ContextID, iohandler);
+ return NULL;
+
}
-static
-size_t MemoryRead(LPVOID buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc)
-{
- FILEMEM* ResData = (FILEMEM*) Icc ->stream;
- LPBYTE Ptr;
- size_t len = size * count;
- size_t extent = ResData -> Pointer + len;
+// Memory-based stream --------------------------------------------------------------
+
+// Those functions implements an iohandler which takes a block of memory as storage medium.
- if (len == 0) {
- return 0;
- }
+typedef struct {
+ cmsUInt8Number* Block; // Points to allocated memory
+ cmsUInt32Number Size; // Size of allocated memory
+ cmsUInt32Number Pointer; // Points to current location
+ int FreeBlockOnClose; // As title
+
+} FILEMEM;
- if (len / size != count) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with count / size.");
- return 0;
- }
+static
+cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
+{
+ FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
+ cmsUInt8Number* Ptr;
+ cmsUInt32Number len = size * count;
- if (extent < len || extent < ResData -> Pointer) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with len.");
- return 0;
- }
+ if (ResData -> Pointer + len > ResData -> Size){
- if (ResData -> Pointer + len > ResData -> Size) {
-
- len = (ResData -> Size - ResData -> Pointer);
- cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Got %d bytes, block should be of %d bytes", len * size, count * size);
- return 0;
- }
+ len = (ResData -> Size - ResData -> Pointer);
+ cmsSignalError(iohandler ->ContextID, cmsERROR_READ, "Read from memory error. Got %d bytes, block should be of %d bytes", len, count * size);
+ return 0;
+ }
Ptr = ResData -> Block;
Ptr += ResData -> Pointer;
- CopyMemory(buffer, Ptr, len);
- ResData -> Pointer += (int) len;
+ memmove(Buffer, Ptr, len);
+ ResData -> Pointer += len;
return count;
}
// SEEK_CUR is assumed
-
static
-LCMSBOOL MemorySeek(struct _lcms_iccprofile_struct* Icc, size_t offset)
+cmsBool MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset)
{
- FILEMEM* ResData = (FILEMEM*) Icc ->stream;
+ FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
if (offset > ResData ->Size) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Pointer error; probably corrupted file");
- return TRUE;
+ cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile");
+ return FALSE;
}
- ResData ->Pointer = (DWORD) offset;
- return FALSE;
+ ResData ->Pointer = offset;
+ return TRUE;
}
-// FTell
-
+// Tell for memory
static
-size_t MemoryTell(struct _lcms_iccprofile_struct* Icc)
+cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler)
{
- FILEMEM* ResData = (FILEMEM*) Icc ->stream;
+ FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
+ if (ResData == NULL) return 0;
return ResData -> Pointer;
}
-// Writes data to memory, also keeps used space for further reference. NO CHECK IS PERFORMED
-
+// Writes data to memory, also keeps used space for further reference.
static
-LCMSBOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr)
+cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr)
{
- FILEMEM* ResData = (FILEMEM*) Icc ->stream;
+ FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
- if (size == 0) return TRUE;
+ if (ResData == NULL) return FALSE; // Housekeeping
- if (ResData != NULL)
- CopyMemory(ResData ->Block + ResData ->Pointer, Ptr, size);
+ if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing
- ResData->Pointer += size;
- Icc->UsedSpace += size;
+ memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
+ ResData ->Pointer += size;
- return TRUE;
-}
+ if (ResData ->Pointer > iohandler->UsedSpace)
+ iohandler->UsedSpace = ResData ->Pointer;
-static
-LCMSBOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size)
-{
- FILEMEM* ResData = (FILEMEM*) Icc->stream;
-
- void* newBlock = NULL;
+ iohandler->UsedSpace += size;
- /* Follow same policies as functions in lcms.h */
- if (ResData->Size + size < 0) return NULL;
- if (ResData->Size + size > ((size_t)1024*1024*500)) return NULL;
-
- newBlock = realloc(ResData->Block, ResData->Size + size);
-
- if (!newBlock) {
- return FALSE;
- }
- ResData->Block = newBlock;
- ResData->Size += size;
return TRUE;
}
static
-LCMSBOOL MemoryClose(struct _lcms_iccprofile_struct* Icc)
+cmsBool MemoryClose(struct _cms_io_handler* iohandler)
{
- FILEMEM* ResData = (FILEMEM*) Icc ->stream;
+ FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
if (ResData ->FreeBlockOnClose) {
- if (ResData ->Block) _cmsFree(ResData ->Block);
+ if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block);
}
- _cmsFree(ResData);
- return 0;
+
+ _cmsFree(iohandler ->ContextID, ResData);
+ _cmsFree(iohandler ->ContextID, iohandler);
+
+ return TRUE;
}
+// Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes
+// a copy of the memory block for letting user to free the memory after invoking open profile. In write
+// mode ("w"), Buffere points to the begin of memory block to be written.
+cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode)
+{
+ cmsIOHANDLER* iohandler = NULL;
+ FILEMEM* fm = NULL;
+
+ _cmsAssert(AccessMode != NULL);
+
+ iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
+ if (iohandler == NULL) return NULL;
+
+ switch (*AccessMode) {
+
+ case 'r':
+ fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM));
+ if (fm == NULL) goto Error;
+
+ if (Buffer == NULL) {
+ cmsSignalError(ContextID, cmsERROR_READ, "Couldn't read profile from NULL pointer");
+ goto Error;
+ }
+
+ fm ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, size);
+ if (fm ->Block == NULL) {
+
+ _cmsFree(ContextID, fm);
+ _cmsFree(ContextID, iohandler);
+ cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", size);
+ return NULL;
+ }
+
+
+ memmove(fm->Block, Buffer, size);
+ fm ->FreeBlockOnClose = TRUE;
+ fm ->Size = size;
+ fm ->Pointer = 0;
+ break;
+
+ case 'w':
+ fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM));
+ if (fm == NULL) goto Error;
+
+ fm ->Block = (cmsUInt8Number*) Buffer;
+ fm ->FreeBlockOnClose = FALSE;
+ fm ->Size = size;
+ fm ->Pointer = 0;
+ break;
+
+ default:
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow access mode '%c'", *AccessMode);
+ return NULL;
+ }
+
+ iohandler ->ContextID = ContextID;
+ iohandler ->stream = (void*) fm;
+ iohandler ->UsedSpace = 0;
+ iohandler ->PhysicalFile[0] = 0;
+
+ iohandler ->Read = MemoryRead;
+ iohandler ->Seek = MemorySeek;
+ iohandler ->Close = MemoryClose;
+ iohandler ->Tell = MemoryTell;
+ iohandler ->Write = MemoryWrite;
+
+ return iohandler;
+
+Error:
+ if (fm) _cmsFree(ContextID, fm);
+ if (iohandler) _cmsFree(ContextID, iohandler);
+ return NULL;
+}
// File-based stream -------------------------------------------------------
+// Read count elements of size bytes each. Return number of elements read
static
-LPVOID FileOpen(const char* filename)
+cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
{
- return (void*) fopen(filename, "rb");
-}
+ cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream);
-static
-size_t FileRead(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc)
-{
- size_t nReaded = fread(buffer, size, count, (FILE*) Icc->stream);
if (nReaded != count) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
+ cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
return 0;
}
return nReaded;
}
+// Postion file pointer in the file
+static
+cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
+{
+ if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) {
+
+ cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Returns file pointer position
+static
+cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
+{
+ return ftell((FILE*)iohandler ->stream);
+}
+
+// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error
+static
+cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer)
+{
+ if (size == 0) return TRUE; // We allow to write 0 bytes, but nothing is written
+
+ iohandler->UsedSpace += size;
+ return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1);
+}
+
+// Closes the file
+static
+cmsBool FileClose(cmsIOHANDLER* iohandler)
+{
+ if (fclose((FILE*) iohandler ->stream) != 0) return FALSE;
+ _cmsFree(iohandler ->ContextID, iohandler);
+ return TRUE;
+}
+
+// Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set
+// to NULL and no real writting is performed. This only happens in writting access mode
+cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode)
+{
+ cmsIOHANDLER* iohandler = NULL;
+ FILE* fm = NULL;
+
+ iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
+ if (iohandler == NULL) return NULL;
+
+ switch (*AccessMode) {
+
+ case 'r':
+ fm = fopen(FileName, "rb");
+ if (fm == NULL) {
+ _cmsFree(ContextID, iohandler);
+ cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
+ return NULL;
+ }
+ break;
+
+ case 'w':
+ fm = fopen(FileName, "wb");
+ if (fm == NULL) {
+ _cmsFree(ContextID, iohandler);
+ cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
+ return NULL;
+ }
+ break;
+
+ default:
+ _cmsFree(ContextID, iohandler);
+ cmsSignalError(ContextID, cmsERROR_FILE, "Unknow access mode '%c'", *AccessMode);
+ return NULL;
+ }
+
+ iohandler ->ContextID = ContextID;
+ iohandler ->stream = (void*) fm;
+ iohandler ->UsedSpace = 0;
+
+ // Keep track of the original file
+ if (FileName != NULL) {
+
+ strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
+ iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
+ }
+
+ iohandler ->Read = FileRead;
+ iohandler ->Seek = FileSeek;
+ iohandler ->Close = FileClose;
+ iohandler ->Tell = FileTell;
+ iohandler ->Write = FileWrite;
+
+ return iohandler;
+}
+
+// Create a iohandler for stream based files
+cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream)
+{
+ cmsIOHANDLER* iohandler = NULL;
+
+ iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
+ if (iohandler == NULL) return NULL;
+
+ iohandler -> ContextID = ContextID;
+ iohandler -> stream = (void*) Stream;
+ iohandler -> UsedSpace = 0;
+ iohandler -> PhysicalFile[0] = 0;
+
+ iohandler ->Read = FileRead;
+ iohandler ->Seek = FileSeek;
+ iohandler ->Close = FileClose;
+ iohandler ->Tell = FileTell;
+ iohandler ->Write = FileWrite;
+
+ return iohandler;
+}
+
+
+
+// Close an open IO handler
+cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
+{
+ return io -> Close(io);
+}
+
+// -------------------------------------------------------------------------------------------------------
+
+// Creates an empty structure holding all required parameters
+cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
+{
+ time_t now = time(NULL);
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
+ if (Icc == NULL) return NULL;
+
+ Icc ->ContextID = ContextID;
+
+ // Set it to empty
+ Icc -> TagCount = 0;
+
+ // Set default version
+ Icc ->Version = 0x02100000;
+
+ // Set creation date/time
+ memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));
+
+ // Return the handle
+ return (cmsHPROFILE) Icc;
+}
+
+cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+
+ if (Icc == NULL) return NULL;
+ return Icc -> ContextID;
+}
+
+
+// Return the number of tags
+cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ if (Icc == NULL) return -1;
+
+ return Icc->TagCount;
+}
+
+// Return the tag signature of a given tag number
+cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+
+ if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available
+ if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check
+
+ return Icc ->TagNames[n];
+}
+
+
+static
+int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig)
+{
+ cmsUInt32Number i;
+
+ for (i=0; i < Profile -> TagCount; i++) {
+
+ if (sig == Profile -> TagNames[i])
+ return i;
+ }
+
+ return -1;
+}
+
+// Search for a specific tag in tag dictionary. Returns position or -1 if tag not found.
+// If followlinks is turned on, then the position of the linked tag is returned
+int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks)
+{
+ int n;
+ cmsTagSignature LinkedSig;
+
+ do {
+
+ // Search for given tag in ICC profile directory
+ n = SearchOneTag(Icc, sig);
+ if (n < 0)
+ return -1; // Not found
+
+ if (!lFollowLinks)
+ return n; // Found, don't follow links
+
+ // Is this a linked tag?
+ LinkedSig = Icc ->TagLinked[n];
+
+ // Yes, follow link
+ if (LinkedSig != (cmsTagSignature) 0) {
+ sig = LinkedSig;
+ }
+
+ } while (LinkedSig != (cmsTagSignature) 0);
+
+ return n;
+}
+
+
+// Create a new tag entry
static
-LCMSBOOL FileSeek(struct _lcms_iccprofile_struct* Icc, size_t offset)
+cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
+{
+ int i;
+
+ // Search for the tag
+ i = _cmsSearchTag(Icc, sig, FALSE);
+
+ // Now let's do it easy. If the tag has been already written, that's an error
+ if (i >= 0) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig);
+ return FALSE;
+ }
+ else {
+
+ // New one
+
+ if (Icc -> TagCount >= MAX_TABLE_TAG) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
+ return FALSE;
+ }
+
+ *NewPos = Icc ->TagCount;
+ Icc -> TagCount++;
+ }
+
+ return TRUE;
+}
+
+
+// Check existance
+cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) (void*) hProfile;
+ return _cmsSearchTag(Icc, sig, FALSE) >= 0;
+}
+
+
+// Read profile header and validate it
+cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
+{
+ cmsTagEntry Tag;
+ cmsICCHeader Header;
+ cmsUInt32Number i, j;
+ cmsUInt32Number HeaderSize;
+ cmsIOHANDLER* io = Icc ->IOhandler;
+ cmsUInt32Number TagCount;
+
+
+ // Read the header
+ if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) {
+ return FALSE;
+ }
+
+ // Validate file as an ICC profile
+ if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature");
+ return FALSE;
+ }
+
+ // Adjust endianess of the used parameters
+ Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
+ Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace);
+ Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs);
+ Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
+ Icc -> flags = _cmsAdjustEndianess32(Header.flags);
+ Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer);
+ Icc -> model = _cmsAdjustEndianess32(Header.model);
+ _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes);
+ Icc -> Version = _cmsAdjustEndianess32(Header.version);
+
+ // Get size as reported in header
+ HeaderSize = _cmsAdjustEndianess32(Header.size);
+
+ // Get creation date/time
+ _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created);
+
+ // The profile ID are 32 raw bytes
+ memmove(Icc ->ProfileID.ID32, Header.profileID.ID32, 16);
+
+
+ // Read tag directory
+ if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE;
+ if (TagCount > MAX_TABLE_TAG) {
+
+ cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount);
+ return FALSE;
+ }
+
+ // Read tag directory
+ Icc -> TagCount = 0;
+ for (i=0; i < TagCount; i++) {
+
+ if (!_cmsReadUInt32Number(io, (cmsUInt32Number *) &Tag.sig)) return FALSE;
+ if (!_cmsReadUInt32Number(io, &Tag.offset)) return FALSE;
+ if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE;
+
+ // Perform some sanity check. Offset + size should fall inside file.
+ if (Tag.offset + Tag.size > HeaderSize)
+ continue;
+
+ Icc -> TagNames[Icc ->TagCount] = Tag.sig;
+ Icc -> TagOffsets[Icc ->TagCount] = Tag.offset;
+ Icc -> TagSizes[Icc ->TagCount] = Tag.size;
+
+ // Search for links
+ for (j=0; j < Icc ->TagCount; j++) {
+
+ if ((Icc ->TagOffsets[j] == Tag.offset) &&
+ (Icc ->TagSizes[j] == Tag.size)) {
+
+ Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j];
+ }
+
+ }
+
+ Icc ->TagCount++;
+ }
+
+ return TRUE;
+}
+
+// Saves profile header
+cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
+{
+ cmsICCHeader Header;
+ cmsUInt32Number i;
+ cmsTagEntry Tag;
+ cmsInt32Number Count = 0;
+
+ Header.size = _cmsAdjustEndianess32(UsedSpace);
+ Header.cmmId = _cmsAdjustEndianess32(lcmsSignature);
+ Header.version = _cmsAdjustEndianess32(Icc ->Version);
+
+ Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass);
+ Header.colorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> ColorSpace);
+ Header.pcs = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> PCS);
+
+ // NOTE: in v4 Timestamp must be in UTC rather than in local time
+ _cmsEncodeDateTimeNumber(&Header.date, &Icc ->Created);
+
+ Header.magic = _cmsAdjustEndianess32(cmsMagicNumber);
+
+#ifdef CMS_IS_WINDOWS_
+ Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft);
+#else
+ Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh);
+#endif
+
+ Header.flags = _cmsAdjustEndianess32(Icc -> flags);
+ Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
+ Header.model = _cmsAdjustEndianess32(Icc -> model);
+
+ _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes);
+
+ // Rendering intent in the header (for embedded profiles)
+ Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
+
+ // Illuminant is always D50
+ Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
+ Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
+ Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
+
+ // Created by LittleCMS (that's me!)
+ Header.creator = _cmsAdjustEndianess32(lcmsSignature);
+
+ memset(&Header.reserved, 0, sizeof(Header.reserved));
+
+ // Set profile ID. Endianess is always big endian
+ memmove(&Header.profileID, &Icc ->ProfileID, 16);
+
+ // Dump the header
+ if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE;
+
+ // Saves Tag directory
+
+ // Get true count
+ for (i=0; i < Icc -> TagCount; i++) {
+ if (Icc ->TagNames[i] != 0)
+ Count++;
+ }
+
+ // Store number of tags
+ if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE;
+
+ for (i=0; i < Icc -> TagCount; i++) {
+
+ if (Icc ->TagNames[i] == 0) continue; // It is just a placeholder
+
+ Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]);
+ Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]);
+ Tag.size = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]);
+
+ if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE;
+ }
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------- Set/Get several struct members
+
+
+cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return Icc -> RenderingIntent;
+}
+
+void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> RenderingIntent = RenderingIntent;
+}
+
+cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return (cmsUInt32Number) Icc -> flags;
+}
+
+void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> flags = (cmsUInt32Number) Flags;
+}
+
+cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return (cmsUInt32Number) Icc ->manufacturer;
+}
+
+void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> manufacturer = (cmsUInt32Number) manufacturer;
+}
+
+cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return (cmsUInt32Number) Icc ->model;
+}
+
+void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> manufacturer = (cmsUInt32Number) model;
+}
+
+
+void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ memmove(Flags, &Icc -> attributes, sizeof(cmsUInt64Number));
+}
+
+void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ memmove(&Icc -> attributes, &Flags, sizeof(cmsUInt64Number));
+}
+
+void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ memmove(ProfileID, Icc ->ProfileID.ID8, 16);
+}
+
+void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ memmove(&Icc -> ProfileID, ProfileID, 16);
+}
+
+cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ memmove(Dest, &Icc ->Created, sizeof(struct tm));
+ return TRUE;
+}
+
+cmsColorSpaceSignature CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return Icc -> PCS;
+}
+
+void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> PCS = pcs;
+}
+
+cmsColorSpaceSignature CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return Icc -> ColorSpace;
+}
+
+void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> ColorSpace = sig;
+}
+
+cmsProfileClassSignature CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return Icc -> DeviceClass;
+}
+
+void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> DeviceClass = sig;
+}
+
+cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ return Icc -> Version;
+}
+
+void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ Icc -> Version = Version;
+}
+
+// Get an hexadecimal number with same digits as v
+static
+cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut)
+{
+ char Buff[100];
+ int i, len;
+ cmsUInt32Number out;
+
+ for (len=0; in > 0 && len < 100; len++) {
+
+ Buff[len] = (char) (in % BaseIn);
+ in /= BaseIn;
+ }
+
+ for (i=len-1, out=0; i >= 0; --i) {
+ out = out * BaseOut + Buff[i];
+ }
+
+ return out;
+}
+
+void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+
+ // 4.2 -> 0x4200000
+
+ Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16;
+}
+
+cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ cmsUInt32Number n = Icc -> Version >> 16;
+
+ return BaseToBase(n, 16, 10) / 100.0;
+}
+// --------------------------------------------------------------------------------------------------------------
+
+
+// Create profile from IOhandler
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io)
{
- if (fseek((FILE*) Icc ->stream, (long) offset, SEEK_SET) != 0) {
+ _cmsICCPROFILE* NewIcc;
+ cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
+
+ if (hEmpty == NULL) return NULL;
+
+ NewIcc = (_cmsICCPROFILE*) hEmpty;
+
+ NewIcc ->IOhandler = io;
+ if (!_cmsReadHeader(NewIcc)) goto Error;
+ return hEmpty;
+
+Error:
+ cmsCloseProfile(hEmpty);
+ return NULL;
+}
+
+// Create profile from disk file
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess)
+{
+ _cmsICCPROFILE* NewIcc;
+ cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
+
+ if (hEmpty == NULL) return NULL;
+
+ NewIcc = (_cmsICCPROFILE*) hEmpty;
+
+ NewIcc ->IOhandler = cmsOpenIOhandlerFromFile(ContextID, lpFileName, sAccess);
+ if (NewIcc ->IOhandler == NULL) goto Error;
+
+ if (*sAccess == 'W' || *sAccess == 'w') {
+
+ NewIcc -> IsWrite = TRUE;
+
+ return hEmpty;
+ }
+
+ if (!_cmsReadHeader(NewIcc)) goto Error;
+ return hEmpty;
+
+Error:
+ cmsCloseProfile(hEmpty);
+ return NULL;
+}
+
+
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess)
+{
+ return cmsOpenProfileFromFileTHR(NULL, ICCProfile, sAccess);
+}
+
+
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char *sAccess)
+{
+ _cmsICCPROFILE* NewIcc;
+ cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
+
+ if (hEmpty == NULL) return NULL;
+
+ NewIcc = (_cmsICCPROFILE*) hEmpty;
+
+ NewIcc ->IOhandler = cmsOpenIOhandlerFromStream(ContextID, ICCProfile);
+ if (NewIcc ->IOhandler == NULL) goto Error;
+
+ if (*sAccess == 'w') {
+
+ NewIcc -> IsWrite = TRUE;
+ return hEmpty;
+ }
+
+ if (!_cmsReadHeader(NewIcc)) goto Error;
+ return hEmpty;
+
+Error:
+ cmsCloseProfile(hEmpty);
+ return NULL;
+
+}
+
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char *sAccess)
+{
+ return cmsOpenProfileFromStreamTHR(NULL, ICCProfile, sAccess);
+}
+
+
+// Open from memory block
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* MemPtr, cmsUInt32Number dwSize)
+{
+ _cmsICCPROFILE* NewIcc;
+ cmsHPROFILE hEmpty;
+
+ hEmpty = cmsCreateProfilePlaceholder(ContextID);
+ if (hEmpty == NULL) return NULL;
+
+ NewIcc = (_cmsICCPROFILE*) hEmpty;
+
+ // Ok, in this case const void* is casted to void* just because open IO handler
+ // shares read and writting modes. Don't abuse this feature!
+ NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r");
+ if (NewIcc ->IOhandler == NULL) goto Error;
+
+ if (!_cmsReadHeader(NewIcc)) goto Error;
+
+ return hEmpty;
+
+Error:
+ cmsCloseProfile(hEmpty);
+ return NULL;
+}
+
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number dwSize)
+{
+ return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize);
+}
+
+
+
+// Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig
+static
+cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
+{
+ cmsUInt8Number* Data;
+ cmsUInt32Number i;
+ cmsUInt32Number Begin;
+ cmsIOHANDLER* io = Icc ->IOhandler;
+ cmsTagDescriptor* TagDescriptor;
+ cmsTagTypeSignature TypeBase;
+ cmsTagTypeHandler* TypeHandler;
+
+
+ for (i=0; i < Icc -> TagCount; i++) {
+
+
+ if (Icc ->TagNames[i] == 0) continue;
+
+ // Linked tags are not written
+ if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue;
+
+ Icc -> TagOffsets[i] = Begin = io ->UsedSpace;
+
+ Data = (cmsUInt8Number*) Icc -> TagPtrs[i];
+
+ if (!Data) {
+
+ // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user.
+ // In this case a blind copy of the block data is performed
+ if (FileOrig != NULL && Icc -> TagOffsets[i]) {
+
+ cmsUInt32Number TagSize = FileOrig -> TagSizes[i];
+ cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
+ void* Mem;
+
+ if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE;
+
+ Mem = _cmsMalloc(Icc ->ContextID, TagSize);
+ if (Mem == NULL) return FALSE;
+
+ if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE;
+ if (!io ->Write(io, TagSize, Mem)) return FALSE;
+ _cmsFree(Icc ->ContextID, Mem);
+
+ Icc -> TagSizes[i] = (io ->UsedSpace - Begin);
+
+
+ // Align to 32 bit boundary.
+ if (! _cmsWriteAlignment(io))
+ return FALSE;
+ }
+
+ continue;
+ }
+
+
+ // Should this tag be saved as RAW? If so, tagsizes should be specified in advance (no further cooking is done)
+ if (Icc ->TagSaveAsRaw[i]) {
+
+ if (io -> Write(io, Icc ->TagSizes[i], Data) != 1) return FALSE;
+ }
+ else {
+
+ // Search for support on this tag
+ TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]);
+ if (TagDescriptor == NULL) continue; // Unsupported, ignore it
+
+ TypeHandler = Icc ->TagTypeHandlers[i];
+
+ if (TypeHandler == NULL) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]);
+ continue;
+ }
+
+ TypeBase = TypeHandler ->Signature;
+ if (!_cmsWriteTypeBase(io, TypeBase))
+ return FALSE;
+
+ if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) {
+
+ char String[5];
- cmsSignalError(LCMS_ERRC_ABORTED, "Seek error; probably corrupted file");
- return TRUE;
+ _cmsTagSignature2String(String, (cmsTagSignature) TypeBase);
+ cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String);
+ return FALSE;
+ }
+ }
+
+
+ Icc -> TagSizes[i] = (io ->UsedSpace - Begin);
+
+ // Align to 32 bit boundary.
+ if (! _cmsWriteAlignment(io))
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+// Fill the offset and size fields for all linked tags
+static
+cmsBool SetLinks( _cmsICCPROFILE* Icc)
+{
+ cmsUInt32Number i;
+
+ for (i=0; i < Icc -> TagCount; i++) {
+
+ cmsTagSignature lnk = Icc ->TagLinked[i];
+ if (lnk != (cmsTagSignature) 0) {
+
+ int j = _cmsSearchTag(Icc, lnk, FALSE);
+ if (j >= 0) {
+
+ Icc ->TagOffsets[i] = Icc ->TagOffsets[j];
+ Icc ->TagSizes[i] = Icc ->TagSizes[j];
+ }
+
+ }
+ }
+
+ return TRUE;
+}
+
+// Low-level save to IOHANDLER. It returns the number of bytes used to
+// store the profile, or zero on error. io may be NULL and in this case
+// no data is written--only sizes are calculated
+cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ _cmsICCPROFILE Keep;
+ cmsIOHANDLER* PrevIO;
+ cmsUInt32Number UsedSpace;
+ cmsContext ContextID;
+
+ memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
+
+ ContextID = cmsGetProfileContextID(hProfile);
+ PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID);
+ if (PrevIO == NULL) return 0;
+
+ // Pass #1 does compute offsets
+
+ if (!_cmsWriteHeader(Icc, 0)) return 0;
+ if (!SaveTags(Icc, &Keep)) return 0;
+
+ UsedSpace = PrevIO ->UsedSpace;
+
+ // Pass #2 does save to iohandler
+
+ if (io != NULL) {
+ Icc ->IOhandler = io;
+ if (!SetLinks(Icc)) goto CleanUp;
+ if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp;
+ if (!SaveTags(Icc, &Keep)) goto CleanUp;
+ }
+
+ memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
+ if (!cmsCloseIOhandler(PrevIO)) return 0;
+
+ return UsedSpace;
+
+
+CleanUp:
+ cmsCloseIOhandler(PrevIO);
+ memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
+ return 0;
+}
+
+
+// Low-level save to disk.
+cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName)
+{
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+ cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w");
+ cmsBool rc;
+
+ if (io == NULL) return FALSE;
+
+ rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
+ rc &= cmsCloseIOhandler(io);
+
+ if (rc == FALSE) { // remove() is C99 per 7.19.4.1
+ remove(FileName); // We have to IGNORE return value in this case
+ }
+ return rc;
+}
+
+// Same as anterior, but for streams
+cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream)
+{
+ cmsBool rc;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+ cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream);
+
+ if (io == NULL) return FALSE;
+
+ rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
+ rc &= cmsCloseIOhandler(io);
+
+ return rc;
+}
+
+
+// Same as anterior, but for memory blocks. In this case, a NULL as MemPtr means calculate needed space only
+cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded)
+{
+ cmsBool rc;
+ cmsIOHANDLER* io;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+
+ // Should we just calculate the needed space?
+ if (MemPtr == NULL) {
+
+ *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL);
+ return TRUE;
+ }
+
+ // That is a real write operation
+ io = cmsOpenIOhandlerFromMem(ContextID, MemPtr, *BytesNeeded, "w");
+ if (io == NULL) return FALSE;
+
+ rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
+ rc &= cmsCloseIOhandler(io);
+
+ return rc;
+}
+
+
+
+// Closes a profile freeing any involved resources
+cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
+{
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ cmsBool rc = TRUE;
+ cmsUInt32Number i;
+
+ if (!Icc) return FALSE;
+
+ // Was open in write mode?
+ if (Icc ->IsWrite) {
+
+ Icc ->IsWrite = FALSE; // Assure no further writting
+ rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile);
+ }
+
+ for (i=0; i < Icc -> TagCount; i++) {
+
+ if (Icc -> TagPtrs[i]) {
+
+ cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
+
+ if (TypeHandler != NULL)
+ TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
+ else
+ _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
+ }
+ }
+
+ if (Icc ->IOhandler != NULL) {
+ rc &= cmsCloseIOhandler(Icc->IOhandler);
+ }
+
+ _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory
+
+ return rc;
+}
+
+
+// -------------------------------------------------------------------------------------------------------------------
+
+
+// Returns TRUE if a given tag is supported by a plug-in
+static
+cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Type)
+{
+ cmsUInt32Number i, nMaxTypes;
+
+ nMaxTypes = TagDescriptor->nSupportedTypes;
+ if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN)
+ nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN;
+
+ for (i=0; i < nMaxTypes; i++) {
+ if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE;
}
return FALSE;
}
-static
-size_t FileTell(struct _lcms_iccprofile_struct* Icc)
-{
- return ftell((FILE*) Icc ->stream);
-}
-
-// Writes data to stream, also keeps used space for further reference
-
-
-static
-LCMSBOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr)
+// That's the main read function
+void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
{
- if (size == 0) return TRUE;
-
- Icc->UsedSpace += size;
-
- if (Icc->stream == NULL) {
-
- return TRUE;
- }
-
- return (fwrite(Ptr, size, 1, (FILE*) Icc->stream) == 1);
-}
-
-
-static
-LCMSBOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size)
-{
- return TRUE;
-}
-
-
-static
-LCMSBOOL FileClose(struct _lcms_iccprofile_struct* Icc)
-{
- return fclose((FILE*) Icc ->stream);
-}
-
-// ----------------------------------------------------------------------------------------------------
-
-
-// Creates an empty structure holding all required parameters
-
-cmsHPROFILE _cmsCreateProfilePlaceholder(void)
-{
-
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) _cmsMalloc(sizeof(LCMSICCPROFILE));
- if (Icc == NULL) return NULL;
-
- // Empty values
- ZeroMemory(Icc, sizeof(LCMSICCPROFILE));
-
- // Make sure illuminant is correct
- Icc ->Illuminant = *cmsD50_XYZ();
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ cmsIOHANDLER* io = Icc ->IOhandler;
+ cmsTagTypeHandler* TypeHandler;
+ cmsTagDescriptor* TagDescriptor;
+ cmsTagTypeSignature BaseType;
+ cmsUInt32Number Offset, TagSize;
+ cmsUInt32Number ElemCount;
+ int n;
- // Set it to empty
- Icc -> TagCount = 0;
-
- // Return the handle
- return (cmsHPROFILE) Icc;
-}
-
-
-// Return the number of tags
-icInt32Number LCMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return Icc->TagCount;
-}
-
-// Return the tag signature of a given tag number
-icTagSignature LCMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, icInt32Number n)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
-
- if (n < 0 || n > Icc->TagCount) return (icTagSignature) 0; // Mark as not available
-
- return Icc ->TagNames[n];
-}
-
-
-// Search for a specific tag in tag dictionary
-// Returns position or -1 if tag not found
-
-icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError)
-{
- icInt32Number i;
-
- if (sig == 0) return -1; // 0 identifies a special tag holding raw memory.
-
- for (i=0; i < Profile -> TagCount; i++) {
-
- if (sig == Profile -> TagNames[i])
- return i;
- }
-
- if (lSignalError)
- cmsSignalError(LCMS_ERRC_ABORTED, "Tag '%lx' not found", sig);
-
- return -1;
-}
-
-
-// Check existance
-
-LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- return _cmsSearchTag(Icc, sig, FALSE) >= 0;
-}
+ n = _cmsSearchTag(Icc, sig, TRUE);
+ if (n < 0) return NULL; // Not found, return NULL
-// Search for a particular tag, replace if found or add new one else
+ // If the element is already in memory, return the pointer
+ if (Icc -> TagPtrs[n]) {
+
+ if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked
+ return Icc -> TagPtrs[n];
+ }
+
+ // We need to read it. Get the offset and size to the file
+ Offset = Icc -> TagOffsets[n];
+ TagSize = Icc -> TagSizes[n];
-LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const void* Init)
-{
- LPVOID Ptr;
- icInt32Number i;
+ // Seek to its location
+ if (!io -> Seek(io, Offset))
+ return NULL;
+
+ // Search for support on this tag
+ TagDescriptor = _cmsGetTagDescriptor(sig);
+ if (TagDescriptor == NULL) return NULL; // Unsupported.
- i = _cmsSearchTag(Icc, sig, FALSE);
+ // if supported, get type and check if in list
+ BaseType = _cmsReadTypeBase(io);
+ if (BaseType == 0) return NULL;
- if (i >=0) {
+ if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL;
+
+ TagSize -= 8; // Alredy read by the type base logic
- if (Icc -> TagPtrs[i]) _cmsFree(Icc -> TagPtrs[i]);
- }
- else {
+ // Get type handler
+ TypeHandler = _cmsGetTagTypeHandler(BaseType);
+ if (TypeHandler == NULL) return NULL;
+
- i = Icc -> TagCount;
- Icc -> TagCount++;
+ // Read the tag
+ Icc -> TagTypeHandlers[n] = TypeHandler;
+ Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize);
+
+ // The tag type is supported, but something wrong happend and we cannot read the tag.
+ // let know the user about this (although it is just a warning)
+ if (Icc -> TagPtrs[n] == NULL) {
+
+ char String[5];
- if (Icc ->TagCount >= MAX_TABLE_TAG) {
+ _cmsTagSignature2String(String, sig);
+ cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
+ return NULL;
+ }
- cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", MAX_TABLE_TAG);
- Icc ->TagCount = MAX_TABLE_TAG-1;
- return NULL;
- }
+ // This is a weird error that may be a symptom of something more serious, the number of
+ // stored item is actually less than the number of required elements.
+ if (ElemCount < TagDescriptor ->ElemCount) {
+
+ char String[5];
+
+ _cmsTagSignature2String(String, sig);
+ cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d",
+ String, TagDescriptor ->ElemCount, ElemCount);
}
- Ptr = _cmsMalloc(size);
- if (Ptr == NULL) return NULL;
-
- CopyMemory(Ptr, Init, size);
-
- Icc ->TagNames[i] = sig;
- Icc ->TagSizes[i] = size;
- Icc ->TagPtrs[i] = Ptr;
-
- return Ptr;
+ // Return the data
+ return Icc -> TagPtrs[n];
}
-
-
-
-// Creates a profile from file read placeholder
-
-LPLCMSICCPROFILE _cmsCreateProfileFromFilePlaceholder(const char* FileName)
+// Get true type of data
+cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig)
{
- LPLCMSICCPROFILE NewIcc;
- LPVOID ICCfile = FileOpen(FileName);
-
- if (ICCfile == NULL) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "File '%s' not found", FileName);
- return NULL;
- }
-
- NewIcc = (LPLCMSICCPROFILE) _cmsCreateProfilePlaceholder();
- if (NewIcc == NULL) return NULL;
-
- strncpy(NewIcc -> PhysicalFile, FileName, MAX_PATH-1);
- NewIcc -> PhysicalFile[MAX_PATH-1] = 0;
-
- NewIcc ->stream = ICCfile;
-
- NewIcc ->Read = FileRead;
- NewIcc ->Seek = FileSeek;
- NewIcc ->Tell = FileTell;
- NewIcc ->Close = FileClose;
- NewIcc ->Grow = FileGrow;
- NewIcc ->Write = NULL;
-
- NewIcc ->IsWrite = FALSE;
-
-
-
-
- return NewIcc;
-}
-
-
-// Creates a profile from memory read placeholder
-
-LPLCMSICCPROFILE _cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr, DWORD dwSize)
-{
-
- LPLCMSICCPROFILE NewIcc;
- LPVOID ICCfile = MemoryOpen((LPBYTE) MemPtr, (size_t) dwSize, 'r');
-
-
- if (ICCfile == NULL) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't allocate %ld bytes for profile", dwSize);
- return NULL;
- }
-
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ cmsTagTypeHandler* TypeHandler;
+ int n;
- NewIcc = (LPLCMSICCPROFILE) _cmsCreateProfilePlaceholder();
- if (NewIcc == NULL) return NULL;
-
- NewIcc -> PhysicalFile[0] = 0;
- NewIcc ->stream = ICCfile;
-
- NewIcc ->Read = MemoryRead;
- NewIcc ->Seek = MemorySeek;
- NewIcc ->Tell = MemoryTell;
- NewIcc ->Close = MemoryClose;
- NewIcc ->Grow = MemoryGrow;
- NewIcc ->Write = MemoryWrite;
-
- NewIcc ->IsWrite = FALSE;
-
-
- return NewIcc;
-}
-
-
-// Turn a placeholder into file writter
-
-void _cmsSetSaveToDisk(LPLCMSICCPROFILE Icc, const char* FileName)
-{
-
- if (FileName == NULL) {
+ // Search for given tag in ICC profile directory
+ n = _cmsSearchTag(Icc, sig, TRUE);
+ if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL
- Icc ->stream = NULL;
- }
- else {
-
- Icc ->stream = fopen(FileName, "wb");
- if (Icc ->stream == NULL)
- cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't write to file '%s'", FileName);
- }
-
- Icc ->Write = FileWrite; // Save to disk
- Icc ->Close = FileClose;
-}
-
-
-
-// Turn a placeholder into memory writter
-
-void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize)
-{
-
- if (MemPtr == NULL) {
-
- Icc ->stream = NULL;
- }
- else {
-
- Icc ->stream = (FILEMEM*) MemoryOpen((LPBYTE) MemPtr, dwSize, 'w');
- if (Icc ->stream == NULL)
- cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't write to memory");
- }
-
- Icc ->Write = MemoryWrite;
- Icc ->Close = MemoryClose;
+ // Get the handler. The true type is there
+ TypeHandler = Icc -> TagTypeHandlers[n];
+ return TypeHandler ->Signature;
}
-// ----------------------------------------------------------------------- Set/Get several struct members
-
-
-
-
-LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- *Dest = Icc -> MediaWhitePoint;
- return TRUE;
-}
-
-
-LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile)
+// Write a single tag. This just keeps track of the tak into a list of "to be written". If the tag is already
+// in that list, the previous version is deleted.
+cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data)
{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- *Dest = Icc -> MediaBlackPoint;
- return TRUE;
-}
-
-LCMSBOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- *Dest = Icc -> Illuminant;
- return TRUE;
-}
-
-int LCMSEXPORT cmsTakeRenderingIntent(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return (int) Icc -> RenderingIntent;
-}
-
-void LCMSEXPORT cmsSetRenderingIntent(cmsHPROFILE hProfile, int RenderingIntent)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> RenderingIntent = (icRenderingIntent) RenderingIntent;
-}
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ cmsTagTypeHandler* TypeHandler = NULL;
+ cmsTagDescriptor* TagDescriptor = NULL;
+ cmsTagTypeSignature Type;
+ int i;
+ cmsFloat64Number Version;
-DWORD LCMSEXPORT cmsTakeHeaderFlags(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return (DWORD) Icc -> flags;
-}
+ if (data == NULL) {
-void LCMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, DWORD Flags)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> flags = (icUInt32Number) Flags;
-}
+ cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag");
+ return FALSE;
+ }
+
+ i = _cmsSearchTag(Icc, sig, FALSE);
+ if (i >=0) {
+
+ if (Icc -> TagPtrs[i] != NULL) {
-DWORD LCMSEXPORT cmsTakeHeaderAttributes(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return (DWORD) Icc -> attributes;
-}
+ // Already exists. Free previous version
+ if (Icc ->TagSaveAsRaw[i]) {
+ _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
+ }
+ else {
+ TypeHandler = Icc ->TagTypeHandlers[i];
+ TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
+ }
+ }
+ }
+ else {
+ // New one
+ i = Icc -> TagCount;
-void LCMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, DWORD Flags)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> attributes = (icUInt32Number) Flags;
-}
+ if (i >= MAX_TABLE_TAG) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
+ return FALSE;
+ }
+
+ Icc -> TagCount++;
+ }
+
+ // This is not raw
+ Icc ->TagSaveAsRaw[i] = FALSE;
+
+ // This is not a link
+ Icc ->TagLinked[i] = (cmsTagSignature) 0;
+
+ // Get information about the TAG.
+ TagDescriptor = _cmsGetTagDescriptor(sig);
+ if (TagDescriptor == NULL){
+ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig);
+ return FALSE;
+ }
-const BYTE* LCMSEXPORT cmsTakeProfileID(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return Icc ->ProfileID;
-}
+ // Now we need to know which type to use. It depends on the version.
+ Version = cmsGetProfileVersion(hProfile);
+ if (TagDescriptor ->DecideType != NULL) {
+
+ // Let the tag descriptor to decide the type base on depending on
+ // the data. This is useful for example on parametric curves, where
+ // curves specified by a table cannot be saved as parametric and needs
+ // to be revented to single v2-curves, even on v4 profiles.
+
+ Type = TagDescriptor ->DecideType(Version, data);
+ }
+ else {
+
+ Type = TagDescriptor ->SupportedTypes[0];
+ }
+
+ // Does the tag support this type?
+ if (!IsTypeSupported(TagDescriptor, Type)) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig);
+ return FALSE;
+ }
-void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- CopyMemory(Icc -> ProfileID, ProfileID, 16);
-}
+ // Does we have a handler for this type?
+ TypeHandler = _cmsGetTagTypeHandler(Type);
+ if (TypeHandler == NULL) {
+ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig);
+ return FALSE; // Should never happen
+ }
+ // Fill fields on icc structure
+ Icc ->TagTypeHandlers[i] = TypeHandler;
+ Icc ->TagNames[i] = sig;
+ Icc ->TagSizes[i] = 0;
+ Icc ->TagOffsets[i] = 0;
+ Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
-LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- CopyMemory(Dest, &Icc ->Created, sizeof(struct tm));
+ if (Icc ->TagPtrs[i] == NULL) {
+
+ TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
+ cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%x' for tag '%x'", Type, sig);
+
+ return FALSE;
+ }
+
return TRUE;
}
-
-icColorSpaceSignature LCMSEXPORT cmsGetPCS(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return Icc -> PCS;
-}
-
-
-void LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> PCS = pcs;
-}
+// Read and write raw data. The only way those function would work and keep consistence with normal read and write
+// is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained
+// data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where
+// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows
+// to write a tag as raw data and the read it as handled.
-icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return Icc -> ColorSpace;
-}
-
-void LCMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, icColorSpaceSignature sig)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> ColorSpace = sig;
-}
-
-icProfileClassSignature LCMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile)
+cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize)
{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return Icc -> DeviceClass;
-}
-
-DWORD LCMSEXPORT cmsGetProfileICCversion(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- return (DWORD) Icc -> Version;
-}
-
-void LCMSEXPORT cmsSetProfileICCversion(cmsHPROFILE hProfile, DWORD Version)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> Version = Version;
-}
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ void *Object;
+ int i;
+ cmsIOHANDLER* MemIO;
+ cmsTagTypeHandler* TypeHandler = NULL;
+ cmsTagDescriptor* TagDescriptor = NULL;
+ cmsUInt32Number rc;
+ cmsUInt32Number Offset, TagSize;
-
-void LCMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, icProfileClassSignature sig)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
- Icc -> DeviceClass = sig;
-}
-
+ // Search for given tag in ICC profile directory
+ i = _cmsSearchTag(Icc, sig, TRUE);
+ if (i < 0) return 0; // Not found, return 0
-// --------------------------------------------------------------------------------------------------------------
-
+ // It is already read?
+ if (Icc -> TagPtrs[i] == NULL) {
-static
-int SizeOfGammaTab(LPGAMMATABLE In)
-{
- return sizeof(GAMMATABLE) + (In -> nEntries - 1)*sizeof(WORD);
-}
+ // No yet, get original position
+ Offset = Icc ->TagOffsets[i];
+ TagSize = Icc ->TagSizes[i];
-// Creates a phantom tag holding a memory block
+ // read the data directly, don't keep copy
+ if (data != NULL) {
+
+ if (BufferSize < TagSize)
+ TagSize = BufferSize;
+
+ if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0;
+ if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0;
+ }
+
+ return Icc ->TagSizes[i];
+ }
+
+ // The data has been already read, or written. But wait!, maybe the user choosed to save as
+ // raw data. In this case, return the raw data directly
+ if (Icc ->TagSaveAsRaw[i]) {
+
+ if (data != NULL) {
+
+ TagSize = Icc ->TagSizes[i];
+ if (BufferSize < TagSize)
+ TagSize = BufferSize;
+
+ memmove(data, Icc ->TagPtrs[i], TagSize);
+ }
-static
-LPVOID DupBlock(LPLCMSICCPROFILE Icc, LPVOID Block, size_t size)
-{
- if (Block != NULL && size > 0)
- return _cmsInitTag(Icc, (icTagSignature) 0, size, Block);
- else
- return NULL;
+ return Icc ->TagSizes[i];
+ }
+
+ // Already readed, or previously set by cmsWriteTag(). We need to serialize that
+ // data to raw in order to maintain consistency.
+ Object = cmsReadTag(hProfile, sig);
+ if (Object == NULL) return 0;
+
+ // Now we need to serialize to a memory block: just use a memory iohandler
+ if (data == NULL) {
+ MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile));
+ } else{
+ MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
+ }
+ if (MemIO == NULL) return 0;
+
+ // Obtain type handling for the tag
+ TypeHandler = Icc ->TagTypeHandlers[i];
+ TagDescriptor = _cmsGetTagDescriptor(sig);
+
+ // Serialize
+ if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0;
+
+ // Get Size and close
+ rc = MemIO ->Tell(MemIO);
+ cmsCloseIOhandler(MemIO); // Ignore return code this time
+
+ return rc;
}
-// This is tricky, since LUT structs does have pointers
-
-LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut)
+// Similar to the anterior. This function allows to write directly to the ICC profile any data, without
+// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading
+// it as cooked without serializing does result into an error. If that is wha you want, you will need to dump
+// the profile to memry or disk and then reopen it.
+cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size)
{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- LPLUT Orig, Stored;
- unsigned int i;
-
- // The struct itself
-
- Orig = (LPLUT) lut;
- Stored = (LPLUT) _cmsInitTag(Icc, (icTagSignature) sig, sizeof(LUT), lut);
-
- // dup' the memory blocks
- for (i=0; i < Orig ->InputChan; i++)
- Stored -> L1[i] = (LPWORD) DupBlock(Icc, (LPWORD) Orig ->L1[i],
- sizeof(WORD) * Orig ->In16params.nSamples);
-
- for (i=0; i < Orig ->OutputChan; i++)
- Stored -> L2[i] = (LPWORD) DupBlock(Icc, (LPWORD) Orig ->L2[i],
- sizeof(WORD) * Orig ->Out16params.nSamples);
-
- Stored -> T = (LPWORD) DupBlock(Icc, (LPWORD) Orig ->T, Orig -> Tsize);
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ int i;
- // Zero any additional pointer
- Stored ->CLut16params.p8 = NULL;
- return TRUE;
-}
-
-
-LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- _cmsInitTag(Icc, sig, sizeof(cmsCIEXYZ), XYZ);
- return TRUE;
-}
+ if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
-
-LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
+ // Mark the tag as being written as RAW
+ Icc ->TagSaveAsRaw[i] = TRUE;
+ Icc ->TagNames[i] = sig;
+ Icc ->TagLinked[i] = (cmsTagSignature) 0;
- _cmsInitTag(Icc, sig, strlen(Text)+1, (LPVOID) Text);
- return TRUE;
-}
+ // Keep a copy of the block
+ Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size);
+ Icc ->TagSizes[i] = Size;
-LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- _cmsInitTag(Icc, sig, SizeOfGammaTab(TransferFunction), TransferFunction);
return TRUE;
}
-
-LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- _cmsInitTag(Icc, sig, sizeof(cmsCIExyYTRIPLE), Chrm);
- return TRUE;
-}
-
-
-LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ pseq)
+// Using this function you can collapse several tag entries to the same block in the profile
+cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest)
{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ int i;
- _cmsInitTag(Icc, sig, sizeof(int) + pseq -> n * sizeof(cmsPSEQDESC), pseq);
- return TRUE;
-
-}
+ if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
+ // Keep necessary information
+ Icc ->TagSaveAsRaw[i] = FALSE;
+ Icc ->TagNames[i] = sig;
+ Icc ->TagLinked[i] = dest;
-LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
+ Icc ->TagPtrs[i] = NULL;
+ Icc ->TagSizes[i] = 0;
+ Icc ->TagOffsets[i] = 0;
- _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc);
return TRUE;
}
-
-
-LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- _cmsInitTag(Icc, sig, sizeof(struct tm), DateTime);
- return TRUE;
-}
-
-
-LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc);
- return TRUE;
-}
-
-
-LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- _cmsInitTag(Icc, sig, 3*sizeof(cmsCIEXYZ), mat);
- return TRUE;
-
-}
-
-
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,1860 +49,108 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// ICC profile serialization
-
-
-#include "lcms.h"
-
-// ----------------------------------------------------------------- Tag Serialization
-
-// Alignment of ICC file format uses 4 bytes DWORD
-
-#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary
-
-
-static int GlobalLanguageCode; // Language & country descriptors, for ICC 4.0 support
-static int GlobalCountryCode;
-
-
-#ifdef __BEOS__
-# define USE_CUSTOM_SWAB 1
-#endif
-
-
-#ifdef USE_CUSTOM_SWAB
-
-// Replacement to swab function, thanks to YNOP
-// for providing the BeOS port
//
-// from: @(#)swab.c 5.10 (Berkeley) 3/6/91
-
-static
-void xswab(const void *from, void *to, size_t len)
-{
- register unsigned long temp;
- register int n;
- register char *fp, *tp;
-
- n = (len >> 1) + 1;
- fp = (char *)from;
- tp = (char *)to;
-#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp
- /* round to multiple of 8 */
- while ((--n) & 07)
- STEP;
- n >>= 3;
- while (--n >= 0) {
-
- STEP; STEP; STEP; STEP;
- STEP; STEP; STEP; STEP;
- }
-#undef STEP
-}
-#else
-#define xswab swab
-#endif
-
-
-//
-// Little-Endian to Big-Endian
+//---------------------------------------------------------------------------------
//
-#ifdef USE_BIG_ENDIAN
-#define AdjustEndianess16(a)
-#define AdjustEndianess32(a)
-#define AdjustEndianessArray16(a, b)
-#else
-
-static
-void AdjustEndianess16(LPBYTE pByte)
-{
- BYTE tmp;
-
- tmp = pByte[0];
- pByte[0] = pByte[1];
- pByte[1] = tmp;
-}
-
-static
-void AdjustEndianess32(LPBYTE pByte)
-{
- BYTE temp1;
- BYTE temp2;
-
- temp1 = *pByte++;
- temp2 = *pByte++;
- *(pByte-1) = *pByte;
- *pByte++ = temp2;
- *(pByte-3) = *pByte;
- *pByte = temp1;
-}
-
-
-// swap bytes in a array of words
-
-static
-void AdjustEndianessArray16(LPWORD p, size_t num_words)
-{
- xswab((char*) p, (char*)p, (int) num_words * sizeof(WORD));
-}
-
-#endif
-
-
-// Transports to properly encoded values - note that icc profiles does use
-// big endian notation.
-
-static
-icInt32Number TransportValue32(icInt32Number Value)
-{
- icInt32Number Temp = Value;
+#include "lcms2_internal.h"
- AdjustEndianess32((LPBYTE) &Temp);
- return Temp;
-}
-
-static
-WORD TransportValue16(WORD Value)
-{
- WORD Temp = Value;
-
- AdjustEndianess16((LPBYTE) &Temp);
- return Temp;
-}
-
-
-// from Fixed point 8.8 to double
-
-static
-double Convert8Fixed8(WORD fixed8)
-{
- BYTE msb, lsb;
-
- lsb = (BYTE) (fixed8 & 0xff);
- msb = (BYTE) (((WORD) fixed8 >> 8) & 0xff);
-
- return (double) ((double) msb + ((double) lsb / 256.0));
-}
-
-
-// from Fixed point 15.16 to double
-static
-double Convert15Fixed16(icS15Fixed16Number fix32)
-{
- double floater, sign, mid, hack;
- int Whole, FracPart;
-
-
- AdjustEndianess32((LPBYTE) &fix32);
-
- sign = (fix32 < 0 ? -1 : 1);
- fix32 = abs(fix32);
-
- Whole = LOWORD(fix32 >> 16);
- FracPart = LOWORD(fix32 & 0x0000ffffL);
-
- hack = 65536.0;
- mid = (double) FracPart / hack;
- floater = (double) Whole + mid;
-
- return sign * floater;
-}
-
-
-// Auxiliar-- read base and return type
+// Read tags using low-level functions, provides necessary glue code to adapt versions, etc.
-static
-icTagTypeSignature ReadBase(LPLCMSICCPROFILE Icc)
-{
- icTagBase Base;
-
- if (Icc -> Read(&Base, sizeof(icTagBase), 1, Icc) != 1)
- return (icTagTypeSignature) 0;
- AdjustEndianess32((LPBYTE) &Base.sig);
-
- return Base.sig;
-}
-
-
-static
-void DecodeDateTimeNumber(const icDateTimeNumber *Source, struct tm *Dest)
-{
- Dest->tm_sec = TransportValue16(Source->seconds);
- Dest->tm_min = TransportValue16(Source->minutes);
- Dest->tm_hour = TransportValue16(Source->hours);
- Dest->tm_mday = TransportValue16(Source->day);
- Dest->tm_mon = TransportValue16(Source->month) - 1;
- Dest->tm_year = TransportValue16(Source->year) - 1900;
- Dest->tm_wday = -1;
- Dest->tm_yday = -1;
- Dest->tm_isdst = 0;
-}
-
-static
-void EncodeDateTimeNumber(icDateTimeNumber *Dest, const struct tm *Source)
-{
- Dest->seconds = TransportValue16((WORD) Source->tm_sec);
- Dest->minutes = TransportValue16((WORD) Source->tm_min);
- Dest->hours = TransportValue16((WORD) Source->tm_hour);
- Dest->day = TransportValue16((WORD) Source->tm_mday);
- Dest->month = TransportValue16((WORD) (Source->tm_mon + 1));
- Dest->year = TransportValue16((WORD) (Source->tm_year + 1900));
-}
-
-
-// Jun-21-2000: Some profiles (those that comes with W2K) comes
-// with the media white (media black?) x 100. Add a sanity check
-
-static
-void NormalizeXYZ(LPcmsCIEXYZ Dest)
-{
- while (Dest -> X > 2. &&
- Dest -> Y > 2. &&
- Dest -> Z > 2.) {
-
- Dest -> X /= 10.;
- Dest -> Y /= 10.;
- Dest -> Z /= 10.;
- }
-}
-
-// Evaluates a XYZ tristimulous across chromatic adaptation matrix
-
-static
-void EvalCHRM(LPcmsCIEXYZ Dest, LPMAT3 Chrm, LPcmsCIEXYZ Src)
-{
- VEC3 d, s;
-
- s.n[VX] = Src -> X;
- s.n[VY] = Src -> Y;
- s.n[VZ] = Src -> Z;
-
- MAT3eval(&d, Chrm, &s);
-
- Dest ->X = d.n[VX];
- Dest ->Y = d.n[VY];
- Dest ->Z = d.n[VZ];
-
-}
-
-
-// Read profile header and validate it
-
-static
-LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, LCMSBOOL lIsFromMemory)
-{
- icTag Tag;
- icHeader Header;
- icInt32Number TagCount, i;
- icUInt32Number extent;
-
- if (Icc -> Read(&Header, sizeof(icHeader), 1, Icc) != 1)
- goto ErrorCleanup;
-
- // Convert endian
-
- AdjustEndianess32((LPBYTE) &Header.size);
- AdjustEndianess32((LPBYTE) &Header.cmmId);
- AdjustEndianess32((LPBYTE) &Header.version);
- AdjustEndianess32((LPBYTE) &Header.deviceClass);
- AdjustEndianess32((LPBYTE) &Header.colorSpace);
- AdjustEndianess32((LPBYTE) &Header.pcs);
- AdjustEndianess32((LPBYTE) &Header.magic);
- AdjustEndianess32((LPBYTE) &Header.flags);
- AdjustEndianess32((LPBYTE) &Header.attributes[0]);
- AdjustEndianess32((LPBYTE) &Header.renderingIntent);
-
- // Validate it
-
- if (Header.magic != icMagicNumber) goto ErrorCleanup;
-
- if (Icc ->Read(&TagCount, sizeof(icInt32Number), 1, Icc) != 1)
- goto ErrorCleanup;
-
- AdjustEndianess32((LPBYTE) &TagCount);
+// LUT tags
+static const cmsTagSignature Device2PCS16[] = {cmsSigAToB0Tag, // Perceptual
+ cmsSigAToB1Tag, // Relative colorimetric
+ cmsSigAToB2Tag, // Saturation
+ cmsSigAToB1Tag }; // Absolute colorimetric
- Icc -> DeviceClass = Header.deviceClass;
- Icc -> ColorSpace = Header.colorSpace;
- Icc -> PCS = Header.pcs;
- Icc -> RenderingIntent = (icRenderingIntent) Header.renderingIntent;
- Icc -> flags = Header.flags;
- Icc -> attributes = Header.attributes[0];
- Icc -> Illuminant.X = Convert15Fixed16(Header.illuminant.X);
- Icc -> Illuminant.Y = Convert15Fixed16(Header.illuminant.Y);
- Icc -> Illuminant.Z = Convert15Fixed16(Header.illuminant.Z);
- Icc -> Version = Header.version;
-
- // Get creation date/time
-
- DecodeDateTimeNumber(&Header.date, &Icc ->Created);
-
- // Fix illuminant, some profiles are broken in this field!
-
- Icc ->Illuminant = *cmsD50_XYZ();
-
- // The profile ID are 16 raw bytes
-
- CopyMemory(Icc ->ProfileID, Header.reserved, 16);
-
- // Get rid of possible wrong profiles
-
- NormalizeXYZ(&Icc -> Illuminant);
-
- // Read tag directory
-
- if (TagCount > MAX_TABLE_TAG || TagCount < 0) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", TagCount);
- goto ErrorCleanup;
- }
-
- Icc -> TagCount = TagCount;
- for (i=0; i < TagCount; i++) {
-
- if (Icc ->Read(&Tag, sizeof(icTag), 1, Icc) != 1)
- goto ErrorCleanup;
-
- AdjustEndianess32((LPBYTE) &Tag.offset);
- AdjustEndianess32((LPBYTE) &Tag.size);
- AdjustEndianess32((LPBYTE) &Tag.sig); // Signature
-
- // Perform some sanity check. Offset + size should fall inside file.
- extent = Tag.offset + Tag.size;
- if (extent > Header.size || extent < Tag.offset)
- goto ErrorCleanup;
-
- Icc -> TagNames[i] = Tag.sig;
- Icc -> TagOffsets[i] = Tag.offset;
- Icc -> TagSizes[i] = Tag.size;
- }
-
- return Icc;
-
-
-ErrorCleanup:
-
- Icc ->Close(Icc);
-
- if (lIsFromMemory)
- cmsSignalError(LCMS_ERRC_ABORTED, "Corrupted memory profile");
- else
- cmsSignalError(LCMS_ERRC_ABORTED, "Corrupted profile: '%s'", Icc->PhysicalFile);
-
-
- _cmsFree(Icc);
- return NULL;
-}
-
-static
-unsigned int uipow(unsigned int a, unsigned int b) {
- unsigned int rv = 1;
- for (; b > 0; b--)
- rv *= a;
- return rv;
-}
-
-
-
-// Convert between notations.
-
-#define TO16_TAB(x) (WORD) (((x) << 8) | (x))
-
-
-// LUT8 can come only in Lab space. There is a fatal flaw in
-// converting from Lut8 to Lut16. Due to particular encoding
-// of Lab, different actions should be taken from input and
-// output Lab8 LUTS. For input, is as easy as applying a << 8,
-// since numbers comes in fixed point. However, for output LUT
-// things goes a bit more complex.... LUT 16 is supposed to
-// have a domain of 0..ff00, so we should remap the LUT in order
-// to get things working. Affected signatures are B2Axx tags,
-// preview and gamut.
-
-// I do solve it by multiplying input matrix by:
-//
-// | 0xffff/0xff00 0 0 |
-// | 0 0xffff/0xff00 0 |
-// | 0 0 0xffff/0xff00 |
-//
-// The input values got then remapped to adequate domain
-
-static
-void FixLUT8(LPLUT Lut, icTagSignature sig, size_t nTabSize)
-{
- MAT3 Fixup, Original, Result;
- LPWORD PtrW;
- size_t i;
-
- switch (sig) {
-
+static const cmsTagSignature Device2PCSFloat[] = {cmsSigDToB0Tag, // Perceptual
+ cmsSigDToB1Tag, // Relative colorimetric
+ cmsSigDToB2Tag, // Saturation
+ cmsSigDToB3Tag }; // Absolute colorimetric
- case icSigBToA0Tag:
- case icSigBToA1Tag:
- case icSigBToA2Tag:
- case icSigGamutTag:
- case icSigPreview0Tag:
- case icSigPreview1Tag:
- case icSigPreview2Tag:
-
-
- VEC3init(&Fixup.v[0], (double) 0xFFFF/0xFF00, 0, 0);
- VEC3init(&Fixup.v[1], 0, (double) 0xFFFF/0xFF00, 0);
- VEC3init(&Fixup.v[2], 0, 0, (double) 0xFFFF/0xFF00);
-
-
- MAT3fromFix(&Original, &Lut->Matrix);
- MAT3per(&Result, &Original, &Fixup);
- MAT3toFix(&Lut->Matrix, &Result);
-
- Lut -> wFlags |= LUT_HASMATRIX;
- break;
-
- // For input, clear low part since this has to be
- // Lab in fixed point
-
- default:
-
- PtrW = Lut -> T;
- for (i = 0; i < nTabSize; i++) {
-
- *PtrW++ &= 0xFF00;
- }
- }
-
-}
-
-// On Lab -> Lab abstract or Lab identities, fix both sides of LUT
-
-static
-void FixLUT8bothSides(LPLUT Lut, size_t nTabSize)
-{
- MAT3 Fixup, Original, Result;
- LPWORD PtrW;
- size_t i;
-
- VEC3init(&Fixup.v[0], (double) 0xFFFF/0xFF00, 0, 0);
- VEC3init(&Fixup.v[1], 0, (double) 0xFFFF/0xFF00, 0);
- VEC3init(&Fixup.v[2], 0, 0, (double) 0xFFFF/0xFF00);
-
- MAT3fromFix(&Original, &Lut->Matrix);
- MAT3per(&Result, &Original, &Fixup);
- MAT3toFix(&Lut->Matrix, &Result);
-
- Lut -> wFlags |= LUT_HASMATRIX;
-
- PtrW = Lut -> T;
- for (i = 0; i < nTabSize; i++) {
-
- *PtrW++ &= 0xFF00;
- }
+static const cmsTagSignature PCS2Device16[] = {cmsSigBToA0Tag, // Perceptual
+ cmsSigBToA1Tag, // Relative colorimetric
+ cmsSigBToA2Tag, // Saturation
+ cmsSigBToA1Tag }; // Absolute colorimetric
-}
-
-
-// The infamous LUT 8
-
-static
-LCMSBOOL ReadLUT8(LPLCMSICCPROFILE Icc, LPLUT NewLUT, icTagSignature sig)
-{
- icLut8 LUT8;
- LPBYTE Temp;
- size_t nTabSize;
- unsigned int i, j;
- unsigned int AllLinear;
- LPWORD PtrW;
-
- if (Icc ->Read(&LUT8, sizeof(icLut8) - SIZEOF_UINT8_ALIGNED, 1, Icc) != 1) return FALSE;
-
- NewLUT -> wFlags = LUT_HASTL1|LUT_HASTL2|LUT_HAS3DGRID;
- NewLUT -> cLutPoints = LUT8.clutPoints;
- NewLUT -> InputChan = LUT8.inputChan;
- NewLUT -> OutputChan = LUT8.outputChan;
- NewLUT -> InputEntries = 256;
- NewLUT -> OutputEntries = 256;
-
- // Do some checking
- if (!_cmsValidateLUT(NewLUT)) {
- return FALSE;
- }
-
- AdjustEndianess32((LPBYTE) &LUT8.e00);
- AdjustEndianess32((LPBYTE) &LUT8.e01);
- AdjustEndianess32((LPBYTE) &LUT8.e02);
- AdjustEndianess32((LPBYTE) &LUT8.e10);
- AdjustEndianess32((LPBYTE) &LUT8.e11);
- AdjustEndianess32((LPBYTE) &LUT8.e12);
- AdjustEndianess32((LPBYTE) &LUT8.e20);
- AdjustEndianess32((LPBYTE) &LUT8.e21);
- AdjustEndianess32((LPBYTE) &LUT8.e22);
-
-
- // Matrix handling
-
- NewLUT -> Matrix.v[0].n[0] = (Fixed32) LUT8.e00;
- NewLUT -> Matrix.v[0].n[1] = (Fixed32) LUT8.e01;
- NewLUT -> Matrix.v[0].n[2] = (Fixed32) LUT8.e02;
- NewLUT -> Matrix.v[1].n[0] = (Fixed32) LUT8.e10;
- NewLUT -> Matrix.v[1].n[1] = (Fixed32) LUT8.e11;
- NewLUT -> Matrix.v[1].n[2] = (Fixed32) LUT8.e12;
- NewLUT -> Matrix.v[2].n[0] = (Fixed32) LUT8.e20;
- NewLUT -> Matrix.v[2].n[1] = (Fixed32) LUT8.e21;
- NewLUT -> Matrix.v[2].n[2] = (Fixed32) LUT8.e22;
-
-
- // Only operates if not identity...
-
- if ((NewLUT -> InputChan == 3) && !MAT3isIdentity(&NewLUT -> Matrix, 0.0001)) {
-
- NewLUT -> wFlags |= LUT_HASMATRIX;
- }
+static const cmsTagSignature PCS2DeviceFloat[] = {cmsSigBToD0Tag, // Perceptual
+ cmsSigBToD1Tag, // Relative colorimetric
+ cmsSigBToD2Tag, // Saturation
+ cmsSigBToD3Tag }; // Absolute colorimetric
- // Copy input tables
-
- Temp = (LPBYTE) _cmsMalloc(256);
- if (Temp == NULL) return FALSE;
-
- AllLinear = 0;
- for (i=0; i < NewLUT -> InputChan; i++) {
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * 256);
- if (PtrW == NULL) {
- _cmsFree(Temp);
- return FALSE;
- }
-
- NewLUT -> L1[i] = PtrW;
- if (Icc ->Read(Temp, 1, 256, Icc) != 256) {
- _cmsFree(Temp);
- return FALSE;
- }
-
- for (j=0; j < 256; j++)
- PtrW[j] = TO16_TAB(Temp[j]);
- AllLinear += cmsIsLinear(NewLUT -> L1[i], NewLUT -> InputEntries);
- }
-
- // Linear input, so ignore full step
-
- if (AllLinear == NewLUT -> InputChan) {
-
- NewLUT -> wFlags &= ~LUT_HASTL1;
- }
-
- _cmsFree(Temp);
-
- // Copy 3D CLUT
-
- nTabSize = (NewLUT -> OutputChan * uipow(NewLUT->cLutPoints,
- NewLUT->InputChan));
-
- if (nTabSize > 0) {
-
- PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize);
- if (PtrW == NULL) return FALSE;
-
- Temp = (LPBYTE) _cmsMalloc(nTabSize);
- if (Temp == NULL) {
- _cmsFree(PtrW);
- return FALSE;
- }
-
- if (Icc ->Read(Temp, 1, nTabSize, Icc) != nTabSize) {
- _cmsFree(Temp);
- _cmsFree(PtrW);
- return FALSE;
- }
-
- NewLUT -> T = PtrW;
- NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD));
-
- for (i = 0; i < nTabSize; i++) {
-
- *PtrW++ = TO16_TAB(Temp[i]);
- }
- _cmsFree(Temp);
- }
- else {
- NewLUT ->T = NULL;
- NewLUT ->Tsize = 0;
- NewLUT ->wFlags &= ~LUT_HAS3DGRID;
- }
-
-
- // Copy output tables
-
- Temp = (LPBYTE) _cmsMalloc(256);
- if (Temp == NULL) {
- return FALSE;
- }
-
- AllLinear = 0;
- for (i=0; i < NewLUT -> OutputChan; i++) {
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * 256);
- if (PtrW == NULL) {
- _cmsFree(Temp);
- return FALSE;
- }
-
- NewLUT -> L2[i] = PtrW;
- if (Icc ->Read(Temp, 1, 256, Icc) != 256) {
- _cmsFree(Temp);
- return FALSE;
- }
-
- for (j=0; j < 256; j++)
- PtrW[j] = TO16_TAB(Temp[j]);
- AllLinear += cmsIsLinear(NewLUT -> L2[i], 256);
- }
-
- // Linear input, so ignore full step
-
- if (AllLinear == NewLUT -> OutputChan) {
-
- NewLUT -> wFlags &= ~LUT_HASTL2;
- }
-
-
- _cmsFree(Temp);
-
- cmsCalcL16Params(NewLUT -> InputEntries, &NewLUT -> In16params);
- cmsCalcL16Params(NewLUT -> OutputEntries, &NewLUT -> Out16params);
- cmsCalcCLUT16Params(NewLUT -> cLutPoints, NewLUT -> InputChan,
- NewLUT -> OutputChan,
- &NewLUT -> CLut16params);
- // Fixup
-
- if (Icc ->PCS == icSigLabData) {
-
- // Abstract or Lab identity
-
- if (Icc -> ColorSpace == icSigLabData)
-
- FixLUT8bothSides(NewLUT, nTabSize);
- else
- FixLUT8(NewLUT, sig, nTabSize);
-
-
- // Now some additional fixup. Lab encoding on 8 bit makes
- // impossible to place gray axis on a exact node. However,
- // some profiles does claim to do that. Poor lcms will try
- // to detect such condition and fix up "on the fly".
-
- switch (sig) {
-
- case icSigBToA0Tag:
- case icSigBToA1Tag:
- case icSigBToA2Tag:
- case icSigGamutTag:
- case icSigPreview0Tag:
- case icSigPreview1Tag:
- case icSigPreview2Tag:
- {
- LPWORD WhiteLab, ExpectedWhite;
- WORD WhiteFixed[MAXCHANNELS], WhiteUnfixed[MAXCHANNELS];
- int j, nChannels;
- double Dist, DistFixed, DistUnfixed;
-
- _cmsEndPointsBySpace(icSigLabData, &WhiteLab, NULL, NULL);
+// Factors to convert from 1.15 fixed point to 0..1.0 range and vice-versa
+#define InpAdj (1.0/MAX_ENCODEABLE_XYZ) // (65536.0/(65535.0*2.0))
+#define OutpAdj (MAX_ENCODEABLE_XYZ) // ((2.0*65535.0)/65536.0)
- if (_cmsEndPointsBySpace(Icc -> ColorSpace,
- &ExpectedWhite, NULL, &nChannels)) {
-
- // 1.- Find white obtained by both combinations
-
- NewLUT -> FixGrayAxes = FALSE;
- cmsEvalLUT(NewLUT, WhiteLab, WhiteUnfixed);
-
- NewLUT -> FixGrayAxes = TRUE;
- cmsEvalLUT(NewLUT, WhiteLab, WhiteFixed);
-
- // 2.- Which method gives closer white?
-
- DistFixed = DistUnfixed = 0;
- for (j=0; j < nChannels; j++) {
-
- Dist = ExpectedWhite[j] - WhiteFixed[j];
- DistFixed += Dist*Dist;
- Dist = ExpectedWhite[j] - WhiteUnfixed[j];
- DistUnfixed += Dist*Dist;
- }
-
- // 3.- Decide method
-
- if (sqrt(DistFixed) < sqrt(DistUnfixed))
- NewLUT -> FixGrayAxes = TRUE;
- else
- NewLUT -> FixGrayAxes = FALSE;
- }
-
- }
- break;
-
- default:;
- }
- }
-
- return TRUE;
-}
-
-
-
-
-// Case LUT 16
-
-static
-LCMSBOOL ReadLUT16(LPLCMSICCPROFILE Icc, LPLUT NewLUT)
-{
- icLut16 LUT16;
- size_t nTabSize;
- unsigned int i;
- unsigned int AllLinear;
- LPWORD PtrW;
-
-
- if (Icc ->Read(&LUT16, sizeof(icLut16)- SIZEOF_UINT16_ALIGNED, 1, Icc) != 1)
- return FALSE;
-
- NewLUT -> wFlags = LUT_HASTL1 | LUT_HASTL2 | LUT_HAS3DGRID;
- NewLUT -> cLutPoints = LUT16.clutPoints;
- NewLUT -> InputChan = LUT16.inputChan;
- NewLUT -> OutputChan = LUT16.outputChan;
-
- AdjustEndianess16((LPBYTE) &LUT16.inputEnt);
- AdjustEndianess16((LPBYTE) &LUT16.outputEnt);
-
- NewLUT -> InputEntries = LUT16.inputEnt;
- NewLUT -> OutputEntries = LUT16.outputEnt;
-
- if (!_cmsValidateLUT(NewLUT)) {
- return FALSE;
- }
-
- // Matrix handling
-
- AdjustEndianess32((LPBYTE) &LUT16.e00);
- AdjustEndianess32((LPBYTE) &LUT16.e01);
- AdjustEndianess32((LPBYTE) &LUT16.e02);
- AdjustEndianess32((LPBYTE) &LUT16.e10);
- AdjustEndianess32((LPBYTE) &LUT16.e11);
- AdjustEndianess32((LPBYTE) &LUT16.e12);
- AdjustEndianess32((LPBYTE) &LUT16.e20);
- AdjustEndianess32((LPBYTE) &LUT16.e21);
- AdjustEndianess32((LPBYTE) &LUT16.e22);
-
- NewLUT -> Matrix.v[0].n[0] = (Fixed32) LUT16.e00;
- NewLUT -> Matrix.v[0].n[1] = (Fixed32) LUT16.e01;
- NewLUT -> Matrix.v[0].n[2] = (Fixed32) LUT16.e02;
- NewLUT -> Matrix.v[1].n[0] = (Fixed32) LUT16.e10;
- NewLUT -> Matrix.v[1].n[1] = (Fixed32) LUT16.e11;
- NewLUT -> Matrix.v[1].n[2] = (Fixed32) LUT16.e12;
- NewLUT -> Matrix.v[2].n[0] = (Fixed32) LUT16.e20;
- NewLUT -> Matrix.v[2].n[1] = (Fixed32) LUT16.e21;
- NewLUT -> Matrix.v[2].n[2] = (Fixed32) LUT16.e22;
-
- // Only operates if not identity...
-
- if ((NewLUT -> InputChan == 3) && !MAT3isIdentity(&NewLUT -> Matrix, 0.0001)) {
-
- NewLUT -> wFlags |= LUT_HASMATRIX;
- }
-
-
- // Copy input tables
-
- AllLinear = 0;
- for (i=0; i < NewLUT -> InputChan; i++) {
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> InputEntries);
- if (PtrW == NULL) return FALSE;
-
- NewLUT -> L1[i] = PtrW;
- if (Icc ->Read(PtrW, sizeof(WORD), NewLUT -> InputEntries, Icc) != NewLUT -> InputEntries) {
- return FALSE;
- }
-
- AdjustEndianessArray16(PtrW, NewLUT -> InputEntries);
- AllLinear += cmsIsLinear(NewLUT -> L1[i], NewLUT -> InputEntries);
- }
-
- // Linear input, so ignore full step
-
- if (AllLinear == NewLUT -> InputChan) {
-
- NewLUT -> wFlags &= ~LUT_HASTL1;
- }
-
-
- // Copy 3D CLUT
-
- nTabSize = (NewLUT -> OutputChan * uipow(NewLUT->cLutPoints,
- NewLUT->InputChan));
- if (nTabSize > 0) {
-
- PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize);
- if (PtrW == NULL)
- return FALSE;
-
- NewLUT -> T = PtrW;
- NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD));
-
- if (Icc -> Read(PtrW, sizeof(WORD), nTabSize, Icc) != nTabSize) {
- return FALSE;
- }
-
- AdjustEndianessArray16(NewLUT -> T, nTabSize);
- }
- else {
- NewLUT ->T = NULL;
- NewLUT ->Tsize = 0;
- NewLUT -> wFlags &= ~LUT_HAS3DGRID;
- }
+// Several resources for gray conversions.
+static const cmsFloat64Number GrayInputMatrix[] = { (InpAdj*cmsD50X), (InpAdj*cmsD50Y), (InpAdj*cmsD50Z) };
+static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 };
+static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 };
+static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 };
- // Copy output tables
-
- AllLinear = 0;
- for (i=0; i < NewLUT -> OutputChan; i++) {
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> OutputEntries);
- if (PtrW == NULL) {
- return FALSE;
- }
-
- NewLUT -> L2[i] = PtrW;
- if (Icc ->Read(PtrW, sizeof(WORD), NewLUT -> OutputEntries, Icc) != NewLUT -> OutputEntries) {
- return FALSE;
- }
-
- AdjustEndianessArray16(PtrW, NewLUT -> OutputEntries);
- AllLinear += cmsIsLinear(NewLUT -> L2[i], NewLUT -> OutputEntries);
- }
-
- // Linear output, ignore step
-
- if (AllLinear == NewLUT -> OutputChan)
- {
- NewLUT -> wFlags &= ~LUT_HASTL2;
- }
-
-
- cmsCalcL16Params(NewLUT -> InputEntries, &NewLUT -> In16params);
- cmsCalcL16Params(NewLUT -> OutputEntries, &NewLUT -> Out16params);
- cmsCalcCLUT16Params(NewLUT -> cLutPoints, NewLUT -> InputChan,
- NewLUT -> OutputChan,
- &NewLUT -> CLut16params);
-
- return TRUE;
-}
-
-
-// This is a shared routine for reading curves. It can handle v2 curves
-// as linear, single gamma and table-based as well as v4 parametric curves.
-
-static
-LPGAMMATABLE ReadCurve(LPLCMSICCPROFILE Icc)
+// Get a media white point fixing some issues found in certain old profiles
+cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile)
{
- icUInt32Number Count;
- LPGAMMATABLE NewGamma;
- icTagTypeSignature BaseType;
- int n;
-
-
- BaseType = ReadBase(Icc);
- switch (BaseType) {
-
-
- case ((icTagTypeSignature) 0x9478ee00): // Monaco 2 profiler is BROKEN!
- case icSigCurveType:
-
- if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL;
- AdjustEndianess32((LPBYTE) &Count);
-
- switch (Count) {
-
- case 0: // Linear.
-
- NewGamma = cmsAllocGamma(2);
- if (!NewGamma) return NULL;
- NewGamma -> GammaTable[0] = 0;
- NewGamma -> GammaTable[1] = 0xFFFF;
- return NewGamma;
-
- case 1: // Specified as the exponent of gamma function
- {
- WORD SingleGammaFixed;
+ cmsCIEXYZ* Tag;
- if (Icc ->Read(&SingleGammaFixed, sizeof(WORD), 1, Icc) != 1) return NULL;
- AdjustEndianess16((LPBYTE) &SingleGammaFixed);
- return cmsBuildGamma(4096, Convert8Fixed8(SingleGammaFixed));
- }
-
- default: { // Curve
-
- NewGamma = cmsAllocGamma(Count);
- if (!NewGamma) return NULL;
-
- if (Icc ->Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc) != Count)
- return NULL;
- AdjustEndianessArray16(NewGamma -> GammaTable, Count);
- return NewGamma;
- }
- }
- break;
-
-
- // Parametric curves
- case icSigParametricCurveType: {
-
- int ParamsByType[] = { 1, 3, 4, 5, 7 };
- double Params[10];
- icS15Fixed16Number Num;
- icUInt32Number Reserved;
- icUInt16Number Type;
- int i;
-
- if (Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc) != 1) return NULL;
- if (Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc) != 1) return NULL;
-
- AdjustEndianess16((LPBYTE) &Type);
- if (Type > 4) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Unknown parametric curve type '%d' found.", Type);
- return NULL;
- }
-
- ZeroMemory(Params, 10* sizeof(double));
- n = ParamsByType[Type];
-
- for (i=0; i < n; i++) {
- Num = 0;
- if (Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc) != 1) return NULL;
- Params[i] = Convert15Fixed16(Num);
- }
-
-
- NewGamma = cmsBuildParametricGamma(4096, Type+1, Params);
- return NewGamma;
- }
-
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature '%lx' found.", BaseType);
- return NULL;
- }
-
-}
-
-
-// Similar to anterior, but curve is reversed
-
-static
-LPGAMMATABLE ReadCurveReversed(LPLCMSICCPROFILE Icc)
-{
-
- icTagTypeSignature BaseType;
- LPGAMMATABLE NewGamma, ReturnGamma;
- icUInt32Number Count;
- int n;
-
-
- BaseType = ReadBase(Icc);
-
- switch (BaseType) {
-
+ _cmsAssert(Dest != NULL);
- case 0x9478ee00L: // Monaco 2 profiler is BROKEN!
- case icSigCurveType:
-
- if (Icc -> Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL;
- AdjustEndianess32((LPBYTE) &Count);
-
-
- switch (Count) {
-
- case 0: // Linear, reverse is same.
-
- NewGamma = cmsAllocGamma(2);
- if (!NewGamma) return NULL;
-
- NewGamma -> GammaTable[0] = 0;
- NewGamma -> GammaTable[1] = 0xFFFF;
- return NewGamma;
-
- case 1: {
- WORD SingleGammaFixed;
-
- if (Icc -> Read(&SingleGammaFixed, sizeof(WORD), 1, Icc) != 1) return NULL;
- AdjustEndianess16((LPBYTE) &SingleGammaFixed);
- return cmsBuildGamma(4096, 1./Convert8Fixed8(SingleGammaFixed));
- }
-
- default: { // Curve. Do our best to trying to reverse the curve
-
- NewGamma = cmsAllocGamma(Count);
- if (!NewGamma) return NULL;
-
- if (Icc -> Read(NewGamma -> GammaTable, sizeof(WORD), Count, Icc) != Count)
- return NULL;
-
- AdjustEndianessArray16(NewGamma -> GammaTable, Count);
-
- if (Count < 256)
- Count = 256; // Reverse of simple curve has not necesarely to be simple
-
- ReturnGamma = cmsReverseGamma(Count, NewGamma);
- cmsFreeGamma(NewGamma);
-
- return ReturnGamma;
- }
- }
- break;
-
-
- // Parametric curves
- case icSigParametricCurveType: {
-
- int ParamsByType[] = { 1, 3, 4, 5, 7 };
- double Params[10];
- icS15Fixed16Number Num;
- icUInt32Number Reserved;
- icUInt16Number Type;
- int i;
-
-
- if (Icc -> Read(&Type, sizeof(icUInt16Number), 1, Icc) != 1) return NULL;
- if (Icc -> Read(&Reserved, sizeof(icUInt16Number), 1, Icc) != 1) return NULL;
-
- AdjustEndianess16((LPBYTE) &Type);
- if (Type > 4) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Unknown parametric curve type '%d' found.", Type);
- return NULL;
- }
-
- ZeroMemory(Params, 10* sizeof(double));
- n = ParamsByType[Type];
+ Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag);
- for (i=0; i < n; i++) {
- if (Icc -> Read(&Num, sizeof(icS15Fixed16Number), 1, Icc) != 1) return NULL;
- Params[i] = Convert15Fixed16(Num);
- }
-
-
- // Negative type as a mark of reversed curve
- NewGamma = cmsBuildParametricGamma(4096, -(Type+1), Params);
- return NewGamma;
- }
-
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature '%lx' found.", BaseType);
- return NULL;
- }
-
-}
-
-
-// V4 stuff. Read matrix for LutAtoB and LutBtoA
-
-static
-LCMSBOOL ReadMatrixOffset(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, DWORD dwFlags)
-{
-
- icS15Fixed16Number All[12];
- int i;
- MAT3 m;
- VEC3 o;
-
- if (Icc -> Seek(Icc, Offset)) return FALSE;
-
- if (Icc ->Read(All, sizeof(icS15Fixed16Number), 12, Icc) != 12)
- return FALSE;
-
- for (i=0; i < 12; i++)
- AdjustEndianess32((LPBYTE) &All[i]);
-
-
- m.v[0].n[0] = FIXED_TO_DOUBLE((Fixed32) All[0]);
- m.v[0].n[1] = FIXED_TO_DOUBLE((Fixed32) All[1]);
- m.v[0].n[2] = FIXED_TO_DOUBLE((Fixed32) All[2]);
- m.v[1].n[0] = FIXED_TO_DOUBLE((Fixed32) All[3]);
- m.v[1].n[1] = FIXED_TO_DOUBLE((Fixed32) All[4]);
- m.v[1].n[2] = FIXED_TO_DOUBLE((Fixed32) All[5]);
- m.v[2].n[0] = FIXED_TO_DOUBLE((Fixed32) All[6]);
- m.v[2].n[1] = FIXED_TO_DOUBLE((Fixed32) All[7]);
- m.v[2].n[2] = FIXED_TO_DOUBLE((Fixed32) All[8]);
-
- o.n[0] = FIXED_TO_DOUBLE((Fixed32) All[9]);
- o.n[1] = FIXED_TO_DOUBLE((Fixed32) All[10]);
- o.n[2] = FIXED_TO_DOUBLE((Fixed32) All[11]);
-
- cmsSetMatrixLUT4(NewLUT, &m, &o, dwFlags);
-
- return TRUE;
-}
-
-
-// V4 stuff. Read CLUT part for LutAtoB and LutBtoA
-
-static
-LCMSBOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT)
-{
- unsigned int j;
- icCLutStruct CLUT;
-
- if (Icc -> Seek(Icc, Offset)) return FALSE;
- if (Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc) != 1) return FALSE;
-
-
- for (j=1; j < NewLUT ->InputChan; j++) {
- if (CLUT.gridPoints[0] != CLUT.gridPoints[j]) {
- cmsSignalError(LCMS_ERRC_ABORTED, "CLUT with different granulatity is currently unsupported.");
- return FALSE;
- }
-
-
+ // If no wp, take D50
+ if (Tag == NULL) {
+ *Dest = *cmsD50_XYZ();
+ return TRUE;
}
- if (cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan,
- NewLUT ->OutputChan) == NULL) return FALSE;
-
- // Precission can be 1 or 2 bytes
-
- if (CLUT.prec == 1) {
+ // V2 display profiles should give D50
+ if (cmsGetEncodedICCversion(hProfile) < 0x4000000) {
- BYTE v;
- unsigned int i;
-
- for (i=0; i < NewLUT->Tsize / sizeof(WORD); i++) {
- if (Icc ->Read(&v, sizeof(BYTE), 1, Icc) != 1) return FALSE;
- NewLUT->T[i] = TO16_TAB(v);
+ if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) {
+ *Dest = *cmsD50_XYZ();
+ return TRUE;
}
-
- }
- else
- if (CLUT.prec == 2) {
-
- size_t n = NewLUT->Tsize / sizeof(WORD);
-
- if (Icc ->Read(NewLUT ->T, sizeof(WORD), n, Icc) != n) return FALSE;
- AdjustEndianessArray16(NewLUT ->T, NewLUT->Tsize / sizeof(WORD));
- }
- else {
- cmsSignalError(LCMS_ERRC_ABORTED, "Unknow precission of '%d'", CLUT.prec);
- return FALSE;
}
+ // All seems ok
+ *Dest = *Tag;
return TRUE;
}
-static
-void ResampleCurves(LPGAMMATABLE Curves[], int nCurves)
-{
- int i;
- LPSAMPLEDCURVE sc;
-
- for (i=0; i < nCurves; i++) {
- sc = cmsConvertGammaToSampledCurve(Curves[i], 4096);
- cmsFreeGamma(Curves[i]);
- Curves[i] = cmsConvertSampledCurveToGamma(sc, 0xFFFF);
- cmsFreeSampledCurve(sc);
- }
-
-}
-
-
-static
-void SkipAlignment(LPLCMSICCPROFILE Icc)
-{
- BYTE Buffer[4];
- size_t At = Icc ->Tell(Icc);
- int BytesToNextAlignedPos = (int) (At % 4);
-
- Icc ->Read(Buffer, 1, BytesToNextAlignedPos, Icc);
-}
-
-// Read a set of curves from specific offset
-static
-LCMSBOOL ReadSetOfCurves(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT, int nLocation)
+// Chromatic adaptation matrix. Fix some issues as well
+cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile)
{
- LPGAMMATABLE Curves[MAXCHANNELS];
- unsigned int i, nCurves;
-
- if (Icc -> Seek(Icc, Offset)) return FALSE;
-
- if (nLocation == 1 || nLocation == 3)
-
- nCurves = NewLUT ->InputChan;
- else
- nCurves = NewLUT ->OutputChan;
-
- ZeroMemory(Curves, sizeof(Curves));
- for (i=0; i < nCurves; i++) {
-
- Curves[i] = ReadCurve(Icc);
- if (Curves[i] == NULL) goto Error;
- SkipAlignment(Icc);
- }
-
- // March-26'08: some V4 profiles may have different sampling
- // rates, in this case resample all curves to maximum
-
- for (i=1; i < nCurves; i++) {
- if (Curves[i]->nEntries != Curves[0]->nEntries) {
- ResampleCurves(Curves, nCurves);
- break;
- }
- }
-
- NewLUT = cmsAllocLinearTable(NewLUT, Curves, nLocation);
- if (NewLUT == NULL) goto Error;
-
- for (i=0; i < nCurves; i++)
- cmsFreeGamma(Curves[i]);
-
- return TRUE;
-
-Error:
+ cmsMAT3* Tag;
- for (i=0; i < nCurves; i++)
- if (Curves[i])
- cmsFreeGamma(Curves[i]);
-
- return FALSE;
-
-
-}
-
-// V4 stuff. LutAtoB type
-//
-// [L1] -> [CLUT] -> [L4] -> [Mat4] -> [Ofs4] -> [L2]
-//
-// Mat, Mat3, Ofs3, L3 are missing
-// L1 = A curves
-// L4 = M curves
-// L2 = B curves
-
-static
-LCMSBOOL ReadLUT_A2B(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig)
-{
- icLutAtoB LUT16;
-
- if (Icc ->Read(&LUT16, sizeof(icLutAtoB), 1, Icc) != 1) return FALSE;
-
- NewLUT -> InputChan = LUT16.inputChan;
- NewLUT -> OutputChan = LUT16.outputChan;
-
- // Validate the NewLUT here to avoid excessive number of channels
- // (leading to stack-based buffer overflow in ReadSetOfCurves).
- // Needs revalidation after table size is filled in.
- if (!_cmsValidateLUT(NewLUT)) {
- return FALSE;
- }
-
- AdjustEndianess32((LPBYTE) &LUT16.offsetB);
- AdjustEndianess32((LPBYTE) &LUT16.offsetMat);
- AdjustEndianess32((LPBYTE) &LUT16.offsetM);
- AdjustEndianess32((LPBYTE) &LUT16.offsetC);
- AdjustEndianess32((LPBYTE) &LUT16.offsetA);
-
- if (LUT16.offsetB != 0)
- ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetB, NewLUT, 2);
-
- if (LUT16.offsetMat != 0)
- ReadMatrixOffset(Icc, BaseOffset + LUT16.offsetMat, NewLUT, LUT_HASMATRIX4);
-
-
- if (LUT16.offsetM != 0)
- ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetM, NewLUT, 4);
-
- if (LUT16.offsetC != 0)
- ReadCLUT(Icc, BaseOffset + LUT16.offsetC, NewLUT);
-
- if (LUT16.offsetA!= 0)
- ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetA, NewLUT, 1);
-
- // Convert to v2 PCS
-
- if (Icc ->PCS == icSigLabData) {
-
- switch (sig) {
-
- case icSigAToB0Tag:
- case icSigAToB1Tag:
- case icSigAToB2Tag:
- case icSigGamutTag:
- case icSigPreview0Tag:
- case icSigPreview1Tag:
- case icSigPreview2Tag:
-
- NewLUT ->wFlags |= LUT_V4_INPUT_EMULATE_V2;
- break;
+ _cmsAssert(Dest != NULL);
- default:;
- }
- }
-
-
- return TRUE;
-}
-
-// V4 stuff. LutBtoA type
-
-static
-LCMSBOOL ReadLUT_B2A(LPLCMSICCPROFILE Icc, LPLUT NewLUT, size_t BaseOffset, icTagSignature sig)
-{
- icLutBtoA LUT16;
-
- if (Icc ->Read(&LUT16, sizeof(icLutBtoA), 1, Icc) != 1) return FALSE;
-
- NewLUT -> InputChan = LUT16.inputChan;
- NewLUT -> OutputChan = LUT16.outputChan;
-
- // Validate the NewLUT here to avoid excessive number of channels
- // (leading to stack-based buffer overflow in ReadSetOfCurves).
- // Needs revalidation after table size is filled in.
- if (!_cmsValidateLUT(NewLUT)) {
- return FALSE;
- }
-
- AdjustEndianess32((LPBYTE) &LUT16.offsetB);
- AdjustEndianess32((LPBYTE) &LUT16.offsetMat);
- AdjustEndianess32((LPBYTE) &LUT16.offsetM);
- AdjustEndianess32((LPBYTE) &LUT16.offsetC);
- AdjustEndianess32((LPBYTE) &LUT16.offsetA);
-
-
- if (LUT16.offsetB != 0)
- ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetB, NewLUT, 1);
-
- if (LUT16.offsetMat != 0)
- ReadMatrixOffset(Icc, BaseOffset + LUT16.offsetMat, NewLUT, LUT_HASMATRIX3);
-
- if (LUT16.offsetM != 0)
- ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetM, NewLUT, 3);
-
- if (LUT16.offsetC != 0)
- ReadCLUT(Icc, BaseOffset + LUT16.offsetC, NewLUT);
-
- if (LUT16.offsetA!= 0)
- ReadSetOfCurves(Icc, BaseOffset + LUT16.offsetA, NewLUT, 2);
-
-
- // Convert to v2 PCS
-
- if (Icc ->PCS == icSigLabData) {
-
- switch (sig) {
-
- case icSigBToA0Tag:
- case icSigBToA1Tag:
- case icSigBToA2Tag:
- case icSigGamutTag:
- case icSigPreview0Tag:
- case icSigPreview1Tag:
- case icSigPreview2Tag:
-
- NewLUT ->wFlags |= LUT_V4_OUTPUT_EMULATE_V2;
- break;
-
- default:;
- }
- }
+ Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag);
- return TRUE;
-}
-
-// CLUT main reader
-
-LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig)
-{
-
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- icTagTypeSignature BaseType;
- int n;
- size_t offset;
- LPLUT NewLUT;
-
- n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0)
- return NULL;
-
-
- // If is in memory, the LUT is already there, so throw a copy
- if (Icc -> TagPtrs[n]) {
- if (!_cmsValidateLUT((LPLUT) Icc ->TagPtrs[n])) {
- return NULL;
- }
-
- return cmsDupLUT((LPLUT) Icc ->TagPtrs[n]);
- }
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return NULL;
-
- BaseType = ReadBase(Icc);
-
+ if (Tag != NULL) {
- NewLUT = cmsAllocLUT();
- if (!NewLUT) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsAllocLUT() failed");
- return NULL;
- }
-
-
- switch (BaseType) {
-
- case icSigLut8Type: if (!ReadLUT8(Icc, NewLUT, sig)) {
- cmsFreeLUT(NewLUT);
- return NULL;
- }
- break;
-
- case icSigLut16Type: if (!ReadLUT16(Icc, NewLUT)) {
- cmsFreeLUT(NewLUT);
- return NULL;
- }
- break;
-
- case icSiglutAtoBType: if (!ReadLUT_A2B(Icc, NewLUT, offset, sig)) {
- cmsFreeLUT(NewLUT);
- return NULL;
- }
- break;
-
- case icSiglutBtoAType: if (!ReadLUT_B2A(Icc, NewLUT, offset, sig)) {
- cmsFreeLUT(NewLUT);
- return NULL;
- }
- break;
-
- default: cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature %lx found.", BaseType);
- cmsFreeLUT(NewLUT);
- return NULL;
+ *Dest = *Tag;
+ return TRUE;
}
-
- return NewLUT;
-}
-
-
-// Sets the language & country preferences. Used only in ICC 4.0 profiles
-
-void LCMSEXPORT cmsSetLanguage(const char LanguageCode[4], const char CountryCode[4])
-{
-
- int LanguageCodeInt = *(int *) LanguageCode;
- int CountryCodeInt = *(int *) CountryCode;
-
- AdjustEndianess32((LPBYTE) &LanguageCodeInt);
- AdjustEndianess32((LPBYTE) &CountryCodeInt);
-
- GlobalLanguageCode = LanguageCodeInt;
- GlobalCountryCode = CountryCodeInt;
-}
-
-
-
-// Some tags (e.g, 'pseq') can have text tags embedded. This function
-// handles such special case. Returns -1 on error, or the number of bytes left on success.
-
-static
-int ReadEmbeddedTextTag(LPLCMSICCPROFILE Icc, size_t size, char* Name, size_t size_max)
-{
- icTagTypeSignature BaseType;
-
-
- BaseType = ReadBase(Icc);
- size -= sizeof(icTagBase);
-
- switch (BaseType) {
-
- case icSigTextDescriptionType: {
-
- icUInt32Number AsciiCount;
- icUInt32Number i, UnicodeCode, UnicodeCount;
- icUInt16Number ScriptCodeCode, Dummy;
- icUInt8Number ScriptCodeCount;
-
- if (Icc ->Read(&AsciiCount, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
+ // No CHAD available, default it to identity
+ _cmsMAT3identity(Dest);
- if (size < sizeof(icUInt32Number)) return (int) size;
- size -= sizeof(icUInt32Number);
-
- AdjustEndianess32((LPBYTE) &AsciiCount);
- Icc ->Read(Name, 1,
- (AsciiCount >= size_max) ? (size_max-1) : AsciiCount, Icc);
-
- if (size < AsciiCount) return (int) size;
- size -= AsciiCount;
-
- // Skip Unicode code
-
- if (Icc ->Read(&UnicodeCode, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
- if (size < sizeof(icUInt32Number)) return (int) size;
- size -= sizeof(icUInt32Number);
-
- if (Icc ->Read(&UnicodeCount, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
- if (size < sizeof(icUInt32Number)) return (int) size;
- size -= sizeof(icUInt32Number);
-
- AdjustEndianess32((LPBYTE) &UnicodeCount);
-
- if (UnicodeCount > size) return (int) size;
-
- for (i=0; i < UnicodeCount; i++) {
- size_t nread = Icc ->Read(&Dummy, sizeof(icUInt16Number), 1, Icc);
- if (nread != 1) return (int) size;
- size -= sizeof(icUInt16Number);
- }
-
- // Skip ScriptCode code
-
- if (Icc ->Read(&ScriptCodeCode, sizeof(icUInt16Number), 1, Icc) != 1) return -1;
- size -= sizeof(icUInt16Number);
- if (Icc ->Read(&ScriptCodeCount, sizeof(icUInt8Number), 1, Icc) != 1) return -1;
- size -= sizeof(icUInt8Number);
-
- // Should remain 67 bytes as filler
-
- if (size < 67) return (int) size;
-
- for (i=0; i < 67; i++) {
- size_t nread = Icc ->Read(&Dummy, sizeof(icUInt8Number), 1, Icc);
- if (nread != 1) return (int) size;
- size --;
- }
- }
- break;
-
+ // V2 display profiles should give D50
+ if (cmsGetEncodedICCversion(hProfile) < 0x4000000) {
- case icSigCopyrightTag: // Broken profiles from agfa does store copyright info in such type
- case icSigTextType:
- {
- char Dummy;
- size_t i, Missing = 0;
-
- if (size >= size_max) {
-
- Missing = size - size_max + 1;
- size = size_max - 1;
- }
-
- if (Icc -> Read(Name, 1, size, Icc) != size) return -1;
-
- for (i=0; i < Missing; i++)
- Icc -> Read(&Dummy, 1, 1, Icc);
- }
- break;
-
- // MultiLocalizedUnicodeType, V4 only
+ if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) {
- case icSigMultiLocalizedUnicodeType: {
-
- icUInt32Number Count, RecLen;
- icUInt16Number Language, Country;
- icUInt32Number ThisLen, ThisOffset;
- size_t Offset = 0;
- size_t Len = 0;
- size_t i;
- wchar_t* wchar = L"";
-
-
- if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
- AdjustEndianess32((LPBYTE) &Count);
- if (Icc ->Read(&RecLen, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
- AdjustEndianess32((LPBYTE) &RecLen);
-
- if (RecLen != 12) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "multiLocalizedUnicodeType of len != 12 is not supported.");
- return -1;
- }
-
- for (i=0; i < Count; i++) {
+ cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag);
- if (Icc ->Read(&Language, sizeof(icUInt16Number), 1, Icc) != 1) return -1;
- AdjustEndianess16((LPBYTE) &Language);
- if (Icc ->Read(&Country, sizeof(icUInt16Number), 1, Icc) != 1) return -1;
- AdjustEndianess16((LPBYTE) &Country);
-
- if (Icc ->Read(&ThisLen, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
- AdjustEndianess32((LPBYTE) &ThisLen);
-
- if (Icc ->Read(&ThisOffset, sizeof(icUInt32Number), 1, Icc) != 1) return -1;
- AdjustEndianess32((LPBYTE) &ThisOffset);
-
- if (Language == GlobalLanguageCode || Offset == 0) {
-
- Len = ThisLen; Offset = ThisOffset;
- if (Country == GlobalCountryCode)
- break; // Found
- }
-
- }
-
-
- if (Offset == 0) {
-
- strcpy(Name, "(no info)");
- break;
- }
+ if (White == NULL) {
- // Compute true offset
- Offset -= 12 * Count + 8 + sizeof(icTagBase);
-
- // Skip unused bytes
- for (i=0; i < Offset; i++) {
-
- char Discard;
- if (Icc ->Read(&Discard, 1, 1, Icc) != 1) return -1;
- }
-
-
- // Bound len
- if (Len < 0) Len = 0;
- if (Len > 20*1024) Len = 20 * 1024;
-
- wchar = (wchar_t*) _cmsMalloc(Len*sizeof(wchar_t)+2);
- if (!wchar) return -1;
-
- if (Icc ->Read(wchar, 1, Len, Icc) != Len) return -1;
- AdjustEndianessArray16((LPWORD) wchar, Len / 2);
-
- wchar[Len / 2] = L'\0';
- i = wcstombs(Name, wchar, size_max );
- if (i == ((size_t) -1)) {
-
- Name[0] = 0; // Error
+ _cmsMAT3identity(Dest);
+ return TRUE;
}
- _cmsFree((void*) wchar);
- }
- break;
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature %lx found.", BaseType);
- return -1;
- }
-
- return (int) size;
-}
-
-
-// Take an ASCII item. Takes at most size_max bytes
-
-int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Name, size_t size_max)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- size_t offset, size;
- int n;
-
- n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0)
- return -1;
-
- size = Icc -> TagSizes[n];
-
- if (Icc -> TagPtrs[n]) {
-
- if (size > size_max)
- size = size_max;
-
- CopyMemory(Name, Icc -> TagPtrs[n], size);
-
- return (int) Icc -> TagSizes[n];
- }
-
- offset = Icc -> TagOffsets[n];
-
-
- if (Icc -> Seek(Icc, offset))
- return -1;
-
- if (ReadEmbeddedTextTag(Icc, size, Name, size_max) < 0) return -1;
-
- return size;
-}
-
-// Keep compatibility with older versions
-
-int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Text)
-{
- return cmsReadICCTextEx(hProfile, sig, Text, LCMS_DESC_MAX);
-}
-
-
-// Take an XYZ item
-
-static
-int ReadICCXYZ(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIEXYZ Value, LCMSBOOL lIsFatal)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- icTagTypeSignature BaseType;
- size_t offset;
- int n;
- icXYZNumber XYZ;
-
- n = _cmsSearchTag(Icc, sig, FALSE);
- if (n < 0)
- return -1;
-
- if (Icc -> TagPtrs[n]) {
-
- CopyMemory(Value, Icc -> TagPtrs[n], Icc -> TagSizes[n]);
- return (int) Icc -> TagSizes[n];
- }
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return -1;
-
-
- BaseType = ReadBase(Icc);
-
- switch (BaseType) {
-
-
- case 0x7c3b10cL: // Some apple broken embedded profiles does not have correct type
- case icSigXYZType:
-
- Icc ->Read(&XYZ, sizeof(icXYZNumber), 1, Icc);
- Value -> X = Convert15Fixed16(XYZ.X);
- Value -> Y = Convert15Fixed16(XYZ.Y);
- Value -> Z = Convert15Fixed16(XYZ.Z);
- break;
-
- // Aug/21-2001 - Monaco 2 does have WRONG values.
-
- default:
- if (lIsFatal)
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature %lx found.", BaseType);
- return -1;
- }
-
- return 1;
-}
-
-
-// Read a icSigS15Fixed16ArrayType (currently only a 3x3 matrix)
-
-static
-int ReadICCXYZArray(cmsHPROFILE hProfile, icTagSignature sig, LPMAT3 v)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- icTagTypeSignature BaseType;
- size_t offset, sz;
- int i, n;
- icXYZNumber XYZ[3];
- cmsCIEXYZ XYZdbl[3];
-
-
- n = _cmsSearchTag(Icc, sig, FALSE);
- if (n < 0)
- return -1; // Not found
-
- if (Icc -> TagPtrs[n]) {
-
- CopyMemory(v, Icc -> TagPtrs[n], Icc -> TagSizes[n]);
- return (int) Icc -> TagSizes[n];
- }
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return -1;
-
- BaseType = ReadBase(Icc);
-
- switch (BaseType) {
-
- case icSigS15Fixed16ArrayType:
-
- sz = Icc ->TagSizes[n] / sizeof(icXYZNumber);
-
- if (sz != 3) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad array size of %d entries.", sz);
- return -1;
- }
-
- Icc ->Read(XYZ, sizeof(icXYZNumber), 3, Icc);
-
- for (i=0; i < 3; i++) {
-
- XYZdbl[i].X = Convert15Fixed16(XYZ[i].X);
- XYZdbl[i].Y = Convert15Fixed16(XYZ[i].Y);
- XYZdbl[i].Z = Convert15Fixed16(XYZ[i].Z);
- }
-
- CopyMemory(v, XYZdbl, 3*sizeof(cmsCIEXYZ));
- break;
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature %lx found.", BaseType);
- return -1;
-
- }
-
- return sizeof(MAT3);
-}
-
-
-
-// Primaries are to be in xyY notation
-
-LCMSBOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile)
-{
- if (ReadICCXYZ(hProfile, icSigRedColorantTag, &Dest -> Red, TRUE) < 0) return FALSE;
- if (ReadICCXYZ(hProfile, icSigGreenColorantTag, &Dest -> Green, TRUE) < 0) return FALSE;
- if (ReadICCXYZ(hProfile, icSigBlueColorantTag, &Dest -> Blue, TRUE) < 0) return FALSE;
-
- return TRUE;
-}
-
-
-LCMSBOOL cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile)
-{
- cmsCIEXYZTRIPLE Primaries;
-
- if (!cmsTakeColorants(&Primaries, hProfile)) return FALSE;
-
- VEC3init(&r -> v[0], Primaries.Red.X, Primaries.Green.X, Primaries.Blue.X);
- VEC3init(&r -> v[1], Primaries.Red.Y, Primaries.Green.Y, Primaries.Blue.Y);
- VEC3init(&r -> v[2], Primaries.Red.Z, Primaries.Green.Z, Primaries.Blue.Z);
-
- return TRUE;
-
-}
-
-
-// Always return a suitable matrix
-
-LCMSBOOL cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile)
-{
-
- if (ReadICCXYZArray(hProfile, icSigChromaticAdaptationTag, r) < 0) {
-
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- // For display profiles, revert to bradford. Else take identity.
-
- MAT3identity(r);
-
- // Emissive devices have non-identity chad
-
- if ((cmsGetDeviceClass(hProfile) == icSigDisplayClass) ||
- cmsTakeHeaderFlags(hProfile) & icTransparency) {
-
- // NULL for cone defaults to Bradford, from media to D50
- cmsAdaptationMatrix(r, NULL, &Icc ->MediaWhitePoint, &Icc ->Illuminant);
+ return _cmsAdaptationMatrix(Dest, NULL, cmsD50_XYZ(), White);
}
}
@@ -1909,1850 +158,599 @@
}
-
-LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- size_t offset;
- int n;
-
-
- n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0)
- return NULL;
-
- if (Icc -> TagPtrs[n]) {
-
- return cmsDupGamma((LPGAMMATABLE) Icc -> TagPtrs[n]);
- }
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return NULL;
-
- return ReadCurve(Icc);
-
-}
-
-
-// Some ways have analytical revese. This function accounts for that
-
-LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSignature sig)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- size_t offset;
- int n;
-
-
- n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0)
- return NULL;
-
- if (Icc -> TagPtrs[n]) {
-
- return cmsReverseGamma(256, (LPGAMMATABLE) Icc -> TagPtrs[n]);
- }
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return NULL;
-
- return ReadCurveReversed(Icc);
-}
-
-// Check Named color header
-
+// Auxiliar, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper
static
-LCMSBOOL CheckHeader(LPcmsNAMEDCOLORLIST v, icNamedColor2* nc2)
-{
- if (v ->Prefix[0] == 0 && v ->Suffix[0] == 0 && v ->ColorantCount == 0) return TRUE;
-
- if (stricmp(v ->Prefix, (const char*) nc2 ->prefix) != 0) return FALSE;
- if (stricmp(v ->Suffix, (const char*) nc2 ->suffix) != 0) return FALSE;
-
- return ((int) v ->ColorantCount == (int) nc2 ->nDeviceCoords);
-}
-
-// Read named color list
-
-int cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSignature sig)
+cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile)
{
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- int n;
- icTagTypeSignature BaseType;
- size_t offset;
-
- n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0)
- return 0;
-
- if (Icc -> TagPtrs[n]) {
-
- // This replaces actual named color list.
- size_t size = Icc -> TagSizes[n];
-
- if (v ->NamedColorList) cmsFreeNamedColorList(v ->NamedColorList);
- v -> NamedColorList = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size);
- CopyMemory(v -> NamedColorList, Icc ->TagPtrs[n], size);
- return v ->NamedColorList->nColors;
- }
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return 0;
-
- BaseType = ReadBase(Icc);
-
- switch (BaseType) {
-
- // I never have seen one of these. Probably is not worth of implementing.
-
- case icSigNamedColorType: {
-
- cmsSignalError(LCMS_ERRC_WARNING, "Ancient named color profiles are not supported.");
- return 0;
- }
-
- // The named color struct
-
- case icSigNamedColor2Type: {
-
- icNamedColor2 nc2;
- unsigned int i, j;
-
- if (Icc -> Read(&nc2, sizeof(icNamedColor2) - SIZEOF_UINT8_ALIGNED, 1, Icc) != 1) return 0;
- AdjustEndianess32((LPBYTE) &nc2.vendorFlag);
- AdjustEndianess32((LPBYTE) &nc2.count);
- AdjustEndianess32((LPBYTE) &nc2.nDeviceCoords);
-
- if (!CheckHeader(v->NamedColorList, &nc2)) {
- cmsSignalError(LCMS_ERRC_WARNING, "prefix/suffix/device for named color profiles mismatch.");
- return 0;
- }
-
- if (nc2.nDeviceCoords > MAXCHANNELS) {
- cmsSignalError(LCMS_ERRC_WARNING, "Too many device coordinates.");
- return 0;
- }
-
- strncpy(v ->NamedColorList->Prefix, (const char*) nc2.prefix, 32);
- strncpy(v ->NamedColorList->Suffix, (const char*) nc2.suffix, 32);
- v ->NamedColorList->Prefix[32] = v->NamedColorList->Suffix[32] = 0;
-
- v ->NamedColorList ->ColorantCount = nc2.nDeviceCoords;
-
- for (i=0; i < nc2.count; i++) {
-
- WORD PCS[3];
- WORD Colorant[MAXCHANNELS];
- char Root[33];
-
- ZeroMemory(Colorant, sizeof(WORD) * MAXCHANNELS);
- Icc -> Read(Root, 1, 32, Icc);
- Icc -> Read(PCS, 3, sizeof(WORD), Icc);
-
- for (j=0; j < 3; j++)
- AdjustEndianess16((LPBYTE) &PCS[j]);
-
- Icc -> Read(Colorant, sizeof(WORD), nc2.nDeviceCoords, Icc);
-
- for (j=0; j < nc2.nDeviceCoords; j++)
- AdjustEndianess16((LPBYTE) &Colorant[j]);
-
- cmsAppendNamedColor(v, Root, PCS, Colorant);
- }
-
- return v ->NamedColorList->nColors;
- }
- break;
-
- default:
- cmsSignalError(LCMS_ERRC_WARNING, "Bad tag signature '%lx' found.", BaseType);
- return 0;
- }
-
- // It would never reach here
- // return 0;
-}
-
-
-
-// Read colorant tables
-
-LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagSignature sig)
-{
- icInt32Number n;
- icUInt32Number Count, i;
- size_t offset;
- icTagTypeSignature BaseType;
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- LPcmsNAMEDCOLORLIST List;
-
- n = _cmsSearchTag(Icc, sig, FALSE);
- if (n < 0)
- return NULL; // Not found
-
- if (Icc -> TagPtrs[n]) {
-
- size_t size = Icc -> TagSizes[n];
- void* v = _cmsMalloc(size);
-
- if (v == NULL) return NULL;
- CopyMemory(v, Icc -> TagPtrs[n], size);
- return (LPcmsNAMEDCOLORLIST) v;
- }
-
-
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return NULL;
-
- BaseType = ReadBase(Icc);
-
- if (BaseType != icSigColorantTableType) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Bad tag signature '%lx' found.", BaseType);
- return NULL;
- }
-
-
- if (Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc) != 1) return NULL;
- AdjustEndianess32((LPBYTE) &Count);
-
- if (Count > MAXCHANNELS) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Too many colorants '%lx'", Count);
- return NULL;
- }
+ cmsCIEXYZ *PtrRed, *PtrGreen, *PtrBlue;
- List = cmsAllocNamedColorList(Count);
- for (i=0; i < Count; i++) {
-
- if (!Icc ->Read(List->List[i].Name, 1, 32 , Icc)) goto Error;
- if (!Icc ->Read(List->List[i].PCS, sizeof(icUInt16Number), 3, Icc)) goto Error;
- AdjustEndianessArray16(List->List[i].PCS, 3);
- }
-
- return List;
-
-Error:
- cmsFreeNamedColorList(List);
- return NULL;
-
-}
-
-
-
-// Uncooked manufacturer
-
-const char* LCMSEXPORT cmsTakeManufacturer(cmsHPROFILE hProfile)
-{
-
- static char Manufacturer[LCMS_DESC_MAX] = "";
-
- Manufacturer[0] = 0;
-
- if (cmsIsTag(hProfile, icSigDeviceMfgDescTag)) {
-
- cmsReadICCTextEx(hProfile, icSigDeviceMfgDescTag, Manufacturer, LCMS_DESC_MAX);
- }
-
- return Manufacturer;
-}
-
-// Uncooked model
-
-const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile)
-{
-
- static char Model[LCMS_DESC_MAX] = "";
-
- Model[0] = 0;
-
- if (cmsIsTag(hProfile, icSigDeviceModelDescTag)) {
-
- cmsReadICCTextEx(hProfile, icSigDeviceModelDescTag, Model, LCMS_DESC_MAX);
- }
-
- return Model;
-}
-
-
-const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile)
-{
-
- static char Copyright[LCMS_DESC_MAX] = "";
-
- Copyright[0] = 0;
- if (cmsIsTag(hProfile, icSigCopyrightTag)) {
-
- cmsReadICCTextEx(hProfile, icSigCopyrightTag, Copyright, LCMS_DESC_MAX);
- }
-
- return Copyright;
-}
-
-
-// We compute name with model - manufacturer
-
-const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile)
-{
- static char Name[LCMS_DESC_MAX*2+4];
- char Manufacturer[LCMS_DESC_MAX], Model[LCMS_DESC_MAX];
-
- Name[0] = '\0';
- Manufacturer[0] = Model[0] = '\0';
-
- if (cmsIsTag(hProfile, icSigDeviceMfgDescTag)) {
-
- cmsReadICCTextEx(hProfile, icSigDeviceMfgDescTag, Manufacturer, LCMS_DESC_MAX);
- }
-
- if (cmsIsTag(hProfile, icSigDeviceModelDescTag)) {
-
- cmsReadICCTextEx(hProfile, icSigDeviceModelDescTag, Model, LCMS_DESC_MAX);
- }
-
- if (!Manufacturer[0] && !Model[0]) {
-
- if (cmsIsTag(hProfile, icSigProfileDescriptionTag)) {
-
- cmsReadICCTextEx(hProfile, icSigProfileDescriptionTag, Name, LCMS_DESC_MAX);
- return Name;
- }
- else return "{no name}";
- }
-
-
- if (!Manufacturer[0] ||
- strncmp(Model, Manufacturer, 8) == 0 || strlen(Model) > 30)
- strcpy(Name, Model);
- else
- sprintf(Name, "%s - %s", Model, Manufacturer);
-
- return Name;
-
-}
+ _cmsAssert(r != NULL);
-
-// We compute desc with manufacturer - model
-
-const char* LCMSEXPORT cmsTakeProductDesc(cmsHPROFILE hProfile)
-{
- static char Name[2048];
-
- if (cmsIsTag(hProfile, icSigProfileDescriptionTag)) {
-
- cmsReadICCText(hProfile, icSigProfileDescriptionTag, Name);
- }
- else return cmsTakeProductName(hProfile);
-
- if (strncmp(Name, "Copyrig", 7) == 0)
- return cmsTakeProductName(hProfile);
-
- return Name;
-}
-
-
-const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- static char Info[4096];
-
- Info[0] = '\0';
-
- if (cmsIsTag(hProfile, icSigProfileDescriptionTag))
- {
- char Desc[1024];
-
- cmsReadICCText(hProfile, icSigProfileDescriptionTag, Desc);
- strcat(Info, Desc);
- strcat(Info, "\r\n\r\n");
- }
-
-
- if (cmsIsTag(hProfile, icSigCopyrightTag))
- {
- char Copyright[LCMS_DESC_MAX];
-
- cmsReadICCText(hProfile, icSigCopyrightTag, Copyright);
- strcat(Info, Copyright);
- strcat(Info, "\r\n\r\n");
- }
-
-
-
-// KODAK private tag... But very useful
-
-#define K007 (icTagSignature)0x4B303037
-
- // MonCal
+ PtrRed = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigRedColorantTag);
+ PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag);
+ PtrBlue = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag);
- if (cmsIsTag(hProfile, K007))
- {
- char MonCal[LCMS_DESC_MAX];
-
- cmsReadICCText(hProfile, K007, MonCal);
- strcat(Info, MonCal);
- strcat(Info, "\r\n\r\n");
- }
- else
- {
- cmsCIEXYZ WhitePt;
- char WhiteStr[1024];
-
- cmsTakeMediaWhitePoint(&WhitePt, hProfile);
- _cmsIdentifyWhitePoint(WhiteStr, &WhitePt);
- strcat(WhiteStr, "\r\n\r\n");
- strcat(Info, WhiteStr);
- }
-
-
- if (Icc -> stream) {
- strcat(Info, Icc -> PhysicalFile);
- }
- return Info;
-}
-
-// Extract the target data as a big string. Does not signal if tag is not present.
-
-LCMSBOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- int n;
-
- *Data = NULL;
- *len = 0;
-
- n = _cmsSearchTag(Icc, icSigCharTargetTag, FALSE);
- if (n < 0) return FALSE;
-
-
- *len = Icc -> TagSizes[n];
-
- // Make sure that is reasonable (600K)
- if (*len > 600*1024) *len = 600*1024;
-
- *Data = (char*) _cmsMalloc(*len + 1); // Plus zero marker
-
- if (!*Data) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Out of memory allocating CharTarget space!");
- return FALSE;
- }
-
- if (cmsReadICCTextEx(hProfile, icSigCharTargetTag, *Data, *len) < 0)
+ if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL)
return FALSE;
- (*Data)[*len] = 0; // Force a zero marker. Shouldn't be needed, but is
- // here to simplify things.
+ _cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X, PtrBlue -> X);
+ _cmsVEC3init(&r -> v[1], PtrRed -> Y, PtrGreen -> Y, PtrBlue -> Y);
+ _cmsVEC3init(&r -> v[2], PtrRed -> Z, PtrGreen -> Z, PtrBlue -> Z);
return TRUE;
}
-
-
-LCMSBOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile)
+// Gray input pipeline
+static
+cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile)
{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- int n;
+ cmsToneCurve *GrayTRC;
+ cmsPipeline* Lut;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+
+ GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag);
+ if (GrayTRC == NULL) return NULL;
- n = _cmsSearchTag(Icc, icSigCalibrationDateTimeTag, FALSE);
- if (n < 0) return FALSE;
+ Lut = cmsPipelineAlloc(ContextID, 1, 3);
+ if (Lut == NULL) return NULL;
+
+ if (cmsGetPCS(hProfile) == cmsSigLabData) {
- if (Icc ->TagPtrs[n]) {
+ // In this case we implement the profile as an identity matrix plus 3 tone curves
+ cmsUInt16Number Zero[2] = { 0x8080, 0x8080 };
+ cmsToneCurve* EmptyTab;
+ cmsToneCurve* LabCurves[3];
- CopyMemory(Dest, Icc ->TagPtrs[n], sizeof(struct tm));
- }
- else
- {
- icDateTimeNumber timestamp;
+ EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
+
+ if (EmptyTab == NULL) {
+
+ cmsPipelineFree(Lut);
+ return NULL;
+ }
- if (Icc -> Seek(Icc, Icc -> TagOffsets[n] + sizeof(icTagBase)))
- return FALSE;
+ LabCurves[0] = GrayTRC;
+ LabCurves[1] = EmptyTab;
+ LabCurves[2] = EmptyTab;
+
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL));
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves));
- if (Icc ->Read(×tamp, 1, sizeof(icDateTimeNumber), Icc) != sizeof(icDateTimeNumber))
- return FALSE;
+ cmsFreeToneCurve(EmptyTab);
- DecodeDateTimeNumber(×tamp, Dest);
+ }
+ else {
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC));
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL));
}
-
- return TRUE;
+ return Lut;
}
-
-
-// PSEQ Tag, used in devicelink profiles
-
-LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile)
+// RGB Matrix shaper
+static
+cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile)
{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- int n;
- icUInt32Number i, Count;
- icDescStruct DescStruct;
- icTagTypeSignature BaseType;
- size_t size, offset;
- LPcmsSEQ OutSeq;
+ cmsPipeline* Lut;
+ cmsMAT3 Mat;
+ cmsToneCurve *Shapes[3];
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+ int i, j;
+
+ if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) return NULL;
+
+ // XYZ PCS in encoded in 1.15 format, and the matrix output comes in 0..0xffff range, so
+ // we need to adjust the output by a factor of (0x10000/0xffff) to put data in
+ // a 1.16 range, and then a >> 1 to obtain 1.15. The total factor is (65536.0)/(65535.0*2)
+
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ Mat.v[i].n[j] *= InpAdj;
- n = _cmsSearchTag(Icc, icSigProfileSequenceDescTag, FALSE);
- if (n < 0) return NULL;
-
- size = Icc -> TagSizes[n];
- if (size < 12) return NULL;
+ Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag);
+ Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag);
+ Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag);
- if (Icc -> TagPtrs[n]) {
+ if (!Shapes[0] || !Shapes[1] || !Shapes[2])
+ return NULL;
- OutSeq = (LPcmsSEQ) _cmsMalloc(size);
- if (OutSeq == NULL) return NULL;
- CopyMemory(OutSeq, Icc ->TagPtrs[n], size);
- return OutSeq;
+ Lut = cmsPipelineAlloc(ContextID, 3, 3);
+ if (Lut != NULL) {
+
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes));
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL));
}
- offset = Icc -> TagOffsets[n];
-
- if (Icc -> Seek(Icc, offset))
- return NULL;
-
- BaseType = ReadBase(Icc);
+ return Lut;
+}
- if (BaseType != icSigProfileSequenceDescType) return NULL;
+// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
+// is adjusted here in order to create a LUT that takes care of all those details
+cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
+{
+ cmsTagTypeSignature OriginalType;
+ cmsTagSignature tag16 = Device2PCS16[Intent];
+ cmsTagSignature tagFloat = Device2PCSFloat[Intent];
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
- Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc);
- AdjustEndianess32((LPBYTE) &Count);
+ if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
- if (Count > 1000) {
- return NULL;
+ // Floating point LUT are always V4, so no adjustment is required
+ return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+ }
+
+ // Revert to perceptual if no tag is found
+ if (!cmsIsTag(hProfile, tag16)) {
+ tag16 = Device2PCS16[0];
}
- size = sizeof(int) + Count * sizeof(cmsPSEQDESC);
- OutSeq = (LPcmsSEQ) _cmsMalloc(size);
- if (OutSeq == NULL) return NULL;
+ if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
- OutSeq ->n = Count;
+ // Check profile version and LUT type. Do the necessary adjustments if needed
- // Get structures as well
-
- for (i=0; i < Count; i++) {
+ // First read the tag
+ cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
+ if (Lut == NULL) return NULL;
- LPcmsPSEQDESC sec = &OutSeq -> seq[i];
+ // After reading it, we have now info about the original type
+ OriginalType = _cmsGetTagTrueType(hProfile, tag16);
- Icc -> Read(&DescStruct, sizeof(icDescStruct) - SIZEOF_UINT8_ALIGNED, 1, Icc);
+ // The profile owns the Lut, so we need to copy it
+ Lut = cmsPipelineDup(Lut);
- AdjustEndianess32((LPBYTE) &DescStruct.deviceMfg);
- AdjustEndianess32((LPBYTE) &DescStruct.deviceModel);
- AdjustEndianess32((LPBYTE) &DescStruct.technology);
- AdjustEndianess32((LPBYTE) &DescStruct.attributes[0]);
- AdjustEndianess32((LPBYTE) &DescStruct.attributes[1]);
+ // We need to adjust data only for Lab16 on output
+ if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
+ return Lut;
+
+ // Add a matrix for conversion V2 to V4 Lab PCS
+ cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
+ return Lut;
+ }
- sec ->attributes[0] = DescStruct.attributes[0];
- sec ->attributes[1] = DescStruct.attributes[1];
- sec ->deviceMfg = DescStruct.deviceMfg;
- sec ->deviceModel = DescStruct.deviceModel;
- sec ->technology = DescStruct.technology;
+ // Lut was not found, try to create a matrix-shaper
- if (ReadEmbeddedTextTag(Icc, size, sec ->Manufacturer, LCMS_DESC_MAX) < 0) return NULL;
- if (ReadEmbeddedTextTag(Icc, size, sec ->Model, LCMS_DESC_MAX) < 0) return NULL;
+ // Check if this is a grayscale profile.
+ if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {
+ // if so, build appropiate conversion tables.
+ // The tables are the PCS iluminant, scaled across GrayTRC
+ return BuildGrayInputMatrixPipeline(hProfile);
}
- return OutSeq;
+ // Not gray, create a normal matrix-shaper
+ return BuildRGBInputMatrixShaper(hProfile);
}
+// ---------------------------------------------------------------------------------------------------------------
-void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq)
+// Gray output pipeline.
+// XYZ -> Gray or Lab -> Gray. Since we only know the GrayTRC, we need to do some assumptions. Gray component will be
+// given by Y on XYZ PCS and by L* on Lab PCS, Both across inverse TRC curve.
+// The complete pipeline on XYZ is Matrix[3:1] -> Tone curve and in Lab Matrix[3:1] -> Tone Curve as well.
+
+static
+cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile)
{
- if (pseq)
- _cmsFree(pseq);
+ cmsToneCurve *GrayTRC, *RevGrayTRC;
+ cmsPipeline* Lut;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+
+ GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag);
+ if (GrayTRC == NULL) return NULL;
+
+ RevGrayTRC = cmsReverseToneCurve(GrayTRC);
+ if (RevGrayTRC == NULL) return NULL;
+
+ Lut = cmsPipelineAlloc(ContextID, 3, 1);
+ if (Lut == NULL) {
+ cmsFreeToneCurve(RevGrayTRC);
+ return NULL;
+ }
+
+ if (cmsGetPCS(hProfile) == cmsSigLabData) {
+
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL));
+ }
+ else {
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL));
+ }
+
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC));
+ cmsFreeToneCurve(RevGrayTRC);
+
+ return Lut;
}
+static
+cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile)
+{
+ cmsPipeline* Lut;
+ cmsToneCurve *Shapes[3], *InvShapes[3];
+ cmsMAT3 Mat, Inv;
+ int i, j;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
-// Read a few tags that are hardly required
+ if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile))
+ return NULL;
+ if (!_cmsMAT3inverse(&Mat, &Inv))
+ return NULL;
+
+ // XYZ PCS in encoded in 1.15 format, and the matrix input should come in 0..0xffff range, so
+ // we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of
+ // (0xffff/0x10000) to put data in 0..0xffff range. Total factor is (2.0*65535.0)/65536.0;
-static
-void ReadCriticalTags(LPLCMSICCPROFILE Icc)
-{
- cmsHPROFILE hProfile = (cmsHPROFILE) Icc;
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ Inv.v[i].n[j] *= OutpAdj;
+
+ Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag);
+ Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag);
+ Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag);
- if (Icc ->Version >= 0x4000000) {
+ if (!Shapes[0] || !Shapes[1] || !Shapes[2])
+ return NULL;
+
+ InvShapes[0] = cmsReverseToneCurve(Shapes[0]);
+ InvShapes[1] = cmsReverseToneCurve(Shapes[1]);
+ InvShapes[2] = cmsReverseToneCurve(Shapes[2]);
+
+ if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) {
+ return NULL;
+ }
- // v4 profiles
+ Lut = cmsPipelineAlloc(ContextID, 3, 3);
+ if (Lut != NULL) {
+
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL));
+ cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes));
+ }
- MAT3 ChrmCanonical;
+ cmsFreeToneCurveTriple(InvShapes);
+ return Lut;
+}
+
+// Create an output MPE LUT from agiven profile. Version mismatches are handled here
+cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
+{
+ cmsTagTypeSignature OriginalType;
+ cmsTagSignature tag16 = PCS2Device16[Intent];
+ cmsTagSignature tagFloat = PCS2DeviceFloat[Intent];
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
- if (ReadICCXYZ(hProfile,
- icSigMediaWhitePointTag,
- &Icc ->MediaWhitePoint, FALSE) < 0) {
+ if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
+
+ // Floating point LUT are always V4, so no adjustment is required
+ return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+ }
+
+ // Revert to perceptual if no tag is found
+ if (!cmsIsTag(hProfile, tag16)) {
+ tag16 = PCS2Device16[0];
+ }
- Icc ->MediaWhitePoint = *cmsD50_XYZ();
- }
+ if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
+
+ // Check profile version and LUT type. Do the necessary adjustments if needed
- // Read media black
+ // First read the tag
+ cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
+ if (Lut == NULL) return NULL;
+
+ // After reading it, we have info about the original type
+ OriginalType = _cmsGetTagTrueType(hProfile, tag16);
- if (ReadICCXYZ(hProfile,
- icSigMediaBlackPointTag,
- &Icc ->MediaBlackPoint, FALSE) < 0) {
+ // The profile owns the Lut, so we need to copy it
+ Lut = cmsPipelineDup(Lut);
+
+ // We need to adjust data only for Lab and Lut16 type
+ if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
+ return Lut;
+
+ // Add a matrix for conversion V4 to V2 Lab PCS
+ cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
+ return Lut;
+ }
+
+ // Lut not found, try to create a matrix-shaper
+
+ // Check if this is a grayscale profile.
+ if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {
- Icc ->MediaBlackPoint.X = 0;
- Icc ->MediaBlackPoint.Y = 0;
- Icc ->MediaBlackPoint.X = 0;
+ // if so, build appropiate conversion tables.
+ // The tables are the PCS iluminant, scaled across GrayTRC
+ return BuildGrayOutputPipeline(hProfile);
+ }
+
+ // Not gray, create a normal matrix-shaper
+ return BuildRGBOutputMatrixShaper(hProfile);
+}
+
+// ---------------------------------------------------------------------------------------------------------------
- }
+// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
+// tag name here may default to AToB0
+cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
+{
+ cmsPipeline* Lut;
+ cmsTagTypeSignature OriginalType;
+ cmsTagSignature tag16 = Device2PCS16[Intent];
+ cmsTagSignature tagFloat = Device2PCSFloat[Intent];
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+
+ if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
- NormalizeXYZ(&Icc ->MediaWhitePoint);
- NormalizeXYZ(&Icc ->MediaBlackPoint);
+ // Floating point LUT are always V4, no adjustment is required
+ return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+ }
+
+ tagFloat = Device2PCSFloat[0];
+ if (cmsIsTag(hProfile, tagFloat)) {
- if (ReadICCXYZArray(hProfile,
- icSigChromaticAdaptationTag,
- &ChrmCanonical) > 0) {
+ return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+ }
+
+ if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
+
+ tag16 = Device2PCS16[0];
+ if (!cmsIsTag(hProfile, tag16)) return NULL;
+ }
+
+ // Check profile version and LUT type. Do the necessary adjustments if needed
- MAT3inverse(&ChrmCanonical, &Icc ->ChromaticAdaptation);
+ // Read the tag
+ Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
+ if (Lut == NULL) return NULL;
+
+ // The profile owns the Lut, so we need to copy it
+ Lut = cmsPipelineDup(Lut);
+
+ // After reading it, we have info about the original type
+ OriginalType = _cmsGetTagTrueType(hProfile, tag16);
- }
- else {
+ // We need to adjust data for Lab16 on output
+ if (OriginalType != cmsSigLut16Type) return Lut;
+
+ // Here it is possible to get Lab on both sides
- MAT3identity(&Icc ->ChromaticAdaptation);
- }
+ if (cmsGetPCS(hProfile) == cmsSigLabData) {
+ cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
+ }
+
+ if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
+ cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
+ }
+
+ return Lut;
- // Convert media white, black to absolute under original illuminant
+}
- EvalCHRM(&Icc ->MediaWhitePoint, &Icc ->ChromaticAdaptation, &Icc ->MediaWhitePoint);
- EvalCHRM(&Icc ->MediaBlackPoint, &Icc ->ChromaticAdaptation, &Icc ->MediaBlackPoint);
+// ---------------------------------------------------------------------------------------------------------------
+// Returns TRUE if the profile is implemented as matrix-shaper
+cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile)
+{
+ switch (cmsGetColorSpace(hProfile)) {
- }
- else {
-
- // v2 profiles
+ case cmsSigGrayData:
- // Read media white
+ return cmsIsTag(hProfile, cmsSigGrayTRCTag);
+
+ case cmsSigRgbData:
- if (ReadICCXYZ(hProfile,
- icSigMediaWhitePointTag,
- &Icc ->MediaWhitePoint, FALSE) < 0) {
+ return (cmsIsTag(hProfile, cmsSigRedColorantTag) &&
+ cmsIsTag(hProfile, cmsSigGreenColorantTag) &&
+ cmsIsTag(hProfile, cmsSigBlueColorantTag) &&
+ cmsIsTag(hProfile, cmsSigRedTRCTag) &&
+ cmsIsTag(hProfile, cmsSigGreenTRCTag) &&
+ cmsIsTag(hProfile, cmsSigBlueTRCTag));
- Icc ->MediaWhitePoint = *cmsD50_XYZ();
- }
-
- // Read media black
+ default:
- if (ReadICCXYZ(hProfile,
- icSigMediaBlackPointTag,
- &Icc ->MediaBlackPoint, FALSE) < 0) {
+ return FALSE;
+ }
+}
- Icc ->MediaBlackPoint.X = 0;
- Icc ->MediaBlackPoint.Y = 0;
- Icc ->MediaBlackPoint.X = 0;
+// Returns TRUE if the intent is implemented as CLUT
+cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection)
+{
+ const cmsTagSignature* TagTable;
- }
-
- NormalizeXYZ(&Icc ->MediaWhitePoint);
- NormalizeXYZ(&Icc ->MediaBlackPoint);
-
+ // For devicelinks, the supported intent is that one stated in the header
+ if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {
+ return (cmsGetHeaderRenderingIntent(hProfile) == Intent);
+ }
- // Take Bradford as default for Display profiles only.
+ switch (UsedDirection) {
- if (cmsGetDeviceClass(hProfile) == icSigDisplayClass) {
-
+ case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break;
+ case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break;
- cmsAdaptationMatrix(&Icc -> ChromaticAdaptation,
- NULL,
- &Icc -> Illuminant,
- &Icc -> MediaWhitePoint);
- }
- else
- MAT3identity(&Icc ->ChromaticAdaptation);
+ // For proofing, we need rel. colorimetric in output. Let's do some recursion
+ case LCMS_USED_AS_PROOF:
+ return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) &&
+ cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT);
+ default:
+ cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_RANGE, "Unexpected direction (%d)", UsedDirection);
+ return FALSE;
}
+ return cmsIsTag(hProfile, TagTable[Intent]);
+
}
-// Create profile from disk file
-
-cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *lpFileName, const char *sAccess)
+// Return info about supported intents
+cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile,
+ cmsUInt32Number Intent, int UsedDirection)
{
- LPLCMSICCPROFILE NewIcc;
- cmsHPROFILE hEmpty;
-
-
- // Open for write means an empty profile
-
- if (*sAccess == 'W' || *sAccess == 'w') {
-
- hEmpty = _cmsCreateProfilePlaceholder();
- NewIcc = (LPLCMSICCPROFILE) (LPSTR) hEmpty;
- NewIcc -> IsWrite = TRUE;
- strncpy(NewIcc ->PhysicalFile, lpFileName, MAX_PATH-1);
- NewIcc ->PhysicalFile[MAX_PATH-1] = 0;
-
- // Save LUT as 8 bit
- sAccess++;
- if (*sAccess == '8') NewIcc ->SaveAs8Bits = TRUE;
-
- return hEmpty;
- }
-
-
- // Open for read means a file placeholder
-
- NewIcc = _cmsCreateProfileFromFilePlaceholder(lpFileName);
- if (!NewIcc) return NULL;
-
- if (!ReadHeader(NewIcc, FALSE)) return NULL;
-
- ReadCriticalTags(NewIcc);
-
- return (cmsHPROFILE) (LPSTR) NewIcc;
-}
-
-
-
-
-// Open from memory block
+ if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE;
-cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize)
-{
- LPLCMSICCPROFILE NewIcc;
-
-
- NewIcc = _cmsCreateProfileFromMemPlaceholder(MemPtr, dwSize);
- if (!NewIcc) return NULL;
-
- if (!ReadHeader(NewIcc, TRUE)) return NULL;
-
- ReadCriticalTags(NewIcc);
-
- return (cmsHPROFILE) (LPSTR) NewIcc;
-
-}
-
-
+ // Is there any matrix-shaper? If so, the intent is supported. This is a bit odd, since V2 matrix shaper
+ // does not fully support relative colorimetric because they cannot deal with non-zero black points, but
+ // many profiles claims that, and this is certainly not true for V4 profiles. Lets answer "yes" no matter
+ // the accuracy would be less than optimal in rel.col and v2 case.
-LCMSBOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- LCMSBOOL rc = TRUE;
- icInt32Number i;
-
- if (!Icc) return FALSE;
-
- // Was open in write mode?
- if (Icc ->IsWrite) {
-
- Icc ->IsWrite = FALSE; // Assure no further writting
- rc = _cmsSaveProfile(hProfile, Icc ->PhysicalFile);
- }
-
- for (i=0; i < Icc -> TagCount; i++) {
-
- if (Icc -> TagPtrs[i])
- free(Icc -> TagPtrs[i]);
- }
-
- if (Icc -> stream != NULL) { // Was a memory (i.e. not serialized) profile?
- Icc -> Close(Icc); // No, close the stream
- }
-
- free(Icc); // Free placeholder memory
-
- return rc;
+ return cmsIsMatrixShaper(hProfile);
}
-
-// Write profile ------------------------------------------------------------
-
+// ---------------------------------------------------------------------------------------------------------------
+// Read both, profile sequence description and profile sequence id if present. Then combine both to
+// create qa unique structure holding both. Shame on ICC to store things in such complicated way.
-static
-LCMSBOOL SaveWordsTable(int nEntries, LPWORD Tab, LPLCMSICCPROFILE Icc)
+cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile)
{
- size_t nTabSize = sizeof(WORD) * nEntries;
- LPWORD PtrW = (LPWORD) _cmsMalloc(nTabSize);
- LCMSBOOL rc;
+ cmsSEQ* ProfileSeq;
+ cmsSEQ* ProfileId;
+ cmsSEQ* NewSeq;
+ cmsUInt32Number i;
+
+ // Take profile sequence description first
+ ProfileSeq = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceDescTag);
+
+ // Take profile sequence ID
+ ProfileId = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceIdTag);
+
+ if (ProfileSeq == NULL && ProfileId == NULL) return NULL;
- if (!PtrW) return FALSE;
- CopyMemory(PtrW, Tab, nTabSize);
- AdjustEndianessArray16(PtrW, nEntries);
- rc = Icc ->Write(Icc, nTabSize, PtrW);
- free(PtrW);
+ if (ProfileSeq == NULL) return cmsDupProfileSequenceDescription(ProfileId);
+ if (ProfileId == NULL) return cmsDupProfileSequenceDescription(ProfileSeq);
+
+ // We have to mix both together. For that they must agree
+ if (ProfileSeq ->n != ProfileId ->n) return cmsDupProfileSequenceDescription(ProfileSeq);
+
+ NewSeq = cmsDupProfileSequenceDescription(ProfileSeq);
- return rc;
+ // Ok, proceed to the mixing
+ for (i=0; i < ProfileSeq ->n; i++) {
+
+ memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID));
+ NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description);
+ }
+
+ return NewSeq;
}
-
-
-// Saves profile header
-
-static
-LCMSBOOL SaveHeader(LPLCMSICCPROFILE Icc)
+// Dump the contents of profile sequence in both tags (if v4 available)
+cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq)
{
- icHeader Header;
- time_t now = time(NULL);
-
- Header.size = TransportValue32((icInt32Number) Icc ->UsedSpace);
- Header.cmmId = TransportValue32(lcmsSignature);
- Header.version = TransportValue32((icInt32Number) 0x02300000);
- Header.deviceClass = (icProfileClassSignature) TransportValue32(Icc -> DeviceClass);
- Header.colorSpace = (icColorSpaceSignature) TransportValue32(Icc -> ColorSpace);
- Header.pcs = (icColorSpaceSignature) TransportValue32(Icc -> PCS);
-
- // NOTE: in v4 Timestamp must be in UTC rather than in local time
- EncodeDateTimeNumber(&Header.date, gmtime(&now));
-
- Header.magic = TransportValue32(icMagicNumber);
-
-#ifdef NON_WINDOWS
- Header.platform = (icPlatformSignature)TransportValue32(icSigMacintosh);
-#else
- Header.platform = (icPlatformSignature)TransportValue32(icSigMicrosoft);
-#endif
-
- Header.flags = TransportValue32(Icc -> flags);
- Header.manufacturer = TransportValue32(lcmsSignature);
- Header.model = TransportValue32(0);
- Header.attributes[0]= TransportValue32(Icc -> attributes);
- Header.attributes[1]= TransportValue32(0);
-
- Header.renderingIntent = TransportValue32(Icc -> RenderingIntent);
-
- // Illuminant is D50
-
- Header.illuminant.X = TransportValue32(DOUBLE_TO_FIXED(Icc -> Illuminant.X));
- Header.illuminant.Y = TransportValue32(DOUBLE_TO_FIXED(Icc -> Illuminant.Y));
- Header.illuminant.Z = TransportValue32(DOUBLE_TO_FIXED(Icc -> Illuminant.Z));
-
- Header.creator = TransportValue32(lcmsSignature);
-
- ZeroMemory(&Header.reserved, sizeof(Header.reserved));
-
- // Set profile ID
- CopyMemory(Header.reserved, Icc ->ProfileID, 16);
-
-
- Icc ->UsedSpace = 0; // Mark as begin-of-file
+ if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE;
- return Icc ->Write(Icc, sizeof(icHeader), &Header);
-}
-
-
-
-// Setup base marker
-
-static
-LCMSBOOL SetupBase(icTagTypeSignature sig, LPLCMSICCPROFILE Icc)
-{
- icTagBase Base;
-
- Base.sig = (icTagTypeSignature) TransportValue32(sig);
- ZeroMemory(&Base.reserved, sizeof(Base.reserved));
- return Icc -> Write(Icc, sizeof(icTagBase), &Base);
-}
-
-
-// Store a XYZ tag
-
-static
-LCMSBOOL SaveXYZNumber(LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc)
-{
-
- icXYZNumber XYZ;
-
- if (!SetupBase(icSigXYZType, Icc)) return FALSE;
+ if (cmsGetProfileVersion(hProfile) >= 4.0) {
- XYZ.X = TransportValue32(DOUBLE_TO_FIXED(Value -> X));
- XYZ.Y = TransportValue32(DOUBLE_TO_FIXED(Value -> Y));
- XYZ.Z = TransportValue32(DOUBLE_TO_FIXED(Value -> Z));
-
-
- return Icc -> Write(Icc, sizeof(icXYZNumber), &XYZ);
-}
-
-
-// Store a XYZ array.
-
-static
-LCMSBOOL SaveXYZArray(int n, LPcmsCIEXYZ Value, LPLCMSICCPROFILE Icc)
-{
- int i;
- icXYZNumber XYZ;
-
- if (!SetupBase(icSigS15Fixed16ArrayType, Icc)) return FALSE;
-
- for (i=0; i < n; i++) {
-
- XYZ.X = TransportValue32(DOUBLE_TO_FIXED(Value -> X));
- XYZ.Y = TransportValue32(DOUBLE_TO_FIXED(Value -> Y));
- XYZ.Z = TransportValue32(DOUBLE_TO_FIXED(Value -> Z));
-
- if (!Icc -> Write(Icc, sizeof(icXYZNumber), &XYZ)) return FALSE;
-
- Value++;
+ if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE;
}
return TRUE;
}
-
-// Save a gamma structure as a table
-
+// Auxiliar, read and duplicate a MLU if found.
static
-LCMSBOOL SaveGammaTable(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc)
-{
- icInt32Number Count;
-
- if (!SetupBase(icSigCurveType, Icc)) return FALSE;
-
- Count = TransportValue32(Gamma->nEntries);
-
- if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE;
-
- return SaveWordsTable(Gamma->nEntries, Gamma ->GammaTable, Icc);
-}
-
-
-// Save a gamma structure as a one-value
-
-static
-LCMSBOOL SaveGammaOneValue(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc)
+cmsMLU* GetMLUFromProfile(cmsHPROFILE h, cmsTagSignature sig)
{
- icInt32Number Count;
- Fixed32 GammaFixed32;
- WORD GammaFixed8;
-
- if (!SetupBase(icSigCurveType, Icc)) return FALSE;
-
- Count = TransportValue32(1);
- if (!Icc ->Write(Icc, sizeof(icInt32Number), &Count)) return FALSE;
-
- GammaFixed32 = DOUBLE_TO_FIXED(Gamma ->Seed.Params[0]);
- GammaFixed8 = (WORD) ((GammaFixed32 >> 8) & 0xFFFF);
- GammaFixed8 = TransportValue16(GammaFixed8);
-
- return Icc ->Write(Icc, sizeof(icInt16Number), &GammaFixed8);
-}
-
-// Save a gamma structure as a parametric gamma
-
-static
-LCMSBOOL SaveGammaParametric(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc)
-{
- icUInt16Number Type, Reserved;
- int i, nParams;
- int ParamsByType[] = { 1, 3, 4, 5, 7 };
+ cmsMLU* mlu = (cmsMLU*) cmsReadTag(h, sig);
+ if (mlu == NULL) return NULL;
- if (!SetupBase(icSigParametricCurveType, Icc)) return FALSE;
-
- nParams = ParamsByType[Gamma -> Seed.Type];
-
- Type = (icUInt16Number) TransportValue16((WORD) Gamma -> Seed. Type);
- Reserved = (icUInt16Number) TransportValue16((WORD) 0);
-
- Icc -> Write(Icc, sizeof(icInt16Number), &Type);
- Icc -> Write(Icc, sizeof(icUInt16Number), &Reserved);
-
- for (i=0; i < nParams; i++) {
-
- icInt32Number val = TransportValue32(DOUBLE_TO_FIXED(Gamma -> Seed.Params[i]));
- Icc ->Write(Icc, sizeof(icInt32Number), &val);
- }
-
-
- return TRUE;
-
-}
-
-
-// Save a gamma table
-
-static
-LCMSBOOL SaveGamma(LPGAMMATABLE Gamma, LPLCMSICCPROFILE Icc)
-{
- // Is the gamma curve type supported by ICC format?
-
- if (Gamma -> Seed.Type < 0 || Gamma -> Seed.Type > 5 ||
-
- // has been modified by user?
-
- _cmsCrc32OfGammaTable(Gamma) != Gamma -> Seed.Crc32) {
-
- return SaveGammaTable(Gamma, Icc);
- }
-
- if (Gamma -> Seed.Type == 1) return SaveGammaOneValue(Gamma, Icc);
-
- // Only v4 profiles are allowed to hold parametric curves
-
- if (cmsGetProfileICCversion((cmsHPROFILE) Icc) >= 0x4000000)
- return SaveGammaParametric(Gamma, Icc);
-
- // Defaults to save as table
-
- return SaveGammaTable(Gamma, Icc);
-
+ return cmsMLUdup(mlu);
}
-
-
-
-// Save an DESC Tag
-
-static
-LCMSBOOL SaveDescription(const char *Text, LPLCMSICCPROFILE Icc)
+// Create a sequence description out of an array of profiles
+cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[])
{
+ cmsUInt32Number i;
+ cmsSEQ* seq = cmsAllocProfileSequenceDescription(ContextID, nProfiles);
- icUInt32Number len, Count, TotalSize, AlignedSize;
- char Filler[256];
+ if (seq == NULL) return NULL;
- len = (icUInt32Number) (strlen(Text) + 1);
+ for (i=0; i < nProfiles; i++) {
- // * icInt8Number desc[count] * NULL terminated ascii string
- // * icUInt32Number ucLangCode; * UniCode language code
- // * icUInt32Number ucCount; * UniCode description length
- // * icInt16Number ucDesc[ucCount];* The UniCode description
- // * icUInt16Number scCode; * ScriptCode code
- // * icUInt8Number scCount; * ScriptCode count
- // * icInt8Number scDesc[67]; * ScriptCode Description
+ cmsPSEQDESC* ps = &seq ->seq[i];
+ cmsHPROFILE h = hProfiles[i];
+ cmsTechnologySignature* techpt;
- TotalSize = sizeof(icTagBase) + sizeof(icUInt32Number) + len +
- sizeof(icUInt32Number) + sizeof(icUInt32Number) +
- sizeof(icUInt16Number) + sizeof(icUInt8Number) + 67;
-
- AlignedSize = TotalSize; // Can be unaligned!!
-
- if (!SetupBase(icSigTextDescriptionType, Icc)) return FALSE;
- AlignedSize -= sizeof(icTagBase);
-
- Count = TransportValue32(len);
- if (!Icc ->Write(Icc, sizeof(icUInt32Number), &Count)) return FALSE;
- AlignedSize -= sizeof(icUInt32Number);
+ cmsGetHeaderAttributes(h, &ps ->attributes);
+ cmsGetHeaderProfileID(h, ps ->ProfileID.ID8);
+ ps ->deviceMfg = cmsGetHeaderManufacturer(h);
+ ps ->deviceModel = cmsGetHeaderModel(h);
- if (!Icc ->Write(Icc, len, (LPVOID)Text)) return FALSE;
- AlignedSize -= len;
+ techpt = (cmsTechnologySignature*) cmsReadTag(h, cmsSigTechnologyTag);
+ if (techpt == NULL)
+ ps ->technology = (cmsTechnologySignature) 0;
+ else
+ ps ->technology = *techpt;
- if (AlignedSize < 0)
- AlignedSize = 0;
- if (AlignedSize > 255)
- AlignedSize = 255;
+ ps ->Manufacturer = GetMLUFromProfile(h, cmsSigDeviceMfgDescTag);
+ ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag);
+ ps ->Description = GetMLUFromProfile(h, cmsSigProfileDescriptionTag);
- ZeroMemory(Filler, AlignedSize);
- if (!Icc ->Write(Icc, AlignedSize, Filler)) return FALSE;
+ }
- return TRUE;
+ return seq;
}
-// Save an ASCII Tag
-
-static
-LCMSBOOL SaveText(const char *Text, LPLCMSICCPROFILE Icc)
-{
- size_t len = strlen(Text) + 1;
-
- if (!SetupBase(icSigTextType, Icc)) return FALSE;
- if (!Icc ->Write(Icc, len, (LPVOID) Text)) return FALSE;
- return TRUE;
-}
-
-
-// Save one of these new chromaticity values
-
-static
-LCMSBOOL SaveOneChromaticity(double x, double y, LPLCMSICCPROFILE Icc)
-{
- Fixed32 xf, yf;
-
- xf = TransportValue32(DOUBLE_TO_FIXED(x));
- yf = TransportValue32(DOUBLE_TO_FIXED(y));
-
- if (!Icc ->Write(Icc, sizeof(Fixed32), &xf)) return FALSE;
- if (!Icc ->Write(Icc, sizeof(Fixed32), &yf)) return FALSE;
-
- return TRUE;
-}
-
-
-// New tag added in Addendum II of old spec.
-
-static
-LCMSBOOL SaveChromaticities(LPcmsCIExyYTRIPLE chrm, LPLCMSICCPROFILE Icc)
-{
- WORD nChans, Table;
-
- if (!SetupBase(icSigChromaticityType, Icc)) return FALSE;
-
- nChans = TransportValue16(3);
- if (!Icc ->Write(Icc, sizeof(WORD) , &nChans)) return FALSE;
- Table = TransportValue16(0);
- if (!Icc ->Write(Icc, sizeof(WORD) , &Table)) return FALSE;
-
- if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, Icc)) return FALSE;
- if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, Icc)) return FALSE;
- if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, Icc)) return FALSE;
-
- return TRUE;
-}
+// -------------------------------------------------------------------------------------------------------------------
static
-LCMSBOOL SaveSequenceDescriptionTag(LPcmsSEQ seq, LPLCMSICCPROFILE Icc)
+const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info)
{
- icUInt32Number nSeqs;
- icDescStruct DescStruct;
- int i, n = seq ->n;
- LPcmsPSEQDESC pseq = seq ->seq;
-
- if (!SetupBase(icSigProfileSequenceDescType, Icc)) return FALSE;
-
- nSeqs = TransportValue32(n);
-
- if (!Icc ->Write(Icc, sizeof(icUInt32Number) , &nSeqs)) return FALSE;
-
- for (i=0; i < n; i++) {
-
- LPcmsPSEQDESC sec = pseq + i;
-
-
- DescStruct.deviceMfg = (icTagTypeSignature) TransportValue32(sec ->deviceMfg);
- DescStruct.deviceModel = (icTagTypeSignature) TransportValue32(sec ->deviceModel);
- DescStruct.technology = (icTechnologySignature) TransportValue32(sec ->technology);
- DescStruct.attributes[0]= TransportValue32(sec ->attributes[0]);
- DescStruct.attributes[1]= TransportValue32(sec ->attributes[1]);
+ cmsTagSignature sig;
- if (!Icc ->Write(Icc, sizeof(icDescStruct) - SIZEOF_UINT8_ALIGNED, &DescStruct)) return FALSE;
-
- if (!SaveDescription(sec ->Manufacturer, Icc)) return FALSE;
- if (!SaveDescription(sec ->Model, Icc)) return FALSE;
- }
-
- return TRUE;
-}
-
-
-// Saves a timestamp tag
+ switch (Info) {
-static
-LCMSBOOL SaveDateTimeNumber(const struct tm *DateTime, LPLCMSICCPROFILE Icc)
-{
- icDateTimeNumber Dest;
-
- if (!SetupBase(icSigDateTimeType, Icc)) return FALSE;
- EncodeDateTimeNumber(&Dest, DateTime);
- if (!Icc ->Write(Icc, sizeof(icDateTimeNumber), &Dest)) return FALSE;
-
- return TRUE;
-}
-
+ case cmsInfoDescription:
+ sig = cmsSigProfileDescriptionTag;
+ break;
-// Saves a named color list into a named color profile
-static
-LCMSBOOL SaveNamedColorList(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc)
-{
-
- icUInt32Number vendorFlag; // Bottom 16 bits for IC use
- icUInt32Number count; // Count of named colors
- icUInt32Number nDeviceCoords; // Num of device coordinates
- char prefix[32]; // Prefix for each color name
- char suffix[32]; // Suffix for each color name
- int i;
-
- if (!SetupBase(icSigNamedColor2Type, Icc)) return FALSE;
-
- vendorFlag = TransportValue32(0);
- count = TransportValue32(NamedColorList ->nColors);
- nDeviceCoords = TransportValue32(NamedColorList ->ColorantCount);
-
- strncpy(prefix, (const char*) NamedColorList->Prefix, 31);
- strncpy(suffix, (const char*) NamedColorList->Suffix, 31);
-
- suffix[31] = prefix[31] = 0;
+ case cmsInfoManufacturer:
+ sig = cmsSigDeviceMfgDescTag;
+ break;
- if (!Icc ->Write(Icc, sizeof(icUInt32Number), &vendorFlag)) return FALSE;
- if (!Icc ->Write(Icc, sizeof(icUInt32Number), &count)) return FALSE;
- if (!Icc ->Write(Icc, sizeof(icUInt32Number), &nDeviceCoords)) return FALSE;
- if (!Icc ->Write(Icc, 32 , prefix)) return FALSE;
- if (!Icc ->Write(Icc, 32 , suffix)) return FALSE;
-
- for (i=0; i < NamedColorList ->nColors; i++) {
-
- icUInt16Number PCS[3];
- icUInt16Number Colorant[MAXCHANNELS];
- char root[32];
- LPcmsNAMEDCOLOR Color;
- int j;
-
- Color = NamedColorList ->List + i;
+ case cmsInfoModel:
+ sig = cmsSigDeviceModelDescTag;
+ break;
- strncpy(root, Color ->Name, 32);
- Color ->Name[32] = 0;
-
- if (!Icc ->Write(Icc, 32 , root)) return FALSE;
-
- for (j=0; j < 3; j++)
- PCS[j] = TransportValue16(Color ->PCS[j]);
+ case cmsInfoCopyright:
+ sig = cmsSigCopyrightTag;
+ break;
- if (!Icc ->Write(Icc, 3 * sizeof(icUInt16Number), PCS)) return FALSE;
-
- for (j=0; j < NamedColorList ->ColorantCount; j++)
- Colorant[j] = TransportValue16(Color ->DeviceColorant[j]);
-
- if (!Icc ->Write(Icc,
- NamedColorList ->ColorantCount * sizeof(icUInt16Number), Colorant)) return FALSE;
+ default: return NULL;
}
- return TRUE;
-}
-
-
-
-// Saves a colorant table. It is using the named color structure for simplicity sake
-
-static
-LCMSBOOL SaveColorantTable(LPcmsNAMEDCOLORLIST NamedColorList, LPLCMSICCPROFILE Icc)
-{
- icUInt32Number count; // Count of named colors
- int i;
-
- if (!SetupBase(icSigColorantTableType, Icc)) return FALSE;
-
- count = TransportValue32(NamedColorList ->nColors);
-
- if (!Icc ->Write(Icc, sizeof(icUInt32Number), &count)) return FALSE;
-
- for (i=0; i < NamedColorList ->nColors; i++) {
-
- icUInt16Number PCS[3];
- icInt8Number root[33];
- LPcmsNAMEDCOLOR Color;
- int j;
-
- Color = NamedColorList ->List + i;
-
- strncpy((char*) root, Color ->Name, 32);
- root[32] = 0;
-
- if (!Icc ->Write(Icc, 32 , root)) return FALSE;
-
- for (j=0; j < 3; j++)
- PCS[j] = TransportValue16(Color ->PCS[j]);
-
- if (!Icc ->Write(Icc, 3 * sizeof(icUInt16Number), PCS)) return FALSE;
-
- }
-
-
- return TRUE;
-}
-
-// Does serialization of LUT16 and writes it.
-
-static
-LCMSBOOL SaveLUT(const LUT* NewLUT, LPLCMSICCPROFILE Icc)
-{
- icLut16 LUT16;
- unsigned int i;
- size_t nTabSize;
- WORD NullTbl[2] = { 0, 0xFFFFU};
-
-
- if (!SetupBase(icSigLut16Type, Icc)) return FALSE;
-
- LUT16.clutPoints = (icUInt8Number) NewLUT -> cLutPoints;
- LUT16.inputChan = (icUInt8Number) NewLUT -> InputChan;
- LUT16.outputChan = (icUInt8Number) NewLUT -> OutputChan;
-
- LUT16.inputEnt = TransportValue16((WORD) ((NewLUT -> wFlags & LUT_HASTL1) ? NewLUT -> InputEntries : 2));
- LUT16.outputEnt = TransportValue16((WORD) ((NewLUT -> wFlags & LUT_HASTL2) ? NewLUT -> OutputEntries : 2));
-
- if (NewLUT -> wFlags & LUT_HASMATRIX) {
-
- LUT16.e00 = TransportValue32(NewLUT -> Matrix.v[0].n[0]);
- LUT16.e01 = TransportValue32(NewLUT -> Matrix.v[0].n[1]);
- LUT16.e02 = TransportValue32(NewLUT -> Matrix.v[0].n[2]);
- LUT16.e10 = TransportValue32(NewLUT -> Matrix.v[1].n[0]);
- LUT16.e11 = TransportValue32(NewLUT -> Matrix.v[1].n[1]);
- LUT16.e12 = TransportValue32(NewLUT -> Matrix.v[1].n[2]);
- LUT16.e20 = TransportValue32(NewLUT -> Matrix.v[2].n[0]);
- LUT16.e21 = TransportValue32(NewLUT -> Matrix.v[2].n[1]);
- LUT16.e22 = TransportValue32(NewLUT -> Matrix.v[2].n[2]);
- }
- else {
-
- LUT16.e00 = TransportValue32(DOUBLE_TO_FIXED(1));
- LUT16.e01 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT16.e02 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT16.e10 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT16.e11 = TransportValue32(DOUBLE_TO_FIXED(1));
- LUT16.e12 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT16.e20 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT16.e21 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT16.e22 = TransportValue32(DOUBLE_TO_FIXED(1));
- }
-
-
- // Save header
-
- Icc -> Write(Icc, sizeof(icLut16)- SIZEOF_UINT16_ALIGNED, &LUT16);
-
- // The prelinearization table
-
- for (i=0; i < NewLUT -> InputChan; i++) {
-
- if (NewLUT -> wFlags & LUT_HASTL1) {
-
- if (!SaveWordsTable(NewLUT -> InputEntries,
- NewLUT -> L1[i], Icc)) return FALSE;
-
- }
- else Icc -> Write(Icc, sizeof(WORD)* 2, NullTbl);
- }
-
-
- nTabSize = (NewLUT -> OutputChan * uipow(NewLUT->cLutPoints,
- NewLUT->InputChan));
- // The 3D CLUT.
-
- if (nTabSize > 0) {
-
- if (!SaveWordsTable((int) nTabSize, NewLUT -> T, Icc)) return FALSE;
- }
- // The postlinearization table
-
- for (i=0; i < NewLUT -> OutputChan; i++) {
-
- if (NewLUT -> wFlags & LUT_HASTL2) {
-
- if (!SaveWordsTable(NewLUT -> OutputEntries,
- NewLUT -> L2[i], Icc)) return FALSE;
- }
- else Icc -> Write(Icc, sizeof(WORD)* 2, NullTbl);
-
- }
-
- return TRUE;
+ return (cmsMLU*) cmsReadTag(hProfile, sig);
}
-// Does serialization of LUT8 and writes it
-
-static
-LCMSBOOL SaveLUT8(const LUT* NewLUT, LPLCMSICCPROFILE Icc)
+cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info,
+ const char LanguageCode[3], const char CountryCode[3],
+ wchar_t* Buffer, cmsUInt32Number BufferSize)
{
- icLut8 LUT8;
- unsigned int i, j;
- size_t nTabSize;
- BYTE val;
-
- // Sanity check
-
- if (NewLUT -> wFlags & LUT_HASTL1) {
-
- if (NewLUT -> InputEntries != 256) {
- cmsSignalError(LCMS_ERRC_ABORTED, "LUT8 needs 256 entries on prelinearization");
- return FALSE;
- }
-
- }
-
-
- if (NewLUT -> wFlags & LUT_HASTL2) {
-
- if (NewLUT -> OutputEntries != 256) {
- cmsSignalError(LCMS_ERRC_ABORTED, "LUT8 needs 256 entries on postlinearization");
- return FALSE;
- }
- }
-
-
-
- if (!SetupBase(icSigLut8Type, Icc)) return FALSE;
-
- LUT8.clutPoints = (icUInt8Number) NewLUT -> cLutPoints;
- LUT8.inputChan = (icUInt8Number) NewLUT -> InputChan;
- LUT8.outputChan = (icUInt8Number) NewLUT -> OutputChan;
-
-
- if (NewLUT -> wFlags & LUT_HASMATRIX) {
-
- LUT8.e00 = TransportValue32(NewLUT -> Matrix.v[0].n[0]);
- LUT8.e01 = TransportValue32(NewLUT -> Matrix.v[0].n[1]);
- LUT8.e02 = TransportValue32(NewLUT -> Matrix.v[0].n[2]);
- LUT8.e10 = TransportValue32(NewLUT -> Matrix.v[1].n[0]);
- LUT8.e11 = TransportValue32(NewLUT -> Matrix.v[1].n[1]);
- LUT8.e12 = TransportValue32(NewLUT -> Matrix.v[1].n[2]);
- LUT8.e20 = TransportValue32(NewLUT -> Matrix.v[2].n[0]);
- LUT8.e21 = TransportValue32(NewLUT -> Matrix.v[2].n[1]);
- LUT8.e22 = TransportValue32(NewLUT -> Matrix.v[2].n[2]);
- }
- else {
-
- LUT8.e00 = TransportValue32(DOUBLE_TO_FIXED(1));
- LUT8.e01 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT8.e02 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT8.e10 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT8.e11 = TransportValue32(DOUBLE_TO_FIXED(1));
- LUT8.e12 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT8.e20 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT8.e21 = TransportValue32(DOUBLE_TO_FIXED(0));
- LUT8.e22 = TransportValue32(DOUBLE_TO_FIXED(1));
- }
-
-
- // Save header
-
- Icc -> Write(Icc, sizeof(icLut8)- SIZEOF_UINT8_ALIGNED, &LUT8);
-
- // The prelinearization table
-
- for (i=0; i < NewLUT -> InputChan; i++) {
-
- for (j=0; j < 256; j++) {
-
- if (NewLUT -> wFlags & LUT_HASTL1)
- val = (BYTE) floor(NewLUT ->L1[i][j] / 257.0 + .5);
- else
- val = (BYTE) j;
+ const cmsMLU* mlu = GetInfo(hProfile, Info);
+ if (mlu == NULL) return 0;
- Icc ->Write(Icc, 1, &val);
- }
-
- }
-
-
- nTabSize = (NewLUT -> OutputChan * uipow(NewLUT->cLutPoints,
- NewLUT->InputChan));
- // The 3D CLUT.
-
- for (j=0; j < nTabSize; j++) {
-
- val = (BYTE) floor(NewLUT ->T[j] / 257.0 + .5);
- Icc ->Write(Icc, 1, &val);
- }
-
- // The postlinearization table
-
- for (i=0; i < NewLUT -> OutputChan; i++) {
-
- for (j=0; j < 256; j++) {
-
- if (NewLUT -> wFlags & LUT_HASTL2)
- val = (BYTE) floor(NewLUT ->L2[i][j] / 257.0 + .5);
- else
- val = (BYTE) j;
-
- Icc ->Write(Icc, 1, &val);
- }
-
- }
-
- return TRUE;
-}
-
-
-
-// Set the LUT bitdepth to be saved
-
-void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
-
- switch (depth) {
-
- case 8: Icc ->SaveAs8Bits = TRUE; break;
- case 16: Icc ->SaveAs8Bits = FALSE; break;
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "%d is an unsupported as bitdepth, use 8 or 16 only.", depth);
- }
-}
-
-
-// Saves Tag directory
-
-static
-LCMSBOOL SaveTagDirectory(LPLCMSICCPROFILE Icc)
-{
- icInt32Number i;
- icTag Tag;
- icInt32Number Count = 0;
-
- // Get true count
- for (i=0; i < Icc -> TagCount; i++) {
- if (Icc ->TagNames[i] != 0)
- Count++;
- }
-
- Count = TransportValue32(Count);
- if (!Icc ->Write(Icc, sizeof(icInt32Number) , &Count)) return FALSE;
-
- for (i=0; i < Icc -> TagCount; i++) {
-
- if (Icc ->TagNames[i] == 0) continue;
-
- Tag.sig = (icTagSignature)TransportValue32(Icc -> TagNames[i]);
- Tag.offset = TransportValue32((icInt32Number) Icc -> TagOffsets[i]);
- Tag.size = TransportValue32((icInt32Number) Icc -> TagSizes[i]);
-
- if (!Icc ->Write(Icc, sizeof(icTag), &Tag)) return FALSE;
- }
-
- return TRUE;
+ return cmsMLUgetWide(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
}
-// Dump tag contents
-
-static
-LCMSBOOL SaveTags(LPLCMSICCPROFILE Icc, LPLCMSICCPROFILE FileOrig)
+cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info,
+ const char LanguageCode[3], const char CountryCode[3],
+ char* Buffer, cmsUInt32Number BufferSize)
{
-
- LPBYTE Data;
- icInt32Number i;
- size_t Begin;
- size_t AlignedSpace, FillerSize;
-
-
- for (i=0; i < Icc -> TagCount; i++) {
-
- if (Icc ->TagNames[i] == 0) continue;
-
- // Align to DWORD boundary, following new spec.
-
- AlignedSpace = ALIGNLONG(Icc ->UsedSpace);
- FillerSize = AlignedSpace - Icc ->UsedSpace;
- if (FillerSize > 0) {
-
- BYTE Filler[20];
-
- ZeroMemory(Filler, 16);
- if (!Icc ->Write(Icc, FillerSize, Filler)) return FALSE;
- }
-
-
- Icc -> TagOffsets[i] = Begin = Icc ->UsedSpace;
- Data = (LPBYTE) Icc -> TagPtrs[i];
- if (!Data) {
-
- // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user.
- // In this case a blind copy of the block data is performed
-
- if (Icc -> TagOffsets[i]) {
-
- size_t TagSize = FileOrig -> TagSizes[i];
- size_t TagOffset = FileOrig -> TagOffsets[i];
- void* Mem;
-
- if (FileOrig ->Seek(FileOrig, TagOffset)) return FALSE;
-
- Mem = _cmsMalloc(TagSize);
-
- if (FileOrig ->Read(Mem, TagSize, 1, FileOrig) != 1) return FALSE;
- if (!Icc ->Write(Icc, TagSize, Mem)) return FALSE;
-
- Icc -> TagSizes[i] = (Icc ->UsedSpace - Begin);
- free(Mem);
- }
-
- continue;
- }
-
-
- switch (Icc -> TagNames[i]) {
-
- case icSigProfileDescriptionTag:
- case icSigDeviceMfgDescTag:
- case icSigDeviceModelDescTag:
- if (!SaveDescription((const char *) Data, Icc)) return FALSE;
- break;
-
- case icSigRedColorantTag:
- case icSigGreenColorantTag:
- case icSigBlueColorantTag:
- case icSigMediaWhitePointTag:
- case icSigMediaBlackPointTag:
- if (!SaveXYZNumber((LPcmsCIEXYZ) Data, Icc)) return FALSE;
- break;
-
-
- case icSigRedTRCTag:
- case icSigGreenTRCTag:
- case icSigBlueTRCTag:
- case icSigGrayTRCTag:
- if (!SaveGamma((LPGAMMATABLE) Data, Icc)) return FALSE;
- break;
-
- case icSigCharTargetTag:
- case icSigCopyrightTag:
- if (!SaveText((const char *) Data, Icc)) return FALSE;
- break;
-
- case icSigChromaticityTag:
- if (!SaveChromaticities((LPcmsCIExyYTRIPLE) Data, Icc)) return FALSE;
- break;
-
- // Save LUT
-
- case icSigAToB0Tag:
- case icSigAToB1Tag:
- case icSigAToB2Tag:
- case icSigBToA0Tag:
- case icSigBToA1Tag:
- case icSigBToA2Tag:
- case icSigGamutTag:
- case icSigPreview0Tag:
- case icSigPreview1Tag:
- case icSigPreview2Tag:
-
- if (Icc ->SaveAs8Bits) {
-
- if (!SaveLUT8((LPLUT) Data, Icc)) return FALSE;
- }
- else {
-
- if (!SaveLUT((LPLUT) Data, Icc)) return FALSE;
- }
- break;
-
- case icSigProfileSequenceDescTag:
- if (!SaveSequenceDescriptionTag((LPcmsSEQ) Data, Icc)) return FALSE;
- break;
-
-
- case icSigNamedColor2Tag:
- if (!SaveNamedColorList((LPcmsNAMEDCOLORLIST) Data, Icc)) return FALSE;
- break;
-
-
- case icSigCalibrationDateTimeTag:
- if (!SaveDateTimeNumber((struct tm *) Data, Icc)) return FALSE;
- break;
-
-
- case icSigColorantTableTag:
- case icSigColorantTableOutTag:
- if (!SaveColorantTable((LPcmsNAMEDCOLORLIST) Data, Icc)) return FALSE;
- break;
-
-
- case icSigChromaticAdaptationTag:
- if (!SaveXYZArray(3, (LPcmsCIEXYZ) Data, Icc)) return FALSE;
- break;
-
- default:
- return FALSE;
- }
-
- Icc -> TagSizes[i] = (Icc ->UsedSpace - Begin);
- }
-
-
-
- return TRUE;
-}
-
-
-
-// Add tags to profile structure
-
-LCMSBOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* Tag)
-{
- LCMSBOOL rc;
-
- switch (sig) {
-
- case icSigCharTargetTag:
- case icSigCopyrightTag:
- case icSigProfileDescriptionTag:
- case icSigDeviceMfgDescTag:
- case icSigDeviceModelDescTag:
- rc = _cmsAddTextTag(hProfile, sig, (const char*) Tag);
- break;
+ const cmsMLU* mlu = GetInfo(hProfile, Info);
+ if (mlu == NULL) return 0;
- case icSigRedColorantTag:
- case icSigGreenColorantTag:
- case icSigBlueColorantTag:
- case icSigMediaWhitePointTag:
- case icSigMediaBlackPointTag:
- rc = _cmsAddXYZTag(hProfile, sig, (const cmsCIEXYZ*) Tag);
- break;
-
- case icSigRedTRCTag:
- case icSigGreenTRCTag:
- case icSigBlueTRCTag:
- case icSigGrayTRCTag:
- rc = _cmsAddGammaTag(hProfile, sig, (LPGAMMATABLE) Tag);
- break;
-
- case icSigAToB0Tag:
- case icSigAToB1Tag:
- case icSigAToB2Tag:
- case icSigBToA0Tag:
- case icSigBToA1Tag:
- case icSigBToA2Tag:
- case icSigGamutTag:
- case icSigPreview0Tag:
- case icSigPreview1Tag:
- case icSigPreview2Tag:
- rc = _cmsAddLUTTag(hProfile, sig, Tag);
- break;
-
- case icSigChromaticityTag:
- rc = _cmsAddChromaticityTag(hProfile, sig, (LPcmsCIExyYTRIPLE) Tag);
- break;
-
- case icSigProfileSequenceDescTag:
- rc = _cmsAddSequenceDescriptionTag(hProfile, sig, (LPcmsSEQ) Tag);
- break;
-
- case icSigNamedColor2Tag:
- rc = _cmsAddNamedColorTag(hProfile, sig, (LPcmsNAMEDCOLORLIST) Tag);
- break;
-
- case icSigCalibrationDateTimeTag:
- rc = _cmsAddDateTimeTag(hProfile, sig, (struct tm*) Tag);
- break;
-
- case icSigColorantTableTag:
- case icSigColorantTableOutTag:
- rc = _cmsAddColorantTableTag(hProfile, sig, (LPcmsNAMEDCOLORLIST) Tag);
- break;
-
-
- case icSigChromaticAdaptationTag:
- rc = _cmsAddChromaticAdaptationTag(hProfile, sig, (const cmsCIEXYZ*) Tag);
- break;
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsAddTag: Tag '%x' is unsupported", sig);
- return FALSE;
- }
-
- // Check for critical tags
-
- switch (sig) {
-
- case icSigMediaWhitePointTag:
- case icSigMediaBlackPointTag:
- case icSigChromaticAdaptationTag:
-
- ReadCriticalTags((LPLCMSICCPROFILE) hProfile);
- break;
-
- default:;
- }
-
- return rc;
-
+ return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
}
-
-// Low-level save to disk. It closes the profile on exit
-
-LCMSBOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- LCMSICCPROFILE Keep;
- LCMSBOOL rc;
-
- CopyMemory(&Keep, Icc, sizeof(LCMSICCPROFILE));
- _cmsSetSaveToDisk(Icc, NULL);
-
- // Pass #1 does compute offsets
-
- if (!SaveHeader(Icc)) return FALSE;
- if (!SaveTagDirectory(Icc)) return FALSE;
- if (!SaveTags(Icc, &Keep)) return FALSE;
-
-
- _cmsSetSaveToDisk(Icc, FileName);
-
-
- // Pass #2 does save to file
-
- if (!SaveHeader(Icc)) goto CleanUp;
- if (!SaveTagDirectory(Icc)) goto CleanUp;
- if (!SaveTags(Icc, &Keep)) goto CleanUp;
-
- rc = (Icc ->Close(Icc) == 0);
- CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE));
- return rc;
-
-
- CleanUp:
-
- Icc ->Close(Icc);
- unlink(FileName);
- CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE));
- return FALSE;
-}
-
-
-// Low-level save from open stream
-LCMSBOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr,
- size_t* BytesNeeded)
-{
- LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
- LCMSICCPROFILE Keep;
-
-
- CopyMemory(&Keep, Icc, sizeof(LCMSICCPROFILE));
-
- _cmsSetSaveToMemory(Icc, NULL, 0);
-
- // Pass #1 does compute offsets
-
- if (!SaveHeader(Icc)) return FALSE;
- if (!SaveTagDirectory(Icc)) return FALSE;
- if (!SaveTags(Icc, &Keep)) return FALSE;
-
- if (!MemPtr) {
-
- // update BytesSaved so caller knows how many bytes are needed for MemPtr
- *BytesNeeded = Icc ->UsedSpace;
- CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE));
- return TRUE;
- }
-
- if (*BytesNeeded < Icc ->UsedSpace) {
-
- // need at least UsedSpace in MemPtr to continue
- CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE));
- return FALSE;
- }
-
- _cmsSetSaveToMemory(Icc, MemPtr, *BytesNeeded);
-
-
- // Pass #2 does save to file into supplied stream
- if (!SaveHeader(Icc)) goto CleanUp;
- if (!SaveTagDirectory(Icc)) goto CleanUp;
- if (!SaveTags(Icc, &Keep)) goto CleanUp;
-
- // update BytesSaved so caller knows how many bytes put into stream
- *BytesNeeded = Icc ->UsedSpace;
-
- Icc ->Close(Icc);
- CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE));
- return TRUE;
-
-CleanUp:
-
- Icc ->Close(Icc);
- CopyMemory(Icc, &Keep, sizeof(LCMSICCPROFILE));
- return FALSE;
-}
-
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,630 +49,1430 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-#include "lcms.h"
-
-// Pipeline of LUT. Enclosed by {} are new revision 4.0 of ICC spec.
//
-// [Mat] -> [L1] -> { [Mat3] -> [Ofs3] -> [L3] ->} [CLUT] { -> [L4] -> [Mat4] -> [Ofs4] } -> [L2]
-//
-// Some of these stages would be missing. This implements the totality of
-// combinations of old and new LUT types as follows:
-//
-// Lut8 & Lut16
-// ============
-// [Mat] -> [L1] -> [CLUT] -> [L2]
-//
-// Mat2, Ofs2, L3, L3, Mat3, Ofs3 are missing
-//
-// LutAToB
-// ========
-//
-// [L1] -> [CLUT] -> [L4] -> [Mat4] -> [Ofs4] -> [L2]
-//
-// Mat, Mat3, Ofs3, L3 are missing
-// L1 = A curves
-// L4 = M curves
-// L2 = B curves
-//
-// LutBToA
-// =======
-//
-// [L1] -> [Mat3] -> [Ofs3] -> [L3] -> [CLUT] -> [L2]
+//---------------------------------------------------------------------------------
//
-// Mat, L4, Mat4, Ofs4 are missing
-// L1 = B Curves
-// L3 = M Curves
-// L2 = A curves
-//
-//
-// V2&3 emulation
-// ===============
-//
-// For output, Mat is multiplied by
-//
-//
-// | 0xff00 / 0xffff 0 0 |
-// | 0 0xff00 / 0xffff 0 |
-// | 0 0 0xff00 / 0xffff |
-//
-//
-// For input, an additional matrix is needed at the very last end of the chain
-//
-//
-// | 0xffff / 0xff00 0 0 |
-// | 0 0xffff / 0xff00 0 |
-// | 0 0 0xffff / 0xff00 |
-//
-//
-// Which reduces to (val * 257) >> 8
+
+#include "lcms2_internal.h"
+
+
+// Allocates an empty multi profile element
+cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID,
+ cmsStageSignature Type,
+ cmsUInt32Number InputChannels,
+ cmsUInt32Number OutputChannels,
+ _cmsStageEvalFn EvalPtr,
+ _cmsStageDupElemFn DupElemPtr,
+ _cmsStageFreeElemFn FreePtr,
+ void* Data)
+{
+ cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage));
+
+ if (ph == NULL) return NULL;
+
+
+ ph ->ContextID = ContextID;
+
+ ph ->Type = Type;
+ ph ->Implements = Type; // By default, no clue on what is implementing
+
+ ph ->InputChannels = InputChannels;
+ ph ->OutputChannels = OutputChannels;
+ ph ->EvalPtr = EvalPtr;
+ ph ->DupElemPtr = DupElemPtr;
+ ph ->FreePtr = FreePtr;
+ ph ->Data = Data;
+
+ return ph;
+}
+
-// A couple of macros to convert between revisions
+static
+void EvaluateIdentity(const cmsFloat32Number In[],
+ cmsFloat32Number Out[],
+ const cmsStage *mpe)
+{
+ memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number));
+}
+
+
+cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels)
+{
+ return _cmsStageAllocPlaceholder(ContextID,
+ cmsSigIdentityElemType,
+ nChannels, nChannels,
+ EvaluateIdentity,
+ NULL,
+ NULL,
+ NULL);
+ }
-#define FROM_V2_TO_V4(x) (((((x)<<8)+(x))+0x80)>>8) // BY 65535 DIV 65280 ROUND
-#define FROM_V4_TO_V2(x) ((((x)<<8)+0x80)/257) // BY 65280 DIV 65535 ROUND
+// Conversion functions. From floating point to 16 bits
+static
+void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32Number n)
+{
+ cmsUInt32Number i;
+
+ for (i=0; i < n; i++) {
+ Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0);
+ }
+}
+
+// From 16 bits to floating point
+static
+void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32Number n)
+{
+ cmsUInt32Number i;
+
+ for (i=0; i < n; i++) {
+ Out[i] = (cmsFloat32Number) In[i] / 65535.0F;
+ }
+}
-// Lut Creation & Destruction
+// This function is quite useful to analyze the structure of a LUT and retrieve the MPE elements
+// that conform the LUT. It should be called with the LUT, the number of expected elements and
+// then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If
+// the function founds a match with current pipeline, it fills the pointers and returns TRUE
+// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass
+// the storage process.
+cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...)
+{
+ va_list args;
+ cmsUInt32Number i;
+ cmsStage* mpe;
+ cmsStageSignature Type;
+ void** ElemPtr;
+
+ // Make sure same number of elements
+ if (cmsPipelineStageCount(Lut) != n) return FALSE;
+
+ va_start(args, n);
-LPLUT LCMSEXPORT cmsAllocLUT(void)
-{
- LPLUT NewLUT;
+ // Iterate across asked types
+ mpe = Lut ->Elements;
+ for (i=0; i < n; i++) {
+
+ // Get asked type
+ Type = va_arg(args, cmsStageSignature);
+ if (mpe ->Type != Type) {
+
+ va_end(args); // Mismatch. We are done.
+ return FALSE;
+ }
+ mpe = mpe ->Next;
+ }
+
+ // Found a combination, fill pointers if not NULL
+ mpe = Lut ->Elements;
+ for (i=0; i < n; i++) {
+
+ ElemPtr = va_arg(args, void**);
+ if (ElemPtr != NULL)
+ *ElemPtr = mpe;
+
+ mpe = mpe ->Next;
+ }
- NewLUT = (LPLUT) _cmsMalloc(sizeof(LUT));
- if (NewLUT)
- ZeroMemory(NewLUT, sizeof(LUT));
+ va_end(args);
+ return TRUE;
+}
+
+// Below there are implementations for several types of elements. Each type may be implemented by a
+// evaluation function, a duplication function, a function to free resources and a constructor.
+
+// *************************************************************************************************
+// Type cmsSigCurveSetElemType (curves)
+// *************************************************************************************************
+
+cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe)
+{
+ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data;
+
+ return Data ->TheCurves;
+}
- return NewLUT;
+static
+void EvaluateCurves(const cmsFloat32Number In[],
+ cmsFloat32Number Out[],
+ const cmsStage *mpe)
+{
+ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data;
+ cmsUInt32Number i;
+
+ if (Data ->TheCurves == NULL) return;
+
+ for (i=0; i < Data ->nCurves; i++) {
+ Out[i] = cmsEvalToneCurveFloat(Data ->TheCurves[i], In[i]);
+ }
+}
+
+static
+void CurveSetElemTypeFree(cmsStage* mpe)
+{
+ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data;
+ cmsUInt32Number i;
+
+ if (Data ->TheCurves != NULL) {
+ for (i=0; i < Data ->nCurves; i++) {
+ if (Data ->TheCurves[i] != NULL)
+ cmsFreeToneCurve(Data ->TheCurves[i]);
+ }
+ }
+ _cmsFree(mpe ->ContextID, Data ->TheCurves);
+ _cmsFree(mpe ->ContextID, Data);
}
-void LCMSEXPORT cmsFreeLUT(LPLUT Lut)
+
+static
+void* CurveSetDup(cmsStage* mpe)
{
- unsigned int i;
+ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data;
+ _cmsStageToneCurvesData* NewElem;
+ cmsUInt32Number i;
+
+ NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageToneCurvesData));
+ if (NewElem == NULL) return NULL;
- if (!Lut) return;
+ NewElem ->nCurves = Data ->nCurves;
+ NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(mpe ->ContextID, NewElem ->nCurves, sizeof(cmsToneCurve*));
+
+ if (NewElem ->TheCurves == NULL) goto Error;
- if (Lut -> T) free(Lut -> T);
+ for (i=0; i < NewElem ->nCurves; i++) {
+
+ // Duplicate each curve. It may fail.
+ NewElem ->TheCurves[i] = cmsDupToneCurve(Data ->TheCurves[i]);
+ if (NewElem ->TheCurves[i] == NULL) goto Error;
+
- for (i=0; i < Lut -> OutputChan; i++)
- {
- if (Lut -> L2[i]) free(Lut -> L2[i]);
- }
+ }
+ return (void*) NewElem;
+
+Error:
- for (i=0; i < Lut -> InputChan; i++)
- {
+ if (NewElem ->TheCurves != NULL) {
+ for (i=0; i < NewElem ->nCurves; i++) {
+ if (NewElem ->TheCurves[i])
+ cmsFreeToneCurve(Data ->TheCurves[i]);
+ }
+ }
+ _cmsFree(mpe ->ContextID, Data ->TheCurves);
+ _cmsFree(mpe ->ContextID, NewElem);
+ return NULL;
+}
- if (Lut -> L1[i]) free(Lut -> L1[i]);
- }
+
+// Curves == NULL forces identity curves
+cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[])
+{
+ cmsUInt32Number i;
+ _cmsStageToneCurvesData* NewElem;
+ cmsStage* NewMPE;
- if (Lut ->wFlags & LUT_HASTL3) {
+ NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels,
+ EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL );
+ if (NewMPE == NULL) return NULL;
- for (i=0; i < Lut -> InputChan; i++) {
+ NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData));
+ if (NewElem == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
+ }
+
+ NewElem ->nCurves = nChannels;
+ NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*));
+ if (NewElem ->TheCurves == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
+ }
+
+ for (i=0; i < nChannels; i++) {
- if (Lut -> L3[i]) free(Lut -> L3[i]);
- }
- }
+ if (Curves == NULL) {
+ NewElem ->TheCurves[i] = cmsBuildGamma(ContextID, 1.0);
+ }
+ else {
+ NewElem ->TheCurves[i] = cmsDupToneCurve(Curves[i]);
+ }
+
+ if (NewElem ->TheCurves[i] == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
+ }
+ }
+
+ NewMPE ->Data = (void*) NewElem;
- if (Lut ->wFlags & LUT_HASTL4) {
+ return NewMPE;
+}
+
+
+// Create a bunch of identity curves
+cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels)
+{
+ cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL);
+
+ if (mpe == NULL) return NULL;
+ mpe ->Implements = cmsSigIdentityElemType;
+ return mpe;
+}
+
- for (i=0; i < Lut -> OutputChan; i++) {
+// *************************************************************************************************
+// Type cmsSigMatrixElemType (Matrices)
+// *************************************************************************************************
+
+
+// Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used
+static
+void EvaluateMatrix(const cmsFloat32Number In[],
+ cmsFloat32Number Out[],
+ const cmsStage *mpe)
+{
+ cmsUInt32Number i, j;
+ _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
+ cmsFloat64Number Tmp;
+
+ // Input is already in 0..1.0 notation
+ for (i=0; i < mpe ->OutputChannels; i++) {
+
+ Tmp = 0;
+ for (j=0; j < mpe->InputChannels; j++) {
+ Tmp += In[j] * Data->Double[i*mpe->InputChannels + j];
+ }
+
+ if (Data ->Offset != NULL)
+ Tmp += Data->Offset[i];
- if (Lut -> L4[i]) free(Lut -> L4[i]);
- }
- }
+ Out[i] = (cmsFloat32Number) Tmp;
+ }
+
+
+ // Output in 0..1.0 domain
+}
+
- if (Lut ->CLut16params.p8)
- free(Lut ->CLut16params.p8);
+// Duplicate a yet-existing matrix element
+static
+void* MatrixElemDup(cmsStage* mpe)
+{
+ _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
+ _cmsStageMatrixData* NewElem;
+ cmsUInt32Number sz;
- free(Lut);
+ NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData));
+ if (NewElem == NULL) return NULL;
+
+ sz = mpe ->InputChannels * mpe ->OutputChannels;
+
+ NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ;
+
+ if (Data ->Offset)
+ NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID,
+ Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ;
+
+ return (void*) NewElem;
}
static
-LPVOID DupBlockTab(LPVOID Org, size_t size)
+void MatrixElemTypeFree(cmsStage* mpe)
+{
+ _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
+ if (Data ->Double)
+ _cmsFree(mpe ->ContextID, Data ->Double);
+
+ if (Data ->Offset)
+ _cmsFree(mpe ->ContextID, Data ->Offset);
+
+ _cmsFree(mpe ->ContextID, mpe ->Data);
+}
+
+
+
+cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols,
+ const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset)
{
- LPVOID mem = _cmsMalloc(size);
- if (mem != NULL)
- CopyMemory(mem, Org, size);
+ cmsUInt32Number i, n;
+ _cmsStageMatrixData* NewElem;
+ cmsStage* NewMPE;
+
+ n = Rows * Cols;
+
+ // Check for overflow
+ if (n < Rows || n < Cols) return NULL;
+
+ NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows,
+ EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL );
+ if (NewMPE == NULL) return NULL;
+
+
+ NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData));
+ if (NewElem == NULL) return NULL;
+
+
+ NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number));
- return mem;
+ if (NewElem->Double == NULL) {
+ MatrixElemTypeFree(NewMPE);
+ return NULL;
+ }
+
+ for (i=0; i < n; i++) {
+ NewElem ->Double[i] = Matrix[i];
+ }
+
+
+ if (Offset != NULL) {
+
+ NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number));
+ if (NewElem->Offset == NULL) {
+ MatrixElemTypeFree(NewMPE);
+ return NULL;
+ }
+
+ for (i=0; i < Cols; i++) {
+ NewElem ->Offset[i] = Offset[i];
+ }
+
+ }
+
+ NewMPE ->Data = (void*) NewElem;
+ return NewMPE;
}
-LPLUT LCMSEXPORT cmsDupLUT(LPLUT Orig)
+// *************************************************************************************************
+// Type cmsSigCLutElemType
+// *************************************************************************************************
+
+
+// Evaluate in true floating point
+static
+void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
{
- LPLUT NewLUT = cmsAllocLUT();
- unsigned int i;
+ _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
+
+ Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params);
+}
+
- CopyMemory(NewLUT, Orig, sizeof(LUT));
+// Convert to 16 bits, evaluate, and back to floating point
+static
+void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
+{
+ _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
+ cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS];
+
+ _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS);
+ _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS);
+
+ FromFloatTo16(In, In16, mpe ->InputChannels);
+ Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params);
+ From16ToFloat(Out16, Out, mpe ->OutputChannels);
+}
+
- for (i=0; i < Orig ->InputChan; i++)
- NewLUT -> L1[i] = (LPWORD) DupBlockTab((LPVOID) Orig ->L1[i],
- sizeof(WORD) * Orig ->In16params.nSamples);
+// Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes
+static
+cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b)
+{
+ cmsUInt32Number rv;
+
+ for (rv = 1; b > 0; b--)
+ rv *= Dims[b-1];
+
+ return rv;
+}
+
+static
+void* CLUTElemDup(cmsStage* mpe)
+{
+ _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
+ _cmsStageCLutData* NewElem;
+
- for (i=0; i < Orig ->OutputChan; i++)
- NewLUT -> L2[i] = (LPWORD) DupBlockTab((LPVOID) Orig ->L2[i],
- sizeof(WORD) * Orig ->Out16params.nSamples);
+ NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData));
+ if (NewElem == NULL) return NULL;
+
+ NewElem ->nEntries = Data ->nEntries;
+ NewElem ->HasFloatValues = Data ->HasFloatValues;
+
+ if (Data ->Tab.T) {
- NewLUT -> T = (LPWORD) DupBlockTab((LPVOID) Orig ->T, Orig -> Tsize);
+ if (Data ->HasFloatValues)
+ NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number));
+ else
+ NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number));
+ }
- return NewLUT;
+ NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID,
+ Data ->Params ->nSamples,
+ Data ->Params ->nInputs,
+ Data ->Params ->nOutputs,
+ NewElem ->Tab.T,
+ Data ->Params ->dwFlags);
+
+ return (void*) NewElem;
}
static
-unsigned int UIpow(unsigned int a, unsigned int b)
+void CLutElemTypeFree(cmsStage* mpe)
{
- unsigned int rv = 1;
+
+ _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
+
+ // Already empty
+ if (Data == NULL) return;
+
+ // This works for both types
+ if (Data -> Tab.T)
+ _cmsFree(mpe ->ContextID, Data -> Tab.T);
+
+ _cmsFreeInterpParams(Data ->Params);
+ _cmsFree(mpe ->ContextID, mpe ->Data);
+}
+
+
+// Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different
+// granularity on each dimension.
+cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID,
+ const cmsUInt32Number clutPoints[],
+ cmsUInt32Number inputChan,
+ cmsUInt32Number outputChan,
+ const cmsUInt16Number* Table)
+{
+ cmsUInt32Number i, n;
+ _cmsStageCLutData* NewElem;
+ cmsStage* NewMPE;
+
+ NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
+ EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL );
+
+ if (NewMPE == NULL) return NULL;
+
+ NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData));
+ if (NewElem == NULL) return NULL;
+
+ NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan);
+ NewElem -> HasFloatValues = FALSE;
+
+ NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number));
+ if (NewElem ->Tab.T == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
+ }
- for (; b > 0; b--)
- rv *= a;
+ if (Table != NULL) {
+ for (i=0; i < n; i++) {
+ NewElem ->Tab.T[i] = Table[i];
+ }
+ }
+
+ NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS);
+ if (NewElem ->Params == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
+ }
+
+ NewMPE ->Data = (void*) NewElem;
+
+ return NewMPE;
+}
- return rv;
+cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID,
+ cmsUInt32Number nGridPoints,
+ cmsUInt32Number inputChan,
+ cmsUInt32Number outputChan,
+ const cmsUInt16Number* Table)
+{
+ cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
+ int i;
+
+ // Our resulting LUT would be same gridpoints on all dimensions
+ for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
+ Dimensions[i] = nGridPoints;
+
+
+ return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table);
+}
+
+
+cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID,
+ cmsUInt32Number nGridPoints,
+ cmsUInt32Number inputChan,
+ cmsUInt32Number outputChan,
+ const cmsFloat32Number* Table)
+{
+ cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
+ int i;
+
+ // Our resulting LUT would be same gridpoints on all dimensions
+ for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
+ Dimensions[i] = nGridPoints;
+
+ return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table);
}
-LCMSBOOL _cmsValidateLUT(LPLUT NewLUT)
+
+cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table)
{
- unsigned int calc = 1;
- unsigned int oldCalc;
- unsigned int power = NewLUT -> InputChan;
+ cmsUInt32Number i, n;
+ _cmsStageCLutData* NewElem;
+ cmsStage* NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
+ EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL);
+
+ if (NewMPE == NULL) return NULL;
- if (NewLUT -> cLutPoints > 100) return FALSE;
- if (NewLUT -> InputChan > MAXCHANNELS) return FALSE;
- if (NewLUT -> OutputChan > MAXCHANNELS) return FALSE;
+
+ NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData));
+ if (NewElem == NULL) return NULL;
+
+ NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan);
+ NewElem -> HasFloatValues = TRUE;
- if (NewLUT -> cLutPoints == 0) return TRUE;
-
- for (; power > 0; power--) {
+ NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number));
+ if (NewElem ->Tab.TFloat == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
+ }
- oldCalc = calc;
- calc *= NewLUT -> cLutPoints;
+ if (Table != NULL) {
+ for (i=0; i < n; i++) {
+ NewElem ->Tab.TFloat[i] = Table[i];
+ }
+ }
- if (calc / NewLUT -> cLutPoints != oldCalc) {
- return FALSE;
- }
+ NewMPE ->Data = (void*) NewElem;
+
+ NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT);
+ if (NewElem ->Params == NULL) {
+ cmsStageFree(NewMPE);
+ return NULL;
}
- oldCalc = calc;
- calc *= NewLUT -> OutputChan;
- if (NewLUT -> OutputChan && calc / NewLUT -> OutputChan != oldCalc) {
- return FALSE;
+
+
+ return NewMPE;
+}
+
+
+static
+int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo)
+{
+ int nChan = *(int*) Cargo;
+ int i;
+
+ for (i=0; i < nChan; i++)
+ Out[i] = In[i];
+
+ return 1;
+}
+
+// Creates an MPE that just copies input to output
+cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan)
+{
+ cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
+ cmsStage* mpe ;
+ int i;
+
+ for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
+ Dimensions[i] = 2;
+
+ mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL);
+ if (mpe == NULL) return NULL;
+
+ if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) {
+ cmsStageFree(mpe);
+ return NULL;
+ }
+
+ mpe ->Implements = cmsSigIdentityElemType;
+ return mpe;
+}
+
+
+
+// Quantize a value 0 <= i < MaxSamples to 0..0xffff
+cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples)
+{
+ cmsFloat64Number x;
+
+ x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1);
+ return _cmsQuickSaturateWord(x);
+}
+
+
+// This routine does a sweep on whole input space, and calls its callback
+// function on knots. returns TRUE if all ok, FALSE otherwise.
+cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags)
+{
+ int i, t, nTotalPoints, index, rest;
+ int nInputs, nOutputs;
+ cmsUInt32Number* nSamples;
+ cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS];
+ _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
+
+
+ nSamples = clut->Params ->nSamples;
+ nInputs = clut->Params ->nInputs;
+ nOutputs = clut->Params ->nOutputs;
+
+ if (nInputs >= cmsMAXCHANNELS) return FALSE;
+ if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
+
+ nTotalPoints = CubeSize(nSamples, nInputs);
+
+ index = 0;
+ for (i = 0; i < nTotalPoints; i++) {
+
+ rest = i;
+ for (t = nInputs-1; t >=0; --t) {
+
+ cmsUInt32Number Colorant = rest % nSamples[t];
+
+ rest /= nSamples[t];
+
+ In[t] = _cmsQuantizeVal(Colorant, nSamples[t]);
+ }
+
+ if (clut ->Tab.T != NULL) {
+ for (t=0; t < nOutputs; t++)
+ Out[t] = clut->Tab.T[index + t];
+ }
+
+ if (!Sampler(In, Out, Cargo))
+ return FALSE;
+
+ if (!(dwFlags & SAMPLER_INSPECT)) {
+
+ if (clut ->Tab.T != NULL) {
+ for (t=0; t < nOutputs; t++)
+ clut->Tab.T[index + t] = Out[t];
+ }
+ }
+
+ index += nOutputs;
}
return TRUE;
}
-LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT NewLUT, int clutPoints, int inputChan, int outputChan)
+// Same as anterior, but for floting point
+cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags)
{
- DWORD nTabSize;
+ int i, t, nTotalPoints, index, rest;
+ int nInputs, nOutputs;
+ cmsUInt32Number* nSamples;
+ cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS];
+ _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
+
+ nSamples = clut->Params ->nSamples;
+ nInputs = clut->Params ->nInputs;
+ nOutputs = clut->Params ->nOutputs;
+
+ if (nInputs >= cmsMAXCHANNELS) return FALSE;
+ if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
+
+ nTotalPoints = CubeSize(nSamples, nInputs);
+
+ index = 0;
+ for (i = 0; i < nTotalPoints; i++) {
+
+ rest = i;
+ for (t = nInputs-1; t >=0; --t) {
+
+ cmsUInt32Number Colorant = rest % nSamples[t];
+
+ rest /= nSamples[t];
+
+ In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0);
+ }
+
+ if (clut ->Tab.TFloat != NULL) {
+ for (t=0; t < nOutputs; t++)
+ Out[t] = clut->Tab.TFloat[index + t];
+ }
- NewLUT -> wFlags |= LUT_HAS3DGRID;
- NewLUT -> cLutPoints = clutPoints;
- NewLUT -> InputChan = inputChan;
- NewLUT -> OutputChan = outputChan;
+ if (!Sampler(In, Out, Cargo))
+ return FALSE;
+
+ if (!(dwFlags & SAMPLER_INSPECT)) {
+
+ if (clut ->Tab.TFloat != NULL) {
+ for (t=0; t < nOutputs; t++)
+ clut->Tab.TFloat[index + t] = Out[t];
+ }
+ }
+
+ index += nOutputs;
+ }
+
+ return TRUE;
+}
+
+
+
+// This routine does a sweep on whole input space, and calls its callback
+// function on knots. returns TRUE if all ok, FALSE otherwise.
+cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
+ cmsSAMPLER16 Sampler, void * Cargo)
+{
+ int i, t, nTotalPoints, rest;
+ cmsUInt16Number In[cmsMAXCHANNELS];
+
+ if (nInputs >= cmsMAXCHANNELS) return FALSE;
+
+ nTotalPoints = CubeSize(clutPoints, nInputs);
+
+ for (i = 0; i < nTotalPoints; i++) {
+
+ rest = i;
+ for (t = nInputs-1; t >=0; --t) {
- if (!_cmsValidateLUT(NewLUT)) {
- return NULL;
- }
+ cmsUInt32Number Colorant = rest % clutPoints[t];
+
+ rest /= clutPoints[t];
+ In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]);
+
+ }
+
+ if (!Sampler(In, NULL, Cargo))
+ return FALSE;
+ }
+
+ return TRUE;
+}
- nTabSize = NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints,
- NewLUT->InputChan);
+cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
+ cmsSAMPLERFLOAT Sampler, void * Cargo)
+{
+ int i, t, nTotalPoints, rest;
+ cmsFloat32Number In[cmsMAXCHANNELS];
+
+ if (nInputs >= cmsMAXCHANNELS) return FALSE;
+
+ nTotalPoints = CubeSize(clutPoints, nInputs);
+
+ for (i = 0; i < nTotalPoints; i++) {
+
+ rest = i;
+ for (t = nInputs-1; t >=0; --t) {
+
+ cmsUInt32Number Colorant = rest % clutPoints[t];
+
+ rest /= clutPoints[t];
+ In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0);
+
+ }
- NewLUT -> T = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize);
- nTabSize *= sizeof(WORD);
- if (NewLUT -> T == NULL) return NULL;
+ if (!Sampler(In, NULL, Cargo))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// ********************************************************************************
+// Type cmsSigLab2XYZElemType
+// ********************************************************************************
+
- ZeroMemory(NewLUT -> T, nTabSize);
- NewLUT ->Tsize = nTabSize;
+static
+void EvaluateLab2XYZ(const cmsFloat32Number In[],
+ cmsFloat32Number Out[],
+ const cmsStage *mpe)
+{
+ cmsCIELab Lab;
+ cmsCIEXYZ XYZ;
+ const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ;
+
+ // V4 rules
+ Lab.L = In[0] * 100.0;
+ Lab.a = In[1] * 255.0 - 128.0;
+ Lab.b = In[2] * 255.0 - 128.0;
+
+ cmsLab2XYZ(NULL, &XYZ, &Lab);
+
+ // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff
+ // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0)
+
+ Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj);
+ Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj);
+ Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj);
+ return;
+
+ cmsUNUSED_PARAMETER(mpe);
+}
- cmsCalcCLUT16Params(NewLUT -> cLutPoints, NewLUT -> InputChan,
- NewLUT -> OutputChan,
- &NewLUT -> CLut16params);
+// No dup or free routines needed, as the structure has no pointers in it.
+cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID)
+{
+ return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL);
+}
+
+// ********************************************************************************
+
+// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable
+// number of gridpoints that would make exact match. However, a prelinearization
+// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot.
+// Almost all what we need but unfortunately, the rest of entries should be scaled by
+// (255*257/256) and this is not exact.
+
+cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
+{
+ cmsStage* mpe;
+ cmsToneCurve* LabTable[3];
+ int i, j;
+
+ LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL);
+ LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL);
+ LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL);
+
+ for (j=0; j < 3; j++) {
+
+ if (LabTable[j] == NULL) {
+ cmsFreeToneCurveTriple(LabTable);
+ return NULL;
+ }
+
+ // We need to map * (0xffff / 0xff00), thats same as (257 / 256)
+ // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256);
+ for (i=0; i < 257; i++) {
+
+ LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8);
+ }
+
+ LabTable[j] ->Table16[257] = 0xffff;
+ }
+
+ mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable);
+ cmsFreeToneCurveTriple(LabTable);
+
+ mpe ->Implements = cmsSigLabV2toV4;
+ return mpe;
+}
+
+// ********************************************************************************
+
+// Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles
+cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID)
+{
+ static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0,
+ 0, 65535.0/65280.0, 0,
+ 0, 0, 65535.0/65280.0
+ };
+
+ cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL);
+
+ if (mpe == NULL) return mpe;
+ mpe ->Implements = cmsSigLabV2toV4;
+ return mpe;
+}
+
+
+// Reverse direction
+cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID)
+{
+ static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0,
+ 0, 65280.0/65535.0, 0,
+ 0, 0, 65280.0/65535.0
+ };
+
+ cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL);
+
+ if (mpe == NULL) return mpe;
+ mpe ->Implements = cmsSigLabV4toV2;
+ return mpe;
+}
+
+
+// ********************************************************************************
+// Type cmsSigXYZ2LabElemType
+// ********************************************************************************
+
+static
+void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
+{
+ cmsCIELab Lab;
+ cmsCIEXYZ XYZ;
+ const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ;
+
+ // From 0..1.0 to XYZ
+
+ XYZ.X = In[0] * XYZadj;
+ XYZ.Y = In[1] * XYZadj;
+ XYZ.Z = In[2] * XYZadj;
+
+ cmsXYZ2Lab(NULL, &Lab, &XYZ);
+
+ // From V4 Lab to 0..1.0
+
+ Out[0] = (cmsFloat32Number) (Lab.L / 100.0);
+ Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0);
+ Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0);
+ return;
+
+ cmsUNUSED_PARAMETER(mpe);
+}
+
+cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID)
+{
+ return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL);
+
+}
+
+// ********************************************************************************
+
+// For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray
+
+cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID)
+{
+ cmsToneCurve* LabTable[3];
+ cmsFloat64Number Params[1] = {2.4} ;
+
+ LabTable[0] = cmsBuildGamma(ContextID, 1.0);
+ LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params);
+ LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params);
+
+ return cmsStageAllocToneCurves(ContextID, 3, LabTable);
+}
- return NewLUT;
+
+// Free a single MPE
+void CMSEXPORT cmsStageFree(cmsStage* mpe)
+{
+ if (mpe ->FreePtr)
+ mpe ->FreePtr(mpe);
+
+ _cmsFree(mpe ->ContextID, mpe);
+}
+
+
+cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe)
+{
+ return mpe ->InputChannels;
+}
+
+cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe)
+{
+ return mpe ->OutputChannels;
+}
+
+cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe)
+{
+ return mpe -> Type;
+}
+
+void* CMSEXPORT cmsStageData(const cmsStage* mpe)
+{
+ return mpe -> Data;
+}
+
+cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe)
+{
+ return mpe -> Next;
+}
+
+
+// Duplicates an MPE
+cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
+{
+ cmsStage* NewMPE;
+
+ if (mpe == NULL) return NULL;
+ NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID,
+ mpe ->Type,
+ mpe ->InputChannels,
+ mpe ->OutputChannels,
+ mpe ->EvalPtr,
+ mpe ->DupElemPtr,
+ mpe ->FreePtr,
+ NULL);
+ if (NewMPE == NULL) return NULL;
+
+ NewMPE ->Implements = mpe ->Implements;
+
+ if (mpe ->DupElemPtr)
+ NewMPE ->Data = mpe ->DupElemPtr(mpe);
+ else
+ NewMPE ->Data = NULL;
+
+ return NewMPE;
+}
+
+
+// ***********************************************************************************************************
+
+// This function sets up the channel count
+
+static
+void BlessLUT(cmsPipeline* lut)
+{
+ // We can set the input/ouput channels only if we have elements.
+ if (lut ->Elements != NULL) {
+
+ cmsStage *First, *Last;
+
+ First = cmsPipelineGetPtrToFirstStage(lut);
+ Last = cmsPipelineGetPtrToLastStage(lut);
+
+ if (First != NULL)lut ->InputChannels = First ->InputChannels;
+ if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels;
+ }
+}
+
+
+// Default to evaluate the LUT on 16 bit-basis. Precision is retained.
+static
+void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D)
+{
+ cmsPipeline* lut = (cmsPipeline*) D;
+ cmsStage *mpe;
+ cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS];
+ int Phase = 0, NextPhase;
+
+ From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels);
+
+ for (mpe = lut ->Elements;
+ mpe != NULL;
+ mpe = mpe ->Next) {
+
+ NextPhase = Phase ^ 1;
+ mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe);
+ Phase = NextPhase;
+ }
+
+
+ FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels);
+}
+
+
+
+// Does evaluate the LUT on cmsFloat32Number-basis.
+static
+void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D)
+{
+ cmsPipeline* lut = (cmsPipeline*) D;
+ cmsStage *mpe;
+ cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS];
+ int Phase = 0, NextPhase;
+
+ memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number));
+
+ for (mpe = lut ->Elements;
+ mpe != NULL;
+ mpe = mpe ->Next) {
+
+ NextPhase = Phase ^ 1;
+ mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe);
+ Phase = NextPhase;
+ }
+
+ memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number));
}
-LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nTable)
+// LUT Creation & Destruction
+
+cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels)
{
- unsigned int i;
- LPWORD PtrW;
-
- switch (nTable) {
-
+ cmsPipeline* NewLUT;
- case 1: NewLUT -> wFlags |= LUT_HASTL1;
- cmsCalcL16Params(Tables[0] -> nEntries, &NewLUT -> In16params);
- NewLUT -> InputEntries = Tables[0] -> nEntries;
-
- for (i=0; i < NewLUT -> InputChan; i++) {
+ if (InputChannels >= cmsMAXCHANNELS ||
+ OutputChannels >= cmsMAXCHANNELS) return NULL;
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> InputEntries);
- if (PtrW == NULL) return NULL;
-
- NewLUT -> L1[i] = PtrW;
- CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> InputEntries);
- CopyMemory(&NewLUT -> LCurvesSeed[0][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS));
- }
+ NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline));
+ if (NewLUT == NULL) return NULL;
- break;
-
- case 2: NewLUT -> wFlags |= LUT_HASTL2;
- cmsCalcL16Params(Tables[0] -> nEntries, &NewLUT -> Out16params);
- NewLUT -> OutputEntries = Tables[0] -> nEntries;
- for (i=0; i < NewLUT -> OutputChan; i++) {
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> OutputEntries);
- if (PtrW == NULL) return NULL;
-
- NewLUT -> L2[i] = PtrW;
- CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> OutputEntries);
- CopyMemory(&NewLUT -> LCurvesSeed[1][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS));
- }
- break;
-
-
- // 3 & 4 according ICC 4.0 spec
-
- case 3:
- NewLUT -> wFlags |= LUT_HASTL3;
- cmsCalcL16Params(Tables[0] -> nEntries, &NewLUT -> L3params);
- NewLUT -> L3Entries = Tables[0] -> nEntries;
-
- for (i=0; i < NewLUT -> InputChan; i++) {
+ NewLUT -> InputChannels = InputChannels;
+ NewLUT -> OutputChannels = OutputChannels;
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> L3Entries);
- if (PtrW == NULL) return NULL;
-
- NewLUT -> L3[i] = PtrW;
- CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> L3Entries);
- CopyMemory(&NewLUT -> LCurvesSeed[2][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS));
- }
- break;
+ NewLUT ->Eval16Fn = _LUTeval16;
+ NewLUT ->EvalFloatFn = _LUTevalFloat;
+ NewLUT ->DupDataFn = NULL;
+ NewLUT ->FreeDataFn = NULL;
+ NewLUT ->Data = NewLUT;
- case 4:
- NewLUT -> wFlags |= LUT_HASTL4;
- cmsCalcL16Params(Tables[0] -> nEntries, &NewLUT -> L4params);
- NewLUT -> L4Entries = Tables[0] -> nEntries;
- for (i=0; i < NewLUT -> OutputChan; i++) {
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewLUT -> L4Entries);
- if (PtrW == NULL) return NULL;
+ NewLUT ->ContextID = ContextID;
- NewLUT -> L4[i] = PtrW;
- CopyMemory(PtrW, Tables[i]->GammaTable, sizeof(WORD) * NewLUT -> L4Entries);
- CopyMemory(&NewLUT -> LCurvesSeed[3][i], &Tables[i] -> Seed, sizeof(LCMSGAMMAPARAMS));
- }
- break;
-
-
- default:;
- }
+ BlessLUT(NewLUT);
return NewLUT;
}
-// Set the LUT matrix
+cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut)
+{
+ return lut ->InputChannels;
+}
-LPLUT LCMSEXPORT cmsSetMatrixLUT(LPLUT Lut, LPMAT3 M)
+cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut)
+{
+ return lut ->OutputChannels;
+}
+
+// Free a profile elements LUT
+void CMSEXPORT cmsPipelineFree(cmsPipeline* lut)
{
- MAT3toFix(&Lut ->Matrix, M);
+ cmsStage *mpe, *Next;
+
+ if (lut == NULL) return;
+
+ for (mpe = lut ->Elements;
+ mpe != NULL;
+ mpe = Next) {
- if (!MAT3isIdentity(&Lut->Matrix, 0.0001))
- Lut ->wFlags |= LUT_HASMATRIX;
+ Next = mpe ->Next;
+ cmsStageFree(mpe);
+ }
- return Lut;
+ if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data);
+
+ _cmsFree(lut ->ContextID, lut);
}
-// Set matrix & offset, v4 compatible
-
-LPLUT LCMSEXPORT cmsSetMatrixLUT4(LPLUT Lut, LPMAT3 M, LPVEC3 off, DWORD dwFlags)
+// Default to evaluate the LUT on 16 bit-basis.
+void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut)
{
- WMAT3 WMat;
- WVEC3 Woff;
- VEC3 Zero = {{0, 0, 0}};
-
- MAT3toFix(&WMat, M);
-
- if (off == NULL)
- off = &Zero;
-
- VEC3toFix(&Woff, off);
-
- // Nop if identity
- if (MAT3isIdentity(&WMat, 0.0001) &&
- (Woff.n[VX] == 0 && Woff.n[VY] == 0 && Woff.n[VZ] == 0))
- return Lut;
-
- switch (dwFlags) {
-
- case LUT_HASMATRIX:
- Lut ->Matrix = WMat;
- Lut ->wFlags |= LUT_HASMATRIX;
- break;
-
- case LUT_HASMATRIX3:
- Lut ->Mat3 = WMat;
- Lut ->Ofs3 = Woff;
- Lut ->wFlags |= LUT_HASMATRIX3;
- break;
-
- case LUT_HASMATRIX4:
- Lut ->Mat4 = WMat;
- Lut ->Ofs4 = Woff;
- Lut ->wFlags |= LUT_HASMATRIX4;
- break;
+ lut ->Eval16Fn(In, Out, lut->Data);
+}
- default:;
- }
-
- return Lut;
+// Does evaluate the LUT on cmsFloat32Number-basis.
+void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut)
+{
+ lut ->EvalFloatFn(In, Out, lut);
}
-// The full evaluator
-
-void LCMSEXPORT cmsEvalLUT(LPLUT Lut, WORD In[], WORD Out[])
+// Duplicates a LUT
+cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
{
- register unsigned int i;
- WORD StageABC[MAXCHANNELS], StageLMN[MAXCHANNELS];
-
-
- // Try to speedup things on plain devicelinks
- if (Lut ->wFlags == LUT_HAS3DGRID) {
-
- Lut ->CLut16params.Interp3D(In, Out, Lut -> T, &Lut -> CLut16params);
- return;
- }
-
-
- // Nope, evaluate whole LUT
+ cmsPipeline* NewLUT;
+ cmsStage *NewMPE, *Anterior = NULL, *mpe;
+ cmsBool First = TRUE;
- for (i=0; i < Lut -> InputChan; i++)
- StageABC[i] = In[i];
-
-
- if (Lut ->wFlags & LUT_V4_OUTPUT_EMULATE_V2) {
-
- // Clamp Lab to avoid overflow
- if (StageABC[0] > 0xFF00)
- StageABC[0] = 0xFF00;
+ if (lut == NULL) return NULL;
- StageABC[0] = (WORD) FROM_V2_TO_V4(StageABC[0]);
- StageABC[1] = (WORD) FROM_V2_TO_V4(StageABC[1]);
- StageABC[2] = (WORD) FROM_V2_TO_V4(StageABC[2]);
-
- }
+ NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels);
+ for (mpe = lut ->Elements;
+ mpe != NULL;
+ mpe = mpe ->Next) {
- if (Lut ->wFlags & LUT_V2_OUTPUT_EMULATE_V4) {
-
- StageABC[0] = (WORD) FROM_V4_TO_V2(StageABC[0]);
- StageABC[1] = (WORD) FROM_V4_TO_V2(StageABC[1]);
- StageABC[2] = (WORD) FROM_V4_TO_V2(StageABC[2]);
- }
+ NewMPE = cmsStageDup(mpe);
-
- // Matrix handling.
-
- if (Lut -> wFlags & LUT_HASMATRIX) {
-
- WVEC3 InVect, OutVect;
-
- // In LUT8 here comes the special gray axis fixup
-
- if (Lut ->FixGrayAxes) {
-
- StageABC[1] = _cmsClampWord(StageABC[1] - 128);
- StageABC[2] = _cmsClampWord(StageABC[2] - 128);
- }
-
- // Matrix
-
- InVect.n[VX] = ToFixedDomain(StageABC[0]);
- InVect.n[VY] = ToFixedDomain(StageABC[1]);
- InVect.n[VZ] = ToFixedDomain(StageABC[2]);
+ if (NewMPE == NULL) {
+ cmsPipelineFree(NewLUT);
+ return NULL;
+ }
-
- MAT3evalW(&OutVect, &Lut -> Matrix, &InVect);
-
- // PCS in 1Fixed15 format, adjusting
-
- StageABC[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX]));
- StageABC[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY]));
- StageABC[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ]));
- }
+ if (First) {
+ NewLUT ->Elements = NewMPE;
+ First = FALSE;
+ }
+ else {
+ Anterior ->Next = NewMPE;
+ }
-
- // First linearization
+ Anterior = NewMPE;
+ }
- if (Lut -> wFlags & LUT_HASTL1)
- {
- for (i=0; i < Lut -> InputChan; i++)
- StageABC[i] = cmsLinearInterpLUT16(StageABC[i],
- Lut -> L1[i],
- &Lut -> In16params);
- }
+ NewLUT ->DupDataFn = lut ->DupDataFn;
+ NewLUT ->FreeDataFn = lut ->FreeDataFn;
+
+ if (NewLUT ->DupDataFn != NULL)
+ NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data);
- // Mat3, Ofs3, L3 processing
-
- if (Lut ->wFlags & LUT_HASMATRIX3) {
-
- WVEC3 InVect, OutVect;
-
- InVect.n[VX] = ToFixedDomain(StageABC[0]);
- InVect.n[VY] = ToFixedDomain(StageABC[1]);
- InVect.n[VZ] = ToFixedDomain(StageABC[2]);
-
- MAT3evalW(&OutVect, &Lut -> Mat3, &InVect);
-
- OutVect.n[VX] += Lut ->Ofs3.n[VX];
- OutVect.n[VY] += Lut ->Ofs3.n[VY];
- OutVect.n[VZ] += Lut ->Ofs3.n[VZ];
-
- StageABC[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX]));
- StageABC[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY]));
- StageABC[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ]));
-
- }
-
- if (Lut ->wFlags & LUT_HASTL3) {
-
- for (i=0; i < Lut -> InputChan; i++)
- StageABC[i] = cmsLinearInterpLUT16(StageABC[i],
- Lut -> L3[i],
- &Lut -> L3params);
-
- }
-
-
-
- if (Lut -> wFlags & LUT_HAS3DGRID) {
-
- Lut ->CLut16params.Interp3D(StageABC, StageLMN, Lut -> T, &Lut -> CLut16params);
-
- }
- else
- {
-
- for (i=0; i < Lut -> InputChan; i++)
- StageLMN[i] = StageABC[i];
-
- }
-
-
- // Mat4, Ofs4, L4 processing
-
- if (Lut ->wFlags & LUT_HASTL4) {
+ NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits;
- for (i=0; i < Lut -> OutputChan; i++)
- StageLMN[i] = cmsLinearInterpLUT16(StageLMN[i],
- Lut -> L4[i],
- &Lut -> L4params);
- }
-
- if (Lut ->wFlags & LUT_HASMATRIX4) {
-
- WVEC3 InVect, OutVect;
-
- InVect.n[VX] = ToFixedDomain(StageLMN[0]);
- InVect.n[VY] = ToFixedDomain(StageLMN[1]);
- InVect.n[VZ] = ToFixedDomain(StageLMN[2]);
-
- MAT3evalW(&OutVect, &Lut -> Mat4, &InVect);
-
- OutVect.n[VX] += Lut ->Ofs4.n[VX];
- OutVect.n[VY] += Lut ->Ofs4.n[VY];
- OutVect.n[VZ] += Lut ->Ofs4.n[VZ];
-
- StageLMN[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX]));
- StageLMN[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY]));
- StageLMN[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ]));
-
- }
-
- // Last linearitzation
-
- if (Lut -> wFlags & LUT_HASTL2)
- {
- for (i=0; i < Lut -> OutputChan; i++)
- Out[i] = cmsLinearInterpLUT16(StageLMN[i],
- Lut -> L2[i],
- &Lut -> Out16params);
- }
- else
- {
- for (i=0; i < Lut -> OutputChan; i++)
- Out[i] = StageLMN[i];
- }
-
-
-
- if (Lut ->wFlags & LUT_V4_INPUT_EMULATE_V2) {
-
- Out[0] = (WORD) FROM_V4_TO_V2(Out[0]);
- Out[1] = (WORD) FROM_V4_TO_V2(Out[1]);
- Out[2] = (WORD) FROM_V4_TO_V2(Out[2]);
-
- }
-
- if (Lut ->wFlags & LUT_V2_INPUT_EMULATE_V4) {
-
- Out[0] = (WORD) FROM_V2_TO_V4(Out[0]);
- Out[1] = (WORD) FROM_V2_TO_V4(Out[1]);
- Out[2] = (WORD) FROM_V2_TO_V4(Out[2]);
- }
+ BlessLUT(NewLUT);
+ return NewLUT;
}
-// Precomputes tables for 8-bit on input devicelink.
-//
-LPLUT _cmsBlessLUT8(LPLUT Lut)
+void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe)
{
- int i, j;
- WORD StageABC[3];
- Fixed32 v1, v2, v3;
- LPL8PARAMS p8;
- LPL16PARAMS p = &Lut ->CLut16params;
+ cmsStage* Anterior = NULL, *pt;
+
+ switch (loc) {
+
+ case cmsAT_BEGIN:
+ mpe ->Next = lut ->Elements;
+ lut ->Elements = mpe;
+ break;
+
+ case cmsAT_END:
+
+ if (lut ->Elements == NULL)
+ lut ->Elements = mpe;
+ else {
+
+ for (pt = lut ->Elements;
+ pt != NULL;
+ pt = pt -> Next) Anterior = pt;
+
+ Anterior ->Next = mpe;
+ mpe ->Next = NULL;
+ }
+ break;
+ default:;
+ }
+
+ BlessLUT(lut);
+}
+
+// Unlink an element and return the pointer to it
+void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe)
+{
+ cmsStage *Anterior, *pt, *Last;
+ cmsStage *Unlinked = NULL;
- p8 = (LPL8PARAMS) _cmsMalloc(sizeof(L8PARAMS));
- if (p8 == NULL) return NULL;
+ // If empty LUT, there is nothing to remove
+ if (lut ->Elements == NULL) {
+ if (mpe) *mpe = NULL;
+ return;
+ }
- // values comes * 257, so we can safely take first byte (x << 8 + x)
- // if there are prelinearization, is already smelted in tables
-
- for (i=0; i < 256; i++) {
-
- StageABC[0] = StageABC[1] = StageABC[2] = RGB_8_TO_16(i);
+ // On depending on the strategy...
+ switch (loc) {
- if (Lut ->wFlags & LUT_HASTL1) {
+ case cmsAT_BEGIN:
+ {
+ cmsStage* elem = lut ->Elements;
- for (j=0; j < 3; j++)
- StageABC[j] = cmsLinearInterpLUT16(StageABC[j],
- Lut -> L1[j],
- &Lut -> In16params);
- Lut ->wFlags &= ~LUT_HASTL1;
- }
+ lut ->Elements = elem -> Next;
+ elem ->Next = NULL;
+ Unlinked = elem;
+ }
+ break;
- v1 = ToFixedDomain(StageABC[0] * p -> Domain);
- v2 = ToFixedDomain(StageABC[1] * p -> Domain);
- v3 = ToFixedDomain(StageABC[2] * p -> Domain);
+ case cmsAT_END:
+ Anterior = Last = NULL;
+ for (pt = lut ->Elements;
+ pt != NULL;
+ pt = pt -> Next) {
+ Anterior = Last;
+ Last = pt;
+ }
- p8 ->X0[i] = p->opta3 * FIXED_TO_INT(v1);
- p8 ->Y0[i] = p->opta2 * FIXED_TO_INT(v2);
- p8 ->Z0[i] = p->opta1 * FIXED_TO_INT(v3);
+ Unlinked = Last; // Next already points to NULL
- p8 ->rx[i] = (WORD) FIXED_REST_TO_INT(v1);
- p8 ->ry[i] = (WORD) FIXED_REST_TO_INT(v2);
- p8 ->rz[i] = (WORD) FIXED_REST_TO_INT(v3);
-
- }
+ // Truncate the chain
+ if (Anterior)
+ Anterior ->Next = NULL;
+ else
+ lut ->Elements = NULL;
+ break;
+ default:;
+ }
- Lut -> CLut16params.p8 = p8;
- Lut -> CLut16params.Interp3D = cmsTetrahedralInterp8;
+ if (mpe)
+ *mpe = Unlinked;
+ else
+ cmsStageFree(Unlinked);
- return Lut;
-
+ BlessLUT(lut);
}
+// Concatenate two LUT into a new single one
+cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
+{
+ cmsStage* mpe, *NewMPE;
+
+ // If both LUTS does not have elements, we need to inherit
+ // the number of channels
+ if (l1 ->Elements == NULL && l2 ->Elements == NULL) {
+ l1 ->InputChannels = l2 ->InputChannels;
+ l1 ->OutputChannels = l2 ->OutputChannels;
+ }
+
+ // Cat second
+ for (mpe = l2 ->Elements;
+ mpe != NULL;
+ mpe = mpe ->Next) {
+
+ // We have to dup each element
+ NewMPE = cmsStageDup(mpe);
+
+ if (NewMPE == NULL) {
+ return FALSE;
+ }
+
+ cmsPipelineInsertStage(l1, cmsAT_END, NewMPE);
+ }
+
+ BlessLUT(l1);
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On)
+{
+ cmsBool Anterior = lut ->SaveAs8Bits;
+
+ lut ->SaveAs8Bits = On;
+ return Anterior;
+}
+
+
+cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut)
+{
+ return lut ->Elements;
+}
+
+cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut)
+{
+ cmsStage *mpe, *Anterior = NULL;
+
+ for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next)
+ Anterior = mpe;
+
+ return Anterior;
+}
+
+cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut)
+{
+ cmsStage *mpe;
+ cmsUInt32Number n;
+
+ for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next)
+ n++;
+
+ return n;
+}
+
+// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional
+// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality.
+void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
+ _cmsOPTeval16Fn Eval16,
+ void* PrivateData,
+ _cmsOPTfreeDataFn FreePrivateDataFn,
+ _cmsOPTdupDataFn DupPrivateDataFn)
+{
+
+ Lut ->Eval16Fn = Eval16;
+ Lut ->DupDataFn = DupPrivateDataFn;
+ Lut ->FreeDataFn = FreePrivateDataFn;
+ Lut ->Data = PrivateData;
+}
// ----------------------------------------------------------- Reverse interpolation
-
-
// Here's how it goes. The derivative Df(x) of the function f is the linear
// transformation that best approximates f near the point x. It can be represented
// by a matrix A whose entries are the partial derivatives of the components of f
@@ -693,15 +1494,12 @@
// if you have a "good enough" initial guess.
-#define JACOBIAN_EPSILON 0.001
+#define JACOBIAN_EPSILON 0.001f
#define INVERSION_MAX_ITERATIONS 30
-
-
// Increment with reflexion on boundary
-
static
-void IncDelta(double *Val)
+void IncDelta(cmsFloat32Number *Val)
{
if (*Val < (1.0 - JACOBIAN_EPSILON))
@@ -714,159 +1512,131 @@
+// Euclidean distance between two vectors of n elements each one
static
-void ToEncoded(WORD Encoded[3], LPVEC3 Float)
-{
- Encoded[0] = (WORD) floor(Float->n[0] * 65535.0 + 0.5);
- Encoded[1] = (WORD) floor(Float->n[1] * 65535.0 + 0.5);
- Encoded[2] = (WORD) floor(Float->n[2] * 65535.0 + 0.5);
-}
-
-static
-void FromEncoded(LPVEC3 Float, WORD Encoded[3])
+cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n)
{
- Float->n[0] = Encoded[0] / 65535.0;
- Float->n[1] = Encoded[1] / 65535.0;
- Float->n[2] = Encoded[2] / 65535.0;
-}
-
-// Evaluates the CLUT part of a LUT (4 -> 3 only)
-static
-void EvalLUTdoubleKLab(LPLUT Lut, const VEC3* In, WORD FixedK, LPcmsCIELab Out)
-{
- WORD wIn[4], wOut[3];
-
- wIn[0] = (WORD) floor(In ->n[0] * 65535.0 + 0.5);
- wIn[1] = (WORD) floor(In ->n[1] * 65535.0 + 0.5);
- wIn[2] = (WORD) floor(In ->n[2] * 65535.0 + 0.5);
- wIn[3] = FixedK;
+ cmsFloat32Number sum = 0;
+ int i;
- cmsEvalLUT(Lut, wIn, wOut);
- cmsLabEncoded2Float(Out, wOut);
-}
-
-// Builds a Jacobian CMY->Lab
-
-static
-void ComputeJacobianLab(LPLUT Lut, LPMAT3 Jacobian, const VEC3* Colorant, WORD K)
-{
- VEC3 ColorantD;
- cmsCIELab Lab, LabD;
- int j;
-
- EvalLUTdoubleKLab(Lut, Colorant, K, &Lab);
-
+ for (i=0; i < n; i++) {
+ cmsFloat32Number dif = b[i] - a[i];
+ sum += dif * dif;
+ }
- for (j = 0; j < 3; j++) {
-
- ColorantD.n[0] = Colorant ->n[0];
- ColorantD.n[1] = Colorant ->n[1];
- ColorantD.n[2] = Colorant ->n[2];
-
- IncDelta(&ColorantD.n[j]);
-
- EvalLUTdoubleKLab(Lut, &ColorantD, K, &LabD);
-
- Jacobian->v[0].n[j] = ((LabD.L - Lab.L) / JACOBIAN_EPSILON);
- Jacobian->v[1].n[j] = ((LabD.a - Lab.a) / JACOBIAN_EPSILON);
- Jacobian->v[2].n[j] = ((LabD.b - Lab.b) / JACOBIAN_EPSILON);
-
- }
+ return sqrtf(sum);
}
-// Evaluate a LUT in reverse direction. It only searches on 3->3 LUT, but It
-// can be used on CMYK -> Lab LUT to obtain black preservation.
-// Target holds LabK in this case
-
+// Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method
+//
// x1 <- x - [J(x)]^-1 * f(x)
-
+//
+// lut: The LUT on where to do the search
+// Target: LabK, 3 values of Lab plus destination K which is fixed
+// Result: The obtained CMYK
+// Hint: Location where begin the search
-LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Result[], LPWORD Hint)
+cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
+ cmsFloat32Number Result[],
+ cmsFloat32Number Hint[],
+ const cmsPipeline* lut)
{
- int i;
- double error, LastError = 1E20;
- cmsCIELab fx, Goal;
- VEC3 tmp, tmp2, x;
- MAT3 Jacobian;
- WORD FixedK;
- WORD LastResult[4];
+ cmsUInt32Number i, j;
+ cmsFloat64Number error, LastError = 1E20;
+ cmsFloat32Number fx[4], x[4], xd[4], fxd[4];
+ cmsVEC3 tmp, tmp2;
+ cmsMAT3 Jacobian;
+ cmsFloat64Number LastResult[4];
- // This is our Lab goal
- cmsLabEncoded2Float(&Goal, Target);
-
- // Special case for CMYK->Lab
+ // Only 3->3 and 4->3 are supported
+ if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE;
+ if (lut ->OutputChannels != 3) return FALSE;
- if (Lut ->InputChan == 4)
- FixedK = Target[3];
- else
- FixedK = 0;
-
+ // Mark result of -1
+ LastResult[0] = LastResult[1] = LastResult[2] = -1.0f;
// Take the hint as starting point if specified
-
if (Hint == NULL) {
- // Begin at any point, we choose 1/3 of neutral CMY gray
-
- x.n[0] = x.n[1] = x.n[2] = 0.3;
-
+ // Begin at any point, we choose 1/3 of CMY axis
+ x[0] = x[1] = x[2] = 0.3f;
}
else {
- FromEncoded(&x, Hint);
+ // Only copy 3 channels from hint...
+ for (j=0; j < 3; j++)
+ x[j] = Hint[j];
}
+ // If Lut is 4-dimensions, then grab target[3], which is fixed
+ if (lut ->InputChannels == 4) {
+ x[3] = Target[3];
+ }
+ else x[3] = 0; // To keep lint happy
+
// Iterate
-
for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) {
// Get beginning fx
- EvalLUTdoubleKLab(Lut, &x, FixedK, &fx);
+ cmsPipelineEvalFloat(x, fx, lut);
// Compute error
- error = cmsDeltaE(&fx, &Goal);
+ error = EuclideanDistance(fx, Target, 3);
// If not convergent, return last safe value
if (error >= LastError)
break;
// Keep latest values
- LastError = error;
+ LastError = error;
+ for (j=0; j < lut ->InputChannels; j++)
+ Result[j] = x[j];
+
+ // Found an exact match?
+ if (error <= 0)
+ break;
+
+ // Obtain slope (the Jacobian)
+ for (j = 0; j < 3; j++) {
- ToEncoded(LastResult, &x);
- LastResult[3] = FixedK;
+ xd[0] = x[0];
+ xd[1] = x[1];
+ xd[2] = x[2];
+ xd[3] = x[3]; // Keep fixed channel
+
+ IncDelta(&xd[j]);
- // Obtain slope
- ComputeJacobianLab(Lut, &Jacobian, &x, FixedK);
+ cmsPipelineEvalFloat(xd, fxd, lut);
+
+ Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON);
+ Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON);
+ Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON);
+ }
// Solve system
- tmp2.n[0] = fx.L - Goal.L;
- tmp2.n[1] = fx.a - Goal.a;
- tmp2.n[2] = fx.b - Goal.b;
+ tmp2.n[0] = fx[0] - Target[0];
+ tmp2.n[1] = fx[1] - Target[1];
+ tmp2.n[2] = fx[2] - Target[2];
- if (!MAT3solve(&tmp, &Jacobian, &tmp2))
- break;
+ if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2))
+ return FALSE;
// Move our guess
- x.n[0] -= tmp.n[0];
- x.n[1] -= tmp.n[1];
- x.n[2] -= tmp.n[2];
+ x[0] -= (cmsFloat32Number) tmp.n[0];
+ x[1] -= (cmsFloat32Number) tmp.n[1];
+ x[2] -= (cmsFloat32Number) tmp.n[2];
// Some clipping....
- VEC3saturate(&x);
+ for (j=0; j < 3; j++) {
+ if (x[j] < 0) x[j] = 0;
+ else
+ if (x[j] > 1.0) x[j] = 1.0;
+ }
}
- Result[0] = LastResult[0];
- Result[1] = LastResult[1];
- Result[2] = LastResult[2];
- Result[3] = LastResult[3];
-
- return LastError;
-
+ return TRUE;
}
-
-
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c Wed Jul 05 17:21:58 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,411 +0,0 @@
-/*
- * 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// This file is available under and governed by the GNU General Public
-// License version 2 only, as published by the Free Software Foundation.
-// However, the following notice accompanied the original version of this
-// file:
-//
-//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software
-// is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-
-// Shaper/Matrix handling
-// This routines handles the matrix-shaper method. A note about domain
-// is here required. If the shaper-matrix is invoked on INPUT profiles,
-// after the shaper process, we have a value between 0 and 0xFFFF. Thus,
-// for proper matrix handling, we must convert it to 15fix16, so
-// ToFixedDomain might be called. But cmsLinearInterpFixed() returns
-// data yet in fixed point, so no additional process is required.
-// Then, we obtain data on 15.16, so we need to shift >> by 1 to
-// obtain 1.15 PCS format.
-
-// On OUTPUT profiles, things are inverse, we must first expand 1 bit
-// by shifting left, and then convert result between 0 and 1.000 to
-// RGB, so FromFixedDomain() must be called before pass values to
-// shaper. Trickly, there is a situation where this shifts works
-// little different. Sometimes, lcms smelts input/output
-// matrices into a single, one shaper, process. In such cases, since
-// input is encoded from 0 to 0xffff, we must first use the shaper and
-// then the matrix, an additional FromFixedDomain() must be used to
-// accomodate output values.
-
-// For a sake of simplicity, I will handle this three behaviours
-// with different routines, so the flags MATSHAPER_INPUT and MATSHAPER_OUTPUT
-// can be conbined to signal smelted matrix-shapers
-
-
-
-static
-int ComputeTables(LPGAMMATABLE Table[3], LPWORD Out[3], LPL16PARAMS p16)
-{
- int i, AllLinear;
-
- cmsCalcL16Params(Table[0] -> nEntries, p16);
-
- AllLinear = 0;
- for (i=0; i < 3; i++)
- {
- LPWORD PtrW;
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * p16 -> nSamples);
-
- if (PtrW == NULL) return -1; // Signal error
-
- CopyMemory(PtrW, Table[i] -> GammaTable, sizeof(WORD) * Table[i] -> nEntries);
-
- Out[i] = PtrW; // Set table pointer
-
- // Linear after all?
-
- AllLinear += cmsIsLinear(PtrW, p16 -> nSamples);
- }
-
- // If is all linear, then supress table interpolation (this
- // will speed greately some trivial operations.
- // Return 1 if present, 0 if all linear
-
-
- if (AllLinear != 3) return 1;
-
- return 0;
-
-}
-
-
-LPMATSHAPER cmsAllocMatShaper2(LPMAT3 Matrix, LPGAMMATABLE In[], LPGAMMATABLE Out[], DWORD Behaviour)
-{
- LPMATSHAPER NewMatShaper;
- int rc;
-
- NewMatShaper = (LPMATSHAPER) _cmsMalloc(sizeof(MATSHAPER));
- if (NewMatShaper)
- ZeroMemory(NewMatShaper, sizeof(MATSHAPER));
-
- NewMatShaper->dwFlags = Behaviour & (MATSHAPER_ALLSMELTED);
-
- // Fill matrix part
-
- MAT3toFix(&NewMatShaper -> Matrix, Matrix);
-
- // Reality check
-
- if (!MAT3isIdentity(&NewMatShaper -> Matrix, 0.00001))
- NewMatShaper -> dwFlags |= MATSHAPER_HASMATRIX;
-
- // Now, on the table characteristics
-
- if (Out) {
-
- rc = ComputeTables(Out, NewMatShaper ->L, &NewMatShaper ->p16);
- if (rc < 0) {
- cmsFreeMatShaper(NewMatShaper);
- return NULL;
- }
- if (rc == 1) NewMatShaper -> dwFlags |= MATSHAPER_HASSHAPER;
- }
-
-
- if (In) {
-
- rc = ComputeTables(In, NewMatShaper ->L2, &NewMatShaper ->p2_16);
- if (rc < 0) {
- cmsFreeMatShaper(NewMatShaper);
- return NULL;
- }
- if (rc == 1) NewMatShaper -> dwFlags |= MATSHAPER_HASINPSHAPER;
- }
-
-
- return NewMatShaper;
-
-}
-
-
-
-// Creation & Destruction
-
-LPMATSHAPER cmsAllocMatShaper(LPMAT3 Matrix, LPGAMMATABLE Tables[], DWORD Behaviour)
-{
- LPMATSHAPER NewMatShaper;
- int i, AllLinear;
-
- if (Matrix == NULL) return NULL;
- for (i=0; i < 3; i++) {
-
- if (Tables[i] == NULL) return NULL;
- }
-
- NewMatShaper = (LPMATSHAPER) _cmsMalloc(sizeof(MATSHAPER));
- if (NewMatShaper)
- ZeroMemory(NewMatShaper, sizeof(MATSHAPER));
-
- NewMatShaper->dwFlags = Behaviour & (MATSHAPER_ALLSMELTED);
-
- // Fill matrix part
-
- MAT3toFix(&NewMatShaper -> Matrix, Matrix);
-
- // Reality check
-
- if (!MAT3isIdentity(&NewMatShaper -> Matrix, 0.00001))
- NewMatShaper -> dwFlags |= MATSHAPER_HASMATRIX;
-
- // Now, on the table characteristics
- cmsCalcL16Params(Tables[0] -> nEntries, &NewMatShaper -> p16);
-
- // Copy tables
-
- AllLinear = 0;
- for (i=0; i < 3; i++) {
-
- LPWORD PtrW;
-
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * NewMatShaper -> p16.nSamples);
-
- if (PtrW == NULL) {
- cmsFreeMatShaper(NewMatShaper);
- return NULL;
- }
-
- CopyMemory(PtrW, Tables[i] -> GammaTable,
- sizeof(WORD) * Tables[i] -> nEntries);
-
- NewMatShaper -> L[i] = PtrW; // Set table pointer
-
- // Linear after all?
-
- AllLinear += cmsIsLinear(PtrW, NewMatShaper -> p16.nSamples);
- }
-
- // If is all linear, then supress table interpolation (this
- // will speed greately some trivial operations
-
- if (AllLinear != 3)
- NewMatShaper -> dwFlags |= MATSHAPER_HASSHAPER;
-
- return NewMatShaper;
-}
-
-
-
-// Free associated memory
-
-void cmsFreeMatShaper(LPMATSHAPER MatShaper)
-{
- int i;
-
- if (!MatShaper) return;
-
- for (i=0; i < 3; i++)
- {
- if (MatShaper -> L[i]) _cmsFree(MatShaper ->L[i]);
- if (MatShaper -> L2[i]) _cmsFree(MatShaper ->L2[i]);
- }
-
- _cmsFree(MatShaper);
-}
-
-
-// All smelted must postpose gamma to last stage.
-
-static
-void AllSmeltedBehaviour(LPMATSHAPER MatShaper, WORD In[], WORD Out[])
-{
-
- WORD tmp[3];
- WVEC3 InVect, OutVect;
-
- if (MatShaper -> dwFlags & MATSHAPER_HASINPSHAPER)
- {
- InVect.n[VX] = cmsLinearInterpFixed(In[0], MatShaper -> L2[0], &MatShaper -> p2_16);
- InVect.n[VY] = cmsLinearInterpFixed(In[1], MatShaper -> L2[1], &MatShaper -> p2_16);
- InVect.n[VZ] = cmsLinearInterpFixed(In[2], MatShaper -> L2[2], &MatShaper -> p2_16);
- }
- else
- {
- InVect.n[VX] = ToFixedDomain(In[0]);
- InVect.n[VY] = ToFixedDomain(In[1]);
- InVect.n[VZ] = ToFixedDomain(In[2]);
- }
-
-
- if (MatShaper -> dwFlags & MATSHAPER_HASMATRIX)
- {
-
- MAT3evalW(&OutVect, &MatShaper -> Matrix, &InVect);
- }
- else {
-
- OutVect.n[VX] = InVect.n[VX];
- OutVect.n[VY] = InVect.n[VY];
- OutVect.n[VZ] = InVect.n[VZ];
- }
-
-
- tmp[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX]));
- tmp[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY]));
- tmp[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ]));
-
-
-
- if (MatShaper -> dwFlags & MATSHAPER_HASSHAPER)
- {
- Out[0] = cmsLinearInterpLUT16(tmp[0], MatShaper -> L[0], &MatShaper -> p16);
- Out[1] = cmsLinearInterpLUT16(tmp[1], MatShaper -> L[1], &MatShaper -> p16);
- Out[2] = cmsLinearInterpLUT16(tmp[2], MatShaper -> L[2], &MatShaper -> p16);
- }
- else
- {
- Out[0] = tmp[0];
- Out[1] = tmp[1];
- Out[2] = tmp[2];
- }
-
-}
-
-
-static
-void InputBehaviour(LPMATSHAPER MatShaper, WORD In[], WORD Out[])
-{
- WVEC3 InVect, OutVect;
-
-
- if (MatShaper -> dwFlags & MATSHAPER_HASSHAPER)
- {
- InVect.n[VX] = cmsLinearInterpFixed(In[0], MatShaper -> L[0], &MatShaper -> p16);
- InVect.n[VY] = cmsLinearInterpFixed(In[1], MatShaper -> L[1], &MatShaper -> p16);
- InVect.n[VZ] = cmsLinearInterpFixed(In[2], MatShaper -> L[2], &MatShaper -> p16);
- }
- else
- {
- InVect.n[VX] = ToFixedDomain(In[0]);
- InVect.n[VY] = ToFixedDomain(In[1]);
- InVect.n[VZ] = ToFixedDomain(In[2]);
- }
-
- if (MatShaper -> dwFlags & MATSHAPER_HASMATRIX)
- {
- MAT3evalW(&OutVect, &MatShaper -> Matrix, &InVect);
- }
- else
- {
- OutVect = InVect;
- }
-
- // PCS in 1Fixed15 format, adjusting
-
- Out[0] = _cmsClampWord((OutVect.n[VX]) >> 1);
- Out[1] = _cmsClampWord((OutVect.n[VY]) >> 1);
- Out[2] = _cmsClampWord((OutVect.n[VZ]) >> 1);
-
-}
-
-
-static
-void OutputBehaviour(LPMATSHAPER MatShaper, WORD In[], WORD Out[])
-{
- WVEC3 InVect, OutVect;
- int i;
-
- // We need to convert from XYZ to RGB, here we must
- // shift << 1 to pass between 1.15 to 15.16 formats
-
- InVect.n[VX] = (Fixed32) In[0] << 1;
- InVect.n[VY] = (Fixed32) In[1] << 1;
- InVect.n[VZ] = (Fixed32) In[2] << 1;
-
- if (MatShaper -> dwFlags & MATSHAPER_HASMATRIX)
- {
- MAT3evalW(&OutVect, &MatShaper -> Matrix, &InVect);
- }
- else
- {
- OutVect = InVect;
- }
-
-
- if (MatShaper -> dwFlags & MATSHAPER_HASSHAPER)
- {
- for (i=0; i < 3; i++)
- {
-
- Out[i] = cmsLinearInterpLUT16(
- _cmsClampWord(FromFixedDomain(OutVect.n[i])),
- MatShaper -> L[i],
- &MatShaper ->p16);
- }
- }
- else
- {
- // Result from fixed domain to RGB
-
- Out[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX]));
- Out[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY]));
- Out[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ]));
- }
-
-}
-
-
-// Master on evaluating shapers, 3 different behaviours
-
-void cmsEvalMatShaper(LPMATSHAPER MatShaper, WORD In[], WORD Out[])
-{
-
- if ((MatShaper -> dwFlags & MATSHAPER_ALLSMELTED) == MATSHAPER_ALLSMELTED)
- {
- AllSmeltedBehaviour(MatShaper, In, Out);
- return;
- }
- if (MatShaper -> dwFlags & MATSHAPER_INPUT)
- {
- InputBehaviour(MatShaper, In, Out);
- return;
- }
-
- OutputBehaviour(MatShaper, In, Out);
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,346 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+
+
+#include "lcms2_internal.h"
+
+#ifdef CMS_USE_BIG_ENDIAN
+
+static
+void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs)
+{
+ do {
+
+ cmsUInt32Number t = _cmsAdjustEndianess32(*(cmsUInt32Number *) buf);
+ *(cmsUInt32Number *) buf = t;
+ buf += sizeof(cmsUInt32Number);
+
+ } while (--longs);
+
+}
+
+#else
+#define byteReverse(buf, len)
+#endif
+
+
+typedef struct {
+
+ cmsUInt32Number buf[4];
+ cmsUInt32Number bits[2];
+ cmsUInt8Number in[64];
+ cmsContext ContextID;
+
+} _cmsMD5;
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+
+static
+void MD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16])
+
+{
+ register cmsUInt32Number a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+
+// Create a MD5 object
+static
+cmsHANDLE MD5alloc(cmsContext ContextID)
+{
+ _cmsMD5* ctx = (_cmsMD5*) _cmsMallocZero(ContextID, sizeof(_cmsMD5));
+ if (ctx == NULL) return NULL;
+
+ ctx ->ContextID = ContextID;
+
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+
+ return (cmsHANDLE) ctx;
+}
+
+
+static
+void MD5add(cmsHANDLE Handle, cmsUInt8Number* buf, cmsUInt32Number len)
+{
+ _cmsMD5* ctx = (_cmsMD5*) Handle;
+ cmsUInt32Number t;
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + (len << 3)) < t)
+ ctx->bits[1]++;
+
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f;
+
+ if (t) {
+
+ cmsUInt8Number *p = (cmsUInt8Number *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memmove(p, buf, len);
+ return;
+ }
+
+ memmove(p, buf, t);
+ byteReverse(ctx->in, 16);
+
+ MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ memmove(ctx->in, buf, len);
+}
+
+// Destroy the object and return the checksum
+static
+void MD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle)
+{
+ _cmsMD5* ctx = (_cmsMD5*) Handle;
+ cmsUInt32Number count;
+ cmsUInt8Number *p;
+
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ count = 64 - 1 - count;
+
+ if (count < 8) {
+
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
+
+ memset(ctx->in, 0, 56);
+ } else {
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ ((cmsUInt32Number *) ctx->in)[14] = ctx->bits[0];
+ ((cmsUInt32Number *) ctx->in)[15] = ctx->bits[1];
+
+ MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
+
+ byteReverse((cmsUInt8Number *) ctx->buf, 4);
+ memmove(ProfileID ->ID8, ctx->buf, 16);
+
+ _cmsFree(ctx ->ContextID, ctx);
+}
+
+
+
+// Assuming io points to an ICC profile, compute and store MD5 checksum
+// In the header, rendering intentent, attributes and ID should be set to zero
+// before computing MD5 checksum (per 6.1.13 in ICC spec)
+
+cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile)
+{
+ cmsContext ContextID;
+ cmsUInt32Number BytesNeeded;
+ cmsUInt8Number* Mem = NULL;
+ cmsHANDLE MD5 = NULL;
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
+ _cmsICCPROFILE Keep;
+
+ _cmsAssert(hProfile != NULL);
+
+ ContextID = cmsGetProfileContextID(hProfile);
+
+ // Save a copy of the profile header
+ memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
+
+ // Set RI, attributes and ID
+ memset(&Icc ->attributes, 0, sizeof(Icc ->attributes));
+ Icc ->RenderingIntent = 0;
+ memset(&Icc ->ProfileID, 0, sizeof(Icc ->ProfileID));
+
+ // Compute needed storage
+ if (!cmsSaveProfileToMem(hProfile, NULL, &BytesNeeded)) goto Error;
+
+ // Allocate memory
+ Mem = (cmsUInt8Number*) _cmsMalloc(ContextID, BytesNeeded);
+ if (Mem == NULL) goto Error;
+
+ // Save to temporary storage
+ if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error;
+
+ // Create MD5 object
+ MD5 = MD5alloc(ContextID);
+ if (MD5 == NULL) goto Error;
+
+ // Add all bytes
+ MD5add(MD5, Mem, BytesNeeded);
+
+ // Temp storage is no longer needed
+ _cmsFree(ContextID, Mem);
+
+ // Restore header
+ memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
+
+ // And store the ID
+ MD5finish(&Icc ->ProfileID, MD5);
+ return TRUE;
+
+Error:
+
+ // Free resources as something went wrong
+ if (MD5 != NULL) _cmsFree(ContextID, MD5);
+ if (Mem != NULL) _cmsFree(ContextID, Mem);
+ memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
+ return FALSE;
+}
+
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,447 +49,105 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// Vector & Matrix stuff
-
-#include "lcms.h"
-
-
-void cdecl VEC3init(LPVEC3 r, double x, double y, double z);
-void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z);
-void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v);
-void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale);
-void cdecl VEC3swap(LPVEC3 a, LPVEC3 b);
-void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d);
-void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d);
-void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b);
-void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b);
-void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d);
-void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v);
-void cdecl VEC3saturate(LPVEC3 v);
-
-double cdecl VEC3length(LPVEC3 a);
-double cdecl VEC3distance(LPVEC3 a, LPVEC3 b);
-
-
-void cdecl MAT3identity(LPMAT3 a);
-void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b);
-int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b);
-LCMSBOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b);
-double cdecl MAT3det(LPMAT3 m);
-void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v);
-void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v);
-void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v);
-void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d);
-void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d);
+//
+//---------------------------------------------------------------------------------
+//
-// --------------------- Implementation ----------------------------
-
-#define DSWAP(x, y) {double tmp = (x); (x)=(y); (y)=tmp;}
-
-
-
-#ifdef USE_ASSEMBLER
-
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4033)
-#pragma warning(disable : 4035)
-#endif
-
-
-
-Fixed32 FixedMul(Fixed32 a, Fixed32 b)
-{
- ASM {
-
- mov eax, ss:a
- mov edx, ss:b
- imul edx
- add eax, 0x8000
- adc edx, 0
- shrd eax, edx, 16
-
- }
-
- RET(_EAX);
-}
-
-
+#include "lcms2_internal.h"
-Fixed32 FixedSquare(Fixed32 a)
-{
- ASM {
- pushf
- push edx
- mov eax, ss:a
- imul eax
- add eax, 0x8000
- adc edx, 0
- shrd eax, edx, 16
- sar eax, 16
- pop edx
- popf
- }
-
- RET(_EAX);
-}
-
-
-
-
-// Linear intERPolation
-// a * (h - l) >> 16 + l
-
-Fixed32 FixedLERP(Fixed32 a, Fixed32 l, Fixed32 h)
-{
- ASM {
- mov eax, dword ptr ss:h
- mov edx, dword ptr ss:l
- push edx
- mov ecx, dword ptr ss:a
- sub eax, edx
- imul ecx
- add eax, 0x8000
- adc edx, 0
- shrd eax, edx, 16
- pop edx
- add eax, edx
- }
-
- RET(_EAX);
-}
-
-
-// a as word is scaled by s as float
-
-WORD FixedScale(WORD a, Fixed32 s)
-{
- ASM {
-
- xor eax,eax
- mov ax, ss:a // This is faster that movzx eax, ss:a
- sal eax, 16
- mov edx, ss:s
- mul edx
- add eax, 0x8000
- adc edx, 0
- mov eax, edx
- }
-
- RET(_EAX);
-}
-
-#ifdef _MSC_VER
-#pragma warning(default : 4033)
-#pragma warning(default : 4035)
-#endif
-
-#else
+#define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;}
-// These are floating point versions for compilers that doesn't
-// support asm at all. Use with care, since this will slow down
-// all operations
-
-
-Fixed32 FixedMul(Fixed32 a, Fixed32 b)
-{
-#ifdef USE_INT64
- LCMSULONGLONG l = (LCMSULONGLONG) (LCMSSLONGLONG) a * (LCMSULONGLONG) (LCMSSLONGLONG) b + (LCMSULONGLONG) 0x8000;
- l >>= 16;
- return (Fixed32) l;
-#else
- return DOUBLE_TO_FIXED(FIXED_TO_DOUBLE(a) * FIXED_TO_DOUBLE(b));
-#endif
-}
-
-Fixed32 FixedSquare(Fixed32 a)
-{
- return FixedMul(a, a);
-}
-
-
-Fixed32 FixedLERP(Fixed32 a, Fixed32 l, Fixed32 h)
+// Initiate a vector
+void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z)
{
-#ifdef USE_INT64
-
- LCMSULONGLONG dif = (LCMSULONGLONG) (h - l) * a + 0x8000;
- dif = (dif >> 16) + l;
- return (Fixed32) (dif);
-#else
- double dif = h - l;
-
- dif *= a;
- dif /= 65536.0;
- dif += l;
-
- return (Fixed32) (dif + 0.5);
-#endif
-
-}
-
-
-WORD FixedScale(WORD a, Fixed32 s)
-{
- return (WORD) (a * FIXED_TO_DOUBLE(s));
-}
-
-#endif
-
-
-#ifndef USE_INLINE
-
-Fixed32 ToFixedDomain(int a)
-{
- return a + ((a + 0x7fff) / 0xffff);
-}
-
-
-int FromFixedDomain(Fixed32 a)
-{
- return a - ((a + 0x7fff) >> 16);
+ r -> n[VX] = x;
+ r -> n[VY] = y;
+ r -> n[VZ] = z;
}
-#endif
-
-
-
-// Initiate a vector (double version)
-
-
-void VEC3init(LPVEC3 r, double x, double y, double z)
-{
- r -> n[VX] = x;
- r -> n[VY] = y;
- r -> n[VZ] = z;
-}
-
-// Init a vector (fixed version)
-
-void VEC3initF(LPWVEC3 r, double x, double y, double z)
-{
- r -> n[VX] = DOUBLE_TO_FIXED(x);
- r -> n[VY] = DOUBLE_TO_FIXED(y);
- r -> n[VZ] = DOUBLE_TO_FIXED(z);
-}
-
-
-// Convert to fixed point encoding is 1.0 = 0xFFFF
-
-void VEC3toFix(LPWVEC3 r, LPVEC3 v)
-{
- r -> n[VX] = DOUBLE_TO_FIXED(v -> n[VX]);
- r -> n[VY] = DOUBLE_TO_FIXED(v -> n[VY]);
- r -> n[VZ] = DOUBLE_TO_FIXED(v -> n[VZ]);
-}
-
-// Convert from fixed point
-
-void VEC3fromFix(LPVEC3 r, LPWVEC3 v)
-{
- r -> n[VX] = FIXED_TO_DOUBLE(v -> n[VX]);
- r -> n[VY] = FIXED_TO_DOUBLE(v -> n[VY]);
- r -> n[VZ] = FIXED_TO_DOUBLE(v -> n[VZ]);
-}
-
-
-// Swap two double vectors
-
-void VEC3swap(LPVEC3 a, LPVEC3 b)
-{
- DSWAP(a-> n[VX], b-> n[VX]);
- DSWAP(a-> n[VY], b-> n[VY]);
- DSWAP(a-> n[VZ], b-> n[VZ]);
-}
-
-// Divide a vector by a constant
-
-void VEC3divK(LPVEC3 r, LPVEC3 v, double d)
-{
- double d_inv = 1./d;
-
- r -> n[VX] = v -> n[VX] * d_inv;
- r -> n[VY] = v -> n[VY] * d_inv;
- r -> n[VZ] = v -> n[VZ] * d_inv;
-}
-
-// Multiply by a constant
-
-void VEC3perK(LPVEC3 r, LPVEC3 v, double d )
-{
- r -> n[VX] = v -> n[VX] * d;
- r -> n[VY] = v -> n[VY] * d;
- r -> n[VZ] = v -> n[VZ] * d;
-}
-
-
-void VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b)
-{
- r -> n[VX] = a->n[VX]*b->n[VX];
- r -> n[VY] = a->n[VY]*b->n[VY];
- r -> n[VZ] = a->n[VZ]*b->n[VZ];
-}
-
-// Minus
-
-
-void VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b)
+// Vector substraction
+void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b)
{
r -> n[VX] = a -> n[VX] - b -> n[VX];
r -> n[VY] = a -> n[VY] - b -> n[VY];
r -> n[VZ] = a -> n[VZ] - b -> n[VZ];
}
-
-// Check id two vectors are the same, allowing tolerance
-
-static
-LCMSBOOL RangeCheck(double l, double h, double v)
-{
- return (v >= l && v <= h);
-}
-
-
-LCMSBOOL VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance)
-{
- int i;
- double c;
-
- for (i=0; i < 3; i++)
- {
- c = FIXED_TO_DOUBLE(a -> n[i]);
- if (!RangeCheck(c - Tolerance,
- c + Tolerance,
- FIXED_TO_DOUBLE(b->n[i]))) return FALSE;
- }
-
- return TRUE;
-}
-
-LCMSBOOL VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance)
+// Vector cross product
+void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v)
{
- int i;
- double c;
-
- for (i=0; i < 3; i++)
- {
- c = a -> n[i];
- if (!RangeCheck(c - Tolerance,
- c + Tolerance,
- b->n[i])) return FALSE;
- }
-
- return TRUE;
-}
-
-
-void VEC3scaleFix(LPWORD r, LPWVEC3 Scale)
-{
- if (Scale -> n[VX] == 0x00010000L &&
- Scale -> n[VY] == 0x00010000L &&
- Scale -> n[VZ] == 0x00010000L) return;
-
- r[0] = (WORD) FixedScale(r[0], Scale -> n[VX]);
- r[1] = (WORD) FixedScale(r[1], Scale -> n[VY]);
- r[2] = (WORD) FixedScale(r[2], Scale -> n[VZ]);
-
-}
-
-
-
-// Vector cross product
-
-void VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v)
-{
-
r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ];
r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX];
r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY];
}
-
+// Vector dot product
+cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v)
+{
+ return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ];
+}
-// The vector size
-
-double VEC3length(LPVEC3 a)
+// Euclidean length
+cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a)
{
return sqrt(a ->n[VX] * a ->n[VX] +
a ->n[VY] * a ->n[VY] +
a ->n[VZ] * a ->n[VZ]);
}
-
-// Saturate a vector into 0..1.0 range
-
-void VEC3saturate(LPVEC3 v)
+// Euclidean distance
+cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b)
{
- int i;
- for (i=0; i < 3; i++) {
- if (v ->n[i] < 0)
- v ->n[i] = 0;
- else
- if (v ->n[i] > 1.0)
- v ->n[i] = 1.0;
- }
-}
-
-
-// Euclidean distance
-
-double VEC3distance(LPVEC3 a, LPVEC3 b)
-{
- double d1 = a ->n[VX] - b ->n[VX];
- double d2 = a ->n[VY] - b ->n[VY];
- double d3 = a ->n[VZ] - b ->n[VZ];
+ cmsFloat64Number d1 = a ->n[VX] - b ->n[VX];
+ cmsFloat64Number d2 = a ->n[VY] - b ->n[VY];
+ cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ];
return sqrt(d1*d1 + d2*d2 + d3*d3);
}
-// Identity
-
-void MAT3identity(LPMAT3 a)
+// 3x3 Identity
+void CMSEXPORT _cmsMAT3identity(cmsMAT3* a)
{
- VEC3init(&a-> v[0], 1.0, 0.0, 0.0);
- VEC3init(&a-> v[1], 0.0, 1.0, 0.0);
- VEC3init(&a-> v[2], 0.0, 0.0, 1.0);
+ _cmsVEC3init(&a-> v[0], 1.0, 0.0, 0.0);
+ _cmsVEC3init(&a-> v[1], 0.0, 1.0, 0.0);
+ _cmsVEC3init(&a-> v[2], 0.0, 0.0, 1.0);
+}
+
+static
+cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
+{
+ return fabs(b - a) < (1.0 / 65535.0);
}
+cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a)
+{
+ cmsMAT3 Identity;
+ int i, j;
+
+ _cmsMAT3identity(&Identity);
+
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE;
+
+ return TRUE;
+}
-// Check if matrix is Identity. Allow a tolerance as %
-
-LCMSBOOL MAT3isIdentity(LPWMAT3 a, double Tolerance)
-{
- int i;
- MAT3 Idd;
- WMAT3 Idf;
-
- MAT3identity(&Idd);
- MAT3toFix(&Idf, &Idd);
-
- for (i=0; i < 3; i++)
- if (!VEC3equal(&a -> v[i], &Idf.v[i], Tolerance)) return FALSE;
-
- return TRUE;
-
-}
-
// Multiply two matrices
-
-
-void MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b)
+void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b)
{
#define ROWCOL(i, j) \
a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j]
- VEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2));
- VEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2));
- VEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2));
+ _cmsVEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2));
+ _cmsVEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2));
+ _cmsVEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2));
#undef ROWCOL //(i, j)
}
@@ -496,350 +155,50 @@
// Inverse of a matrix b = a^(-1)
-// Gauss-Jordan elimination with partial pivoting
-
-int MAT3inverse(LPMAT3 a, LPMAT3 b)
+cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b)
{
- register int i, j, max;
-
- MAT3identity(b);
+ cmsFloat64Number det, c0, c1, c2;
- // Loop over cols of a from left to right, eliminating above and below diag
- for (j=0; j<3; j++) { // Find largest pivot in column j among rows j..2
+ c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1];
+ c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0];
+ c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0];
- max = j; // Row with largest pivot candidate
- for (i=j+1; i<3; i++)
- if (fabs(a -> v[i].n[j]) > fabs(a -> v[max].n[j]))
- max = i;
+ det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2;
- // Swap rows max and j in a and b to put pivot on diagonal
-
- VEC3swap(&a -> v[max], &a -> v[j]);
- VEC3swap(&b -> v[max], &b -> v[j]);
+ if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert
- // Scale row j to have a unit diagonal
-
- if (a -> v[j].n[j]==0.)
- return -1; // singular matrix; can't invert
-
- VEC3divK(&b-> v[j], &b -> v[j], a->v[j].n[j]);
- VEC3divK(&a-> v[j], &a -> v[j], a->v[j].n[j]);
-
- // Eliminate off-diagonal elems in col j of a, doing identical ops to b
- for (i=0; i<3; i++)
+ b -> v[0].n[0] = c0/det;
+ b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det;
+ b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det;
+ b -> v[1].n[0] = c1/det;
+ b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det;
+ b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det;
+ b -> v[2].n[0] = c2/det;
+ b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det;
+ b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det;
- if (i !=j) {
- VEC3 temp;
-
- VEC3perK(&temp, &b -> v[j], a -> v[i].n[j]);
- VEC3minus(&b -> v[i], &b -> v[i], &temp);
-
- VEC3perK(&temp, &a -> v[j], a -> v[i].n[j]);
- VEC3minus(&a -> v[i], &a -> v[i], &temp);
- }
- }
-
- return 1;
+ return TRUE;
}
// Solve a system in the form Ax = b
-
-LCMSBOOL MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b)
+cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b)
{
- MAT3 m, a_1;
+ cmsMAT3 m, a_1;
- CopyMemory(&m, a, sizeof(MAT3));
+ memmove(&m, a, sizeof(cmsMAT3));
- if (!MAT3inverse(&m, &a_1)) return FALSE; // Singular matrix
+ if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix
- MAT3eval(x, &a_1, b);
+ _cmsMAT3eval(x, &a_1, b);
return TRUE;
}
-
-// The determinant
-
-double MAT3det(LPMAT3 m)
-{
-
- double a1 = m ->v[VX].n[VX];
- double a2 = m ->v[VX].n[VY];
- double a3 = m ->v[VX].n[VZ];
- double b1 = m ->v[VY].n[VX];
- double b2 = m ->v[VY].n[VY];
- double b3 = m ->v[VY].n[VZ];
- double c1 = m ->v[VZ].n[VX];
- double c2 = m ->v[VZ].n[VY];
- double c3 = m ->v[VZ].n[VZ];
-
-
- return a1*b2*c3 - a1*b3*c2 + a2*b3*c1 - a2*b1*c3 - a3*b1*c2 - a3*b2*c1;
-}
-
-
-// linear transform
-
-
-void MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v)
+// Evaluate a vector across a matrix
+void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v)
{
r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ];
r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ];
r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ];
}
-
-// Ok, this is another bottleneck of performance.
-
-
-#ifdef USE_ASSEMBLER
-
-// ecx:ebx is result in 64 bits format
-// edi points to matrix, esi points to input vector
-// since only 3 accesses are in output, this is a stack variable
-
-
-void MAT3evalW(LPWVEC3 r_, LPWMAT3 a_, LPWVEC3 v_)
-{
-
- ASM {
-
-
- mov esi, dword ptr ss:v_
- mov edi, dword ptr ss:a_
-
- // r->n[VX] = FixedMul(a->v[0].n[0], v->n[0]) +
-
- mov eax,dword ptr [esi]
- mov edx,dword ptr [edi]
- imul edx
- mov ecx, eax
- mov ebx, edx
-
- // FixedMul(a->v[0].n[1], v->n[1]) +
-
- mov eax,dword ptr [esi+4]
- mov edx,dword ptr [edi+4]
- imul edx
- add ecx, eax
- adc ebx, edx
-
- // FixedMul(a->v[0].n[2], v->n[2]);
-
- mov eax,dword ptr [esi+8]
- mov edx,dword ptr [edi+8]
- imul edx
- add ecx, eax
- adc ebx, edx
-
- // Back to Fixed 15.16
-
- add ecx, 0x8000
- adc ebx, 0
- shrd ecx, ebx, 16
-
- push edi
- mov edi, dword ptr ss:r_
- mov dword ptr [edi], ecx // r -> n[VX]
- pop edi
-
-
-
- // 2nd row ***************************
-
- // FixedMul(a->v[1].n[0], v->n[0])
-
- mov eax,dword ptr [esi]
- mov edx,dword ptr [edi+12]
- imul edx
- mov ecx, eax
- mov ebx, edx
-
- // FixedMul(a->v[1].n[1], v->n[1]) +
-
- mov eax,dword ptr [esi+4]
- mov edx,dword ptr [edi+16]
- imul edx
- add ecx, eax
- adc ebx, edx
-
- // FixedMul(a->v[1].n[2], v->n[2]);
-
- mov eax,dword ptr [esi+8]
- mov edx,dword ptr [edi+20]
- imul edx
- add ecx, eax
- adc ebx, edx
-
- add ecx, 0x8000
- adc ebx, 0
- shrd ecx, ebx, 16
-
- push edi
- mov edi, dword ptr ss:r_
- mov dword ptr [edi+4], ecx // r -> n[VY]
- pop edi
-
-// 3d row **************************
-
- // r->n[VZ] = FixedMul(a->v[2].n[0], v->n[0]) +
-
- mov eax,dword ptr [esi]
- mov edx,dword ptr [edi+24]
- imul edx
- mov ecx, eax
- mov ebx, edx
-
- // FixedMul(a->v[2].n[1], v->n[1]) +
-
- mov eax,dword ptr [esi+4]
- mov edx,dword ptr [edi+28]
- imul edx
- add ecx, eax
- adc ebx, edx
-
- // FixedMul(a->v[2].n[2], v->n[2]);
-
- mov eax,dword ptr [esi+8]
- mov edx,dword ptr [edi+32]
- imul edx
- add ecx, eax
- adc ebx, edx
-
- add ecx, 0x8000
- adc ebx, 0
- shrd ecx, ebx, 16
-
- mov edi, dword ptr ss:r_
- mov dword ptr [edi+8], ecx // r -> n[VZ]
- }
-}
-
-
-#else
-
-
-#ifdef USE_FLOAT
-
-void MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v)
-{
- r->n[VX] = DOUBLE_TO_FIXED(
- FIXED_TO_DOUBLE(a->v[0].n[0]) * FIXED_TO_DOUBLE(v->n[0]) +
- FIXED_TO_DOUBLE(a->v[0].n[1]) * FIXED_TO_DOUBLE(v->n[1]) +
- FIXED_TO_DOUBLE(a->v[0].n[2]) * FIXED_TO_DOUBLE(v->n[2])
- );
-
- r->n[VY] = DOUBLE_TO_FIXED(
- FIXED_TO_DOUBLE(a->v[1].n[0]) * FIXED_TO_DOUBLE(v->n[0]) +
- FIXED_TO_DOUBLE(a->v[1].n[1]) * FIXED_TO_DOUBLE(v->n[1]) +
- FIXED_TO_DOUBLE(a->v[1].n[2]) * FIXED_TO_DOUBLE(v->n[2])
- );
-
- r->n[VZ] = DOUBLE_TO_FIXED(
- FIXED_TO_DOUBLE(a->v[2].n[0]) * FIXED_TO_DOUBLE(v->n[0]) +
- FIXED_TO_DOUBLE(a->v[2].n[1]) * FIXED_TO_DOUBLE(v->n[1]) +
- FIXED_TO_DOUBLE(a->v[2].n[2]) * FIXED_TO_DOUBLE(v->n[2])
- );
-}
-
-
-#else
-
-void MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v)
-{
-
-#ifdef USE_INT64
-
- LCMSULONGLONG l1 = (LCMSULONGLONG) (LCMSSLONGLONG) a->v[0].n[0] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[0] +
- (LCMSULONGLONG) (LCMSSLONGLONG) a->v[0].n[1] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[1] +
- (LCMSULONGLONG) (LCMSSLONGLONG) a->v[0].n[2] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[2] + (LCMSULONGLONG) 0x8000;
-
- LCMSULONGLONG l2 = (LCMSULONGLONG) (LCMSSLONGLONG) a->v[1].n[0] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[0] +
- (LCMSULONGLONG) (LCMSSLONGLONG) a->v[1].n[1] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[1] +
- (LCMSULONGLONG) (LCMSSLONGLONG) a->v[1].n[2] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[2] + (LCMSULONGLONG) 0x8000;
-
- LCMSULONGLONG l3 = (LCMSULONGLONG) (LCMSSLONGLONG) a->v[2].n[0] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[0] +
- (LCMSULONGLONG) (LCMSSLONGLONG) a->v[2].n[1] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[1] +
- (LCMSULONGLONG) (LCMSSLONGLONG) a->v[2].n[2] *
- (LCMSULONGLONG) (LCMSSLONGLONG) v->n[2] + (LCMSULONGLONG) 0x8000;
- l1 >>= 16;
- l2 >>= 16;
- l3 >>= 16;
-
- r->n[VX] = (Fixed32) l1;
- r->n[VY] = (Fixed32) l2;
- r->n[VZ] = (Fixed32) l3;
-
-#else
-
- // FIXME: Rounding should be done at very last stage. There is 1-Contone rounding error!
-
- r->n[VX] = FixedMul(a->v[0].n[0], v->n[0]) +
- FixedMul(a->v[0].n[1], v->n[1]) +
- FixedMul(a->v[0].n[2], v->n[2]);
-
- r->n[VY] = FixedMul(a->v[1].n[0], v->n[0]) +
- FixedMul(a->v[1].n[1], v->n[1]) +
- FixedMul(a->v[1].n[2], v->n[2]);
-
- r->n[VZ] = FixedMul(a->v[2].n[0], v->n[0]) +
- FixedMul(a->v[2].n[1], v->n[1]) +
- FixedMul(a->v[2].n[2], v->n[2]);
-#endif
-}
-
-#endif
-#endif
-
-
-void MAT3perK(LPMAT3 r, LPMAT3 v, double d)
-{
- VEC3perK(&r -> v[0], &v -> v[0], d);
- VEC3perK(&r -> v[1], &v -> v[1], d);
- VEC3perK(&r -> v[2], &v -> v[2], d);
-}
-
-
-void MAT3toFix(LPWMAT3 r, LPMAT3 v)
-{
- VEC3toFix(&r -> v[0], &v -> v[0]);
- VEC3toFix(&r -> v[1], &v -> v[1]);
- VEC3toFix(&r -> v[2], &v -> v[2]);
-}
-
-void MAT3fromFix(LPMAT3 r, LPWMAT3 v)
-{
- VEC3fromFix(&r -> v[0], &v -> v[0]);
- VEC3fromFix(&r -> v[1], &v -> v[1]);
- VEC3fromFix(&r -> v[2], &v -> v[2]);
-}
-
-
-
-// Scale v by d and store it in r giving INTEGER
-
-void VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d)
-{
- r -> n[VX] = (int) floor(v -> n[VX] * d + .5);
- r -> n[VY] = (int) floor(v -> n[VY] * d + .5);
- r -> n[VZ] = (int) floor(v -> n[VZ] * d + .5);
-}
-
-void MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d)
-{
- VEC3scaleAndCut(&r -> v[0], &v -> v[0], d);
- VEC3scaleAndCut(&r -> v[1], &v -> v[1], d);
- VEC3scaleAndCut(&r -> v[2], &v -> v[2], d);
-}
-
-
-
-
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,153 +49,725 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+// Multilocalized unicode objects. That is an attempt to encapsulate i18n.
+
+
+// Allocates an empty multi localizad unicode object
+cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)
+{
+ cmsMLU* mlu;
+
+ // nItems should be positive if given
+ if (nItems <= 0) nItems = 2;
+
+ // Create the container
+ mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU));
+ if (mlu == NULL) return NULL;
+
+ mlu ->ContextID = ContextID;
+
+ // Create entry array
+ mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry));
+ if (mlu ->Entries == NULL) {
+ _cmsFree(ContextID, mlu);
+ return NULL;
+ }
+
+ // Ok, keep indexes up to date
+ mlu ->AllocatedEntries = nItems;
+ mlu ->UsedEntries = 0;
+
+ return mlu;
+}
-// Named color support
+// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.
+static
+cmsBool GrowMLUpool(cmsMLU* mlu)
+{
+ cmsUInt32Number size;
+ void *NewPtr;
+
+ // Sanity check
+ if (mlu == NULL) return FALSE;
+
+ if (mlu ->PoolSize == 0)
+ size = 256;
+ else
+ size = mlu ->PoolSize * 2;
+
+ // Check for overflow
+ if (size < mlu ->PoolSize) return FALSE;
+
+ // Reallocate the pool
+ NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size);
+ if (NewPtr == NULL) return FALSE;
+
+
+ mlu ->MemPool = NewPtr;
+ mlu ->PoolSize = size;
-#include "lcms.h"
+ return TRUE;
+}
+
+
+// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two.
+static
+cmsBool GrowMLUtable(cmsMLU* mlu)
+{
+ int AllocatedEntries;
+ _cmsMLUentry *NewPtr;
+
+ // Sanity check
+ if (mlu == NULL) return FALSE;
+ AllocatedEntries = mlu ->AllocatedEntries * 2;
+
+ // Check for overflow
+ if (AllocatedEntries < mlu ->AllocatedEntries) return FALSE;
+
+ // Reallocate the memory
+ NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));
+ if (NewPtr == NULL) return FALSE;
+
+ mlu ->Entries = NewPtr;
+ mlu ->AllocatedEntries = AllocatedEntries;
+
+ return TRUE;
+}
+// Search for a specific entry in the structure. Language and Country are used.
static
-LPcmsNAMEDCOLORLIST GrowNamedColorList(LPcmsNAMEDCOLORLIST v, int ByElements)
+int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
{
- if (ByElements > v ->Allocated) {
+ int i;
+
+ // Sanity check
+ if (mlu == NULL) return -1;
+
+ // Iterate whole table
+ for (i=0; i < mlu ->UsedEntries; i++) {
+
+ if (mlu ->Entries[i].Country == CountryCode &&
+ mlu ->Entries[i].Language == LanguageCode) return i;
+ }
+
+ // Not found
+ return -1;
+}
- LPcmsNAMEDCOLORLIST TheNewList;
- int NewElements;
- size_t size;
+// Add a block of characters to the intended MLU. Language and country are specified.
+// Only one entry for Language/country pair is allowed.
+static
+cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
+ cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
+{
+ cmsUInt32Number Offset;
+ cmsUInt8Number* Ptr;
+
+ // Sanity check
+ if (mlu == NULL) return FALSE;
+
+ // Is there any room available?
+ if (mlu ->UsedEntries >= mlu ->AllocatedEntries) {
+ if (!GrowMLUtable(mlu)) return FALSE;
+ }
+
+ // Only one ASCII string
+ if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed!
+
+ // Check for size
+ while ((mlu ->PoolSize - mlu ->PoolUsed) < size) {
+
+ if (!GrowMLUpool(mlu)) return FALSE;
+ }
+
+ Offset = mlu ->PoolUsed;
+
+ Ptr = (cmsUInt8Number*) mlu ->MemPool;
+ if (Ptr == NULL) return FALSE;
- if (v ->Allocated == 0)
- NewElements = 64; // Initial guess
- else
- NewElements = v ->Allocated;
+ // Set the entry
+ memmove(Ptr + Offset, Block, size);
+ mlu ->PoolUsed += size;
+
+ mlu ->Entries[mlu ->UsedEntries].StrW = Offset;
+ mlu ->Entries[mlu ->UsedEntries].Len = size;
+ mlu ->Entries[mlu ->UsedEntries].Country = CountryCode;
+ mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode;
+ mlu ->UsedEntries++;
+
+ return TRUE;
+}
+
+
+// Add an ASCII entry.
+cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
+{
+ cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1;
+ wchar_t* WStr;
+ cmsBool rc;
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+
+ if (mlu == NULL) return FALSE;
- while (ByElements > NewElements)
- NewElements *= 2;
+ WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t));
+ if (WStr == NULL) return FALSE;
+
+ for (i=0; i < len; i++)
+ WStr[i] = (wchar_t) ASCIIString[i];
+
+ rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
+
+ _cmsFree(mlu ->ContextID, WStr);
+ return rc;
+
+}
- size = sizeof(cmsNAMEDCOLORLIST) + (sizeof(cmsNAMEDCOLOR) * NewElements);
- TheNewList = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size);
+// We don't need any wcs support library
+static
+cmsUInt32Number mywcslen(const wchar_t *s)
+{
+ const wchar_t *p;
+
+ p = s;
+ while (*p)
+ p++;
+
+ return (cmsUInt32Number)(p - s);
+}
- if (TheNewList == NULL) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Out of memory reallocating named color list");
- return NULL;
- }
- else {
- ZeroMemory(TheNewList, size);
- CopyMemory(TheNewList, v, sizeof(cmsNAMEDCOLORLIST) + (v ->nColors - 1) * sizeof(cmsNAMEDCOLOR));
- TheNewList -> Allocated = NewElements;
+// Add a wide entry
+cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString)
+{
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country);
+ cmsUInt32Number len;
+
+ if (mlu == NULL) return FALSE;
+ if (WideString == NULL) return FALSE;
+
+ len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t);
+ return AddMLUBlock(mlu, len, WideString, Lang, Cntry);
+}
+
+// Duplicating a MLU is as easy as copying all members
+cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu)
+{
+ cmsMLU* NewMlu = NULL;
+
+ // Duplicating a NULL obtains a NULL
+ if (mlu == NULL) return NULL;
+
+ NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries);
+ if (NewMlu == NULL) return NULL;
+
+ // Should never happen
+ if (NewMlu ->AllocatedEntries < mlu ->UsedEntries)
+ goto Error;
+
+ // Sanitize...
+ if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error;
+
+ memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry));
+ NewMlu ->UsedEntries = mlu ->UsedEntries;
+
+ // The MLU may be empty
+ if (mlu ->PoolUsed == 0) {
+ NewMlu ->MemPool = NULL;
+ }
+ else {
+ // It is not empty
+ NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed);
+ if (NewMlu ->MemPool == NULL) goto Error;
+ }
+
+ NewMlu ->PoolSize = mlu ->PoolUsed;
+
+ if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error;
+
+ memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed);
+ NewMlu ->PoolUsed = mlu ->PoolUsed;
- _cmsFree(v);
- return TheNewList;
+ return NewMlu;
+
+Error:
+
+ if (NewMlu != NULL) cmsMLUfree(NewMlu);
+ return NULL;
+}
+
+// Free any used memory
+void CMSEXPORT cmsMLUfree(cmsMLU* mlu)
+{
+ if (mlu) {
+
+ if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries);
+ if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool);
+
+ _cmsFree(mlu ->ContextID, mlu);
+ }
+}
+
+
+// The algorithm first searches for an exact match of country and language, if not found it uses
+// the Language. If none is found, first entry is used instead.
+static
+const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
+ cmsUInt32Number *len,
+ cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode,
+ cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)
+{
+ int i;
+ int Best = -1;
+ _cmsMLUentry* v;
+
+ if (mlu == NULL) return NULL;
+
+ if (mlu -> AllocatedEntries <= 0) return NULL;
+
+ for (i=0; i < mlu ->UsedEntries; i++) {
+
+ v = mlu ->Entries + i;
+
+ if (v -> Language == LanguageCode) {
+
+ if (Best == -1) Best = i;
+
+ if (v -> Country == CountryCode) {
+
+ if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
+ if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
+
+ if (len != NULL) *len = v ->Len;
+
+ return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match
+ }
}
}
- return v;
+ // No string found. Return First one
+ if (Best == -1)
+ Best = 0;
+
+ v = mlu ->Entries + Best;
+
+ if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
+ if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
+
+ if (len != NULL) *len = v ->Len;
+
+ return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
}
-LPcmsNAMEDCOLORLIST cmsAllocNamedColorList(int n)
+// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len
+cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ char* Buffer, cmsUInt32Number BufferSize)
{
- size_t size = sizeof(cmsNAMEDCOLORLIST) + (n - 1) * sizeof(cmsNAMEDCOLOR);
+ const wchar_t *Wide;
+ cmsUInt32Number StrLen = 0;
+ cmsUInt32Number ASCIIlen, i;
+
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+
+ // Sanitize
+ if (mlu == NULL) return 0;
+
+ // Get WideChar
+ Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
+ if (Wide == NULL) return 0;
+
+ ASCIIlen = StrLen / sizeof(wchar_t);
+
+ // Maybe we want only to know the len?
+ if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end
+
+ // No buffer size means no data
+ if (BufferSize <= 0) return 0;
+
+ // Some clipping may be required
+ if (BufferSize < ASCIIlen + 1)
+ ASCIIlen = BufferSize - 1;
+
+ // Precess each character
+ for (i=0; i < ASCIIlen; i++) {
+
+ if (Wide[i] == 0)
+ Buffer[i] = 0;
+ else
+ Buffer[i] = (char) Wide[i];
+ }
- LPcmsNAMEDCOLORLIST v = (LPcmsNAMEDCOLORLIST) _cmsMalloc(size);
+ // We put a termination "\0"
+ Buffer[ASCIIlen] = 0;
+ return ASCIIlen + 1;
+}
+
+// Obtain a wide representation of the MLU, on depending on current locale settings
+cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ wchar_t* Buffer, cmsUInt32Number BufferSize)
+{
+ const wchar_t *Wide;
+ cmsUInt32Number StrLen = 0;
+
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+
+ // Sanitize
+ if (mlu == NULL) return 0;
+
+ Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
+ if (Wide == NULL) return 0;
+
+ // Maybe we want only to know the len?
+ if (Buffer == NULL) return StrLen + sizeof(wchar_t);
+
+ // No buffer size means no data
+ if (BufferSize <= 0) return 0;
+
+ // Some clipping may be required
+ if (BufferSize < StrLen + sizeof(wchar_t))
+ StrLen = BufferSize - + sizeof(wchar_t);
+
+ memmove(Buffer, Wide, StrLen);
+ Buffer[StrLen / sizeof(wchar_t)] = 0;
+
+ return StrLen + sizeof(wchar_t);
+}
- if (v == NULL) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Out of memory creating named color list");
- return NULL;
- }
+// Get also the language and country
+CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ char ObtainedLanguage[3], char ObtainedCountry[3])
+{
+ const wchar_t *Wide;
+
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+ cmsUInt16Number ObtLang, ObtCode;
+
+ // Sanitize
+ if (mlu == NULL) return FALSE;
+
+ Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);
+ if (Wide == NULL) return FALSE;
+
+ // Get used language and code
+ *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang);
+ *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode);
+
+ ObtainedLanguage[2] = ObtainedCountry[2] = 0;
+ return TRUE;
+}
+
+
+// Named color lists --------------------------------------------------------------------------------------------
- ZeroMemory(v, size);
+// Grow the list to keep at least NumElements
+static
+cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v)
+{
+ cmsUInt32Number size;
+ _cmsNAMEDCOLOR * NewPtr;
+
+ if (v == NULL) return FALSE;
+
+ if (v ->Allocated == 0)
+ size = 64; // Initial guess
+ else
+ size = v ->Allocated * 2;
+
+ NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));
+ if (NewPtr == NULL)
+ return FALSE;
- v ->nColors = n;
- v ->Allocated = n;
- v ->Prefix[0] = 0;
- v ->Suffix[0] = 0;
+ v ->List = NewPtr;
+ v ->Allocated = size;
+ return TRUE;
+}
+
+// Allocate a list for n elements
+cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)
+{
+ cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
+
+ if (v == NULL) return NULL;
+
+ v ->List = NULL;
+ v ->nColors = 0;
+ v ->ContextID = ContextID;
+
+ while (v -> Allocated < n)
+ GrowNamedColorList(v);
+
+ strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix));
+ strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix));
+ v -> ColorantCount = ColorantCount;
return v;
}
-void cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST v)
+// Free a list
+void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)
{
- if (v == NULL) {
- cmsSignalError(LCMS_ERRC_RECOVERABLE, "Couldn't free a NULL named color list");
- return;
- }
-
- _cmsFree(v);
+ if (v ->List) _cmsFree(v ->ContextID, v ->List);
+ if (v) _cmsFree(v ->ContextID, v);
}
-LCMSBOOL cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS])
+cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
{
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
- LPcmsNAMEDCOLORLIST List;
- int i;
+ cmsNAMEDCOLORLIST* NewNC;
- if (v ->NamedColorList == NULL) return FALSE;
+ if (v == NULL) return NULL;
- v ->NamedColorList = GrowNamedColorList(v ->NamedColorList, v->NamedColorList ->nColors + 1);
-
- List = v ->NamedColorList;
+ NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix);
+ if (NewNC == NULL) return NULL;
- for (i=0; i < MAXCHANNELS; i++)
- List ->List[List ->nColors].DeviceColorant[i] = Colorant[i];
-
- for (i=0; i < 3; i++)
- List ->List[List ->nColors].PCS[i] = PCS[i];
+ // For really large tables we need this
+ while (NewNC ->Allocated < v ->Allocated)
+ GrowNamedColorList(NewNC);
- strncpy(List ->List[List ->nColors].Name, Name, MAX_PATH-1);
- List ->List[List ->nColors].Name[MAX_PATH-1] = 0;
-
- List ->nColors++;
- return TRUE;
+ memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));
+ memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
+ NewNC ->ColorantCount = v ->ColorantCount;
+ memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR));
+ NewNC ->nColors = v ->nColors;
+ return NewNC;
}
+// Append a color to a list. List pointer may change if reallocated
+cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
+ const char* Name,
+ cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS])
+{
+ cmsUInt32Number i;
-// Returns named color count
+ if (NamedColorList == NULL) return FALSE;
+
+ if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) {
+ if (!GrowNamedColorList(NamedColorList)) return FALSE;
+ }
+
+ for (i=0; i < NamedColorList ->ColorantCount; i++)
+ NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i];
+
+ for (i=0; i < 3; i++)
+ NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i];
+
+ if (Name != NULL)
+ strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name,
+ sizeof(NamedColorList ->List[NamedColorList ->nColors].Name));
+ else
+ NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0;
+
-int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform)
+ NamedColorList ->nColors++;
+ return TRUE;
+}
+
+// Returns number of elements
+cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList)
+{
+ if (NamedColorList == NULL) return 0;
+ return NamedColorList ->nColors;
+}
+
+// Info aboout a given color
+cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
+ char* Name,
+ char* Prefix,
+ char* Suffix,
+ cmsUInt16Number* PCS,
+ cmsUInt16Number* Colorant)
{
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
+ if (NamedColorList == NULL) return FALSE;
+
+ if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;
+
+ if (Name) strcpy(Name, NamedColorList->List[nColor].Name);
+ if (Prefix) strcpy(Prefix, NamedColorList->Prefix);
+ if (Suffix) strcpy(Suffix, NamedColorList->Suffix);
+ if (PCS)
+ memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number));
+
+ if (Colorant)
+ memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant,
+ sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount);
+
+
+ return TRUE;
+}
+
+// Search for a given color name (no prefix or suffix)
+cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)
+{
+ int i, n;
+
+ if (NamedColorList == NULL) return -1;
+ n = cmsNamedColorCount(NamedColorList);
+ for (i=0; i < n; i++) {
+ if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)
+ return i;
+ }
- if (v ->NamedColorList == NULL) return 0;
- return v ->NamedColorList ->nColors;
+ return -1;
+}
+
+// MPE support -----------------------------------------------------------------------------------------------------------------
+
+static
+void FreeNamedColorList(cmsStage* mpe)
+{
+ cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
+ cmsFreeNamedColorList(List);
+}
+
+static
+void* DupNamedColorList(cmsStage* mpe)
+{
+ cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
+ return cmsDupNamedColorList(List);
+}
+
+static
+void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
+{
+ cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
+ cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
+ cmsUInt32Number j;
+
+ if (index >= NamedColorList-> nColors) {
+ cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
+ }
+ else {
+ for (j=0; j < NamedColorList ->ColorantCount; j++)
+ Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0);
+ }
}
-LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix)
+// Named color lookup element
+cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList)
{
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
-
- if (v ->NamedColorList == NULL) return FALSE;
+ return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
+ cmsSigNamedColorElemType,
+ 1, 3,
+ EvalNamedColor,
+ DupNamedColorList,
+ FreeNamedColorList,
+ cmsDupNamedColorList(NamedColorList));
- if (nColor < 0 || nColor >= cmsNamedColorCount(xform)) return FALSE;
+}
+
- if (Name) { strncpy(Name, v ->NamedColorList->List[nColor].Name, 31); Name[31] = 0; }
- if (Prefix) { strncpy(Prefix, v ->NamedColorList->Prefix, 31); Prefix[31] = 0; }
- if (Suffix) { strncpy(Suffix, v ->NamedColorList->Suffix, 31); Suffix[31] = 0; }
+// Retrieve the named color list from a transform. Should be first element in the LUT
+cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform)
+{
+ _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
+ cmsStage* mpe = v ->Lut->Elements;
- return TRUE;
+ if (mpe ->Type != cmsSigNamedColorElemType) return NULL;
+ return (cmsNAMEDCOLORLIST*) mpe ->Data;
}
-int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name)
+// Profile sequence description routines -------------------------------------------------------------------------------------
+
+cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n)
{
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
- int i, n;
+ cmsSEQ* Seq;
+ cmsUInt32Number i;
- if (v ->NamedColorList == NULL) return -1;
+ if (n == 0) return NULL;
+
+ // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked
+ // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!
+ if (n > 255) return NULL;
- n = cmsNamedColorCount(xform);
- for (i=0; i < n; i++) {
- if (stricmp(Name, v ->NamedColorList->List[i].Name) == 0)
- return i;
- }
+ Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ));
+ if (Seq == NULL) return NULL;
+
+ Seq -> ContextID = ContextID;
+ Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC));
+ Seq -> n = n;
+
- return -1;
+ for (i=0; i < n; i++) {
+ Seq -> seq[i].Manufacturer = NULL;
+ Seq -> seq[i].Model = NULL;
+ Seq -> seq[i].Description = NULL;
+ }
+
+ return Seq;
}
+void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
+{
+ cmsUInt32Number i;
+ for (i=0; i < pseq ->n; i++) {
+ if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
+ if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
+ if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
+ }
+
+ if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
+ _cmsFree(pseq -> ContextID, pseq);
+}
+
+cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)
+{
+ cmsSEQ *NewSeq;
+ cmsUInt32Number i;
+
+ if (pseq == NULL)
+ return NULL;
+
+ NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));
+ if (NewSeq == NULL) return NULL;
+
+
+ NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));
+ if (NewSeq ->seq == NULL) goto Error;
+
+ NewSeq -> ContextID = pseq ->ContextID;
+ NewSeq -> n = pseq ->n;
+
+ for (i=0; i < pseq->n; i++) {
+
+ memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));
+
+ NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg;
+ NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel;
+ memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID));
+ NewSeq ->seq[i].technology = pseq ->seq[i].technology;
+
+ NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer);
+ NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model);
+ NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description);
+
+ }
+
+ return NewSeq;
+
+Error:
+
+ cmsFreeProfileSequenceDescription(NewSeq);
+ return NULL;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,1657 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+
+//----------------------------------------------------------------------------------
+
+// Optimization for 8 bits, Shaper-CLUT (3 inputs only)
+typedef struct {
+
+ cmsContext ContextID;
+
+ const cmsInterpParams* p; // Tetrahedrical interpolation parameters. This is a not-owned pointer.
+
+ cmsUInt16Number rx[256], ry[256], rz[256];
+ cmsUInt32Number X0[256], Y0[256], Z0[256]; // Precomputed nodes and offsets for 8-bit input data
+
+
+} Prelin8Data;
+
+
+// Generic optimization for 16 bits Shaper-CLUT-Shaper (any inputs)
+typedef struct {
+
+ cmsContext ContextID;
+
+ // Number of channels
+ int nInputs;
+ int nOutputs;
+
+ // Since there is no limitation of the output number of channels, this buffer holding the connexion CLUT-shaper
+ // has to be dynamically allocated. This is not the case of first step shaper-CLUT, which is limited to max inputs
+ cmsUInt16Number* StageDEF;
+
+ _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance
+ cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS];
+
+ _cmsInterpFn16 EvalCLUT; // The evaluator for 3D grid
+ const cmsInterpParams* CLUTparams; // (not-owned pointer)
+
+
+ _cmsInterpFn16* EvalCurveOut16; // Points to an array of curve evaluators in 16 bits (not-owned pointer)
+ cmsInterpParams** ParamsCurveOut16; // Points to an array of references to interpolation params (not-owned pointer)
+
+
+} Prelin16Data;
+
+
+// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed
+
+typedef cmsInt32Number cmsS1Fixed14Number; // Note that this may hold more than 16 bits!
+
+#define DOUBLE_TO_1FIXED14(x) ((cmsS1Fixed14Number) floor((x) * 16384.0 + 0.5))
+
+typedef struct {
+
+ cmsContext ContextID;
+
+ cmsS1Fixed14Number Shaper1R[256]; // from 0..255 to 1.14 (0.0...1.0)
+ cmsS1Fixed14Number Shaper1G[256];
+ cmsS1Fixed14Number Shaper1B[256];
+
+ cmsS1Fixed14Number Mat[3][3]; // n.14 to n.14 (needs a saturation after that)
+ cmsS1Fixed14Number Off[3];
+
+ cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255
+ cmsUInt16Number Shaper2G[16385];
+ cmsUInt16Number Shaper2B[16385];
+
+} MatShaper8Data;
+
+// Curves, optimization is shared between 8 and 16 bits
+typedef struct {
+
+ cmsContext ContextID;
+
+ int nCurves; // Number of curves
+ int nElements; // Elements in curves
+ cmsUInt16Number** Curves; // Points to a dynamically allocated array
+
+} Curves16Data;
+
+
+// Simple optimizations ----------------------------------------------------------------------------------------------------------
+
+
+// Remove an element in linked chain
+static
+void _RemoveElement(cmsStage** head)
+{
+ cmsStage* mpe = *head;
+ cmsStage* next = mpe ->Next;
+ *head = next;
+ cmsStageFree(mpe);
+}
+
+// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer.
+static
+cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp)
+{
+ cmsStage** pt = &Lut ->Elements;
+ cmsBool AnyOpt = FALSE;
+
+ while (*pt != NULL) {
+
+ if ((*pt) ->Implements == UnaryOp) {
+ _RemoveElement(pt);
+ AnyOpt = TRUE;
+ }
+ else
+ pt = &((*pt) -> Next);
+ }
+
+ return AnyOpt;
+}
+
+// Same, but only if two adjacent elements are found
+static
+cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op2)
+{
+ cmsStage** pt1;
+ cmsStage** pt2;
+ cmsBool AnyOpt = FALSE;
+
+ pt1 = &Lut ->Elements;
+ if (*pt1 == NULL) return AnyOpt;
+
+ while (*pt1 != NULL) {
+
+ pt2 = &((*pt1) -> Next);
+ if (*pt2 == NULL) return AnyOpt;
+
+ if ((*pt1) ->Implements == Op1 && (*pt2) ->Implements == Op2) {
+ _RemoveElement(pt2);
+ _RemoveElement(pt1);
+ AnyOpt = TRUE;
+ }
+ else
+ pt1 = &((*pt1) -> Next);
+ }
+
+ return AnyOpt;
+}
+
+// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed
+// by a v4 to v2 and vice-versa. The elements are then discarded.
+static
+cmsBool PreOptimize(cmsPipeline* Lut)
+{
+ cmsBool AnyOpt = FALSE, Opt;
+
+ AnyOpt = FALSE;
+
+ do {
+
+ Opt = FALSE;
+
+ // Remove all identities
+ Opt |= _Remove1Op(Lut, cmsSigIdentityElemType);
+
+ // Remove XYZ2Lab followed by Lab2XYZ
+ Opt |= _Remove2Op(Lut, cmsSigXYZ2LabElemType, cmsSigLab2XYZElemType);
+
+ // Remove Lab2XYZ followed by XYZ2Lab
+ Opt |= _Remove2Op(Lut, cmsSigLab2XYZElemType, cmsSigXYZ2LabElemType);
+
+ // Remove V4 to V2 followed by V2 to V4
+ Opt |= _Remove2Op(Lut, cmsSigLabV4toV2, cmsSigLabV2toV4);
+
+ // Remove V2 to V4 followed by V4 to V2
+ Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2);
+
+ if (Opt) AnyOpt = TRUE;
+
+ } while (Opt);
+
+ return AnyOpt;
+}
+
+static
+void Eval16nop1D(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const struct _cms_interp_struc* p)
+{
+ Output[0] = Input[0];
+
+ cmsUNUSED_PARAMETER(p);
+}
+
+static
+void PrelinEval16(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const void* D)
+{
+ Prelin16Data* p16 = (Prelin16Data*) D;
+ cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS];
+ int i;
+
+ for (i=0; i < p16 ->nInputs; i++) {
+
+ p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]);
+ }
+
+ p16 ->EvalCLUT(StageABC, p16 ->StageDEF, p16 ->CLUTparams);
+
+ for (i=0; i < p16 ->nOutputs; i++) {
+
+ p16 ->EvalCurveOut16[i](&p16->StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]);
+ }
+}
+
+
+static
+void PrelinOpt16free(cmsContext ContextID, void* ptr)
+{
+ Prelin16Data* p16 = (Prelin16Data*) ptr;
+
+ _cmsFree(ContextID, p16 ->StageDEF);
+ _cmsFree(ContextID, p16 ->EvalCurveOut16);
+ _cmsFree(ContextID, p16 ->ParamsCurveOut16);
+
+ _cmsFree(ContextID, p16);
+}
+
+static
+void* Prelin16dup(cmsContext ContextID, const void* ptr)
+{
+ Prelin16Data* p16 = (Prelin16Data*) ptr;
+ Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data));
+
+ if (Duped == NULL) return NULL;
+
+ Duped ->StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number));
+ Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16));
+ Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* ));
+
+ return Duped;
+}
+
+
+static
+Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
+ const cmsInterpParams* ColorMap,
+ int nInputs, cmsToneCurve** In,
+ int nOutputs, cmsToneCurve** Out )
+{
+ int i;
+ Prelin16Data* p16 = (Prelin16Data*) _cmsMallocZero(ContextID, sizeof(Prelin16Data));
+ if (p16 == NULL) return NULL;
+
+ p16 ->nInputs = nInputs;
+ p16 -> nOutputs = nOutputs;
+
+
+ for (i=0; i < nInputs; i++) {
+
+ if (In == NULL) {
+ p16 -> ParamsCurveIn16[i] = NULL;
+ p16 -> EvalCurveIn16[i] = Eval16nop1D;
+
+ }
+ else {
+ p16 -> ParamsCurveIn16[i] = In[i] ->InterpParams;
+ p16 -> EvalCurveIn16[i] = p16 ->ParamsCurveIn16[i]->Interpolation.Lerp16;
+ }
+ }
+
+ p16 ->CLUTparams = ColorMap;
+ p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16;
+
+
+ p16 -> StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number));
+ p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16));
+ p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* ));
+
+ for (i=0; i < nOutputs; i++) {
+
+ if (Out == NULL) {
+ p16 ->ParamsCurveOut16[i] = NULL;
+ p16 -> EvalCurveOut16[i] = Eval16nop1D;
+ }
+ else {
+
+ p16 ->ParamsCurveOut16[i] = Out[i] ->InterpParams;
+ p16 -> EvalCurveOut16[i] = p16 ->ParamsCurveOut16[i]->Interpolation.Lerp16;
+ }
+ }
+
+ return p16;
+}
+
+
+
+// Resampling ---------------------------------------------------------------------------------
+
+#define PRELINEARIZATION_POINTS 4096
+
+// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for
+// almost any transform. We use floating point precision and then convert from floating point to 16 bits.
+static
+int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+{
+ cmsPipeline* Lut = (cmsPipeline*) Cargo;
+ cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS];
+ cmsUInt32Number i;
+
+ _cmsAssert(Lut -> InputChannels < cmsMAXCHANNELS);
+ _cmsAssert(Lut -> OutputChannels < cmsMAXCHANNELS);
+
+ // From 16 bit to floating point
+ for (i=0; i < Lut ->InputChannels; i++)
+ InFloat[i] = (cmsFloat32Number) (In[i] / 65535.0);
+
+ // Evaluate in floating point
+ cmsPipelineEvalFloat(InFloat, OutFloat, Lut);
+
+ // Back to 16 bits representation
+ for (i=0; i < Lut ->OutputChannels; i++)
+ Out[i] = _cmsQuickSaturateWord(OutFloat[i] * 65535.0);
+
+ // Always succeed
+ return TRUE;
+}
+
+// Try to see if the curves of a given MPE are linear
+static
+cmsBool AllCurvesAreLinear(cmsStage* mpe)
+{
+ cmsToneCurve** Curves;
+ cmsUInt32Number i, n;
+
+ Curves = _cmsStageGetPtrToCurveSet(mpe);
+ if (Curves == NULL) return FALSE;
+
+ n = cmsStageOutputChannels(mpe);
+
+ for (i=0; i < n; i++) {
+ if (!cmsIsToneCurveLinear(Curves[i])) return FALSE;
+ }
+
+ return TRUE;
+}
+
+// This function replaces a specific node placed in "At" by the "Value" numbers. Its purpose
+// is to fix scum dot on broken profiles/transforms. Works on 1, 3 and 4 channels
+static
+cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[],
+ int nChannelsOut, int nChannelsIn)
+{
+ _cmsStageCLutData* Grid = (_cmsStageCLutData*) CLUT ->Data;
+ cmsInterpParams* p16 = Grid ->Params;
+ cmsFloat64Number px, py, pz, pw;
+ int x0, y0, z0, w0;
+ int i, index;
+
+ if (CLUT -> Type != cmsSigCLutElemType) {
+ cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut MPE");
+ return FALSE;
+ }
+
+ px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0;
+ py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0;
+ pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0;
+ pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0;
+
+ x0 = (int) floor(px);
+ y0 = (int) floor(py);
+ z0 = (int) floor(pz);
+ w0 = (int) floor(pw);
+
+ if (nChannelsIn == 4) {
+
+ if (((px - x0) != 0) ||
+ ((py - y0) != 0) ||
+ ((pz - z0) != 0) ||
+ ((pw - w0) != 0)) return FALSE; // Not on exact node
+
+ index = p16 -> opta[3] * x0 +
+ p16 -> opta[2] * y0 +
+ p16 -> opta[1] * z0 +
+ p16 -> opta[0] * w0;
+ }
+ else
+ if (nChannelsIn == 3) {
+
+ if (((px - x0) != 0) ||
+ ((py - y0) != 0) ||
+ ((pz - z0) != 0)) return FALSE; // Not on exact node
+
+ index = p16 -> opta[2] * x0 +
+ p16 -> opta[1] * y0 +
+ p16 -> opta[0] * z0;
+ }
+ else
+ if (nChannelsIn == 1) {
+
+ if (((px - x0) != 0)) return FALSE; // Not on exact node
+
+ index = p16 -> opta[0] * x0;
+ }
+ else {
+ cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn);
+ return FALSE;
+ }
+
+ for (i=0; i < nChannelsOut; i++)
+ Grid -> Tab.T[index + i] = Value[i];
+
+ return TRUE;
+}
+
+// Auxiliar, to see if two values are equal.
+static
+cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] )
+{
+ int i;
+
+ for (i=0; i < n; i++) {
+ if (White1[i] != White2[i]) return FALSE;
+ }
+ return TRUE;
+}
+
+
+// Locate the node for the white point and fix it to pure white in order to avoid scum dot.
+static
+cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColorSpace, cmsColorSpaceSignature ExitColorSpace)
+{
+ cmsUInt16Number *WhitePointIn, *WhitePointOut;
+ cmsUInt16Number WhiteIn[cmsMAXCHANNELS], WhiteOut[cmsMAXCHANNELS], ObtainedOut[cmsMAXCHANNELS];
+ cmsUInt32Number i, nOuts, nIns;
+ cmsStage *PreLin = NULL, *CLUT = NULL, *PostLin = NULL;
+
+ if (!_cmsEndPointsBySpace(EntryColorSpace,
+ &WhitePointIn, NULL, &nIns)) return FALSE;
+
+ if (!_cmsEndPointsBySpace(ExitColorSpace,
+ &WhitePointOut, NULL, &nOuts)) return FALSE;
+
+ // It needs to be fixed?
+
+ cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut);
+
+ if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match
+
+ // Check if the LUT comes as Prelin, CLUT or Postlin. We allow all combinations
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &PreLin, &CLUT, &PostLin))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCurveSetElemType, cmsSigCLutElemType, &PreLin, &CLUT))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCLutElemType, cmsSigCurveSetElemType, &CLUT, &PostLin))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCLutElemType, &CLUT))
+ return FALSE;
+
+ // We need to interpolate white points of both, pre and post curves
+ if (PreLin) {
+
+ cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PreLin);
+
+ for (i=0; i < nIns; i++) {
+ WhiteIn[i] = cmsEvalToneCurve16(Curves[i], WhitePointIn[i]);
+ }
+ }
+ else {
+ for (i=0; i < nIns; i++)
+ WhiteIn[i] = WhitePointIn[i];
+ }
+
+ // If any post-linearization, we need to find how is represented white before the curve, do
+ // a reverse interpolation in this case.
+ if (PostLin) {
+
+ cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PostLin);
+
+ for (i=0; i < nOuts; i++) {
+
+ cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]);
+ WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]);
+ cmsFreeToneCurve(InversePostLin);
+ }
+ }
+ else {
+ for (i=0; i < nOuts; i++)
+ WhiteOut[i] = WhitePointOut[i];
+ }
+
+ // Ok, proceed with patching. May fail and we don't care if it fails
+ PatchLUT(CLUT, WhiteIn, WhiteOut, nOuts, nIns);
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------------------------------------------------------------------------------
+// This function creates simple LUT from complex ones. The generated LUT has an optional set of
+// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables.
+// These curves have to exist in the original LUT in order to be used in the simplified output.
+// Caller may also use the flags to allow this feature.
+// LUTS with all curves will be simplified to a single curve. Parametric curves are lost.
+// This function should be used on 16-bits LUTS only, as floating point losses precision when simplified
+// -----------------------------------------------------------------------------------------------------------------------------------------------
+
+static
+cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
+{
+ cmsPipeline* Src;
+ cmsPipeline* Dest;
+ cmsStage* CLUT;
+ cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
+ int nGridPoints;
+ cmsColorSpaceSignature ColorSpace, OutputColorSpace;
+ cmsStage *NewPreLin = NULL;
+ cmsStage *NewPostLin = NULL;
+ _cmsStageCLutData* DataCLUT;
+ cmsToneCurve** DataSetIn;
+ cmsToneCurve** DataSetOut;
+ Prelin16Data* p16;
+
+
+ // This is a loosy optimization! does not apply in floating-point cases
+ if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE;
+
+ ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat));
+ OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat));
+ nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
+
+ // For empty LUTs, 2 points are enough
+ if (cmsPipelineStageCount(*Lut) == 0)
+ nGridPoints = 2;
+
+ Src = *Lut;
+
+ // Allocate an empty LUT
+ Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
+ if (!Dest) return FALSE;
+
+ // Prelinearization tables are kept unless indicated by flags
+ if (*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION) {
+
+ // Get a pointer to the prelinearization element
+ cmsStage* PreLin = cmsPipelineGetPtrToFirstStage(Src);
+
+ // Check if suitable
+ if (PreLin ->Type == cmsSigCurveSetElemType) {
+
+ // Maybe this is a linear tram, so we can avoid the whole stuff
+ if (!AllCurvesAreLinear(PreLin)) {
+
+ // All seems ok, proceed.
+ NewPreLin = cmsStageDup(PreLin);
+ cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin);
+
+ // Remove prelinearization. Since we have duplicated the curve
+ // in destination LUT, the sampling shoud be applied after this stage.
+ cmsPipelineUnlinkStage(Src, cmsAT_BEGIN, &KeepPreLin);
+ }
+ }
+ }
+
+ // Allocate the CLUT
+ CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL);
+ if (CLUT == NULL) return FALSE;
+
+ // Add the CLUT to the destination LUT
+ cmsPipelineInsertStage(Dest, cmsAT_END, CLUT);
+
+ // Postlinearization tables are kept unless indicated by flags
+ if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) {
+
+ // Get a pointer to the postlinearization if present
+ cmsStage* PostLin = cmsPipelineGetPtrToLastStage(Src);
+
+ // Check if suitable
+ if (cmsStageType(PostLin) == cmsSigCurveSetElemType) {
+
+ // Maybe this is a linear tram, so we can avoid the whole stuff
+ if (!AllCurvesAreLinear(PostLin)) {
+
+ // All seems ok, proceed.
+ NewPostLin = cmsStageDup(PostLin);
+ cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin);
+
+ // In destination LUT, the sampling shoud be applied after this stage.
+ cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin);
+ }
+ }
+ }
+
+ // Now its time to do the sampling. We have to ignore pre/post linearization
+ // The source LUT whithout pre/post curves is passed as parameter.
+ if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) {
+
+ // Ops, something went wrong, Restore stages
+ if (KeepPreLin != NULL) cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin);
+ if (KeepPostLin != NULL) cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin);
+ cmsPipelineFree(Dest);
+ return FALSE;
+ }
+
+ // Done.
+
+ if (KeepPreLin != NULL) cmsStageFree(KeepPreLin);
+ if (KeepPostLin != NULL) cmsStageFree(KeepPostLin);
+ cmsPipelineFree(Src);
+
+ DataCLUT = (_cmsStageCLutData*) CLUT ->Data;
+
+ if (NewPreLin == NULL) DataSetIn = NULL;
+ else DataSetIn = ((_cmsStageToneCurvesData*) NewPreLin ->Data) ->TheCurves;
+
+ if (NewPostLin == NULL) DataSetOut = NULL;
+ else DataSetOut = ((_cmsStageToneCurvesData*) NewPostLin ->Data) ->TheCurves;
+
+
+ if (DataSetIn == NULL && DataSetOut == NULL) {
+
+ _cmsPipelineSetOptimizationParameters(Dest, (_cmsOPTeval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL);
+ }
+ else {
+
+ p16 = PrelinOpt16alloc(Dest ->ContextID,
+ DataCLUT ->Params,
+ Dest ->InputChannels,
+ DataSetIn,
+ Dest ->OutputChannels,
+ DataSetOut);
+
+
+ _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup);
+ }
+
+
+ // Don't fix white on absolute colorimetric
+ if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
+ *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP;
+
+ if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) {
+
+ FixWhiteMisalignment(Dest, ColorSpace, OutputColorSpace);
+ }
+
+ *Lut = Dest;
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(Intent);
+}
+
+
+// -----------------------------------------------------------------------------------------------------------------------------------------------
+// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on
+// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works
+// for RGB transforms. See the paper for more details
+// -----------------------------------------------------------------------------------------------------------------------------------------------
+
+
+// Normalize endpoints by slope limiting max and min. This assures endpoints as well.
+// Descending curves are handled as well.
+static
+void SlopeLimiting(cmsToneCurve* g)
+{
+ int BeginVal, EndVal;
+ int AtBegin = (int) floor((cmsFloat64Number) g ->nEntries * 0.02 + 0.5); // Cutoff at 2%
+ int AtEnd = g ->nEntries - AtBegin - 1; // And 98%
+ cmsFloat64Number Val, Slope, beta;
+ int i;
+
+ if (cmsIsToneCurveDescending(g)) {
+ BeginVal = 0xffff; EndVal = 0;
+ }
+ else {
+ BeginVal = 0; EndVal = 0xffff;
+ }
+
+ // Compute slope and offset for begin of curve
+ Val = g ->Table16[AtBegin];
+ Slope = (Val - BeginVal) / AtBegin;
+ beta = Val - Slope * AtBegin;
+
+ for (i=0; i < AtBegin; i++)
+ g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta);
+
+ // Compute slope and offset for the end
+ Val = g ->Table16[AtEnd];
+ Slope = (EndVal - Val) / AtBegin; // AtBegin holds the X interval, which is same in both cases
+ beta = Val - Slope * AtEnd;
+
+ for (i = AtEnd; i < (int) g ->nEntries; i++)
+ g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta);
+}
+
+
+// Precomputes tables for 8-bit on input devicelink.
+static
+Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cmsToneCurve* G[3])
+{
+ int i;
+ cmsUInt16Number Input[3];
+ cmsS15Fixed16Number v1, v2, v3;
+ Prelin8Data* p8;
+
+ p8 = _cmsMallocZero(ContextID, sizeof(Prelin8Data));
+ if (p8 == NULL) return NULL;
+
+ // Since this only works for 8 bit input, values comes always as x * 257,
+ // we can safely take msb byte (x << 8 + x)
+
+ for (i=0; i < 256; i++) {
+
+ if (G != NULL) {
+
+ // Get 16-bit representation
+ Input[0] = cmsEvalToneCurve16(G[0], FROM_8_TO_16(i));
+ Input[1] = cmsEvalToneCurve16(G[1], FROM_8_TO_16(i));
+ Input[2] = cmsEvalToneCurve16(G[2], FROM_8_TO_16(i));
+ }
+ else {
+ Input[0] = FROM_8_TO_16(i);
+ Input[1] = FROM_8_TO_16(i);
+ Input[2] = FROM_8_TO_16(i);
+ }
+
+
+ // Move to 0..1.0 in fixed domain
+ v1 = _cmsToFixedDomain(Input[0] * p -> Domain[0]);
+ v2 = _cmsToFixedDomain(Input[1] * p -> Domain[1]);
+ v3 = _cmsToFixedDomain(Input[2] * p -> Domain[2]);
+
+ // Store the precalculated table of nodes
+ p8 ->X0[i] = (p->opta[2] * FIXED_TO_INT(v1));
+ p8 ->Y0[i] = (p->opta[1] * FIXED_TO_INT(v2));
+ p8 ->Z0[i] = (p->opta[0] * FIXED_TO_INT(v3));
+
+ // Store the precalculated table of offsets
+ p8 ->rx[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v1);
+ p8 ->ry[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v2);
+ p8 ->rz[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v3);
+ }
+
+ p8 ->ContextID = ContextID;
+ p8 ->p = p;
+
+ return p8;
+}
+
+static
+void Prelin8free(cmsContext ContextID, void* ptr)
+{
+ _cmsFree(ContextID, ptr);
+}
+
+static
+void* Prelin8dup(cmsContext ContextID, const void* ptr)
+{
+ return _cmsDupMem(ContextID, ptr, sizeof(Prelin8Data));
+}
+
+
+
+// A optimized interpolation for 8-bit input.
+#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
+static
+void PrelinEval8(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const void* D)
+{
+
+ cmsUInt8Number r, g, b;
+ cmsS15Fixed16Number rx, ry, rz;
+ cmsS15Fixed16Number c0, c1, c2, c3, Rest;
+ int OutChan;
+ register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+ Prelin8Data* p8 = (Prelin8Data*) D;
+ register const cmsInterpParams* p = p8 ->p;
+ int TotalOut = p -> nOutputs;
+ const cmsUInt16Number* LutTable = p -> Table;
+
+ r = Input[0] >> 8;
+ g = Input[1] >> 8;
+ b = Input[2] >> 8;
+
+ X0 = X1 = p8->X0[r];
+ Y0 = Y1 = p8->Y0[g];
+ Z0 = Z1 = p8->Z0[b];
+
+ rx = p8 ->rx[r];
+ ry = p8 ->ry[g];
+ rz = p8 ->rz[b];
+
+ X1 = X0 + ((rx == 0) ? 0 : p ->opta[2]);
+ Y1 = Y0 + ((ry == 0) ? 0 : p ->opta[1]);
+ Z1 = Z0 + ((rz == 0) ? 0 : p ->opta[0]);
+
+
+ // These are the 6 Tetrahedral
+ for (OutChan=0; OutChan < TotalOut; OutChan++) {
+
+ c0 = DENS(X0, Y0, Z0);
+
+ if (rx >= ry && ry >= rz)
+ {
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+ }
+ else
+ if (rx >= rz && rz >= ry)
+ {
+ c1 = DENS(X1, Y0, Z0) - c0;
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
+ }
+ else
+ if (rz >= rx && rx >= ry)
+ {
+ c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
+ c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+ }
+ else
+ if (ry >= rx && rx >= rz)
+ {
+ c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
+ }
+ else
+ if (ry >= rz && rz >= rx)
+ {
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z0) - c0;
+ c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
+ }
+ else
+ if (rz >= ry && ry >= rx)
+ {
+ c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
+ c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
+ c3 = DENS(X0, Y0, Z1) - c0;
+ }
+ else {
+ c1 = c2 = c3 = 0;
+ }
+
+
+ Rest = c1 * rx + c2 * ry + c3 * rz;
+
+ Output[OutChan] = (cmsUInt16Number)c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
+
+ }
+}
+
+#undef DENS
+
+// --------------------------------------------------------------------------------------------------------------
+// We need xput over here
+
+static
+cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
+{
+ cmsPipeline* OriginalLut;
+ int nGridPoints;
+ cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS];
+ cmsUInt32Number t, i;
+ cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS];
+ cmsBool lIsSuitable, lIsLinear;
+ cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL;
+ cmsStage* OptimizedCLUTmpe;
+ cmsColorSpaceSignature ColorSpace, OutputColorSpace;
+ cmsStage* OptimizedPrelinMpe;
+ cmsToneCurve** OptimizedPrelinCurves;
+ _cmsStageCLutData* OptimizedPrelinCLUT;
+
+
+ // This is a loosy optimization! does not apply in floating-point cases
+ if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE;
+
+ // Only on RGB
+ if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE;
+ if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE;
+
+
+ // On 16 bits, user has to specify the feature
+ if (!_cmsFormatterIs8bit(*InputFormat)) {
+ if (!(*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION)) return FALSE;
+ }
+
+ OriginalLut = *Lut;
+ ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat));
+ OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat));
+ nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
+
+ // Empty gamma containers
+ memset(Trans, 0, sizeof(Trans));
+ memset(TransReverse, 0, sizeof(TransReverse));
+
+ for (t = 0; t < OriginalLut ->InputChannels; t++) {
+ Trans[t] = cmsBuildTabulatedToneCurve16(OriginalLut ->ContextID, PRELINEARIZATION_POINTS, NULL);
+ if (Trans[t] == NULL) goto Error;
+ }
+
+ // Populate the curves
+ for (i=0; i < PRELINEARIZATION_POINTS; i++) {
+
+ v = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1));
+
+ // Feed input with a gray ramp
+ for (t=0; t < OriginalLut ->InputChannels; t++)
+ In[t] = v;
+
+ // Evaluate the gray value
+ cmsPipelineEvalFloat(In, Out, OriginalLut);
+
+ // Store result in curve
+ for (t=0; t < OriginalLut ->InputChannels; t++)
+ Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0);
+ }
+
+ // Slope-limit the obtained curves
+ for (t = 0; t < OriginalLut ->InputChannels; t++)
+ SlopeLimiting(Trans[t]);
+
+ // Check for validity
+ lIsSuitable = TRUE;
+ lIsLinear = TRUE;
+ for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) {
+
+ // Exclude if already linear
+ if (!cmsIsToneCurveLinear(Trans[t]))
+ lIsLinear = FALSE;
+
+ // Exclude if non-monotonic
+ if (!cmsIsToneCurveMonotonic(Trans[t]))
+ lIsSuitable = FALSE;
+ }
+
+ // If it is not suitable, just quit
+ if (!lIsSuitable) goto Error;
+
+ // Invert curves if possible
+ for (t = 0; t < OriginalLut ->InputChannels; t++) {
+ TransReverse[t] = cmsReverseToneCurveEx(PRELINEARIZATION_POINTS, Trans[t]);
+ if (TransReverse[t] == NULL) goto Error;
+ }
+
+ // Now inset the reversed curves at the begin of transform
+ LutPlusCurves = cmsPipelineDup(OriginalLut);
+ if (LutPlusCurves == NULL) goto Error;
+
+ cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse));
+
+ // Create the result LUT
+ OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels);
+ if (OptimizedLUT == NULL) goto Error;
+
+ OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans);
+
+ // Create and insert the curves at the beginning
+ cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe);
+
+ // Allocate the CLUT for result
+ OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL);
+
+ // Add the CLUT to the destination LUT
+ cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe);
+
+ // Resample the LUT
+ if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error;
+
+ // Free resources
+ for (t = 0; t < OriginalLut ->InputChannels; t++) {
+
+ if (Trans[t]) cmsFreeToneCurve(Trans[t]);
+ if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]);
+ }
+
+ cmsPipelineFree(LutPlusCurves);
+
+
+ OptimizedPrelinCurves = _cmsStageGetPtrToCurveSet(OptimizedPrelinMpe);
+ OptimizedPrelinCLUT = (_cmsStageCLutData*) OptimizedCLUTmpe ->Data;
+
+ // Set the evaluator if 8-bit
+ if (_cmsFormatterIs8bit(*InputFormat)) {
+
+ Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID,
+ OptimizedPrelinCLUT ->Params,
+ OptimizedPrelinCurves);
+ if (p8 == NULL) return FALSE;
+
+ _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup);
+
+ }
+ else
+ {
+ Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID,
+ OptimizedPrelinCLUT ->Params,
+ 3, OptimizedPrelinCurves, 3, NULL);
+ if (p16 == NULL) return FALSE;
+
+ _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup);
+
+ }
+
+ // Don't fix white on absolute colorimetric
+ if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
+ *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP;
+
+ if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) {
+
+ if (!FixWhiteMisalignment(OptimizedLUT, ColorSpace, OutputColorSpace)) {
+
+ return FALSE;
+ }
+ }
+
+ // And return the obtained LUT
+
+ cmsPipelineFree(OriginalLut);
+ *Lut = OptimizedLUT;
+ return TRUE;
+
+Error:
+
+ for (t = 0; t < OriginalLut ->InputChannels; t++) {
+
+ if (Trans[t]) cmsFreeToneCurve(Trans[t]);
+ if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]);
+ }
+
+ if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves);
+ if (OptimizedLUT != NULL) cmsPipelineFree(OptimizedLUT);
+
+ return FALSE;
+
+ cmsUNUSED_PARAMETER(Intent);
+}
+
+
+// Curves optimizer ------------------------------------------------------------------------------------------------------------------
+
+static
+void CurvesFree(cmsContext ContextID, void* ptr)
+{
+ Curves16Data* Data = (Curves16Data*) ptr;
+ int i;
+
+ for (i=0; i < Data -> nCurves; i++) {
+
+ _cmsFree(ContextID, Data ->Curves[i]);
+ }
+
+ _cmsFree(ContextID, Data ->Curves);
+ _cmsFree(ContextID, ptr);
+}
+
+static
+void* CurvesDup(cmsContext ContextID, const void* ptr)
+{
+ Curves16Data* Data = _cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
+ int i;
+
+ if (Data == NULL) return NULL;
+
+ Data ->Curves = _cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*));
+
+ for (i=0; i < Data -> nCurves; i++) {
+ Data ->Curves[i] = _cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number));
+ }
+
+ return (void*) Data;
+}
+
+// Precomputes tables for 8-bit on input devicelink.
+static
+Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G)
+{
+ int i, j;
+ Curves16Data* c16;
+
+ c16 = _cmsMallocZero(ContextID, sizeof(Curves16Data));
+ if (c16 == NULL) return NULL;
+
+ c16 ->nCurves = nCurves;
+ c16 ->nElements = nElements;
+
+ c16 ->Curves = _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*));
+ if (c16 ->Curves == NULL) return NULL;
+
+ for (i=0; i < nCurves; i++) {
+
+ c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number));
+
+ if (nElements == 256) {
+
+ for (j=0; j < nElements; j++) {
+
+ c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j));
+ }
+ }
+ else {
+
+ for (j=0; j < nElements; j++) {
+ c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j);
+ }
+ }
+ }
+
+ return c16;
+}
+
+static
+void FastEvaluateCurves8(register const cmsUInt16Number In[],
+ register cmsUInt16Number Out[],
+ register const void* D)
+{
+ Curves16Data* Data = (Curves16Data*) D;
+ cmsUInt8Number x;
+ int i;
+
+ for (i=0; i < Data ->nCurves; i++) {
+
+ x = (In[i] >> 8);
+ Out[i] = Data -> Curves[i][x];
+ }
+}
+
+
+static
+void FastEvaluateCurves16(register const cmsUInt16Number In[],
+ register cmsUInt16Number Out[],
+ register const void* D)
+{
+ Curves16Data* Data = (Curves16Data*) D;
+ int i;
+
+ for (i=0; i < Data ->nCurves; i++) {
+ Out[i] = Data -> Curves[i][In[i]];
+ }
+}
+
+
+static
+void FastIdentity16(register const cmsUInt16Number In[],
+ register cmsUInt16Number Out[],
+ register const void* D)
+{
+ cmsPipeline* Lut = (cmsPipeline*) D;
+ cmsUInt32Number i;
+
+ for (i=0; i < Lut ->InputChannels; i++) {
+ Out[i] = In[i];
+ }
+}
+
+
+// If the target LUT holds only curves, the optimization procedure is to join all those
+// curves together. That only works on curves and does not work on matrices.
+static
+cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
+{
+ cmsToneCurve** GammaTables = NULL;
+ cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS];
+ cmsUInt32Number i, j;
+ cmsPipeline* Src = *Lut;
+ cmsPipeline* Dest = NULL;
+ cmsStage* mpe;
+ cmsStage* ObtainedCurves = NULL;
+
+
+ // This is a loosy optimization! does not apply in floating-point cases
+ if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE;
+
+ // Only curves in this LUT?
+ for (mpe = cmsPipelineGetPtrToFirstStage(Src);
+ mpe != NULL;
+ mpe = cmsStageNext(mpe)) {
+ if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE;
+ }
+
+ // Allocate an empty LUT
+ Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
+ if (Dest == NULL) return FALSE;
+
+ // Create target curves
+ GammaTables = (cmsToneCurve**) _cmsCalloc(Src ->ContextID, Src ->InputChannels, sizeof(cmsToneCurve*));
+ if (GammaTables == NULL) goto Error;
+
+ for (i=0; i < Src ->InputChannels; i++) {
+ GammaTables[i] = cmsBuildTabulatedToneCurve16(Src ->ContextID, PRELINEARIZATION_POINTS, NULL);
+ if (GammaTables[i] == NULL) goto Error;
+ }
+
+ // Compute 16 bit result by using floating point
+ for (i=0; i < PRELINEARIZATION_POINTS; i++) {
+
+ for (j=0; j < Src ->InputChannels; j++)
+ InFloat[j] = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1));
+
+ cmsPipelineEvalFloat(InFloat, OutFloat, Src);
+
+ for (j=0; j < Src ->InputChannels; j++)
+ GammaTables[j] -> Table16[i] = _cmsQuickSaturateWord(OutFloat[j] * 65535.0);
+ }
+
+ ObtainedCurves = cmsStageAllocToneCurves(Src ->ContextID, Src ->InputChannels, GammaTables);
+ if (ObtainedCurves == NULL) goto Error;
+
+ for (i=0; i < Src ->InputChannels; i++) {
+ cmsFreeToneCurve(GammaTables[i]);
+ GammaTables[i] = NULL;
+ }
+
+ if (GammaTables != NULL) _cmsFree(Src ->ContextID, GammaTables);
+
+ // Maybe the curves are linear at the end
+ if (!AllCurvesAreLinear(ObtainedCurves)) {
+
+ cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves);
+
+ // If the curves are to be applied in 8 bits, we can save memory
+ if (_cmsFormatterIs8bit(*InputFormat)) {
+
+ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data;
+ Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves);
+
+ *dwFlags |= cmsFLAGS_NOCACHE;
+ _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup);
+
+ }
+ else {
+
+ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves);
+ Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves);
+
+ *dwFlags |= cmsFLAGS_NOCACHE;
+ _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup);
+ }
+ }
+ else {
+
+ // LUT optimizes to nothing. Set the identity LUT
+ cmsStageFree(ObtainedCurves);
+
+ cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels));
+
+ *dwFlags |= cmsFLAGS_NOCACHE;
+ _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL);
+ }
+
+ // We are done.
+ cmsPipelineFree(Src);
+ *Lut = Dest;
+ return TRUE;
+
+Error:
+
+ if (ObtainedCurves != NULL) cmsStageFree(ObtainedCurves);
+ if (GammaTables != NULL) {
+ for (i=0; i < Src ->InputChannels; i++) {
+ if (GammaTables[i] != NULL) cmsFreeToneCurve(GammaTables[i]);
+ }
+
+ _cmsFree(Src ->ContextID, GammaTables);
+ }
+
+ if (Dest != NULL) cmsPipelineFree(Dest);
+ return FALSE;
+
+ cmsUNUSED_PARAMETER(Intent);
+ cmsUNUSED_PARAMETER(InputFormat);
+ cmsUNUSED_PARAMETER(OutputFormat);
+ cmsUNUSED_PARAMETER(dwFlags);
+}
+
+// -------------------------------------------------------------------------------------------------------------------------------------
+// LUT is Shaper - Matrix - Matrix - Shaper, which is very frequent when combining two matrix-shaper profiles
+
+
+static
+void FreeMatShaper(cmsContext ContextID, void* Data)
+{
+ if (Data != NULL) _cmsFree(ContextID, Data);
+}
+
+static
+void* DupMatShaper(cmsContext ContextID, const void* Data)
+{
+ return _cmsDupMem(ContextID, Data, sizeof(MatShaper8Data));
+}
+
+
+// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point
+// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits,
+// in total about 50K, and the performance boost is huge!
+static
+void MatShaperEval16(register const cmsUInt16Number In[],
+ register cmsUInt16Number Out[],
+ register const void* D)
+{
+ MatShaper8Data* p = (MatShaper8Data*) D;
+ cmsS1Fixed14Number l1, l2, l3, r, g, b;
+ cmsUInt32Number ri, gi, bi;
+
+ // In this case (and only in this case!) we can use this simplification since
+ // In[] is assured to come from a 8 bit number. (a << 8 | a)
+ ri = In[0] & 0xFF;
+ gi = In[1] & 0xFF;
+ bi = In[2] & 0xFF;
+
+ // Across first shaper, which also converts to 1.14 fixed point
+ r = p->Shaper1R[ri];
+ g = p->Shaper1G[gi];
+ b = p->Shaper1B[bi];
+
+ // Evaluate the matrix in 1.14 fixed point
+ l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14;
+ l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14;
+ l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14;
+
+ // Now we have to clip to 0..1.0 range
+ ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1);
+ gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2);
+ bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3);
+
+ // And across second shaper,
+ Out[0] = p->Shaper2R[ri];
+ Out[1] = p->Shaper2G[gi];
+ Out[2] = p->Shaper2B[bi];
+
+}
+
+// This table converts from 8 bits to 1.14 after applying the curve
+static
+void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve)
+{
+ int i;
+ cmsFloat32Number R, y;
+
+ for (i=0; i < 256; i++) {
+
+ R = (cmsFloat32Number) (i / 255.0);
+ y = cmsEvalToneCurveFloat(Curve, R);
+
+ Table[i] = DOUBLE_TO_1FIXED14(y);
+ }
+}
+
+// This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve
+static
+void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput)
+{
+ int i;
+ cmsFloat32Number R, Val;
+
+ for (i=0; i < 16385; i++) {
+
+ R = (cmsFloat32Number) (i / 16384.0);
+ Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0
+
+ if (Is8BitsOutput) {
+
+ // If 8 bits output, we can optimize further by computing the / 257 part.
+ // first we compute the resulting byte and then we store the byte times
+ // 257. This quantization allows to round very quick by doing a >> 8, but
+ // since the low byte is always equal to msb, we can do a & 0xff and this works!
+ cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0 + 0.5);
+ cmsUInt8Number b = FROM_16_TO_8(w);
+
+ Table[i] = FROM_8_TO_16(b);
+ }
+ else Table[i] = _cmsQuickSaturateWord(Val * 65535.0 + 0.5);
+ }
+}
+
+// Compute the matrix-shaper structure
+static
+cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, cmsVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat)
+{
+ MatShaper8Data* p;
+ int i, j;
+ cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat);
+
+ // Allocate a big chuck of memory to store precomputed tables
+ p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data));
+ if (p == NULL) return FALSE;
+
+ p -> ContextID = Dest -> ContextID;
+
+ // Precompute tables
+ FillFirstShaper(p ->Shaper1R, Curve1[0]);
+ FillFirstShaper(p ->Shaper1G, Curve1[1]);
+ FillFirstShaper(p ->Shaper1B, Curve1[2]);
+
+ FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits);
+ FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits);
+ FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits);
+
+ // Convert matrix to nFixed14. Note that those values may take more than 16 bits as
+ for (i=0; i < 3; i++) {
+ for (j=0; j < 3; j++) {
+ p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]);
+ }
+ }
+
+ for (i=0; i < 3; i++) {
+
+ if (Off == NULL) {
+ p ->Off[i] = 0;
+ }
+ else {
+ p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]);
+ }
+ }
+
+ // Mark as optimized for faster formatter
+ if (Is8Bits)
+ *OutputFormat |= OPTIMIZED_SH(1);
+
+ // Fill function pointers
+ _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper);
+ return TRUE;
+}
+
+// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast!
+// TODO: Allow a third matrix for abs. colorimetric
+static
+cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
+{
+ cmsStage* Curve1, *Curve2;
+ cmsStage* Matrix1, *Matrix2;
+ _cmsStageMatrixData* Data1;
+ _cmsStageMatrixData* Data2;
+ cmsMAT3 res;
+ cmsBool IdentityMat;
+ cmsPipeline* Dest, *Src;
+
+ // Only works on RGB to RGB
+ if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE;
+
+ // Only works on 8 bit input
+ if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE;
+
+ // Seems suitable, proceed
+ Src = *Lut;
+
+ // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for
+ if (!cmsPipelineCheckAndRetreiveStages(Src, 4,
+ cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
+ &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE;
+
+ // Get both matrices
+ Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1);
+ Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2);
+
+ // Input offset should be zero
+ if (Data1 ->Offset != NULL) return FALSE;
+
+ // Multiply both matrices to get the result
+ _cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double);
+
+ // Now the result is in res + Data2 -> Offset. Maybe is a plain identity?
+ IdentityMat = FALSE;
+ if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) {
+
+ // We can get rid of full matrix
+ IdentityMat = TRUE;
+ }
+
+ // Allocate an empty LUT
+ Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
+ if (!Dest) return FALSE;
+
+ // Assamble the new LUT
+ cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1));
+ if (!IdentityMat)
+ cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset));
+ cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2));
+
+ // If identity on matrix, we can further optimize the curves, so call the join curves routine
+ if (IdentityMat) {
+
+ OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags);
+ }
+ else {
+ _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1);
+ _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2);
+
+ // In this particular optimization, caché does not help as it takes more time to deal with
+ // the caché that with the pixel handling
+ *dwFlags |= cmsFLAGS_NOCACHE;
+
+ // Setup the optimizarion routines
+ SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat);
+ }
+
+ cmsPipelineFree(Src);
+ *Lut = Dest;
+ return TRUE;
+}
+
+
+// -------------------------------------------------------------------------------------------------------------------------------------
+// Optimization plug-ins
+
+// List of optimizations
+typedef struct _cmsOptimizationCollection_st {
+
+ _cmsOPToptimizeFn OptimizePtr;
+
+ struct _cmsOptimizationCollection_st *Next;
+
+} _cmsOptimizationCollection;
+
+
+// The built-in list. We currently implement 4 types of optimizations. Joining of curves, matrix-shaper, linearization and resampling
+static _cmsOptimizationCollection DefaultOptimization[] = {
+
+ { OptimizeByJoiningCurves, &DefaultOptimization[1] },
+ { OptimizeMatrixShaper, &DefaultOptimization[2] },
+ { OptimizeByComputingLinearization, &DefaultOptimization[3] },
+ { OptimizeByResampling, NULL }
+};
+
+// The linked list head
+static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization;
+
+// Register new ways to optimize
+cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data)
+{
+ cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data;
+ _cmsOptimizationCollection* fl;
+
+ if (Data == NULL) {
+
+ OptimizationCollection = DefaultOptimization;
+ return TRUE;
+ }
+
+ // Optimizer callback is required
+ if (Plugin ->OptimizePtr == NULL) return FALSE;
+
+ fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(sizeof(_cmsOptimizationCollection));
+ if (fl == NULL) return FALSE;
+
+ // Copy the parameters
+ fl ->OptimizePtr = Plugin ->OptimizePtr;
+
+ // Keep linked list
+ fl ->Next = OptimizationCollection;
+ OptimizationCollection = fl;
+
+ // All is ok
+ return TRUE;
+}
+
+// The entry point for LUT optimization
+cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
+ int Intent,
+ cmsUInt32Number* InputFormat,
+ cmsUInt32Number* OutputFormat,
+ cmsUInt32Number* dwFlags)
+{
+ _cmsOptimizationCollection* Opts;
+ cmsBool AnySuccess = FALSE;
+
+ // A CLUT is being asked, so force this specific optimization
+ if (*dwFlags & cmsFLAGS_FORCE_CLUT) {
+
+ PreOptimize(*PtrLut);
+ return OptimizeByResampling(PtrLut, Intent, InputFormat, OutputFormat, dwFlags);
+ }
+
+ // Anything to optimize?
+ if ((*PtrLut) ->Elements == NULL) {
+ _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL);
+ return TRUE;
+ }
+
+ // Try to get rid of identities and trivial conversions.
+ AnySuccess = PreOptimize(*PtrLut);
+
+ // After removal do we end with an identity?
+ if ((*PtrLut) ->Elements == NULL) {
+ _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL);
+ return TRUE;
+ }
+
+ // Do not optimize, keep all precision
+ if (*dwFlags & cmsFLAGS_NOOPTIMIZE)
+ return FALSE;
+
+ // Try built-in optimizations and plug-in
+ for (Opts = OptimizationCollection;
+ Opts != NULL;
+ Opts = Opts ->Next) {
+
+ // If one schema succeeded, we are done
+ if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) {
+
+ return TRUE; // Optimized!
+ }
+ }
+
+ // Only simple optimizations succeeded
+ return AnySuccess;
+}
+
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,8 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -47,2129 +49,2551 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-// This module handles all formats supported by lcms
-
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+// This module handles all formats supported by lcms. There are two flavors, 16 bits and
+// floating point. Floating point is supported only in a subset, those formats holding
+// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component as special
+// case)
// ---------------------------------------------------------------------------
// This macro return words stored as big endian
-
-#define CHANGE_ENDIAN(w) (WORD) ((WORD) ((w)<<8)|((w)>>8))
+#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
// These macros handles reversing (negative)
-
-#define REVERSE_FLAVOR_8(x) ((BYTE) (0xff-(x)))
-#define REVERSE_FLAVOR_16(x) ((WORD)(0xffff-(x)))
+#define REVERSE_FLAVOR_8(x) ((cmsUInt8Number) (0xff-(x)))
+#define REVERSE_FLAVOR_16(x) ((cmsUInt16Number)(0xffff-(x)))
+
+// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256
+cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x)
+{
+ int a;
+
+ a = (x << 8 | x) >> 8; // * 257 / 256
+ if ( a > 0xffff) return 0xffff;
+ return (cmsUInt16Number) a;
+}
+
+// * 0xf00 / 0xffff = * 256 / 257
+cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x)
+{
+ return (cmsUInt16Number) (((x << 8) + 0x80) / 257);
+}
+
+
+typedef struct {
+ cmsUInt32Number Type;
+ cmsUInt32Number Mask;
+ cmsFormatter16 Frm;
+
+} cmsFormatters16;
+
+typedef struct {
+ cmsUInt32Number Type;
+ cmsUInt32Number Mask;
+ cmsFormatterFloat Frm;
+
+} cmsFormattersFloat;
+
+#define ANYSPACE COLORSPACE_SH(31)
+#define ANYCHANNELS CHANNELS_SH(15)
+#define ANYEXTRA EXTRA_SH(7)
+#define ANYPLANAR PLANAR_SH(1)
+#define ANYENDIAN ENDIAN16_SH(1)
+#define ANYSWAP DOSWAP_SH(1)
+#define ANYSWAPFIRST SWAPFIRST_SH(1)
+#define ANYFLAVOR FLAVOR_SH(1)
+
// Supress waning about info never being used
-#ifdef __BORLANDC__
-#pragma warn -par
-#endif
-
#ifdef _MSC_VER
#pragma warning(disable : 4100)
#endif
-// -------------------------------------------------------- Unpacking routines.
+// Unpacking routines (16 bits) ----------------------------------------------------------------------------------------
+
+// Does almost everything but is slow
+static
+cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int DoSwap = T_DOSWAP(info ->InputFormat);
+ int Reverse = T_FLAVOR(info ->InputFormat);
+ int SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ int Extra = T_EXTRA(info -> InputFormat);
+ int ExtraFirst = DoSwap && !SwapFirst;
+ cmsUInt16Number v;
+ int i;
+
+ if (ExtraFirst) {
+ accum += Extra;
+ }
+
+ for (i=0; i < nChan; i++) {
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = FROM_8_TO_16(*accum);
+ v = Reverse ? REVERSE_FLAVOR_16(v) : v;
+ wIn[index] = v;
+ accum++;
+ }
+
+ if (!ExtraFirst) {
+ accum += Extra;
+ }
+
+ if (Extra == 0 && SwapFirst) {
+ cmsUInt16Number tmp = wIn[0];
+
+ memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
+ wIn[nChan-1] = tmp;
+ }
+
+ return accum;
+}
+
+// Extra channels are just ignored because come in the next planes
+static
+cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int DoSwap= T_DOSWAP(info ->InputFormat);
+ int Reverse= T_FLAVOR(info ->InputFormat);
+ int i;
+ cmsUInt8Number* Init = accum;
+
+ if (DoSwap) {
+ accum += T_EXTRA(info -> InputFormat) * Stride;
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt16Number v = FROM_8_TO_16(*accum);
+
+ wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
+ accum += Stride;
+ }
+
+ return (Init + 1);
+}
+
+// Special cases, provided for performance
+static
+cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // C
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // M
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
+ wIn[3] = FROM_8_TO_16(*accum); accum++; // K
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C
+ wIn[1] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M
+ wIn[2] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y
+ wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[3] = FROM_8_TO_16(*accum); accum++; // K
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // C
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // M
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
+
+ return accum;
+}
+
+// KYMC
+static
+cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[3] = FROM_8_TO_16(*accum); accum++; // K
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // M
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // C
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // K
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // Y
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // M
+ wIn[3] = FROM_8_TO_16(*accum); accum++; // C
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // R
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // G
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // B
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ accum++; // A
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // B
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // G
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // R
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ accum++; // A
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // R
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // G
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // B
+
+ return accum;
+}
+
+
+// BRG
+static
+cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[2] = FROM_8_TO_16(*accum); accum++; // B
+ wIn[1] = FROM_8_TO_16(*accum); accum++; // G
+ wIn[0] = FROM_8_TO_16(*accum); accum++; // R
+
+ return accum;
+}
+
+static
+cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L
+ wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a
+ wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b
+
+ return accum;
+}
+
+static
+cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ accum++; // A
+ wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L
+ wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a
+ wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b
+
+ return accum;
+}
+
+static
+cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L
+ wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a
+ wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b
+
+ return accum;
+}
+
+
+
+// Monochrome + alpha. Alpha is lost
+static
+cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L
+ wIn[3] = FROM_8_TO_16(*accum); accum++; // alpha
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll2ByteSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[3] = FROM_8_TO_16(*accum); accum++; // alpha
+ wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L
+ return accum;
+}
+
+
+// Monochrome duplicates L into RGB for null-transforms
+static
+cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L
+ accum += 2;
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++; // L
+ return accum;
+}
+
+
+static
+cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int SwapEndian = T_ENDIAN16(info -> InputFormat);
+ int DoSwap = T_DOSWAP(info ->InputFormat);
+ int Reverse = T_FLAVOR(info ->InputFormat);
+ int SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ int Extra = T_EXTRA(info -> InputFormat);
+ int ExtraFirst = DoSwap && !SwapFirst;
+ int i;
+
+ if (ExtraFirst) {
+ accum += Extra * sizeof(cmsUInt16Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt16Number v = *(cmsUInt16Number*) accum;
+
+ if (SwapEndian)
+ v = CHANGE_ENDIAN(v);
+
+ wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
+
+ accum += sizeof(cmsUInt16Number);
+ }
+
+ if (!ExtraFirst) {
+ accum += Extra * sizeof(cmsUInt16Number);
+ }
+
+ if (Extra == 0 && SwapFirst) {
+
+ cmsUInt16Number tmp = wIn[0];
+
+ memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
+ wIn[nChan-1] = tmp;
+ }
+
+ return accum;
+}
+
+static
+cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int DoSwap= T_DOSWAP(info ->InputFormat);
+ int Reverse= T_FLAVOR(info ->InputFormat);
+ int SwapEndian = T_ENDIAN16(info -> InputFormat);
+ int i;
+ cmsUInt8Number* Init = accum;
+
+ if (DoSwap) {
+ accum += T_EXTRA(info -> InputFormat) * Stride * sizeof(cmsUInt16Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt16Number v = *(cmsUInt16Number*) accum;
+
+ if (SwapEndian)
+ v = CHANGE_ENDIAN(v);
+
+ wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
+
+ accum += Stride * sizeof(cmsUInt16Number);
+ }
+
+ return (Init + sizeof(cmsUInt16Number));
+}
static
-LPBYTE UnrollAnyBytes(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
+ wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
+ wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
+ wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C
+ wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M
+ wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y
+ wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
+ wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
+ wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
+ wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
+
+ return accum;
+}
+
+// KYMC
+static
+cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
+ wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
+ wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
+ wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K
+ wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y
+ wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M
+ wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C R
+ wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G
+ wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y B
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // C R
+ wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G
+ wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // Y B
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ accum += 2; // A
+ wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R
+ wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
+ wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ accum += 2; // A
+ wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R
+ wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
+ wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2;
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum;
+
+ accum += 8;
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L
+ wIn[3] = *(cmsUInt16Number*) accum; accum += 2; // alpha
+
+ return accum;
+}
+
+static
+cmsUInt8Number* Unroll2WordSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ wIn[3] = *(cmsUInt16Number*) accum; accum += 2; // alpha
+ wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L
+
+ return accum;
+}
+
+// This is a conversion of Lab double to 16 bits
+static
+cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ if (T_PLANAR(info -> InputFormat)) {
+
+ cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
+
+ cmsCIELab Lab;
+
+ Lab.L = Pt[0];
+ Lab.a = Pt[Stride];
+ Lab.b = Pt[Stride*2];
+
+ cmsFloat2LabEncoded(wIn, &Lab);
+ return accum + sizeof(cmsFloat64Number);
+ }
+ else {
+
+ cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum);
+ accum += sizeof(cmsCIELab);
+ return accum;
+ }
+}
+
+// This is a conversion of XYZ double to 16 bits
+static
+cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ if (T_PLANAR(info -> InputFormat)) {
+
+ cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
+ cmsCIEXYZ XYZ;
+
+ XYZ.X = Pt[0];
+ XYZ.Y = Pt[Stride];
+ XYZ.Z = Pt[Stride*2];
+ cmsFloat2XYZEncoded(wIn, &XYZ);
+
+ return accum + sizeof(cmsFloat64Number);
+
+ }
+
+ else {
+ cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum);
+ accum += sizeof(cmsCIEXYZ);
+
+ return accum;
+ }
+}
+
+// Check if space is marked as ink
+cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
+{
+ switch (T_COLORSPACE(Type)) {
+
+ case PT_CMY:
+ case PT_CMYK:
+ case PT_MCH5:
+ case PT_MCH6:
+ case PT_MCH7:
+ case PT_MCH8:
+ case PT_MCH9:
+ case PT_MCH10:
+ case PT_MCH11:
+ case PT_MCH12:
+ case PT_MCH13:
+ case PT_MCH14:
+ case PT_MCH15: return TRUE;
+
+ default: return FALSE;
+ }
+}
+
+// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits
+static
+cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- register int i;
-
- for (i=0; i < nChan; i++) {
-
- wIn[i] = RGB_8_TO_16(*accum); accum++;
- }
-
- return accum + T_EXTRA(info -> InputFormat);
+ cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int Planar = T_PLANAR(info -> InputFormat);
+ int i;
+ cmsFloat64Number v;
+ cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+
+ for (i=0; i < nChan; i++) {
+
+ if (Planar)
+
+ v = Inks[i * Stride];
+ else
+ v = Inks[i];
+
+ wIn[i] = _cmsQuickSaturateWord(v * maximum);
+ }
+
+ if (T_PLANAR(info -> InputFormat))
+ return accum + sizeof(cmsFloat64Number);
+ else
+ return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number);
+}
+
+static
+cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ cmsFloat32Number* Inks = (cmsFloat32Number*) accum;
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int Planar = T_PLANAR(info -> InputFormat);
+ int i;
+ cmsFloat32Number v;
+ cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+
+ for (i=0; i < nChan; i++) {
+
+ if (Planar)
+
+ v = Inks[i * Stride];
+ else
+ v = Inks[i];
+
+ wIn[i] = _cmsQuickSaturateWord(v * maximum);
+ }
+
+ if (T_PLANAR(info -> InputFormat))
+ return accum + sizeof(cmsFloat32Number);
+ else
+ return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
+}
+
+
+// For 1 channel, we need to duplicate data (it comes in 0..1.0 range)
+static
+cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
+
+ wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0);
+
+ return accum + sizeof(cmsFloat64Number);
+}
+
+//-------------------------------------------------------------------------------------------------------------------
+
+// True cmsFloat32Number transformation.
+
+// For anything going from cmsFloat32Number
+static
+cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsFloat32Number* Inks = (cmsFloat32Number*) accum;
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int Planar = T_PLANAR(info -> InputFormat);
+ int i;
+ cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
+
+
+ for (i=0; i < nChan; i++) {
+
+ if (Planar)
+ wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum);
+ else
+ wIn[i] = (cmsFloat32Number) (Inks[i] / maximum);
+ }
+
+ if (T_PLANAR(info -> InputFormat))
+ return accum + sizeof(cmsFloat32Number);
+ else
+ return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
+}
+
+// For anything going from double
+static
+cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int Planar = T_PLANAR(info -> InputFormat);
+ int i;
+ cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
+
+ for (i=0; i < nChan; i++) {
+
+ if (Planar)
+ wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum);
+ else
+ wIn[i] = (cmsFloat32Number) (Inks[i] / maximum);
+ }
+
+ if (T_PLANAR(info -> InputFormat))
+ return accum + sizeof(cmsFloat64Number);
+ else
+ return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number);
+}
+
+
+// From Lab double to cmsFloat32Number
+static
+cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
+
+ if (T_PLANAR(info -> InputFormat)) {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
+ wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1
+ wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
+
+ return accum + sizeof(cmsFloat64Number);
+ }
+ else {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
+ wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1
+ wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
+
+ accum += sizeof(cmsFloat64Number)*3;
+ return accum;
+ }
+}
+
+// From Lab double to cmsFloat32Number
+static
+cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
+
+ if (T_PLANAR(info -> InputFormat)) {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
+ wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1
+ wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
+
+ return accum + sizeof(cmsFloat32Number);
+ }
+ else {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
+ wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1
+ wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
+
+ accum += sizeof(cmsFloat32Number)*3;
+ return accum;
+ }
+}
+
+
+// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
+static
+cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
+
+ if (T_PLANAR(info -> InputFormat)) {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
+ wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
+ wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
+
+ return accum + sizeof(cmsFloat64Number);
+ }
+ else {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
+ wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
+ wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
+
+ accum += sizeof(cmsFloat64Number)*3;
+ return accum;
+ }
+}
+
+static
+cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
+
+ if (T_PLANAR(info -> InputFormat)) {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
+ wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
+ wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
+
+ return accum + sizeof(cmsFloat32Number);
+ }
+ else {
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
+ wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
+ wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
+
+ accum += sizeof(cmsFloat32Number)*3;
+ return accum;
+ }
+}
+
+// Packing routines -----------------------------------------------------------------------------------------------------------
+
+
+// Generic chunky for byte
+
+static
+cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse = T_FLAVOR(info ->OutputFormat);
+ int Extra = T_EXTRA(info -> OutputFormat);
+ int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ int ExtraFirst = DoSwap && !SwapFirst;
+ cmsUInt8Number* swap1;
+ cmsUInt8Number v = 0;
+ int i;
+
+ swap1 = output;
+
+ if (ExtraFirst) {
+ output += Extra;
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = FROM_16_TO_8(wOut[index]);
+
+ if (Reverse)
+ v = REVERSE_FLAVOR_8(v);
+
+ *output++ = v;
+ }
+
+ if (!ExtraFirst) {
+ output += Extra;
+ }
+
+ if (Extra == 0 && SwapFirst) {
+
+ memmove(swap1 + 1, swap1, nChan-1);
+ *swap1 = v;
+ }
+
+
+ return output;
}
static
-LPBYTE Unroll4Bytes(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = RGB_8_TO_16(*accum); accum++; // C
- wIn[1] = RGB_8_TO_16(*accum); accum++; // M
- wIn[2] = RGB_8_TO_16(*accum); accum++; // Y
- wIn[3] = RGB_8_TO_16(*accum); accum++; // K
-
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int SwapEndian = T_ENDIAN16(info -> InputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse = T_FLAVOR(info ->OutputFormat);
+ int Extra = T_EXTRA(info -> OutputFormat);
+ int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ int ExtraFirst = DoSwap && !SwapFirst;
+ cmsUInt16Number* swap1;
+ cmsUInt16Number v = 0;
+ int i;
+
+ swap1 = (cmsUInt16Number*) output;
+
+ if (ExtraFirst) {
+ output += Extra * sizeof(cmsUInt16Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = wOut[index];
+
+ if (SwapEndian)
+ v = CHANGE_ENDIAN(v);
+
+ if (Reverse)
+ v = REVERSE_FLAVOR_16(v);
+
+ *(cmsUInt16Number*) output = v;
+
+ output += sizeof(cmsUInt16Number);
+ }
+
+ if (!ExtraFirst) {
+ output += Extra * sizeof(cmsUInt16Number);
+ }
+
+ if (Extra == 0 && SwapFirst) {
+
+ memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
+ *swap1 = v;
+ }
+
+
+ return output;
}
+
static
-LPBYTE Unroll4BytesReverse(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = RGB_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C
- wIn[1] = RGB_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M
- wIn[2] = RGB_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y
- wIn[3] = RGB_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K
-
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse= T_FLAVOR(info ->OutputFormat);
+ int i;
+ cmsUInt8Number* Init = output;
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt8Number v = FROM_16_TO_8(wOut[index]);
+
+ *(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v);
+ output += Stride;
+ }
+
+ return (Init + 1);
}
static
-LPBYTE Unroll4BytesSwapFirst(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
-
- wIn[3] = RGB_8_TO_16(*accum); accum++; // K
- wIn[0] = RGB_8_TO_16(*accum); accum++; // C
- wIn[1] = RGB_8_TO_16(*accum); accum++; // M
- wIn[2] = RGB_8_TO_16(*accum); accum++; // Y
-
-
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse= T_FLAVOR(info ->OutputFormat);
+ int SwapEndian = T_ENDIAN16(info -> OutputFormat);
+ int i;
+ cmsUInt8Number* Init = output;
+ cmsUInt16Number v;
+
+ if (DoSwap) {
+ output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsUInt16Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = wOut[index];
+
+ if (SwapEndian)
+ v = CHANGE_ENDIAN(v);
+
+ if (Reverse)
+ v = REVERSE_FLAVOR_16(v);
+
+ *(cmsUInt16Number*) output = v;
+ output += (Stride * sizeof(cmsUInt16Number));
+ }
+
+ return (Init + sizeof(cmsUInt16Number));
+}
+
+// CMYKcm (unrolled for speed)
+
+static
+cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[3]);
+ *output++ = FROM_16_TO_8(wOut[4]);
+ *output++ = FROM_16_TO_8(wOut[5]);
+
+ return output;
}
-
-
-// KYMC
+// KCMYcm
+
static
-LPBYTE Unroll4BytesSwap(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[5]);
+ *output++ = FROM_16_TO_8(wOut[4]);
+ *output++ = FROM_16_TO_8(wOut[3]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+
+ return output;
+}
+
+// CMYKcm
+static
+cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[3] = RGB_8_TO_16(*accum); accum++; // K
- wIn[2] = RGB_8_TO_16(*accum); accum++; // Y
- wIn[1] = RGB_8_TO_16(*accum); accum++; // M
- wIn[0] = RGB_8_TO_16(*accum); accum++; // C
-
- return accum;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[3];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[4];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[5];
+ output+= 2;
+
+ return output;
+}
+
+// KCMYcm
+static
+cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = wOut[5];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[4];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[3];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+
+ return output;
}
static
-LPBYTE Unroll4BytesSwapSwapFirst(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[2] = RGB_8_TO_16(*accum); accum++; // K
- wIn[1] = RGB_8_TO_16(*accum); accum++; // Y
- wIn[0] = RGB_8_TO_16(*accum); accum++; // M
- wIn[3] = RGB_8_TO_16(*accum); accum++; // C
-
- return accum;
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[3]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0]));
+ *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1]));
+ *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2]));
+ *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3]));
+
+ return output;
}
static
-LPBYTE UnrollAnyWords(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[3]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+
+ return output;
+}
+
+// ABGR
+static
+cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[3]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[3]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- register int i;
-
- for (i=0; i < nChan; i++) {
-
- wIn[i] = *(LPWORD) accum; accum += 2;
- }
-
- return accum + T_EXTRA(info -> InputFormat) * sizeof(WORD);
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[3];
+ output+= 2;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
+ output+= 2;
+ *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]);
+ output+= 2;
+ *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]);
+ output+= 2;
+ *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]);
+ output+= 2;
+
+ return output;
+}
+
+// ABGR
+static
+cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = wOut[3];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+
+ return output;
+}
+
+// CMYK
+static
+cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
+ output+= 2;
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
+ output+= 2;
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
+ output+= 2;
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]);
+ output+= 2;
+
+ return output;
}
static
-LPBYTE Unroll4Words(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
+ *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
+ *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
+
+ return output;
+}
+
+static
+cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = *(LPWORD) accum; accum+= 2; // C
- wIn[1] = *(LPWORD) accum; accum+= 2; // M
- wIn[2] = *(LPWORD) accum; accum+= 2; // Y
- wIn[3] = *(LPWORD) accum; accum+= 2; // K
-
- return accum;
+ output++;
+ *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
+ *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
+ *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
+
+ return output;
+}
+
+static
+cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]);
+ output += 2;
+ *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]);
+ output += 2;
+ *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]);
+ output += 2;
+
+ return output;
}
static
-LPBYTE Unroll4WordsReverse(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = REVERSE_FLAVOR_16(*(LPWORD) accum); accum+= 2; // C
- wIn[1] = REVERSE_FLAVOR_16(*(LPWORD) accum); accum+= 2; // M
- wIn[2] = REVERSE_FLAVOR_16(*(LPWORD) accum); accum+= 2; // Y
- wIn[3] = REVERSE_FLAVOR_16(*(LPWORD) accum); accum+= 2; // K
-
- return accum;
+ *output++ = (wOut[0] & 0xFF);
+ *output++ = (wOut[1] & 0xFF);
+ *output++ = (wOut[2] & 0xFF);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = (wOut[2] & 0xFF);
+ *output++ = (wOut[1] & 0xFF);
+ *output++ = (wOut[0] & 0xFF);
+
+ return output;
}
static
-LPBYTE Unroll4WordsSwapFirst(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[3] = *(LPWORD) accum; accum+= 2; // K
- wIn[0] = *(LPWORD) accum; accum+= 2; // C
- wIn[1] = *(LPWORD) accum; accum+= 2; // M
- wIn[2] = *(LPWORD) accum; accum+= 2; // Y
-
- return accum;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+
+ return output;
}
-
-// KYMC
static
-LPBYTE Unroll4WordsSwap(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[3] = *(LPWORD) accum; accum+= 2; // K
- wIn[2] = *(LPWORD) accum; accum+= 2; // Y
- wIn[1] = *(LPWORD) accum; accum+= 2; // M
- wIn[0] = *(LPWORD) accum; accum+= 2; // C
-
- return accum;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+
+ return output;
}
static
-LPBYTE Unroll4WordsSwapSwapFirst(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
+ output+= 2;
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
+ output+= 2;
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
+ output+= 2;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[2] = *(LPWORD) accum; accum+= 2; // K
- wIn[1] = *(LPWORD) accum; accum+= 2; // Y
- wIn[0] = *(LPWORD) accum; accum+= 2; // M
- wIn[3] = *(LPWORD) accum; accum+= 2; // C
-
- return accum;
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+ output++;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = (wOut[0] & 0xFF);
+ *output++ = (wOut[1] & 0xFF);
+ *output++ = (wOut[2] & 0xFF);
+ output++;
+
+ return output;
}
static
-LPBYTE Unroll4WordsBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[0] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //C
- wIn[1] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //M
- wIn[2] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //Y
- wIn[3] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //K
-
- return accum;
-}
-
-static
-LPBYTE Unroll4WordsBigEndianReverse(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = REVERSE_FLAVOR_16(CHANGE_ENDIAN(*(LPWORD) accum)); accum+= 2; //C
- wIn[1] = REVERSE_FLAVOR_16(CHANGE_ENDIAN(*(LPWORD) accum)); accum+= 2; //M
- wIn[2] = REVERSE_FLAVOR_16(CHANGE_ENDIAN(*(LPWORD) accum)); accum+= 2; //Y
- wIn[3] = REVERSE_FLAVOR_16(CHANGE_ENDIAN(*(LPWORD) accum)); accum+= 2; //K
-
- return accum;
-}
-
-
-// KYMC
-static
-LPBYTE Unroll4WordsSwapBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[3] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //K
- wIn[2] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //Y
- wIn[1] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //M
- wIn[0] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2; //C
-
- return accum;
+ output++;
+ *output++ = FROM_16_TO_8(wOut[0]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[2]);
+
+ return output;
}
static
-LPBYTE Unroll3Bytes(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
-
- wIn[0] = RGB_8_TO_16(*accum); accum++; // R
- wIn[1] = RGB_8_TO_16(*accum); accum++; // G
- wIn[2] = RGB_8_TO_16(*accum); accum++; // B
-
- return accum;
-}
-
-
-// Lab8 encoding using v2 PCS
-
-static
-LPBYTE Unroll3BytesLab(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
-
- wIn[0] = (WORD) ((*accum) << 8); accum++;
- wIn[1] = (WORD) ((*accum) << 8); accum++;
- wIn[2] = (WORD) ((*accum) << 8); accum++;
-
- return accum;
-}
-
-
-// BRG
-
-static
-LPBYTE Unroll3BytesSwap(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
-
- wIn[2] = RGB_8_TO_16(*accum); accum++; // B
- wIn[1] = RGB_8_TO_16(*accum); accum++; // G
- wIn[0] = RGB_8_TO_16(*accum); accum++; // R
-
- return accum;
+ output++;
+ *output++ = (wOut[0] & 0xFF);
+ *output++ = (wOut[1] & 0xFF);
+ *output++ = (wOut[2] & 0xFF);
+
+ return output;
}
static
-LPBYTE Unroll3Words(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = *(LPWORD) accum; accum+= 2; // C R
- wIn[1] = *(LPWORD) accum; accum+= 2; // M G
- wIn[2] = *(LPWORD) accum; accum+= 2; // Y B
- return accum;
+ output++;
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ output++;
+ *output++ = (wOut[2] & 0xFF);
+ *output++ = (wOut[1] & 0xFF);
+ *output++ = (wOut[0] & 0xFF);
+
+ return output;
}
static
-LPBYTE Unroll3WordsSwap(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[2]);
+ *output++ = FROM_16_TO_8(wOut[1]);
+ *output++ = FROM_16_TO_8(wOut[0]);
+ output++;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = (wOut[2] & 0xFF);
+ *output++ = (wOut[1] & 0xFF);
+ *output++ = (wOut[0] & 0xFF);
+ output++;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[2] = *(LPWORD) accum; accum+= 2; // C R
- wIn[1] = *(LPWORD) accum; accum+= 2; // M G
- wIn[0] = *(LPWORD) accum; accum+= 2; // Y B
- return accum;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ output+= 2;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+
+ return output;
+}
+
+
+static
+cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+
+ return output;
}
static
-LPBYTE Unroll3WordsBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = wOut[2];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[1];
+ output+= 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+ output+= 2;
+
+ return output;
+}
+
+
+
+static
+cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(wOut[0]);
+ return output;
+}
+
+
+static
+cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0]));
+ return output;
+}
+
+
+static
+cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- wIn[1] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- wIn[2] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- return accum;
+ *output++ = FROM_16_TO_8(wOut[0]);
+ output++;
+ return output;
+}
+
+
+static
+cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ output++;
+ *output++ = FROM_16_TO_8(wOut[0]);
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+
+ return output;
+}
+
+
+static
+cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
+ output+= 2;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
+ output+= 2;
+
+ return output;
}
static
-LPBYTE Unroll3WordsSwapBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 4;
+
+ return output;
+}
+
+static
+cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[2] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- wIn[1] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- wIn[0] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- return accum;
+ output += 2;
+ *(cmsUInt16Number*) output = wOut[0];
+ output+= 2;
+
+ return output;
}
-
-// Monochrome duplicates L into RGB for null-transforms
+// Unencoded Float values -- don't try optimize speed
+static
+cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ cmsCIELab Lab;
+ cmsFloat64Number* Out = (cmsFloat64Number*) output;
+ cmsLabEncoded2Float(&Lab, wOut);
+
+ Out[0] = Lab.L;
+ Out[Stride] = Lab.a;
+ Out[Stride*2] = Lab.b;
+
+ return output + sizeof(cmsFloat64Number);
+ }
+ else {
+
+ cmsLabEncoded2Float((cmsCIELab*) output, wOut);
+ return output + (sizeof(cmsCIELab) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
+ }
+
+}
static
-LPBYTE Unroll1Byte(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = RGB_8_TO_16(*accum); accum++; // L
- return accum;
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ cmsCIEXYZ XYZ;
+ cmsFloat64Number* Out = (cmsFloat64Number*) output;
+ cmsXYZEncoded2Float(&XYZ, wOut);
+
+ Out[0] = XYZ.X;
+ Out[Stride] = XYZ.Y;
+ Out[Stride*2] = XYZ.Z;
+
+ return output + sizeof(cmsFloat64Number);
+
+ }
+ else {
+
+ cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut);
+
+ return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
+ }
}
-
static
-LPBYTE Unroll1ByteSkip2(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = RGB_8_TO_16(*accum); accum++; // L
- accum += 2;
- return accum;
+ cmsFloat64Number* Inks = (cmsFloat64Number*) output;
+ int nChan = T_CHANNELS(Info -> OutputFormat);
+ int i;
+ cmsFloat64Number maximum = IsInkSpace(Info ->InputFormat) ? 655.35 : 65535.0;
+
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ for (i=0; i < nChan; i++) {
+
+ Inks[i*Stride] = wOut[i] / maximum;
+ }
+
+ return output + sizeof(cmsFloat64Number);
+ }
+ else {
+
+ for (i=0; i < nChan; i++) {
+
+ Inks[i] = wOut[i] / maximum;
+ }
+
+
+ return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat64Number);
+ }
+
}
static
-LPBYTE Unroll1ByteReversed(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(RGB_8_TO_16(*accum)); accum++; // L
- return accum;
+ cmsFloat32Number* Inks = (cmsFloat32Number*) output;
+ int nChan = T_CHANNELS(Info -> OutputFormat);
+ int i;
+ cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0;
+
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ for (i=0; i < nChan; i++) {
+
+ Inks[i*Stride] = (cmsFloat32Number) (wOut[i] / maximum);
+ }
+
+ return output + sizeof(cmsFloat32Number);
+ }
+ else {
+
+ for (i=0; i < nChan; i++) {
+
+ Inks[i] = (cmsFloat32Number) (wOut[i] / maximum);
+ }
+
+
+ return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat32Number);
+ }
+
}
+// --------------------------------------------------------------------------------------------------------
+
static
-LPBYTE Unroll1Word(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = *(LPWORD) accum; accum+= 2; // L
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse = T_FLAVOR(info ->OutputFormat);
+ int Extra = T_EXTRA(info -> OutputFormat);
+ int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ int ExtraFirst = DoSwap && !SwapFirst;
+ cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
+ cmsFloat32Number* swap1;
+ cmsFloat64Number v = 0;
+ int i;
+
+ swap1 = (cmsFloat32Number*) output;
+
+ if (ExtraFirst) {
+ output += Extra * sizeof(cmsFloat32Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = wOut[index] * maximum;
+
+ if (Reverse)
+ v = maximum - v;
+
+ *(cmsFloat32Number*) output = (cmsFloat32Number) v;
+
+ output += sizeof(cmsFloat32Number);
+ }
+
+ if (!ExtraFirst) {
+ output += Extra * sizeof(cmsFloat32Number);
+ }
+
+ if (Extra == 0 && SwapFirst) {
+
+ memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
+ *swap1 = (cmsFloat32Number) v;
+ }
+
+
+ return output;
}
static
-LPBYTE Unroll1WordReversed(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(LPWORD) accum); accum+= 2;
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse= T_FLAVOR(info ->OutputFormat);
+ int i;
+ cmsUInt8Number* Init = output;
+ cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
+ cmsFloat64Number v;
+
+ if (DoSwap) {
+ output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat32Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = wOut[index] * maximum;
+
+ if (Reverse)
+ v = maximum - v;
+
+ *(cmsFloat32Number*) output = (cmsFloat32Number) v;
+ output += (Stride * sizeof(cmsFloat32Number));
+ }
+
+ return (Init + sizeof(cmsFloat32Number));
}
static
-LPBYTE Unroll1WordBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[0] = wIn[1] = wIn[2] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- return accum;
-}
-
-static
-LPBYTE Unroll1WordSkip3(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackChunkyDoublesFromFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = *(LPWORD) accum;
-
- accum += 8;
- return accum;
-}
-
-
-// Monochrome + alpha. Alpha is lost
-
-static
-LPBYTE Unroll2Byte(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[0] = wIn[1] = wIn[2] = RGB_8_TO_16(*accum); accum++; // L
- wIn[3] = RGB_8_TO_16(*accum); accum++; // alpha
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse = T_FLAVOR(info ->OutputFormat);
+ int Extra = T_EXTRA(info -> OutputFormat);
+ int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ int ExtraFirst = DoSwap && !SwapFirst;
+ cmsFloat64Number* swap1;
+ cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
+ cmsFloat64Number v = 0;
+ int i;
+
+ swap1 = (cmsFloat64Number*) output;
+
+ if (ExtraFirst) {
+ output += Extra * sizeof(cmsFloat64Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = (cmsFloat64Number) wOut[index] * maximum;
+
+ if (Reverse)
+ v = maximum - v;
+
+ *(cmsFloat64Number*) output = v;
+
+ output += sizeof(cmsFloat64Number);
+ }
+
+ if (!ExtraFirst) {
+ output += Extra * sizeof(cmsFloat64Number);
+ }
+
+ if (Extra == 0 && SwapFirst) {
+
+ memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
+ *swap1 = v;
+ }
+
+
+ return output;
}
static
-LPBYTE Unroll2ByteSwapFirst(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[3] = RGB_8_TO_16(*accum); accum++; // alpha
- wIn[0] = wIn[1] = wIn[2] = RGB_8_TO_16(*accum); accum++; // L
- return accum;
-}
-
-
-static
-LPBYTE Unroll2Word(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackPlanarDoublesFromFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
- wIn[0] = wIn[1] = wIn[2] = *(LPWORD) accum; accum+= 2; // L
- wIn[3] = *(LPWORD) accum; accum += 2; // alpha
-
- return accum;
-}
-
-
-static
-LPBYTE Unroll2WordSwapFirst(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[3] = *(LPWORD) accum; accum += 2; // alpha
- wIn[0] = wIn[1] = wIn[2] = *(LPWORD) accum; accum+= 2; // L
-
- return accum;
-}
-
-static
-LPBYTE Unroll2WordBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- wIn[0] = wIn[1] = wIn[2] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
- wIn[3] = CHANGE_ENDIAN(*(LPWORD) accum); accum+= 2;
-
- return accum;
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int Reverse= T_FLAVOR(info ->OutputFormat);
+ int i;
+ cmsUInt8Number* Init = output;
+ cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
+ cmsFloat64Number v;
+
+ if (DoSwap) {
+ output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat64Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ v = (cmsFloat64Number) wOut[index] * maximum;
+
+ if (Reverse)
+ v = maximum - v;
+
+ *(cmsFloat64Number*) output = v;
+ output += (Stride * sizeof(cmsFloat64Number));
+ }
+
+ return (Init + sizeof(cmsFloat64Number));
}
static
-LPBYTE UnrollPlanarBytes(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- int nChan = T_CHANNELS(info -> InputFormat);
- register int i;
- LPBYTE Init = accum;
-
- for (i=0; i < nChan; i++) {
-
- wIn[i] = RGB_8_TO_16(*accum);
- accum += info -> StrideIn;
- }
-
- return (Init + 1);
-}
-
-
-
-static
-LPBYTE UnrollPlanarWords(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
+cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- register int i;
- LPBYTE Init = accum;
-
- for (i=0; i < nChan; i++) {
-
- wIn[i] = *(LPWORD) accum;
- accum += (info -> StrideIn * sizeof(WORD));
- }
-
- return (Init + sizeof(WORD));
-}
-
-
-
-static
-LPBYTE UnrollPlanarWordsBigEndian(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- int nChan = T_CHANNELS(info -> InputFormat);
- register int i;
- LPBYTE Init = accum;
-
- for (i=0; i < nChan; i++) {
-
- wIn[i] = CHANGE_ENDIAN(*(LPWORD) accum);
- accum += (info -> StrideIn * sizeof(WORD));
- }
-
- return (Init + sizeof(WORD));
-}
-
-
-// floating point
-static
-LPBYTE UnrollLabDouble(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
-
- if (T_PLANAR(info -> InputFormat)) {
-
- double* Pt = (double*) accum;
-
- cmsCIELab Lab;
-
- Lab.L = Pt[0];
- Lab.a = Pt[info->StrideIn];
- Lab.b = Pt[info->StrideIn*2];
-
- if (info ->lInputV4Lab)
- cmsFloat2LabEncoded4(wIn, &Lab);
- else
- cmsFloat2LabEncoded(wIn, &Lab);
-
- return accum + sizeof(double);
+ cmsFloat32Number* Out = (cmsFloat32Number*) output;
+
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
+ Out[Stride] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
+ Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
+
+ return output + sizeof(cmsFloat32Number);
}
else {
- if (info ->lInputV4Lab)
- cmsFloat2LabEncoded4(wIn, (LPcmsCIELab) accum);
- else
- cmsFloat2LabEncoded(wIn, (LPcmsCIELab) accum);
-
- accum += sizeof(cmsCIELab);
-
- return accum;
- }
-}
-
-static
-LPBYTE UnrollXYZDouble(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- if (T_PLANAR(info -> InputFormat)) {
-
- double* Pt = (double*) accum;
- cmsCIEXYZ XYZ;
-
- XYZ.X = Pt[0];
- XYZ.Y = Pt[info->StrideIn];
- XYZ.Z = Pt[info->StrideIn*2];
- cmsFloat2XYZEncoded(wIn, &XYZ);
-
- return accum + sizeof(double);
-
- }
-
- else {
-
-
- cmsFloat2XYZEncoded(wIn, (LPcmsCIEXYZ) accum);
- accum += sizeof(cmsCIEXYZ);
-
- return accum;
- }
-}
-
-
-
-// Inks does come in percentage
-static
-LPBYTE UnrollInkDouble(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- double* Inks = (double*) accum;
- int nChan = T_CHANNELS(info -> InputFormat);
- int Planar = T_PLANAR(info -> InputFormat);
- int i;
- double v;
-
- for (i=0; i < nChan; i++) {
-
- if (Planar)
-
- v = Inks[i * info ->StrideIn];
- else
- v = Inks[i];
-
- v = floor(v * 655.35 + 0.5);
-
- if (v > 65535.0) v = 65535.0;
- if (v < 0) v = 0;
-
- wIn[i] = (WORD) v;
- }
-
- if (T_PLANAR(info -> InputFormat))
- return accum + sizeof(double);
- else
- return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(double);
-}
-
-
-// Remaining cases are between 0..1.0
-static
-LPBYTE UnrollDouble(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- double* Inks = (double*) accum;
- int nChan = T_CHANNELS(info -> InputFormat);
- int Planar = T_PLANAR(info -> InputFormat);
- int i;
- double v;
-
- for (i=0; i < nChan; i++) {
-
- if (Planar)
-
- v = Inks[i * info ->StrideIn];
- else
- v = Inks[i];
-
- v = floor(v * 65535.0 + 0.5);
-
- if (v > 65535.0) v = 65535.0;
- if (v < 0) v = 0;
-
- wIn[i] = (WORD) v;
- }
-
- if (T_PLANAR(info -> InputFormat))
- return accum + sizeof(double);
- else
- return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(double);
-}
-
-
-
-static
-LPBYTE UnrollDouble1Chan(register _LPcmsTRANSFORM info, register WORD wIn[], register LPBYTE accum)
-{
- double* Inks = (double*) accum;
- double v;
-
-
- v = floor(Inks[0] * 65535.0 + 0.5);
-
- if (v > 65535.0) v = 65535.0;
- if (v < 0) v = 0;
-
-
- wIn[0] = wIn[1] = wIn[2] = (WORD) v;
-
- return accum + sizeof(double);
-}
-
-
-// ----------------------------------------------------------- Packing routines
-
-
-// Generic N-bytes plus dither 16-to-8 conversion. Currently is just a quick hack
-
-static int err[MAXCHANNELS];
-
-static
-LPBYTE PackNBytesDither(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
- unsigned int n, pe, pf;
-
- for (i=0; i < nChan; i++) {
-
- n = wOut[i] + err[i]; // Value
-
- pe = (n / 257); // Whole part
- pf = (n % 257); // Fractional part
-
- err[i] = pf; // Store it for next pixel
-
- *output++ = (BYTE) pe;
- }
-
- return output + T_EXTRA(info ->OutputFormat);
-}
-
-
-
-static
-LPBYTE PackNBytesSwapDither(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
- unsigned int n, pe, pf;
-
- for (i=nChan-1; i >= 0; --i) {
-
- n = wOut[i] + err[i]; // Value
-
- pe = (n / 257); // Whole part
- pf = (n % 257); // Fractional part
-
- err[i] = pf; // Store it for next pixel
-
- *output++ = (BYTE) pe;
- }
-
-
- return output + T_EXTRA(info ->OutputFormat);
-}
-
-
-
-// Generic chunky for byte
-
-static
-LPBYTE PackNBytes(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
-
- for (i=0; i < nChan; i++)
- *output++ = RGB_16_TO_8(wOut[i]);
-
- return output + T_EXTRA(info ->OutputFormat);
-}
-
-// Chunky reversed order bytes
-
-static
-LPBYTE PackNBytesSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
-
- for (i=nChan-1; i >= 0; --i)
- *output++ = RGB_16_TO_8(wOut[i]);
-
- return output + T_EXTRA(info ->OutputFormat);
-
-}
-
-
-static
-LPBYTE PackNWords(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
-
- for (i=0; i < nChan; i++) {
- *(LPWORD) output = wOut[i];
- output += sizeof(WORD);
- }
-
- return output + T_EXTRA(info ->OutputFormat) * sizeof(WORD);
-}
-
-static
-LPBYTE PackNWordsSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
-
- for (i=nChan-1; i >= 0; --i) {
- *(LPWORD) output = wOut[i];
- output += sizeof(WORD);
- }
-
- return output + T_EXTRA(info ->OutputFormat) * sizeof(WORD);
-}
-
-
-
-static
-LPBYTE PackNWordsBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
-
- for (i=0; i < nChan; i++) {
- *(LPWORD) output = CHANGE_ENDIAN(wOut[i]);
- output += sizeof(WORD);
- }
-
- return output + T_EXTRA(info ->OutputFormat) * sizeof(WORD);
-}
-
-
-static
-LPBYTE PackNWordsSwapBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
-
- for (i=nChan-1; i >= 0; --i) {
- *(LPWORD) output = CHANGE_ENDIAN(wOut[i]);
- output += sizeof(WORD);
- }
-
- return output + T_EXTRA(info ->OutputFormat) * sizeof(WORD);
-}
-
-
-static
-LPBYTE PackPlanarBytes(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
- LPBYTE Init = output;
-
- for (i=0; i < nChan; i++) {
-
- *(LPBYTE) output = RGB_16_TO_8(wOut[i]);
- output += info -> StrideOut;
- }
-
- return (Init + 1);
-}
-
-
-static
-LPBYTE PackPlanarWords(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- int nChan = T_CHANNELS(info -> OutputFormat);
- register int i;
- LPBYTE Init = output;
-
- for (i=0; i < nChan; i++) {
-
- *(LPWORD) output = wOut[i];
- output += (info -> StrideOut * sizeof(WORD));
- }
-
- return (Init + 2);
-}
-
-
-// CMYKcm (unrolled for speed)
-
-static
-LPBYTE Pack6Bytes(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[3]);
- *output++ = RGB_16_TO_8(wOut[4]);
- *output++ = RGB_16_TO_8(wOut[5]);
-
- return output;
-}
-
-// KCMYcm
-
-static
-LPBYTE Pack6BytesSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[3]);
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[4]);
- *output++ = RGB_16_TO_8(wOut[5]);
-
- return output;
-}
-
-// CMYKcm
-static
-LPBYTE Pack6Words(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[0];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[3];
- output+= 2;
- *(LPWORD) output = wOut[4];
- output+= 2;
- *(LPWORD) output = wOut[5];
- output+= 2;
-
- return output;
-}
-
-// KCMYcm
-static
-LPBYTE Pack6WordsSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[3];
- output+= 2;
- *(LPWORD) output = wOut[0];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[4];
- output+= 2;
- *(LPWORD) output = wOut[5];
- output+= 2;
-
- return output;
-}
-
-// CMYKcm
-static
-LPBYTE Pack6WordsBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[3]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[4]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[5]);
- output+= 2;
-
- return output;
-}
-
-// KCMYcm
-static
-LPBYTE Pack6WordsSwapBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[3]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[4]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[5]);
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack4Bytes(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[3]);
-
- return output;
-}
-
-static
-LPBYTE Pack4BytesReverse(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = REVERSE_FLAVOR_8(RGB_16_TO_8(wOut[0]));
- *output++ = REVERSE_FLAVOR_8(RGB_16_TO_8(wOut[1]));
- *output++ = REVERSE_FLAVOR_8(RGB_16_TO_8(wOut[2]));
- *output++ = REVERSE_FLAVOR_8(RGB_16_TO_8(wOut[3]));
-
- return output;
-}
-
-
-static
-LPBYTE Pack4BytesSwapFirst(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[3]);
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
-
- return output;
-}
-
-
-// ABGR
-
-static
-LPBYTE Pack4BytesSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[3]);
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[0]);
-
- return output;
-}
-
-
-static
-LPBYTE Pack4BytesSwapSwapFirst(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[3]);
-
- return output;
-}
-
-
-static
-LPBYTE Pack4Words(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[0];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[3];
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack4WordsReverse(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = REVERSE_FLAVOR_16(wOut[0]);
- output+= 2;
- *(LPWORD) output = REVERSE_FLAVOR_16(wOut[1]);
- output+= 2;
- *(LPWORD) output = REVERSE_FLAVOR_16(wOut[2]);
- output+= 2;
- *(LPWORD) output = REVERSE_FLAVOR_16(wOut[3]);
- output+= 2;
-
- return output;
-}
-
-// ABGR
-
-static
-LPBYTE Pack4WordsSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[3];
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[0];
- output+= 2;
-
- return output;
-}
-
-// CMYK
-static
-LPBYTE Pack4WordsBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[3]);
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack4WordsBigEndianReverse(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(REVERSE_FLAVOR_16(wOut[0]));
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(REVERSE_FLAVOR_16(wOut[1]));
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(REVERSE_FLAVOR_16(wOut[2]));
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(REVERSE_FLAVOR_16(wOut[3]));
- output+= 2;
-
- return output;
-}
-
-// KYMC
-
-static
-LPBYTE Pack4WordsSwapBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[3]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
-
- return output;
-}
-
-static
-LPBYTE Pack3Bytes(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
-
- return output;
-}
-
-static
-LPBYTE Pack3BytesLab(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = (BYTE) (wOut[0] >> 8);
- *output++ = (BYTE) (wOut[1] >> 8);
- *output++ = (BYTE) (wOut[2] >> 8);
-
- return output;
-}
-
-
-static
-LPBYTE Pack3BytesSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[0]);
-
- return output;
-}
-
-
-static
-LPBYTE Pack3Words(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[0];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
-
- return output;
-}
-
-static
-LPBYTE Pack3WordsSwap(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[0];
- output+= 2;
-
- return output;
-}
-
-static
-LPBYTE Pack3WordsBigEndian(register _LPcmsTRANSFORM info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack3WordsSwapBigEndian(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack3BytesAndSkip1(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
- output++;
-
- return output;
-}
-
-
-static
-LPBYTE Pack3BytesAndSkip1SwapFirst(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- output++;
- *output++ = RGB_16_TO_8(wOut[0]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[2]);
-
- return output;
-}
-
-static
-LPBYTE Pack3BytesAndSkip1Swap(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- output++;
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[0]);
-
- return output;
-}
-
-
-static
-LPBYTE Pack3BytesAndSkip1SwapSwapFirst(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[2]);
- *output++ = RGB_16_TO_8(wOut[1]);
- *output++ = RGB_16_TO_8(wOut[0]);
- output++;
-
- return output;
-}
-
-
-static
-LPBYTE Pack3WordsAndSkip1(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[0];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
- output+= 2;
-
- return output;
-}
-
-static
-LPBYTE Pack3WordsAndSkip1Swap(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- output+= 2;
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[0];
- output+= 2;
-
-
- return output;
-}
-
-
-static
-LPBYTE Pack3WordsAndSkip1SwapSwapFirst(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[2];
- output+= 2;
- *(LPWORD) output = wOut[1];
- output+= 2;
- *(LPWORD) output = wOut[0];
- output+= 2;
- output+= 2;
-
-
- return output;
-}
-
-
-static
-LPBYTE Pack3WordsAndSkip1BigEndian(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack3WordsAndSkip1SwapBigEndian(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[2]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[1]);
- output+= 2;
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
-
-
- return output;
-}
-
-
-
-static
-LPBYTE Pack1Byte(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[0]);
- return output;
-}
-
-
-static
-LPBYTE Pack1ByteAndSkip1(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *output++ = RGB_16_TO_8(wOut[0]);
- output++;
- return output;
-}
-
-
-static
-LPBYTE Pack1ByteAndSkip1SwapFirst(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- output++;
- *output++ = RGB_16_TO_8(wOut[0]);
-
- return output;
-}
-
-static
-LPBYTE Pack1Word(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[0];
- output+= 2;
-
- return output;
-}
-
-static
-LPBYTE Pack1WordBigEndian(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack1WordAndSkip1(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = wOut[0];
- output+= 4;
-
- return output;
-}
-
-static
-LPBYTE Pack1WordAndSkip1SwapFirst(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- output += 2;
- *(LPWORD) output = wOut[0];
- output+= 2;
-
- return output;
-}
-
-
-static
-LPBYTE Pack1WordAndSkip1BigEndian(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- *(LPWORD) output = CHANGE_ENDIAN(wOut[0]);
- output+= 4;
-
- return output;
-}
-
-
-// Unencoded Float values -- don't try optimize speed
-
-static
-LPBYTE PackLabDouble(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
-
- if (T_PLANAR(Info -> OutputFormat)) {
-
- cmsCIELab Lab;
- double* Out = (double*) output;
- cmsLabEncoded2Float(&Lab, wOut);
-
- Out[0] = Lab.L;
- Out[Info ->StrideOut] = Lab.a;
- Out[Info ->StrideOut*2] = Lab.b;
-
- return output + sizeof(double);
-
- }
- else {
-
- if (Info ->lOutputV4Lab)
- cmsLabEncoded2Float4((LPcmsCIELab) output, wOut);
- else
- cmsLabEncoded2Float((LPcmsCIELab) output, wOut);
-
- return output + (sizeof(cmsCIELab) + T_EXTRA(Info ->OutputFormat) * sizeof(double));
+ Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
+ Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
+ Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
+
+ return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
}
}
static
-LPBYTE PackXYZDouble(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
+cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
+ cmsFloat64Number* Out = (cmsFloat64Number*) output;
if (T_PLANAR(Info -> OutputFormat)) {
- cmsCIEXYZ XYZ;
- double* Out = (double*) output;
- cmsXYZEncoded2Float(&XYZ, wOut);
-
- Out[0] = XYZ.X;
- Out[Info ->StrideOut] = XYZ.Y;
- Out[Info ->StrideOut*2] = XYZ.Z;
-
- return output + sizeof(double);
-
+ Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
+ Out[Stride] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
+ Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
+
+ return output + sizeof(cmsFloat64Number);
}
else {
- cmsXYZEncoded2Float((LPcmsCIEXYZ) output, wOut);
-
- return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(double));
- }
-}
-
-
-
-static
-LPBYTE PackInkDouble(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
-{
- double* Inks = (double*) output;
- int nChan = T_CHANNELS(Info -> OutputFormat);
- int i;
-
- if (T_PLANAR(Info -> OutputFormat)) {
-
- for (i=0; i < nChan; i++) {
-
- Inks[i*Info ->StrideOut] = wOut[i] / 655.35;
- }
-
- return output + sizeof(double);
- }
- else {
-
- for (i=0; i < nChan; i++) {
-
- Inks[i] = wOut[i] / 655.35;
- }
-
-
- return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(double);
+ Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
+ Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
+ Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
+
+ return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
}
}
+// From 0..1 range to 0..MAX_ENCODEABLE_XYZ
static
-LPBYTE PackDouble(register _LPcmsTRANSFORM Info, register WORD wOut[], register LPBYTE output)
+cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
{
- double* Inks = (double*) output;
- int nChan = T_CHANNELS(Info -> OutputFormat);
- int i;
-
+ cmsFloat32Number* Out = (cmsFloat32Number*) output;
if (T_PLANAR(Info -> OutputFormat)) {
- for (i=0; i < nChan; i++) {
-
- Inks[i*Info ->StrideOut] = wOut[i] / 65535.0;
- }
-
- return output + sizeof(double);
-
+ Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
+ Out[Stride] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
+ Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
+
+ return output + sizeof(cmsFloat32Number);
}
else {
- for (i=0; i < nChan; i++) {
-
- Inks[i] = wOut[i] / 65535.0;
- }
-
- return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(double);
+
+ Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
+ Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
+ Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
+
+ return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
+ }
+
+}
+
+
+// Same, but convert to double
+static
+cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
+ cmsFloat32Number wOut[],
+ cmsUInt8Number* output,
+ cmsUInt32Number Stride)
+{
+ cmsFloat64Number* Out = (cmsFloat64Number*) output;
+
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
+ Out[Stride] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
+ Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
+
+ return output + sizeof(cmsFloat64Number);
+ }
+ else {
+
+ Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
+ Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
+ Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
+
+ return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
}
}
-// choose routine from Input identifier
-
-_cmsFIXFN _cmsIdentifyInputFormat(_LPcmsTRANSFORM xform, DWORD dwInput)
-{
- _cmsFIXFN FromInput = NULL;
-
-
- // Check Named Color
-
- if (xform) {
-
- if (xform ->InputProfile) {
-
- if (cmsGetDeviceClass(xform ->InputProfile) == icSigNamedColorClass) {
-
- if (dwInput != TYPE_NAMED_COLOR_INDEX) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Named color needs TYPE_NAMED_COLOR_INDEX");
- return NULL;
- }
- }
-
- }
- }
-
- // Unencoded modes
-
- if (T_BYTES(dwInput) == 0) {
-
- switch (T_COLORSPACE(dwInput)) {
-
- case PT_Lab:
- FromInput = UnrollLabDouble;
- break;
- case PT_XYZ:
- FromInput = UnrollXYZDouble;
- break;
-
- // 0.0 .. 1.0 range
-
- case PT_GRAY:
- case PT_RGB:
- case PT_YCbCr:
- case PT_YUV:
- case PT_YUVK:
- case PT_HSV:
- case PT_HLS:
- case PT_Yxy:
- if (T_CHANNELS(dwInput) == 1)
- FromInput = UnrollDouble1Chan;
- else
- FromInput = UnrollDouble;
- break;
-
- // Inks (%) 0.0 .. 100.0
-
- default:
- FromInput = UnrollInkDouble;
- break;
- }
-
- }
- else {
-
- if (T_PLANAR(dwInput)) {
-
- switch (T_BYTES(dwInput)) {
-
- case 1:
- FromInput = UnrollPlanarBytes;
- break;
-
- case 2:
- if (T_ENDIAN16(dwInput))
- FromInput = UnrollPlanarWordsBigEndian;
- else
- FromInput = UnrollPlanarWords;
- break;
-
- default:;
- }
- }
- else {
-
- switch (T_BYTES(dwInput)) {
-
- case 1: // 1 byte per channel
-
- switch (T_CHANNELS(dwInput) + T_EXTRA(dwInput)) {
-
- case 1: if (T_FLAVOR(dwInput))
- FromInput = Unroll1ByteReversed;
- else
- FromInput = Unroll1Byte;
- break;
-
- case 2: if (T_SWAPFIRST(dwInput))
- FromInput = Unroll2ByteSwapFirst;
- else
- FromInput = Unroll2Byte;
- break;
-
- case 3: if (T_DOSWAP(dwInput))
- FromInput = Unroll3BytesSwap;
- else {
- if (T_EXTRA(dwInput) == 2)
- FromInput = Unroll1ByteSkip2;
- else
- if (T_COLORSPACE(dwInput) == PT_Lab)
- FromInput = Unroll3BytesLab;
- else
- FromInput = Unroll3Bytes;
- }
- break;
- case 4:
- // TODO: ALab8 must be fixed to match v2 encoding
-
- if (T_DOSWAP(dwInput)) {
- if (T_SWAPFIRST(dwInput))
-
- FromInput = Unroll4BytesSwapSwapFirst;
- else
- FromInput = Unroll4BytesSwap;
- }
- else {
- if (T_SWAPFIRST(dwInput))
- FromInput = Unroll4BytesSwapFirst;
- else {
- if (T_FLAVOR(dwInput))
- FromInput = Unroll4BytesReverse;
- else
- FromInput = Unroll4Bytes;
- }
- }
- break;
-
-
- case 5:
- case 6:
- case 7:
- case 8:
- if (!T_DOSWAP(dwInput) && !T_SWAPFIRST(dwInput))
- FromInput = UnrollAnyBytes;
- break;
-
-
- default:;
- }
- break;
-
-
- case 2: // 1 word per channel
-
- switch (T_CHANNELS(dwInput) + T_EXTRA(dwInput))
- {
- case 1: if (T_ENDIAN16(dwInput))
- FromInput = Unroll1WordBigEndian;
- else
- if (T_FLAVOR(dwInput))
- FromInput = Unroll1WordReversed;
- else
- FromInput = Unroll1Word;
- break;
-
- case 2: if (T_ENDIAN16(dwInput))
- FromInput = Unroll2WordBigEndian;
- else {
- if (T_SWAPFIRST(dwInput))
- FromInput = Unroll2WordSwapFirst;
- else
- FromInput = Unroll2Word;
- }
- break;
-
- case 3: if (T_DOSWAP(dwInput)) {
- if (T_ENDIAN16(dwInput))
- FromInput = Unroll3WordsSwapBigEndian;
- else
- FromInput = Unroll3WordsSwap;
- }
- else {
- if (T_ENDIAN16(dwInput))
- FromInput = Unroll3WordsBigEndian;
- else
- FromInput = Unroll3Words;
- }
- break;
-
- case 4: if (T_DOSWAP(dwInput)) {
-
- if (T_ENDIAN16(dwInput))
- FromInput = Unroll4WordsSwapBigEndian;
- else {
-
- if (T_SWAPFIRST(dwInput))
- FromInput = Unroll4WordsSwapSwapFirst;
- else
- FromInput = Unroll4WordsSwap;
-
- }
-
- }
- else {
-
- if (T_EXTRA(dwInput) == 3)
- FromInput = Unroll1WordSkip3;
- else
-
- if (T_ENDIAN16(dwInput)) {
-
- if (T_FLAVOR(dwInput))
- FromInput = Unroll4WordsBigEndianReverse;
- else
- FromInput = Unroll4WordsBigEndian;
- }
- else {
- if (T_SWAPFIRST(dwInput))
- FromInput = Unroll4WordsSwapFirst;
- else {
- if (T_FLAVOR(dwInput))
- FromInput = Unroll4WordsReverse;
- else
- FromInput = Unroll4Words;
- }
- }
- }
- break;
-
-
- case 5:
- case 6:
- case 7:
- case 8:
- if (!T_DOSWAP(dwInput) && !T_SWAPFIRST(dwInput))
- FromInput = UnrollAnyWords;
- break;
-
- }
- break;
-
- default:;
- }
- }
- }
-
-
- if (!FromInput)
- cmsSignalError(LCMS_ERRC_ABORTED, "Unknown input format");
-
- return FromInput;
-}
-
-// choose routine from Input identifier
-
-_cmsFIXFN _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput)
+// ----------------------------------------------------------------------------------------------------------------
+
+
+static cmsFormatters16 InputFormatters16[] = {
+
+ // Type Mask Function
+ // ---------------------------- ------------------------------------ ----------------------------
+ { TYPE_Lab_DBL, ANYPLANAR, UnrollLabDoubleTo16},
+ { TYPE_XYZ_DBL, ANYPLANAR, UnrollXYZDoubleTo16},
+ { TYPE_GRAY_DBL, 0, UnrollDouble1Chan},
+ { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollDoubleTo16},
+ { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollFloatTo16},
+
+
+ { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Unroll1Byte},
+ { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2), ANYSPACE, Unroll1ByteSkip2},
+ { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll1ByteReversed},
+
+ { CHANNELS_SH(2)|BYTES_SH(1), ANYSPACE, Unroll2Bytes},
+ { CHANNELS_SH(2)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll2ByteSwapFirst},
+
+ { TYPE_LabV2_8, 0, UnrollLabV2_8 },
+ { TYPE_ALabV2_8, 0, UnrollALabV2_8 },
+ { TYPE_LabV2_16, 0, UnrollLabV2_16 },
+
+ { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Unroll3Bytes},
+ { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSwap},
+ { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap},
+ { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst},
+
+ { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes},
+ { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse},
+ { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst},
+ { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap},
+ { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst},
+
+ { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
+ { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
+
+
+ { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word},
+ { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed},
+ { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3), ANYSPACE, Unroll1WordSkip3},
+
+ { CHANNELS_SH(2)|BYTES_SH(2), ANYSPACE, Unroll2Words},
+ { CHANNELS_SH(2)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll2WordSwapFirst},
+
+ { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Unroll3Words},
+ { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Unroll4Words},
+
+ { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSwap},
+ { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3WordsSkip1SwapFirst},
+ { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSkip1Swap},
+ { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll4WordsReverse},
+ { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapFirst},
+ { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll4WordsSwap},
+ { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst},
+
+
+ { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords },
+ { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords},
+};
+
+
+
+static cmsFormattersFloat InputFormattersFloat[] = {
+
+ // Type Mask Function
+ // ---------------------------- ------------------------------------ ----------------------------
+ { TYPE_Lab_DBL, ANYPLANAR, UnrollLabDoubleToFloat},
+ { TYPE_Lab_FLT, ANYPLANAR, UnrollLabFloatToFloat},
+ { TYPE_XYZ_DBL, ANYPLANAR, UnrollXYZDoubleToFloat},
+ { TYPE_XYZ_FLT, ANYPLANAR, UnrollXYZFloatToFloat},
+
+ { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat},
+ { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat},
+};
+
+
+// Bit fields set to one in the mask are not compared
+static
+cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
{
- _cmsFIXFN ToOutput = NULL;
-
-
- if (T_BYTES(dwOutput) == 0) {
-
- switch (T_COLORSPACE(dwOutput)) {
-
- case PT_Lab:
- ToOutput = PackLabDouble;
- break;
- case PT_XYZ:
- ToOutput = PackXYZDouble;
- break;
-
- // 0.0 .. 1.0 range
- case PT_GRAY:
- case PT_RGB:
- case PT_YCbCr:
- case PT_YUV:
- case PT_YUVK:
- case PT_HSV:
- case PT_HLS:
- case PT_Yxy:
- ToOutput = PackDouble;
- break;
-
- // Inks (%) 0.0 .. 100.0
-
- default:
- ToOutput = PackInkDouble;
- break;
- }
-
- }
- else
-
- if (T_PLANAR(dwOutput)) {
-
- switch (T_BYTES(dwOutput)) {
-
- case 1: ToOutput = PackPlanarBytes;
- break;
-
- case 2:if (!T_ENDIAN16(dwOutput))
- ToOutput = PackPlanarWords;
- break;
-
- default:;
- }
- }
- else {
-
- switch (T_BYTES(dwOutput)) {
-
- case 1:
- switch (T_CHANNELS(dwOutput))
- {
- case 1:
- if (T_DITHER(dwOutput))
- ToOutput = PackNBytesDither;
- else
- ToOutput = Pack1Byte;
- if (T_EXTRA(dwOutput) == 1) {
- if (T_SWAPFIRST(dwOutput))
- ToOutput = Pack1ByteAndSkip1SwapFirst;
- else
- ToOutput = Pack1ByteAndSkip1;
- }
- break;
-
- case 3:
- switch (T_EXTRA(dwOutput)) {
-
- case 0: if (T_DOSWAP(dwOutput))
- ToOutput = Pack3BytesSwap;
- else
- if (T_COLORSPACE(dwOutput) == PT_Lab)
- ToOutput = Pack3BytesLab;
- else {
- if (T_DITHER(dwOutput))
- ToOutput = PackNBytesDither;
- else
- ToOutput = Pack3Bytes;
- }
- break;
-
- case 1: // TODO: ALab8 should be handled here
-
- if (T_DOSWAP(dwOutput)) {
-
- if (T_SWAPFIRST(dwOutput))
- ToOutput = Pack3BytesAndSkip1SwapSwapFirst;
- else
- ToOutput = Pack3BytesAndSkip1Swap;
- }
- else {
- if (T_SWAPFIRST(dwOutput))
- ToOutput = Pack3BytesAndSkip1SwapFirst;
- else
- ToOutput = Pack3BytesAndSkip1;
- }
- break;
-
- default:;
- }
- break;
-
- case 4: if (T_EXTRA(dwOutput) == 0) {
-
-
- if (T_DOSWAP(dwOutput)) {
-
-
- if (T_SWAPFIRST(dwOutput)) {
- ToOutput = Pack4BytesSwapSwapFirst;
- }
- else {
-
- if (T_DITHER(dwOutput)) {
- ToOutput = PackNBytesSwapDither;
- }
- else {
- ToOutput = Pack4BytesSwap;
- }
- }
- }
- else {
- if (T_SWAPFIRST(dwOutput))
- ToOutput = Pack4BytesSwapFirst;
- else {
-
- if (T_FLAVOR(dwOutput))
- ToOutput = Pack4BytesReverse;
- else {
- if (T_DITHER(dwOutput))
- ToOutput = PackNBytesDither;
- else
- ToOutput = Pack4Bytes;
- }
- }
- }
- }
- else {
- if (!T_DOSWAP(dwOutput) && !T_SWAPFIRST(dwOutput))
- ToOutput = PackNBytes;
- }
- break;
-
- // Hexachrome separations.
- case 6: if (T_EXTRA(dwOutput) == 0) {
-
- if( T_DOSWAP(dwOutput))
- ToOutput = Pack6BytesSwap;
- else
- ToOutput = Pack6Bytes;
- }
- else {
- if (!T_DOSWAP(dwOutput) && !T_SWAPFIRST(dwOutput))
- ToOutput = PackNBytes;
-
- }
- break;
-
- case 2:
- case 5:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
-
- if ((T_EXTRA(dwOutput) == 0) && (T_SWAPFIRST(dwOutput) == 0))
- {
- if (T_DOSWAP(dwOutput))
- ToOutput = PackNBytesSwap;
- else {
-
- if (T_DITHER(dwOutput))
- ToOutput = PackNBytesDither;
- else
- ToOutput = PackNBytes;
- }
- }
- break;
-
- default:;
- }
- break;
-
-
- case 2:
-
- switch (T_CHANNELS(dwOutput)) {
-
- case 1:
- if (T_ENDIAN16(dwOutput))
-
- ToOutput = Pack1WordBigEndian;
- else
- ToOutput = Pack1Word;
-
- if (T_EXTRA(dwOutput) == 1) {
-
- if (T_ENDIAN16(dwOutput))
-
- ToOutput = Pack1WordAndSkip1BigEndian;
- else {
- if (T_SWAPFIRST(dwOutput))
- ToOutput = Pack1WordAndSkip1SwapFirst;
- else
- ToOutput = Pack1WordAndSkip1;
- }
- }
- break;
-
- case 3:
-
- switch (T_EXTRA(dwOutput)) {
-
- case 0:
- if (T_DOSWAP(dwOutput)) {
-
- if (T_ENDIAN16(dwOutput))
-
- ToOutput = Pack3WordsSwapBigEndian;
- else
- ToOutput = Pack3WordsSwap;
- }
- else {
- if (T_ENDIAN16(dwOutput))
-
- ToOutput = Pack3WordsBigEndian;
- else
- ToOutput = Pack3Words;
- }
- break;
-
- case 1: if (T_DOSWAP(dwOutput)) {
-
- if (T_ENDIAN16(dwOutput))
-
- ToOutput = Pack3WordsAndSkip1SwapBigEndian;
- else {
- if (T_SWAPFIRST(dwOutput))
- ToOutput = Pack3WordsAndSkip1SwapSwapFirst;
- else
- ToOutput = Pack3WordsAndSkip1Swap;
- }
- }
- else {
- if (T_ENDIAN16(dwOutput))
- ToOutput = Pack3WordsAndSkip1BigEndian;
- else
- ToOutput = Pack3WordsAndSkip1;
- }
- default:;
- }
- break;
-
- case 4: if (T_EXTRA(dwOutput) == 0) {
-
- if (T_DOSWAP(dwOutput)) {
-
- if (T_ENDIAN16(dwOutput))
- ToOutput = Pack4WordsSwapBigEndian;
- else
- ToOutput = Pack4WordsSwap;
- }
- else {
-
- if (T_ENDIAN16(dwOutput)) {
-
- if (T_FLAVOR(dwOutput))
- ToOutput = Pack4WordsBigEndianReverse;
- else
- ToOutput = Pack4WordsBigEndian;
- }
- else {
- if (T_FLAVOR(dwOutput))
- ToOutput = Pack4WordsReverse;
- else
- ToOutput = Pack4Words;
- }
- }
- }
- else {
- if (!T_DOSWAP(dwOutput) && !T_SWAPFIRST(dwOutput))
- ToOutput = PackNWords;
- }
- break;
-
- case 6: if (T_EXTRA(dwOutput) == 0) {
-
- if (T_DOSWAP(dwOutput)) {
-
- if (T_ENDIAN16(dwOutput))
- ToOutput = Pack6WordsSwapBigEndian;
- else
- ToOutput = Pack6WordsSwap;
- }
- else {
-
- if (T_ENDIAN16(dwOutput))
- ToOutput = Pack6WordsBigEndian;
- else
- ToOutput = Pack6Words;
- }
- }
- else {
- if (!T_DOSWAP(dwOutput) && !T_SWAPFIRST(dwOutput))
- ToOutput = PackNWords;
- }
- break;
-
-
- case 2:
- case 5:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15: if ((T_EXTRA(dwOutput) == 0) && (T_SWAPFIRST(dwOutput) == 0)) {
-
- if (T_DOSWAP(dwOutput)) {
-
- if (T_ENDIAN16(dwOutput))
- ToOutput = PackNWordsSwapBigEndian;
- else
- ToOutput = PackNWordsSwap;
- }
- else {
-
- if (T_ENDIAN16(dwOutput))
- ToOutput = PackNWordsBigEndian;
- else
- ToOutput = PackNWords;
- }
- }
- break;
-
- default:;
- }
- break;
-
- default:;
- }
- }
-
- if (!ToOutput)
- cmsSignalError(LCMS_ERRC_ABORTED, "Unknown output format");
-
- return ToOutput;
+ cmsUInt32Number i;
+ cmsFormatter fr;
+
+
+ if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) {
+
+ for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
+ cmsFormatters16* f = InputFormatters16 + i;
+
+ if ((dwInput & ~f ->Mask) == f ->Type) {
+ fr.Fmt16 = f ->Frm;
+ return fr;
+ }
+ }
+ }
+ else {
+ for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
+ cmsFormattersFloat* f = InputFormattersFloat + i;
+
+ if ((dwInput & ~f ->Mask) == f ->Type) {
+ fr.FmtFloat = f ->Frm;
+ return fr;
+ }
+ }
+ }
+
+ fr.Fmt16 = NULL;
+ return fr;
}
-// User formatters for (weird) cases not already included
-
-void LCMSEXPORT cmsSetUserFormatters(cmsHTRANSFORM hTransform, DWORD dwInput, cmsFORMATTER Input,
- DWORD dwOutput, cmsFORMATTER Output)
-{
- _LPcmsTRANSFORM xform = (_LPcmsTRANSFORM) (LPSTR) hTransform;
-
- if (Input != NULL) {
- xform ->FromInput = (_cmsFIXFN) Input;
- xform ->InputFormat = dwInput;
- }
-
- if (Output != NULL) {
- xform ->ToOutput = (_cmsFIXFN) Output;
- xform ->OutputFormat = dwOutput;
- }
-
-}
-
-void LCMSEXPORT cmsGetUserFormatters(cmsHTRANSFORM hTransform,
- LPDWORD InputFormat, cmsFORMATTER* Input,
- LPDWORD OutputFormat, cmsFORMATTER* Output)
+static cmsFormatters16 OutputFormatters16[] = {
+ // Type Mask Function
+ // ---------------------------- ------------------------------------ ----------------------------
+
+ { TYPE_Lab_DBL, ANYPLANAR, PackLabDoubleFrom16},
+ { TYPE_XYZ_DBL, ANYPLANAR, PackXYZDoubleFrom16},
+ { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16},
+ { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16},
+
+ { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Pack1Byte},
+ { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack1ByteSkip1},
+ { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1ByteSkip1SwapFirst},
+
+ { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack1ByteReversed},
+
+ { TYPE_LabV2_8, 0, PackLabV2_8 },
+ { TYPE_ALabV2_8, 0, PackALabV2_8 },
+ { TYPE_LabV2_16, 0, PackLabV2_16 },
+
+ { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesOptimized},
+ { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1Optimized},
+ { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
+ ANYSPACE, Pack3BytesAndSkip1SwapFirstOptimized},
+ { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
+ ANYSPACE, Pack3BytesAndSkip1SwapSwapFirstOptimized},
+ { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),
+ ANYSPACE, Pack3BytesAndSkip1SwapOptimized},
+ { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesSwapOptimized},
+
+
+
+ { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Pack3Bytes},
+ { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1},
+ { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapFirst},
+ { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
+ ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst},
+ { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap},
+ { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap},
+ { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes},
+ { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap},
+ { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes},
+ { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse},
+ { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst},
+ { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap},
+ { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst},
+
+ { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
+ { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
+
+ { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word},
+ { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1},
+ { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1WordSkip1SwapFirst},
+ { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack1WordReversed},
+ { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack1WordBigEndian},
+ { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Pack3Words},
+ { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack3WordsSwap},
+ { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack3WordsBigEndian},
+ { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack3WordsAndSkip1},
+ { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3WordsAndSkip1Swap},
+ { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3WordsAndSkip1SwapFirst},
+
+ { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
+ ANYSPACE, Pack3WordsAndSkip1SwapSwapFirst},
+
+ { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Pack4Words},
+ { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack4WordsReverse},
+ { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack4WordsSwap},
+ { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack4WordsBigEndian},
+
+ { CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words},
+ { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap},
+
+ { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords},
+ { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords}
+
+};
+
+
+static cmsFormattersFloat OutputFormattersFloat[] = {
+ // Type Mask Function
+ // ---------------------------- --------------------------------------------------- ----------------------------
+ { TYPE_Lab_FLT, ANYPLANAR, PackLabFloatFromFloat},
+ { TYPE_XYZ_FLT, ANYPLANAR, PackXYZFloatFromFloat},
+ { TYPE_Lab_DBL, ANYPLANAR, PackLabDoubleFromFloat},
+ { TYPE_XYZ_DBL, ANYPLANAR, PackXYZDoubleFromFloat},
+ { FLOAT_SH(1)|BYTES_SH(4),
+ ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyFloatsFromFloat },
+ { FLOAT_SH(1)|BYTES_SH(4)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarFloatsFromFloat},
+ { FLOAT_SH(1)|BYTES_SH(0),
+ ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyDoublesFromFloat },
+ { FLOAT_SH(1)|BYTES_SH(0)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarDoublesFromFloat},
+
+
+};
+
+
+// Bit fields set to one in the mask are not compared
+cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
{
- _LPcmsTRANSFORM xform = (_LPcmsTRANSFORM) (LPSTR) hTransform;
-
- if (Input) *Input = (cmsFORMATTER) xform ->FromInput;
- if (InputFormat) *InputFormat = xform -> InputFormat;
- if (Output) *Output = (cmsFORMATTER) xform ->ToOutput;
- if (OutputFormat) *OutputFormat = xform -> OutputFormat;
+ cmsUInt32Number i;
+ cmsFormatter fr;
+
+
+ if (dwFlags & CMS_PACK_FLAGS_FLOAT) {
+
+ for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
+ cmsFormattersFloat* f = OutputFormattersFloat + i;
+
+ if ((dwInput & ~f ->Mask) == f ->Type) {
+ fr.FmtFloat = f ->Frm;
+ return fr;
+ }
+ }
+
+ }
+ else {
+
+ for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
+ cmsFormatters16* f = OutputFormatters16 + i;
+
+ if ((dwInput & ~f ->Mask) == f ->Type) {
+ fr.Fmt16 = f ->Frm;
+ return fr;
+ }
+ }
+ }
+
+ fr.Fmt16 = NULL;
+ return fr;
}
-// Change format of yet existing transform. No colorspace checking is performed
-
-void LCMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
- DWORD dwInputFormat,
- DWORD dwOutputFormat)
+typedef struct _cms_formatters_factory_list {
+
+ cmsFormatterFactory Factory;
+ struct _cms_formatters_factory_list *Next;
+
+} cmsFormattersFactoryList;
+
+static cmsFormattersFactoryList* FactoryList = NULL;
+
+
+// Formatters management
+cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data)
+{
+ cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
+ cmsFormattersFactoryList* fl ;
+
+ // Reset
+ if (Data == NULL) {
+
+ FactoryList = NULL;
+ return TRUE;
+ }
+
+ fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList));
+ if (fl == NULL) return FALSE;
+
+ fl ->Factory = Plugin ->FormattersFactory;
+
+ fl ->Next = FactoryList;
+ FactoryList = fl;
+
+ return TRUE;
+}
+
+cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+ cmsFormatterDirection Dir,
+ cmsUInt32Number dwFlags) // Float or 16 bits
{
-
- cmsSetUserFormatters(hTransform,
- dwInputFormat,
- (cmsFORMATTER) _cmsIdentifyInputFormat((_LPcmsTRANSFORM) hTransform, dwInputFormat),
- dwOutputFormat,
- (cmsFORMATTER) _cmsIdentifyOutputFormat((_LPcmsTRANSFORM) hTransform, dwOutputFormat));
+ cmsFormattersFactoryList* f;
+
+ for (f = FactoryList; f != NULL; f = f ->Next) {
+
+ cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
+ if (fn.Fmt16 != NULL) return fn;
+ }
+
+ // Revert to default
+ if (Dir == cmsFormatterInput)
+ return _cmsGetStockInputFormatter(Type, dwFlags);
+ else
+ return _cmsGetStockOutputFormatter(Type, dwFlags);
+}
+
+
+// Return whatever given formatter refers to float values
+cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type)
+{
+ return T_FLOAT(Type) ? TRUE : FALSE;
}
+
+// Return whatever given formatter refers to 8 bits
+cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type)
+{
+ int Bytes = T_BYTES(Type);
+
+ return (Bytes == 1);
+}
+
+// Build a suitable formatter for the colorspace of this profile
+cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
+{
+
+ cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile);
+ cmsUInt32Number ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace);
+ cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
+ cmsUInt32Number Float = lIsFloat ? 1 : 0;
+
+ // Create a fake formatter for result
+ return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
+}
+
+// Build a suitable formatter for the colorspace of this profile
+cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
+{
+
+ cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
+ int ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace);
+ cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
+ cmsUInt32Number Float = lIsFloat ? 1 : 0;
+
+ // Create a fake formatter for result
+ return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
+}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,11 +49,13 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
// inter PCS conversions XYZ <-> CIE L* a* b*
-
-#include "lcms.h"
-
/*
@@ -75,7 +78,7 @@
- Following ICC. PCS in Lab is coded as:
+ PCS in Lab2 is encoded as:
8 bit Lab PCS:
@@ -90,9 +93,6 @@
b*
- We are always playing with 16 bits-data, so I will ignore the
- 8-bits encoding scheme.
-
Interchange Space Component Actual Range Encoded Range
CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff
@@ -116,318 +116,134 @@
*/
+// Conversions
+void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source)
+{
+ cmsFloat64Number ISum;
-
+ ISum = 1./(Source -> X + Source -> Y + Source -> Z);
-// On most modern computers, D > 4 M (i.e. a division takes more than 4
-// multiplications worth of time), so it is probably preferable to compute
-// a 24 bit result directly.
+ Dest -> x = (Source -> X) * ISum;
+ Dest -> y = (Source -> Y) * ISum;
+ Dest -> Y = Source -> Y;
+}
-// #define ITERATE 1
+void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source)
+{
+ Dest -> X = (Source -> x / Source -> y) * Source -> Y;
+ Dest -> Y = Source -> Y;
+ Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y;
+}
static
-float CubeRoot(float x)
+cmsFloat64Number f(cmsFloat64Number t)
{
- float fr, r;
- int ex, shx;
-
- /* Argument reduction */
- fr = (float) frexp(x, &ex); /* separate into mantissa and exponent */
- shx = ex % 3;
-
- if (shx > 0)
- shx -= 3; /* compute shx such that (ex - shx) is divisible by 3 */
-
- ex = (ex - shx) / 3; /* exponent of cube root */
- fr = (float) ldexp(fr, shx);
-
- /* 0.125 <= fr < 1.0 */
-
-#ifdef ITERATE
- /* Compute seed with a quadratic approximation */
-
- fr = (-0.46946116F * fr + 1.072302F) * fr + 0.3812513F;/* 0.5<=fr<1 */
- r = ldexp(fr, ex); /* 6 bits of precision */
+ const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0);
- /* Newton-Raphson iterations */
-
- r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 12 bits */
- r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 24 bits */
-#else /* ITERATE */
-
- /* Use quartic rational polynomial with error < 2^(-24) */
-
- fr = (float) (((((45.2548339756803022511987494 * fr +
- 192.2798368355061050458134625) * fr +
- 119.1654824285581628956914143) * fr +
- 13.43250139086239872172837314) * fr +
- 0.1636161226585754240958355063)
- /
- ((((14.80884093219134573786480845 * fr +
- 151.9714051044435648658557668) * fr +
- 168.5254414101568283957668343) * fr +
- 33.9905941350215598754191872) * fr +
- 1.0));
- r = (float) ldexp(fr, ex); /* 24 bits of precision */
-#endif
- return r;
+ if (t <= Limit)
+ return (841.0/108.0) * t + (16.0/116.0);
+ else
+ return pow(t, 1.0/3.0);
}
static
-double f(double t)
+cmsFloat64Number f_1(cmsFloat64Number t)
+{
+ const cmsFloat64Number Limit = (24.0/116.0);
+
+ if (t <= Limit) {
+ return (108.0/841.0) * (t - (16.0/116.0));
+ }
+
+ return t * t * t;
+}
+
+
+// Standard XYZ to Lab. it can handle negative XZY numbers in some cases
+void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz)
{
+ cmsFloat64Number fx, fy, fz;
- const double Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0);
+ if (WhitePoint == NULL)
+ WhitePoint = cmsD50_XYZ();
+
+ fx = f(xyz->X / WhitePoint->X);
+ fy = f(xyz->Y / WhitePoint->Y);
+ fz = f(xyz->Z / WhitePoint->Z);
+
+ Lab->L = 116.0*fy - 16.0;
+ Lab->a = 500.0*(fx - fy);
+ Lab->b = 200.0*(fy - fz);
+}
+
+
+// Standard XYZ to Lab. It can return negative XYZ in some cases
+void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab)
+{
+ cmsFloat64Number x, y, z;
- if (t <= Limit)
- return (841.0/108.0) * t + (16.0/116.0);
- else
- return CubeRoot((float) t);
+ if (WhitePoint == NULL)
+ WhitePoint = cmsD50_XYZ();
+
+ y = (Lab-> L + 16.0) / 116.0;
+ x = y + 0.002 * Lab -> a;
+ z = y - 0.005 * Lab -> b;
+
+ xyz -> X = f_1(x) * WhitePoint -> X;
+ xyz -> Y = f_1(y) * WhitePoint -> Y;
+ xyz -> Z = f_1(z) * WhitePoint -> Z;
+
+}
+
+static
+cmsFloat64Number L2float2(cmsUInt16Number v)
+{
+ return (cmsFloat64Number) v / 652.800;
+}
+
+// the a/b part
+static
+cmsFloat64Number ab2float2(cmsUInt16Number v)
+{
+ return ((cmsFloat64Number) v / 256.0) - 128.0;
+}
+
+static
+cmsUInt16Number L2Fix2(cmsFloat64Number L)
+{
+ return _cmsQuickSaturateWord(L * 652.8);
+}
+
+static
+cmsUInt16Number ab2Fix2(cmsFloat64Number ab)
+{
+ return _cmsQuickSaturateWord((ab + 128.0) * 256.0);
}
static
-double f_1(double t)
-{
- const double Limit = (24.0/116.0);
-
- if (t <= Limit)
- {
- double tmp;
-
- tmp = (108.0/841.0) * (t - (16.0/116.0));
- if (tmp <= 0.0) return 0.0;
- else return tmp;
- }
-
- return t * t * t;
-}
-
-
-
-void LCMSEXPORT cmsXYZ2Lab(LPcmsCIEXYZ WhitePoint, LPcmsCIELab Lab, const cmsCIEXYZ* xyz)
+cmsFloat64Number L2float4(cmsUInt16Number v)
{
- double fx, fy, fz;
-
- if (xyz -> X == 0 && xyz -> Y == 0 && xyz -> Z == 0)
- {
- Lab -> L = 0;
- Lab -> a = 0;
- Lab -> b = 0;
- return;
- }
-
- if (WhitePoint == NULL)
- WhitePoint = cmsD50_XYZ();
-
- fx = f(xyz->X / WhitePoint->X);
- fy = f(xyz->Y / WhitePoint->Y);
- fz = f(xyz->Z / WhitePoint->Z);
-
- Lab->L = 116.0* fy - 16.;
-
- Lab->a = 500.0*(fx - fy);
- Lab->b = 200.0*(fy - fz);
+ return (cmsFloat64Number) v / 655.35;
}
-
-
-void cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3])
+// the a/b part
+static
+cmsFloat64Number ab2float4(cmsUInt16Number v)
{
- Fixed32 X, Y, Z;
- double x, y, z, L, a, b;
- double fx, fy, fz;
- Fixed32 wL, wa, wb;
-
- X = (Fixed32) XYZ[0] << 1;
- Y = (Fixed32) XYZ[1] << 1;
- Z = (Fixed32) XYZ[2] << 1;
-
-
- if (X==0 && Y==0 && Z==0) {
-
- Lab[0] = 0;
- Lab[1] = Lab[2] = 0x8000;
- return;
- }
-
- // PCS is in D50
-
-
- x = FIXED_TO_DOUBLE(X) / D50X;
- y = FIXED_TO_DOUBLE(Y) / D50Y;
- z = FIXED_TO_DOUBLE(Z) / D50Z;
-
-
- fx = f(x);
- fy = f(y);
- fz = f(z);
-
- L = 116.* fy - 16.;
-
- a = 500.*(fx - fy);
- b = 200.*(fy - fz);
-
- a += 128.;
- b += 128.;
-
- wL = (int) (L * 652.800 + .5);
- wa = (int) (a * 256.0 + .5);
- wb = (int) (b * 256.0 + .5);
-
-
- Lab[0] = Clamp_L(wL);
- Lab[1] = Clamp_ab(wa);
- Lab[2] = Clamp_ab(wb);
-
-
+ return ((cmsFloat64Number) v / 257.0) - 128.0;
}
-
-
-
-
-void LCMSEXPORT cmsLab2XYZ(LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ xyz, const cmsCIELab* Lab)
+void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3])
{
- double x, y, z;
-
- if (Lab -> L <= 0) {
- xyz -> X = 0;
- xyz -> Y = 0;
- xyz -> Z = 0;
- return;
- }
-
-
- if (WhitePoint == NULL)
- WhitePoint = cmsD50_XYZ();
-
- y = (Lab-> L + 16.0) / 116.0;
- x = y + 0.002 * Lab -> a;
- z = y - 0.005 * Lab -> b;
-
- xyz -> X = f_1(x) * WhitePoint -> X;
- xyz -> Y = f_1(y) * WhitePoint -> Y;
- xyz -> Z = f_1(z) * WhitePoint -> Z;
-
+ Lab->L = L2float2(wLab[0]);
+ Lab->a = ab2float2(wLab[1]);
+ Lab->b = ab2float2(wLab[2]);
}
-
-void cmsLab2XYZEncoded(WORD Lab[3], WORD XYZ[3])
-{
- double L, a, b;
- double X, Y, Z, x, y, z;
-
-
- L = ((double) Lab[0] * 100.0) / 65280.0;
- if (L==0.0) {
-
- XYZ[0] = 0; XYZ[1] = 0; XYZ[2] = 0;
- return;
- }
-
- a = ((double) Lab[1] / 256.0) - 128.0;
- b = ((double) Lab[2] / 256.0) - 128.0;
-
- y = (L + 16.) / 116.0;
- x = y + 0.002 * a;
- z = y - 0.005 * b;
-
- X = f_1(x) * D50X;
- Y = f_1(y) * D50Y;
- Z = f_1(z) * D50Z;
-
- // Convert to 1.15 fixed format PCS
-
-
- XYZ[0] = _cmsClampWord((int) floor(X * 32768.0 + 0.5));
- XYZ[1] = _cmsClampWord((int) floor(Y * 32768.0 + 0.5));
- XYZ[2] = _cmsClampWord((int) floor(Z * 32768.0 + 0.5));
-
-
-}
-
-static
-double L2float3(WORD v)
-{
- Fixed32 fix32;
-
- fix32 = (Fixed32) v;
- return (double) fix32 / 652.800;
-}
-
-
-// the a/b part
-
-static
-double ab2float3(WORD v)
-{
- Fixed32 fix32;
-
- fix32 = (Fixed32) v;
- return ((double) fix32/256.0)-128.0;
-}
-
-static
-WORD L2Fix3(double L)
-{
- return (WORD) (L * 652.800 + 0.5);
-}
-
-static
-WORD ab2Fix3(double ab)
-{
- return (WORD) ((ab + 128.0) * 256.0 + 0.5);
-}
-
-
-// ICC 4.0 -- ICC has changed PCS Lab encoding.
-
-static
-WORD L2Fix4(double L)
-{
- return (WORD) (L * 655.35 + 0.5);
-}
-
-static
-WORD ab2Fix4(double ab)
-{
- return (WORD) ((ab + 128.0) * 257.0 + 0.5);
-}
-
-static
-double L2float4(WORD v)
-{
- Fixed32 fix32;
-
- fix32 = (Fixed32) v;
- return (double) fix32 / 655.35;
-}
-
-
-// the a/b part
-
-static
-double ab2float4(WORD v)
-{
- Fixed32 fix32;
-
- fix32 = (Fixed32) v;
- return ((double) fix32/257.0)-128.0;
-}
-
-
-void LCMSEXPORT cmsLabEncoded2Float(LPcmsCIELab Lab, const WORD wLab[3])
-{
- Lab->L = L2float3(wLab[0]);
- Lab->a = ab2float3(wLab[1]);
- Lab->b = ab2float3(wLab[2]);
-}
-
-
-void LCMSEXPORT cmsLabEncoded2Float4(LPcmsCIELab Lab, const WORD wLab[3])
+void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3])
{
Lab->L = L2float4(wLab[0]);
Lab->a = ab2float4(wLab[1]);
@@ -435,122 +251,147 @@
}
static
-double Clamp_L_double(double L)
+cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L)
{
+ const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00;
+
if (L < 0) L = 0;
- if (L > 100) L = 100;
+ if (L > L_max) L = L_max;
return L;
}
static
-double Clamp_ab_double(double ab)
+cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab)
{
- if (ab < -128) ab = -128.0;
- if (ab > +127.9961) ab = +127.9961;
+ if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2;
+ if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2;
return ab;
}
-void LCMSEXPORT cmsFloat2LabEncoded(WORD wLab[3], const cmsCIELab* fLab)
+void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab)
{
cmsCIELab Lab;
+ Lab.L = Clamp_L_doubleV2(fLab ->L);
+ Lab.a = Clamp_ab_doubleV2(fLab ->a);
+ Lab.b = Clamp_ab_doubleV2(fLab ->b);
- Lab.L = Clamp_L_double(fLab ->L);
- Lab.a = Clamp_ab_double(fLab ->a);
- Lab.b = Clamp_ab_double(fLab ->b);
-
- wLab[0] = L2Fix3(Lab.L);
- wLab[1] = ab2Fix3(Lab.a);
- wLab[2] = ab2Fix3(Lab.b);
+ wLab[0] = L2Fix2(Lab.L);
+ wLab[1] = ab2Fix2(Lab.a);
+ wLab[2] = ab2Fix2(Lab.b);
}
-void LCMSEXPORT cmsFloat2LabEncoded4(WORD wLab[3], const cmsCIELab* fLab)
+static
+cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L)
+{
+ if (L < 0) L = 0;
+ if (L > 100.0) L = 100.0;
+
+ return L;
+}
+
+static
+cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab)
+{
+ if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4;
+ if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4;
+
+ return ab;
+}
+
+static
+cmsUInt16Number L2Fix4(cmsFloat64Number L)
+{
+ return _cmsQuickSaturateWord(L * 655.35);
+}
+
+static
+cmsUInt16Number ab2Fix4(cmsFloat64Number ab)
+{
+ return _cmsQuickSaturateWord((ab + 128.0) * 257.0);
+}
+
+void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab)
{
cmsCIELab Lab;
-
- Lab.L = fLab ->L;
- Lab.a = fLab ->a;
- Lab.b = fLab ->b;
-
-
- if (Lab.L < 0) Lab.L = 0;
- if (Lab.L > 100.) Lab.L = 100.;
-
- if (Lab.a < -128.) Lab.a = -128.;
- if (Lab.a > 127.) Lab.a = 127.;
- if (Lab.b < -128.) Lab.b = -128.;
- if (Lab.b > 127.) Lab.b = 127.;
-
+ Lab.L = Clamp_L_doubleV4(fLab ->L);
+ Lab.a = Clamp_ab_doubleV4(fLab ->a);
+ Lab.b = Clamp_ab_doubleV4(fLab ->b);
wLab[0] = L2Fix4(Lab.L);
wLab[1] = ab2Fix4(Lab.a);
wLab[2] = ab2Fix4(Lab.b);
}
-
+// Auxiliar: convert to Radians
+static
+cmsFloat64Number RADIANS(cmsFloat64Number deg)
+{
+ return (deg * M_PI) / 180.;
+}
-void LCMSEXPORT cmsLab2LCh(LPcmsCIELCh LCh, const cmsCIELab* Lab)
+// Auxiliar: atan2 but operating in degrees and returning 0 if a==b==0
+static
+cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b)
{
- double a, b;
-
- LCh -> L = Clamp_L_double(Lab -> L);
-
- a = Clamp_ab_double(Lab -> a);
- b = Clamp_ab_double(Lab -> b);
-
- LCh -> C = pow(a * a + b * b, 0.5);
+ cmsFloat64Number h;
- if (a == 0 && b == 0)
- LCh -> h = 0;
+ if (a == 0 && b == 0)
+ h = 0;
else
- LCh -> h = atan2(b, a);
+ h = atan2(a, b);
-
- LCh -> h *= (180. / M_PI);
+ h *= (180. / M_PI);
-
- while (LCh -> h >= 360.) // Not necessary, but included as a check.
- LCh -> h -= 360.;
+ while (h > 360.)
+ h -= 360.;
- while (LCh -> h < 0)
- LCh -> h += 360.;
+ while ( h < 0)
+ h += 360.;
+ return h;
}
-
-
-void LCMSEXPORT cmsLCh2Lab(LPcmsCIELab Lab, const cmsCIELCh* LCh)
+// Auxiliar: Square
+static
+cmsFloat64Number Sqr(cmsFloat64Number v)
{
-
- double h = (LCh -> h * M_PI) / 180.0;
-
- Lab -> L = Clamp_L_double(LCh -> L);
- Lab -> a = Clamp_ab_double(LCh -> C * cos(h));
- Lab -> b = Clamp_ab_double(LCh -> C * sin(h));
-
+ return v * v;
+}
+// From cylindrical coordinates. No check is performed, then negative values are allowed
+void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab)
+{
+ LCh -> L = Lab -> L;
+ LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5);
+ LCh -> h = atan2deg(Lab ->b, Lab ->a);
}
+// To cylindrical coordinates. No check is performed, then negative values are allowed
+void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh)
+{
+ cmsFloat64Number h = (LCh -> h * M_PI) / 180.0;
-
+ Lab -> L = LCh -> L;
+ Lab -> a = LCh -> C * cos(h);
+ Lab -> b = LCh -> C * sin(h);
+}
// In XYZ All 3 components are encoded using 1.15 fixed point
-
static
-WORD XYZ2Fix(double d)
+cmsUInt16Number XYZ2Fix(cmsFloat64Number d)
{
- return (WORD) floor(d * 32768.0 + 0.5);
+ return _cmsQuickSaturateWord(d * 32768.0);
}
-
-void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXYZ* fXYZ)
+void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ)
{
cmsCIEXYZ xyz;
@@ -558,73 +399,557 @@
xyz.Y = fXYZ -> Y;
xyz.Z = fXYZ -> Z;
-
// Clamp to encodeable values.
- // 1.99997 is reserved as out-of-gamut marker
-
-
if (xyz.Y <= 0) {
- xyz.X = 0;
- xyz.Y = 0;
- xyz.Z = 0;
+ xyz.X = 0;
+ xyz.Y = 0;
+ xyz.Z = 0;
}
-
- if (xyz.X > 1.99996)
- xyz.X = 1.99996;
+ if (xyz.X > MAX_ENCODEABLE_XYZ)
+ xyz.X = MAX_ENCODEABLE_XYZ;
if (xyz.X < 0)
- xyz.X = 0;
+ xyz.X = 0;
- if (xyz.Y > 1.99996)
- xyz.Y = 1.99996;
+ if (xyz.Y > MAX_ENCODEABLE_XYZ)
+ xyz.Y = MAX_ENCODEABLE_XYZ;
if (xyz.Y < 0)
- xyz.Y = 0;
-
+ xyz.Y = 0;
- if (xyz.Z > 1.99996)
- xyz.Z = 1.99996;
+ if (xyz.Z > MAX_ENCODEABLE_XYZ)
+ xyz.Z = MAX_ENCODEABLE_XYZ;
if (xyz.Z < 0)
- xyz.Z = 0;
-
+ xyz.Z = 0;
XYZ[0] = XYZ2Fix(xyz.X);
XYZ[1] = XYZ2Fix(xyz.Y);
XYZ[2] = XYZ2Fix(xyz.Z);
+}
+
+// To convert from Fixed 1.15 point to cmsFloat64Number
+static
+cmsFloat64Number XYZ2float(cmsUInt16Number v)
+{
+ cmsS15Fixed16Number fix32;
+
+ // From 1.15 to 15.16
+ fix32 = v << 1;
+
+ // From fixed 15.16 to cmsFloat64Number
+ return _cms15Fixed16toDouble(fix32);
+}
+
+
+void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3])
+{
+ fXYZ -> X = XYZ2float(XYZ[0]);
+ fXYZ -> Y = XYZ2float(XYZ[1]);
+ fXYZ -> Z = XYZ2float(XYZ[2]);
+}
+
+
+// Returns dE on two Lab values
+cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
+{
+ cmsFloat64Number dL, da, db;
+
+ dL = fabs(Lab1 -> L - Lab2 -> L);
+ da = fabs(Lab1 -> a - Lab2 -> a);
+ db = fabs(Lab1 -> b - Lab2 -> b);
+
+ return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5);
}
-// To convert from Fixed 1.15 point to double
+// Return the CIE94 Delta E
+cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
+{
+ cmsCIELCh LCh1, LCh2;
+ cmsFloat64Number dE, dL, dC, dh, dhsq;
+ cmsFloat64Number c12, sc, sh;
-static
-double XYZ2float(WORD v)
-{
- Fixed32 fix32;
+ dL = fabs(Lab1 ->L - Lab2 ->L);
+
+ cmsLab2LCh(&LCh1, Lab1);
+ cmsLab2LCh(&LCh2, Lab2);
- // From 1.15 to 15.16
-
- fix32 = v << 1;
+ dC = fabs(LCh1.C - LCh2.C);
+ dE = cmsDeltaE(Lab1, Lab2);
- // From fixed 15.16 to double
+ dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC);
+ if (dhsq < 0)
+ dh = 0;
+ else
+ dh = pow(dhsq, 0.5);
- return FIXED_TO_DOUBLE(fix32);
+ c12 = sqrt(LCh1.C * LCh2.C);
+
+ sc = 1.0 + (0.048 * c12);
+ sh = 1.0 + (0.014 * c12);
+
+ return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh));
}
-void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fXYZ, const WORD XYZ[3])
+// Auxiliary
+static
+cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab)
{
+ cmsFloat64Number yt;
- fXYZ -> X = XYZ2float(XYZ[0]);
- fXYZ -> Y = XYZ2float(XYZ[1]);
- fXYZ -> Z = XYZ2float(XYZ[2]);
+ if (Lab->L > 7.996969)
+ yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100;
+ else
+ yt = 100 * (Lab->L / 903.3);
+ return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6);
}
+// bfd - gets BFD(1:1) difference between Lab1, Lab2
+cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
+{
+ cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL,
+ deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd;
+ cmsCIELCh LCh1, LCh2;
+
+ lbfd1 = ComputeLBFD(Lab1);
+ lbfd2 = ComputeLBFD(Lab2);
+ deltaL = lbfd2 - lbfd1;
+
+ cmsLab2LCh(&LCh1, Lab1);
+ cmsLab2LCh(&LCh2, Lab2);
+
+ deltaC = LCh2.C - LCh1.C;
+ AveC = (LCh1.C+LCh2.C)/2;
+ Aveh = (LCh1.h+LCh2.h)/2;
+
+ dE = cmsDeltaE(Lab1, Lab2);
+
+ if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC)))
+ deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC));
+ else
+ deltah =0;
+
+
+ dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521;
+ g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000));
+ t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))-
+ 0.040*cos((2*Aveh-136)/(180/M_PI))+
+ 0.070*cos((3*Aveh-31)/(180/M_PI))+
+ 0.049*cos((4*Aveh+114)/(180/M_PI))-
+ 0.015*cos((5*Aveh-103)/(180/M_PI)));
+
+ dh = dc*(g*t+1-g);
+ rh = -0.260*cos((Aveh-308)/(180/M_PI))-
+ 0.379*cos((2*Aveh-160)/(180/M_PI))-
+ 0.636*cos((3*Aveh+254)/(180/M_PI))+
+ 0.226*cos((4*Aveh+140)/(180/M_PI))-
+ 0.194*cos((5*Aveh+280)/(180/M_PI));
+
+ rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000));
+ rt = rh*rc;
+
+ bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh)));
+
+ return bfd;
+}
+
+
+// cmc - CMC(l:c) difference between Lab1, Lab2
+cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c)
+{
+ cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc;
+ cmsCIELCh LCh1, LCh2;
+
+ if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
+
+ cmsLab2LCh(&LCh1, Lab1);
+ cmsLab2LCh(&LCh2, Lab2);
+
+
+ dL = Lab2->L-Lab1->L;
+ dC = LCh2.C-LCh1.C;
+
+ dE = cmsDeltaE(Lab1, Lab2);
+
+ if (Sqr(dE)>(Sqr(dL)+Sqr(dC)))
+ dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC));
+ else
+ dh =0;
+
+ if ((LCh1.h > 164) && (LCh1.h < 345))
+ t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI))));
+ else
+ t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI))));
+
+ sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638;
+ sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L);
+
+ if (Lab1->L<16)
+ sl = 0.511;
+
+ f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900));
+ sh = sc*(t*f+1-f);
+ cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh));
+
+ return cmc;
+}
+
+// dE2000 The weightings KL, KC and KH can be modified to reflect the relative
+// importance of lightness, chroma and hue in different industrial applications
+cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2,
+ cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh)
+{
+ cmsFloat64Number L1 = Lab1->L;
+ cmsFloat64Number a1 = Lab1->a;
+ cmsFloat64Number b1 = Lab1->b;
+ cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) );
+
+ cmsFloat64Number Ls = Lab2 ->L;
+ cmsFloat64Number as = Lab2 ->a;
+ cmsFloat64Number bs = Lab2 ->b;
+ cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) );
+
+ cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) ));
+
+ cmsFloat64Number a_p = (1 + G ) * a1;
+ cmsFloat64Number b_p = b1;
+ cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p));
+ cmsFloat64Number h_p = atan2deg(b_p, a_p);
+
+
+ cmsFloat64Number a_ps = (1 + G) * as;
+ cmsFloat64Number b_ps = bs;
+ cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps));
+ cmsFloat64Number h_ps = atan2deg(b_ps, a_ps);
+
+ cmsFloat64Number meanC_p =(C_p + C_ps) / 2;
+
+ cmsFloat64Number hps_plus_hp = h_ps + h_p;
+ cmsFloat64Number hps_minus_hp = h_ps - h_p;
+
+ cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 :
+ (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 :
+ (hps_plus_hp - 360)/2;
+
+ cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) :
+ (hps_minus_hp) > 180 ? (hps_minus_hp - 360) :
+ (hps_minus_hp);
+ cmsFloat64Number delta_L = (Ls - L1);
+ cmsFloat64Number delta_C = (C_ps - C_p );
+
+
+ cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2);
+
+ cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30))
+ + 0.24 * cos(RADIANS(2*meanh_p))
+ + 0.32 * cos(RADIANS(3*meanh_p + 6))
+ - 0.2 * cos(RADIANS(4*meanh_p - 63));
+
+ cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) );
+
+ cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2;
+ cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T;
+
+ cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25)));
+
+ cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0)));
+
+ cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc;
+
+ cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) +
+ Sqr(delta_C/(Sc * Kc)) +
+ Sqr(delta_H/(Sh * Kh)) +
+ Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh)));
+
+ return deltaE00;
+}
+
+// This function returns a number of gridpoints to be used as LUT table. It assumes same number
+// of gripdpoints in all dimensions. Flags may override the choice.
+int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
+{
+ int nChannels;
+
+ // Already specified?
+ if (dwFlags & 0x00FF0000) {
+ // Yes, grab'em
+ return (dwFlags >> 16) & 0xFF;
+ }
+
+ nChannels = cmsChannelsOf(Colorspace);
+
+ // HighResPrecalc is maximum resolution
+ if (dwFlags & cmsFLAGS_HIGHRESPRECALC) {
+
+ if (nChannels > 4)
+ return 7; // 7 for Hifi
+
+ if (nChannels == 4) // 23 for CMYK
+ return 23;
+
+ return 49; // 49 for RGB and others
+ }
+
+
+ // LowResPrecal is lower resolution
+ if (dwFlags & cmsFLAGS_LOWRESPRECALC) {
+
+ if (nChannels > 4)
+ return 6; // 6 for more than 4 channels
+
+ if (nChannels == 1)
+ return 33; // For monochrome
+
+ return 17; // 17 for remaining
+ }
+
+ // Default values
+ if (nChannels > 4)
+ return 7; // 7 for Hifi
+
+ if (nChannels == 4)
+ return 17; // 17 for CMYK
+
+ return 33; // 33 for RGB
+}
+
+
+cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
+ cmsUInt16Number **White,
+ cmsUInt16Number **Black,
+ cmsUInt32Number *nOutputs)
+{
+ // Only most common spaces
+
+ static cmsUInt16Number RGBblack[4] = { 0, 0, 0 };
+ static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff };
+ static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink
+ static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 };
+ static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding
+ static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 };
+ static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff };
+ static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 };
+ static cmsUInt16Number Grayblack[4] = { 0 };
+ static cmsUInt16Number GrayWhite[4] = { 0xffff };
+
+ switch (Space) {
+
+ case cmsSigGrayData: if (White) *White = GrayWhite;
+ if (Black) *Black = Grayblack;
+ if (nOutputs) *nOutputs = 1;
+ return TRUE;
+
+ case cmsSigRgbData: if (White) *White = RGBwhite;
+ if (Black) *Black = RGBblack;
+ if (nOutputs) *nOutputs = 3;
+ return TRUE;
+
+ case cmsSigLabData: if (White) *White = LABwhite;
+ if (Black) *Black = LABblack;
+ if (nOutputs) *nOutputs = 3;
+ return TRUE;
+
+ case cmsSigCmykData: if (White) *White = CMYKwhite;
+ if (Black) *Black = CMYKblack;
+ if (nOutputs) *nOutputs = 4;
+ return TRUE;
+
+ case cmsSigCmyData: if (White) *White = CMYwhite;
+ if (Black) *Black = CMYblack;
+ if (nOutputs) *nOutputs = 3;
+ return TRUE;
+
+ default:;
+ }
+
+ return FALSE;
+}
+
+
+
+// Several utilities -------------------------------------------------------
+
+// Translate from our colorspace to ICC representation
+
+cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation)
+{
+ switch (OurNotation) {
+
+ case 1:
+ case PT_GRAY: return cmsSigGrayData;
+
+ case 2:
+ case PT_RGB: return cmsSigRgbData;
+
+ case PT_CMY: return cmsSigCmyData;
+ case PT_CMYK: return cmsSigCmykData;
+ case PT_YCbCr:return cmsSigYCbCrData;
+ case PT_YUV: return cmsSigLuvData;
+ case PT_XYZ: return cmsSigXYZData;
+
+ case PT_LabV2:
+ case PT_Lab: return cmsSigLabData;
+
+ case PT_YUVK: return cmsSigLuvKData;
+ case PT_HSV: return cmsSigHsvData;
+ case PT_HLS: return cmsSigHlsData;
+ case PT_Yxy: return cmsSigYxyData;
+
+ case PT_MCH1: return cmsSigMCH1Data;
+ case PT_MCH2: return cmsSigMCH2Data;
+ case PT_MCH3: return cmsSigMCH3Data;
+ case PT_MCH4: return cmsSigMCH4Data;
+ case PT_MCH5: return cmsSigMCH5Data;
+ case PT_MCH6: return cmsSigMCH6Data;
+ case PT_MCH7: return cmsSigMCH7Data;
+ case PT_MCH8: return cmsSigMCH8Data;
+
+ case PT_MCH9: return cmsSigMCH9Data;
+ case PT_MCH10: return cmsSigMCHAData;
+ case PT_MCH11: return cmsSigMCHBData;
+ case PT_MCH12: return cmsSigMCHCData;
+ case PT_MCH13: return cmsSigMCHDData;
+ case PT_MCH14: return cmsSigMCHEData;
+ case PT_MCH15: return cmsSigMCHFData;
+
+ default: return (cmsColorSpaceSignature) (-1);
+ }
+}
+
+
+int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace)
+{
+ switch (ProfileSpace) {
+
+ case cmsSigGrayData: return PT_GRAY;
+ case cmsSigRgbData: return PT_RGB;
+ case cmsSigCmyData: return PT_CMY;
+ case cmsSigCmykData: return PT_CMYK;
+ case cmsSigYCbCrData:return PT_YCbCr;
+ case cmsSigLuvData: return PT_YUV;
+ case cmsSigXYZData: return PT_XYZ;
+ case cmsSigLabData: return PT_Lab;
+ case cmsSigLuvKData: return PT_YUVK;
+ case cmsSigHsvData: return PT_HSV;
+ case cmsSigHlsData: return PT_HLS;
+ case cmsSigYxyData: return PT_Yxy;
+
+ case cmsSig1colorData:
+ case cmsSigMCH1Data: return PT_MCH1;
+
+ case cmsSig2colorData:
+ case cmsSigMCH2Data: return PT_MCH2;
+
+ case cmsSig3colorData:
+ case cmsSigMCH3Data: return PT_MCH3;
+
+ case cmsSig4colorData:
+ case cmsSigMCH4Data: return PT_MCH4;
+
+ case cmsSig5colorData:
+ case cmsSigMCH5Data: return PT_MCH5;
+
+ case cmsSig6colorData:
+ case cmsSigMCH6Data: return PT_MCH6;
+
+ case cmsSigMCH7Data:
+ case cmsSig7colorData:return PT_MCH7;
+
+ case cmsSigMCH8Data:
+ case cmsSig8colorData:return PT_MCH8;
+
+ case cmsSigMCH9Data:
+ case cmsSig9colorData:return PT_MCH9;
+
+ case cmsSigMCHAData:
+ case cmsSig10colorData:return PT_MCH10;
+
+ case cmsSigMCHBData:
+ case cmsSig11colorData:return PT_MCH11;
+
+ case cmsSigMCHCData:
+ case cmsSig12colorData:return PT_MCH12;
+
+ case cmsSigMCHDData:
+ case cmsSig13colorData:return PT_MCH13;
+
+ case cmsSigMCHEData:
+ case cmsSig14colorData:return PT_MCH14;
+
+ case cmsSigMCHFData:
+ case cmsSig15colorData:return PT_MCH15;
+
+ default: return (cmsColorSpaceSignature) (-1);
+ }
+}
+
+
+cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
+{
+ switch (ColorSpace) {
+
+ case cmsSigGrayData: return 1;
+
+ case cmsSig2colorData: return 2;
+
+ case cmsSigXYZData:
+ case cmsSigLabData:
+ case cmsSigLuvData:
+ case cmsSigYCbCrData:
+ case cmsSigYxyData:
+ case cmsSigRgbData:
+ case cmsSigHsvData:
+ case cmsSigHlsData:
+ case cmsSigCmyData:
+ case cmsSig3colorData: return 3;
+
+ case cmsSigLuvKData:
+ case cmsSigCmykData:
+ case cmsSig4colorData: return 4;
+
+ case cmsSigMCH5Data:
+ case cmsSig5colorData: return 5;
+
+ case cmsSigMCH6Data:
+ case cmsSig6colorData: return 6;
+
+ case cmsSigMCH7Data:
+ case cmsSig7colorData: return 7;
+
+ case cmsSigMCH8Data:
+ case cmsSig8colorData: return 8;
+
+ case cmsSigMCH9Data:
+ case cmsSig9colorData: return 9;
+
+ case cmsSigMCHAData:
+ case cmsSig10colorData: return 10;
+
+ case cmsSigMCHBData:
+ case cmsSig11colorData: return 11;
+
+ case cmsSigMCHCData:
+ case cmsSig12colorData: return 12;
+
+ case cmsSigMCHDData:
+ case cmsSig13colorData: return 13;
+
+ case cmsSigMCHEData:
+ case cmsSig14colorData: return 14;
+
+ case cmsSigMCHFData:
+ case cmsSig15colorData: return 15;
+
+ default: return 3;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,641 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+
+// ----------------------------------------------------------------------------------
+// Encoding & Decoding support functions
+// ----------------------------------------------------------------------------------
+
+// Little-Endian to Big-Endian
+
+// Adjust a word value after being readed/ before being written from/to an ICC profile
+cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)
+{
+#ifndef CMS_USE_BIG_ENDIAN
+
+ cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
+ cmsUInt8Number tmp;
+
+ tmp = pByte[0];
+ pByte[0] = pByte[1];
+ pByte[1] = tmp;
+#endif
+
+ return Word;
+}
+
+
+// Transports to properly encoded values - note that icc profiles does use big endian notation.
+
+// 1 2 3 4
+// 4 3 2 1
+
+cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)
+{
+#ifndef CMS_USE_BIG_ENDIAN
+
+ cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
+ cmsUInt8Number temp1;
+ cmsUInt8Number temp2;
+
+ temp1 = *pByte++;
+ temp2 = *pByte++;
+ *(pByte-1) = *pByte;
+ *pByte++ = temp2;
+ *(pByte-3) = *pByte;
+ *pByte = temp1;
+#endif
+ return DWord;
+}
+
+// 1 2 3 4 5 6 7 8
+// 8 7 6 5 4 3 2 1
+
+void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord)
+{
+
+#ifndef CMS_USE_BIG_ENDIAN
+
+ cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord;
+ cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
+
+ _cmsAssert(Result != NULL);
+
+ pOut[7] = pIn[0];
+ pOut[6] = pIn[1];
+ pOut[5] = pIn[2];
+ pOut[4] = pIn[3];
+ pOut[3] = pIn[4];
+ pOut[2] = pIn[5];
+ pOut[1] = pIn[6];
+ pOut[0] = pIn[7];
+
+#else
+
+ _cmsAssert(Result != NULL);
+
+ *Result = QWord;
+#endif
+}
+
+// Auxiliar -- read 8, 16 and 32-bit numbers
+cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
+{
+ cmsUInt8Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) *n = tmp;
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
+{
+ cmsUInt16Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
+{
+ cmsUInt32Number i;
+
+ _cmsAssert(io != NULL);
+
+ for (i=0; i < n; i++) {
+
+ if (Array != NULL) {
+ if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
+ }
+ else {
+ if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
+ }
+
+ }
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) {
+
+ tmp = _cmsAdjustEndianess32(tmp);
+ *n = *(cmsFloat32Number*) &tmp;
+ }
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
+{
+ cmsUInt64Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) _cmsAdjustEndianess64(n, tmp);
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) {
+ *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
+ }
+
+ return TRUE;
+}
+
+
+// Jun-21-2000: Some profiles (those that comes with W2K) comes
+// with the media white (media black?) x 100. Add a sanity check
+
+static
+void NormalizeXYZ(cmsCIEXYZ* Dest)
+{
+ while (Dest -> X > 2. &&
+ Dest -> Y > 2. &&
+ Dest -> Z > 2.) {
+
+ Dest -> X /= 10.;
+ Dest -> Y /= 10.;
+ Dest -> Z /= 10.;
+ }
+}
+
+cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
+{
+ cmsEncodedXYZNumber xyz;
+
+ _cmsAssert(io != NULL);
+
+ if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
+
+ if (XYZ != NULL) {
+
+ XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
+ XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
+ XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
+
+ NormalizeXYZ(XYZ);
+ }
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
+{
+ _cmsAssert(io != NULL);
+
+ if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
+{
+ cmsUInt16Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = _cmsAdjustEndianess16(n);
+ if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
+{
+ cmsUInt32Number i;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(Array != NULL);
+
+ for (i=0; i < n; i++) {
+ if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
+ }
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = _cmsAdjustEndianess32(n);
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = *(cmsUInt32Number*) &n;
+ tmp = _cmsAdjustEndianess32(tmp);
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
+{
+ cmsUInt64Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ _cmsAdjustEndianess64(&tmp, n);
+ if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
+{
+ cmsEncodedXYZNumber xyz;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(XYZ != NULL);
+
+ xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
+ xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
+ xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
+
+ return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
+}
+
+// from Fixed point 8.8 to double
+cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
+{
+ cmsUInt8Number msb, lsb;
+
+ lsb = (cmsUInt8Number) (fixed8 & 0xff);
+ msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
+
+ return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
+}
+
+cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
+{
+ cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
+ return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
+}
+
+// from Fixed point 15.16 to double
+cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
+{
+ cmsFloat64Number floater, sign, mid;
+ int Whole, FracPart;
+
+ sign = (fix32 < 0 ? -1 : 1);
+ fix32 = abs(fix32);
+
+ Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
+ FracPart = (cmsUInt16Number)(fix32 & 0xffff);
+
+ mid = (cmsFloat64Number) FracPart / 65536.0;
+ floater = (cmsFloat64Number) Whole + mid;
+
+ return sign * floater;
+}
+
+// from double to Fixed point 15.16
+cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
+{
+ return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
+}
+
+// Date/Time functions
+
+void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
+{
+
+ _cmsAssert(Dest != NULL);
+ _cmsAssert(Source != NULL);
+
+ Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds);
+ Dest->tm_min = _cmsAdjustEndianess16(Source->minutes);
+ Dest->tm_hour = _cmsAdjustEndianess16(Source->hours);
+ Dest->tm_mday = _cmsAdjustEndianess16(Source->day);
+ Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1;
+ Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900;
+ Dest->tm_wday = -1;
+ Dest->tm_yday = -1;
+ Dest->tm_isdst = 0;
+}
+
+void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
+{
+ _cmsAssert(Dest != NULL);
+ _cmsAssert(Source != NULL);
+
+ Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
+ Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
+ Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
+ Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
+ Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
+ Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
+}
+
+// Read base and return type base
+cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
+{
+ _cmsTagBase Base;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
+ return (cmsTagTypeSignature) 0;
+
+ return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
+}
+
+// Setup base marker
+cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
+{
+ _cmsTagBase Base;
+
+ _cmsAssert(io != NULL);
+
+ Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
+ memset(&Base.reserved, 0, sizeof(Base.reserved));
+ return io -> Write(io, sizeof(_cmsTagBase), &Base);
+}
+
+cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
+{
+ cmsUInt8Number Buffer[4];
+ cmsUInt32Number NextAligned, At;
+ cmsUInt32Number BytesToNextAlignedPos;
+
+ _cmsAssert(io != NULL);
+
+ At = io -> Tell(io);
+ NextAligned = _cmsALIGNLONG(At);
+ BytesToNextAlignedPos = NextAligned - At;
+ if (BytesToNextAlignedPos == 0) return TRUE;
+ if (BytesToNextAlignedPos > 4) return FALSE;
+
+ return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
+}
+
+cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
+{
+ cmsUInt8Number Buffer[4];
+ cmsUInt32Number NextAligned, At;
+ cmsUInt32Number BytesToNextAlignedPos;
+
+ _cmsAssert(io != NULL);
+
+ At = io -> Tell(io);
+ NextAligned = _cmsALIGNLONG(At);
+ BytesToNextAlignedPos = NextAligned - At;
+ if (BytesToNextAlignedPos == 0) return TRUE;
+ if (BytesToNextAlignedPos > 4) return FALSE;
+
+ memset(Buffer, 0, BytesToNextAlignedPos);
+ return io -> Write(io, BytesToNextAlignedPos, Buffer);
+}
+
+
+// To deal with text streams. 2K at most
+cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
+{
+ va_list args;
+ int len;
+ cmsUInt8Number Buffer[2048];
+ cmsBool rc;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(frm != NULL);
+
+ va_start(args, frm);
+
+ len = vsnprintf((char*) Buffer, 2047, frm, args);
+ if (len < 0) return FALSE; // Truncated, which is a fatal error for us
+
+ rc = io ->Write(io, len, Buffer);
+
+ va_end(args);
+
+ return rc;
+}
+
+
+// Plugin memory management -------------------------------------------------------------------------------------------------
+
+static _cmsSubAllocator* PluginPool = NULL;
+
+// Specialized malloc for plug-ins, that is freed upon exit.
+void* _cmsPluginMalloc(cmsUInt32Number size)
+{
+ if (PluginPool == NULL)
+ PluginPool = _cmsCreateSubAlloc(0, 4*1024);
+
+ return _cmsSubAlloc(PluginPool, size);
+}
+
+
+// Main plug-in dispatcher
+cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
+{
+ cmsPluginBase* Plugin;
+
+ for (Plugin = (cmsPluginBase*) Plug_in;
+ Plugin != NULL;
+ Plugin = Plugin -> Next) {
+
+ if (Plugin -> Magic != cmsPluginMagicNumber) {
+ cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
+ return FALSE;
+ }
+
+ if (Plugin ->ExpectedVersion > LCMS_VERSION) {
+ cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
+ Plugin ->ExpectedVersion, LCMS_VERSION);
+ return FALSE;
+ }
+
+ switch (Plugin -> Type) {
+
+ case cmsPluginMemHandlerSig:
+ if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginInterpolationSig:
+ if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginTagTypeSig:
+ if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginTagSig:
+ if (!_cmsRegisterTagPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginFormattersSig:
+ if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginRenderingIntentSig:
+ if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginParametricCurveSig:
+ if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginMultiProcessElementSig:
+ if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginOptimizationSig:
+ if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
+ break;
+
+ default:
+ cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
+ return FALSE;
+ }
+ }
+
+ // Keep a reference to the plug-in
+ return TRUE;
+}
+
+
+// Revert all plug-ins to default
+void CMSEXPORT cmsUnregisterPlugins(void)
+{
+ _cmsRegisterMemHandlerPlugin(NULL);
+ _cmsRegisterInterpPlugin(NULL);
+ _cmsRegisterTagTypePlugin(NULL);
+ _cmsRegisterTagPlugin(NULL);
+ _cmsRegisterFormattersPlugin(NULL);
+ _cmsRegisterRenderingIntentPlugin(NULL);
+ _cmsRegisterParametricCurvesPlugin(NULL);
+ _cmsRegisterMultiProcessElementPlugin(NULL);
+ _cmsRegisterOptimizationPlugin(NULL);
+
+ if (PluginPool != NULL)
+ _cmsSubAllocDestroy(PluginPool);
+
+ PluginPool = NULL;
+}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2008 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,22 +49,14 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-// Postscript level 2 operators
-
+//
+//---------------------------------------------------------------------------------
+//
-
-#include "lcms.h"
-#include <time.h>
-#include <stdarg.h>
+#include "lcms2_internal.h"
// PostScript ColorRenderingDictionary and ColorSpaceArray
-LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen);
-LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRD(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen);
-LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, int Intent, DWORD dwFlags, LPVOID Buffer, DWORD dwBufferLen);
-// -------------------------------------------------------------------- Implementation
#define MAXPSCOLS 60 // Columns on tables
@@ -83,9 +76,9 @@
Color Space Arrays (CSA)
==================================================================================
- In order to obtain precission, code chooses between three ways to implement
+ In order to obtain precision, code chooses between three ways to implement
the device -> XYZ transform. These cases identifies monochrome profiles (often
- implemented as a set of curves), matrix-shaper and LUT-based.
+ implemented as a set of curves), matrix-shaper and Pipeline-based.
Monochrome
-----------
@@ -101,7 +94,7 @@
<<
/DecodeA { transfer function } bind
/MatrixA [D50]
- /RangeLMN [ 0.0 D50X 0.0 D50Y 0.0 D50Z ]
+ /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
/WhitePoint [D50]
/BlackPoint [BP]
/RenderingIntent (intent)
@@ -115,7 +108,7 @@
-------------------
This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig
- of profile implementation. Since here is no interpolation tables, I do
+ of profile implementation. Since here there are no interpolation tables, I do
the conversion directly to XYZ
@@ -124,7 +117,7 @@
<<
/DecodeABC [ {transfer1} {transfer2} {transfer3} ]
/MatrixABC [Matrix]
- /RangeLMN [ 0.0 D50X 0.0 D50Y 0.0 D50Z ]
+ /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
/DecodeLMN [ { / 2} dup dup ]
/WhitePoint [D50]
/BlackPoint [BP]
@@ -299,153 +292,66 @@
*/
-static icTagSignature Device2PCSTab[] = {icSigAToB0Tag, // Perceptual
- icSigAToB1Tag, // Relative colorimetric
- icSigAToB2Tag, // Saturation
- icSigAToB1Tag }; // Absolute colorimetric
- // (Relative/WhitePoint)
-
-// --------------------------------------------------------------- Memory Stream
-//
// This struct holds the memory block currently being write
-//
+typedef struct {
+ _cmsStageCLutData* Pipeline;
+ cmsIOHANDLER* m;
+
+ int FirstComponent;
+ int SecondComponent;
-typedef struct {
- LPBYTE Block;
- LPBYTE Ptr;
- DWORD dwMax;
- DWORD dwUsed;
- int MaxCols;
- int Col;
- int HasError;
+ const char* PreMaj;
+ const char* PostMaj;
+ const char* PreMin;
+ const char* PostMin;
- } MEMSTREAM, FAR* LPMEMSTREAM;
+ int FixWhite; // Force mapping of pure white
+
+ cmsColorSpaceSignature ColorSpace; // ColorSpace of profile
-typedef struct {
- LPLUT Lut;
- LPMEMSTREAM m;
-
- int FirstComponent;
- int SecondComponent;
-
- int bps;
- const char* PreMaj;
- const char* PostMaj;
- const char* PreMin;
- const char* PostMin;
-
- int lIsInput; // Handle L* encoding
- int FixWhite; // Force mapping of pure white
-
- icColorSpaceSignature ColorSpace; // ColorSpace of profile
-
-
- } SAMPLERCARGO, FAR* LPSAMPLERCARGO;
+} cmsPsSamplerCargo;
-
-// Creates a ready to use memory stream
-static
-LPMEMSTREAM CreateMemStream(LPBYTE Buffer, DWORD dwMax, int MaxCols)
-{
- LPMEMSTREAM m = (LPMEMSTREAM) _cmsMalloc(sizeof(MEMSTREAM));
- if (m == NULL) return NULL;
-
- ZeroMemory(m, sizeof(MEMSTREAM));
-
- m -> Block = m -> Ptr = Buffer;
- m -> dwMax = dwMax;
- m -> dwUsed = 0;
- m -> MaxCols = MaxCols;
- m -> Col = 0;
- m -> HasError = 0;
-
- return m;
-}
-
+static int _cmsPSActualColumn = 0;
// Convert to byte
static
-BYTE Word2Byte(WORD w)
+cmsUInt8Number Word2Byte(cmsUInt16Number w)
{
- return (BYTE) floor((double) w / 257.0 + 0.5);
+ return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
}
// Convert to byte (using ICC2 notation)
-
-static
-BYTE L2Byte(WORD w)
-{
- int ww = w + 0x0080;
-
- if (ww > 0xFFFF) return 0xFF;
-
- return (BYTE) ((WORD) (ww >> 8) & 0xFF);
-}
-
-// Write a raw, uncooked byte. Check for space
+/*
static
-void WriteRawByte(LPMEMSTREAM m, BYTE b)
+cmsUInt8Number L2Byte(cmsUInt16Number w)
{
- if (m -> dwUsed + 1 > m -> dwMax) {
- m -> HasError = 1;
- }
+ int ww = w + 0x0080;
- if (!m ->HasError && m ->Block) {
- *m ->Ptr++ = b;
- }
+ if (ww > 0xFFFF) return 0xFF;
- m -> dwUsed++;
+ return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF);
}
+*/
// Write a cooked byte
+
static
-void WriteByte(LPMEMSTREAM m, BYTE b)
+void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b)
{
- static const BYTE Hex[] = "0123456789ABCDEF";
- BYTE c;
-
- c = Hex[(b >> 4) & 0x0f];
- WriteRawByte(m, c);
-
- c = Hex[b & 0x0f];
- WriteRawByte(m, c);
-
- m -> Col += 2;
-
- if (m -> Col > m -> MaxCols) {
-
- WriteRawByte(m, '\n');
- m -> Col = 0;
- }
-
-}
+ _cmsIOPrintf(m, "%02x", b);
+ _cmsPSActualColumn += 2;
-// Does write a formatted string. Guaranteed to be 2048 bytes at most.
-static
-void Writef(LPMEMSTREAM m, const char *frm, ...)
-{
- va_list args;
- LPBYTE pt;
- BYTE Buffer[2048];
-
- va_start(args, frm);
+ if (_cmsPSActualColumn > MAXPSCOLS) {
- vsnprintf((char*) Buffer, 2048, frm, args);
-
- for (pt = Buffer; *pt; pt++) {
-
- WriteRawByte(m, *pt);
- }
-
- va_end(args);
+ _cmsIOPrintf(m, "\n");
+ _cmsPSActualColumn = 0;
+ }
}
-
-
// ----------------------------------------------------------------- PostScript generation
@@ -466,21 +372,31 @@
}
static
-void EmitHeader(LPMEMSTREAM m, const char* Title, cmsHPROFILE hProfile)
+void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile)
{
-
time_t timer;
+ cmsMLU *Description, *Copyright;
+ char DescASCII[256], CopyrightASCII[256];
time(&timer);
- Writef(m, "%%!PS-Adobe-3.0\n");
- Writef(m, "%%\n");
- Writef(m, "%% %s\n", Title);
- Writef(m, "%% Source: %s\n", RemoveCR(cmsTakeProductName(hProfile)));
- Writef(m, "%% Description: %s\n", RemoveCR(cmsTakeProductDesc(hProfile)));
- Writef(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!!
- Writef(m, "%%\n");
- Writef(m, "%%%%BeginResource\n");
+ Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag);
+ Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag);
+
+ DescASCII[0] = DescASCII[255] = 0;
+ CopyrightASCII[0] = CopyrightASCII[255] = 0;
+
+ if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255);
+ if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255);
+
+ _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n");
+ _cmsIOPrintf(m, "%%\n");
+ _cmsIOPrintf(m, "%% %s\n", Title);
+ _cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII));
+ _cmsIOPrintf(m, "%% %s\n", RemoveCR(CopyrightASCII));
+ _cmsIOPrintf(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!!
+ _cmsIOPrintf(m, "%%\n");
+ _cmsIOPrintf(m, "%%%%BeginResource\n");
}
@@ -489,31 +405,31 @@
// Black point adapted to D50.
static
-void EmitWhiteBlackD50(LPMEMSTREAM m, LPcmsCIEXYZ BlackPoint)
+void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint)
{
- Writef(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X,
+ _cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X,
BlackPoint -> Y,
BlackPoint -> Z);
- Writef(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X,
+ _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X,
cmsD50_XYZ()->Y,
cmsD50_XYZ()->Z);
}
static
-void EmitRangeCheck(LPMEMSTREAM m)
+void EmitRangeCheck(cmsIOHANDLER* m)
{
- Writef(m, "dup 0.0 lt { pop 0.0 } if "
- "dup 1.0 gt { pop 1.0 } if ");
+ _cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if "
+ "dup 1.0 gt { pop 1.0 } if ");
}
// Does write the intent
static
-void EmitIntent(LPMEMSTREAM m, int RenderingIntent)
+void EmitIntent(cmsIOHANDLER* m, int RenderingIntent)
{
const char *intent;
@@ -527,7 +443,7 @@
default: intent = "Undefined"; break;
}
- Writef(m, "/RenderingIntent (%s)\n", intent );
+ _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent );
}
//
@@ -539,9 +455,9 @@
/*
static
-void EmitL2Y(LPMEMSTREAM m)
+void EmitL2Y(cmsIOHANDLER* m)
{
- Writef(m,
+ _cmsIOPrintf(m,
"{ "
"100 mul 16 add 116 div " // (L * 100 + 16) / 116
"dup 6 29 div ge " // >= 6 / 29 ?
@@ -555,21 +471,21 @@
// Lab -> XYZ, see the discussion above
static
-void EmitLab2XYZ(LPMEMSTREAM m)
+void EmitLab2XYZ(cmsIOHANDLER* m)
{
- Writef(m, "/RangeABC [ 0 1 0 1 0 1]\n");
- Writef(m, "/DecodeABC [\n");
- Writef(m, "{100 mul 16 add 116 div } bind\n");
- Writef(m, "{255 mul 128 sub 500 div } bind\n");
- Writef(m, "{255 mul 128 sub 200 div } bind\n");
- Writef(m, "]\n");
- Writef(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
- Writef(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
- Writef(m, "/DecodeLMN [\n");
- Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
- Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
- Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n");
+ _cmsIOPrintf(m, "/DecodeABC [\n");
+ _cmsIOPrintf(m, "{100 mul 16 add 116 div } bind\n");
+ _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n");
+ _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n");
+ _cmsIOPrintf(m, "]\n");
+ _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
+ _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
+ _cmsIOPrintf(m, "/DecodeLMN [\n");
+ _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
+ _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
+ _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
+ _cmsIOPrintf(m, "]\n");
}
@@ -577,29 +493,25 @@
// Outputs a table of words. It does use 16 bits
static
-void Emit1Gamma(LPMEMSTREAM m, LPWORD Table, int nEntries)
+void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
{
- int i;
- double gamma;
+ cmsUInt32Number i;
+ cmsFloat64Number gamma;
- if (nEntries <= 0) return; // Empty table
+ if (Table ->nEntries <= 0) return; // Empty table
// Suppress whole if identity
- if (cmsIsLinear(Table, nEntries)) {
- Writef(m, "{} ");
- return;
- }
-
+ if (cmsIsToneCurveLinear(Table)) return;
// Check if is really an exponential. If so, emit "exp"
- gamma = cmsEstimateGammaEx(Table, nEntries, 0.001);
+ gamma = cmsEstimateGamma(Table, 0.001);
if (gamma > 0) {
- Writef(m, "{ %g exp } bind ", gamma);
+ _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
return;
}
- Writef(m, "{ ");
+ _cmsIOPrintf(m, "{ ");
// Bounds check
EmitRangeCheck(m);
@@ -609,94 +521,74 @@
// PostScript code Stack
// =============== ========================
// v
- Writef(m, " [");
+ _cmsIOPrintf(m, " [");
- // TODO: Check for endianess!!!
-
- for (i=0; i < nEntries; i++) {
- Writef(m, "%d ", Table[i]);
+ for (i=0; i < Table->nEntries; i++) {
+ _cmsIOPrintf(m, "%d ", Table->Table16[i]);
}
- Writef(m, "] "); // v tab
+ _cmsIOPrintf(m, "] "); // v tab
- Writef(m, "dup "); // v tab tab
- Writef(m, "length 1 sub "); // v tab dom
- Writef(m, "3 -1 roll "); // tab dom v
- Writef(m, "mul "); // tab val2
- Writef(m, "dup "); // tab val2 val2
- Writef(m, "dup "); // tab val2 val2 val2
- Writef(m, "floor cvi "); // tab val2 val2 cell0
- Writef(m, "exch "); // tab val2 cell0 val2
- Writef(m, "ceiling cvi "); // tab val2 cell0 cell1
- Writef(m, "3 index "); // tab val2 cell0 cell1 tab
- Writef(m, "exch "); // tab val2 cell0 tab cell1
- Writef(m, "get "); // tab val2 cell0 y1
- Writef(m, "4 -1 roll "); // val2 cell0 y1 tab
- Writef(m, "3 -1 roll "); // val2 y1 tab cell0
- Writef(m, "get "); // val2 y1 y0
- Writef(m, "dup "); // val2 y1 y0 y0
- Writef(m, "3 1 roll "); // val2 y0 y1 y0
- Writef(m, "sub "); // val2 y0 (y1-y0)
- Writef(m, "3 -1 roll "); // y0 (y1-y0) val2
- Writef(m, "dup "); // y0 (y1-y0) val2 val2
- Writef(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2)
- Writef(m, "sub "); // y0 (y1-y0) rest
- Writef(m, "mul "); // y0 t1
- Writef(m, "add "); // y
- Writef(m, "65535 div "); // result
+ _cmsIOPrintf(m, "dup "); // v tab tab
+ _cmsIOPrintf(m, "length 1 sub "); // v tab dom
+ _cmsIOPrintf(m, "3 -1 roll "); // tab dom v
+ _cmsIOPrintf(m, "mul "); // tab val2
+ _cmsIOPrintf(m, "dup "); // tab val2 val2
+ _cmsIOPrintf(m, "dup "); // tab val2 val2 val2
+ _cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0
+ _cmsIOPrintf(m, "exch "); // tab val2 cell0 val2
+ _cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1
+ _cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab
+ _cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1
+ _cmsIOPrintf(m, "get "); // tab val2 cell0 y1
+ _cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab
+ _cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0
+ _cmsIOPrintf(m, "get "); // val2 y1 y0
+ _cmsIOPrintf(m, "dup "); // val2 y1 y0 y0
+ _cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0
+ _cmsIOPrintf(m, "sub "); // val2 y0 (y1-y0)
+ _cmsIOPrintf(m, "3 -1 roll "); // y0 (y1-y0) val2
+ _cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2
+ _cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2)
+ _cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest
+ _cmsIOPrintf(m, "mul "); // y0 t1
+ _cmsIOPrintf(m, "add "); // y
+ _cmsIOPrintf(m, "65535 div "); // result
- Writef(m, " } bind ");
+ _cmsIOPrintf(m, " } bind ");
}
// Compare gamma table
static
-LCMSBOOL GammaTableEquals(LPWORD g1, LPWORD g2, int nEntries)
+cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries)
{
- return memcmp(g1, g2, nEntries* sizeof(WORD)) == 0;
+ return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
}
// Does write a set of gamma curves
static
-void EmitNGamma(LPMEMSTREAM m, int n, LPWORD g[], int nEntries)
+void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[])
{
int i;
for( i=0; i < n; i++ )
{
- if (i > 0 && GammaTableEquals(g[i-1], g[i], nEntries)) {
+ if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
- Writef(m, "dup ");
+ _cmsIOPrintf(m, "dup ");
}
else {
- Emit1Gamma(m, g[i], nEntries);
+ Emit1Gamma(m, g[i]);
}
}
}
-// Check whatever a profile has CLUT tables (only on input)
-
-static
-LCMSBOOL IsLUTbased(cmsHPROFILE hProfile, int Intent)
-{
- icTagSignature Tag;
-
- // Check if adequate tag is present
- Tag = Device2PCSTab[Intent];
-
- if (cmsIsTag(hProfile, Tag)) return 1;
-
- // If not present, revert to default (perceptual)
- Tag = icSigAToB0Tag;
-
- // If no tag present, try matrix-shaper
- return cmsIsTag(hProfile, Tag);
-}
@@ -707,19 +599,19 @@
// that is, the callback will be called for each knot with
//
// In[] The grid location coordinates, normalized to 0..ffff
-// Out[] The LUT values, normalized to 0..ffff
+// Out[] The Pipeline values, normalized to 0..ffff
//
// Returning a value other than 0 does terminate the sampling process
//
-// Each row contains LUT values for all but first component. So, I
+// Each row contains Pipeline values for all but first component. So, I
// detect row changing by keeping a copy of last value of first
// component. -1 is used to mark begining of whole block.
static
-int OutputValueSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
- LPSAMPLERCARGO sc = (LPSAMPLERCARGO) Cargo;
- unsigned int i;
+ cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
+ cmsUInt32Number i;
if (sc -> FixWhite) {
@@ -729,14 +621,14 @@
if ((In[1] >= 0x7800 && In[1] <= 0x8800) &&
(In[2] >= 0x7800 && In[2] <= 0x8800)) {
- WORD* Black;
- WORD* White;
- int nOutputs;
+ cmsUInt16Number* Black;
+ cmsUInt16Number* White;
+ cmsUInt32Number nOutputs;
if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs))
return 0;
- for (i=0; i < (unsigned int) nOutputs; i++)
+ for (i=0; i < nOutputs; i++)
Out[i] = White[i];
}
@@ -751,15 +643,15 @@
if (sc ->FirstComponent != -1) {
- Writef(sc ->m, sc ->PostMin);
+ _cmsIOPrintf(sc ->m, sc ->PostMin);
sc ->SecondComponent = -1;
- Writef(sc ->m, sc ->PostMaj);
+ _cmsIOPrintf(sc ->m, sc ->PostMaj);
}
// Begin block
- sc->m->Col = 0;
+ _cmsPSActualColumn = 0;
- Writef(sc ->m, sc ->PreMaj);
+ _cmsIOPrintf(sc ->m, sc ->PreMaj);
sc ->FirstComponent = In[0];
}
@@ -768,96 +660,66 @@
if (sc ->SecondComponent != -1) {
- Writef(sc ->m, sc ->PostMin);
+ _cmsIOPrintf(sc ->m, sc ->PostMin);
}
- Writef(sc ->m, sc ->PreMin);
+ _cmsIOPrintf(sc ->m, sc ->PreMin);
sc ->SecondComponent = In[1];
}
-
-
- // Dump table. Could be Word or byte based on
- // depending on bps member (16 bps mode is not currently
- // being used at all, but is here for future ampliations)
-
- for (i=0; i < sc -> Lut ->OutputChan; i++) {
+ // Dump table.
- WORD wWordOut = Out[i];
-
- if (sc ->bps == 8) {
+ for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) {
- // Value as byte
- BYTE wByteOut;
-
- // If is input, convert from Lab2 to Lab4 (just divide by 256)
+ cmsUInt16Number wWordOut = Out[i];
+ cmsUInt8Number wByteOut; // Value as byte
- if (sc ->lIsInput) {
-
-
- wByteOut = L2Byte(wWordOut);
- }
- else
- wByteOut = Word2Byte(wWordOut);
+ // We always deal with Lab4
- WriteByte(sc -> m, wByteOut);
- }
- else {
+ wByteOut = Word2Byte(wWordOut);
+ WriteByte(sc -> m, wByteOut);
+ }
- // Value as word
- WriteByte(sc -> m, (BYTE) (wWordOut & 0xFF));
- WriteByte(sc -> m, (BYTE) ((wWordOut >> 8) & 0xFF));
- }
- }
-
- return 1;
+ return 1;
}
-// Writes a LUT on memstream. Could be 8 or 16 bits based
+// Writes a Pipeline on memstream. Could be 8 or 16 bits based
static
-void WriteCLUT(LPMEMSTREAM m, LPLUT Lut, int bps, const char* PreMaj,
- const char* PostMaj,
- const char* PreMin,
- const char* PostMin,
- int lIsInput,
- int FixWhite,
- icColorSpaceSignature ColorSpace)
+void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
+ const char* PostMaj,
+ const char* PreMin,
+ const char* PostMin,
+ int FixWhite,
+ cmsColorSpaceSignature ColorSpace)
{
- unsigned int i;
- SAMPLERCARGO sc;
+ cmsUInt32Number i;
+ cmsPsSamplerCargo sc;
sc.FirstComponent = -1;
sc.SecondComponent = -1;
- sc.Lut = Lut;
+ sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
sc.m = m;
- sc.bps = bps;
sc.PreMaj = PreMaj;
sc.PostMaj= PostMaj;
sc.PreMin = PreMin;
sc.PostMin = PostMin;
- sc.lIsInput = lIsInput;
sc.FixWhite = FixWhite;
sc.ColorSpace = ColorSpace;
- Writef(m, "[");
+ _cmsIOPrintf(m, "[");
- for (i=0; i < Lut ->InputChan; i++)
- Writef(m, " %d ", Lut ->cLutPoints);
-
- Writef(m, " [\n");
-
-
+ for (i=0; i < sc.Pipeline->Params->nInputs; i++)
+ _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
- cmsSample3DGrid(Lut, OutputValueSampler, (LPVOID) &sc, SAMPLER_INSPECT);
+ _cmsIOPrintf(m, " [\n");
+ cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
- Writef(m, PostMin);
- Writef(m, PostMaj);
- Writef(m, "] ");
-
-
+ _cmsIOPrintf(m, PostMin);
+ _cmsIOPrintf(m, PostMaj);
+ _cmsIOPrintf(m, "] ");
}
@@ -865,89 +727,92 @@
// Dumps CIEBasedA Color Space Array
static
-int EmitCIEBasedA(LPMEMSTREAM m, LPWORD Tab, int nEntries, LPcmsCIEXYZ BlackPoint)
+int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
{
- Writef(m, "[ /CIEBasedA\n");
- Writef(m, " <<\n");
+ _cmsIOPrintf(m, "[ /CIEBasedA\n");
+ _cmsIOPrintf(m, " <<\n");
- Writef(m, "/DecodeA ");
+ _cmsIOPrintf(m, "/DecodeA ");
- Emit1Gamma(m,Tab, nEntries);
+ Emit1Gamma(m, Curve);
- Writef(m, " \n");
+ _cmsIOPrintf(m, " \n");
- Writef(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
- Writef(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
+ _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
+ _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
- EmitWhiteBlackD50(m, BlackPoint);
- EmitIntent(m, INTENT_PERCEPTUAL);
+ EmitWhiteBlackD50(m, BlackPoint);
+ EmitIntent(m, INTENT_PERCEPTUAL);
- Writef(m, ">>\n");
- Writef(m, "]\n");
+ _cmsIOPrintf(m, ">>\n");
+ _cmsIOPrintf(m, "]\n");
- return 1;
+ return 1;
}
// Dumps CIEBasedABC Color Space Array
static
-int EmitCIEBasedABC(LPMEMSTREAM m, LPWORD L[], int nEntries, LPWMAT3 Matrix, LPcmsCIEXYZ BlackPoint)
+int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
{
int i;
- Writef(m, "[ /CIEBasedABC\n");
- Writef(m, "<<\n");
- Writef(m, "/DecodeABC [ ");
+ _cmsIOPrintf(m, "[ /CIEBasedABC\n");
+ _cmsIOPrintf(m, "<<\n");
+ _cmsIOPrintf(m, "/DecodeABC [ ");
- EmitNGamma(m, 3, L, nEntries);
+ EmitNGamma(m, 3, CurveSet);
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "]\n");
- Writef(m, "/MatrixABC [ " );
+ _cmsIOPrintf(m, "/MatrixABC [ " );
- for( i=0; i < 3; i++ ) {
+ for( i=0; i < 3; i++ ) {
- Writef(m, "%.6f %.6f %.6f ",
- FIXED_TO_DOUBLE(Matrix->v[0].n[i]),
- FIXED_TO_DOUBLE(Matrix->v[1].n[i]),
- FIXED_TO_DOUBLE(Matrix->v[2].n[i]));
- }
+ _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[0 + 3*i],
+ Matrix[1 + 3*i],
+ Matrix[2 + 3*i]);
+ }
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "]\n");
- Writef(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
+ _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
- EmitWhiteBlackD50(m, BlackPoint);
- EmitIntent(m, INTENT_PERCEPTUAL);
+ EmitWhiteBlackD50(m, BlackPoint);
+ EmitIntent(m, INTENT_PERCEPTUAL);
- Writef(m, ">>\n");
- Writef(m, "]\n");
+ _cmsIOPrintf(m, ">>\n");
+ _cmsIOPrintf(m, "]\n");
- return 1;
+ return 1;
}
static
-int EmitCIEBasedDEF(LPMEMSTREAM m, LPLUT Lut, int Intent, LPcmsCIEXYZ BlackPoint)
+int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint)
{
const char* PreMaj;
const char* PostMaj;
const char* PreMin, *PostMin;
+ cmsStage* mpe;
- switch (Lut ->InputChan) {
+ mpe = Pipeline ->Elements;
+
+
+ switch (cmsStageInputChannels(mpe)) {
case 3:
- Writef(m, "[ /CIEBasedDEF\n");
+ _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
PreMaj ="<";
PostMaj= ">\n";
PreMin = PostMin = "";
break;
case 4:
- Writef(m, "[ /CIEBasedDEFG\n");
+ _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
PreMaj = "[";
PostMaj = "]\n";
PreMin = "<";
@@ -958,30 +823,32 @@
}
- Writef(m, "<<\n");
+ _cmsIOPrintf(m, "<<\n");
- if (Lut ->wFlags & LUT_HASTL1) {
+ if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
- Writef(m, "/DecodeDEF [ ");
- EmitNGamma(m, Lut ->InputChan, Lut ->L1, Lut ->CLut16params.nSamples);
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "/DecodeDEF [ ");
+ EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
+ _cmsIOPrintf(m, "]\n");
+
+ mpe = mpe ->Next;
}
- if (Lut ->wFlags & LUT_HAS3DGRID) {
+ if (cmsStageType(mpe) == cmsSigCLutElemType) {
- Writef(m, "/Table ");
- WriteCLUT(m, Lut, 8, PreMaj, PostMaj, PreMin, PostMin, TRUE, FALSE, (icColorSpaceSignature) 0);
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "/Table ");
+ WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
+ _cmsIOPrintf(m, "]\n");
}
EmitLab2XYZ(m);
EmitWhiteBlackD50(m, BlackPoint);
EmitIntent(m, Intent);
- Writef(m, " >>\n");
- Writef(m, "]\n");
+ _cmsIOPrintf(m, " >>\n");
+ _cmsIOPrintf(m, "]\n");
return 1;
@@ -990,21 +857,21 @@
// Generates a curve from a gray profile
static
-LPGAMMATABLE ExtractGray2Y(cmsHPROFILE hProfile, int Intent)
+cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
{
- LPGAMMATABLE Out = cmsAllocGamma(256);
- cmsHPROFILE hXYZ = cmsCreateXYZProfile();
- cmsHTRANSFORM xform = cmsCreateTransform(hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOTPRECALC);
+ cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
+ cmsHPROFILE hXYZ = cmsCreateXYZProfile();
+ cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);
int i;
for (i=0; i < 256; i++) {
- BYTE Gray = (BYTE) i;
+ cmsUInt8Number Gray = (cmsUInt8Number) i;
cmsCIEXYZ XYZ;
cmsDoTransform(xform, &Gray, &XYZ, 1);
- Out ->GammaTable[i] =_cmsClampWord((int) floor(XYZ.Y * 65535.0 + 0.5));
+ Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
}
cmsDeleteTransform(xform);
@@ -1014,17 +881,16 @@
-// Because PostScrip has only 8 bits in /Table, we should use
+// Because PostScript has only 8 bits in /Table, we should use
// a more perceptually uniform space... I do choose Lab.
static
-int WriteInputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent)
+int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
{
cmsHPROFILE hLab;
cmsHTRANSFORM xform;
- icColorSpaceSignature ColorSpace;
- int nChannels;
- DWORD InputFormat;
+ cmsUInt32Number nChannels;
+ cmsUInt32Number InputFormat;
int rc;
cmsHPROFILE Profiles[2];
cmsCIEXYZ BlackPointAdaptedToD50;
@@ -1032,49 +898,25 @@
// Does create a device-link based transform.
// The DeviceLink is next dumped as working CSA.
- hLab = cmsCreateLabProfile(NULL);
- ColorSpace = cmsGetColorSpace(hProfile);
- nChannels = _cmsChannelsOf(ColorSpace);
- InputFormat = CHANNELS_SH(nChannels) | BYTES_SH(2);
-
- cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent,LCMS_BPFLAGS_D50_ADAPTED);
-
- // Is a devicelink profile?
- if (cmsGetDeviceClass(hProfile) == icSigLinkClass) {
-
- // if devicelink output already Lab, use it directly
-
- if (cmsGetPCS(hProfile) == icSigLabData) {
-
- xform = cmsCreateTransform(hProfile, InputFormat, NULL,
- TYPE_Lab_DBL, Intent, 0);
- }
- else {
-
- // Nope, adjust output to Lab if possible
-
- Profiles[0] = hProfile;
- Profiles[1] = hLab;
-
- xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat,
- TYPE_Lab_DBL, Intent, 0);
- }
+ InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
+ nChannels = T_CHANNELS(InputFormat);
- }
- else {
+ cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
+
+ // Adjust output to Lab4
+ hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
- // This is a normal profile
- xform = cmsCreateTransform(hProfile, InputFormat, hLab,
- TYPE_Lab_DBL, Intent, 0);
- }
+ Profiles[0] = hProfile;
+ Profiles[1] = hLab;
-
+ xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0);
+ cmsCloseProfile(hLab);
if (xform == NULL) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Cannot create transform Profile -> Lab");
- return 0;
+ cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab");
+ return 0;
}
// Only 1, 3 and 4 channels are allowed
@@ -1082,86 +924,82 @@
switch (nChannels) {
case 1: {
- LPGAMMATABLE Gray2Y = ExtractGray2Y(hProfile, Intent);
- EmitCIEBasedA(m, Gray2Y->GammaTable, Gray2Y ->nEntries, &BlackPointAdaptedToD50);
- cmsFreeGamma(Gray2Y);
+ cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
+ EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50);
+ cmsFreeToneCurve(Gray2Y);
}
break;
case 3:
case 4: {
- LPLUT DeviceLink;
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
+ cmsUInt32Number OutFrm = TYPE_Lab_16;
+ cmsPipeline* DeviceLink;
+ _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
- if (v ->DeviceLink)
- rc = EmitCIEBasedDEF(m, v->DeviceLink, Intent, &BlackPointAdaptedToD50);
- else {
- DeviceLink = _cmsPrecalculateDeviceLink(xform, 0);
- rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
- cmsFreeLUT(DeviceLink);
- }
+ DeviceLink = cmsPipelineDup(v ->Lut);
+ if (DeviceLink == NULL) return 0;
+
+ dwFlags |= cmsFLAGS_FORCE_CLUT;
+ _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
+
+ rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
+ cmsPipelineFree(DeviceLink);
}
break;
default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
- return 0;
+ cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
+ return 0;
}
cmsDeleteTransform(xform);
- cmsCloseProfile(hLab);
+
return 1;
}
+static
+cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
+{
+ _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
+
+ return Data -> Double;
+}
// Does create CSA based on matrix-shaper. Allowed types are gray and RGB based
static
-int WriteInputMatrixShaper(LPMEMSTREAM m, cmsHPROFILE hProfile)
+int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper)
{
- icColorSpaceSignature ColorSpace;
- LPMATSHAPER MatShaper;
+ cmsColorSpaceSignature ColorSpace;
int rc;
cmsCIEXYZ BlackPointAdaptedToD50;
-
ColorSpace = cmsGetColorSpace(hProfile);
- MatShaper = cmsBuildInputMatrixShaper(hProfile);
- cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_BPFLAGS_D50_ADAPTED);
-
- if (MatShaper == NULL) {
+ cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsSignalError(LCMS_ERRC_ABORTED, "This profile is not suitable for input");
- return 0;
- }
+ if (ColorSpace == cmsSigGrayData) {
- if (ColorSpace == icSigGrayData) {
-
- rc = EmitCIEBasedA(m, MatShaper ->L[0],
- MatShaper ->p16.nSamples,
- &BlackPointAdaptedToD50);
+ cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
+ rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
}
else
- if (ColorSpace == icSigRgbData) {
-
+ if (ColorSpace == cmsSigRgbData) {
- rc = EmitCIEBasedABC(m, MatShaper->L,
- MatShaper ->p16.nSamples,
- &MatShaper ->Matrix,
- &BlackPointAdaptedToD50);
+ rc = EmitCIEBasedABC(m, GetPtrToMatrix(Matrix),
+ _cmsStageGetPtrToCurveSet(Shaper),
+ &BlackPointAdaptedToD50);
}
else {
- cmsSignalError(LCMS_ERRC_ABORTED, "Profile is not suitable for CSA. Unsupported colorspace.");
+ cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
return 0;
}
- cmsFreeMatShaper(MatShaper);
return rc;
}
@@ -1171,45 +1009,46 @@
// This is a HP extension, and it works in Lab instead of XYZ
static
-int WriteNamedColorCSA(LPMEMSTREAM m, cmsHPROFILE hNamedColor, int Intent)
+int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent)
{
cmsHTRANSFORM xform;
cmsHPROFILE hLab;
int i, nColors;
char ColorName[32];
-
+ cmsNAMEDCOLORLIST* NamedColorList;
- hLab = cmsCreateLabProfile(NULL);
- xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX,
- hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOTPRECALC);
+ hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
+ xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);
if (xform == NULL) return 0;
+ NamedColorList = cmsGetNamedColorList(xform);
+ if (NamedColorList == NULL) return 0;
- Writef(m, "<<\n");
- Writef(m, "(colorlistcomment) (%s)\n", "Named color CSA");
- Writef(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
- Writef(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
+ _cmsIOPrintf(m, "<<\n");
+ _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
+ _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
+ _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
- nColors = cmsNamedColorCount(xform);
+ nColors = cmsNamedColorCount(NamedColorList);
for (i=0; i < nColors; i++) {
- WORD In[1];
+ cmsUInt16Number In[1];
cmsCIELab Lab;
- In[0] = (WORD) i;
+ In[0] = (cmsUInt16Number) i;
- if (!cmsNamedColorInfo(xform, i, ColorName, NULL, NULL))
+ if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
continue;
cmsDoTransform(xform, In, &Lab, 1);
- Writef(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
+ _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
}
- Writef(m, ">>\n");
+ _cmsIOPrintf(m, ">>\n");
cmsDeleteTransform(xform);
cmsCloseProfile(hLab);
@@ -1218,75 +1057,68 @@
// Does create a Color Space Array on XYZ colorspace for PostScript usage
-
-DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile,
- int Intent,
- LPVOID Buffer, DWORD dwBufferLen)
+static
+cmsUInt32Number GenerateCSA(cmsContext ContextID,
+ cmsHPROFILE hProfile,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags,
+ cmsIOHANDLER* mem)
{
-
- LPMEMSTREAM mem;
- DWORD dwBytesUsed;
-
- // Set up the serialization engine
- mem = CreateMemStream((LPBYTE) Buffer, dwBufferLen, MAXPSCOLS);
- if (!mem) return 0;
+ cmsUInt32Number dwBytesUsed;
+ cmsPipeline* lut = NULL;
+ cmsStage* Matrix, *Shaper;
// Is a named color profile?
- if (cmsGetDeviceClass(hProfile) == icSigNamedColorClass) {
-
- if (!WriteNamedColorCSA(mem, hProfile, Intent)) {
+ if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
- _cmsFree((void*) mem);
- return 0;
- }
+ if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error;
}
else {
- // Any profile class are allowed (including devicelink), but
- // output (PCS) colorspace must be XYZ or Lab
- icColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
-
- if (ColorSpace != icSigXYZData &&
- ColorSpace != icSigLabData) {
+ // Any profile class are allowed (including devicelink), but
+ // output (PCS) colorspace must be XYZ or Lab
+ cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
- cmsSignalError(LCMS_ERRC_ABORTED, "Invalid output color space");
- _cmsFree((void*) mem);
- return 0;
- }
+ if (ColorSpace != cmsSigXYZData &&
+ ColorSpace != cmsSigLabData) {
- // Is there any CLUT?
- if (IsLUTbased(hProfile, Intent)) {
+ cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space");
+ goto Error;
+ }
+
- // Yes, so handle as LUT-based
- if (!WriteInputLUT(mem, hProfile, Intent)) {
+ // Read the lut with all necessary conversion stages
+ lut = _cmsReadInputLUT(hProfile, Intent);
+ if (lut == NULL) goto Error;
- _cmsFree((void*) mem);
- return 0;
- }
- }
- else {
+
+ // Tone curves + matrix can be implemented without any LUT
+ if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) {
- // No, try Matrix-shaper (this only works on XYZ)
-
- if (!WriteInputMatrixShaper(mem, hProfile)) {
+ if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error;
- _cmsFree((void*) mem); // Something went wrong
- return 0;
}
- }
+ else {
+ // We need a LUT for the rest
+ if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error;
+ }
}
// Done, keep memory usage
- dwBytesUsed = mem ->dwUsed;
+ dwBytesUsed = mem ->UsedSpace;
- // Get rid of memory stream
- _cmsFree((void*) mem);
+ // Get rid of LUT
+ if (lut != NULL) cmsPipelineFree(lut);
// Finally, return used byte count
return dwBytesUsed;
+
+Error:
+ if (lut != NULL) cmsPipelineFree(lut);
+ return 0;
}
// ------------------------------------------------------ Color Rendering Dictionary (CRD)
@@ -1356,45 +1188,45 @@
static
-void EmitPQRStage(LPMEMSTREAM m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute)
+void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute)
{
if (lIsAbsolute) {
// For absolute colorimetric intent, encode back to relative
- // and generate a relative LUT
+ // and generate a relative Pipeline
// Relative encoding is obtained across XYZpcs*(D50/WhitePoint)
cmsCIEXYZ White;
- cmsTakeMediaWhitePoint(&White, hProfile);
+ _cmsReadMediaWhitePoint(&White, hProfile);
- Writef(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n");
- Writef(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
+ _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n");
+ _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
- Writef(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n"
+ _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n"
"/TransformPQR [\n"
"{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n"
"{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n"
"{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n",
- White.X, White.Y, White.Z);
+ White.X, White.Y, White.Z);
return;
}
- Writef(m,"%% Bradford Cone Space\n"
+ _cmsIOPrintf(m,"%% Bradford Cone Space\n"
"/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n");
- Writef(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
+ _cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
// No BPC
if (!DoBPC) {
- Writef(m, "%% VonKries-like transform in Bradford Cone Space\n"
+ _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n"
"/TransformPQR [\n"
"{exch pop exch 3 get mul exch pop exch 3 get div} bind\n"
"{exch pop exch 4 get mul exch pop exch 4 get div} bind\n"
@@ -1403,22 +1235,22 @@
// BPC
- Writef(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n"
+ _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n"
"/TransformPQR [\n");
- Writef(m, "{4 index 3 get div 2 index 3 get mul "
+ _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul "
"2 index 3 get 2 index 3 get sub mul "
"2 index 3 get 4 index 3 get 3 index 3 get sub mul sub "
"3 index 3 get 3 index 3 get exch sub div "
"exch pop exch pop exch pop exch pop } bind\n");
- Writef(m, "{4 index 4 get div 2 index 4 get mul "
+ _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul "
"2 index 4 get 2 index 4 get sub mul "
"2 index 4 get 4 index 4 get 3 index 4 get sub mul sub "
"3 index 4 get 3 index 4 get exch sub div "
"exch pop exch pop exch pop exch pop } bind\n");
- Writef(m, "{4 index 5 get div 2 index 5 get mul "
+ _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul "
"2 index 5 get 2 index 5 get sub mul "
"2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
"3 index 5 get 3 index 5 get exch sub div "
@@ -1431,24 +1263,24 @@
static
-void EmitXYZ2Lab(LPMEMSTREAM m)
+void EmitXYZ2Lab(cmsIOHANDLER* m)
{
- Writef(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
- Writef(m, "/EncodeLMN [\n");
- Writef(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
- Writef(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
- Writef(m, "{ 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
- Writef(m, "]\n");
- Writef(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
- Writef(m, "/EncodeABC [\n");
+ _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
+ _cmsIOPrintf(m, "/EncodeLMN [\n");
+ _cmsIOPrintf(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
+ _cmsIOPrintf(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
+ _cmsIOPrintf(m, "{ 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
+ _cmsIOPrintf(m, "]\n");
+ _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
+ _cmsIOPrintf(m, "/EncodeABC [\n");
- Writef(m, "{ 116 mul 16 sub 100 div } bind\n");
- Writef(m, "{ 500 mul 128 add 256 div } bind\n");
- Writef(m, "{ 200 mul 128 add 256 div } bind\n");
+ _cmsIOPrintf(m, "{ 116 mul 16 sub 100 div } bind\n");
+ _cmsIOPrintf(m, "{ 500 mul 128 add 256 div } bind\n");
+ _cmsIOPrintf(m, "{ 200 mul 128 add 256 div } bind\n");
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "]\n");
}
@@ -1460,104 +1292,74 @@
// 8 bits.
static
-int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlags)
+int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
{
cmsHPROFILE hLab;
cmsHTRANSFORM xform;
- icColorSpaceSignature ColorSpace;
int i, nChannels;
- DWORD OutputFormat;
- _LPcmsTRANSFORM v;
- LPLUT DeviceLink;
+ cmsUInt32Number OutputFormat;
+ _cmsTRANSFORM* v;
+ cmsPipeline* DeviceLink;
cmsHPROFILE Profiles[3];
cmsCIEXYZ BlackPointAdaptedToD50;
- LCMSBOOL lFreeDeviceLink = FALSE;
- LCMSBOOL lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
- LCMSBOOL lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
+ cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
+ cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
+ cmsUInt32Number InFrm = TYPE_Lab_16;
int RelativeEncodingIntent;
-
+ cmsColorSpaceSignature ColorSpace;
- hLab = cmsCreateLabProfile(NULL);
+ hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
+ if (hLab == NULL) return 0;
- ColorSpace = cmsGetColorSpace(hProfile);
- nChannels = _cmsChannelsOf(ColorSpace);
- OutputFormat = CHANNELS_SH(nChannels) | BYTES_SH(2);
+ OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
+ nChannels = T_CHANNELS(OutputFormat);
- // For absolute colorimetric, the LUT is encoded as relative
- // in order to preserve precission.
+ ColorSpace = cmsGetColorSpace(hProfile);
+
+ // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision.
RelativeEncodingIntent = Intent;
if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC)
RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC;
- // Is a devicelink profile?
- if (cmsGetDeviceClass(hProfile) == icSigLinkClass) {
-
- // if devicelink input already in Lab
-
- if (ColorSpace == icSigLabData) {
-
- // adjust input to Lab to our v4
-
- Profiles[0] = hLab;
- Profiles[1] = hProfile;
+ // Use V4 Lab always
+ Profiles[0] = hLab;
+ Profiles[1] = hProfile;
- xform = cmsCreateMultiprofileTransform(Profiles, 2, TYPE_Lab_DBL,
- OutputFormat, RelativeEncodingIntent,
- dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION);
-
- }
- else {
- cmsSignalError(LCMS_ERRC_ABORTED, "Cannot use devicelink profile for CRD creation");
- return 0;
- }
-
-
- }
- else {
-
- // This is a normal profile
- xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hProfile,
- OutputFormat, RelativeEncodingIntent, dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION);
- }
+ xform = cmsCreateMultiprofileTransformTHR(m ->ContextID,
+ Profiles, 2, TYPE_Lab_DBL,
+ OutputFormat, RelativeEncodingIntent, 0);
+ cmsCloseProfile(hLab);
if (xform == NULL) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Cannot create transform Lab -> Profile in CRD creation");
- return 0;
+ cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
+ return 0;
}
- // Get the internal precalculated devicelink
-
- v = (_LPcmsTRANSFORM) xform;
- DeviceLink = v ->DeviceLink;
-
- if (!DeviceLink) {
-
- DeviceLink = _cmsPrecalculateDeviceLink(xform, cmsFLAGS_NOPRELINEARIZATION);
- lFreeDeviceLink = TRUE;
- }
-
- Writef(m, "<<\n");
- Writef(m, "/ColorRenderingType 1\n");
+ // Get a copy of the internal devicelink
+ v = (_cmsTRANSFORM*) xform;
+ DeviceLink = cmsPipelineDup(v ->Lut);
+ if (DeviceLink == NULL) return 0;
- cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, LCMS_BPFLAGS_D50_ADAPTED);
+ // We need a CLUT
+ dwFlags |= cmsFLAGS_FORCE_CLUT;
+ _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
+
+ _cmsIOPrintf(m, "<<\n");
+ _cmsIOPrintf(m, "/ColorRenderingType 1\n");
+
+
+ cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
// Emit headers, etc.
EmitWhiteBlackD50(m, &BlackPointAdaptedToD50);
EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC);
EmitXYZ2Lab(m);
- if (DeviceLink ->wFlags & LUT_HASTL1) {
-
- // Shouldn't happen
- cmsSignalError(LCMS_ERRC_ABORTED, "Internal error (prelinearization on CRD)");
- return 0;
- }
-
// FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab
// does map a=b=0 not falling into any specific node. Since range a,b goes -128..127,
@@ -1568,31 +1370,30 @@
if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
lFixWhite = FALSE;
- Writef(m, "/RenderTable ");
+ _cmsIOPrintf(m, "/RenderTable ");
+
- WriteCLUT(m, DeviceLink, 8, "<", ">\n", "", "", FALSE,
- lFixWhite, ColorSpace);
+ WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);
- Writef(m, " %d {} bind ", nChannels);
+ _cmsIOPrintf(m, " %d {} bind ", nChannels);
for (i=1; i < nChannels; i++)
- Writef(m, "dup ");
+ _cmsIOPrintf(m, "dup ");
- Writef(m, "]\n");
+ _cmsIOPrintf(m, "]\n");
EmitIntent(m, Intent);
- Writef(m, ">>\n");
+ _cmsIOPrintf(m, ">>\n");
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
- Writef(m, "/Current exch /ColorRendering defineresource pop\n");
+ _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n");
}
- if (lFreeDeviceLink) cmsFreeLUT(DeviceLink);
+ cmsPipelineFree(DeviceLink);
cmsDeleteTransform(xform);
- cmsCloseProfile(hLab);
return 1;
}
@@ -1600,14 +1401,14 @@
// Builds a ASCII string containing colorant list in 0..1.0 range
static
-void BuildColorantList(char *Colorant, int nColorant, WORD Out[])
+void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[])
{
char Buff[32];
int j;
Colorant[0] = 0;
- if (nColorant > MAXCHANNELS)
- nColorant = MAXCHANNELS;
+ if (nColorant > cmsMAXCHANNELS)
+ nColorant = cmsMAXCHANNELS;
for (j=0; j < nColorant; j++) {
@@ -1624,50 +1425,54 @@
// This is a HP extension.
static
-int WriteNamedColorCRD(LPMEMSTREAM m, cmsHPROFILE hNamedColor, int Intent, DWORD dwFlags)
+int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags)
{
cmsHTRANSFORM xform;
int i, nColors, nColorant;
- DWORD OutputFormat;
+ cmsUInt32Number OutputFormat;
char ColorName[32];
char Colorant[128];
+ cmsNAMEDCOLORLIST* NamedColorList;
- nColorant = _cmsChannelsOf(cmsGetColorSpace(hNamedColor));
- OutputFormat = CHANNELS_SH(nColorant) | BYTES_SH(2);
- xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX,
- NULL, OutputFormat, Intent, cmsFLAGS_NOTPRECALC);
+ OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
+ nColorant = T_CHANNELS(OutputFormat);
+
+
+ xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
if (xform == NULL) return 0;
- Writef(m, "<<\n");
- Writef(m, "(colorlistcomment) (%s) \n", "Named profile");
- Writef(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
- Writef(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
+ NamedColorList = cmsGetNamedColorList(xform);
+ if (NamedColorList == NULL) return 0;
- nColors = cmsNamedColorCount(xform);
+ _cmsIOPrintf(m, "<<\n");
+ _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
+ _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
+ _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
+ nColors = cmsNamedColorCount(NamedColorList);
for (i=0; i < nColors; i++) {
- WORD In[1];
- WORD Out[MAXCHANNELS];
+ cmsUInt16Number In[1];
+ cmsUInt16Number Out[cmsMAXCHANNELS];
- In[0] = (WORD) i;
+ In[0] = (cmsUInt16Number) i;
- if (!cmsNamedColorInfo(xform, i, ColorName, NULL, NULL))
+ if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
continue;
cmsDoTransform(xform, In, Out, 1);
BuildColorantList(Colorant, nColorant, Out);
- Writef(m, " (%s) [ %s ]\n", ColorName, Colorant);
+ _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant);
}
- Writef(m, " >>");
+ _cmsIOPrintf(m, " >>");
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
- Writef(m, " /Current exch /HPSpotTable defineresource pop\n");
+ _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n");
}
cmsDeleteTransform(xform);
@@ -1680,67 +1485,129 @@
// CRD are always LUT-Based, no matter if profile is
// implemented as matrix-shaper.
-DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile,
- int Intent, DWORD dwFlags,
- LPVOID Buffer, DWORD dwBufferLen)
+static
+cmsUInt32Number GenerateCRD(cmsContext ContextID,
+ cmsHPROFILE hProfile,
+ cmsUInt32Number Intent, cmsUInt32Number dwFlags,
+ cmsIOHANDLER* mem)
{
-
- LPMEMSTREAM mem;
- DWORD dwBytesUsed;
-
- // Set up the serialization artifact
- mem = CreateMemStream((LPBYTE) Buffer, dwBufferLen, MAXPSCOLS);
- if (!mem) return 0;
-
+ cmsUInt32Number dwBytesUsed;
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
- EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile);
+ EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile);
}
// Is a named color profile?
- if (cmsGetDeviceClass(hProfile) == icSigNamedColorClass) {
+ if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) {
-
- _cmsFree((void*) mem);
- return 0;
+ return 0;
}
}
else {
- // CRD are always implemented as LUT.
-
+ // CRD are always implemented as LUT
- if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) {
- _cmsFree((void*) mem);
- return 0;
- }
+ if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) {
+ return 0;
+ }
}
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
- Writef(mem, "%%%%EndResource\n");
- Writef(mem, "\n%% CRD End\n");
+ _cmsIOPrintf(mem, "%%%%EndResource\n");
+ _cmsIOPrintf(mem, "\n%% CRD End\n");
}
// Done, keep memory usage
- dwBytesUsed = mem ->dwUsed;
+ dwBytesUsed = mem ->UsedSpace;
+
+ // Finally, return used byte count
+ return dwBytesUsed;
+
+ cmsUNUSED_PARAMETER(ContextID);
+}
+
+
+
+
+cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID,
+ cmsPSResourceType Type,
+ cmsHPROFILE hProfile,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags,
+ cmsIOHANDLER* io)
+{
+ cmsUInt32Number rc;
+
+
+ switch (Type) {
+
+ case cmsPS_RESOURCE_CSA:
+ rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io);
+ break;
+ default:
+ case cmsPS_RESOURCE_CRD:
+ rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
+ break;
+ }
+
+ return rc;
+}
+
+
+
+cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID,
+ cmsHPROFILE hProfile,
+ cmsUInt32Number Intent, cmsUInt32Number dwFlags,
+ void* Buffer, cmsUInt32Number dwBufferLen)
+{
+ cmsIOHANDLER* mem;
+ cmsUInt32Number dwBytesUsed;
+
+ // Set up the serialization engine
+ if (Buffer == NULL)
+ mem = cmsOpenIOhandlerFromNULL(ContextID);
+ else
+ mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
+
+ if (!mem) return 0;
+
+ dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem);
// Get rid of memory stream
- _cmsFree((void*) mem);
+ cmsCloseIOhandler(mem);
- // Finally, return used byte count
return dwBytesUsed;
}
-// For compatibility with previous versions
+
+// Does create a Color Space Array on XYZ colorspace for PostScript usage
+cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID,
+ cmsHPROFILE hProfile,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags,
+ void* Buffer,
+ cmsUInt32Number dwBufferLen)
+{
+ cmsIOHANDLER* mem;
+ cmsUInt32Number dwBytesUsed;
-DWORD LCMSEXPORT cmsGetPostScriptCRD(cmsHPROFILE hProfile,
- int Intent,
- LPVOID Buffer, DWORD dwBufferLen)
-{
- return cmsGetPostScriptCRDEx(hProfile, Intent, 0, Buffer, dwBufferLen);
+ if (Buffer == NULL)
+ mem = cmsOpenIOhandlerFromNULL(ContextID);
+ else
+ mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
+
+ if (!mem) return 0;
+
+ dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem);
+
+ // Get rid of memory stream
+ cmsCloseIOhandler(mem);
+
+ return dwBytesUsed;
+
}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,650 +49,246 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-
-// ---------------------------------------------------------------------------------
-
-static volatile int GlobalBlackPreservationStrategy = 0;
-
-// Quantize a value 0 <= i < MaxSamples
-
-WORD _cmsQuantizeVal(double i, int MaxSamples)
-{
- double x;
-
- x = ((double) i * 65535.) / (double) (MaxSamples - 1);
+//
+//---------------------------------------------------------------------------------
+//
- return (WORD) floor(x + .5);
-}
-
-
-// Is a table linear?
-
-int cmsIsLinear(WORD Table[], int nEntries)
-{
- register int i;
- int diff;
-
- for (i=0; i < nEntries; i++) {
-
- diff = abs((int) Table[i] - (int) _cmsQuantizeVal(i, nEntries));
- if (diff > 3)
- return 0;
- }
-
- return 1;
-}
+#include "lcms2_internal.h"
-// pow() restricted to integer
-
-static
-int ipow(int base, int exp)
-{
- int res = base;
-
- while (--exp)
- res *= base;
-
- return res;
-}
-
+// This file contains routines for resampling and LUT optimization, black point detection
+// and black preservation.
-// Given n, 0<=n<=clut^dim, returns the colorant.
-
-static
-int ComponentOf(int n, int clut, int nColorant)
-{
- if (nColorant <= 0)
- return (n % clut);
-
- n /= ipow(clut, nColorant);
-
- return (n % clut);
-}
-
+// Black point detection -------------------------------------------------------------------------
-// This routine does a sweep on whole input space, and calls its callback
-// function on knots. returns TRUE if all ok, FALSE otherwise.
-
-LCMSBOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags)
+// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs
+static
+cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent)
{
- int i, t, nTotalPoints, Colorant, index;
- WORD In[MAXCHANNELS], Out[MAXCHANNELS];
-
- nTotalPoints = ipow(Lut->cLutPoints, Lut -> InputChan);
+ cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
+ cmsHTRANSFORM xform;
+ cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE };
+ cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 };
+ cmsHPROFILE hProfiles[4];
+ cmsUInt32Number Intents[4];
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
- index = 0;
- for (i = 0; i < nTotalPoints; i++) {
+ hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab;
+ Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC;
- for (t=0; t < (int) Lut -> InputChan; t++) {
+ xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents,
+ States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
+
+ cmsCloseProfile(hLab);
+ return xform;
+}
- Colorant = ComponentOf(i, Lut -> cLutPoints, (Lut -> InputChan - t - 1 ));
- In[t] = _cmsQuantizeVal(Colorant, Lut -> cLutPoints);
- }
+// Use darker colorants to obtain black point. This works in the relative colorimetric intent and
+// assumes more ink results in darker colors. No ink limit is assumed.
+static
+cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
+ cmsUInt32Number Intent,
+ cmsCIEXYZ* BlackPoint,
+ cmsUInt32Number dwFlags)
+{
+ cmsUInt16Number *Black;
+ cmsHTRANSFORM xform;
+ cmsColorSpaceSignature Space;
+ cmsUInt32Number nChannels;
+ cmsUInt32Number dwFormat;
+ cmsHPROFILE hLab;
+ cmsCIELab Lab;
+ cmsCIEXYZ BlackXYZ;
+ cmsContext ContextID = cmsGetProfileContextID(hInput);
+ // If the profile does not support input direction, assume Black point 0
+ if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) {
- if (dwFlags & SAMPLER_HASTL1) {
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
+ }
- for (t=0; t < (int) Lut -> InputChan; t++)
- In[t] = cmsReverseLinearInterpLUT16(In[t],
- Lut -> L1[t],
- &Lut -> In16params);
- }
+ // Create a formatter which has n channels and floating point
+ dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE);
+
+ // Try to get black by using black colorant
+ Space = cmsGetColorSpace(hInput);
+
+ // This function returns darker colorant in 16 bits for several spaces
+ if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) {
- for (t=0; t < (int) Lut -> OutputChan; t++)
- Out[t] = Lut->T[index + t];
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
+ }
+
+ if (nChannels != T_CHANNELS(dwFormat)) {
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
+ }
+
+ // Lab will be used as the output space, but lab2 will avoid recursion
+ hLab = cmsCreateLab2ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) {
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
+ }
- if (dwFlags & SAMPLER_HASTL2) {
+ // Create the transform
+ xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat,
+ hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
+ cmsCloseProfile(hLab);
- for (t=0; t < (int) Lut -> OutputChan; t++)
- Out[t] = cmsLinearInterpLUT16(Out[t],
- Lut -> L2[t],
- &Lut -> Out16params);
- }
+ if (xform == NULL) {
+ // Something went wrong. Get rid of open resources and return zero as black
+
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
+ }
+
+ // Convert black to Lab
+ cmsDoTransform(xform, Black, &Lab, 1);
+ // Force it to be neutral, clip to max. L* of 50
+ Lab.a = Lab.b = 0;
+ if (Lab.L > 50) Lab.L = 50;
- if (!Sampler(In, Out, Cargo))
- return FALSE;
+ // Free the resources
+ cmsDeleteTransform(xform);
- if (!(dwFlags & SAMPLER_INSPECT)) {
+ // Convert from Lab (which is now clipped) to XYZ.
+ cmsLab2XYZ(NULL, &BlackXYZ, &Lab);
- if (dwFlags & SAMPLER_HASTL2) {
+ if (BlackPoint != NULL)
+ *BlackPoint = BlackXYZ;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(dwFlags);
+}
- for (t=0; t < (int) Lut -> OutputChan; t++)
- Out[t] = cmsReverseLinearInterpLUT16(Out[t],
- Lut -> L2[t],
- &Lut -> Out16params);
- }
+// Get a black point of output CMYK profile, discounting any ink-limiting embedded
+// in the profile. For doing that, we use perceptual intent in input direction:
+// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab
+static
+cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile)
+{
+ cmsHTRANSFORM hRoundTrip;
+ cmsCIELab LabIn, LabOut;
+ cmsCIEXYZ BlackXYZ;
+
+ // Is the intent supported by the profile?
+ if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return TRUE;
+ }
- for (t=0; t < (int) Lut -> OutputChan; t++)
- Lut->T[index + t] = Out[t];
+ hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL);
+ if (hRoundTrip == NULL) {
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
+ }
+
+ LabIn.L = LabIn.a = LabIn.b = 0;
+ cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1);
- }
+ // Clip Lab to reasonable limits
+ if (LabOut.L > 50) LabOut.L = 50;
+ LabOut.a = LabOut.b = 0;
+
+ cmsDeleteTransform(hRoundTrip);
- index += Lut -> OutputChan;
+ // Convert it to XYZ
+ cmsLab2XYZ(NULL, &BlackXYZ, &LabOut);
- }
+ if (BlackPoint != NULL)
+ *BlackPoint = BlackXYZ;
return TRUE;
}
-
-
-
-
+// This function shouldn't exist at all -- there is such quantity of broken
+// profiles on black point tag, that we must somehow fix chromaticity to
+// avoid huge tint when doing Black point compensation. This function does
+// just that. There is a special flag for using black point tag, but turned
+// off by default because it is bogus on most profiles. The detection algorithm
+// involves to turn BP to neutral and to use only L component.
-// choose reasonable resolution
-int _cmsReasonableGridpointsByColorspace(icColorSpaceSignature Colorspace, DWORD dwFlags)
+cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
- int nChannels;
- // Already specified?
- if (dwFlags & 0x00FF0000) {
- // Yes, grab'em
- return (dwFlags >> 16) & 0xFF;
+ // Zero for black point
+ if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {
+
+ BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
+ return FALSE;
}
- nChannels = _cmsChannelsOf(Colorspace);
+ // v4 + perceptual & saturation intents does have its own black point, and it is
+ // well specified enough to use it. Black point tag is deprecated in V4.
- // HighResPrecalc is maximum resolution
-
- if (dwFlags & cmsFLAGS_HIGHRESPRECALC) {
+ if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) &&
+ (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {
- if (nChannels > 4)
- return 7; // 7 for Hifi
+ // Matrix shaper share MRC & perceptual intents
+ if (cmsIsMatrixShaper(hProfile))
+ return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0);
- if (nChannels == 4) // 23 for CMYK
- return 23;
+ // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents
+ BlackPoint -> X = cmsPERCEPTUAL_BLACK_X;
+ BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y;
+ BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z;
- return 49; // 49 for RGB and others
+ return TRUE;
}
- // LowResPrecal is stripped resolution
-
- if (dwFlags & cmsFLAGS_LOWRESPRECALC) {
-
- if (nChannels > 4)
- return 6; // 6 for Hifi
-
- if (nChannels == 1)
- return 33; // For monochrome
-
- return 17; // 17 for remaining
- }
-
- // Default values
-
- if (nChannels > 4)
- return 7; // 7 for Hifi
-
- if (nChannels == 4)
- return 17; // 17 for CMYK
-
- return 33; // 33 for RGB
-
-}
+#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG
-// Sampler implemented by another transform. This is a clean way to
-// precalculate the devicelink 3D CLUT for almost any transform
-
-static
-int XFormSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
-{
- cmsDoTransform((cmsHTRANSFORM) Cargo, In, Out, 1);
- return TRUE;
-}
-
-// This routine does compute the devicelink CLUT containing whole
-// transform. Handles any channel number.
-
-LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags)
-{
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) h;
- LPLUT Grid;
- int nGridPoints;
- DWORD dwFormatIn, dwFormatOut;
- DWORD SaveFormatIn, SaveFormatOut;
- int ChannelsIn, ChannelsOut;
- LPLUT SaveGamutLUT;
-
-
- // Remove any gamut checking
- SaveGamutLUT = p ->Gamut;
- p ->Gamut = NULL;
+ // v2, v4 rel/abs colorimetric
+ if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) &&
+ Intent == INTENT_RELATIVE_COLORIMETRIC) {
- ChannelsIn = _cmsChannelsOf(p -> EntryColorSpace);
- ChannelsOut = _cmsChannelsOf(p -> ExitColorSpace);
-
- nGridPoints = _cmsReasonableGridpointsByColorspace(p -> EntryColorSpace, dwFlags);
-
- Grid = cmsAllocLUT();
- if (!Grid) return NULL;
-
- Grid = cmsAlloc3DGrid(Grid, nGridPoints, ChannelsIn, ChannelsOut);
-
- // Compute device link on 16-bit basis
- dwFormatIn = (CHANNELS_SH(ChannelsIn)|BYTES_SH(2));
- dwFormatOut = (CHANNELS_SH(ChannelsOut)|BYTES_SH(2));
-
- SaveFormatIn = p ->InputFormat;
- SaveFormatOut = p ->OutputFormat;
-
- p -> InputFormat = dwFormatIn;
- p -> OutputFormat = dwFormatOut;
- p -> FromInput = _cmsIdentifyInputFormat(p, dwFormatIn);
- p -> ToOutput = _cmsIdentifyOutputFormat(p, dwFormatOut);
-
- // Fix gamut & gamma possible mismatches.
-
- if (!(dwFlags & cmsFLAGS_NOPRELINEARIZATION)) {
+ cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite;
+ cmsCIELab Lab;
- cmsHTRANSFORM hOne[1];
- hOne[0] = h;
-
- _cmsComputePrelinearizationTablesFromXFORM(hOne, 1, Grid);
- }
-
- // Attention to this typecast! we can take the luxury to
- // do this since cmsHTRANSFORM is only an alias to a pointer
- // to the transform struct.
-
- if (!cmsSample3DGrid(Grid, XFormSampler, (LPVOID) p, Grid -> wFlags)) {
+ // If black point is specified, then use it,
- cmsFreeLUT(Grid);
- Grid = NULL;
- }
-
- p ->Gamut = SaveGamutLUT;
- p ->InputFormat = SaveFormatIn;
- p ->OutputFormat = SaveFormatOut;
-
- return Grid;
-}
-
-
-
-// Sampler for Black-preserving CMYK->CMYK transforms
+ BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag);
+ if (BlackPtr != NULL) {
-typedef struct {
- cmsHTRANSFORM cmyk2cmyk;
- cmsHTRANSFORM cmyk2Lab;
- LPGAMMATABLE KTone;
- L16PARAMS KToneParams;
- LPLUT LabK2cmyk;
- double MaxError;
-
- cmsHTRANSFORM hRoundTrip;
- int MaxTAC;
-
- cmsHTRANSFORM hProofOutput;
-
- } BPCARGO, *LPBPCARGO;
-
-
-
-// Preserve black only if that is the only ink used
-static
-int BlackPreservingGrayOnlySampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
-{
- BPCARGO* bp = (LPBPCARGO) Cargo;
-
- // If going across black only, keep black only
- if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
+ BlackXYZ = *BlackPtr;
+ _cmsReadMediaWhitePoint(&MediaWhite, hProfile);
- // TAC does not apply because it is black ink!
- Out[0] = Out[1] = Out[2] = 0;
- Out[3] = cmsLinearInterpLUT16(In[3], bp->KTone ->GammaTable, &bp->KToneParams);
- return 1;
- }
-
- // Keep normal transform for other colors
- cmsDoTransform(bp ->cmyk2cmyk, In, Out, 1);
- return 1;
-}
-
-
-
-// Preserve all K plane.
-static
-int BlackPreservingSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
-{
-
- WORD LabK[4];
- double SumCMY, SumCMYK, Error;
- cmsCIELab ColorimetricLab, BlackPreservingLab;
- BPCARGO* bp = (LPBPCARGO) Cargo;
-
- // Get the K across Tone curve
- LabK[3] = cmsLinearInterpLUT16(In[3], bp->KTone ->GammaTable, &bp->KToneParams);
+ // Black point is absolute XYZ, so adapt to D50 to get PCS value
+ cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ);
- // If going across black only, keep black only
- if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
-
- Out[0] = Out[1] = Out[2] = 0;
- Out[3] = LabK[3];
- return 1;
- }
-
- // Try the original transform, maybe K is already ok (valid on K=0)
- cmsDoTransform(bp ->cmyk2cmyk, In, Out, 1);
- if (Out[3] == LabK[3]) return 1;
-
-
- // No, mesure and keep Lab measurement for further usage
- cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1);
-
- // Is not black only and the transform doesn't keep black.
- // Obtain the Lab of CMYK. After that we have Lab + K
- cmsDoTransform(bp ->cmyk2Lab, In, LabK, 1);
-
- // Obtain the corresponding CMY using reverse interpolation.
- // As a seed, we use the colorimetric CMY
- cmsEvalLUTreverse(bp ->LabK2cmyk, LabK, Out, Out);
+ // Force a=b=0 to get rid of any chroma
+ cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint);
+ Lab.a = Lab.b = 0;
+ if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50
+ cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab);
- // Estimate the error
- cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1);
- Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab);
-
-
- // Apply TAC if needed
-
- SumCMY = Out[0] + Out[1] + Out[2];
- SumCMYK = SumCMY + Out[3];
-
- if (SumCMYK > bp ->MaxTAC) {
+ if (BlackPoint != NULL)
+ *BlackPoint = TrustedBlackPoint;
- double Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY);
- if (Ratio < 0)
- Ratio = 0;
-
- Out[0] = (WORD) floor(Out[0] * Ratio + 0.5); // C
- Out[1] = (WORD) floor(Out[1] * Ratio + 0.5); // M
- Out[2] = (WORD) floor(Out[2] * Ratio + 0.5); // Y
+ return TRUE;
+ }
}
-
- return 1;
-}
-
-
-// Sample whole gamut to estimate maximum TAC
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4100)
#endif
-static
-int EstimateTAC(register WORD In[], register WORD Out[], register LPVOID Cargo)
-{
- BPCARGO* bp = (LPBPCARGO) Cargo;
- WORD RoundTrip[4];
- int Sum;
+ // That is about v2 profiles.
- cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1);
-
- Sum = RoundTrip[0] + RoundTrip[1] + RoundTrip[2] + RoundTrip[3];
+ // If output profile, discount ink-limiting and that's all
+ if (Intent == INTENT_RELATIVE_COLORIMETRIC &&
+ (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) &&
+ (cmsGetColorSpace(hProfile) == cmsSigCmykData))
+ return BlackPointUsingPerceptualBlack(BlackPoint, hProfile);
- if (Sum > bp ->MaxTAC)
- bp ->MaxTAC = Sum;
-
- return 1;
+ // Nope, compute BP using current intent.
+ return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);
}
-
-// Estimate the maximum error
-static
-int BlackPreservingEstimateErrorSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
-{
- BPCARGO* bp = (LPBPCARGO) Cargo;
- WORD ColorimetricOut[4];
- cmsCIELab ColorimetricLab, BlackPreservingLab;
- double Error;
-
- if (In[0] == 0 && In[1] == 0 && In[2] == 0) return 1;
-
- cmsDoTransform(bp->cmyk2cmyk, In, ColorimetricOut, 1);
-
- cmsDoTransform(bp->hProofOutput, ColorimetricOut, &ColorimetricLab, 1);
- cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1);
-
- Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab);
-
- if (Error > bp ->MaxError)
- bp ->MaxError = Error;
-
- return 1;
-}
-
-// Setup the K preservation strategy
-int LCMSEXPORT cmsSetCMYKPreservationStrategy(int n)
-{
- int OldVal = GlobalBlackPreservationStrategy;
-
- if (n >= 0)
- GlobalBlackPreservationStrategy = n;
-
- return OldVal;
-}
-
-#pragma warning(disable: 4550)
-
-// Get a pointer to callback on depending of strategy
-static
-_cmsSAMPLER _cmsGetBlackPreservationSampler(void)
-{
- switch (GlobalBlackPreservationStrategy) {
-
- case 0: return BlackPreservingGrayOnlySampler;
- default: return BlackPreservingSampler;
- }
-
-}
-
-// This is the black-preserving devicelink generator
-LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD dwFlags)
-{
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) hCMYK2CMYK;
- BPCARGO Cargo;
- LPLUT Grid;
- DWORD LocalFlags;
- cmsHPROFILE hLab = cmsCreateLabProfile(NULL);
- int nGridPoints;
- icTagSignature Device2PCS[] = {icSigAToB0Tag, // Perceptual
- icSigAToB1Tag, // Relative colorimetric
- icSigAToB2Tag, // Saturation
- icSigAToB1Tag }; // Absolute colorimetric
- // (Relative/WhitePoint)
-
- nGridPoints = _cmsReasonableGridpointsByColorspace(p -> EntryColorSpace, dwFlags);
-
- // Get a copy of inteserting flags for this kind of xform
- LocalFlags = cmsFLAGS_NOTPRECALC;
- if (p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION)
- LocalFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
-
- // Fill in cargo struct
- Cargo.cmyk2cmyk = hCMYK2CMYK;
-
- // Compute tone curve.
- Cargo.KTone = _cmsBuildKToneCurve(hCMYK2CMYK, 256);
- if (Cargo.KTone == NULL) return NULL;
- cmsCalcL16Params(Cargo.KTone ->nEntries, &Cargo.KToneParams);
-
-
- // Create a CMYK->Lab "normal" transform on input, without K-preservation
- Cargo.cmyk2Lab = cmsCreateTransform(p ->InputProfile, TYPE_CMYK_16,
- hLab, TYPE_Lab_16, p->Intent, LocalFlags);
-
- // We are going to use the reverse of proof direction
- Cargo.LabK2cmyk = cmsReadICCLut(p->OutputProfile, Device2PCS[p->Intent]);
-
- // Is there any table available?
- if (Cargo.LabK2cmyk == NULL) {
-
- Grid = NULL;
- goto Cleanup;
- }
-
- // Setup a roundtrip on output profile for TAC estimation
- Cargo.hRoundTrip = cmsCreateTransform(p ->OutputProfile, TYPE_CMYK_16,
- p ->OutputProfile, TYPE_CMYK_16, p->Intent, cmsFLAGS_NOTPRECALC);
-
-
- // Setup a proof CMYK->Lab on output
- Cargo.hProofOutput = cmsCreateTransform(p ->OutputProfile, TYPE_CMYK_16,
- hLab, TYPE_Lab_DBL, p->Intent, LocalFlags);
-
-
- // Create an empty LUT for holding K-preserving xform
- Grid = cmsAllocLUT();
- if (!Grid) goto Cleanup;
-
- Grid = cmsAlloc3DGrid(Grid, nGridPoints, 4, 4);
-
- // Setup formatters
- p -> FromInput = _cmsIdentifyInputFormat(p, TYPE_CMYK_16);
- p -> ToOutput = _cmsIdentifyOutputFormat(p, TYPE_CMYK_16);
-
-
-
- // Step #1, estimate TAC
- Cargo.MaxTAC = 0;
- if (!cmsSample3DGrid(Grid, EstimateTAC, (LPVOID) &Cargo, 0)) {
-
- cmsFreeLUT(Grid);
- Grid = NULL;
- goto Cleanup;
- }
-
-
- // Step #2, compute approximation
- if (!cmsSample3DGrid(Grid, _cmsGetBlackPreservationSampler(), (LPVOID) &Cargo, 0)) {
-
- cmsFreeLUT(Grid);
- Grid = NULL;
- goto Cleanup;
- }
-
- // Step #3, estimate error
- Cargo.MaxError = 0;
- cmsSample3DGrid(Grid, BlackPreservingEstimateErrorSampler, (LPVOID) &Cargo, SAMPLER_INSPECT);
-
-
-Cleanup:
-
- if (Cargo.cmyk2Lab) cmsDeleteTransform(Cargo.cmyk2Lab);
- if (Cargo.hRoundTrip) cmsDeleteTransform(Cargo.hRoundTrip);
- if (Cargo.hProofOutput) cmsDeleteTransform(Cargo.hProofOutput);
-
- if (hLab) cmsCloseProfile(hLab);
- if (Cargo.KTone) cmsFreeGamma(Cargo.KTone);
- if (Cargo.LabK2cmyk) cmsFreeLUT(Cargo.LabK2cmyk);
-
- return Grid;
-}
-
-
-
-// Fix broken LUT. just to obtain other CMS compatibility
-
-static
-void PatchLUT(LPLUT Grid, WORD At[], WORD Value[],
- int nChannelsOut, int nChannelsIn)
-{
- LPL16PARAMS p16 = &Grid -> CLut16params;
- double px, py, pz, pw;
- int x0, y0, z0, w0;
- int i, index;
-
-
- if (Grid ->wFlags & LUT_HASTL1) return; // There is a prelinearization
-
- px = ((double) At[0] * (p16->Domain)) / 65535.0;
- py = ((double) At[1] * (p16->Domain)) / 65535.0;
- pz = ((double) At[2] * (p16->Domain)) / 65535.0;
- pw = ((double) At[3] * (p16->Domain)) / 65535.0;
-
- x0 = (int) floor(px);
- y0 = (int) floor(py);
- z0 = (int) floor(pz);
- w0 = (int) floor(pw);
-
- if (nChannelsIn == 4) {
-
- if (((px - x0) != 0) ||
- ((py - y0) != 0) ||
- ((pz - z0) != 0) ||
- ((pw - w0) != 0)) return; // Not on exact node
-
- index = p16 -> opta4 * x0 +
- p16 -> opta3 * y0 +
- p16 -> opta2 * z0 +
- p16 -> opta1 * w0;
- }
- else
- if (nChannelsIn == 3) {
-
- if (((px - x0) != 0) ||
- ((py - y0) != 0) ||
- ((pz - z0) != 0)) return; // Not on exact node
-
- index = p16 -> opta3 * x0 +
- p16 -> opta2 * y0 +
- p16 -> opta1 * z0;
- }
- else
- if (nChannelsIn == 1) {
-
- if (((px - x0) != 0)) return; // Not on exact node
-
- index = p16 -> opta1 * x0;
- }
- else {
- cmsSignalError(LCMS_ERRC_ABORTED, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn);
- return;
- }
-
- for (i=0; i < nChannelsOut; i++)
- Grid -> T[index + i] = Value[i];
-
-}
-
-
-
-LCMSBOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p)
-{
-
- WORD *WhitePointIn, *WhitePointOut, *BlackPointIn, *BlackPointOut;
- int nOuts, nIns;
-
-
- if (!p -> DeviceLink) return FALSE;
-
- if (p ->Intent == INTENT_ABSOLUTE_COLORIMETRIC) return FALSE;
- if ((p ->PreviewProfile != NULL) &&
- (p ->ProofIntent == INTENT_ABSOLUTE_COLORIMETRIC)) return FALSE;
-
-
- if (!_cmsEndPointsBySpace(p -> EntryColorSpace,
- &WhitePointIn, &BlackPointIn, &nIns)) return FALSE;
-
-
- if (!_cmsEndPointsBySpace(p -> ExitColorSpace,
- &WhitePointOut, &BlackPointOut, &nOuts)) return FALSE;
-
- // Fix white only
-
- PatchLUT(p -> DeviceLink, WhitePointIn, WhitePointOut, nOuts, nIns);
- // PatchLUT(p -> DeviceLink, BlackPointIn, BlackPointOut, nOuts, nIns);
-
- return TRUE;
-}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,762 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+
+// ------------------------------------------------------------------------
+
+// Gamut boundary description by using Jan Morovic's Segment maxima method
+// Many thanks to Jan for allowing me to use his algorithm.
+
+// r = C*
+// alpha = Hab
+// theta = L*
+
+#define SECTORS 16 // number of divisions in alpha and theta
+
+// Spherical coordinates
+typedef struct {
+
+ cmsFloat64Number r;
+ cmsFloat64Number alpha;
+ cmsFloat64Number theta;
+
+} cmsSpherical;
+
+typedef enum {
+ GP_EMPTY,
+ GP_SPECIFIED,
+ GP_MODELED
+
+ } GDBPointType;
+
+
+typedef struct {
+
+ GDBPointType Type;
+ cmsSpherical p; // Keep also alpha & theta of maximum
+
+} cmsGDBPoint;
+
+
+typedef struct {
+
+ cmsContext ContextID;
+ cmsGDBPoint Gamut[SECTORS][SECTORS];
+
+} cmsGDB;
+
+
+// A line using the parametric form
+// P = a + t*u
+typedef struct {
+
+ cmsVEC3 a;
+ cmsVEC3 u;
+
+} cmsLine;
+
+
+// A plane using the parametric form
+// Q = b + r*v + s*w
+typedef struct {
+
+ cmsVEC3 b;
+ cmsVEC3 v;
+ cmsVEC3 w;
+
+} cmsPlane;
+
+
+
+// --------------------------------------------------------------------------------------------
+
+// ATAN2() which always returns degree positive numbers
+
+static
+cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x)
+{
+ cmsFloat64Number a;
+
+ // Deal with undefined case
+ if (x == 0.0 && y == 0.0) return 0;
+
+ a = (atan2(y, x) * 180.0) / M_PI;
+
+ while (a < 0) {
+ a += 360;
+ }
+
+ return a;
+}
+
+// Convert to spherical coordinates
+static
+void ToSpherical(cmsSpherical* sp, const cmsVEC3* v)
+{
+
+ cmsFloat64Number L, a, b;
+
+ L = v ->n[VX];
+ a = v ->n[VY];
+ b = v ->n[VZ];
+
+ sp ->r = sqrt( L*L + a*a + b*b );
+
+ if (sp ->r == 0) {
+ sp ->alpha = sp ->theta = 0;
+ return;
+ }
+
+ sp ->alpha = _cmsAtan2(a, b);
+ sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L);
+}
+
+
+// Convert to cartesian from spherical
+static
+void ToCartesian(cmsVEC3* v, const cmsSpherical* sp)
+{
+ cmsFloat64Number sin_alpha;
+ cmsFloat64Number cos_alpha;
+ cmsFloat64Number sin_theta;
+ cmsFloat64Number cos_theta;
+ cmsFloat64Number L, a, b;
+
+ sin_alpha = sin((M_PI * sp ->alpha) / 180.0);
+ cos_alpha = cos((M_PI * sp ->alpha) / 180.0);
+ sin_theta = sin((M_PI * sp ->theta) / 180.0);
+ cos_theta = cos((M_PI * sp ->theta) / 180.0);
+
+ a = sp ->r * sin_theta * sin_alpha;
+ b = sp ->r * sin_theta * cos_alpha;
+ L = sp ->r * cos_theta;
+
+ v ->n[VX] = L;
+ v ->n[VY] = a;
+ v ->n[VZ] = b;
+}
+
+
+// Quantize sector of a spherical coordinate. Saturate 360, 180 to last sector
+// The limits are the centers of each sector, so
+static
+void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta)
+{
+ *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) );
+ *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) );
+
+ if (*alpha >= SECTORS)
+ *alpha = SECTORS-1;
+ if (*theta >= SECTORS)
+ *theta = SECTORS-1;
+}
+
+
+// Line determined by 2 points
+static
+void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b)
+{
+
+ _cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]);
+ _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX],
+ b ->n[VY] - a ->n[VY],
+ b ->n[VZ] - a ->n[VZ]);
+}
+
+
+// Evaluate parametric line
+static
+void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t)
+{
+ p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX];
+ p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY];
+ p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ];
+}
+
+
+
+/*
+ Closest point in sector line1 to sector line2 (both are defined as 0 <=t <= 1)
+ http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
+
+ Copyright 2001, softSurfer (www.softsurfer.com)
+ This code may be freely used and modified for any purpose
+ providing that this copyright notice is included with it.
+ SoftSurfer makes no warranty for this code, and cannot be held
+ liable for any real or imagined damage resulting from its use.
+ Users of this code must verify correctness for their application.
+
+*/
+
+static
+cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2)
+{
+ cmsFloat64Number a, b, c, d, e, D;
+ cmsFloat64Number sc, sN, sD;
+ cmsFloat64Number tc, tN, tD;
+ cmsVEC3 w0;
+
+ _cmsVEC3minus(&w0, &line1 ->a, &line2 ->a);
+
+ a = _cmsVEC3dot(&line1 ->u, &line1 ->u);
+ b = _cmsVEC3dot(&line1 ->u, &line2 ->u);
+ c = _cmsVEC3dot(&line2 ->u, &line2 ->u);
+ d = _cmsVEC3dot(&line1 ->u, &w0);
+ e = _cmsVEC3dot(&line2 ->u, &w0);
+
+ D = a*c - b * b; // Denominator
+ sD = tD = D; // default sD = D >= 0
+
+ if (D < MATRIX_DET_TOLERANCE) { // the lines are almost parallel
+
+ sN = 0.0; // force using point P0 on segment S1
+ sD = 1.0; // to prevent possible division by 0.0 later
+ tN = e;
+ tD = c;
+ }
+ else { // get the closest points on the infinite lines
+
+ sN = (b*e - c*d);
+ tN = (a*e - b*d);
+
+ if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
+
+ sN = 0.0;
+ tN = e;
+ tD = c;
+ }
+ else if (sN > sD) { // sc > 1 => the s=1 edge is visible
+ sN = sD;
+ tN = e + b;
+ tD = c;
+ }
+ }
+
+ if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
+
+ tN = 0.0;
+ // recompute sc for this edge
+ if (-d < 0.0)
+ sN = 0.0;
+ else if (-d > a)
+ sN = sD;
+ else {
+ sN = -d;
+ sD = a;
+ }
+ }
+ else if (tN > tD) { // tc > 1 => the t=1 edge is visible
+
+ tN = tD;
+
+ // recompute sc for this edge
+ if ((-d + b) < 0.0)
+ sN = 0;
+ else if ((-d + b) > a)
+ sN = sD;
+ else {
+ sN = (-d + b);
+ sD = a;
+ }
+ }
+ // finally do the division to get sc and tc
+ sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD);
+ tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD);
+
+ GetPointOfLine(r, line1, sc);
+ return TRUE;
+}
+
+
+
+// ------------------------------------------------------------------ Wrapper
+
+
+// Allocate & free structure
+cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID)
+{
+ cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB));
+ if (gbd == NULL) return NULL;
+
+ gbd -> ContextID = ContextID;
+
+ return (cmsHANDLE) gbd;
+}
+
+
+void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD)
+{
+ cmsGDB* gbd = (cmsGDB*) hGBD;
+ if (hGBD != NULL)
+ _cmsFree(gbd->ContextID, (void*) gbd);
+}
+
+
+// Auxiliar to retrieve a pointer to the segmentr containing the Lab value
+static
+cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp)
+{
+ cmsVEC3 v;
+ int alpha, theta;
+
+ // Housekeeping
+ _cmsAssert(gbd != NULL);
+ _cmsAssert(Lab != NULL);
+ _cmsAssert(sp != NULL);
+
+ // Center L* by substracting half of its domain, that's 50
+ _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b);
+
+ // Convert to spherical coordinates
+ ToSpherical(sp, &v);
+
+ if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) {
+ cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range");
+ return NULL;
+ }
+
+ // On which sector it falls?
+ QuantizeToSector(sp, &alpha, &theta);
+
+ if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) {
+ cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range");
+ return NULL;
+ }
+
+ // Get pointer to the sector
+ return &gbd ->Gamut[theta][alpha];
+}
+
+// Add a point to gamut descriptor. Point to add is in Lab color space.
+// GBD is centered on a=b=0 and L*=50
+cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
+{
+ cmsGDB* gbd = (cmsGDB*) hGBD;
+ cmsGDBPoint* ptr;
+ cmsSpherical sp;
+
+
+ // Get pointer to the sector
+ ptr = GetPoint(gbd, Lab, &sp);
+ if (ptr == NULL) return FALSE;
+
+ // If no samples at this sector, add it
+ if (ptr ->Type == GP_EMPTY) {
+
+ ptr -> Type = GP_SPECIFIED;
+ ptr -> p = sp;
+ }
+ else {
+
+
+ // Substitute only if radius is greater
+ if (sp.r > ptr -> p.r) {
+
+ ptr -> Type = GP_SPECIFIED;
+ ptr -> p = sp;
+ }
+ }
+
+ return TRUE;
+}
+
+// Check if a given point falls inside gamut
+cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
+{
+ cmsGDB* gbd = (cmsGDB*) hGBD;
+ cmsGDBPoint* ptr;
+ cmsSpherical sp;
+
+ // Get pointer to the sector
+ ptr = GetPoint(gbd, Lab, &sp);
+ if (ptr == NULL) return FALSE;
+
+ // If no samples at this sector, return no data
+ if (ptr ->Type == GP_EMPTY) return FALSE;
+
+ // In gamut only if radius is greater
+
+ return (sp.r <= ptr -> p.r);
+}
+
+// -----------------------------------------------------------------------------------------------------------------------
+
+// Find near sectors. The list of sectors found is returned on Close[].
+// The function returns the number of sectors as well.
+
+// 24 9 10 11 12
+// 23 8 1 2 13
+// 22 7 * 3 14
+// 21 6 5 4 15
+// 20 19 18 17 16
+//
+// Those are the relative movements
+// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
+// {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1},
+// {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0},
+// {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1},
+// {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}};
+
+
+static
+const struct _spiral {
+
+ int AdvX, AdvY;
+
+ } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1},
+ {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
+ {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2},
+ {-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} };
+
+#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral))
+
+static
+int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[])
+{
+ int nSectors = 0;
+ int i, a, t;
+ cmsGDBPoint* pt;
+
+ for (i=0; i < NSTEPS; i++) {
+
+ a = alpha + Spiral[i].AdvX;
+ t = theta + Spiral[i].AdvY;
+
+ // Cycle at the end
+ a %= SECTORS;
+ t %= SECTORS;
+
+ // Cycle at the begin
+ if (a < 0) a = SECTORS + a;
+ if (t < 0) t = SECTORS + t;
+
+ pt = &gbd ->Gamut[t][a];
+
+ if (pt -> Type != GP_EMPTY) {
+
+ Close[nSectors++] = pt;
+ }
+ }
+
+ return nSectors;
+}
+
+
+// Interpolate a missing sector. Method identifies whatever this is top, bottom or mid
+static
+cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta)
+{
+ cmsSpherical sp;
+ cmsVEC3 Lab;
+ cmsVEC3 Centre;
+ cmsLine ray;
+ int nCloseSectors;
+ cmsGDBPoint* Close[NSTEPS];
+ cmsSpherical closel, templ;
+ cmsLine edge;
+ int k, m;
+
+ // Is that point already specified?
+ if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE;
+
+ // Fill close points
+ nCloseSectors = FindNearSectors(gbd, alpha, theta, Close);
+
+
+ // Find a central point on the sector
+ sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS);
+ sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS);
+ sp.r = 50.0;
+
+ // Convert to Cartesian
+ ToCartesian(&Lab, &sp);
+
+ // Create a ray line from centre to this point
+ _cmsVEC3init(&Centre, 50.0, 0, 0);
+ LineOf2Points(&ray, &Lab, &Centre);
+
+ // For all close sectors
+ closel.r = 0.0;
+ closel.alpha = 0;
+ closel.theta = 0;
+
+ for (k=0; k < nCloseSectors; k++) {
+
+ for(m = k+1; m < nCloseSectors; m++) {
+
+ cmsVEC3 temp, a1, a2;
+
+ // A line from sector to sector
+ ToCartesian(&a1, &Close[k]->p);
+ ToCartesian(&a2, &Close[m]->p);
+
+ LineOf2Points(&edge, &a1, &a2);
+
+ // Find a line
+ ClosestLineToLine(&temp, &ray, &edge);
+
+ // Convert to spherical
+ ToSpherical(&templ, &temp);
+
+
+ if ( templ.r > closel.r &&
+ templ.theta >= (theta*180.0/SECTORS) &&
+ templ.theta <= ((theta+1)*180.0/SECTORS) &&
+ templ.alpha >= (alpha*360.0/SECTORS) &&
+ templ.alpha <= ((alpha+1)*360.0/SECTORS)) {
+
+ closel = templ;
+ }
+ }
+ }
+
+ gbd ->Gamut[theta][alpha].p = closel;
+ gbd ->Gamut[theta][alpha].Type = GP_MODELED;
+
+ return TRUE;
+
+}
+
+
+// Interpolate missing parts. The algorithm fist computes slices at
+// theta=0 and theta=Max.
+cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags)
+{
+ int alpha, theta;
+ cmsGDB* gbd = (cmsGDB*) hGBD;
+
+ _cmsAssert(hGBD != NULL);
+
+ // Interpolate black
+ for (alpha = 0; alpha <= SECTORS; alpha++) {
+
+ if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE;
+ }
+
+ // Interpolate white
+ for (alpha = 0; alpha <= SECTORS; alpha++) {
+
+ if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE;
+ }
+
+
+ // Interpolate Mid
+ for (theta = 1; theta < SECTORS; theta++) {
+ for (alpha = 0; alpha <= SECTORS; alpha++) {
+
+ if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE;
+ }
+ }
+
+ // Done
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(dwFlags);
+}
+
+
+
+
+// --------------------------------------------------------------------------------------------------------
+
+// Great for debug, but not suitable for real use
+
+#if 0
+cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname)
+{
+ FILE* fp;
+ int i, j;
+ cmsGDB* gbd = (cmsGDB*) hGBD;
+ cmsGDBPoint* pt;
+
+ fp = fopen (fname, "wt");
+ if (fp == NULL)
+ return FALSE;
+
+ fprintf (fp, "#VRML V2.0 utf8\n");
+
+ // set the viewing orientation and distance
+ fprintf (fp, "DEF CamTest Group {\n");
+ fprintf (fp, "\tchildren [\n");
+ fprintf (fp, "\t\tDEF Cameras Group {\n");
+ fprintf (fp, "\t\t\tchildren [\n");
+ fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n");
+ fprintf (fp, "\t\t\t\t\tposition 0 0 340\n");
+ fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n");
+ fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n");
+ fprintf (fp, "\t\t\t\t}\n");
+ fprintf (fp, "\t\t\t]\n");
+ fprintf (fp, "\t\t},\n");
+ fprintf (fp, "\t]\n");
+ fprintf (fp, "}\n");
+
+ // Output the background stuff
+ fprintf (fp, "Background {\n");
+ fprintf (fp, "\tskyColor [\n");
+ fprintf (fp, "\t\t.5 .5 .5\n");
+ fprintf (fp, "\t]\n");
+ fprintf (fp, "}\n");
+
+ // Output the shape stuff
+ fprintf (fp, "Transform {\n");
+ fprintf (fp, "\tscale .3 .3 .3\n");
+ fprintf (fp, "\tchildren [\n");
+
+ // Draw the axes as a shape:
+ fprintf (fp, "\t\tShape {\n");
+ fprintf (fp, "\t\t\tappearance Appearance {\n");
+ fprintf (fp, "\t\t\t\tmaterial Material {\n");
+ fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
+ fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n");
+ fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
+ fprintf (fp, "\t\t\t\t}\n");
+ fprintf (fp, "\t\t\t}\n");
+ fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n");
+ fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
+ fprintf (fp, "\t\t\t\t\tpoint [\n");
+ fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n");
+ fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0);
+ fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0);
+ fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0);
+ fprintf (fp, "\t\t\t\t}\n");
+ fprintf (fp, "\t\t\t\tcoordIndex [\n");
+ fprintf (fp, "\t\t\t\t\t0, 1, -1\n");
+ fprintf (fp, "\t\t\t\t\t0, 2, -1\n");
+ fprintf (fp, "\t\t\t\t\t0, 3, -1]\n");
+ fprintf (fp, "\t\t\t}\n");
+ fprintf (fp, "\t\t}\n");
+
+
+ fprintf (fp, "\t\tShape {\n");
+ fprintf (fp, "\t\t\tappearance Appearance {\n");
+ fprintf (fp, "\t\t\t\tmaterial Material {\n");
+ fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
+ fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n");
+ fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
+ fprintf (fp, "\t\t\t\t}\n");
+ fprintf (fp, "\t\t\t}\n");
+ fprintf (fp, "\t\t\tgeometry PointSet {\n");
+
+ // fill in the points here
+ fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
+ fprintf (fp, "\t\t\t\t\tpoint [\n");
+
+ // We need to transverse all gamut hull.
+ for (i=0; i < SECTORS; i++)
+ for (j=0; j < SECTORS; j++) {
+
+ cmsVEC3 v;
+
+ pt = &gbd ->Gamut[i][j];
+ ToCartesian(&v, &pt ->p);
+
+ fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]);
+
+ if ((j == SECTORS - 1) && (i == SECTORS - 1))
+ fprintf (fp, "]\n");
+ else
+ fprintf (fp, ",\n");
+
+ }
+
+ fprintf (fp, "\t\t\t\t}\n");
+
+
+
+ // fill in the face colors
+ fprintf (fp, "\t\t\t\tcolor Color {\n");
+ fprintf (fp, "\t\t\t\t\tcolor [\n");
+
+ for (i=0; i < SECTORS; i++)
+ for (j=0; j < SECTORS; j++) {
+
+ cmsVEC3 v;
+
+ pt = &gbd ->Gamut[i][j];
+
+
+ ToCartesian(&v, &pt ->p);
+
+
+ if (pt ->Type == GP_EMPTY)
+ fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0);
+ else
+ if (pt ->Type == GP_MODELED)
+ fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5);
+ else {
+ fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0);
+
+ }
+
+ if ((j == SECTORS - 1) && (i == SECTORS - 1))
+ fprintf (fp, "]\n");
+ else
+ fprintf (fp, ",\n");
+ }
+ fprintf (fp, "\t\t\t}\n");
+
+
+ fprintf (fp, "\t\t\t}\n");
+ fprintf (fp, "\t\t}\n");
+ fprintf (fp, "\t]\n");
+ fprintf (fp, "}\n");
+
+ fclose (fp);
+
+ return TRUE;
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,4863 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+// Tag Serialization -----------------------------------------------------------------------------
+// This file implements every single tag and tag type as described in the ICC spec. Some types
+// have been deprecated, like ncl and Data. There is no implementation for those types as there
+// are no profiles holding them. The programmer can also extend this list by defining his own types
+// by using the appropiate plug-in. There are three types of plug ins regarding that. First type
+// allows to define new tags using any existing type. Next plug-in type allows to define new types
+// and the third one is very specific: allows to extend the number of elements in the multiprofile
+// elements special type.
+//--------------------------------------------------------------------------------------------------
+
+// Some broken types
+#define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8)
+#define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00)
+
+// This is the linked list that keeps track of the defined types
+typedef struct _cmsTagTypeLinkedList_st {
+
+ cmsTagTypeHandler Handler;
+ struct _cmsTagTypeLinkedList_st* Next;
+
+} _cmsTagTypeLinkedList;
+
+// Some macros to define callbacks.
+#define READ_FN(x) Type_##x##_Read
+#define WRITE_FN(x) Type_##x##_Write
+#define FREE_FN(x) Type_##x##_Free
+#define DUP_FN(x) Type_##x##_Dup
+
+// Helper macro to define a handler. Callbacks do have a fixed naming convention.
+#define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x) }
+
+// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
+#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree }
+
+// Register a new type handler. This routine is shared between normal types and MPE
+static
+cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
+{
+ cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
+ _cmsTagTypeLinkedList *pt, *Anterior = NULL;
+
+ // Calling the function with NULL as plug-in would unregister the plug in.
+ if (Data == NULL) {
+
+ LinkedList[DefaultListCount-1].Next = NULL;
+ return TRUE;
+ }
+
+ pt = Anterior = LinkedList;
+ while (pt != NULL) {
+
+ if (Plugin->Handler.Signature == pt -> Handler.Signature) {
+ pt ->Handler = Plugin ->Handler; // Replace old behaviour.
+ // Note that since no memory is allocated, unregister does not
+ // reset this action.
+ return TRUE;
+ }
+
+ Anterior = pt;
+ pt = pt ->Next;
+ }
+
+ // Registering happens in plug-in memory pool
+ pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagTypeLinkedList));
+ if (pt == NULL) return FALSE;
+
+ pt ->Handler = Plugin ->Handler;
+ pt ->Next = NULL;
+
+ if (Anterior)
+ Anterior -> Next = pt;
+
+ return TRUE;
+}
+
+// Return handler for a given type or NULL if not found. Shared between normal types and MPE
+static
+cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList)
+{
+ _cmsTagTypeLinkedList* pt;
+
+ for (pt = LinkedList;
+ pt != NULL;
+ pt = pt ->Next) {
+
+ if (sig == pt -> Handler.Signature) return &pt ->Handler;
+ }
+
+ return NULL;
+}
+
+
+// Auxiliar to convert UTF-32 to UTF-16 in some cases
+static
+cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
+{
+ cmsUInt32Number i;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(Array != NULL);
+
+ for (i=0; i < n; i++) {
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// To deal with position tables
+typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Cargo,
+ cmsUInt32Number n,
+ cmsUInt32Number SizeOfTag);
+
+// Helper function to deal with position tables as decribed in several addendums to ICC spec 4.2
+// A table of n elements is written, where first comes n records containing offsets and sizes and
+// then a block containing the data itself. This allows to reuse same data in more than one entry
+static
+cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ cmsUInt32Number Count,
+ cmsUInt32Number BaseOffset,
+ void *Cargo,
+ PositionTableEntryFn ElementFn)
+{
+ cmsUInt32Number i;
+ cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
+
+ // Let's take the offsets to each element
+ ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
+ if (ElementOffsets == NULL) goto Error;
+
+ ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
+ if (ElementSizes == NULL) goto Error;
+
+ for (i=0; i < Count; i++) {
+
+ if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error;
+ if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error;
+
+ ElementOffsets[i] += BaseOffset;
+ }
+
+ // Seek to each element and read it
+ for (i=0; i < Count; i++) {
+
+ if (!io -> Seek(io, ElementOffsets[i])) goto Error;
+
+ // This is the reader callback
+ if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error;
+ }
+
+ // Success
+ if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
+ if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
+ return TRUE;
+
+Error:
+ if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
+ if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
+ return FALSE;
+}
+
+// Same as anterior, but for write position tables
+static
+cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ cmsUInt32Number SizeOfTag,
+ cmsUInt32Number Count,
+ cmsUInt32Number BaseOffset,
+ void *Cargo,
+ PositionTableEntryFn ElementFn)
+{
+ cmsUInt32Number i;
+ cmsUInt32Number DirectoryPos, CurrentPos, Before;
+ cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
+
+ // Create table
+ ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
+ if (ElementOffsets == NULL) goto Error;
+
+ ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
+ if (ElementSizes == NULL) goto Error;
+
+ // Keep starting position of curve offsets
+ DirectoryPos = io ->Tell(io);
+
+ // Write a fake directory to be filled latter on
+ for (i=0; i < Count; i++) {
+
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
+ }
+
+ // Write each element. Keep track of the size as well.
+ for (i=0; i < Count; i++) {
+
+ Before = io ->Tell(io);
+ ElementOffsets[i] = Before - BaseOffset;
+
+ // Callback to write...
+ if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error;
+
+ // Now the size
+ ElementSizes[i] = io ->Tell(io) - Before;
+ }
+
+ // Write the directory
+ CurrentPos = io ->Tell(io);
+ if (!io ->Seek(io, DirectoryPos)) goto Error;
+
+ for (i=0; i < Count; i++) {
+ if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
+ if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
+ }
+
+ if (!io ->Seek(io, CurrentPos)) goto Error;
+
+ if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
+ if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
+ return TRUE;
+
+Error:
+ if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
+ if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
+ return FALSE;
+}
+
+
+// ********************************************************************************
+// Type XYZ. Only one value is allowed
+// ********************************************************************************
+
+//The XYZType contains an array of three encoded values for the XYZ tristimulus
+//values. Tristimulus values must be non-negative. The signed encoding allows for
+//implementation optimizations by minimizing the number of fixed formats.
+
+
+static
+void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsCIEXYZ* xyz;
+
+ *nItems = 0;
+ xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
+ if (xyz == NULL) return NULL;
+
+ if (!_cmsReadXYZNumber(io, xyz)) {
+ _cmsFree(self ->ContextID, xyz);
+ return NULL;
+ }
+
+ *nItems = 1;
+ return (void*) xyz;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+static
+void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+
+static
+cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
+{
+ return cmsSigXYZType;
+
+ cmsUNUSED_PARAMETER(ICCVersion);
+ cmsUNUSED_PARAMETER(Data);
+}
+
+
+// ********************************************************************************
+// Type chromaticity. Only one value is allowed
+// ********************************************************************************
+// The chromaticity tag type provides basic chromaticity data and type of
+// phosphors or colorants of a monitor to applications and utilities.
+
+static
+void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsCIExyYTRIPLE* chrm;
+ cmsUInt16Number nChans, Table;
+
+ *nItems = 0;
+ chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
+ if (chrm == NULL) return NULL;
+
+ if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
+
+ // Let's recover from a bug introduced in early versions of lcms1
+ if (nChans == 0 && SizeOfTag == 32) {
+
+ if (!_cmsReadUInt16Number(io, NULL)) goto Error;
+ if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
+ }
+
+ if (nChans != 3) goto Error;
+
+ if (!_cmsReadUInt16Number(io, &Table)) goto Error;
+
+ if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
+
+ chrm ->Red.Y = 1.0;
+
+ if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
+
+ chrm ->Green.Y = 1.0;
+
+ if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
+
+ chrm ->Blue.Y = 1.0;
+
+ *nItems = 1;
+ return (void*) chrm;
+
+Error:
+ _cmsFree(self ->ContextID, (void*) chrm);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
+{
+ if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
+ if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
+
+ return TRUE;
+}
+
+static
+cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
+
+ if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
+ if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
+
+ if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
+ if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
+ if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
+ cmsUNUSED_PARAMETER(n);
+}
+
+static
+void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+
+// ********************************************************************************
+// Type cmsSigColorantOrderType
+// ********************************************************************************
+
+// This is an optional tag which specifies the laydown order in which colorants will
+// be printed on an n-colorant device. The laydown order may be the same as the
+// channel generation order listed in the colorantTableTag or the channel order of a
+// colour space such as CMYK, in which case this tag is not needed. When this is not
+// the case (for example, ink-towers sometimes use the order KCMY), this tag may be
+// used to specify the laydown order of the colorants.
+
+
+static
+void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt8Number* ColorantOrder;
+ cmsUInt32Number Count;
+
+ *nItems = 0;
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+ if (Count > cmsMAXCHANNELS) return NULL;
+
+ ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
+ if (ColorantOrder == NULL) return NULL;
+
+ // We use FF as end marker
+ memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
+
+ if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
+
+ _cmsFree(self ->ContextID, (void*) ColorantOrder);
+ return NULL;
+ }
+
+ *nItems = 1;
+ return (void*) ColorantOrder;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
+ cmsUInt32Number i, sz, Count;
+
+ // Get the length
+ for (Count=i=0; i < cmsMAXCHANNELS; i++) {
+ if (ColorantOrder[i] != 0xFF) Count++;
+ }
+
+ if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
+
+ sz = Count * sizeof(cmsUInt8Number);
+ if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+
+static
+void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type cmsSigS15Fixed16ArrayType
+// ********************************************************************************
+// This type represents an array of generic 4-byte/32-bit fixed point quantity.
+// The number of values is determined from the size of the tag.
+
+static
+void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsFloat64Number* array_double;
+ cmsUInt32Number i, n;
+
+ *nItems = 0;
+ n = SizeOfTag / sizeof(cmsUInt32Number);
+ array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
+ if (array_double == NULL) return NULL;
+
+ for (i=0; i < n; i++) {
+
+ if (!_cmsRead15Fixed16Number(io, &array_double[i])) {
+
+ _cmsFree(self ->ContextID, array_double);
+ return NULL;
+ }
+ }
+
+ *nItems = n;
+ return (void*) array_double;
+}
+
+static
+cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
+ cmsUInt32Number i;
+
+ for (i=0; i < nItems; i++) {
+
+ if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
+}
+
+
+static
+void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type cmsSigU16Fixed16ArrayType
+// ********************************************************************************
+// This type represents an array of generic 4-byte/32-bit quantity.
+// The number of values is determined from the size of the tag.
+
+
+static
+void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsFloat64Number* array_double;
+ cmsUInt32Number v;
+ cmsUInt32Number i, n;
+
+ *nItems = 0;
+ n = SizeOfTag / sizeof(cmsUInt32Number);
+ array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
+ if (array_double == NULL) return NULL;
+
+ for (i=0; i < n; i++) {
+
+ if (!_cmsReadUInt32Number(io, &v)) {
+ _cmsFree(self ->ContextID, (void*) array_double);
+ return NULL;
+ }
+
+ // Convert to cmsFloat64Number
+ array_double[i] = (cmsFloat64Number) (v / 65536.0);
+ }
+
+ *nItems = n;
+ return (void*) array_double;
+}
+
+static
+cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
+ cmsUInt32Number i;
+
+ for (i=0; i < nItems; i++) {
+
+ cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
+
+ if (!_cmsWriteUInt32Number(io, v)) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
+}
+
+static
+void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type cmsSigSignatureType
+// ********************************************************************************
+//
+// The signatureType contains a four-byte sequence, Sequences of less than four
+// characters are padded at the end with spaces, 20h.
+// Typically this type is used for registered tags that can be displayed on many
+// development systems as a sequence of four characters.
+
+static
+void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
+ if (SigPtr == NULL) return NULL;
+
+ if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
+ *nItems = 1;
+
+ return SigPtr;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsSignature* SigPtr = (cmsSignature*) Ptr;
+
+ return _cmsWriteUInt32Number(io, *SigPtr);
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
+}
+
+static
+void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+
+// ********************************************************************************
+// Type cmsSigTextType
+// ********************************************************************************
+//
+// The textType is a simple text structure that contains a 7-bit ASCII text string.
+// The length of the string is obtained by subtracting 8 from the element size portion
+// of the tag itself. This string must be terminated with a 00h byte.
+
+static
+void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ char* Text = NULL;
+ cmsMLU* mlu = NULL;
+
+ // Create a container
+ mlu = cmsMLUalloc(self ->ContextID, 1);
+ if (mlu == NULL) return NULL;
+
+ *nItems = 0;
+
+ // We need to store the "\0" at the end, so +1
+ Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
+ if (Text == NULL) goto Error;
+
+ if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error;
+
+ // Make sure text is properly ended
+ Text[SizeOfTag] = 0;
+ *nItems = 1;
+
+ // Keep the result
+ if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
+
+ _cmsFree(self ->ContextID, Text);
+ return (void*) mlu;
+
+Error:
+ if (mlu != NULL)
+ cmsMLUfree(mlu);
+ if (Text != NULL)
+ _cmsFree(self ->ContextID, Text);
+
+ return NULL;
+}
+
+// The conversion implies to choose a language. So, we choose the actual language.
+static
+cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsMLU* mlu = (cmsMLU*) Ptr;
+ cmsUInt32Number size;
+ cmsBool rc;
+ char* Text;
+
+ // Get the size of the string. Note there is an extra "\0" at the end
+ size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
+ if (size == 0) return FALSE; // Cannot be zero!
+
+ // Create memory
+ Text = (char*) _cmsMalloc(self ->ContextID, size);
+ cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
+
+ // Write it, including separator
+ rc = io ->Write(io, size, Text);
+
+ _cmsFree(self ->ContextID, Text);
+ return rc;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+static
+void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsMLUdup((cmsMLU*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsMLU* mlu = (cmsMLU*) Ptr;
+ cmsMLUfree(mlu);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
+{
+ if (ICCVersion >= 4.0)
+ return cmsSigMultiLocalizedUnicodeType;
+
+ return cmsSigTextType;
+
+ cmsUNUSED_PARAMETER(Data);
+}
+
+
+// ********************************************************************************
+// Type cmsSigDataType
+// ********************************************************************************
+
+// General purpose data type
+static
+void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsICCData* BinData;
+ cmsUInt32Number LenOfData;
+
+ *nItems = 0;
+ LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
+
+ BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
+ if (BinData == NULL) return NULL;
+
+ BinData ->len = LenOfData;
+ if (!_cmsReadUInt32Number(io, &BinData->flag)) return NULL;
+
+ if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
+
+ _cmsFree(self ->ContextID, BinData);
+ return NULL;
+ }
+
+ *nItems = 1;
+
+ return (void*) BinData;
+}
+
+
+static
+cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsICCData* BinData = (cmsICCData*) Ptr;
+
+ if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
+
+ return io ->Write(io, BinData ->len, BinData ->data);
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ cmsICCData* BinData = (cmsICCData*) Ptr;
+
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+static
+void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type cmsSigTextDescriptionType
+// ********************************************************************************
+
+static
+void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ char* Text = NULL;
+ cmsMLU* mlu = NULL;
+ cmsUInt32Number AsciiCount;
+ cmsUInt32Number i, UnicodeCode, UnicodeCount;
+ cmsUInt16Number ScriptCodeCode, Dummy;
+ cmsUInt8Number ScriptCodeCount;
+
+ *nItems = 0;
+
+ // One dword should be there
+ if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+
+ // Read len of ASCII
+ if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ // Check for size
+ if (SizeOfTag < AsciiCount) return NULL;
+
+ // All seems Ok, allocate the container
+ mlu = cmsMLUalloc(self ->ContextID, 1);
+ if (mlu == NULL) return NULL;
+
+ // As many memory as size of tag
+ Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1);
+ if (Text == NULL) goto Error;
+
+ // Read it
+ if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error;
+ SizeOfTag -= AsciiCount;
+
+ // Make sure there is a terminator
+ Text[AsciiCount] = 0;
+
+ // Set the MLU entry. From here we can be tolerant to wrong types
+ if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
+ _cmsFree(self ->ContextID, (void*) Text);
+ Text = NULL;
+
+ // Skip Unicode code
+ if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done;
+ if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done;
+ if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
+ SizeOfTag -= 2* sizeof(cmsUInt32Number);
+
+ if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
+
+ for (i=0; i < UnicodeCount; i++) {
+ if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
+ }
+ SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
+
+ // Skip ScriptCode code if present. Some buggy profiles does have less
+ // data that stricttly required. We need to skip it as this type may come
+ // embedded in other types.
+
+ if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
+
+ if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done;
+ if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done;
+
+ // Skip rest of tag
+ for (i=0; i < 67; i++) {
+ if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error;
+ }
+ }
+
+Done:
+
+ *nItems = 1;
+ return mlu;
+
+Error:
+ if (Text) _cmsFree(self ->ContextID, (void*) Text);
+ if (mlu) cmsMLUfree(mlu);
+ return NULL;
+}
+
+
+// This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
+static
+cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsMLU* mlu = (cmsMLU*) Ptr;
+ char *Text = NULL;
+ wchar_t *Wide = NULL;
+ cmsUInt32Number len, len_aligned, len_filler_alignment;
+ cmsBool rc = FALSE;
+ char Filler[68];
+
+ // Used below for writting zeroes
+ memset(Filler, 0, sizeof(Filler));
+
+ // Get the len of string
+ len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
+
+ // From ICC3.4: It has been found that textDescriptionType can contain misaligned data
+ //(see clause 4.1 for the definition of “aligned”). Because the Unicode language
+ // code and Unicode count immediately follow the ASCII description, their
+ // alignment is not correct if the ASCII count is not a multiple of four. The
+ // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
+ // writing software must be written carefully in order to handle these alignment
+ // problems.
+
+ // Compute an aligned size
+ len_aligned = _cmsALIGNLONG(len);
+ len_filler_alignment = len_aligned - len;
+
+ // Null strings
+ if (len <= 0) {
+
+ Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
+ Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
+ }
+ else {
+ // Create independent buffers
+ Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
+ if (Text == NULL) goto Error;
+
+ Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
+ if (Wide == NULL) goto Error;
+
+ // Get both representations.
+ cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char));
+ cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t));
+ }
+
+ // * cmsUInt32Number count; * Description length
+ // * cmsInt8Number desc[count] * NULL terminated ascii string
+ // * cmsUInt32Number ucLangCode; * UniCode language code
+ // * cmsUInt32Number ucCount; * UniCode description length
+ // * cmsInt16Number ucDesc[ucCount];* The UniCode description
+ // * cmsUInt16Number scCode; * ScriptCode code
+ // * cmsUInt8Number scCount; * ScriptCode count
+ // * cmsInt8Number scDesc[67]; * ScriptCode Description
+
+ if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error;
+ if (!io ->Write(io, len, Text)) goto Error;
+ if (!io ->Write(io, len_filler_alignment, Filler)) goto Error;
+
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
+
+ // This part is tricky: we need an aligned tag size, and the ScriptCode part
+ // takes 70 bytes, so we need 2 extra bytes to do the alignment
+
+ if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error;
+
+ // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
+ if (!_cmsWriteWCharArray(io, len, Wide)) goto Error;
+ if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error;
+
+ // ScriptCode Code & count (unused)
+ if (!_cmsWriteUInt16Number(io, 0)) goto Error;
+ if (!_cmsWriteUInt8Number(io, 0)) goto Error;
+
+ if (!io ->Write(io, 67, Filler)) goto Error;
+
+ rc = TRUE;
+
+Error:
+ if (Text) _cmsFree(self ->ContextID, Text);
+ if (Wide) _cmsFree(self ->ContextID, Wide);
+
+ return rc;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsMLUdup((cmsMLU*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsMLU* mlu = (cmsMLU*) Ptr;
+
+ cmsMLUfree(mlu);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
+{
+ if (ICCVersion >= 4.0)
+ return cmsSigMultiLocalizedUnicodeType;
+
+ return cmsSigTextDescriptionType;
+
+ cmsUNUSED_PARAMETER(Data);
+}
+
+
+// ********************************************************************************
+// Type cmsSigCurveType
+// ********************************************************************************
+
+static
+void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt32Number Count;
+ cmsToneCurve* NewGamma;
+ cmsUInt16Number Linear[2] = { 0, 0xffff };
+
+
+ *nItems = 0;
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+
+ switch (Count) {
+
+ case 0: // Linear.
+
+ NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, 2, Linear);
+ if (!NewGamma) return NULL;
+ *nItems = 1;
+ return NewGamma;
+
+ case 1: // Specified as the exponent of gamma function
+ {
+ cmsUInt16Number SingleGammaFixed;
+ cmsFloat64Number SingleGamma;
+
+ if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
+ SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
+
+ *nItems = 1;
+ return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
+ }
+
+ default: // Curve
+
+ NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
+ if (!NewGamma) return NULL;
+
+ if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
+
+ *nItems = 1;
+ return NewGamma;
+ }
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+static
+cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
+
+ if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
+
+ // Single gamma, preserve number
+ cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
+
+ if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
+ return TRUE;
+
+ }
+
+ if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
+ return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
+
+ cmsFreeToneCurve(gamma);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigParametricCurveType
+// ********************************************************************************
+
+
+// Decide which curve type to use on writting
+static
+cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
+{
+ cmsToneCurve* Curve = (cmsToneCurve*) Data;
+
+ if (ICCVersion < 4.0) return cmsSigCurveType;
+ if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
+ if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
+
+ return cmsSigParametricCurveType;
+}
+
+static
+void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
+ cmsFloat64Number Params[10];
+ cmsUInt16Number Type;
+ int i, n;
+ cmsToneCurve* NewGamma;
+
+ if (!_cmsReadUInt16Number(io, &Type)) return NULL;
+ if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
+
+ if (Type > 4) {
+
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
+ return NULL;
+ }
+
+ memset(Params, 0, sizeof(Params));
+ n = ParamsByType[Type];
+
+ for (i=0; i < n; i++) {
+
+ if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
+ }
+
+ NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
+
+ *nItems = 1;
+ return NewGamma;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+static
+cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
+ int i, nParams;
+ static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
+
+
+ if (Curve ->nSegments > 1 || Curve -> Segments[0].Type < 1) {
+
+ cmsSignalError(self->ContextID, 0, "Multisegment or Inverted parametric curves cannot be written");
+ return FALSE;
+ }
+
+ nParams = ParamsByType[Curve ->Segments[0].Type];
+
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
+ if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
+
+ for (i=0; i < nParams; i++) {
+
+ if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+static
+void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
+
+ cmsFreeToneCurve(gamma);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigDateTimeType
+// ********************************************************************************
+
+// A 12-byte value representation of the time and date, where the byte usage is assigned
+// as specified in table 1. The actual values are encoded as 16-bit unsigned integers
+// (uInt16Number - see 5.1.6).
+//
+// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
+// (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
+// time to UTC when setting these values. Programmes that display these values may show
+// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
+// display both UTC and local versions of the dateTimeNumber.
+
+static
+void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsDateTimeNumber timestamp;
+ struct tm * NewDateTime;
+
+ *nItems = 0;
+ NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
+ if (NewDateTime == NULL) return NULL;
+
+ if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
+
+ _cmsDecodeDateTimeNumber(×tamp, NewDateTime);
+
+ *nItems = 1;
+ return NewDateTime;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+static
+cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ struct tm * DateTime = (struct tm*) Ptr;
+ cmsDateTimeNumber timestamp;
+
+ _cmsEncodeDateTimeNumber(×tamp, DateTime);
+ if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+static
+void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+
+
+// ********************************************************************************
+// Type icMeasurementType
+// ********************************************************************************
+
+/*
+The measurementType information refers only to the internal profile data and is
+meant to provide profile makers an alternative to the default measurement
+specifications.
+*/
+
+static
+void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsICCMeasurementConditions mc;
+
+ if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
+ if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
+ if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
+ if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
+
+ *nItems = 1;
+ return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+static
+cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
+
+ if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
+ if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+static
+void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+
+// ********************************************************************************
+// Type cmsSigMultiLocalizedUnicodeType
+// ********************************************************************************
+
+//
+// Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
+// Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
+// taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
+//
+// FIXME: this doesn't work if sizeof(wchat_t) != 2 !!!
+
+static
+void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsMLU* mlu;
+ cmsUInt32Number Count, RecLen, NumOfWchar;
+ cmsUInt32Number SizeOfHeader;
+ cmsUInt32Number Len, Offset;
+ cmsUInt32Number i;
+ cmsUInt16Number* Block;
+ cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition;
+
+ *nItems = 0;
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+ if (!_cmsReadUInt32Number(io, &RecLen)) return NULL;
+
+ if (RecLen != 12) {
+
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported.");
+ return NULL;
+ }
+
+ mlu = cmsMLUalloc(self ->ContextID, Count);
+ if (mlu == NULL) return NULL;
+
+ mlu ->UsedEntries = Count;
+
+ SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
+ LargestPosition = 0;
+
+ for (i=0; i < Count; i++) {
+
+ if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
+ if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
+
+ // Now deal with Len and offset.
+ if (!_cmsReadUInt32Number(io, &Len)) goto Error;
+ mlu ->Entries[i].Len = Len;
+
+ if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
+
+ BeginOfThisString = Offset - SizeOfHeader - 8;
+ mlu ->Entries[i].StrW = BeginOfThisString;
+
+ // To guess maximum size, add offset + len
+ EndOfThisString = BeginOfThisString + Len;
+ if (EndOfThisString > LargestPosition)
+ LargestPosition = EndOfThisString;
+ }
+
+ // Now read the remaining of tag and fill all strings. Substract the directory
+ SizeOfTag = LargestPosition;
+
+ Block = (cmsUInt16Number*) _cmsMalloc(self ->ContextID, SizeOfTag);
+ if (Block == NULL) goto Error;
+
+ NumOfWchar = SizeOfTag / sizeof(cmsUInt16Number);
+
+ if (!_cmsReadUInt16Array(io, NumOfWchar, Block)) goto Error;
+ mlu ->MemPool = Block;
+ mlu ->PoolSize = SizeOfTag;
+ mlu ->PoolUsed = SizeOfTag;
+
+ *nItems = 1;
+ return (void*) mlu;
+
+Error:
+ if (mlu) cmsMLUfree(mlu);
+ return NULL;
+}
+
+static
+cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsMLU* mlu =(cmsMLU*) Ptr;
+ cmsUInt32Number HeaderSize, Offset;
+ int i;
+
+ if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
+
+ HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
+
+ for (i=0; i < mlu ->UsedEntries; i++) {
+
+ if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, mlu ->Entries[i].Len)) return FALSE;
+
+ Offset = mlu ->Entries[i].StrW + HeaderSize + 8;
+
+ if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
+ }
+
+ if (!_cmsWriteUInt16Array(io, mlu ->PoolUsed / sizeof(cmsUInt16Number), (cmsUInt16Number*) mlu ->MemPool)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsMLUdup((cmsMLU*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsMLUfree((cmsMLU*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigLut8Type
+// ********************************************************************************
+
+// Decide which LUT type to use on writting
+static
+cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
+{
+ cmsPipeline* Lut = (cmsPipeline*) Data;
+
+ if (ICCVersion < 4.0) {
+ if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
+ return cmsSigLut16Type;
+ }
+ else {
+ return cmsSigLutAtoBType;
+ }
+}
+
+static
+cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data)
+{
+ cmsPipeline* Lut = (cmsPipeline*) Data;
+
+ if (ICCVersion < 4.0) {
+ if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
+ return cmsSigLut16Type;
+ }
+ else {
+ return cmsSigLutBtoAType;
+ }
+}
+
+/*
+This structure represents a colour transform using tables of 8-bit precision.
+This type contains four processing elements: a 3 by 3 matrix (which shall be
+the identity matrix unless the input colour space is XYZ), a set of one dimensional
+input tables, a multidimensional lookup table, and a set of one dimensional output
+tables. Data is processed using these elements via the following sequence:
+(matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
+
+Byte Position Field Length (bytes) Content Encoded as...
+8 1 Number of Input Channels (i) uInt8Number
+9 1 Number of Output Channels (o) uInt8Number
+10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
+11 1 Reserved for padding (fill with 00h)
+
+12..15 4 Encoded e00 parameter s15Fixed16Number
+*/
+
+
+// Read 8 bit tables as gamma functions
+static
+cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
+{
+ cmsStage* mpe;
+ cmsUInt8Number* Temp = NULL;
+ int i, j;
+ cmsToneCurve* Tables[cmsMAXCHANNELS];
+
+ if (nChannels > cmsMAXCHANNELS) return FALSE;
+
+ memset(Tables, 0, sizeof(Tables));
+
+ Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256);
+ if (Temp == NULL) return FALSE;
+
+ for (i=0; i < nChannels; i++) {
+ Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
+ if (Tables[i] == NULL) goto Error;
+ }
+
+ for (i=0; i < nChannels; i++) {
+
+ if (io ->Read(io, Temp, 256, 1) != 1) goto Error;
+
+ for (j=0; j < 256; j++)
+ Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]);
+ }
+
+ _cmsFree(ContextID, Temp);
+
+
+ mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
+ if (mpe == NULL) goto Error;
+
+ cmsPipelineInsertStage(lut, cmsAT_END, mpe);
+
+ for (i=0; i < nChannels; i++)
+ cmsFreeToneCurve(Tables[i]);
+
+ return TRUE;
+
+Error:
+ for (i=0; i < nChannels; i++) {
+ if (Tables[i]) cmsFreeToneCurve(Tables[i]);
+ }
+
+ if (Temp) _cmsFree(ContextID, Temp);
+ return FALSE;
+}
+
+
+static
+cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables)
+{
+ int j;
+ cmsUInt32Number i;
+ cmsUInt8Number val;
+
+ for (i=0; i < n; i++) {
+
+ if (Tables) {
+
+ if (Tables ->TheCurves[i]->nEntries != 256) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
+ return FALSE;
+ }
+
+ }
+
+ for (j=0; j < 256; j++) {
+
+ if (Tables != NULL)
+ val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
+ else
+ val = (cmsUInt8Number) j;
+
+ if (!_cmsWriteUInt8Number(io, val)) return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+static
+unsigned int uipow(cmsUInt32Number a, cmsUInt32Number b) {
+ cmsUInt32Number rv = 1;
+ for (; b > 0; b--)
+ rv *= a;
+ return rv;
+}
+
+
+// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
+// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
+// PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
+
+static
+void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
+ cmsUInt8Number* Temp = NULL;
+ cmsPipeline* NewLUT = NULL;
+ cmsStage *mpemat, *mpeclut;
+ cmsUInt32Number nTabSize, i;
+ cmsFloat64Number Matrix[3*3];
+
+ *nItems = 0;
+
+ if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error;
+ if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
+ if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
+
+ // Padding
+ if (!_cmsReadUInt8Number(io, NULL)) goto Error;
+
+ // Do some checking
+
+ if (InputChannels > cmsMAXCHANNELS) goto Error;
+ if (OutputChannels > cmsMAXCHANNELS) goto Error;
+
+ // Allocates an empty Pipeline
+ NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
+ if (NewLUT == NULL) goto Error;
+
+ // Read the Matrix
+ if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
+
+
+ // Only operates if not identity...
+ if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
+
+ mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
+ if (mpemat == NULL) goto Error;
+ cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, mpemat);
+ }
+
+ // Get input tables
+ if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error;
+
+ // Get 3D CLUT
+ nTabSize = (OutputChannels * uipow(CLUTpoints, InputChannels));
+ if (nTabSize > 0) {
+
+ cmsUInt16Number *PtrW, *T;
+ cmsUInt32Number Tsize;
+
+ Tsize = (cmsUInt32Number) nTabSize * sizeof(cmsUInt16Number);
+
+ PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
+ if (T == NULL) goto Error;
+
+ Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
+ if (Temp == NULL) goto Error;
+
+ if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error;
+
+ for (i = 0; i < nTabSize; i++) {
+
+ *PtrW++ = FROM_8_TO_16(Temp[i]);
+ }
+ _cmsFree(self ->ContextID, Temp);
+ Temp = NULL;
+
+
+ mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
+ if (mpeclut == NULL) goto Error;
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
+ _cmsFree(self ->ContextID, T);
+ }
+
+
+ // Get output tables
+ if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
+
+ *nItems = 1;
+ return NewLUT;
+
+Error:
+ if (NewLUT != NULL) cmsPipelineFree(NewLUT);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+// We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
+static
+cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt32Number j, nTabSize;
+ cmsUInt8Number val;
+ cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
+ cmsStage* mpe;
+ _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
+ _cmsStageMatrixData* MatMPE = NULL;
+ _cmsStageCLutData* clut = NULL;
+ int clutPoints;
+
+ // Disassemble the LUT into components.
+ mpe = NewLUT -> Elements;
+ if (mpe ->Type == cmsSigMatrixElemType) {
+
+ MatMPE = (_cmsStageMatrixData*) mpe ->Data;
+ mpe = mpe -> Next;
+ }
+
+ if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
+ PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
+ mpe = mpe -> Next;
+ }
+
+ if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
+ clut = (_cmsStageCLutData*) mpe -> Data;
+ mpe = mpe ->Next;
+ }
+
+ if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
+ PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
+ mpe = mpe -> Next;
+ }
+
+ // That should be all
+ if (mpe != NULL) {
+ cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
+ return FALSE;
+ }
+
+
+ if (clut == NULL)
+ clutPoints = 0;
+ else
+ clutPoints = clut->Params->nSamples[0];
+
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
+
+
+ if (MatMPE != NULL) {
+
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
+
+ }
+ else {
+
+ if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
+ }
+
+ // The prelinearization table
+ if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
+
+ nTabSize = (NewLUT->OutputChannels * uipow(clutPoints, NewLUT ->InputChannels));
+
+ // The 3D CLUT.
+ if (clut != NULL) {
+
+ for (j=0; j < nTabSize; j++) {
+
+ val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
+ if (!_cmsWriteUInt8Number(io, val)) return FALSE;
+ }
+ }
+
+ // The postlinearization table
+ if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsPipelineFree((cmsPipeline*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+// ********************************************************************************
+// Type cmsSigLut16Type
+// ********************************************************************************
+
+// Read 16 bit tables as gamma functions
+static
+cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
+{
+ cmsStage* mpe;
+ int i;
+ cmsToneCurve* Tables[cmsMAXCHANNELS];
+
+ // Maybe an empty table? (this is a lcms extension)
+ if (nEntries <= 0) return TRUE;
+
+ // Check for malicious profiles
+ if (nChannels > cmsMAXCHANNELS) return FALSE;
+
+ // Init table to zero
+ memset(Tables, 0, sizeof(Tables));
+
+ for (i=0; i < nChannels; i++) {
+
+ Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
+ if (Tables[i] == NULL) goto Error;
+
+ if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error;
+ }
+
+
+ // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
+ mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
+ if (mpe == NULL) goto Error;
+
+ cmsPipelineInsertStage(lut, cmsAT_END, mpe);
+
+ for (i=0; i < nChannels; i++)
+ cmsFreeToneCurve(Tables[i]);
+
+ return TRUE;
+
+Error:
+ for (i=0; i < nChannels; i++) {
+ if (Tables[i]) cmsFreeToneCurve(Tables[i]);
+ }
+
+ return FALSE;
+}
+
+static
+cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
+{
+ int j;
+ cmsUInt32Number i;
+ cmsUInt16Number val;
+ int nEntries = 256;
+
+ nEntries = Tables->TheCurves[0]->nEntries;
+
+ for (i=0; i < Tables ->nCurves; i++) {
+
+ for (j=0; j < nEntries; j++) {
+
+ if (Tables != NULL)
+ val = Tables->TheCurves[i]->Table16[j];
+ else
+ val = _cmsQuantizeVal(j, nEntries);
+
+ if (!_cmsWriteUInt16Number(io, val)) return FALSE;
+ }
+ }
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(ContextID);
+}
+
+static
+void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
+ cmsPipeline* NewLUT = NULL;
+ cmsStage *mpemat, *mpeclut;
+ cmsUInt32Number nTabSize;
+ cmsFloat64Number Matrix[3*3];
+ cmsUInt16Number InputEntries, OutputEntries;
+
+ *nItems = 0;
+
+ if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
+ if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
+ if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL;
+
+ // Padding
+ if (!_cmsReadUInt8Number(io, NULL)) return NULL;
+
+ // Do some checking
+ if (CLUTpoints > 100) goto Error;
+ if (InputChannels > cmsMAXCHANNELS) goto Error;
+ if (OutputChannels > cmsMAXCHANNELS) goto Error;
+
+ // Allocates an empty LUT
+ NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
+ if (NewLUT == NULL) goto Error;
+
+ // Read the Matrix
+ if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
+
+
+ // Only operates on 3 channels
+
+ if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
+
+ mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
+ if (mpemat == NULL) goto Error;
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat);
+ }
+
+ if (!_cmsReadUInt16Number(io, &InputEntries)) return NULL;
+ if (!_cmsReadUInt16Number(io, &OutputEntries)) return NULL;
+
+
+ // Get input tables
+ if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error;
+
+ // Get 3D CLUT
+ nTabSize = (OutputChannels * uipow(CLUTpoints, InputChannels));
+ if (nTabSize > 0) {
+
+ cmsUInt16Number *T;
+
+ T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
+ if (T == NULL) goto Error;
+
+ if (!_cmsReadUInt16Array(io, nTabSize, T)) goto Error;
+
+ mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
+ if (mpeclut == NULL) goto Error;
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
+ _cmsFree(self ->ContextID, T);
+ }
+
+
+ // Get output tables
+ if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
+
+ *nItems = 1;
+ return NewLUT;
+
+Error:
+ if (NewLUT != NULL) cmsPipelineFree(NewLUT);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+// We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
+// Some empty defaults are created for missing parts
+
+static
+cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt32Number nTabSize;
+ cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
+ cmsStage* mpe;
+ _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
+ _cmsStageMatrixData* MatMPE = NULL;
+ _cmsStageCLutData* clut = NULL;
+ int InputChannels, OutputChannels, clutPoints;
+
+ // Disassemble the LUT into components.
+ mpe = NewLUT -> Elements;
+ if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
+
+ MatMPE = (_cmsStageMatrixData*) mpe ->Data;
+ mpe = mpe -> Next;
+ }
+
+
+ if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
+ PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
+ mpe = mpe -> Next;
+ }
+
+ if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
+ clut = (_cmsStageCLutData*) mpe -> Data;
+ mpe = mpe ->Next;
+ }
+
+ if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
+ PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
+ mpe = mpe -> Next;
+ }
+
+ // That should be all
+ if (mpe != NULL) {
+ cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
+ return FALSE;
+ }
+
+ InputChannels = cmsPipelineInputChannels(NewLUT);
+ OutputChannels = cmsPipelineOutputChannels(NewLUT);
+
+ if (clut == NULL)
+ clutPoints = 0;
+ else
+ clutPoints = clut->Params->nSamples[0];
+
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
+
+
+ if (MatMPE != NULL) {
+
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
+ }
+ else {
+
+ if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
+ }
+
+
+ if (PreMPE != NULL) {
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
+ } else {
+ if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
+ }
+
+ if (PostMPE != NULL) {
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
+ } else {
+ if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
+
+ }
+
+ // The prelinearization table
+
+ if (PreMPE != NULL) {
+ if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
+ }
+
+ nTabSize = (OutputChannels * uipow(clutPoints, InputChannels));
+
+ // The 3D CLUT.
+ if (clut != NULL) {
+ if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
+ }
+
+ // The postlinearization table
+ if (PostMPE != NULL) {
+ if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
+ }
+
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+static
+void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsPipelineFree((cmsPipeline*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigLutAToBType
+// ********************************************************************************
+
+
+// V4 stuff. Read matrix for LutAtoB and LutBtoA
+
+static
+cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
+{
+ cmsFloat64Number dMat[3*3];
+ cmsFloat64Number dOff[3];
+ cmsStage* Mat;
+
+ // Go to address
+ if (!io -> Seek(io, Offset)) return NULL;
+
+ // Read the Matrix
+ if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL;
+
+ if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL;
+ if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL;
+
+ Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff);
+
+ return Mat;
+}
+
+
+
+
+// V4 stuff. Read CLUT part for LutAtoB and LutBtoA
+
+static
+cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels)
+{
+ cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
+ cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
+ cmsUInt8Number Precision;
+ cmsStage* CLUT;
+ _cmsStageCLutData* Data;
+
+ if (!io -> Seek(io, Offset)) return NULL;
+ if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
+
+ for (i=0; i < cmsMAXCHANNELS; i++)
+ GridPoints[i] = gridPoints8[i];
+
+ if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
+
+ if (!_cmsReadUInt8Number(io, NULL)) return NULL;
+ if (!_cmsReadUInt8Number(io, NULL)) return NULL;
+ if (!_cmsReadUInt8Number(io, NULL)) return NULL;
+
+ CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
+ Data = (_cmsStageCLutData*) CLUT ->Data;
+
+ // Precision can be 1 or 2 bytes
+ if (Precision == 1) {
+
+ cmsUInt8Number v;
+
+ for (i=0; i < Data ->nEntries; i++) {
+
+ if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
+ Data ->Tab.T[i] = FROM_8_TO_16(v);
+ }
+
+ }
+ else
+ if (Precision == 2) {
+
+ if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL;
+ }
+ else {
+ cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow precision of '%d'", Precision);
+ return NULL;
+ }
+
+
+ return CLUT;
+}
+
+static
+cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
+{
+ cmsTagTypeSignature BaseType;
+ cmsUInt32Number nItems;
+
+ BaseType = _cmsReadTypeBase(io);
+ switch (BaseType) {
+
+ case cmsSigCurveType:
+ return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0);
+
+ case cmsSigParametricCurveType:
+ return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0);
+
+ default:
+ {
+ char String[5];
+
+ _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
+ cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow curve type '%s'", String);
+ }
+ return NULL;
+ }
+}
+
+
+// Read a set of curves from specific offset
+static
+cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int nCurves)
+{
+ cmsToneCurve* Curves[cmsMAXCHANNELS];
+ int i;
+ cmsStage* Lin;
+
+
+ if (nCurves > cmsMAXCHANNELS) return FALSE;
+
+ if (!io -> Seek(io, Offset)) return FALSE;
+
+ for (i=0; i < nCurves; i++) {
+
+ Curves[i] = ReadEmbeddedCurve(self, io);
+ if (Curves[i] == NULL) return FALSE;
+ if (!_cmsReadAlignment(io)) return FALSE;
+ }
+
+ Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
+
+ for (i=0; i < nCurves; i++)
+ cmsFreeToneCurve(Curves[i]);
+
+ return Lin;
+}
+
+
+// LutAtoB type
+
+// This structure represents a colour transform. The type contains up to five processing
+// elements which are stored in the AtoBTag tag in the following order: a set of one
+// dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
+// a multidimensional lookup table, and a set of one dimensional output curves.
+// Data are processed using these elements via the following sequence:
+//
+//("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
+//
+/*
+It is possible to use any or all of these processing elements. At least one processing element
+must be included.Only the following combinations are allowed:
+
+B
+M - Matrix - B
+A - CLUT - B
+A - CLUT - M - Matrix - B
+
+*/
+
+static
+void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt32Number BaseOffset;
+ cmsUInt8Number inputChan; // Number of input channels
+ cmsUInt8Number outputChan; // Number of output channels
+ cmsUInt32Number offsetB; // Offset to first "B" curve
+ cmsUInt32Number offsetMat; // Offset to matrix
+ cmsUInt32Number offsetM; // Offset to first "M" curve
+ cmsUInt32Number offsetC; // Offset to CLUT
+ cmsUInt32Number offsetA; // Offset to first "A" curve
+ cmsStage* mpe;
+ cmsPipeline* NewLUT = NULL;
+
+
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
+ if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
+
+ if (!_cmsReadUInt16Number(io, NULL)) return NULL;
+
+ if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
+
+ // Allocates an empty LUT
+ NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
+ if (NewLUT == NULL) return NULL;
+
+ if (offsetA!= 0) {
+ mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetC != 0) {
+ mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetM != 0) {
+ mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetMat != 0) {
+ mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetB != 0) {
+ mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ *nItems = 1;
+ return NewLUT;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+// Write a set of curves
+static
+cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
+{
+ _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
+
+ // Write the Matrix
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
+
+ if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// Write a set of curves
+static
+cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
+{
+ cmsUInt32Number i, n;
+ cmsTagTypeSignature CurrentType;
+ cmsToneCurve** Curves;
+
+
+ n = cmsStageOutputChannels(mpe);
+ Curves = _cmsStageGetPtrToCurveSet(mpe);
+
+ for (i=0; i < n; i++) {
+
+ // If this is a table-based curve, use curve type even on V4
+ CurrentType = Type;
+
+ if (Curves[i] ->nSegments == 0)
+ CurrentType = cmsSigCurveType;
+ else
+ if (Curves[i] ->Segments[0].Type < 0)
+ CurrentType = cmsSigCurveType;
+
+ if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE;
+
+ switch (CurrentType) {
+
+ case cmsSigCurveType:
+ if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE;
+ break;
+
+ case cmsSigParametricCurveType:
+ if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE;
+ break;
+
+ default:
+ {
+ char String[5];
+
+ _cmsTagSignature2String(String, (cmsTagSignature) Type);
+ cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow curve type '%s'", String);
+ }
+ return FALSE;
+ }
+
+ if (!_cmsWriteAlignment(io)) return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+static
+cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe)
+{
+ cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension.
+ cmsUInt32Number i;
+ _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
+
+ memset(gridPoints, 0, sizeof(gridPoints));
+ for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
+ gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
+
+ if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE;
+
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
+
+ // Precision can be 1 or 2 bytes
+ if (Precision == 1) {
+
+ for (i=0; i < CLUT->nEntries; i++) {
+
+ if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE;
+ }
+ }
+ else
+ if (Precision == 2) {
+
+ if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
+ }
+ else {
+ cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow precision of '%d'", Precision);
+ return FALSE;
+ }
+
+ if (!_cmsWriteAlignment(io)) return FALSE;
+
+ return TRUE;
+}
+
+
+
+
+static
+cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsPipeline* Lut = (cmsPipeline*) Ptr;
+ int inputChan, outputChan;
+ cmsStage *A = NULL, *B = NULL, *M = NULL;
+ cmsStage * Matrix = NULL;
+ cmsStage * CLUT = NULL;
+ cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
+ cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
+
+ // Get the base for all offsets
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ if (Lut ->Elements != NULL)
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType,
+ cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) {
+
+ cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB");
+ return FALSE;
+ }
+
+ // Get input, output channels
+ inputChan = cmsPipelineInputChannels(Lut);
+ outputChan = cmsPipelineOutputChannels(Lut);
+
+ // Write channel count
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
+
+ // Keep directory to be filled latter
+ DirectoryPos = io ->Tell(io);
+
+ // Write the directory
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+
+ if (A != NULL) {
+
+ offsetA = io ->Tell(io) - BaseOffset;
+ if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
+ }
+
+ if (CLUT != NULL) {
+ offsetC = io ->Tell(io) - BaseOffset;
+ if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
+
+ }
+ if (M != NULL) {
+
+ offsetM = io ->Tell(io) - BaseOffset;
+ if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
+ }
+
+ if (Matrix != NULL) {
+ offsetMat = io ->Tell(io) - BaseOffset;
+ if (!WriteMatrix(self, io, Matrix)) return FALSE;
+ }
+
+ if (B != NULL) {
+
+ offsetB = io ->Tell(io) - BaseOffset;
+ if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
+ }
+
+ CurrentPos = io ->Tell(io);
+
+ if (!io ->Seek(io, DirectoryPos)) return FALSE;
+
+ if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
+
+ if (!io ->Seek(io, CurrentPos)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsPipelineFree((cmsPipeline*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// LutBToA type
+
+static
+void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt8Number inputChan; // Number of input channels
+ cmsUInt8Number outputChan; // Number of output channels
+ cmsUInt32Number BaseOffset; // Actual position in file
+ cmsUInt32Number offsetB; // Offset to first "B" curve
+ cmsUInt32Number offsetMat; // Offset to matrix
+ cmsUInt32Number offsetM; // Offset to first "M" curve
+ cmsUInt32Number offsetC; // Offset to CLUT
+ cmsUInt32Number offsetA; // Offset to first "A" curve
+ cmsStage* mpe;
+ cmsPipeline* NewLUT = NULL;
+
+
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
+ if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
+
+ // Padding
+ if (!_cmsReadUInt16Number(io, NULL)) return NULL;
+
+ if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
+ if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
+
+ // Allocates an empty LUT
+ NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
+ if (NewLUT == NULL) return NULL;
+
+ if (offsetB != 0) {
+ mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetMat != 0) {
+ mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetM != 0) {
+ mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetC != 0) {
+ mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ if (offsetA!= 0) {
+ mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan);
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ *nItems = 1;
+ return NewLUT;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+/*
+B
+B - Matrix - M
+B - CLUT - A
+B - Matrix - M - CLUT - A
+*/
+
+static
+cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsPipeline* Lut = (cmsPipeline*) Ptr;
+ int inputChan, outputChan;
+ cmsStage *A = NULL, *B = NULL, *M = NULL;
+ cmsStage *Matrix = NULL;
+ cmsStage *CLUT = NULL;
+ cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
+ cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
+
+
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A))
+ if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
+ cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) {
+ cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA");
+ return FALSE;
+ }
+
+ inputChan = cmsPipelineInputChannels(Lut);
+ outputChan = cmsPipelineOutputChannels(Lut);
+
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
+
+ DirectoryPos = io ->Tell(io);
+
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+
+ if (A != NULL) {
+
+ offsetA = io ->Tell(io) - BaseOffset;
+ if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
+ }
+
+ if (CLUT != NULL) {
+ offsetC = io ->Tell(io) - BaseOffset;
+ if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
+
+ }
+ if (M != NULL) {
+
+ offsetM = io ->Tell(io) - BaseOffset;
+ if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
+ }
+
+ if (Matrix != NULL) {
+ offsetMat = io ->Tell(io) - BaseOffset;
+ if (!WriteMatrix(self, io, Matrix)) return FALSE;
+ }
+
+ if (B != NULL) {
+
+ offsetB = io ->Tell(io) - BaseOffset;
+ if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
+ }
+
+ CurrentPos = io ->Tell(io);
+
+ if (!io ->Seek(io, DirectoryPos)) return FALSE;
+
+ if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
+
+ if (!io ->Seek(io, CurrentPos)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+
+static
+void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsPipelineFree((cmsPipeline*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+
+// ********************************************************************************
+// Type cmsSigColorantTableType
+// ********************************************************************************
+/*
+The purpose of this tag is to identify the colorants used in the profile by a
+unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
+value. The first colorant listed is the colorant of the first device channel of
+a lut tag. The second colorant listed is the colorant of the second device channel
+of a lut tag, and so on.
+*/
+
+static
+void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt32Number i, Count;
+ cmsNAMEDCOLORLIST* List;
+ char Name[34];
+ cmsUInt16Number PCS[3];
+
+
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+
+ if (Count > cmsMAXCHANNELS) {
+ cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count);
+ return NULL;
+ }
+
+ List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
+ for (i=0; i < Count; i++) {
+
+ if (io ->Read(io, Name, 32, 1) != 1) goto Error;
+ Name[33] = 0;
+
+ if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
+
+ if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
+
+ }
+
+ *nItems = 1;
+ return List;
+
+Error:
+ *nItems = 0;
+ cmsFreeNamedColorList(List);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+
+// Saves a colorant table. It is using the named color structure for simplicity sake
+static
+cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
+ int i, nColors;
+
+ nColors = cmsNamedColorCount(NamedColorList);
+
+ if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
+
+ for (i=0; i < nColors; i++) {
+
+ char root[33];
+ cmsUInt16Number PCS[3];
+
+ if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
+ root[32] = 0;
+
+ if (!io ->Write(io, 32, root)) return FALSE;
+ if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
+{
+ cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
+ return (void*) cmsDupNamedColorList(nc);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigNamedColor2Type
+// ********************************************************************************
+//
+//The namedColor2Type is a count value and array of structures that provide color
+//coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
+//device representation of the color are given. Both representations are 16-bit values.
+//The device representation corresponds to the header’s “color space of data” field.
+//This representation should be consistent with the “number of device components”
+//field in the namedColor2Type. If this field is 0, device coordinates are not provided.
+//The PCS representation corresponds to the header’s PCS field. The PCS representation
+//is always provided. Color names are fixed-length, 32-byte fields including null
+//termination. In order to maintain maximum portability, it is strongly recommended
+//that special characters of the 7-bit ASCII set not be used.
+
+static
+void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+
+ cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
+ cmsUInt32Number count; // Count of named colors
+ cmsUInt32Number nDeviceCoords; // Num of device coordinates
+ char prefix[32]; // Prefix for each color name
+ char suffix[32]; // Suffix for each color name
+ cmsNAMEDCOLORLIST* v;
+ cmsUInt32Number i;
+
+
+ *nItems = 0;
+ if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
+ if (!_cmsReadUInt32Number(io, &count)) return NULL;
+ if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL;
+
+ if (io -> Read(io, prefix, 32, 1) != 1) return NULL;
+ if (io -> Read(io, suffix, 32, 1) != 1) return NULL;
+
+ prefix[31] = suffix[31] = 0;
+
+ v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
+ if (v == NULL) return NULL;
+
+ if (nDeviceCoords > cmsMAXCHANNELS) {
+ cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
+ return 0;
+ }
+ for (i=0; i < count; i++) {
+
+ cmsUInt16Number PCS[3];
+ cmsUInt16Number Colorant[cmsMAXCHANNELS];
+ char Root[33];
+
+ memset(Colorant, 0, sizeof(Colorant));
+ if (io -> Read(io, Root, 32, 1) != 1) return NULL;
+ if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
+ if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
+
+ if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
+ }
+
+ *nItems = 1;
+ return (void*) v ;
+
+Error:
+ cmsFreeNamedColorList(v);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+// Saves a named color list into a named color profile
+static
+cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
+ char prefix[32]; // Prefix for each color name
+ char suffix[32]; // Suffix for each color name
+ int i, nColors;
+
+ nColors = cmsNamedColorCount(NamedColorList);
+
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
+
+ strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
+ strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
+
+ suffix[31] = prefix[31] = 0;
+
+ if (!io ->Write(io, 32, prefix)) return FALSE;
+ if (!io ->Write(io, 32, suffix)) return FALSE;
+
+ for (i=0; i < nColors; i++) {
+
+ cmsUInt16Number PCS[3];
+ cmsUInt16Number Colorant[cmsMAXCHANNELS];
+ char Root[33];
+
+ if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
+ if (!io ->Write(io, 32 , Root)) return FALSE;
+ if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
+ if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
+{
+ cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
+
+ return (void*) cmsDupNamedColorList(nc);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigProfileSequenceDescType
+// ********************************************************************************
+
+static
+cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
+{
+ cmsTagTypeSignature BaseType;
+ cmsUInt32Number nItems;
+
+ BaseType = _cmsReadTypeBase(io);
+
+ switch (BaseType) {
+
+ case cmsSigTextType:
+ if (*mlu) cmsMLUfree(*mlu);
+ *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag);
+ return (*mlu != NULL);
+
+ case cmsSigTextDescriptionType:
+ if (*mlu) cmsMLUfree(*mlu);
+ *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag);
+ return (*mlu != NULL);
+
+ /*
+ TBD: Size is needed for MLU, and we have no idea on which is the available size
+ */
+
+ case cmsSigMultiLocalizedUnicodeType:
+ if (*mlu) cmsMLUfree(*mlu);
+ *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag);
+ return (*mlu != NULL);
+
+ default: return FALSE;
+ }
+}
+
+
+static
+void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsSEQ* OutSeq;
+ cmsUInt32Number i, Count;
+
+ *nItems = 0;
+
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+
+ OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
+ if (OutSeq == NULL) return NULL;
+
+ OutSeq ->n = Count;
+
+ // Get structures as well
+
+ for (i=0; i < Count; i++) {
+
+ cmsPSEQDESC* sec = &OutSeq -> seq[i];
+
+ if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ if (!_cmsReadUInt64Number(io, &sec ->attributes)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt64Number);
+
+ if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) return NULL;
+ if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) return NULL;
+ }
+
+ *nItems = 1;
+ return OutSeq;
+}
+
+
+// Aux--Embed a text description type. It can be of type text description or multilocalized unicode
+static
+cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
+{
+ if (Text == NULL) {
+
+ // Placeholder for a null entry
+ if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
+ return Type_Text_Description_Write(self, io, NULL, 1);
+
+ }
+
+ if (Text->UsedEntries <= 1) {
+ if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
+ return Type_Text_Description_Write(self, io, Text, 1);
+ }
+ else {
+ if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE;
+ return Type_MLU_Write(self, io, Text, 1);
+ }
+}
+
+
+static
+cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsSEQ* Seq = (cmsSEQ*) Ptr;
+ cmsUInt32Number i;
+
+ if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
+
+ for (i=0; i < Seq ->n; i++) {
+
+ cmsPSEQDESC* sec = &Seq -> seq[i];
+
+ if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
+ if (!_cmsWriteUInt64Number(io, sec ->attributes)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
+
+ if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
+ if (!SaveDescription(self, io, sec ->Model)) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigProfileSequenceIdType
+// ********************************************************************************
+/*
+In certain workflows using ICC Device Link Profiles, it is necessary to identify the
+original profiles that were combined to create the Device Link Profile.
+This type is an array of structures, each of which contains information for
+identification of a profile used in a sequence
+*/
+
+
+static
+cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Cargo,
+ cmsUInt32Number n,
+ cmsUInt32Number SizeOfTag)
+{
+ cmsSEQ* OutSeq = (cmsSEQ*) Cargo;
+ cmsPSEQDESC* seq = &OutSeq ->seq[n];
+
+ if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE;
+ if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE;
+
+ return TRUE;
+}
+
+
+
+static
+void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsSEQ* OutSeq;
+ cmsUInt32Number Count;
+ cmsUInt32Number BaseOffset;
+
+ *nItems = 0;
+
+ // Get actual position as a basis for element offsets
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ // Get table count
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ // Allocate an empty structure
+ OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
+ if (OutSeq == NULL) return NULL;
+
+
+ // Read the position table
+ if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) {
+
+ cmsFreeProfileSequenceDescription(OutSeq);
+ return NULL;
+ }
+
+ // Success
+ *nItems = 1;
+ return OutSeq;
+
+}
+
+
+static
+cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Cargo,
+ cmsUInt32Number n,
+ cmsUInt32Number SizeOfTag)
+{
+ cmsSEQ* Seq = (cmsSEQ*) Cargo;
+
+ if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
+
+ // Store here the MLU
+ if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsSEQ* Seq = (cmsSEQ*) Ptr;
+ cmsUInt32Number BaseOffset;
+
+ // Keep the base offset
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ // This is the table count
+ if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
+
+ // This is the position table and content
+ if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+static
+void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigUcrBgType
+// ********************************************************************************
+/*
+This type contains curves representing the under color removal and black
+generation and a text string which is a general description of the method used
+for the ucr/bg.
+*/
+
+static
+void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
+ cmsUInt32Number CountUcr, CountBg;
+ char* ASCIIString;
+
+ *nItems = 0;
+ if (n == NULL) return NULL;
+
+ // First curve is Under color removal
+ if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
+ if (n ->Ucr == NULL) return NULL;
+
+ if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
+ SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
+
+ // Second curve is Black generation
+ if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
+ SizeOfTag -= sizeof(cmsUInt32Number);
+
+ n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
+ if (n ->Bg == NULL) return NULL;
+ if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
+ SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
+
+ // Now comes the text. The length is specified by the tag size
+ n ->Desc = cmsMLUalloc(self ->ContextID, 1);
+ ASCIIString = (char*) _cmsMalloc(self ->ContextID, sizeof(cmsUInt8Number)*(SizeOfTag + 1));
+ if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
+ ASCIIString[SizeOfTag] = 0;
+ cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
+ _cmsFree(self ->ContextID, ASCIIString);
+
+ *nItems = 1;
+ return (void*) n;
+}
+
+static
+cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUcrBg* Value = (cmsUcrBg*) Ptr;
+ cmsUInt32Number TextSize;
+ char* Text;
+
+ // First curve is Under color removal
+ if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
+ if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
+
+ // Then black generation
+ if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
+ if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
+
+ // Now comes the text. The length is specified by the tag size
+ TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
+ Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
+ if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
+
+ if (!io ->Write(io, TextSize, Text)) return FALSE;
+ _cmsFree(self ->ContextID, Text);
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+static
+void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ cmsUcrBg* Src = (cmsUcrBg*) Ptr;
+ cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
+
+ if (NewUcrBg == NULL) return NULL;
+
+ NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
+ NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
+ NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
+
+ return (void*) NewUcrBg;
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+static
+void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
+{
+ cmsUcrBg* Src = (cmsUcrBg*) Ptr;
+
+ if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
+ if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
+ if (Src ->Desc) cmsMLUfree(Src ->Desc);
+
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type cmsSigCrdInfoType
+// ********************************************************************************
+
+/*
+This type contains the PostScript product name to which this profile corresponds
+and the names of the companion CRDs. Recall that a single profile can generate
+multiple CRDs. It is implemented as a MLU being the language code "PS" and then
+country varies for each element:
+
+ nm: PostScript product name
+ #0: Rendering intent 0 CRD name
+ #1: Rendering intent 1 CRD name
+ #2: Rendering intent 2 CRD name
+ #3: Rendering intent 3 CRD name
+*/
+
+
+
+// Auxiliar, read an string specified as count + string
+static
+cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
+{
+ cmsUInt32Number Count;
+ char* Text;
+
+ if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
+
+ if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
+
+ if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
+ Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
+ if (Text == NULL) return FALSE;
+
+ if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
+ _cmsFree(self ->ContextID, Text);
+ return FALSE;
+ }
+
+ Text[Count] = 0;
+
+ cmsMLUsetASCII(mlu, "PS", Section, Text);
+ _cmsFree(self ->ContextID, Text);
+
+ *SizeOfTag -= (Count + sizeof(cmsUInt32Number));
+ return TRUE;
+}
+
+static
+cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
+{
+ cmsUInt32Number TextSize;
+ char* Text;
+
+ TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0);
+ Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
+
+ if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE;
+
+ if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE;
+
+ if (!io ->Write(io, TextSize, Text)) return FALSE;
+ _cmsFree(self ->ContextID, Text);
+
+ return TRUE;
+}
+
+static
+void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
+
+ *nItems = 0;
+ if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error;
+ if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error;
+ if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error;
+ if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error;
+ if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error;
+
+ *nItems = 1;
+ return (void*) mlu;
+
+Error:
+ cmsMLUfree(mlu);
+ return NULL;
+
+}
+
+static
+cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+
+ cmsMLU* mlu = (cmsMLU*) Ptr;
+
+ if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
+ if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
+ if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
+ if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
+ if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
+
+ return TRUE;
+
+Error:
+ return FALSE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsMLUdup((cmsMLU*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
+{
+ cmsMLUfree((cmsMLU*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+// ********************************************************************************
+// Type cmsSigScreeningType
+// ********************************************************************************
+//
+//The screeningType describes various screening parameters including screen
+//frequency, screening angle, and spot shape.
+
+static
+void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsScreening* sc = NULL;
+ cmsUInt32Number i;
+
+ sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
+ if (sc == NULL) return NULL;
+
+ *nItems = 0;
+
+ if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
+ if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
+
+ for (i=0; i < sc ->nChannels; i++) {
+
+ if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
+ if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
+ }
+
+
+ *nItems = 1;
+
+ return (void*) sc;
+
+Error:
+ if (sc != NULL)
+ _cmsFree(self ->ContextID, sc);
+
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+static
+cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsScreening* sc = (cmsScreening* ) Ptr;
+ cmsUInt32Number i;
+
+ if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
+
+ for (i=0; i < sc ->nChannels; i++) {
+
+ if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+
+static
+void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type cmsSigViewingConditionsType
+// ********************************************************************************
+//
+//This type represents a set of viewing condition parameters including:
+//CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’
+//surround tristimulus values.
+
+static
+void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsICCViewingConditions* vc = NULL;
+
+ vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
+ if (vc == NULL) return NULL;
+
+ *nItems = 0;
+
+ if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
+ if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
+ if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
+
+ *nItems = 1;
+
+ return (void*) vc;
+
+Error:
+ if (vc != NULL)
+ _cmsFree(self ->ContextID, vc);
+
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+static
+cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
+
+ if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
+ if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
+ if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+static
+void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+
+static
+void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+
+// ********************************************************************************
+// Type cmsSigMultiProcessElementType
+// ********************************************************************************
+
+
+static
+void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsStageDup((cmsStage*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
+{
+ cmsStageFree((cmsStage*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+// Each curve is stored in one or more curve segments, with break-points specified between curve segments.
+// The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The
+// first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
+// specified either in terms of a formula, or by a sampled curve.
+
+
+// Read an embedded segmented curve
+static
+cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
+{
+ cmsCurveSegSignature ElementSig;
+ cmsUInt32Number i, j;
+ cmsUInt16Number nSegments;
+ cmsCurveSegment* Segments;
+ cmsToneCurve* Curve;
+ cmsFloat32Number PrevBreak = -1E22F; // - infinite
+
+ // Take signature and channels for each element.
+ if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
+
+ // That should be a segmented curve
+ if (ElementSig != cmsSigSegmentedCurve) return NULL;
+
+ if (!_cmsReadUInt32Number(io, NULL)) return NULL;
+ if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
+ if (!_cmsReadUInt16Number(io, NULL)) return NULL;
+
+ Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
+ if (Segments == NULL) return NULL;
+
+ // Read breakpoints
+ for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) {
+
+ Segments[i].x0 = PrevBreak;
+ if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error;
+ PrevBreak = Segments[i].x1;
+ }
+
+ Segments[nSegments-1].x0 = PrevBreak;
+ Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number
+
+ // Read segments
+ for (i=0; i < nSegments; i++) {
+
+ if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error;
+ if (!_cmsReadUInt32Number(io, NULL)) goto Error;
+
+ switch (ElementSig) {
+
+ case cmsSigFormulaCurveSeg: {
+
+ cmsUInt16Number Type;
+ cmsUInt32Number ParamsByType[] = {4, 5, 5 };
+
+ if (!_cmsReadUInt16Number(io, &Type)) goto Error;
+ if (!_cmsReadUInt16Number(io, NULL)) goto Error;
+
+ Segments[i].Type = Type + 6;
+ if (Type > 2) goto Error;
+
+ for (j=0; j < ParamsByType[Type]; j++) {
+
+ cmsFloat32Number f;
+ if (!_cmsReadFloat32Number(io, &f)) goto Error;
+ Segments[i].Params[j] = f;
+ }
+ }
+ break;
+
+
+ case cmsSigSampledCurveSeg: {
+ cmsUInt32Number Count;
+
+ if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+
+ Segments[i].nGridPoints = Count;
+ Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
+ if (Segments[i].SampledPoints == NULL) goto Error;
+
+ for (j=0; j < Count; j++) {
+ if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
+ }
+ }
+ break;
+
+ default:
+ {
+ char String[5];
+
+ _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
+ }
+ return NULL;
+
+ }
+ }
+
+ Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments);
+
+ for (i=0; i < nSegments; i++) {
+ if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
+ }
+ _cmsFree(self ->ContextID, Segments);
+ return Curve;
+
+Error:
+ if (Segments) _cmsFree(self ->ContextID, Segments);
+ return NULL;
+}
+
+
+static
+cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Cargo,
+ cmsUInt32Number n,
+ cmsUInt32Number SizeOfTag)
+{
+ cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
+
+ GammaTables[n] = ReadSegmentedCurve(self, io);
+ return (GammaTables[n] != NULL);
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsStage* mpe = NULL;
+ cmsUInt16Number InputChans, OutputChans;
+ cmsUInt32Number i, BaseOffset;
+ cmsToneCurve** GammaTables;
+
+ *nItems = 0;
+
+ // Get actual position as a basis for element offsets
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
+ if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+
+ if (InputChans != OutputChans) return NULL;
+
+ GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
+ if (GammaTables == NULL) return NULL;
+
+ if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
+
+ mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
+ }
+ else {
+ mpe = NULL;
+ }
+
+ for (i=0; i < InputChans; i++) {
+ if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
+ }
+
+ _cmsFree(self ->ContextID, GammaTables);
+ *nItems = (mpe != NULL) ? 1 : 0;
+ return mpe;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+// Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
+static
+cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
+{
+ cmsUInt32Number i, j;
+ cmsCurveSegment* Segments = g ->Segments;
+ cmsUInt32Number nSegments = g ->nSegments;
+
+ if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error;
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
+ if (!_cmsWriteUInt16Number(io, 0)) goto Error;
+
+ // Write the break-points
+ for (i=0; i < nSegments - 1; i++) {
+ if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
+ }
+
+ // Write the segments
+ for (i=0; i < g ->nSegments; i++) {
+
+ cmsCurveSegment* ActualSeg = Segments + i;
+
+ if (ActualSeg -> Type == 0) {
+
+ // This is a sampled curve
+ if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error;
+ if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
+
+ for (j=0; j < g ->Segments[i].nGridPoints; j++) {
+ if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
+ }
+
+ }
+ else {
+ int Type;
+ cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
+
+ // This is a formula-based
+ if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error;
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error;
+
+ // We only allow 1, 2 and 3 as types
+ Type = ActualSeg ->Type - 6;
+ if (Type > 2 || Type < 0) goto Error;
+
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error;
+ if (!_cmsWriteUInt16Number(io, 0)) goto Error;
+
+ for (j=0; j < ParamsByType[Type]; j++) {
+ if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error;
+ }
+ }
+
+ // It seems there is no need to align. Code is here, and for safety commented out
+ // if (!_cmsWriteAlignment(io)) goto Error;
+ }
+
+ return TRUE;
+
+Error:
+ return FALSE;
+}
+
+
+static
+cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Cargo,
+ cmsUInt32Number n,
+ cmsUInt32Number SizeOfTag)
+{
+ _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
+
+ return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+ cmsUNUSED_PARAMETER(self);
+}
+
+// Write a curve, checking first for validity
+static
+cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt32Number BaseOffset;
+ cmsStage* mpe = (cmsStage*) Ptr;
+ _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
+
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ // Write the header. Since those are curves, input and output channels are same
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
+
+ if (!WritePositionTable(self, io, 0,
+ mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
+
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+
+// The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
+// matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
+// is organized as follows:
+// array = [e11, e12, …, e1P, e21, e22, …, e2P, …, eQ1, eQ2, …, eQP, e1, e2, …, eQ]
+
+static
+void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsStage* mpe;
+ cmsUInt16Number InputChans, OutputChans;
+ cmsUInt32Number nElems, i;
+ cmsFloat64Number* Matrix;
+ cmsFloat64Number* Offsets;
+
+ if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
+ if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+
+
+ nElems = InputChans * OutputChans;
+
+ // Input and output chans may be ANY (up to 0xffff)
+ Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
+ if (Matrix == NULL) return NULL;
+
+ Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number));
+ if (Offsets == NULL) {
+
+ _cmsFree(self ->ContextID, Matrix);
+ return NULL;
+ }
+
+ for (i=0; i < nElems; i++) {
+
+ cmsFloat32Number v;
+
+ if (!_cmsReadFloat32Number(io, &v)) return NULL;
+ Matrix[i] = v;
+ }
+
+
+ for (i=0; i < OutputChans; i++) {
+
+ cmsFloat32Number v;
+
+ if (!_cmsReadFloat32Number(io, &v)) return NULL;
+ Offsets[i] = v;
+ }
+
+
+ mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
+ _cmsFree(self ->ContextID, Matrix);
+ _cmsFree(self ->ContextID, Offsets);
+
+ *nItems = 1;
+
+ return mpe;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+static
+cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt32Number i, nElems;
+ cmsStage* mpe = (cmsStage*) Ptr;
+ _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
+
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
+
+ nElems = mpe ->InputChannels * mpe ->OutputChannels;
+
+ for (i=0; i < nElems; i++) {
+ if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
+ }
+
+
+ for (i=0; i < mpe ->OutputChannels; i++) {
+
+ if (Matrix ->Offset == NULL) {
+
+ if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
+ }
+ else {
+ if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
+ }
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+
+static
+void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsStage* mpe = NULL;
+ cmsUInt16Number InputChans, OutputChans;
+ cmsUInt8Number Dimensions8[16];
+ cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
+ _cmsStageCLutData* clut;
+
+ if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
+ if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+
+ if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
+ goto Error;
+
+ // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
+ nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
+ for (i=0; i < nMaxGrids; i++) GridPoints[i] = Dimensions8[i];
+
+ // Allocate the true CLUT
+ mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
+ if (mpe == NULL) goto Error;
+
+ // Read the data
+ clut = (_cmsStageCLutData*) mpe ->Data;
+ for (i=0; i < clut ->nEntries; i++) {
+
+ if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
+ }
+
+ *nItems = 1;
+ return mpe;
+
+Error:
+ *nItems = 0;
+ if (mpe != NULL) cmsStageFree(mpe);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+// Write a CLUT in floating point
+static
+cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt8Number Dimensions8[16];
+ cmsUInt32Number i;
+ cmsStage* mpe = (cmsStage*) Ptr;
+ _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
+
+ // Check for maximum number of channels
+ if (mpe -> InputChannels > 15) return FALSE;
+
+ // Only floats are supported in MPE
+ if (clut ->HasFloatValues == FALSE) return FALSE;
+
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
+
+ memset(Dimensions8, 0, sizeof(Dimensions8));
+
+ for (i=0; i < mpe ->InputChannels; i++)
+ Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
+
+ if (!io ->Write(io, 16, Dimensions8)) return FALSE;
+
+ for (i=0; i < clut ->nEntries; i++) {
+
+ if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(nItems);
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+
+// This is the list of built-in MPE types
+static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
+
+{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[1] }, // Ignore those elements for now
+{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[2] }, // (That's what the spec says)
+
+{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
+{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
+{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
+};
+
+#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList))
+
+static
+cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Cargo,
+ cmsUInt32Number n,
+ cmsUInt32Number SizeOfTag)
+{
+ cmsStageSignature ElementSig;
+ cmsTagTypeHandler* TypeHandler;
+ cmsStage *mpe = NULL;
+ cmsUInt32Number nItems;
+ cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
+
+ // Take signature and channels for each element.
+ if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
+
+ // The reserved placeholder
+ if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
+
+ // Read diverse MPE types
+ TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
+ if (TypeHandler == NULL) {
+
+ char String[5];
+
+ _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
+
+ // An unknown element was found.
+ cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
+ return FALSE;
+ }
+
+ // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
+ // Read the MPE. No size is given
+ if (TypeHandler ->ReadPtr != NULL) {
+
+ // This is a real element which should be read and processed
+ mpe = (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag);
+ if (mpe == NULL) return FALSE;
+
+ // All seems ok, insert element
+ cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+ cmsUNUSED_PARAMETER(n);
+}
+
+
+// This is the main dispatcher for MPE
+static
+void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsUInt16Number InputChans, OutputChans;
+ cmsUInt32Number ElementCount;
+ cmsPipeline *NewLUT = NULL;
+ cmsUInt32Number BaseOffset;
+
+ // Get actual position as a basis for element offsets
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ // Read channels and element count
+ if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
+ if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+
+ // Allocates an empty LUT
+ NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
+ if (NewLUT == NULL) return NULL;
+
+ if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
+
+ if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
+ if (NewLUT != NULL) cmsPipelineFree(NewLUT);
+ *nItems = 0;
+ return NULL;
+ }
+
+ // Success
+ *nItems = 1;
+ return NewLUT;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+
+// This one is a liitle bit more complex, so we don't use position tables this time.
+static
+cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
+ int inputChan, outputChan;
+ cmsUInt32Number ElemCount;
+ cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
+ cmsStageSignature ElementSig;
+ cmsPipeline* Lut = (cmsPipeline*) Ptr;
+ cmsStage* Elem = Lut ->Elements;
+ cmsTagTypeHandler* TypeHandler;
+
+ BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
+
+ inputChan = cmsPipelineInputChannels(Lut);
+ outputChan = cmsPipelineOutputChannels(Lut);
+ ElemCount = cmsPipelineStageCount(Lut);
+
+ ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *));
+ if (ElementOffsets == NULL) goto Error;
+
+ ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *));
+ if (ElementSizes == NULL) goto Error;
+
+ // Write the head
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error;
+ if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error;
+ if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error;
+
+ DirectoryPos = io ->Tell(io);
+
+ // Write a fake directory to be filled latter on
+ for (i=0; i < ElemCount; i++) {
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
+ }
+
+ // Write each single tag. Keep track of the size as well.
+ for (i=0; i < ElemCount; i++) {
+
+ ElementOffsets[i] = io ->Tell(io) - BaseOffset;
+
+ ElementSig = Elem ->Type;
+
+ TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
+ if (TypeHandler == NULL) {
+
+ char String[5];
+
+ _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
+
+ // An unknow element was found.
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
+ goto Error;
+ }
+
+ if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
+ if (!_cmsWriteUInt32Number(io, 0)) goto Error;
+ Before = io ->Tell(io);
+ if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
+ if (!_cmsWriteAlignment(io)) goto Error;
+
+ ElementSizes[i] = io ->Tell(io) - Before;
+
+ Elem = Elem ->Next;
+ }
+
+ // Write the directory
+ CurrentPos = io ->Tell(io);
+
+ if (!io ->Seek(io, DirectoryPos)) goto Error;
+
+ for (i=0; i < ElemCount; i++) {
+ if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
+ if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
+ }
+
+ if (!io ->Seek(io, CurrentPos)) goto Error;
+
+ if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
+ if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
+ return TRUE;
+
+Error:
+ if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
+ if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
+ return FALSE;
+
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
+
+ cmsUNUSED_PARAMETER(n);
+ cmsUNUSED_PARAMETER(self);
+}
+
+static
+void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
+{
+ cmsPipelineFree((cmsPipeline*) Ptr);
+ return;
+
+ cmsUNUSED_PARAMETER(self);
+}
+
+
+// ********************************************************************************
+// Type cmsSigVcgtType
+// ********************************************************************************
+
+
+#define cmsVideoCardGammaTableType 0
+#define cmsVideoCardGammaFormulaType 1
+
+// Used internally
+typedef struct {
+ double Gamma;
+ double Min;
+ double Max;
+} _cmsVCGTGAMMA;
+
+
+static
+void *Type_vcgt_Read(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ cmsUInt32Number* nItems,
+ cmsUInt32Number SizeOfTag)
+{
+ cmsUInt32Number TagType, n, i;
+ cmsToneCurve** Curves;
+
+ *nItems = 0;
+
+ // Read tag type
+ if (!_cmsReadUInt32Number(io, &TagType)) return NULL;
+
+ // Allocate space for the array
+ Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
+ if (Curves == NULL) return NULL;
+
+ // There are two possible flavors
+ switch (TagType) {
+
+ // Gamma is stored as a table
+ case cmsVideoCardGammaTableType:
+ {
+ cmsUInt16Number nChannels, nElems, nBytes;
+
+ // Check channel count, which should be 3 (we don't support monochrome this time)
+ if (!_cmsReadUInt16Number(io, &nChannels)) goto Error;
+
+ if (nChannels != 3) {
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels);
+ goto Error;
+ }
+
+ // Get Table element count and bytes per element
+ if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
+ if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
+
+ // Populate tone curves
+ for (n=0; n < 3; n++) {
+
+ Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL);
+ if (Curves[n] == NULL) goto Error;
+
+ // On depending on byte depth
+ switch (nBytes) {
+
+ // One byte, 0..255
+ case 1:
+ for (i=0; i < nElems; i++) {
+
+ cmsUInt8Number v;
+
+ if (!_cmsReadUInt8Number(io, &v)) goto Error;
+ Curves[n] ->Table16[i] = FROM_8_TO_16(v);
+ }
+ break;
+
+ // One word 0..65535
+ case 2:
+ if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error;
+ break;
+
+ // Unsupported
+ default:
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8);
+ goto Error;
+ }
+ } // For all 3 channels
+ }
+ break;
+
+ // In this case, gamma is stored as a formula
+ case cmsVideoCardGammaFormulaType:
+ {
+ _cmsVCGTGAMMA Colorant[3];
+
+ // Populate tone curves
+ for (n=0; n < 3; n++) {
+
+ double Params[10];
+
+ if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
+ if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
+
+ // Parametric curve type 5 is:
+ // Y = (aX + b)^Gamma + e | X >= d
+ // Y = cX + f | X < d
+
+ // vcgt formula is:
+ // Y = (Max – Min) * (X ^ Gamma) + Min
+
+ // So, the translation is
+ // a = (Max – Min) ^ ( 1 / Gamma)
+ // e = Min
+ // b=c=d=f=0
+
+ Params[0] = Colorant[n].Gamma;
+ Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
+ Params[2] = 0;
+ Params[3] = 0;
+ Params[4] = 0;
+ Params[5] = Colorant[n].Min;
+ Params[6] = 0;
+
+ Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
+ if (Curves[n] == NULL) goto Error;
+ }
+ }
+ break;
+
+ // Unsupported
+ default:
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
+ goto Error;
+ }
+
+ *nItems = 1;
+ return (void*) Curves;
+
+// Regret, free all resources
+Error:
+
+ cmsFreeToneCurveTriple(Curves);
+ _cmsFree(self ->ContextID, Curves);
+ return NULL;
+
+ cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+// We don't support all flavors, only 16bits tables and formula
+static
+cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
+ cmsUInt32Number i, j;
+
+ if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
+ cmsGetToneCurveParametricType(Curves[1]) == 5 &&
+ cmsGetToneCurveParametricType(Curves[2]) == 5) {
+
+ if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
+
+ // Save parameters
+ for (i=0; i < 3; i++) {
+
+ _cmsVCGTGAMMA v;
+
+ v.Gamma = Curves[i] ->Segments[0].Params[0];
+ v.Min = Curves[i] ->Segments[0].Params[5];
+ v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
+
+ if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
+ if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
+ }
+ }
+
+ else {
+
+ // Always store as a table of 256 words
+ if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
+ if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
+
+ for (i=0; i < 3; i++) {
+ for (j=0; j < 256; j++) {
+
+ cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
+ cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
+
+ if (!_cmsWriteUInt16Number(io, n)) return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(self);
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+static
+void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
+{
+ cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
+ cmsToneCurve** NewCurves;
+
+ NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
+ if (NewCurves == NULL) return NULL;
+
+ NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
+ NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
+ NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
+
+ return (void*) NewCurves;
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+
+static
+void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
+ _cmsFree(self ->ContextID, Ptr);
+}
+
+// ********************************************************************************
+// Type support main routines
+// ********************************************************************************
+
+
+// This is the list of built-in types
+static _cmsTagTypeLinkedList SupportedTagTypes[] = {
+
+{TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
+{TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] },
+{TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] },
+{TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] },
+{TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] },
+{TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] },
+{TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] },
+{TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] },
+{TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] },
+{TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] },
+{TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] },
+{TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] },
+{TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] },
+{TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] },
+{TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] },
+{TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] },
+{TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] },
+{TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] },
+{TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] },
+{TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] },
+{TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] },
+{TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] },
+{TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] },
+{TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] },
+{TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] },
+{TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] },
+{TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] },
+{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] },
+{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] },
+{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
+};
+
+#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList))
+
+// Both kind of plug-ins share same structure
+cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Data)
+{
+ return RegisterTypesPlugin(Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
+}
+
+cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Data)
+{
+ return RegisterTypesPlugin(Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
+}
+
+
+// Wrapper for tag types
+cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig)
+{
+ return GetHandler(sig, SupportedTagTypes);
+}
+
+// ********************************************************************************
+// Tag support main routines
+// ********************************************************************************
+
+typedef struct _cmsTagLinkedList_st {
+
+ cmsTagSignature Signature;
+ cmsTagDescriptor Descriptor;
+ struct _cmsTagLinkedList_st* Next;
+
+} _cmsTagLinkedList;
+
+// This is the list of built-in tags
+static _cmsTagLinkedList SupportedTags[] = {
+
+ { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
+ { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]},
+ { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]},
+ { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]},
+ { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]},
+ { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]},
+
+ // Allow corbis and its broken XYZ type
+ { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]},
+ { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]},
+ { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]},
+
+ { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]},
+ { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]},
+ { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]},
+
+ { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]},
+ { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]},
+
+ { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]},
+ { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]},
+ { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]},
+ { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]},
+ { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]},
+
+ { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]},
+ { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]},
+
+ { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]},
+ { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]},
+
+ { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]},
+
+ { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]},
+ { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]},
+
+ { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]},
+ { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]},
+
+ { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]},
+
+ { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]},
+ { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]},
+ { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
+
+ { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
+ { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
+ { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]},
+
+ { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
+ { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]},
+ { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]},
+
+ { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]},
+
+ { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]},
+ { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]},
+ { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]},
+ { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]},
+ { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]},
+ { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]},
+
+ { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]},
+
+ { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
+ { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
+
+ { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
+ { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
+ { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
+ { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
+ { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
+ { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
+ { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
+ { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
+
+ { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
+ { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
+
+ { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
+ { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
+ { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL}, NULL}
+
+};
+
+/*
+ Not supported Why
+ ======================= =========================================
+ cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
+ cmsSigNamedColorTag ==> Deprecated
+ cmsSigDataTag ==> Ancient, unused
+ cmsSigDeviceSettingsTag ==> Deprecated, useless
+*/
+
+#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList))
+
+cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data)
+{
+ cmsPluginTag* Plugin = (cmsPluginTag*) Data;
+ _cmsTagLinkedList *pt, *Anterior;
+
+
+ if (Data == NULL) {
+
+ SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL;
+ return TRUE;
+ }
+
+ pt = Anterior = SupportedTags;
+ while (pt != NULL) {
+
+ if (Plugin->Signature == pt -> Signature) {
+ pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour
+ return TRUE;
+ }
+
+ Anterior = pt;
+ pt = pt ->Next;
+ }
+
+ pt = (_cmsTagLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagLinkedList));
+ if (pt == NULL) return FALSE;
+
+ pt ->Signature = Plugin ->Signature;
+ pt ->Descriptor = Plugin ->Descriptor;
+ pt ->Next = NULL;
+
+ if (Anterior != NULL) Anterior -> Next = pt;
+
+ return TRUE;
+}
+
+// Return a descriptor for a given tag or NULL
+cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig)
+{
+ _cmsTagLinkedList* pt;
+
+ for (pt = SupportedTags;
+ pt != NULL;
+ pt = pt ->Next) {
+
+ if (sig == pt -> Signature) return &pt ->Descriptor;
+ }
+
+ return NULL;
+}
+
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,425 +49,313 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+//
+//---------------------------------------------------------------------------------
+//
-#include "lcms.h"
-
+#include "lcms2_internal.h"
// Virtual (built-in) profiles
// -----------------------------------------------------------------------------------
+static
+cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description)
+{
+ cmsMLU *DescriptionMLU, *CopyrightMLU;
+ cmsBool rc = FALSE;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+
+ DescriptionMLU = cmsMLUalloc(ContextID, 1);
+ CopyrightMLU = cmsMLUalloc(ContextID, 1);
+
+ if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error;
+
+ if (!cmsMLUsetWide(DescriptionMLU, "en", "US", Description)) goto Error;
+ if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error;
+
+ if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error;
+ if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error;
+
+ rc = TRUE;
+
+Error:
+
+ if (DescriptionMLU)
+ cmsMLUfree(DescriptionMLU);
+ if (CopyrightMLU)
+ cmsMLUfree(CopyrightMLU);
+ return rc;
+}
+
+
+static
+cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model)
+{
+ cmsBool rc = FALSE;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+ cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1);
+
+ if (Seq == NULL) return FALSE;
+
+ Seq->seq[0].deviceMfg = (cmsSignature) 0;
+ Seq->seq[0].deviceModel = (cmsSignature) 0;
+
+#ifdef CMS_DONT_USE_INT64
+ Seq->seq[0].attributes[0] = 0;
+ Seq->seq[0].attributes[1] = 0;
+#else
+ Seq->seq[0].attributes = 0;
+#endif
+
+ Seq->seq[0].technology = (cmsTechnologySignature) 0;
+
+ cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS");
+ cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model);
+
+ if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error;
+
+ rc = TRUE;
+
+Error:
+ if (Seq)
+ cmsFreeProfileSequenceDescription(Seq);
+
+ return rc;
+}
+
+
// This function creates a profile based on White point, primaries and
// transfer functions.
-
-
-cmsHPROFILE LCMSEXPORT cmsCreateRGBProfile(LPcmsCIExyY WhitePoint,
- LPcmsCIExyYTRIPLE Primaries,
- LPGAMMATABLE TransferFunction[3])
+cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID,
+ const cmsCIExyY* WhitePoint,
+ const cmsCIExyYTRIPLE* Primaries,
+ cmsToneCurve* const TransferFunction[3])
{
- cmsHPROFILE hICC;
- cmsCIEXYZ tmp;
- MAT3 MColorants;
- cmsCIEXYZTRIPLE Colorants;
- cmsCIExyY MaxWhite;
-
+ cmsHPROFILE hICC;
+ cmsMAT3 MColorants;
+ cmsCIEXYZTRIPLE Colorants;
+ cmsCIExyY MaxWhite;
+ cmsMAT3 CHAD;
+ cmsCIEXYZ WhitePointXYZ;
- hICC = _cmsCreateProfilePlaceholder();
- if (!hICC) // can't allocate
- return NULL;
+ hICC = cmsCreateProfilePlaceholder(ContextID);
+ if (!hICC) // can't allocate
+ return NULL;
+ cmsSetProfileVersion(hICC, 4.2);
- cmsSetDeviceClass(hICC, icSigDisplayClass);
- cmsSetColorSpace(hICC, icSigRgbData);
- cmsSetPCS(hICC, icSigXYZData);
- cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL);
+ cmsSetDeviceClass(hICC, cmsSigDisplayClass);
+ cmsSetColorSpace(hICC, cmsSigRgbData);
+ cmsSetPCS(hICC, cmsSigXYZData);
+
+ cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
- // Implement profile using following tags:
- //
- // 1 icSigProfileDescriptionTag
- // 2 icSigMediaWhitePointTag
- // 3 icSigRedColorantTag
- // 4 icSigGreenColorantTag
- // 5 icSigBlueColorantTag
- // 6 icSigRedTRCTag
- // 7 icSigGreenTRCTag
- // 8 icSigBlueTRCTag
-
- // This conforms a standard RGB DisplayProfile as says ICC, and then I add
-
- // 9 icSigChromaticityTag
-
- // As addendum II
+ // Implement profile using following tags:
+ //
+ // 1 cmsSigProfileDescriptionTag
+ // 2 cmsSigMediaWhitePointTag
+ // 3 cmsSigRedColorantTag
+ // 4 cmsSigGreenColorantTag
+ // 5 cmsSigBlueColorantTag
+ // 6 cmsSigRedTRCTag
+ // 7 cmsSigGreenTRCTag
+ // 8 cmsSigBlueTRCTag
+ // 9 Chromatic adaptation Tag
+ // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II)
+ // 10 cmsSigChromaticityTag
- // Fill-in the tags
+ if (!SetTextTags(hICC, L"RGB built-in")) goto Error;
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms RGB virtual profile");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "rgb built-in");
+ if (WhitePoint) {
+ if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
- if (WhitePoint) {
+ cmsxyY2XYZ(&WhitePointXYZ, WhitePoint);
+ _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ());
- cmsxyY2XYZ(&tmp, WhitePoint);
- cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) &tmp);
- }
+ // This is a V4 tag, but many CMM does read and understand it no matter which version
+ if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error;
+ }
- if (WhitePoint && Primaries) {
+ if (WhitePoint && Primaries) {
MaxWhite.x = WhitePoint -> x;
MaxWhite.y = WhitePoint -> y;
MaxWhite.Y = 1.0;
- if (!cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries))
- {
- cmsCloseProfile(hICC);
- return NULL;
- }
+ if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error;
- cmsAdaptMatrixToD50(&MColorants, &MaxWhite);
-
- Colorants.Red.X = MColorants.v[0].n[0];
- Colorants.Red.Y = MColorants.v[1].n[0];
- Colorants.Red.Z = MColorants.v[2].n[0];
+ Colorants.Red.X = MColorants.v[0].n[0];
+ Colorants.Red.Y = MColorants.v[1].n[0];
+ Colorants.Red.Z = MColorants.v[2].n[0];
- Colorants.Green.X = MColorants.v[0].n[1];
- Colorants.Green.Y = MColorants.v[1].n[1];
- Colorants.Green.Z = MColorants.v[2].n[1];
+ Colorants.Green.X = MColorants.v[0].n[1];
+ Colorants.Green.Y = MColorants.v[1].n[1];
+ Colorants.Green.Z = MColorants.v[2].n[1];
- Colorants.Blue.X = MColorants.v[0].n[2];
- Colorants.Blue.Y = MColorants.v[1].n[2];
- Colorants.Blue.Z = MColorants.v[2].n[2];
+ Colorants.Blue.X = MColorants.v[0].n[2];
+ Colorants.Blue.Y = MColorants.v[1].n[2];
+ Colorants.Blue.Z = MColorants.v[2].n[2];
- cmsAddTag(hICC, icSigRedColorantTag, (LPVOID) &Colorants.Red);
- cmsAddTag(hICC, icSigBlueColorantTag, (LPVOID) &Colorants.Blue);
- cmsAddTag(hICC, icSigGreenColorantTag, (LPVOID) &Colorants.Green);
- }
+ if (!cmsWriteTag(hICC, cmsSigRedColorantTag, (void*) &Colorants.Red)) goto Error;
+ if (!cmsWriteTag(hICC, cmsSigBlueColorantTag, (void*) &Colorants.Blue)) goto Error;
+ if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error;
+ }
- if (TransferFunction) {
+ if (TransferFunction) {
- // In case of gamma, we must dup' the table pointer
+ if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error;
+ if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error;
+ if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error;
+ }
+
+ if (Primaries) {
+ if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error;
+ }
+
- cmsAddTag(hICC, icSigRedTRCTag, (LPVOID) TransferFunction[0]);
- cmsAddTag(hICC, icSigGreenTRCTag, (LPVOID) TransferFunction[1]);
- cmsAddTag(hICC, icSigBlueTRCTag, (LPVOID) TransferFunction[2]);
- }
+ return hICC;
- if (Primaries) {
- cmsAddTag(hICC, icSigChromaticityTag, (LPVOID) Primaries);
- }
+Error:
+ if (hICC)
+ cmsCloseProfile(hICC);
+ return NULL;
+}
- return hICC;
+cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint,
+ const cmsCIExyYTRIPLE* Primaries,
+ cmsToneCurve* const TransferFunction[3])
+{
+ return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction);
}
// This function creates a profile based on White point and transfer function.
-
-cmsHPROFILE LCMSEXPORT cmsCreateGrayProfile(LPcmsCIExyY WhitePoint,
- LPGAMMATABLE TransferFunction)
+cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID,
+ const cmsCIExyY* WhitePoint,
+ const cmsToneCurve* TransferFunction)
{
- cmsHPROFILE hICC;
- cmsCIEXYZ tmp;
-
-
- hICC = _cmsCreateProfilePlaceholder();
- if (!hICC) // can't allocate
- return NULL;
-
-
- cmsSetDeviceClass(hICC, icSigDisplayClass);
- cmsSetColorSpace(hICC, icSigGrayData);
- cmsSetPCS(hICC, icSigXYZData);
- cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL);
-
-
-
- // Implement profile using following tags:
- //
- // 1 icSigProfileDescriptionTag
- // 2 icSigMediaWhitePointTag
- // 6 icSigGrayTRCTag
+ cmsHPROFILE hICC;
+ cmsCIEXYZ tmp;
- // This conforms a standard Gray DisplayProfile
-
- // Fill-in the tags
-
-
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms gray virtual profile");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "gray built-in");
-
-
- if (WhitePoint) {
+ hICC = cmsCreateProfilePlaceholder(ContextID);
+ if (!hICC) // can't allocate
+ return NULL;
- cmsxyY2XYZ(&tmp, WhitePoint);
- cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) &tmp);
- }
-
-
- if (TransferFunction) {
+ cmsSetProfileVersion(hICC, 4.2);
- // In case of gamma, we must dup' the table pointer
-
- cmsAddTag(hICC, icSigGrayTRCTag, (LPVOID) TransferFunction);
- }
-
- return hICC;
-
-}
+ cmsSetDeviceClass(hICC, cmsSigDisplayClass);
+ cmsSetColorSpace(hICC, cmsSigGrayData);
+ cmsSetPCS(hICC, cmsSigXYZData);
+ cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
-static
-int IsPCS(icColorSpaceSignature ColorSpace)
-{
- return (ColorSpace == icSigXYZData ||
- ColorSpace == icSigLabData);
-}
+ // Implement profile using following tags:
+ //
+ // 1 cmsSigProfileDescriptionTag
+ // 2 cmsSigMediaWhitePointTag
+ // 3 cmsSigGrayTRCTag
-static
-void FixColorSpaces(cmsHPROFILE hProfile,
- icColorSpaceSignature ColorSpace,
- icColorSpaceSignature PCS,
- DWORD dwFlags)
-{
-
- if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) {
-
- if (IsPCS(ColorSpace) && IsPCS(PCS)) {
+ // This conforms a standard Gray DisplayProfile
- cmsSetDeviceClass(hProfile, icSigAbstractClass);
- cmsSetColorSpace(hProfile, ColorSpace);
- cmsSetPCS(hProfile, PCS);
- return;
- }
+ // Fill-in the tags
- if (IsPCS(ColorSpace) && !IsPCS(PCS)) {
+ if (!SetTextTags(hICC, L"gray built-in")) goto Error;
+
- cmsSetDeviceClass(hProfile, icSigOutputClass);
- cmsSetPCS(hProfile, ColorSpace);
- cmsSetColorSpace(hProfile, PCS);
- return;
- }
+ if (WhitePoint) {
- if (IsPCS(PCS) && !IsPCS(ColorSpace)) {
-
- cmsSetDeviceClass(hProfile, icSigInputClass);
- cmsSetColorSpace(hProfile, ColorSpace);
- cmsSetPCS(hProfile, PCS);
- return;
- }
+ cmsxyY2XYZ(&tmp, WhitePoint);
+ if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error;
}
- cmsSetDeviceClass(hProfile, icSigLinkClass);
- cmsSetColorSpace(hProfile, ColorSpace);
- cmsSetPCS(hProfile, PCS);
-
-}
-
-
-static
-cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
-{
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
- cmsHPROFILE hICC;
- cmsCIEXYZ WhitePoint;
- int i, nColors;
- size_t Size;
- LPcmsNAMEDCOLORLIST nc2;
-
-
- hICC = _cmsCreateProfilePlaceholder();
- if (hICC == NULL) return NULL;
+ if (TransferFunction) {
- cmsSetRenderingIntent(hICC, v -> Intent);
- cmsSetDeviceClass(hICC, icSigNamedColorClass);
- cmsSetColorSpace(hICC, v ->ExitColorSpace);
- cmsSetPCS(hICC, cmsGetPCS(v ->InputProfile));
- cmsTakeMediaWhitePoint(&WhitePoint, v ->InputProfile);
-
- cmsAddTag(hICC, icSigMediaWhitePointTag, &WhitePoint);
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "LittleCMS");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "Named color Device link");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "Named color Device link");
-
-
- nColors = cmsNamedColorCount(xform);
- nc2 = cmsAllocNamedColorList(nColors);
-
- Size = sizeof(cmsNAMEDCOLORLIST) + (sizeof(cmsNAMEDCOLOR) * (nColors-1));
-
- CopyMemory(nc2, v->NamedColorList, Size);
- nc2 ->ColorantCount = _cmsChannelsOf(v ->ExitColorSpace);
-
- for (i=0; i < nColors; i++) {
- cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1);
+ if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error;
}
- cmsAddTag(hICC, icSigNamedColor2Tag, (void*) nc2);
- cmsFreeNamedColorList(nc2);
+ return hICC;
- return hICC;
+Error:
+ if (hICC)
+ cmsCloseProfile(hICC);
+ return NULL;
}
-// Does convert a transform into a device link profile
-cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags)
+cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint,
+ const cmsToneCurve* TransferFunction)
+{
+ return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction);
+}
+
+// This is a devicelink operating in the target colorspace with as many transfer functions as components
+
+cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
+ cmsColorSpaceSignature ColorSpace,
+ cmsToneCurve* const TransferFunctions[])
{
cmsHPROFILE hICC;
- _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) hTransform;
- LPLUT Lut;
- LCMSBOOL MustFreeLUT;
- LPcmsNAMEDCOLORLIST InputColorant = NULL;
- LPcmsNAMEDCOLORLIST OutputColorant = NULL;
-
-
- // Check if is a named color transform
-
- if (cmsGetDeviceClass(v ->InputProfile) == icSigNamedColorClass) {
-
- return CreateNamedColorDevicelink(hTransform);
-
- }
+ cmsPipeline* Pipeline;
+ cmsStage* Lin;
+ int nChannels;
- if (v ->DeviceLink) {
-
- Lut = v -> DeviceLink;
- MustFreeLUT = FALSE;
- }
- else {
+ hICC = cmsCreateProfilePlaceholder(ContextID);
+ if (!hICC)
+ return NULL;
- Lut = _cmsPrecalculateDeviceLink(hTransform, dwFlags);
- if (!Lut) return NULL;
- MustFreeLUT = TRUE;
- }
-
- hICC = _cmsCreateProfilePlaceholder();
- if (!hICC) { // can't allocate
+ cmsSetProfileVersion(hICC, 4.2);
- if (MustFreeLUT) cmsFreeLUT(Lut);
- return NULL;
- }
-
-
- FixColorSpaces(hICC, v -> EntryColorSpace, v -> ExitColorSpace, dwFlags);
+ cmsSetDeviceClass(hICC, cmsSigLinkClass);
+ cmsSetColorSpace(hICC, ColorSpace);
+ cmsSetPCS(hICC, ColorSpace);
- cmsSetRenderingIntent(hICC, v -> Intent);
-
- // Implement devicelink profile using following tags:
- //
- // 1 icSigProfileDescriptionTag
- // 2 icSigMediaWhitePointTag
- // 3 icSigAToB0Tag
+ cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
-
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "LittleCMS");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "Device link");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "Device link");
-
-
- cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
+ // Set up channels
+ nChannels = cmsChannelsOf(ColorSpace);
- if (cmsGetDeviceClass(hICC) == icSigOutputClass) {
-
- cmsAddTag(hICC, icSigBToA0Tag, (LPVOID) Lut);
- }
- else
- cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut);
-
+ // Creates a Pipeline with prelinearization step only
+ Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels);
+ if (Pipeline == NULL) goto Error;
- // Try to read input and output colorant table
- if (cmsIsTag(v ->InputProfile, icSigColorantTableTag)) {
-
- // Input table can only come in this way.
- InputColorant = cmsReadColorantTable(v ->InputProfile, icSigColorantTableTag);
- }
+ // Copy tables to Pipeline
+ Lin = cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions);
+ if (Lin == NULL) goto Error;
- // Output is a little bit more complex.
- if (cmsGetDeviceClass(v ->OutputProfile) == icSigLinkClass) {
-
- // This tag may exist only on devicelink profiles.
- if (cmsIsTag(v ->OutputProfile, icSigColorantTableOutTag)) {
-
- OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableOutTag);
- }
-
- } else {
+ cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Lin);
- if (cmsIsTag(v ->OutputProfile, icSigColorantTableTag)) {
-
- OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableTag);
- }
- }
-
- if (InputColorant)
- cmsAddTag(hICC, icSigColorantTableTag, InputColorant);
+ // Create tags
+ if (!SetTextTags(hICC, L"Linearization built-in")) goto Error;
+ if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error;
+ if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error;
- if (OutputColorant)
- cmsAddTag(hICC, icSigColorantTableOutTag, OutputColorant);
-
-
+ // Pipeline is already on virtual profile
+ cmsPipelineFree(Pipeline);
- if (MustFreeLUT) cmsFreeLUT(Lut);
- if (InputColorant) cmsFreeNamedColorList(InputColorant);
- if (OutputColorant) cmsFreeNamedColorList(OutputColorant);
-
+ // Ok, done
return hICC;
-}
+Error:
+ if (hICC)
+ cmsCloseProfile(hICC);
-// This is a devicelink operating in the target colorspace with as many transfer
-// functions as components
-
-cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature ColorSpace,
- LPGAMMATABLE TransferFunctions[])
-{
- cmsHPROFILE hICC;
- LPLUT Lut;
-
-
- hICC = _cmsCreateProfilePlaceholder();
- if (!hICC) // can't allocate
- return NULL;
-
-
- cmsSetDeviceClass(hICC, icSigLinkClass);
- cmsSetColorSpace(hICC, ColorSpace);
- cmsSetPCS(hICC, ColorSpace);
- cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL);
-
-
- // Creates a LUT with prelinearization step only
- Lut = cmsAllocLUT();
- if (Lut == NULL) return NULL;
-
- // Set up channels
- Lut ->InputChan = Lut ->OutputChan = _cmsChannelsOf(ColorSpace);
-
- // Copy tables to LUT
- cmsAllocLinearTable(Lut, TransferFunctions, 1);
-
- // Create tags
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms linearization device link");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "linearization built-in");
-
- cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
- cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut);
-
- // LUT is already on virtual profile
- cmsFreeLUT(Lut);
-
- // Ok, done
- return hICC;
+ return NULL;
}
+cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace,
+ cmsToneCurve* const TransferFunctions[])
+{
+ return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions);
+}
// Ink-limiting algorithm
//
@@ -486,257 +375,282 @@
// K: Does not change
static
-int InkLimitingSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+int InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
- double InkLimit = *(double *) Cargo;
- double SumCMY, SumCMYK, Ratio;
+ cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo;
+ cmsFloat64Number SumCMY, SumCMYK, Ratio;
- InkLimit = (InkLimit * 655.35);
+ InkLimit = (InkLimit * 655.35);
- SumCMY = In[0] + In[1] + In[2];
- SumCMYK = SumCMY + In[3];
+ SumCMY = In[0] + In[1] + In[2];
+ SumCMYK = SumCMY + In[3];
- if (SumCMYK > InkLimit) {
+ if (SumCMYK > InkLimit) {
- Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY);
- if (Ratio < 0)
- Ratio = 0;
- }
- else Ratio = 1;
+ Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY);
+ if (Ratio < 0)
+ Ratio = 0;
+ }
+ else Ratio = 1;
- Out[0] = (WORD) floor(In[0] * Ratio + 0.5); // C
- Out[1] = (WORD) floor(In[1] * Ratio + 0.5); // M
- Out[2] = (WORD) floor(In[2] * Ratio + 0.5); // Y
+ Out[0] = _cmsQuickSaturateWord(In[0] * Ratio); // C
+ Out[1] = _cmsQuickSaturateWord(In[1] * Ratio); // M
+ Out[2] = _cmsQuickSaturateWord(In[2] * Ratio); // Y
- Out[3] = In[3]; // K (untouched)
+ Out[3] = In[3]; // K (untouched)
- return TRUE;
+ return TRUE;
}
// This is a devicelink operating in CMYK for ink-limiting
-cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature ColorSpace,
- double Limit)
+cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
+ cmsColorSpaceSignature ColorSpace,
+ cmsFloat64Number Limit)
{
- cmsHPROFILE hICC;
- LPLUT Lut;
+ cmsHPROFILE hICC;
+ cmsPipeline* LUT;
+ cmsStage* CLUT;
+ int nChannels;
- if (ColorSpace != icSigCmykData) {
- cmsSignalError(LCMS_ERRC_ABORTED, "InkLimiting: Only CMYK currently supported");
- return NULL;
- }
+ if (ColorSpace != cmsSigCmykData) {
+ cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported");
+ return NULL;
+ }
- if (Limit < 0.0 || Limit > 400) {
-
- cmsSignalError(LCMS_ERRC_WARNING, "InkLimiting: Limit should be between 0..400");
- if (Limit < 0) Limit = 0;
- if (Limit > 400) Limit = 400;
+ if (Limit < 0.0 || Limit > 400) {
- }
+ cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400");
+ if (Limit < 0) Limit = 0;
+ if (Limit > 400) Limit = 400;
- hICC = _cmsCreateProfilePlaceholder();
- if (!hICC) // can't allocate
- return NULL;
-
+ }
- cmsSetDeviceClass(hICC, icSigLinkClass);
- cmsSetColorSpace(hICC, ColorSpace);
- cmsSetPCS(hICC, ColorSpace);
- cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL);
+ hICC = cmsCreateProfilePlaceholder(ContextID);
+ if (!hICC) // can't allocate
+ return NULL;
+ cmsSetProfileVersion(hICC, 4.2);
- // Creates a LUT with 3D grid only
- Lut = cmsAllocLUT();
- if (Lut == NULL) {
- cmsCloseProfile(hICC);
- return NULL;
- }
+ cmsSetDeviceClass(hICC, cmsSigLinkClass);
+ cmsSetColorSpace(hICC, ColorSpace);
+ cmsSetPCS(hICC, ColorSpace);
+
+ cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
- cmsAlloc3DGrid(Lut, 17, _cmsChannelsOf(ColorSpace),
- _cmsChannelsOf(ColorSpace));
-
- if (!cmsSample3DGrid(Lut, InkLimitingSampler, (LPVOID) &Limit, 0)) {
-
- // Shouldn't reach here
- cmsFreeLUT(Lut);
- cmsCloseProfile(hICC);
- return NULL;
- }
-
- // Create tags
-
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms ink limiting device link");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "ink limiting built-in");
-
- cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
-
- cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut);
-
- // LUT is already on virtual profile
- cmsFreeLUT(Lut);
-
- // Ok, done
- return hICC;
-}
-
+ // Creates a Pipeline with 3D grid only
+ LUT = cmsPipelineAlloc(ContextID, 4, 4);
+ if (LUT == NULL) goto Error;
-static
-LPLUT Create3x3EmptyLUT(void)
-{
- LPLUT AToB0 = cmsAllocLUT();
- if (AToB0 == NULL) return NULL;
+ nChannels = cmsChannelsOf(ColorSpace);
+
+ CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL);
+ if (CLUT == NULL) goto Error;
+
+ if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error;
+
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels));
+ cmsPipelineInsertStage(LUT, cmsAT_END, CLUT);
+ cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels));
+
+ // Create tags
+ if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error;
- AToB0 -> InputChan = AToB0 -> OutputChan = 3;
- return AToB0;
+ if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error;
+ if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error;
+
+ // cmsPipeline is already on virtual profile
+ cmsPipelineFree(LUT);
+
+ // Ok, done
+ return hICC;
+
+Error:
+ if (LUT != NULL)
+ cmsPipelineFree(LUT);
+
+ if (hICC != NULL)
+ cmsCloseProfile(hICC);
+
+ return NULL;
}
-
-
-// Creates a fake Lab identity.
-cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint)
+cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit)
{
- cmsHPROFILE hProfile;
- LPLUT Lut;
-
- hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
- if (hProfile == NULL) return NULL;
-
- cmsSetDeviceClass(hProfile, icSigAbstractClass);
- cmsSetColorSpace(hProfile, icSigLabData);
- cmsSetPCS(hProfile, icSigLabData);
-
- cmsAddTag(hProfile, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hProfile, icSigProfileDescriptionTag, (LPVOID) "lcms Lab identity");
- cmsAddTag(hProfile, icSigDeviceModelDescTag, (LPVOID) "Lab built-in");
-
-
- // An empty LUTs is all we need
- Lut = Create3x3EmptyLUT();
- if (Lut == NULL) {
- cmsCloseProfile(hProfile);
- return NULL;
- }
-
- cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut);
- cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut);
-
- cmsFreeLUT(Lut);
-
- return hProfile;
+ return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit);
}
// Creates a fake Lab identity.
-cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint)
+cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint)
{
- cmsHPROFILE hProfile;
- LPLUT Lut;
+ cmsHPROFILE hProfile;
+ cmsPipeline* LUT = NULL;
+
+ hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
+ if (hProfile == NULL) return NULL;
- hProfile = cmsCreateRGBProfile(WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
- if (hProfile == NULL) return NULL;
+ cmsSetProfileVersion(hProfile, 2.1);
+
+ cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
+ cmsSetColorSpace(hProfile, cmsSigLabData);
+ cmsSetPCS(hProfile, cmsSigLabData);
+
+ if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL;
- cmsSetProfileICCversion(hProfile, 0x4000000);
+ // An identity LUT is all we need
+ LUT = cmsPipelineAlloc(ContextID, 3, 3);
+ if (LUT == NULL) goto Error;
+
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3));
+
+ if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
+ cmsPipelineFree(LUT);
+
+ return hProfile;
- cmsSetDeviceClass(hProfile, icSigAbstractClass);
- cmsSetColorSpace(hProfile, icSigLabData);
- cmsSetPCS(hProfile, icSigLabData);
+Error:
+
+ if (LUT != NULL)
+ cmsPipelineFree(LUT);
- cmsAddTag(hProfile, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hProfile, icSigProfileDescriptionTag, (LPVOID) "lcms Lab identity v4");
- cmsAddTag(hProfile, icSigDeviceModelDescTag, (LPVOID) "Lab v4 built-in");
+ if (hProfile != NULL)
+ cmsCloseProfile(hProfile);
+
+ return NULL;
+}
- // An empty LUTs is all we need
- Lut = Create3x3EmptyLUT();
- if (Lut == NULL) {
- cmsCloseProfile(hProfile);
- return NULL;
- }
-
- Lut -> wFlags |= LUT_V4_INPUT_EMULATE_V2;
- cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut);
-
- Lut -> wFlags |= LUT_V4_OUTPUT_EMULATE_V2;
- cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut);
-
- cmsFreeLUT(Lut);
-
- return hProfile;
+cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint)
+{
+ return cmsCreateLab2ProfileTHR(NULL, WhitePoint);
}
+// Creates a fake Lab V4 identity.
+cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint)
+{
+ cmsHPROFILE hProfile;
+ cmsPipeline* LUT = NULL;
+
+ hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
+ if (hProfile == NULL) return NULL;
+
+ cmsSetProfileVersion(hProfile, 4.2);
+
+ cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
+ cmsSetColorSpace(hProfile, cmsSigLabData);
+ cmsSetPCS(hProfile, cmsSigLabData);
+
+ if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error;
+
+ // An empty LUTs is all we need
+ LUT = cmsPipelineAlloc(ContextID, 3, 3);
+ if (LUT == NULL) goto Error;
+
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3));
+
+ if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
+ cmsPipelineFree(LUT);
+
+ return hProfile;
+
+Error:
+
+ if (LUT != NULL)
+ cmsPipelineFree(LUT);
+
+ if (hProfile != NULL)
+ cmsCloseProfile(hProfile);
+
+ return NULL;
+}
+
+cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint)
+{
+ return cmsCreateLab4ProfileTHR(NULL, WhitePoint);
+}
+
// Creates a fake XYZ identity
-cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void)
+cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID)
{
- cmsHPROFILE hProfile;
- LPLUT Lut;
+ cmsHPROFILE hProfile;
+ cmsPipeline* LUT = NULL;
+
+ hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL);
+ if (hProfile == NULL) return NULL;
- hProfile = cmsCreateRGBProfile(cmsD50_xyY(), NULL, NULL);
- if (hProfile == NULL) return NULL;
+ cmsSetProfileVersion(hProfile, 4.2);
- cmsSetDeviceClass(hProfile, icSigAbstractClass);
- cmsSetColorSpace(hProfile, icSigXYZData);
- cmsSetPCS(hProfile, icSigXYZData);
+ cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
+ cmsSetColorSpace(hProfile, cmsSigXYZData);
+ cmsSetPCS(hProfile, cmsSigXYZData);
+
+ if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error;
- cmsAddTag(hProfile, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hProfile, icSigProfileDescriptionTag, (LPVOID) "lcms XYZ identity");
- cmsAddTag(hProfile, icSigDeviceModelDescTag, (LPVOID) "XYZ built-in");
+ // An identity LUT is all we need
+ LUT = cmsPipelineAlloc(ContextID, 3, 3);
+ if (LUT == NULL) goto Error;
+
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3));
+
+ if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
+ cmsPipelineFree(LUT);
- // An empty LUTs is all we need
- Lut = Create3x3EmptyLUT();
- if (Lut == NULL) {
- cmsCloseProfile(hProfile);
- return NULL;
- }
+ return hProfile;
+
+Error:
- cmsAddTag(hProfile, icSigAToB0Tag, (LPVOID) Lut);
- cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut);
- cmsAddTag(hProfile, icSigPreview0Tag, (LPVOID) Lut);
+ if (LUT != NULL)
+ cmsPipelineFree(LUT);
- cmsFreeLUT(Lut);
- return hProfile;
+ if (hProfile != NULL)
+ cmsCloseProfile(hProfile);
+
+ return NULL;
}
-
-/*
-
-If R’sRGB,G’sRGB, B’sRGB < 0.04045
-
- R = R’sRGB / 12.92
- G = G’sRGB / 12.92
- B = B’sRGB / 12.92
-
+cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void)
+{
+ return cmsCreateXYZProfileTHR(NULL);
+}
-else if R’sRGB,G’sRGB, B’sRGB >= 0.04045
-
- R = ((R’sRGB + 0.055) / 1.055)^2.4
- G = ((G’sRGB + 0.055) / 1.055)^2.4
- B = ((B’sRGB + 0.055) / 1.055)^2.4
-
- */
+//sRGB Curves are defined by:
+//
+//If R’sRGB,G’sRGB, B’sRGB < 0.04045
+//
+// R = R’sRGB / 12.92
+// G = G’sRGB / 12.92
+// B = B’sRGB / 12.92
+//
+//
+//else if R’sRGB,G’sRGB, B’sRGB >= 0.04045
+//
+// R = ((R’sRGB + 0.055) / 1.055)^2.4
+// G = ((G’sRGB + 0.055) / 1.055)^2.4
+// B = ((B’sRGB + 0.055) / 1.055)^2.4
static
-LPGAMMATABLE Build_sRGBGamma(void)
+cmsToneCurve* Build_sRGBGamma(cmsContext ContextID)
{
- double Parameters[5];
+ cmsFloat64Number Parameters[5];
Parameters[0] = 2.4;
Parameters[1] = 1. / 1.055;
Parameters[2] = 0.055 / 1.055;
Parameters[3] = 1. / 12.92;
- Parameters[4] = 0.04045; // d
+ Parameters[4] = 0.04045;
- return cmsBuildParametricGamma(1024, 4, Parameters);
+ return cmsBuildParametricToneCurve(ContextID, 4, Parameters);
}
// Create the ICC virtual profile for sRGB space
-cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void)
+cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID)
{
cmsCIExyY D65;
cmsCIExyYTRIPLE Rec709Primaries = {
@@ -744,38 +658,44 @@
{0.3000, 0.6000, 1.0},
{0.1500, 0.0600, 1.0}
};
- LPGAMMATABLE Gamma22[3];
+ cmsToneCurve* Gamma22[3];
cmsHPROFILE hsRGB;
- cmsWhitePointFromTemp(6504, &D65);
- Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma();
+ cmsWhitePointFromTemp(&D65, 6504);
+ Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID);
+ if (Gamma22[0] == NULL) return NULL;
- hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma22);
- cmsFreeGamma(Gamma22[0]);
+ hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22);
+ cmsFreeToneCurve(Gamma22[0]);
if (hsRGB == NULL) return NULL;
-
- cmsAddTag(hsRGB, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hsRGB, icSigDeviceModelDescTag, (LPVOID) "sRGB built-in");
- cmsAddTag(hsRGB, icSigProfileDescriptionTag, (LPVOID) "sRGB built-in");
+ if (!SetTextTags(hsRGB, L"sRGB built-in")) {
+ cmsCloseProfile(hsRGB);
+ return NULL;
+ }
return hsRGB;
}
+cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void)
+{
+ return cmsCreate_sRGBProfileTHR(NULL);
+}
+
typedef struct {
- double Brightness;
- double Contrast;
- double Hue;
- double Saturation;
+ cmsFloat64Number Brightness;
+ cmsFloat64Number Contrast;
+ cmsFloat64Number Hue;
+ cmsFloat64Number Saturation;
cmsCIEXYZ WPsrc, WPdest;
} BCHSWADJUSTS, *LPBCHSWADJUSTS;
static
-int bchswSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
cmsCIELab LabIn, LabOut;
cmsCIELCh LChIn, LChOut;
@@ -813,116 +733,438 @@
// Creates an abstract profile operating in Lab space for Brightness,
// contrast, Saturation and white point displacement
-cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
- double Bright,
- double Contrast,
- double Hue,
- double Saturation,
+cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
+ int nLUTPoints,
+ cmsFloat64Number Bright,
+ cmsFloat64Number Contrast,
+ cmsFloat64Number Hue,
+ cmsFloat64Number Saturation,
int TempSrc,
int TempDest)
{
cmsHPROFILE hICC;
- LPLUT Lut;
+ cmsPipeline* Pipeline;
BCHSWADJUSTS bchsw;
cmsCIExyY WhitePnt;
+ cmsStage* CLUT;
+ cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
+ int i;
+
bchsw.Brightness = Bright;
bchsw.Contrast = Contrast;
bchsw.Hue = Hue;
bchsw.Saturation = Saturation;
- cmsWhitePointFromTemp(TempSrc, &WhitePnt);
+ cmsWhitePointFromTemp(&WhitePnt, TempSrc );
cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
- cmsWhitePointFromTemp(TempDest, &WhitePnt);
+ cmsWhitePointFromTemp(&WhitePnt, TempDest);
cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt);
- hICC = _cmsCreateProfilePlaceholder();
+ hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC) // can't allocate
return NULL;
- cmsSetDeviceClass(hICC, icSigAbstractClass);
- cmsSetColorSpace(hICC, icSigLabData);
- cmsSetPCS(hICC, icSigLabData);
+ cmsSetDeviceClass(hICC, cmsSigAbstractClass);
+ cmsSetColorSpace(hICC, cmsSigLabData);
+ cmsSetPCS(hICC, cmsSigLabData);
- cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL);
+ cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
- // Creates a LUT with 3D grid only
- Lut = cmsAllocLUT();
- if (Lut == NULL) {
+ // Creates a Pipeline with 3D grid only
+ Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
+ if (Pipeline == NULL) {
cmsCloseProfile(hICC);
return NULL;
}
- cmsAlloc3DGrid(Lut, nLUTPoints, 3, 3);
+ for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints;
+ CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
+ if (CLUT == NULL) return NULL;
- if (!cmsSample3DGrid(Lut, bchswSampler, (LPVOID) &bchsw, 0)) {
+
+ if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
// Shouldn't reach here
- cmsFreeLUT(Lut);
+ cmsPipelineFree(Pipeline);
cmsCloseProfile(hICC);
return NULL;
}
+ cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT);
+
// Create tags
- cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)");
- cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms BCHSW abstract profile");
- cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "BCHSW built-in");
+ if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
+
+ cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
- cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
+ cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
- cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut);
-
- // LUT is already on virtual profile
- cmsFreeLUT(Lut);
+ // Pipeline is already on virtual profile
+ cmsPipelineFree(Pipeline);
// Ok, done
return hICC;
+}
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
+ cmsFloat64Number Bright,
+ cmsFloat64Number Contrast,
+ cmsFloat64Number Hue,
+ cmsFloat64Number Saturation,
+ int TempSrc,
+ int TempDest)
+{
+ return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest);
}
// Creates a fake NULL profile. This profile return 1 channel as always 0.
// Is useful only for gamut checking tricks
-
-cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void)
+cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
{
- cmsHPROFILE hProfile;
- LPLUT Lut;
- LPGAMMATABLE EmptyTab;
+ cmsHPROFILE hProfile;
+ cmsPipeline* LUT = NULL;
+ cmsStage* PostLin;
+ cmsToneCurve* EmptyTab;
+ cmsUInt16Number Zero[2] = { 0, 0 };
+
+ hProfile = cmsCreateProfilePlaceholder(ContextID);
+ if (!hProfile) // can't allocate
+ return NULL;
+
+ cmsSetProfileVersion(hProfile, 4.2);
+
+ if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error;
+
+
+
+ cmsSetDeviceClass(hProfile, cmsSigOutputClass);
+ cmsSetColorSpace(hProfile, cmsSigGrayData);
+ cmsSetPCS(hProfile, cmsSigLabData);
+
+ // An empty LUTs is all we need
+ LUT = cmsPipelineAlloc(ContextID, 1, 1);
+ if (LUT == NULL) goto Error;
+
+ EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
+ PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab);
+ cmsFreeToneCurve(EmptyTab);
+
+ cmsPipelineInsertStage(LUT, cmsAT_END, PostLin);
+
+ if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error;
+ if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
+
+ cmsPipelineFree(LUT);
+ return hProfile;
+
+Error:
+
+ if (LUT != NULL)
+ cmsPipelineFree(LUT);
+
+ if (hProfile != NULL)
+ cmsCloseProfile(hProfile);
+
+ return NULL;
+}
+
+cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void)
+{
+ return cmsCreateNULLProfileTHR(NULL);
+}
+
+
+static
+int IsPCS(cmsColorSpaceSignature ColorSpace)
+{
+ return (ColorSpace == cmsSigXYZData ||
+ ColorSpace == cmsSigLabData);
+}
+
+
+static
+void FixColorSpaces(cmsHPROFILE hProfile,
+ cmsColorSpaceSignature ColorSpace,
+ cmsColorSpaceSignature PCS,
+ cmsUInt32Number dwFlags)
+{
+ if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) {
+
+ if (IsPCS(ColorSpace) && IsPCS(PCS)) {
- hProfile = _cmsCreateProfilePlaceholder();
- if (!hProfile) // can't allocate
- return NULL;
+ cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
+ cmsSetColorSpace(hProfile, ColorSpace);
+ cmsSetPCS(hProfile, PCS);
+ return;
+ }
+
+ if (IsPCS(ColorSpace) && !IsPCS(PCS)) {
+
+ cmsSetDeviceClass(hProfile, cmsSigOutputClass);
+ cmsSetPCS(hProfile, ColorSpace);
+ cmsSetColorSpace(hProfile, PCS);
+ return;
+ }
+
+ if (IsPCS(PCS) && !IsPCS(ColorSpace)) {
+
+ cmsSetDeviceClass(hProfile, cmsSigInputClass);
+ cmsSetColorSpace(hProfile, ColorSpace);
+ cmsSetPCS(hProfile, PCS);
+ return;
+ }
+ }
+
+ cmsSetDeviceClass(hProfile, cmsSigLinkClass);
+ cmsSetColorSpace(hProfile, ColorSpace);
+ cmsSetPCS(hProfile, PCS);
+}
+
+
- cmsSetDeviceClass(hProfile, icSigOutputClass);
- cmsSetColorSpace(hProfile, icSigGrayData);
- cmsSetPCS(hProfile, icSigLabData);
+// This function creates a named color profile dumping all the contents of transform to a single profile
+// In this way, LittleCMS may be used to "group" several named color databases into a single profile.
+// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this
+// is the normal PCS for named color profiles.
+static
+cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
+{
+ _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
+ cmsHPROFILE hICC = NULL;
+ int i, nColors;
+ cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL;
+
+ // Create an empty placeholder
+ hICC = cmsCreateProfilePlaceholder(v->ContextID);
+ if (hICC == NULL) return NULL;
+
+ // Critical information
+ cmsSetDeviceClass(hICC, cmsSigNamedColorClass);
+ cmsSetColorSpace(hICC, v ->ExitColorSpace);
+ cmsSetPCS(hICC, cmsSigLabData);
+
+ // Tag profile with information
+ if (!SetTextTags(hICC, L"Named color devicelink")) goto Error;
+
+ Original = cmsGetNamedColorList(xform);
+ if (Original == NULL) goto Error;
+
+ nColors = cmsNamedColorCount(Original);
+ nc2 = cmsDupNamedColorList(Original);
+ if (nc2 == NULL) goto Error;
+
+ // Colorant count now depends on the output space
+ nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut);
+
+ // Apply the transfor to colorants.
+ for (i=0; i < nColors; i++) {
+ cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1);
+ }
+
+ if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error;
+ cmsFreeNamedColorList(nc2);
+
+ return hICC;
+
+Error:
+ if (hICC != NULL) cmsCloseProfile(hICC);
+ return NULL;
+}
- // An empty LUTs is all we need
- Lut = cmsAllocLUT();
- if (Lut == NULL) {
- cmsCloseProfile(hProfile);
- return NULL;
- }
+// This structure holds information about which MPU can be stored on a profile based on the version
+
+typedef struct {
+ cmsBool IsV4; // Is a V4 tag?
+ cmsTagTypeSignature LutType; // The LUT type
+ int nTypes; // Number of types (up to 5)
+ cmsStageSignature MpeTypes[5]; // 5 is the maximum number
+
+} cmsAllowedLUT;
+
+static const cmsAllowedLUT AllowedLUTTypes[] = {
+
+ { FALSE, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
+ { FALSE, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
+ { TRUE , cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } },
+ { TRUE , cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } },
+ { TRUE , cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
+ { TRUE , cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
+ { TRUE , cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }},
+ { TRUE , cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
+ { TRUE , cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }},
+ { TRUE , cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}
+};
+
+#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT))
+
+// Check a single entry
+static
+cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
+{
+ cmsStage* mpe;
+ int n;
+
+ for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) {
+
+ if (n > Tab ->nTypes) return FALSE;
+ if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE;
+ }
+
+ return (n == Tab ->nTypes);
+}
+
- Lut -> InputChan = 3;
- Lut -> OutputChan = 1;
+static
+const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4)
+{
+ int n;
+
+ for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) {
+
+ const cmsAllowedLUT* Tab = AllowedLUTTypes + n;
+
+ if (IsV4 ^ Tab -> IsV4) continue;
+ if (CheckOne(Tab, Lut)) return Tab;
+ }
+
+ return NULL;
+}
+
+
+// Does convert a transform into a device link profile
+cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
+{
+ cmsHPROFILE hProfile = NULL;
+ cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut;
+ cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut;
+ _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
+ cmsPipeline* LUT = NULL;
+ cmsStage* mpe;
+ cmsContext ContextID = cmsGetTransformContextID(hTransform);
+ const cmsAllowedLUT* AllowedLUT;
+
+ _cmsAssert(hTransform != NULL);
+
+ // Get the first mpe to check for named color
+ mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);
+
+ // Check if is a named color transform
+ if (mpe != NULL) {
+
+ if (cmsStageType(mpe) == cmsSigNamedColorElemType) {
+ return CreateNamedColorDevicelink(hTransform);
+ }
+ }
+
+ // First thing to do is to get a copy of the transformation
+ LUT = cmsPipelineDup(xform ->Lut);
+ if (LUT == NULL) return NULL;
+
+ // Time to fix the Lab2/Lab4 issue.
+ if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) {
+
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID));
+ }
- EmptyTab = cmsAllocGamma(2);
- EmptyTab ->GammaTable[0] = 0;
- EmptyTab ->GammaTable[1] = 0;
+ // On the output side too
+ if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) {
+
+ cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID));
+ }
+
+ // Optimize the LUT and precalculate a devicelink
+
+ ChansIn = cmsChannelsOf(xform -> EntryColorSpace);
+ ChansOut = cmsChannelsOf(xform -> ExitColorSpace);
+
+ ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace);
+ ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace);
+
+ FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2);
+ FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2);
+
- cmsAllocLinearTable(Lut, &EmptyTab, 2);
+ // Check if the profile/version can store the result
+ if (dwFlags & cmsFLAGS_FORCE_CLUT)
+ AllowedLUT = NULL;
+ else
+ AllowedLUT = FindCombination(LUT, Version >= 4.0);
+
+ if (AllowedLUT == NULL) {
+
+ // Try to optimize
+ _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
+ AllowedLUT = FindCombination(LUT, Version >= 4.0);
+
+ }
+
+ // If no way, then force CLUT that for sure can be written
+ if (AllowedLUT == NULL) {
+
+ dwFlags |= cmsFLAGS_FORCE_CLUT;
+ _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
+
+ // Put identity curves if needed
+ if (cmsPipelineStageCount(LUT) == 1) {
+
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn));
+ cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut));
+ }
- cmsAddTag(hProfile, icSigBToA0Tag, (LPVOID) Lut);
+ AllowedLUT = FindCombination(LUT, Version >= 4.0);
+ }
+
+ // Somethings is wrong...
+ if (AllowedLUT == NULL) {
+ goto Error;
+ }
+
+ hProfile = cmsCreateProfilePlaceholder(ContextID);
+ if (!hProfile) goto Error; // can't allocate
+
+ cmsSetProfileVersion(hProfile, Version);
+
+ FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags);
+
+ if (dwFlags & cmsFLAGS_8BITS_DEVICELINK)
+ cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE);
+
+ // Tag profile with information
+ if (!SetTextTags(hProfile, L"devicelink")) return NULL;
+
+ if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) {
- cmsFreeLUT(Lut);
- cmsFreeGamma(EmptyTab);
+ if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, LUT)) goto Error;
+ }
+ else
+ if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
+
+
+ if (xform -> InputColorant != NULL) {
+ if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error;
+ }
- return hProfile;
+ if (xform -> OutputColorant != NULL) {
+ if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error;
+ }
+
+ if (xform ->Sequence != NULL) {
+ if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error;
+ }
+
+ cmsPipelineFree(LUT);
+ return hProfile;
+
+Error:
+ if (LUT != NULL) cmsPipelineFree(LUT);
+ cmsCloseProfile(hProfile);
+ return NULL;
}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,43 +49,38 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-#include "lcms.h"
-
-
-// Conversions
+//
+//---------------------------------------------------------------------------------
+//
-void LCMSEXPORT cmsXYZ2xyY(LPcmsCIExyY Dest, const cmsCIEXYZ* Source)
-{
- double ISum;
-
- ISum = 1./(Source -> X + Source -> Y + Source -> Z);
-
- Dest -> x = (Source -> X) * ISum;
- Dest -> y = (Source -> Y) * ISum;
- Dest -> Y = Source -> Y;
-}
+#include "lcms2_internal.h"
-void LCMSEXPORT cmsxyY2XYZ(LPcmsCIEXYZ Dest, const cmsCIExyY* Source)
+// D50 - Widely used
+const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void)
{
+ static cmsCIEXYZ D50XYZ = {cmsD50X, cmsD50Y, cmsD50Z};
- Dest -> X = (Source -> x / Source -> y) * Source -> Y;
- Dest -> Y = Source -> Y;
- Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y;
+ return &D50XYZ;
}
+const cmsCIExyY* CMSEXPORT cmsD50_xyY(void)
+{
+ static cmsCIExyY D50xyY;
+
+ cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
+
+ return &D50xyY;
+}
// Obtains WhitePoint from Temperature
-
-LCMSBOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint)
+cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK)
{
- double x, y;
- double T, T2, T3;
- // double M1, M2;
+ cmsFloat64Number x, y;
+ cmsFloat64Number T, T2, T3;
+ // cmsFloat64Number M1, M2;
-
- // No optimization provided.
+ _cmsAssert(WhitePoint != NULL);
T = TempK;
T2 = T*T; // Square
@@ -104,7 +100,7 @@
x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040;
}
else {
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsWhitePointFromTemp: invalid temp");
+ cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp");
return FALSE;
}
@@ -117,10 +113,6 @@
// M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y);
// M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y);
-
-
- // Fill WhitePoint struct
-
WhitePoint -> x = x;
WhitePoint -> y = y;
WhitePoint -> Y = 1.0;
@@ -128,205 +120,16 @@
return TRUE;
}
-// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
-// This is just an approximation, I am not handling all the non-linear
-// aspects of the RGB to XYZ process, and assumming that the gamma correction
-// has transitive property in the tranformation chain.
-//
-// the alghoritm:
-//
-// - First I build the absolute conversion matrix using
-// primaries in XYZ. This matrix is next inverted
-// - Then I eval the source white point across this matrix
-// obtaining the coeficients of the transformation
-// - Then, I apply these coeficients to the original matrix
-
-
-LCMSBOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt,
- LPcmsCIExyYTRIPLE Primrs)
-{
- VEC3 WhitePoint, Coef;
- MAT3 Result, Primaries;
- double xn, yn;
- double xr, yr;
- double xg, yg;
- double xb, yb;
-
-
- xn = WhitePt -> x;
- yn = WhitePt -> y;
- xr = Primrs -> Red.x;
- yr = Primrs -> Red.y;
- xg = Primrs -> Green.x;
- yg = Primrs -> Green.y;
- xb = Primrs -> Blue.x;
- yb = Primrs -> Blue.y;
-
-
- // Build Primaries matrix
- VEC3init(&Primaries.v[0], xr, xg, xb);
- VEC3init(&Primaries.v[1], yr, yg, yb);
- VEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb));
-
-
- // Result = Primaries ^ (-1) inverse matrix
- if (!MAT3inverse(&Primaries, &Result))
- return FALSE;
-
-
- VEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn);
-
- // Across inverse primaries ...
- MAT3eval(&Coef, &Result, &WhitePoint);
-
- // Give us the Coefs, then I build transformation matrix
- VEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb);
- VEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb);
- VEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb));
-
-
- return TRUE;
-}
-
-
-
-// Compute chromatic adaptation matrix using Chad as cone matrix
-
-static
-void ComputeChromaticAdaptation(LPMAT3 Conversion,
- LPcmsCIEXYZ SourceWhitePoint,
- LPcmsCIEXYZ DestWhitePoint,
- LPMAT3 Chad)
-
-{
-
- MAT3 Chad_Inv;
- VEC3 ConeSourceXYZ, ConeSourceRGB;
- VEC3 ConeDestXYZ, ConeDestRGB;
- MAT3 Cone, Tmp;
-
-
- Tmp = *Chad;
- MAT3inverse(&Tmp, &Chad_Inv);
-
- VEC3init(&ConeSourceXYZ, SourceWhitePoint -> X,
- SourceWhitePoint -> Y,
- SourceWhitePoint -> Z);
-
- VEC3init(&ConeDestXYZ, DestWhitePoint -> X,
- DestWhitePoint -> Y,
- DestWhitePoint -> Z);
-
- MAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ);
- MAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ);
-
- // Build matrix
-
- VEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0);
- VEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0);
- VEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]);
-
-
- // Normalize
- MAT3per(&Tmp, &Cone, Chad);
- MAT3per(Conversion, &Chad_Inv, &Tmp);
-
-}
-
-
-// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll
-// The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed
-
-LCMSBOOL cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll)
-{
- MAT3 LamRigg = {{ // Bradford matrix
- {{ 0.8951, 0.2664, -0.1614 }},
- {{ -0.7502, 1.7135, 0.0367 }},
- {{ 0.0389, -0.0685, 1.0296 }}
- }};
-
-
- if (ConeMatrix == NULL)
- ConeMatrix = &LamRigg;
-
- ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix);
- return TRUE;
-
-}
-
-// Same as anterior, but assuming D50 destination. White point is given in xyY
-
-LCMSBOOL cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt)
-{
- cmsCIEXYZ Dn;
- MAT3 Bradford;
- MAT3 Tmp;
-
- cmsxyY2XYZ(&Dn, SourceWhitePt);
-
- cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ());
-
- Tmp = *r;
- MAT3per(r, &Bradford, &Tmp);
-
- return TRUE;
-}
-
-
-// Same as anterior, but assuming D50 source. White point is given in xyY
-
-LCMSBOOL cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt)
-{
- cmsCIEXYZ Dn;
- MAT3 Bradford;
- MAT3 Tmp;
-
- cmsxyY2XYZ(&Dn, DestWhitePt);
-
- cmsAdaptationMatrix(&Bradford, NULL, cmsD50_XYZ(), &Dn);
-
- Tmp = *r;
- MAT3per(r, &Bradford, &Tmp);
-
- return TRUE;
-}
-
-
-// Adapts a color to a given illuminant. Original color is expected to have
-// a SourceWhitePt white point.
-
-LCMSBOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result,
- LPcmsCIEXYZ SourceWhitePt,
- LPcmsCIEXYZ Illuminant,
- LPcmsCIEXYZ Value)
-{
- MAT3 Bradford;
- VEC3 In, Out;
-
- // BradfordLamRiggChromaticAdaptation(&Bradford, SourceWhitePt, Illuminant);
-
- cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant);
-
- VEC3init(&In, Value -> X, Value -> Y, Value -> Z);
- MAT3eval(&Out, &Bradford, &In);
-
- Result -> X = Out.n[0];
- Result -> Y = Out.n[1];
- Result -> Z = Out.n[2];
-
- return TRUE;
-}
-
typedef struct {
- double mirek; // temp (in microreciprocal kelvin)
- double ut; // u coord of intersection w/ blackbody locus
- double vt; // v coord of intersection w/ blackbody locus
- double tt; // slope of ISOTEMPERATURE. line
+ cmsFloat64Number mirek; // temp (in microreciprocal kelvin)
+ cmsFloat64Number ut; // u coord of intersection w/ blackbody locus
+ cmsFloat64Number vt; // v coord of intersection w/ blackbody locus
+ cmsFloat64Number tt; // slope of ISOTEMPERATURE. line
- } ISOTEMPERATURE,FAR* LPISOTEMPERATURE;
+ } ISOTEMPERATURE;
static ISOTEMPERATURE isotempdata[] = {
// {Mirek, Ut, Vt, Tt }
@@ -360,27 +163,28 @@
{525, 0.31320, 0.35968, -15.628 },
{550, 0.32129, 0.36011, -23.325 },
{575, 0.32931, 0.36038, -40.770 },
- {600, 0.33724, 0.36051, -116.45 }
+ {600, 0.33724, 0.36051, -116.45 }
};
#define NISO sizeof(isotempdata)/sizeof(ISOTEMPERATURE)
// Robertson's method
-
-static
-double Robertson(LPcmsCIExyY v)
+cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint)
{
int j;
- double us,vs;
- double uj,vj,tj,di,dj,mi,mj;
- double Tc = -1, xs, ys;
+ cmsFloat64Number us,vs;
+ cmsFloat64Number uj,vj,tj,di,dj,mi,mj;
+ cmsFloat64Number xs, ys;
+
+ _cmsAssert(WhitePoint != NULL);
+ _cmsAssert(TempK != NULL);
di = mi = 0;
- xs = v -> x;
- ys = v -> y;
+ xs = WhitePoint -> x;
+ ys = WhitePoint -> y;
- // convert (x,y) to CIE 1960 (u,v)
+ // convert (x,y) to CIE 1960 (u,WhitePoint)
us = (2*xs) / (-xs + 6*ys + 1.5);
vs = (3*ys) / (-xs + 6*ys + 1.5);
@@ -393,332 +197,182 @@
tj = isotempdata[j].tt;
mj = isotempdata[j].mirek;
- dj = ((vs - vj) - tj * (us - uj)) / sqrt(1 + tj*tj);
+ dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj);
+
+ if ((j != 0) && (di/dj < 0.0)) {
- if ((j!=0) && (di/dj < 0.0)) {
- Tc = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi));
- break;
+ // Found a match
+ *TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi));
+ return TRUE;
}
di = dj;
mi = mj;
}
-
- if (j == NISO) return -1;
- return Tc;
-}
-
-
-
-static
-LCMSBOOL InRange(LPcmsCIExyY a, LPcmsCIExyY b, double tolerance)
-{
- double dist_x, dist_y;
-
- dist_x = fabs(a->x - b->x);
- dist_y = fabs(a->y - b->y);
-
- return (tolerance >= dist_x * dist_x + dist_y * dist_y);
-
+ // Not found
+ return FALSE;
}
-typedef struct {
- char Name[30];
- cmsCIExyY Val;
-
- } WHITEPOINTS,FAR *LPWHITEPOINTS;
+// Compute chromatic adaptation matrix using Chad as cone matrix
static
-int FromD40toD150(LPWHITEPOINTS pts)
+cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion,
+ const cmsCIEXYZ* SourceWhitePoint,
+ const cmsCIEXYZ* DestWhitePoint,
+ const cmsMAT3* Chad)
+
{
- int i, n;
+
+ cmsMAT3 Chad_Inv;
+ cmsVEC3 ConeSourceXYZ, ConeSourceRGB;
+ cmsVEC3 ConeDestXYZ, ConeDestRGB;
+ cmsMAT3 Cone, Tmp;
+
+
+ Tmp = *Chad;
+ if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE;
- n = 0;
- for (i=40; i < 150; i ++)
- {
- sprintf(pts[n].Name, "D%d", i);
- cmsWhitePointFromTemp((int) (i*100.0), &pts[n].Val);
- n++;
- }
+ _cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X,
+ SourceWhitePoint -> Y,
+ SourceWhitePoint -> Z);
+
+ _cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X,
+ DestWhitePoint -> Y,
+ DestWhitePoint -> Z);
- return n;
-}
+ _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ);
+ _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ);
+
+ // Build matrix
+ _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0);
+ _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0);
+ _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]);
-// To be removed in future versions
-void _cmsIdentifyWhitePoint(char *Buffer, LPcmsCIEXYZ WhitePt)
+ // Normalize
+ _cmsMAT3per(&Tmp, &Cone, Chad);
+ _cmsMAT3per(Conversion, &Chad_Inv, &Tmp);
+
+ return TRUE;
+}
+
+// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll
+// The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed
+cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll)
{
- int i, n;
- cmsCIExyY Val;
- double T;
- WHITEPOINTS SomeIlluminants[140] = {
+ cmsMAT3 LamRigg = {{ // Bradford matrix
+ {{ 0.8951, 0.2664, -0.1614 }},
+ {{ -0.7502, 1.7135, 0.0367 }},
+ {{ 0.0389, -0.0685, 1.0296 }}
+ }};
+
+ if (ConeMatrix == NULL)
+ ConeMatrix = &LamRigg;
- {"CIE illuminant A", {0.4476, 0.4074, 1.0}},
- {"CIE illuminant C", {0.3101, 0.3162, 1.0}},
- {"D65 (daylight)", {0.3127, 0.3291, 1.0}},
- };
+ return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix);
+}
- n = FromD40toD150(&SomeIlluminants[3]) + 3;
+// Same as anterior, but assuming D50 destination. White point is given in xyY
+static
+cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt)
+{
+ cmsCIEXYZ Dn;
+ cmsMAT3 Bradford;
+ cmsMAT3 Tmp;
- cmsXYZ2xyY(&Val, WhitePt);
+ cmsxyY2XYZ(&Dn, SourceWhitePt);
+
+ if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE;
+
+ Tmp = *r;
+ _cmsMAT3per(r, &Bradford, &Tmp);
+
+ return TRUE;
+}
- Val.Y = 1.;
- for (i=0; i < n; i++)
- {
+// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
+// This is just an approximation, I am not handling all the non-linear
+// aspects of the RGB to XYZ process, and assumming that the gamma correction
+// has transitive property in the tranformation chain.
+//
+// the alghoritm:
+//
+// - First I build the absolute conversion matrix using
+// primaries in XYZ. This matrix is next inverted
+// - Then I eval the source white point across this matrix
+// obtaining the coeficients of the transformation
+// - Then, I apply these coeficients to the original matrix
+//
+cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs)
+{
+ cmsVEC3 WhitePoint, Coef;
+ cmsMAT3 Result, Primaries;
+ cmsFloat64Number xn, yn;
+ cmsFloat64Number xr, yr;
+ cmsFloat64Number xg, yg;
+ cmsFloat64Number xb, yb;
- if (InRange(&Val, &SomeIlluminants[i].Val, 0.000005))
- {
- strcpy(Buffer, "WhitePoint : ");
- strcat(Buffer, SomeIlluminants[i].Name);
- return;
- }
- }
+ xn = WhitePt -> x;
+ yn = WhitePt -> y;
+ xr = Primrs -> Red.x;
+ yr = Primrs -> Red.y;
+ xg = Primrs -> Green.x;
+ yg = Primrs -> Green.y;
+ xb = Primrs -> Blue.x;
+ yb = Primrs -> Blue.y;
+
+ // Build Primaries matrix
+ _cmsVEC3init(&Primaries.v[0], xr, xg, xb);
+ _cmsVEC3init(&Primaries.v[1], yr, yg, yb);
+ _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb));
+
- T = Robertson(&Val);
+ // Result = Primaries ^ (-1) inverse matrix
+ if (!_cmsMAT3inverse(&Primaries, &Result))
+ return FALSE;
+
+
+ _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn);
- if (T > 0)
- sprintf(Buffer, "White point near %dK", (int) T);
- else
- {
- sprintf(Buffer, "Unknown white point (X:%1.2g, Y:%1.2g, Z:%1.2g)",
- WhitePt -> X, WhitePt -> Y, WhitePt -> Z);
+ // Across inverse primaries ...
+ _cmsMAT3eval(&Coef, &Result, &WhitePoint);
- }
+ // Give us the Coefs, then I build transformation matrix
+ _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb);
+ _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb);
+ _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb));
+
+
+ return _cmsAdaptMatrixToD50(r, WhitePt);
}
-// Use darker colorant to obtain black point
-
-static
-int BlackPointAsDarkerColorant(cmsHPROFILE hInput,
- int Intent,
- LPcmsCIEXYZ BlackPoint,
- DWORD dwFlags)
+// Adapts a color to a given illuminant. Original color is expected to have
+// a SourceWhitePt white point.
+cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result,
+ const cmsCIEXYZ* SourceWhitePt,
+ const cmsCIEXYZ* Illuminant,
+ const cmsCIEXYZ* Value)
{
- WORD *Black, *White;
- cmsHTRANSFORM xform;
- icColorSpaceSignature Space;
- int nChannels;
- DWORD dwFormat;
- cmsHPROFILE hLab;
- cmsCIELab Lab;
- cmsCIEXYZ BlackXYZ, MediaWhite;
-
- // If the profile does not support input direction, assume Black point 0
- if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) {
-
- BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
- return 0;
- }
-
-
- // Try to get black by using black colorant
- Space = cmsGetColorSpace(hInput);
-
- if (!_cmsEndPointsBySpace(Space, &White, &Black, &nChannels)) {
-
- BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
- return 0;
- }
-
- dwFormat = CHANNELS_SH(nChannels)|BYTES_SH(2);
-
- hLab = cmsCreateLabProfile(NULL);
-
- xform = cmsCreateTransform(hInput, dwFormat,
- hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOTPRECALC);
-
-
- cmsDoTransform(xform, Black, &Lab, 1);
-
- // Force it to be neutral, clip to max. L* of 50
-
- Lab.a = Lab.b = 0;
- if (Lab.L > 50) Lab.L = 50;
-
- cmsCloseProfile(hLab);
- cmsDeleteTransform(xform);
-
- cmsLab2XYZ(NULL, &BlackXYZ, &Lab);
-
- if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) {
-
- *BlackPoint = BlackXYZ;
- }
- else {
-
- if (!(dwFlags & LCMS_BPFLAGS_D50_ADAPTED)) {
-
- cmsTakeMediaWhitePoint(&MediaWhite, hInput);
- cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &BlackXYZ);
- }
- else
- *BlackPoint = BlackXYZ;
- }
-
- return 1;
-}
-
-
-// Get a black point of output CMYK profile, discounting any ink-limiting embedded
-// in the profile. For doing that, use perceptual intent in input direction:
-// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab
-
-static
-int BlackPointUsingPerceptualBlack(LPcmsCIEXYZ BlackPoint,
- cmsHPROFILE hProfile,
- DWORD dwFlags)
-{
- cmsHTRANSFORM hPercLab2CMYK, hRelColCMYK2Lab;
- cmsHPROFILE hLab;
- cmsCIELab LabIn, LabOut;
- WORD CMYK[MAXCHANNELS];
- cmsCIEXYZ BlackXYZ, MediaWhite;
-
-
- if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-
- BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
- return 0;
- }
-
- hLab = cmsCreateLabProfile(NULL);
-
- hPercLab2CMYK = cmsCreateTransform(hLab, TYPE_Lab_DBL,
- hProfile, TYPE_CMYK_16,
- INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC);
-
- hRelColCMYK2Lab = cmsCreateTransform(hProfile, TYPE_CMYK_16,
- hLab, TYPE_Lab_DBL,
- INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOTPRECALC);
-
- LabIn.L = LabIn.a = LabIn.b = 0;
-
- cmsDoTransform(hPercLab2CMYK, &LabIn, CMYK, 1);
- cmsDoTransform(hRelColCMYK2Lab, CMYK, &LabOut, 1);
-
- if (LabOut.L > 50) LabOut.L = 50;
- LabOut.a = LabOut.b = 0;
+ cmsMAT3 Bradford;
+ cmsVEC3 In, Out;
- cmsDeleteTransform(hPercLab2CMYK);
- cmsDeleteTransform(hRelColCMYK2Lab);
- cmsCloseProfile(hLab);
-
- cmsLab2XYZ(NULL, &BlackXYZ, &LabOut);
-
- if (!(dwFlags & LCMS_BPFLAGS_D50_ADAPTED)){
- cmsTakeMediaWhitePoint(&MediaWhite, hProfile);
- cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &BlackXYZ);
- }
- else
- *BlackPoint = BlackXYZ;
-
- return 1;
-
-}
-
-
-// Get Perceptual black of v4 profiles.
-static
-int GetV4PerceptualBlack(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, DWORD dwFlags)
-{
- if (dwFlags & LCMS_BPFLAGS_D50_ADAPTED) {
+ _cmsAssert(Result != NULL);
+ _cmsAssert(SourceWhitePt != NULL);
+ _cmsAssert(Illuminant != NULL);
+ _cmsAssert(Value != NULL);
- BlackPoint->X = PERCEPTUAL_BLACK_X;
- BlackPoint->Y = PERCEPTUAL_BLACK_Y;
- BlackPoint->Z = PERCEPTUAL_BLACK_Z;
- }
- else {
-
- cmsCIEXYZ D50BlackPoint, MediaWhite;
-
- cmsTakeMediaWhitePoint(&MediaWhite, hProfile);
- D50BlackPoint.X = PERCEPTUAL_BLACK_X;
- D50BlackPoint.Y = PERCEPTUAL_BLACK_Y;
- D50BlackPoint.Z = PERCEPTUAL_BLACK_Z;
-
- // Obtain the absolute XYZ. Adapt perceptual black back from D50 to whatever media white
- cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &D50BlackPoint);
- }
-
-
- return 1;
-}
-
-
-// This function shouldn't exist at all -- there is such quantity of broken
-// profiles on black point tag, that we must somehow fix chromaticity to
-// avoid huge tint when doing Black point compensation. This function does
-// just that. There is a special flag for using black point tag, but turned
-// off by default because it is bogus on most profiles. The detection algorithm
-// involves to turn BP to neutral and to use only L component.
-
-int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent, DWORD dwFlags)
-{
-
- // v4 + perceptual & saturation intents does have its own black point, and it is
- // well specified enough to use it.
+ if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE;
- if ((cmsGetProfileICCversion(hProfile) >= 0x4000000) &&
- (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {
-
- // Matrix shaper share MRC & perceptual intents
- if (_cmsIsMatrixShaper(hProfile))
- return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, cmsFLAGS_NOTPRECALC);
-
- // CLUT based - Get perceptual black point (fixed value)
- return GetV4PerceptualBlack(BlackPoint, hProfile, dwFlags);
- }
-
-
-#ifdef HONOR_BLACK_POINT_TAG
-
- // v2, v4 rel/abs colorimetric
- if (cmsIsTag(hProfile, icSigMediaBlackPointTag) &&
- Intent == INTENT_RELATIVE_COLORIMETRIC) {
-
- cmsCIEXYZ BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite;
- cmsCIELab Lab;
-
- // If black point is specified, then use it,
-
- cmsTakeMediaBlackPoint(&BlackXYZ, hProfile);
- cmsTakeMediaWhitePoint(&MediaWhite, hProfile);
-
- // Black point is absolute XYZ, so adapt to D50 to get PCS value
- cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ);
+ _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z);
+ _cmsMAT3eval(&Out, &Bradford, &In);
- // Force a=b=0 to get rid of any chroma
-
- cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint);
- Lab.a = Lab.b = 0;
- if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50
-
- cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab);
-
- // Return BP as D50 relative or absolute XYZ (depends on flags)
- if (!(dwFlags & LCMS_BPFLAGS_D50_ADAPTED))
- cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &TrustedBlackPoint);
- else
- *BlackPoint = TrustedBlackPoint;
+ Result -> X = Out.n[0];
+ Result -> Y = Out.n[1];
+ Result -> Z = Out.n[2];
- return 1;
- }
-
-#endif
-
- // That is about v2 profiles.
-
- // If output profile, discount ink-limiting and that's all
- if (Intent == INTENT_RELATIVE_COLORIMETRIC &&
- (cmsGetDeviceClass(hProfile) == icSigOutputClass) &&
- (cmsGetColorSpace(hProfile) == icSigCmykData))
- return BlackPointUsingPerceptualBlack(BlackPoint, hProfile, dwFlags);
-
- // Nope, compute BP using current intent.
- return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);
-
+ return TRUE;
}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c Thu Sep 16 11:15:07 2010 -0700
@@ -27,9 +27,10 @@
// However, the following notice accompanied the original version of this
// file:
//
+//---------------------------------------------------------------------------------
//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -48,1863 +49,436 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+//
+//---------------------------------------------------------------------------------
+//
-#include "lcms.h"
-
+#include "lcms2_internal.h"
// Transformations stuff
// -----------------------------------------------------------------------
-
-// Interface
-
-cmsHTRANSFORM LCMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
- DWORD InputFormat,
- cmsHPROFILE Output,
- DWORD OutputFormat,
- int Intent,
- DWORD dwFlags);
-
-cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE Input,
- DWORD InputFormat,
- cmsHPROFILE Output,
- DWORD OutputFormat,
- cmsHPROFILE Proofing,
- int Intent,
- int ProofingIntent,
- DWORD dwFlags);
+// Alarm codes for 16-bit transformations, because the fixed range of containers there are
+// no values left to mark out of gamut. volatile is C99 per 6.2.5
+static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS];
+static volatile cmsFloat64Number GlobalAdaptationState = 0;
-
-void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform);
-
-void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
- LPVOID InputBuffer,
- LPVOID OutputBuffer, unsigned int Size);
+// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
+cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
+{
+ cmsFloat64Number OldVal = GlobalAdaptationState;
-void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b);
-void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b);
-LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile,
- int Intent, int UsedDirection);
-
-// -------------------------------------------------------------------------
-
-
-// Alarm RGB codes
-
-static WORD AlarmR = 0x8fff, AlarmG = 0x8fff, AlarmB = 0x8fff;
+ if (d >= 0)
+ GlobalAdaptationState = d;
-// Tag tables, soted by intents
-
-static icTagSignature Device2PCS[] = {icSigAToB0Tag, // Perceptual
- icSigAToB1Tag, // Relative colorimetric
- icSigAToB2Tag, // Saturation
- icSigAToB1Tag }; // Absolute colorimetric
- // (Relative/WhitePoint)
-
-static icTagSignature PCS2Device[] = {icSigBToA0Tag, // Perceptual
- icSigBToA1Tag, // Relative colorimetric
- icSigBToA2Tag, // Saturation
- icSigBToA1Tag }; // Absolute colorimetric
- // (Relative/WhitePoint)
-
+ return OldVal;
+}
-static icTagSignature Preview[] = {icSigPreview0Tag,
- icSigPreview1Tag,
- icSigPreview2Tag,
- icSigPreview1Tag };
-
-
-
-static volatile double GlobalAdaptationState = 0;
-
-// --------------------------------Stages--------------------------------------
+// Alarm codes are always global
+void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
+{
+ int i;
-// Following routines does implement several kind of steps inside
-// transform. On building the transform, code chooses adequate.
-
-
-// From Shaper-Matrix to PCS
+ _cmsAssert(NewAlarm != NULL);
-static
-void ShaperMatrixToPCS(struct _cmstransform_struct *p,
- WORD In[3], WORD Out[3])
-{
- cmsEvalMatShaper(p -> InMatShaper, In, Out);
+ for (i=0; i < cmsMAXCHANNELS; i++)
+ Alarm[i] = NewAlarm[i];
}
-// From LUT to PCS
-
-static
-void LUTtoPCS(struct _cmstransform_struct *p,
- WORD In[], WORD Out[3])
-{
- cmsEvalLUT(p -> Device2PCS, In, Out);
-}
-
-// From indexed named color to PCS
-
-static
-void NC2toPCS(struct _cmstransform_struct *p,
- WORD In[], WORD Out[3])
+// You can get the codes cas well
+void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
{
- int index = In[0];
-
- if (index >= p ->NamedColorList-> nColors)
- cmsSignalError(LCMS_ERRC_WARNING, "Color %d out of range", index);
- else
- CopyMemory(Out, p ->NamedColorList->List[index].PCS, 3 * sizeof(WORD));
-}
+ int i;
-// From PCS to Shaper-Matrix
+ _cmsAssert(OldAlarm != NULL);
-static
-void PCStoShaperMatrix(struct _cmstransform_struct *p,
- WORD In[3], WORD Out[3])
-{
- cmsEvalMatShaper(p -> OutMatShaper, In, Out);
+ for (i=0; i < cmsMAXCHANNELS; i++)
+ OldAlarm[i] = Alarm[i];
}
-// From PCS to LUT
+// Get rid of transform resources
+void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
+{
+ _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
+
+ _cmsAssert(p != NULL);
+
+ if (p -> GamutCheck)
+ cmsPipelineFree(p -> GamutCheck);
-static
-void PCStoLUT(struct _cmstransform_struct *p,
- WORD In[3], WORD Out[])
-{
- cmsEvalLUT(p -> PCS2Device, In, Out);
+ if (p -> Lut)
+ cmsPipelineFree(p -> Lut);
+
+ if (p ->InputColorant)
+ cmsFreeNamedColorList(p ->InputColorant);
+
+ if (p -> OutputColorant)
+ cmsFreeNamedColorList(p ->OutputColorant);
+
+ if (p ->Sequence)
+ cmsFreeProfileSequenceDescription(p ->Sequence);
+
+ LCMS_FREE_LOCK(&p->rwlock);
+ _cmsFree(p ->ContextID, (void *) p);
}
-
-
-
-// ----------------------- TRANSFORMATIONS --------------------------
-
-
-// Inlining some assignations
-
-#define COPY_3CHANS(to, from) { to[0]=from[0]; to[1]=from[1]; to[2]=from[2]; }
-
-
-// Null transformation, only hold channels
+// Apply transform
+void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
+ const void* InputBuffer,
+ void* OutputBuffer,
+ cmsUInt32Number Size)
-static
-void NullXFORM(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS];
- register unsigned int i, n;
-
+ _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
- n = Size; // Buffer len
-
- for (i=0; i < n; i++)
- {
- accum = p -> FromInput(p, wIn, accum);
- output = p -> ToOutput(p, wIn, output);
- }
-
+ p -> xform(p, InputBuffer, OutputBuffer, Size);
}
-// This is the "normal" proofing transform
+// Transform routines ----------------------------------------------------------------------------------------------------------
+// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
+// Note that because extended range, we can use a -1.0 value for out of gamut in this case.
static
-void NormalXFORM(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
+void FloatXFORM(_cmsTRANSFORM* p,
+ const void* in,
+ void* out, cmsUInt32Number Size)
{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- WORD wStageABC[3], wPCS[3], wStageLMN[MAXCHANNELS];
- WORD wGamut[1];
- register unsigned int i, n;
+ cmsUInt8Number* accum;
+ cmsUInt8Number* output;
+ cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
+ cmsFloat32Number OutOfGamut;
+ cmsUInt32Number i, j;
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
+
+ for (i=0; i < Size; i++) {
+
+ accum = p -> FromInputFloat(p, fIn, accum, Size);
+ // Any gamut chack to do?
+ if (p ->GamutCheck != NULL) {
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
- n = Size; // Buffer len
+ // Evaluate gamut marker.
+ cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck);
- for (i=0; i < n; i++)
- {
+ // Is current color out of gamut?
+ if (OutOfGamut > 0.0) {
+
+ // Certainly, out of gamut
+ for (j=0; j < cmsMAXCHANNELS; j++)
+ fOut[j] = -1.0;
- accum = p -> FromInput(p, wIn, accum);
-
- p -> FromDevice(p, wIn, wStageABC);
+ }
+ else {
+ // No, proceed normally
+ cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
+ }
+ }
+ else {
- if (p -> Stage1) {
+ // No gamut check at all
+ cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
+ }
- p -> Stage1(wStageABC, wPCS, &p->m1, &p->of1);
+ // Back to asked representation
+ output = p -> ToOutputFloat(p, fOut, output, Size);
+ }
+}
+
+// 16 bit precision -----------------------------------------------------------------------------------------------------------
- if (wPCS[0] == 0xFFFF &&
- wPCS[1] == 0xFFFF &&
- wPCS[2] == 0xFFFF) {
-
- // White cutoff
+// Null transformation, only applies formatters. No caché
+static
+void NullXFORM(_cmsTRANSFORM* p,
+ const void* in,
+ void* out, cmsUInt32Number Size)
+{
+ cmsUInt8Number* accum;
+ cmsUInt8Number* output;
+ cmsUInt16Number wIn[cmsMAXCHANNELS];
+ cmsUInt32Number i, n;
- output = p -> ToOutput((_LPcmsTRANSFORM) p,
- _cmsWhiteBySpace(cmsGetColorSpace(p -> OutputProfile)),
- output);
- continue;
- }
- }
- else
- COPY_3CHANS(wPCS, wStageABC);
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
+ n = Size; // Buffer len
+
+ for (i=0; i < n; i++) {
+
+ accum = p -> FromInput(p, wIn, accum, Size);
+ output = p -> ToOutput(p, wIn, output, Size);
+ }
+}
- if (p->Gamut) {
-
- // Gamut check, enabled across CLUT
-
- cmsEvalLUT(p -> Gamut, wPCS, wGamut);
-
- if (wGamut[0] >= 1) {
-
- wOut[0] = AlarmR; // Gamut alarm
- wOut[1] = AlarmG;
- wOut[2] = AlarmB;
- wOut[3] = 0;
-
- output = p -> ToOutput((_LPcmsTRANSFORM)p, wOut, output);
- continue;
- }
- }
-
- if (p -> Preview)
- {
- WORD wPreview[3]; // PCS
-
- cmsEvalLUT(p -> Preview, wPCS, wPreview);
- COPY_3CHANS(wPCS, wPreview);
- }
-
- if (p -> Stage2) {
-
- p -> Stage2(wPCS, wStageLMN, &p->m2, &p->of2);
-
- if (wPCS[0] == 0xFFFF &&
- wPCS[1] == 0xFFFF &&
- wPCS[2] == 0xFFFF) {
-
- // White cutoff
-
- output = p -> ToOutput((_LPcmsTRANSFORM)p,
- _cmsWhiteBySpace(cmsGetColorSpace(p -> OutputProfile)),
- output);
-
- continue;
- }
-
- }
- else
- COPY_3CHANS(wStageLMN, wPCS);
-
- // Here wOut may come as MAXCHANNELS channels
-
- p -> ToDevice(p, wStageLMN, wOut);
-
- output = p -> ToOutput((_LPcmsTRANSFORM)p, wOut, output);
- }
-}
-
-// Using precalculated LUT
+// No gamut check, no cache, 16 bits
+static
+void PrecalculatedXFORM(_cmsTRANSFORM* p,
+ const void* in,
+ void* out, cmsUInt32Number Size)
+{
+ register cmsUInt8Number* accum;
+ register cmsUInt8Number* output;
+ cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
+ cmsUInt32Number i, n;
-static
-void PrecalculatedXFORM(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
-{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- unsigned int i, n;
-
-
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
- n = Size; // Buffer len
-
-
- for (i=0; i < n; i++) {
-
- accum = p -> FromInput(p, wIn, accum);
-
- // Try to speedup things on plain devicelinks
-
- if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) {
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
+ n = Size;
- p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut,
- p ->DeviceLink -> T,
- &p ->DeviceLink -> CLut16params);
- }
- else
- cmsEvalLUT(p -> DeviceLink, wIn, wOut);
-
-
- output = p -> ToOutput(p, wOut, output);
- }
-}
-
-// Auxiliar: Handle precalculated gamut check
+ for (i=0; i < n; i++) {
-static
-void TransformOnePixelWithGamutCheck(_LPcmsTRANSFORM p, WORD wIn[], WORD wOut[])
-{
- WORD wOutOfGamut;
-
- cmsEvalLUT(p ->GamutCheck, wIn, &wOutOfGamut);
-
- if (wOutOfGamut >= 1) {
-
- ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS);
-
- wOut[0] = AlarmR;
- wOut[1] = AlarmG;
- wOut[2] = AlarmB;
-
- }
- else
- cmsEvalLUT(p -> DeviceLink, wIn, wOut);
-
+ accum = p -> FromInput(p, wIn, accum, Size);
+ p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
+ output = p -> ToOutput(p, wOut, output, Size);
+ }
}
+// Auxiliar: Handle precalculated gamut check
static
-void PrecalculatedXFORMGamutCheck(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
+void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
+ const cmsUInt16Number wIn[],
+ cmsUInt16Number wOut[])
{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- register unsigned int i, n;
+ cmsUInt16Number wOutOfGamut;
+
+ p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
+ if (wOutOfGamut >= 1) {
+
+ cmsUInt16Number i;
+ for (i=0; i < p ->Lut->OutputChannels; i++)
+ wOut[i] = Alarm[i];
+ }
+ else
+ p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
+}
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
- n = Size; // Buffer len
-
- for (i=0; i < n; i++) {
+// Gamut check, No caché, 16 bits.
+static
+void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
+ const void* in,
+ void* out, cmsUInt32Number Size)
+{
+ cmsUInt8Number* accum;
+ cmsUInt8Number* output;
+ cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
+ cmsUInt32Number i, n;
- accum = p -> FromInput(p, wIn, accum);
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
+ n = Size; // Buffer len
- TransformOnePixelWithGamutCheck(p, wIn, wOut);
+ for (i=0; i < n; i++) {
- output = p -> ToOutput(p, wOut, output);
- }
+ accum = p -> FromInput(p, wIn, accum, Size);
+ TransformOnePixelWithGamutCheck(p, wIn, wOut);
+ output = p -> ToOutput(p, wOut, output, Size);
+ }
}
-
-// Using precalculated LUT + Cache
-
+// No gamut check, Caché, 16 bits,
static
-void CachedXFORM(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
+void CachedXFORM(_cmsTRANSFORM* p,
+ const void* in,
+ void* out, cmsUInt32Number Size)
{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- register unsigned int i, n;
- WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS];
+ cmsUInt8Number* accum;
+ cmsUInt8Number* output;
+ cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
+ cmsUInt32Number i, n;
+ cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS];
+
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
+ n = Size; // Buffer len
+
+ // Empty buffers for quick memcmp
+ memset(wIn, 0, sizeof(wIn));
+ memset(wOut, 0, sizeof(wOut));
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
+ LCMS_READ_LOCK(&p ->rwlock);
+ memmove(CacheIn, p ->CacheIn, sizeof(CacheIn));
+ memmove(CacheOut, p ->CacheOut, sizeof(CacheOut));
+ LCMS_UNLOCK(&p ->rwlock);
+
+ for (i=0; i < n; i++) {
+
+ accum = p -> FromInput(p, wIn, accum, Size);
+
+ if (memcmp(wIn, CacheIn, sizeof(CacheIn)) == 0) {
+
+ memmove(wOut, CacheOut, sizeof(CacheOut));
+ }
+ else {
+
+ p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
+
+ memmove(CacheIn, wIn, sizeof(CacheIn));
+ memmove(CacheOut, wOut, sizeof(CacheOut));
+ }
+
+ output = p -> ToOutput(p, wOut, output, Size);
+ }
+
+
+ LCMS_WRITE_LOCK(&p ->rwlock);
+ memmove(p->CacheIn, CacheIn, sizeof(CacheIn));
+ memmove(p->CacheOut, CacheOut, sizeof(CacheOut));
+ LCMS_UNLOCK(&p ->rwlock);
+}
+
+
+// All those nice features together
+static
+void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
+ const void* in,
+ void* out, cmsUInt32Number Size)
+{
+ cmsUInt8Number* accum;
+ cmsUInt8Number* output;
+ cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
+ cmsUInt32Number i, n;
+ cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS];
+
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
n = Size; // Buffer len
// Empty buffers for quick memcmp
-
- ZeroMemory(wIn, sizeof(WORD) * MAXCHANNELS);
- ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS);
-
+ memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+ memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
LCMS_READ_LOCK(&p ->rwlock);
- CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS);
- CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS);
- LCMS_UNLOCK(&p ->rwlock);
-
- for (i=0; i < n; i++) {
-
- accum = p -> FromInput(p, wIn, accum);
-
-
- if (memcmp(wIn, CacheIn, sizeof(WORD) * MAXCHANNELS) == 0) {
-
- CopyMemory(wOut, CacheOut, sizeof(WORD) * MAXCHANNELS);
- }
- else {
-
- // Try to speedup things on plain devicelinks
-
- if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) {
-
- p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut,
- p ->DeviceLink -> T,
- &p ->DeviceLink -> CLut16params);
- }
- else
- cmsEvalLUT(p -> DeviceLink, wIn, wOut);
-
-
- CopyMemory(CacheIn, wIn, sizeof(WORD) * MAXCHANNELS);
- CopyMemory(CacheOut, wOut, sizeof(WORD) * MAXCHANNELS);
- }
-
- output = p -> ToOutput(p, wOut, output);
- }
-
-
- LCMS_WRITE_LOCK(&p ->rwlock);
- CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS);
- CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS);
- LCMS_UNLOCK(&p ->rwlock);
-
-}
-
-
-
-// Using precalculated LUT + Cache
-
-static
-void CachedXFORMGamutCheck(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
-{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- register unsigned int i, n;
- WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS];
-
-
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
- n = Size; // Buffer len
-
- // Empty buffers for quick memcmp
-
- ZeroMemory(wIn, sizeof(WORD) * MAXCHANNELS);
- ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS);
-
- LCMS_READ_LOCK(&p ->rwlock);
- CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS);
- CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS);
+ memmove(CacheIn, p ->CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+ memmove(CacheOut, p ->CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
LCMS_UNLOCK(&p ->rwlock);
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum);
-
- if (memcmp(wIn, CacheIn, sizeof(WORD) * MAXCHANNELS) == 0) {
-
- CopyMemory(wOut, CacheOut, sizeof(WORD) * MAXCHANNELS);
- }
- else {
+ accum = p -> FromInput(p, wIn, accum, Size);
- TransformOnePixelWithGamutCheck(p, wIn, wOut);
+ if (memcmp(wIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS) == 0) {
+ memmove(wOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+ }
+ else {
+ TransformOnePixelWithGamutCheck(p, wIn, wOut);
+ memmove(CacheIn, wIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+ memmove(CacheOut, wOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+ }
- CopyMemory(CacheIn, wIn, sizeof(WORD) * MAXCHANNELS);
- CopyMemory(CacheOut, wOut, sizeof(WORD) * MAXCHANNELS);
- }
-
- output = p -> ToOutput(p, wOut, output);
+ output = p -> ToOutput(p, wOut, output, Size);
}
LCMS_WRITE_LOCK(&p ->rwlock);
- CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS);
- CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS);
+ memmove(p->CacheIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
+ memmove(p->CacheOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
LCMS_UNLOCK(&p ->rwlock);
}
-// Using smelted Matrix/Shaper
-
-static
-void MatrixShaperXFORM(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
-{
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- register unsigned int i, n;
-
-
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
- n = Size; // Buffer len
-
- for (i=0; i < n; i++)
- {
- accum = p -> FromInput(p, wIn, accum);
- cmsEvalMatShaper(p -> SmeltMatShaper, wIn, wOut);
- output = p -> ToOutput(p, wOut, output);
- }
-}
-
-
-// Using Named color input table
-
-static
-void NC2deviceXform(_LPcmsTRANSFORM p,
- LPVOID in,
- LPVOID out, unsigned int Size)
-{
-
- register LPBYTE accum;
- register LPBYTE output;
- WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS];
- register unsigned int i;
-
-
- accum = (LPBYTE) in;
- output = (LPBYTE) out;
-
- for (i=0; i < Size; i++) {
-
- accum = p -> FromInput(p, wIn, accum);
- CopyMemory(wOut, p ->NamedColorList->List[wIn[0]].DeviceColorant, sizeof(WORD) * MAXCHANNELS);
- output = p -> ToOutput(p, wOut, output);
- }
-
-}
-
-
-
-// --------------------------------------------------------------------------
-// Build a LUT based on shape-matrix method.
-
-
-// Some non-conformant gray profiles are using kTCR as L*,
-// this function converts the curve to XYZ PCS.
-
-static
-void FromLstarToXYZ(LPGAMMATABLE g, LPGAMMATABLE gxyz[3])
-{
- int i;
- int nPoints = 4096;
- cmsCIELab Lab;
- cmsCIEXYZ XYZ;
- L16PARAMS L16;
-
- // Setup interpolation across origin
- cmsCalcL16Params(g ->nEntries, &L16);
-
- // Allocate curves
- gxyz[0] = cmsAllocGamma(nPoints);
- gxyz[1] = cmsAllocGamma(nPoints);
- gxyz[2] = cmsAllocGamma(nPoints);
-
- // Transport from Lab to XYZ
-
- for (i=0; i < nPoints; i++) {
-
- WORD val = _cmsQuantizeVal(i, nPoints);
- WORD w = cmsLinearInterpLUT16(val, g->GammaTable, &L16);
-
- Lab.L = ((double) 100.0 * w ) / 65535.0;
- Lab.a = Lab.b = 0;
-
- cmsLab2XYZ(NULL, &XYZ, &Lab);
-
- // Should be same curve
- gxyz[0] ->GammaTable[i] = (WORD) floor((65535.0 * XYZ.X) / D50X + 0.5);
- gxyz[1] ->GammaTable[i] = (WORD) floor((65535.0 * XYZ.Y) / D50Y + 0.5);
- gxyz[2] ->GammaTable[i] = (WORD) floor((65535.0 * XYZ.Z) / D50Z + 0.5);
- }
-}
-
-// Monochrome version
-
-static
-LPMATSHAPER cmsBuildGrayInputMatrixShaper(cmsHPROFILE hProfile)
-{
- cmsCIEXYZ Illuminant;
- LPGAMMATABLE GrayTRC, Shapes[3];
- LPMATSHAPER MatShaper;
- MAT3 Scale;
-
- GrayTRC = cmsReadICCGamma(hProfile, icSigGrayTRCTag); // Y
- if (GrayTRC == NULL) return NULL;
-
- cmsTakeIluminant(&Illuminant, hProfile);
-
- if (cmsGetPCS(hProfile) == icSigLabData) {
-
- // Fixup for Lab monochrome
- FromLstarToXYZ(GrayTRC, Shapes);
- }
- else {
- Shapes[0] = cmsDupGamma(GrayTRC);
- Shapes[1] = cmsDupGamma(GrayTRC);
- Shapes[2] = cmsDupGamma(GrayTRC);
- }
-
- if (!Shapes[0] || !Shapes[1] || !Shapes[2])
- return NULL;
-
- cmsFreeGamma(GrayTRC);
-
- // R=G=B as precondition
-
- VEC3init(&Scale.v[0], Illuminant.X/3, Illuminant.X/3, Illuminant.X/3);
- VEC3init(&Scale.v[1], Illuminant.Y/3, Illuminant.Y/3, Illuminant.Y/3);
- VEC3init(&Scale.v[2], Illuminant.Z/3, Illuminant.Z/3, Illuminant.Z/3);
-
-
- MatShaper = cmsAllocMatShaper(&Scale, Shapes, MATSHAPER_INPUT);
- cmsFreeGammaTriple(Shapes);
- return MatShaper;
-
-}
-
-
-// Monochrome as output
-
-static
-LPMATSHAPER cmsBuildGrayOutputMatrixShaper(cmsHPROFILE hProfile)
-{
- cmsCIEXYZ Illuminant;
- LPGAMMATABLE GrayTRC, Shapes[3];
- LPMATSHAPER MatShaper;
- MAT3 Scale;
-
- cmsTakeIluminant(&Illuminant, hProfile);
-
- // That is a special case for non-compliant profiles.
-
- if (cmsGetPCS(hProfile) == icSigLabData) {
-
- LPGAMMATABLE Shapes1[3];
-
- GrayTRC = cmsReadICCGamma(hProfile, icSigGrayTRCTag);
- FromLstarToXYZ(GrayTRC, Shapes1);
-
- // Reversing must be done after curve translation
-
- Shapes[0] = cmsReverseGamma(Shapes1[0]->nEntries, Shapes1[0]);
- Shapes[1] = cmsReverseGamma(Shapes1[1]->nEntries, Shapes1[1]);
- Shapes[2] = cmsReverseGamma(Shapes1[2]->nEntries, Shapes1[2]);
-
- cmsFreeGammaTriple(Shapes1);
-
- }
- else {
-
- // Normal case
-
- GrayTRC = cmsReadICCGammaReversed(hProfile, icSigGrayTRCTag); // Y
-
- Shapes[0] = cmsDupGamma(GrayTRC);
- Shapes[1] = cmsDupGamma(GrayTRC);
- Shapes[2] = cmsDupGamma(GrayTRC);
- }
-
- if (!Shapes[0] || !Shapes[1] || !Shapes[2])
- return NULL;
-
- cmsFreeGamma(GrayTRC);
-
- VEC3init(&Scale.v[0], 0, 1.0/Illuminant.Y, 0);
- VEC3init(&Scale.v[1], 0, 1.0/Illuminant.Y, 0);
- VEC3init(&Scale.v[2], 0, 1.0/Illuminant.Y, 0);
-
-
- MatShaper = cmsAllocMatShaper(&Scale, Shapes, MATSHAPER_OUTPUT);
- cmsFreeGammaTriple(Shapes);
- return MatShaper;
-
-}
-
-
-
-// Input matrix, only in XYZ
-
-LPMATSHAPER cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile)
-{
- MAT3 DoubleMat;
- LPGAMMATABLE Shapes[3];
- LPMATSHAPER InMatSh;
-
- // Check if this is a grayscale profile. If so, build
- // appropiate conversion tables. The tables are the PCS
- // iluminant, scaled across GrayTRC
-
- if (cmsGetColorSpace(InputProfile) == icSigGrayData)
- {
- return cmsBuildGrayInputMatrixShaper(InputProfile);
- }
-
- if (!cmsReadICCMatrixRGB2XYZ(&DoubleMat, InputProfile))
- return NULL;
-
- Shapes[0] = cmsReadICCGamma(InputProfile, icSigRedTRCTag);
- Shapes[1] = cmsReadICCGamma(InputProfile, icSigGreenTRCTag);
- Shapes[2] = cmsReadICCGamma(InputProfile, icSigBlueTRCTag);
-
- if (!Shapes[0] || !Shapes[1] || !Shapes[2])
- return NULL;
-
- InMatSh = cmsAllocMatShaper(&DoubleMat, Shapes, MATSHAPER_INPUT);
-
- cmsFreeGammaTriple(Shapes);
-
- return InMatSh;
-}
-
-
-// Output style matrix-shaper
-
-
-LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile)
-{
- MAT3 DoubleMat, DoubleInv;
- LPGAMMATABLE InverseShapes[3];
- LPMATSHAPER OutMatSh;
-
-
-
- if (cmsGetColorSpace(OutputProfile) == icSigGrayData)
- {
- return cmsBuildGrayOutputMatrixShaper(OutputProfile);
- }
-
-
- if (!cmsReadICCMatrixRGB2XYZ(&DoubleMat, OutputProfile))
- return NULL;
-
- if (MAT3inverse(&DoubleMat, &DoubleInv) < 0)
- return NULL;
-
-
- InverseShapes[0] = cmsReadICCGammaReversed(OutputProfile, icSigRedTRCTag);
- InverseShapes[1] = cmsReadICCGammaReversed(OutputProfile, icSigGreenTRCTag);
- InverseShapes[2] = cmsReadICCGammaReversed(OutputProfile, icSigBlueTRCTag);
-
- if (InverseShapes[0] == NULL ||
- InverseShapes[1] == NULL ||
- InverseShapes[2] == NULL) return NULL;
-
- OutMatSh = cmsAllocMatShaper(&DoubleInv, InverseShapes, MATSHAPER_OUTPUT);
-
- cmsFreeGammaTriple(InverseShapes);
-
- return OutMatSh;
-}
-
-
-
-// This function builds a transform matrix chaining parameters
-
-static
-LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p)
-{
- MAT3 From, To, ToInv, Transfer;
- LPGAMMATABLE In[3], InverseOut[3];
-
-
- if (!cmsReadICCMatrixRGB2XYZ(&From, p -> InputProfile))
- return FALSE;
-
-
- if (!cmsReadICCMatrixRGB2XYZ(&To, p -> OutputProfile))
- return FALSE;
-
- // invert dest
-
- if (MAT3inverse(&To, &ToInv) < 0)
- return FALSE;
-
- // Multiply
- MAT3per(&Transfer, &ToInv, &From);
-
-
- // Read gamma curves
-
- In[0] = cmsReadICCGamma(p -> InputProfile, icSigRedTRCTag);
- In[1] = cmsReadICCGamma(p -> InputProfile, icSigGreenTRCTag);
- In[2] = cmsReadICCGamma(p -> InputProfile, icSigBlueTRCTag);
-
- if (!In[0] || !In[1] || !In[2])
- return FALSE;
-
-
- InverseOut[0] = cmsReadICCGammaReversed(p -> OutputProfile, icSigRedTRCTag);
- InverseOut[1] = cmsReadICCGammaReversed(p -> OutputProfile, icSigGreenTRCTag);
- InverseOut[2] = cmsReadICCGammaReversed(p -> OutputProfile, icSigBlueTRCTag);
-
- if (!InverseOut[0] || !InverseOut[1] || !InverseOut[2]) {
- cmsFreeGammaTriple(In);
- return FALSE;
- }
-
- p -> SmeltMatShaper = cmsAllocMatShaper2(&Transfer, In, InverseOut, MATSHAPER_ALLSMELTED);
-
- cmsFreeGammaTriple(In);
- cmsFreeGammaTriple(InverseOut);
-
- return (p -> SmeltMatShaper != NULL);
-}
-
-
-
-
-// Conversion between PCS ------------------------------------------
-
-// Identifies intent archieved by LUT
-
-static
-int GetPhase(cmsHPROFILE hProfile)
-{
- switch (cmsGetPCS(hProfile)) {
-
- case icSigXYZData: return XYZRel;
-
- case icSigLabData: return LabRel;
-
- default: cmsSignalError(LCMS_ERRC_ABORTED, "Invalid PCS");
- }
-
- return XYZRel;
-}
-
-
+// Allocate transform struct and set it to defaults
static
-void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC)
-{
- cmsCIEXYZ BlackPointIn, WhitePointIn, IlluminantIn;
- cmsCIEXYZ BlackPointOut, WhitePointOut, IlluminantOut;
- cmsCIEXYZ BlackPointProof, WhitePointProof, IlluminantProof;
- MAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut;
- MAT3 ChromaticAdaptationMatrixProof;
-
-
- cmsTakeIluminant(&IlluminantIn, p -> InputProfile);
- cmsTakeMediaWhitePoint(&WhitePointIn, p -> InputProfile);
- cmsTakeMediaBlackPoint(&BlackPointIn, p -> InputProfile);
- cmsReadChromaticAdaptationMatrix(&ChromaticAdaptationMatrixIn, p -> InputProfile);
-
- cmsTakeIluminant(&IlluminantOut, p -> OutputProfile);
- cmsTakeMediaWhitePoint(&WhitePointOut, p -> OutputProfile);
- cmsTakeMediaBlackPoint(&BlackPointOut, p -> OutputProfile);
- cmsReadChromaticAdaptationMatrix(&ChromaticAdaptationMatrixOut, p -> OutputProfile);
-
-
- if (p -> Preview == NULL && p ->Gamut == NULL) // Non-proofing
- {
- if (p ->Intent == INTENT_PERCEPTUAL ||
- p ->Intent == INTENT_SATURATION) {
-
-
- // For v4 profiles, Perceptual PCS has a reference black point
- // which v2 profiles should scale to.
-
- if ((cmsGetProfileICCversion(p ->InputProfile) >= 0x4000000) ||
- (cmsGetProfileICCversion(p ->OutputProfile) >= 0x4000000)) {
-
- DoBPC = TRUE;
- }
- }
-
- // Black point compensation does not apply to absolute intent
-
- if (p ->Intent == INTENT_ABSOLUTE_COLORIMETRIC)
- DoBPC = FALSE;
-
- // Black point compensation does not apply to devicelink profiles
-
- if (cmsGetDeviceClass(p ->InputProfile) == icSigLinkClass)
- DoBPC = FALSE;
-
- if (cmsGetDeviceClass(p ->OutputProfile) == icSigLinkClass)
- DoBPC = FALSE;
-
- if (DoBPC) {
-
- // Detect Black points
-
- cmsDetectBlackPoint(&BlackPointIn, p->InputProfile, p->Intent, 0);
- cmsDetectBlackPoint(&BlackPointOut, p->OutputProfile, p->Intent, 0);
-
- // If equal black points, then do nothing. This often applies to BP=0
-
- if (BlackPointIn.X == BlackPointOut.X &&
- BlackPointIn.Y == BlackPointOut.Y &&
- BlackPointIn.Z == BlackPointOut.Z)
- DoBPC = FALSE;
-
-
- }
-
- cmsChooseCnvrt(p -> Intent == INTENT_ABSOLUTE_COLORIMETRIC,
-
- p -> Phase1,
- &BlackPointIn,
- &WhitePointIn,
- &IlluminantIn,
- &ChromaticAdaptationMatrixIn,
-
- p -> Phase3,
- &BlackPointOut,
- &WhitePointOut,
- &IlluminantOut,
- &ChromaticAdaptationMatrixOut,
-
- DoBPC,
- p ->AdaptationState,
- &p->Stage1,
- &p->m1, &p->of1);
-
- }
- else // Proofing
- {
-
-
- cmsTakeIluminant(&IlluminantProof, p -> PreviewProfile);
- cmsTakeMediaWhitePoint(&WhitePointProof, p -> PreviewProfile);
- cmsTakeMediaBlackPoint(&BlackPointProof, p -> PreviewProfile);
- cmsReadChromaticAdaptationMatrix(&ChromaticAdaptationMatrixProof, p -> PreviewProfile);
-
- if (DoBPC) {
-
- cmsDetectBlackPoint(&BlackPointProof, p->PreviewProfile, p->Intent, 0);
- cmsDetectBlackPoint(&BlackPointIn, p->InputProfile, p->Intent, 0);
- cmsDetectBlackPoint(&BlackPointOut, p->OutputProfile, p->Intent, 0);
-
- // Reality check
-
- if (BlackPointIn.X == BlackPointProof.X &&
- BlackPointIn.Y == BlackPointProof.Y &&
- BlackPointIn.Z == BlackPointProof.Z)
- DoBPC = FALSE;
-
-
- }
-
-
-
- cmsChooseCnvrt(p -> Intent == INTENT_ABSOLUTE_COLORIMETRIC,
-
- p -> Phase1,
- &BlackPointIn,
- &WhitePointIn,
- &IlluminantIn,
- &ChromaticAdaptationMatrixIn,
-
- p -> Phase2,
- &BlackPointProof,
- &WhitePointProof,
- &IlluminantProof,
- &ChromaticAdaptationMatrixProof,
- DoBPC,
- p ->AdaptationState,
- &p->Stage1,
- &p->m1, &p->of1);
-
- cmsChooseCnvrt(p -> ProofIntent == INTENT_ABSOLUTE_COLORIMETRIC,
-
- p -> Phase2,
- &BlackPointProof,
- &WhitePointProof,
- &IlluminantProof,
- &ChromaticAdaptationMatrixProof,
-
- p -> Phase3,
- &BlackPointOut,
- &WhitePointOut,
- &IlluminantOut,
- &ChromaticAdaptationMatrixOut,
- 0,
- 0.0,
- &p->Stage2,
- &p->m2, &p->of2);
- }
-
-}
-
-
-// Check colorspace
-
-static
-LCMSBOOL IsProperColorSpace(cmsHPROFILE hProfile, DWORD dwFormat, LCMSBOOL lUsePCS)
-{
- int Space = T_COLORSPACE(dwFormat);
-
- if (Space == PT_ANY) return TRUE;
-
- if (lUsePCS)
- return (Space == _cmsLCMScolorSpace(cmsGetPCS(hProfile)));
- else
- return (Space == _cmsLCMScolorSpace(cmsGetColorSpace(hProfile)));
-}
-
-
-// Auxiliary: allocate transform struct and set to defaults
-
-static
-_LPcmsTRANSFORM AllocEmptyTransform(void)
+_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags)
{
// Allocate needed memory
-
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) _cmsMalloc(sizeof(_cmsTRANSFORM));
- if (!p) {
+ _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
+ if (!p) return NULL;
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateTransform: _cmsMalloc() failed");
- return NULL;
- }
-
- ZeroMemory(p, sizeof(_cmsTRANSFORM));
-
- // Initialize default methods
+ // Check whatever this is a true floating point transform
+ if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) {
- p -> xform = NULL;
- p -> Intent = INTENT_PERCEPTUAL;
- p -> ProofIntent = INTENT_ABSOLUTE_COLORIMETRIC;
- p -> DoGamutCheck = FALSE;
- p -> InputProfile = NULL;
- p -> OutputProfile = NULL;
- p -> PreviewProfile = NULL;
- p -> Preview = NULL;
- p -> Gamut = NULL;
- p -> DeviceLink = NULL;
- p -> InMatShaper = NULL;
- p -> OutMatShaper = NULL;
- p -> SmeltMatShaper = NULL;
- p -> NamedColorList = NULL;
- p -> EntryColorSpace = (icColorSpaceSignature) 0;
- p -> ExitColorSpace = (icColorSpaceSignature) 0;
- p -> AdaptationState = GlobalAdaptationState;
+ // Get formatter function always return a valid union, but the contents of this union may be NULL.
+ p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- LCMS_CREATE_LOCK(&p->rwlock);
-
- return p;
-}
-
-
-// Identify whatever a transform is to be cached
+ if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
-static
-void SetPrecalculatedTransform(_LPcmsTRANSFORM p)
-{
- if ((p->dwOriginalFlags & cmsFLAGS_GAMUTCHECK) && p ->GamutCheck != NULL) {
-
- p -> xform = PrecalculatedXFORMGamutCheck;
-
- if (!(p->dwOriginalFlags & cmsFLAGS_NOTCACHE)) {
-
- ZeroMemory(p ->CacheIn, sizeof(WORD) * MAXCHANNELS);
- TransformOnePixelWithGamutCheck(p, p->CacheIn, p ->CacheOut);
- p ->xform = CachedXFORMGamutCheck;
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
+ _cmsFree(ContextID, p);
+ return NULL;
}
+ // Float transforms don't use caché, always are non-NULL
+ p ->xform = FloatXFORM;
}
else {
- p -> xform = PrecalculatedXFORM;
-
- if (!(p->dwOriginalFlags & cmsFLAGS_NOTCACHE)) {
-
- ZeroMemory(p ->CacheIn, sizeof(WORD) * MAXCHANNELS);
- cmsEvalLUT(p ->DeviceLink, p->CacheIn, p ->CacheOut);
- p ->xform = CachedXFORM;
- }
- }
-}
-
-
-// Transform is identified as device-link
-static
-cmsHPROFILE CreateDeviceLinkTransform(_LPcmsTRANSFORM p)
-{
-
- if (!IsProperColorSpace(p->InputProfile, p->InputFormat, FALSE)) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Device link is operating on wrong colorspace on input");
- return NULL;
- }
-
- if (!IsProperColorSpace(p->InputProfile, p->OutputFormat, TRUE)) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Device link is operating on wrong colorspace on output");
- return NULL;
- }
-
- // Device link does only have AToB0Tag (ICC-Spec 1998/09)
-
- p->DeviceLink = cmsReadICCLut(p->InputProfile, icSigAToB0Tag);
-
- if (!p->DeviceLink) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Noncompliant device-link profile");
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
- }
-
- if (p ->PreviewProfile != NULL) {
- cmsSignalError(LCMS_ERRC_WARNING, "Proofing not supported on device link transforms");
- }
-
- if (p ->OutputProfile != NULL) {
- cmsSignalError(LCMS_ERRC_WARNING, "Output profile should be NULL, since this is a device-link transform");
- }
+ p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p -> Phase1 = -1;
- p -> Phase2 = -1;
- p -> Phase3 = -1;
-
- SetPrecalculatedTransform(p);
-
- p -> EntryColorSpace = cmsGetColorSpace(p -> InputProfile);
- p -> ExitColorSpace = cmsGetPCS(p -> InputProfile);
-
- if (p ->EntryColorSpace == icSigRgbData ||
- p ->EntryColorSpace == icSigCmyData) {
-
- p->DeviceLink -> CLut16params.Interp3D = cmsTetrahedralInterp16;
- }
-
- // Precalculated device-link profile is ready
- return (cmsHTRANSFORM) p;
-}
-
-
-// Transform that includes proofing
-static
-void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr)
+ if (p ->FromInput == NULL || p ->ToOutput == NULL) {
-{
- icTagSignature ProofTag;
-
- if (p -> dwOriginalFlags & cmsFLAGS_SOFTPROOFING) {
-
- // Apr-15, 2002 - Too much profiles does have bogus content
- // on preview tag, so I do compute it by my own.
-
- p -> Preview = _cmsComputeSoftProofLUT(p ->PreviewProfile, p ->Intent);
- p -> Phase2 = LabRel;
-
- // That's a proofing transfor, so use second intent for output.
-
- *ToTagPtr = PCS2Device[p->ProofIntent];
-
- if (p -> Preview == NULL) {
-
- ProofTag = Preview[p -> Intent];
-
- if (!cmsIsTag(p ->PreviewProfile, ProofTag)) {
-
- ProofTag = Preview[0];
- if (!cmsIsTag(p ->PreviewProfile, ProofTag))
- ProofTag = (icTagSignature)0;
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
+ _cmsFree(ContextID, p);
+ return NULL;
}
- if (ProofTag) {
+ if (dwFlags & cmsFLAGS_NULLTRANSFORM) {
- p -> Preview = cmsReadICCLut(p ->PreviewProfile, ProofTag);
- p -> Phase2 = GetPhase(p ->PreviewProfile);
-
+ p ->xform = NullXFORM;
}
- else
- {
- p -> Preview = NULL;
- p ->PreviewProfile = NULL;
- cmsSignalError(LCMS_ERRC_WARNING, "Sorry, the proof profile has not previewing capabilities");
- }
- }
+ else {
+ if (dwFlags & cmsFLAGS_NOCACHE) {
+ if (dwFlags & cmsFLAGS_GAMUTCHECK)
+ p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché
+ else
+ p ->xform = PrecalculatedXFORM; // No caché, no gamut check
+ }
+ else {
+
+ if (dwFlags & cmsFLAGS_GAMUTCHECK)
+ p ->xform = CachedXFORMGamutCheck; // Gamut check, caché
+ else
+ p ->xform = CachedXFORM; // No gamut check, caché
+
+ }
+ }
}
- // Aug-31, 2001 - Too much profiles does have bogus content
- // on gamut tag, so I do compute it by my own.
-
- if ((p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK) && (p -> dwOriginalFlags & cmsFLAGS_NOTPRECALC)) {
-
-
- p -> Gamut = _cmsComputeGamutLUT(p->PreviewProfile, p ->Intent);
- p -> Phase2 = LabRel;
-
- if (p -> Gamut == NULL) {
-
- // Profile goes only in one direction... try to see
- // if profile has the tag, and use it, no matter it
- // could be bogus. This is the last chance!
-
- if (cmsIsTag(p ->PreviewProfile, icSigGamutTag)) {
-
- p -> Gamut = cmsReadICCLut(p ->PreviewProfile, icSigGamutTag);
-
- }
- else {
-
- // Nope, cannot be done.
-
- cmsSignalError(LCMS_ERRC_WARNING, "Sorry, the proof profile has not gamut checking capabilities");
- p -> Gamut = NULL;
- }
- }
-
- }
-
-}
-
-// Choose the adequate transform routine
-
-static
-_LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p,
- icTagSignature *FromTagPtr,
- icTagSignature *ToTagPtr)
-{
-
-
-
-
- // Is a named color profile?
- if (cmsGetDeviceClass(p->InputProfile) == icSigNamedColorClass) {
-
- // Yes, and used as input
- p ->FromDevice = NC2toPCS;
- }
- else {
- // Can we optimize matrix-shaper only transform?
-
- if ((*FromTagPtr == 0) &&
- (*ToTagPtr == 0) &&
- (!p->PreviewProfile) &&
- (p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC) &&
- (p -> EntryColorSpace == icSigRgbData) &&
- (p -> ExitColorSpace == icSigRgbData) &&
- !(p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION)) {
-
- // Yes... try to smelt matrix-shapers
- p -> xform = MatrixShaperXFORM;
- p -> dwOriginalFlags |= cmsFLAGS_NOTPRECALC;
+ // Create a mutex for shared memory
+ LCMS_CREATE_LOCK(&p->rwlock);
- if (!cmsBuildSmeltMatShaper(p))
- {
- cmsSignalError(LCMS_ERRC_ABORTED, "unable to smelt shaper-matrix, required tags missing");
- return NULL;
- }
-
- p -> Phase1 = p -> Phase3 = XYZRel;
- return p;
-
- }
-
- // No, is a transform involving LUT
-
- if (*FromTagPtr != 0) {
-
- p -> FromDevice = LUTtoPCS;
- p -> Device2PCS = cmsReadICCLut(p -> InputProfile, *FromTagPtr);
- if (!p -> Device2PCS) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for input");
- return NULL;
- }
-
- }
- else
- {
- p -> FromDevice = ShaperMatrixToPCS;
- p -> InMatShaper = cmsBuildInputMatrixShaper(p -> InputProfile);
-
- if (!p ->InMatShaper) {
- cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for input");
- return NULL;
- }
-
- p -> Phase1 = XYZRel;
-
- }
- }
-
- if (*ToTagPtr != 0) {
-
- p -> ToDevice = PCStoLUT;
- p -> PCS2Device = cmsReadICCLut(p -> OutputProfile, *ToTagPtr);
- if (!p -> PCS2Device) {
- cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for output");
- return NULL;
- }
-
- }
- else
- {
- p -> ToDevice = PCStoShaperMatrix;
- p -> OutMatShaper = cmsBuildOutputMatrixShaper(p->OutputProfile);
-
- if (!p -> OutMatShaper) {
- cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for output");
- return NULL;
- }
- p -> Phase3 = XYZRel;
-
- }
-
-
- return p;
+ p ->InputFormat = InputFormat;
+ p ->OutputFormat = OutputFormat;
+ p ->dwOriginalFlags = dwFlags;
+ p ->ContextID = ContextID;
+ return p;
}
-
-
-
-// Create a transform.
-
-cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
- DWORD InputFormat,
- cmsHPROFILE OutputProfile,
- DWORD OutputFormat,
- cmsHPROFILE ProofingProfile,
- int nIntent,
- int ProofingIntent,
- DWORD dwFlags)
-
+static
+cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
{
- _LPcmsTRANSFORM p;
- icTagSignature FromTag;
- icTagSignature ToTag;
-
- if (nIntent < 0 || nIntent > 3 ||
- ProofingIntent < 0 || ProofingIntent > 3) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateTransform: intent mismatch");
- return NULL;
- }
-
- p = AllocEmptyTransform();
- if (p == NULL) return NULL;
-
- p -> xform = NormalXFORM;
- p -> Intent = nIntent;
- p -> ProofIntent = ProofingIntent;
- p -> DoGamutCheck = FALSE;
- p -> InputProfile = InputProfile;
- p -> OutputProfile = OutputProfile;
- p -> PreviewProfile = ProofingProfile;
- p -> InputFormat = InputFormat;
- p -> OutputFormat = OutputFormat;
- p -> dwOriginalFlags = dwFlags;
-
- p -> lInputV4Lab = p ->lOutputV4Lab = FALSE;
-
-
- p -> FromInput = _cmsIdentifyInputFormat(p, InputFormat);
- p -> ToOutput = _cmsIdentifyOutputFormat(p, OutputFormat);
-
- // Null transform can be done without profiles
- if ((p->dwOriginalFlags & cmsFLAGS_NULLTRANSFORM) ||
- ((InputProfile == NULL) &&
- (OutputProfile == NULL))) {
-
- p -> xform = NullXFORM;
- return (cmsHTRANSFORM) p;
- }
-
- // From here we need at least one input profile
- if (InputProfile == NULL) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Input profile cannot be NULL!");
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
- }
-
-
- // Device link are means to store precalculated transform grids.
- if (cmsGetDeviceClass(InputProfile) == icSigLinkClass) {
-
- return CreateDeviceLinkTransform(p);
- }
-
- if (!IsProperColorSpace(InputProfile, InputFormat, FALSE)) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Input profile is operating on wrong colorspace");
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
- }
-
- p ->EntryColorSpace = cmsGetColorSpace(InputProfile);
-
- // Oct-21-2002: Added named color transforms
- if (cmsGetDeviceClass(InputProfile) == icSigNamedColorClass) {
-
- if (p ->NamedColorList == NULL)
- p ->NamedColorList = cmsAllocNamedColorList(0);
-
- cmsReadICCnamedColorList(p, InputProfile, icSigNamedColor2Tag);
-
- // Special case. If output profile == NULL, then the transform gives
- // device values from named colors.
-
- if (OutputProfile == NULL) {
-
- p ->ExitColorSpace = p -> EntryColorSpace;
- p ->xform = NC2deviceXform;
- return (cmsHTRANSFORM) p;
- }
-
- // Named color doesn't precalc anything
- p -> dwOriginalFlags |= cmsFLAGS_NOTPRECALC;
- }
-
-
- // From here we need also output profile.
- if (OutputProfile == NULL) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Output profile cannot be NULL!");
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
- }
-
-
- if (!IsProperColorSpace(OutputProfile, OutputFormat, FALSE)) {
- cmsSignalError(LCMS_ERRC_ABORTED, "Output profile is operating on wrong colorspace");
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
- }
-
- p -> ExitColorSpace = cmsGetColorSpace(OutputProfile);
-
- // Named color only on input
- if (cmsGetDeviceClass(OutputProfile) == icSigNamedColorClass) {
-
- cmsSignalError(LCMS_ERRC_ABORTED, "Named color profiles are not supported as output");
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
- }
-
- p -> Phase1 = GetPhase(InputProfile);
- p -> Phase2 = -1;
- p -> Phase3 = GetPhase(OutputProfile);
-
- // Try to locate a LUT
-
- FromTag = Device2PCS[nIntent];
- ToTag = PCS2Device[nIntent];
-
- if (!cmsIsTag(InputProfile, FromTag)) {
-
- FromTag = Device2PCS[0];
-
- if (!cmsIsTag(InputProfile, FromTag)) {
- FromTag = (icTagSignature)0;
- }
- }
-
- // If proofing is needed, add required tags/parameters
- if (ProofingProfile)
- CreateProof(p, &ToTag);
-
-
- if (!cmsIsTag(OutputProfile, ToTag)) {
-
- ToTag = PCS2Device[0];
-
- // 12-Dec-2003, Abstract profiles can be placed as output and still using AToB0
- if (cmsGetDeviceClass(OutputProfile) == icSigAbstractClass) {
-
- if (!cmsIsTag(OutputProfile, ToTag)) {
- ToTag = (icTagSignature) icSigAToB0Tag;
- }
- }
-
- if (!cmsIsTag(OutputProfile, ToTag))
- ToTag = (icTagSignature)0;
- }
-
-
- if (p-> dwOriginalFlags & cmsFLAGS_MATRIXINPUT)
- FromTag = (icTagSignature)0;
-
- if (p -> dwOriginalFlags & cmsFLAGS_MATRIXOUTPUT)
- ToTag = (icTagSignature)0;
-
-
-
- if (PickTransformRoutine(p, &FromTag, &ToTag) == NULL) {
-
- cmsDeleteTransform((cmsHTRANSFORM) p);
- return NULL;
-
- }
-
- TakeConversionRoutines(p, dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
-
- if (!(p -> dwOriginalFlags & cmsFLAGS_NOTPRECALC)) {
-
- LPLUT DeviceLink;
- LPLUT GamutCheck = NULL;
-
-
- if (p ->EntryColorSpace == icSigCmykData &&
- p ->ExitColorSpace == icSigCmykData &&
- (dwFlags & cmsFLAGS_PRESERVEBLACK)) {
-
- DeviceLink = _cmsPrecalculateBlackPreservingDeviceLink((cmsHTRANSFORM) p, dwFlags);
-
- // Cannot be done at all?
- if (DeviceLink == NULL)
- DeviceLink = _cmsPrecalculateDeviceLink((cmsHTRANSFORM) p, dwFlags);
-
- }
- else {
-
- DeviceLink = _cmsPrecalculateDeviceLink((cmsHTRANSFORM) p, dwFlags);
- }
-
- // Allow to specify cmsFLAGS_GAMUTCHECK, even if no proofing profile is given
- if ((p ->PreviewProfile != NULL) && (p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK)) {
-
- GamutCheck = _cmsPrecalculateGamutCheck((cmsHTRANSFORM) p);
- }
-
- // If input colorspace is Rgb, Cmy, then use tetrahedral interpolation
- // for speed reasons (it only works well on spaces on Luma is diagonal, and
- // not if luma is in separate channel)
- if (p ->EntryColorSpace == icSigRgbData ||
- p ->EntryColorSpace == icSigCmyData) {
-
-
- cmsCalcCLUT16ParamsEx(DeviceLink->CLut16params.nSamples,
- DeviceLink->CLut16params.nInputs,
- DeviceLink->CLut16params.nOutputs,
- TRUE, &DeviceLink->CLut16params);
-
- }
-
- // If this is a 8-bit transform, optimize LUT further.
-
- if ((T_BYTES(InputFormat) == 1) && (T_CHANNELS(InputFormat) == 3)) {
-
- DeviceLink = _cmsBlessLUT8(DeviceLink);
- if (DeviceLink == NULL) return NULL;
-
- }
-
-
- p ->GamutCheck = GamutCheck;
-
- if (DeviceLink) {
-
- p ->DeviceLink = DeviceLink;
-
- if ((nIntent != INTENT_ABSOLUTE_COLORIMETRIC) &&
- !(p -> dwOriginalFlags & cmsFLAGS_NOWHITEONWHITEFIXUP))
-
- _cmsFixWhiteMisalignment(p);
-
- }
- else
- {
-
- cmsSignalError(LCMS_ERRC_ABORTED,
- "Cannot precalculate %d->%d channels transform!",
- T_CHANNELS(InputFormat), T_CHANNELS(OutputFormat));
-
- cmsDeleteTransform(p);
- return NULL;
- }
-
-
- SetPrecalculatedTransform(p);
-
-
- }
-
- // Re-Identify formats
- p -> FromInput = _cmsIdentifyInputFormat(p, InputFormat);
- p -> ToOutput = _cmsIdentifyOutputFormat(p, OutputFormat);
-
-
- return p;
-}
-
-
-// Wrapper por simpler non-proofing transforms.
-
-cmsHTRANSFORM LCMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
- DWORD InputFormat,
- cmsHPROFILE Output,
- DWORD OutputFormat,
- int Intent,
- DWORD dwFlags)
-
-{
- return cmsCreateProofingTransform(Input, InputFormat,
- Output, OutputFormat,
- NULL,
- Intent, INTENT_ABSOLUTE_COLORIMETRIC,
- dwFlags);
-}
-
-
-// Profiles are *NOT* closed
-
-void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
-{
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) (LPSTR) hTransform;
-
- if (p -> Device2PCS)
- cmsFreeLUT(p -> Device2PCS);
- if (p -> PCS2Device)
- cmsFreeLUT(p -> PCS2Device);
- if (p -> Gamut)
- cmsFreeLUT(p -> Gamut);
- if (p -> Preview)
- cmsFreeLUT(p -> Preview);
- if (p -> DeviceLink)
- cmsFreeLUT(p -> DeviceLink);
- if (p -> InMatShaper)
- cmsFreeMatShaper(p -> InMatShaper);
- if (p -> OutMatShaper)
- cmsFreeMatShaper(p -> OutMatShaper);
- if (p -> SmeltMatShaper)
- cmsFreeMatShaper(p -> SmeltMatShaper);
- if (p ->NamedColorList)
- cmsFreeNamedColorList(p ->NamedColorList);
- if (p -> GamutCheck)
- cmsFreeLUT(p -> GamutCheck);
-
- LCMS_FREE_LOCK(&p->rwlock);
-
- _cmsFree((void *) p);
-}
-
-
-// Apply transform code
-void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
- LPVOID InputBuffer,
- LPVOID OutputBuffer, unsigned int Size)
-
-{
-
- _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) (LPSTR) Transform;
-
- p -> StrideIn = p -> StrideOut = Size;
-
- p -> xform(p, InputBuffer, OutputBuffer, Size);
-
-}
-
-
-void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b)
-{
- AlarmR = RGB_8_TO_16(r);
- AlarmG = RGB_8_TO_16(g);
- AlarmB = RGB_8_TO_16(b);
-}
-
-void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b)
-{
- *r = RGB_16_TO_8(AlarmR);
- *g = RGB_16_TO_8(AlarmG);
- *b = RGB_16_TO_8(AlarmB);
-}
-
-// Returns TRUE if the profile is implemented as matrix-shaper
-
-LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile)
-{
- switch (cmsGetColorSpace(hProfile)) {
-
- case icSigGrayData:
-
- return cmsIsTag(hProfile, icSigGrayTRCTag);
-
- case icSigRgbData:
-
- return (cmsIsTag(hProfile, icSigRedColorantTag) &&
- cmsIsTag(hProfile, icSigGreenColorantTag) &&
- cmsIsTag(hProfile, icSigBlueColorantTag) &&
- cmsIsTag(hProfile, icSigRedTRCTag) &&
- cmsIsTag(hProfile, icSigGreenTRCTag) &&
- cmsIsTag(hProfile, icSigBlueTRCTag));
-
- default:
-
- return FALSE;
- }
-}
-
-
-LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile,
- int Intent, int UsedDirection)
-{
-
- icTagSignature* TagTable;
-
- // Device link profiles only implements the intent in header
-
- if (cmsGetDeviceClass(hProfile) != icSigLinkClass) {
-
- switch (UsedDirection) {
-
- case LCMS_USED_AS_INPUT: TagTable = Device2PCS; break;
- case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device; break;
- case LCMS_USED_AS_PROOF: TagTable = Preview; break;
-
- default:
- cmsSignalError(LCMS_ERRC_ABORTED, "Unexpected direction (%d)", UsedDirection);
- return FALSE;
- }
-
- if (cmsIsTag(hProfile, TagTable[Intent])) return TRUE;
- return _cmsIsMatrixShaper(hProfile);
- }
-
- return (cmsTakeRenderingIntent(hProfile) == Intent);
-}
-
-// Multiple profile transform.
-static
-int MultiprofileSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
-{
- cmsHTRANSFORM* Transforms = (cmsHTRANSFORM*) Cargo;
+ cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
+ cmsColorSpaceSignature PostColorSpace;
int i;
- cmsDoTransform(Transforms[0], In, Out, 1);
-
- for (i=1; Transforms[i]; i++)
- cmsDoTransform(Transforms[i], Out, Out, 1);
-
-
-
- return TRUE;
-}
-
-
-static
-int IsAllowedInSingleXform(icProfileClassSignature aClass)
-{
- return (aClass == icSigInputClass) ||
- (aClass == icSigDisplayClass) ||
- (aClass == icSigOutputClass) ||
- (aClass == icSigColorSpaceClass);
-}
-
-
-// A multiprofile transform does chain several profiles into a single
-// devicelink. It couls also be used to merge named color profiles into
-// a single database.
-
-
-cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
- int nProfiles,
- DWORD dwInput,
- DWORD dwOutput,
- int Intent,
- DWORD dwFlags)
-{
- cmsHTRANSFORM Transforms[257];
- DWORD dwPrecalcFlags = (dwFlags|cmsFLAGS_NOTPRECALC|cmsFLAGS_NOTCACHE);
- DWORD FormatInput, FormatOutput;
- cmsHPROFILE hLab, hXYZ, hProfile;
- icColorSpaceSignature ColorSpace, CurrentColorSpace;
- icColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
- LPLUT Grid;
- int nGridPoints, ChannelsInput, ChannelsOutput = 3, i;
- _LPcmsTRANSFORM p;
- int nNamedColor;
-
- if (nProfiles > 255) {
- cmsSignalError(LCMS_ERRC_ABORTED, "What are you trying to do with more that 255 profiles?!?, of course aborted");
- return NULL;
- }
-
- // There is a simple case with just two profiles, try to catch it in order of getting
- // black preservation to work on this function, at least with two profiles.
-
-
- if (nProfiles == 2) {
-
- icProfileClassSignature Class1 = cmsGetDeviceClass(hProfiles[0]);
- icProfileClassSignature Class2 = cmsGetDeviceClass(hProfiles[1]);
+ if (hProfiles[0] == NULL) return FALSE;
- // Only input, output and display are allowed
-
- if (IsAllowedInSingleXform(Class1) &&
- IsAllowedInSingleXform(Class2))
- return cmsCreateTransform(hProfiles[0], dwInput, hProfiles[1], dwOutput, Intent, dwFlags);
- }
-
-
- // Creates a phantom transform for latter filling
- p = (_LPcmsTRANSFORM) cmsCreateTransform(NULL, dwInput,
- NULL, dwOutput, Intent, cmsFLAGS_NULLTRANSFORM);
-
- // If user wants null one, give it
- if (dwFlags & cmsFLAGS_NULLTRANSFORM) return (cmsHPROFILE) p;
-
- // Is a bunch of named color profiles?
- nNamedColor = 0;
- for (i=0; i < nProfiles; i++) {
- if (cmsGetDeviceClass(hProfiles[i]) == icSigNamedColorClass)
- nNamedColor++;
- }
-
-
- if (nNamedColor == nProfiles) {
-
- // Yes, only named color. Create a named color-device
- // and append to named color table
-
- cmsDeleteTransform((cmsHTRANSFORM) p);
-
- p = (_LPcmsTRANSFORM) cmsCreateTransform(hProfiles[0], dwInput, NULL, dwOutput, Intent, dwFlags);
- for (i=1; i < nProfiles; i++) {
- cmsReadICCnamedColorList(p, hProfiles[i], icSigNamedColor2Tag);
- }
-
- return p; // Ok, done so far
- }
- else
- if (nNamedColor > 0) {
-
- cmsDeleteTransform((cmsHTRANSFORM) p);
- cmsSignalError(LCMS_ERRC_ABORTED, "Could not mix named color profiles with other types in multiprofile transform");
- return NULL;
- }
-
-
- // We will need a 3DCLUT for device link
- Grid = cmsAllocLUT();
- if (!Grid) return NULL;
-
- // This one is our PCS (Always Lab)
- hLab = cmsCreateLabProfile(NULL);
- hXYZ = cmsCreateXYZProfile();
-
- if (!hLab || !hXYZ) goto ErrorCleanup;
-
- // Take some info....
-
- p ->EntryColorSpace = CurrentColorSpace = cmsGetColorSpace(hProfiles[0]);
-
+ *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
for (i=0; i < nProfiles; i++) {
- int lIsDeviceLink, lIsInput;
-
- // Check colorspace
+ cmsHPROFILE hProfile = hProfiles[i];
- hProfile = hProfiles[i];
- lIsDeviceLink = (cmsGetDeviceClass(hProfile) == icSigLinkClass);
- lIsInput = (CurrentColorSpace != icSigXYZData) &&
- (CurrentColorSpace != icSigLabData);
+ int lIsInput = (PostColorSpace != cmsSigXYZData) &&
+ (PostColorSpace != cmsSigLabData);
+
+ if (hProfile == NULL) return FALSE;
if (lIsInput) {
ColorSpaceIn = cmsGetColorSpace(hProfile);
ColorSpaceOut = cmsGetPCS(hProfile);
-
}
else {
@@ -1912,136 +486,302 @@
ColorSpaceOut = cmsGetColorSpace(hProfile);
}
- ChannelsInput = _cmsChannelsOf(ColorSpaceIn);
- ChannelsOutput = _cmsChannelsOf(ColorSpaceOut);
+ PostColorSpace = ColorSpaceOut;
+ }
+
+ *Output = PostColorSpace;
+
+ return TRUE;
+}
+
+// Check colorspace
+static
+cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
+{
+ int Space1 = T_COLORSPACE(dwFormat);
+ int Space2 = _cmsLCMScolorSpace(Check);
+
+ if (Space1 == PT_ANY) return TRUE;
+ if (Space1 == Space2) return TRUE;
+
+ if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
+ if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
+
+ return FALSE;
+}
+
+// ----------------------------------------------------------------------------------------------------------------
- FormatInput = BYTES_SH(2)|CHANNELS_SH(ChannelsInput);
- FormatOutput = BYTES_SH(2)|CHANNELS_SH(ChannelsOutput);
+// New to lcms 2.0 -- have all parameters available.
+cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
+ cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsUInt32Number Intents[],
+ cmsFloat64Number AdaptationStates[],
+ cmsHPROFILE hGamutProfile,
+ cmsUInt32Number nGamutPCSposition,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number dwFlags)
+{
+ _cmsTRANSFORM* xform;
+ cmsBool FloatTransform;
+ cmsColorSpaceSignature EntryColorSpace;
+ cmsColorSpaceSignature ExitColorSpace;
+ cmsPipeline* Lut;
+ cmsUInt32Number LastIntent = Intents[nProfiles-1];
+
+ // If gamut check is requested, make sure we have a gamut profile
+ if (dwFlags & cmsFLAGS_GAMUTCHECK) {
+ if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
+ }
+
+ // On floating point transforms, inhibit optimizations
+ FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat));
- ColorSpace = ColorSpaceIn;
+ if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
+ dwFlags |= cmsFLAGS_NOCACHE;
+
+ // Mark entry/exit spaces
+ if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
+ cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
+ return NULL;
+ }
+
+ // Check if proper colorspaces
+ if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
+ cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
+ return NULL;
+ }
+
+ if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
+ cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
+ return NULL;
+ }
+
+ // Create a pipeline with all transformations
+ Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+ if (Lut == NULL) {
+ cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
+ return NULL;
+ }
+
+ // Optimize the LUT if possible
+ _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
- if (ColorSpace == CurrentColorSpace) {
-
- if (lIsDeviceLink) {
-
- Transforms[i] = cmsCreateTransform(hProfile, FormatInput,
- NULL, FormatOutput,
- Intent, dwPrecalcFlags);
- }
-
- else {
+ // All seems ok
+ xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
+ if (xform == NULL) {
+ cmsPipelineFree(Lut);
+ return NULL;
+ }
- if (lIsInput) {
+ // Keep values
+ xform ->EntryColorSpace = EntryColorSpace;
+ xform ->ExitColorSpace = ExitColorSpace;
+ xform ->Lut = Lut;
+
- Transforms[i] = cmsCreateTransform(hProfile, FormatInput,
- (ColorSpaceOut == icSigLabData ? hLab : hXYZ), FormatOutput,
- Intent, dwPrecalcFlags);
- }
- else {
- Transforms[i] = cmsCreateTransform((ColorSpaceIn == icSigLabData ? hLab : hXYZ), FormatInput,
- hProfile, FormatOutput,
- Intent, dwPrecalcFlags);
-
- }
- }
+ // Create a gamut check LUT if requested
+ if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
+ xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
+ BPC, Intents,
+ AdaptationStates,
+ nGamutPCSposition,
+ hGamutProfile);
- }
- else // Can come from pcs?
- if (CurrentColorSpace == icSigXYZData) {
+ // Try to read input and output colorant table
+ if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
+
+ // Input table can only come in this way.
+ xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
+ }
- Transforms[i] = cmsCreateTransform(hXYZ, FormatInput,
- hProfile, FormatOutput,
- Intent, dwPrecalcFlags);
+ // Output is a little bit more complex.
+ if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
+
+ // This tag may exist only on devicelink profiles.
+ if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
+
+ // It may be NULL if error
+ xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
+ }
+
+ } else {
+ if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
+
+ xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
}
- else
- if (CurrentColorSpace == icSigLabData) {
+ }
- Transforms[i] = cmsCreateTransform(hLab, FormatInput,
- hProfile, FormatOutput,
- Intent, dwPrecalcFlags);
+ // Store the sequence of profiles
+ if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
+ xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
+ }
+ else
+ xform ->Sequence = NULL;
+ // If this is a cached transform, init first value, which is zero (16 bits only)
+ if (!(dwFlags & cmsFLAGS_NOCACHE)) {
+
+ memset(&xform ->CacheIn, 0, sizeof(xform ->CacheIn));
+
+ if (xform ->GamutCheck != NULL) {
+ TransformOnePixelWithGamutCheck(xform, xform ->CacheIn, xform->CacheOut);
}
else {
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateMultiprofileTransform: ColorSpace mismatch");
- goto ErrorCleanup;
+
+ xform ->Lut ->Eval16Fn(xform ->CacheIn, xform->CacheOut, xform -> Lut->Data);
}
- if (Transforms[i] == NULL) {
- cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateMultiprofileTransform: unable to create transform");
- goto ErrorCleanup;
- }
- CurrentColorSpace = ColorSpaceOut;
-
}
- p ->ExitColorSpace = CurrentColorSpace;
- Transforms[i] = NULL; // End marker
+ return (cmsHTRANSFORM) xform;
+}
- p ->InputProfile = hProfiles[0];
- p ->OutputProfile = hProfiles[nProfiles - 1];
-
- nGridPoints = _cmsReasonableGridpointsByColorspace(p ->EntryColorSpace, dwFlags);
-
- ChannelsInput = _cmsChannelsOf(cmsGetColorSpace(p ->InputProfile));
+// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
- Grid = cmsAlloc3DGrid(Grid, nGridPoints, ChannelsInput, ChannelsOutput);
-
- if (!(dwFlags & cmsFLAGS_NOPRELINEARIZATION))
- _cmsComputePrelinearizationTablesFromXFORM(Transforms, nProfiles, Grid);
+cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
+ cmsHPROFILE hProfiles[],
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags)
+{
+ cmsUInt32Number i;
+ cmsBool BPC[256];
+ cmsUInt32Number Intents[256];
+ cmsFloat64Number AdaptationStates[256];
- // Compute device link on 16-bit basis
- if (!cmsSample3DGrid(Grid, MultiprofileSampler, (LPVOID) Transforms, Grid -> wFlags)) {
-
- cmsFreeLUT(Grid);
- goto ErrorCleanup;
+ if (nProfiles <= 0 || nProfiles > 255) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
+ return NULL;
}
- // All ok, store the newly created LUT
- p -> DeviceLink = Grid;
-
- SetPrecalculatedTransform(p);
-
- for (i=nProfiles-1; i >= 0; --i)
- cmsDeleteTransform(Transforms[i]);
-
-
- if (hLab) cmsCloseProfile(hLab);
- if (hXYZ) cmsCloseProfile(hXYZ);
-
-
- if (p ->EntryColorSpace == icSigRgbData ||
- p ->EntryColorSpace == icSigCmyData) {
-
- p->DeviceLink -> CLut16params.Interp3D = cmsTetrahedralInterp16;
+ for (i=0; i < nProfiles; i++) {
+ BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
+ Intents[i] = Intent;
+ AdaptationStates[i] = GlobalAdaptationState;
}
- if ((Intent != INTENT_ABSOLUTE_COLORIMETRIC) &&
- !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP))
- _cmsFixWhiteMisalignment(p);
-
- return (cmsHTRANSFORM) p;
-
-
-ErrorCleanup:
-
- if (hLab) cmsCloseProfile(hLab);
- if (hXYZ) cmsCloseProfile(hXYZ);
- return NULL;
+ return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
}
-double LCMSEXPORT cmsSetAdaptationState(double d)
+cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags)
{
- double OldVal = GlobalAdaptationState;
+
+ if (nProfiles <= 0 || nProfiles > 255) {
+ cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
+ return NULL;
+ }
+
+ return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
+ hProfiles,
+ nProfiles,
+ InputFormat,
+ OutputFormat,
+ Intent,
+ dwFlags);
+}
+
+cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
+ cmsHPROFILE Input,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE Output,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags)
+{
+
+ cmsHPROFILE hArray[2];
+
+ hArray[0] = Input;
+ hArray[1] = Output;
+
+ return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
+}
- if (d >= 0)
- GlobalAdaptationState = d;
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE Output,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags)
+{
+ return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
+}
+
- return OldVal;
+cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
+ cmsHPROFILE InputProfile,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE OutputProfile,
+ cmsUInt32Number OutputFormat,
+ cmsHPROFILE ProofingProfile,
+ cmsUInt32Number nIntent,
+ cmsUInt32Number ProofingIntent,
+ cmsUInt32Number dwFlags)
+{
+ cmsHPROFILE hArray[4];
+ cmsUInt32Number Intents[4];
+ cmsBool BPC[4];
+ cmsFloat64Number Adaptation[4];
+ cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
+
+
+ hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;
+ Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
+ BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
+
+ Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState;
+
+ if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
+ return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
+
+ return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
+ ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
}
+
+
+cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE OutputProfile,
+ cmsUInt32Number OutputFormat,
+ cmsHPROFILE ProofingProfile,
+ cmsUInt32Number nIntent,
+ cmsUInt32Number ProofingIntent,
+ cmsUInt32Number dwFlags)
+{
+ return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
+ InputProfile,
+ InputFormat,
+ OutputProfile,
+ OutputFormat,
+ ProofingProfile,
+ nIntent,
+ ProofingIntent,
+ dwFlags);
+}
+
+
+// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
+cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
+{
+ _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
+
+ if (xform == NULL) return NULL;
+ return xform -> ContextID;
+}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/icc34.h Wed Jul 05 17:21:58 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1023 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/* Header file guard bands */
-#ifndef ICC_H
-#define ICC_H
-
-/*
- * This version of the header file corresponds to the profile
- * specification version 3.4.
- *
- * All header file entries are pre-fixed with "ic" to help
- * avoid name space collisions. Signatures are pre-fixed with
- * icSig.
- *
- * The structures defined in this header file were created to
- * represent a description of an ICC profile on disk. Rather
- * than use pointers a technique is used where a single byte array
- * was placed at the end of each structure. This allows us in "C"
- * to extend the structure by allocating more data than is needed
- * to account for variable length structures.
- *
- * This also ensures that data following is allocated
- * contiguously and makes it easier to write and read data from
- * the file.
- *
- * For example to allocate space for a 256 count length UCR
- * and BG array, and fill the allocated data. Note strlen + 1
- * to remember NULL terminator.
- *
- icUcrBgCurve *ucrCurve, *bgCurve;
- int ucr_nbytes, bg_nbytes, string_bytes;
- icUcrBg *ucrBgWrite;
- char ucr_string[100], *ucr_char;
-
- strcpy(ucr_string, "Example ucrBG curves");
- ucr_nbytes = sizeof(icUInt32Number) +
- (UCR_CURVE_SIZE * sizeof(icUInt16Number));
- bg_nbytes = sizeof(icUInt32Number) +
- (BG_CURVE_SIZE * sizeof(icUInt16Number));
- string_bytes = strlen(ucr_string) + 1;
-
- ucrBgWrite = (icUcrBg *)malloc(
- (ucr_nbytes + bg_nbytes + string_bytes));
-
- ucrCurve = (icUcrBgCurve *)ucrBgWrite->data;
- ucrCurve->count = UCR_CURVE_SIZE;
- for (i=0; i<ucrCurve->count; i++)
- ucrCurve->curve[i] = (icUInt16Number)i;
-
- bgCurve = (icUcrBgCurve *)((char *)ucrCurve + ucr_nbytes);
- bgCurve->count = BG_CURVE_SIZE;
- for (i=0; i<bgCurve->count; i++)
- bgCurve->curve[i] = 255 - (icUInt16Number)i;
-
- ucr_char = (char *)((char *)bgCurve + bg_nbytes);
- memcpy(ucr_char, ucr_string, string_bytes);
- *
- */
-
-/*
- * Many of the structures contain variable length arrays. This
- * is represented by the use of the convention.
- *
- * type data[icAny];
- */
-
-/*------------------------------------------------------------------------*/
-/*
- * Defines used in the specification
- */
-#define icMagicNumber 0x61637370L /* 'acsp' */
-#define icVersionNumber 0x02100000L /* 2.1.0, BCD */
-
-/* Screening Encodings */
-#define icPrtrDefaultScreensFalse 0x00000000L /* Bit pos 0 */
-#define icPrtrDefaultScreensTrue 0x00000001L /* Bit pos 0 */
-#define icLinesPerInch 0x00000002L /* Bit pos 1 */
-#define icLinesPerCm 0x00000000L /* Bit pos 1 */
-
-/*
- * Device attributes, currently defined values correspond
- * to the low 4 bytes of the 8 byte attribute quantity, see
- * the header for their location.
- */
-#define icReflective 0x00000000L /* Bit pos 0 */
-#define icTransparency 0x00000001L /* Bit pos 0 */
-#define icGlossy 0x00000000L /* Bit pos 1 */
-#define icMatte 0x00000002L /* Bit pos 1 */
-
-/*
- * Profile header flags, the low 16 bits are reserved for consortium
- * use.
- */
-#define icEmbeddedProfileFalse 0x00000000L /* Bit pos 0 */
-#define icEmbeddedProfileTrue 0x00000001L /* Bit pos 0 */
-#define icUseAnywhere 0x00000000L /* Bit pos 1 */
-#define icUseWithEmbeddedDataOnly 0x00000002L /* Bit pos 1 */
-
-/* Ascii or Binary data */
-#define icAsciiData 0x00000000L
-#define icBinaryData 0x00000001L
-
-/*
- * Define used to indicate that this is a variable length array
- */
-#define icAny 1
-
-
-/*------------------------------------------------------------------------*/
-/*
- * Use this area to translate platform definitions of long
- * etc into icXXX form. The rest of the header uses the icXXX
- * typedefs. Signatures are 4 byte quantities.
- *
- */
-
-
-#ifdef PACKAGE_NAME
-/*
- June 9, 2003, Adapted for use with configure by Bob Friesenhahn
- Added the stupid check for autoconf by Marti Maria.
- PACKAGE_NAME is defined if autoconf is being used
-*/
-
-typedef @UINT8_T@ icUInt8Number;
-typedef @UINT16_T@ icUInt16Number;
-typedef @UINT32_T@ icUInt32Number;
-typedef @UINT32_T@ icUInt64Number[2];
-
-typedef @INT8_T@ icInt8Number;
-typedef @INT16_T@ icInt16Number;
-typedef @INT32_T@ icInt32Number;
-typedef @INT32_T@ icInt64Number[2];
-
-#else
-
-/*
- *Apr-17-2002: Modified by Marti Maria in order to provide wider portability.
- */
-
-#if defined (__digital__) && defined (__unix__)
-
-/* Tru64 */
-
-#include <inttypes.h>
-
-typedef uint8_t icUInt8Number;
-typedef uint16_t icUInt16Number;
-typedef uint32_t icUInt32Number;
-typedef uint32_t icUInt64Number[2];
-
-typedef int8_t icInt8Number;
-typedef int16_t icInt16Number;
-typedef int32_t icInt32Number;
-typedef int32_t icInt64Number[2];
-
-#else
-#ifdef __sgi
-#include "sgidefs.h"
-
-
-/*
- * Number definitions
- */
-
-/* Unsigned integer numbers */
-typedef unsigned char icUInt8Number;
-typedef unsigned short icUInt16Number;
-typedef __uint32_t icUInt32Number;
-typedef __uint32_t icUInt64Number[2];
-
-/* Signed numbers */
-typedef char icInt8Number;
-typedef short icInt16Number;
-typedef __int32_t icInt32Number;
-typedef __int32_t icInt64Number[2];
-
-
-#else
-#if defined(__GNUC__) || defined(__unix__) || defined(__unix)
-
-#include <sys/types.h>
-
-#if defined(__sun) || defined(__hpux) || defined (__MINGW) || defined(__MINGW32__)
-
-#if defined (__MINGW) || defined(__MINGW32__)
-#include <stdint.h>
-#endif
-
-
-typedef uint8_t icUInt8Number;
-typedef uint16_t icUInt16Number;
-typedef uint32_t icUInt32Number;
-typedef uint32_t icUInt64Number[2];
-
-#else
-
-/* Unsigned integer numbers */
-typedef u_int8_t icUInt8Number;
-typedef u_int16_t icUInt16Number;
-typedef u_int32_t icUInt32Number;
-typedef u_int32_t icUInt64Number[2];
-
-#endif
-
-
-/* Signed numbers */
-typedef int8_t icInt8Number;
-typedef int16_t icInt16Number;
-typedef int32_t icInt32Number;
-typedef int32_t icInt64Number[2];
-
-
-#else /* default definitions */
-
-/*
- * Number definitions
- */
-
-/* Unsigned integer numbers */
-typedef unsigned char icUInt8Number;
-typedef unsigned short icUInt16Number;
-typedef unsigned long icUInt32Number;
-typedef unsigned long icUInt64Number[2];
-
-/* Signed numbers */
-typedef char icInt8Number;
-typedef short icInt16Number;
-typedef long icInt32Number;
-typedef long icInt64Number[2];
-
-
-#endif /* default defs */
-#endif
-#endif
-#endif
-
-/* Base types */
-
-typedef icInt32Number icSignature;
-typedef icInt32Number icS15Fixed16Number;
-typedef icUInt32Number icU16Fixed16Number;
-
-
-/*------------------------------------------------------------------------*/
-/* public tags and sizes */
-typedef enum {
- icSigAToB0Tag = 0x41324230L, /* 'A2B0' */
- icSigAToB1Tag = 0x41324231L, /* 'A2B1' */
- icSigAToB2Tag = 0x41324232L, /* 'A2B2' */
- icSigBlueColorantTag = 0x6258595AL, /* 'bXYZ' */
- icSigBlueTRCTag = 0x62545243L, /* 'bTRC' */
- icSigBToA0Tag = 0x42324130L, /* 'B2A0' */
- icSigBToA1Tag = 0x42324131L, /* 'B2A1' */
- icSigBToA2Tag = 0x42324132L, /* 'B2A2' */
- icSigCalibrationDateTimeTag = 0x63616C74L, /* 'calt' */
- icSigCharTargetTag = 0x74617267L, /* 'targ' */
- icSigCopyrightTag = 0x63707274L, /* 'cprt' */
- icSigCrdInfoTag = 0x63726469L, /* 'crdi' */
- icSigDeviceMfgDescTag = 0x646D6E64L, /* 'dmnd' */
- icSigDeviceModelDescTag = 0x646D6464L, /* 'dmdd' */
- icSigGamutTag = 0x67616D74L, /* 'gamt ' */
- icSigGrayTRCTag = 0x6b545243L, /* 'kTRC' */
- icSigGreenColorantTag = 0x6758595AL, /* 'gXYZ' */
- icSigGreenTRCTag = 0x67545243L, /* 'gTRC' */
- icSigLuminanceTag = 0x6C756d69L, /* 'lumi' */
- icSigMeasurementTag = 0x6D656173L, /* 'meas' */
- icSigMediaBlackPointTag = 0x626B7074L, /* 'bkpt' */
- icSigMediaWhitePointTag = 0x77747074L, /* 'wtpt' */
- icSigNamedColorTag = 0x6E636f6CL, /* 'ncol'
- * OBSOLETE, use ncl2 */
- icSigNamedColor2Tag = 0x6E636C32L, /* 'ncl2' */
- icSigPreview0Tag = 0x70726530L, /* 'pre0' */
- icSigPreview1Tag = 0x70726531L, /* 'pre1' */
- icSigPreview2Tag = 0x70726532L, /* 'pre2' */
- icSigProfileDescriptionTag = 0x64657363L, /* 'desc' */
- icSigProfileSequenceDescTag = 0x70736571L, /* 'pseq' */
- icSigPs2CRD0Tag = 0x70736430L, /* 'psd0' */
- icSigPs2CRD1Tag = 0x70736431L, /* 'psd1' */
- icSigPs2CRD2Tag = 0x70736432L, /* 'psd2' */
- icSigPs2CRD3Tag = 0x70736433L, /* 'psd3' */
- icSigPs2CSATag = 0x70733273L, /* 'ps2s' */
- icSigPs2RenderingIntentTag = 0x70733269L, /* 'ps2i' */
- icSigRedColorantTag = 0x7258595AL, /* 'rXYZ' */
- icSigRedTRCTag = 0x72545243L, /* 'rTRC' */
- icSigScreeningDescTag = 0x73637264L, /* 'scrd' */
- icSigScreeningTag = 0x7363726EL, /* 'scrn' */
- icSigTechnologyTag = 0x74656368L, /* 'tech' */
- icSigUcrBgTag = 0x62666420L, /* 'bfd ' */
- icSigViewingCondDescTag = 0x76756564L, /* 'vued' */
- icSigViewingConditionsTag = 0x76696577L, /* 'view' */
- icMaxEnumTag = 0xFFFFFFFFL
-} icTagSignature;
-
-/* technology signature descriptions */
-typedef enum {
- icSigDigitalCamera = 0x6463616DL, /* 'dcam' */
- icSigFilmScanner = 0x6673636EL, /* 'fscn' */
- icSigReflectiveScanner = 0x7273636EL, /* 'rscn' */
- icSigInkJetPrinter = 0x696A6574L, /* 'ijet' */
- icSigThermalWaxPrinter = 0x74776178L, /* 'twax' */
- icSigElectrophotographicPrinter = 0x6570686FL, /* 'epho' */
- icSigElectrostaticPrinter = 0x65737461L, /* 'esta' */
- icSigDyeSublimationPrinter = 0x64737562L, /* 'dsub' */
- icSigPhotographicPaperPrinter = 0x7270686FL, /* 'rpho' */
- icSigFilmWriter = 0x6670726EL, /* 'fprn' */
- icSigVideoMonitor = 0x7669646DL, /* 'vidm' */
- icSigVideoCamera = 0x76696463L, /* 'vidc' */
- icSigProjectionTelevision = 0x706A7476L, /* 'pjtv' */
- icSigCRTDisplay = 0x43525420L, /* 'CRT ' */
- icSigPMDisplay = 0x504D4420L, /* 'PMD ' */
- icSigAMDisplay = 0x414D4420L, /* 'AMD ' */
- icSigPhotoCD = 0x4B504344L, /* 'KPCD' */
- icSigPhotoImageSetter = 0x696D6773L, /* 'imgs' */
- icSigGravure = 0x67726176L, /* 'grav' */
- icSigOffsetLithography = 0x6F666673L, /* 'offs' */
- icSigSilkscreen = 0x73696C6BL, /* 'silk' */
- icSigFlexography = 0x666C6578L, /* 'flex' */
- icMaxEnumTechnology = 0xFFFFFFFFL
-} icTechnologySignature;
-
-/* type signatures */
-typedef enum {
- icSigCurveType = 0x63757276L, /* 'curv' */
- icSigDataType = 0x64617461L, /* 'data' */
- icSigDateTimeType = 0x6474696DL, /* 'dtim' */
- icSigLut16Type = 0x6d667432L, /* 'mft2' */
- icSigLut8Type = 0x6d667431L, /* 'mft1' */
- icSigMeasurementType = 0x6D656173L, /* 'meas' */
- icSigNamedColorType = 0x6E636f6CL, /* 'ncol'
- * OBSOLETE, use ncl2 */
- icSigProfileSequenceDescType = 0x70736571L, /* 'pseq' */
- icSigS15Fixed16ArrayType = 0x73663332L, /* 'sf32' */
- icSigScreeningType = 0x7363726EL, /* 'scrn' */
- icSigSignatureType = 0x73696720L, /* 'sig ' */
- icSigTextType = 0x74657874L, /* 'text' */
- icSigTextDescriptionType = 0x64657363L, /* 'desc' */
- icSigU16Fixed16ArrayType = 0x75663332L, /* 'uf32' */
- icSigUcrBgType = 0x62666420L, /* 'bfd ' */
- icSigUInt16ArrayType = 0x75693136L, /* 'ui16' */
- icSigUInt32ArrayType = 0x75693332L, /* 'ui32' */
- icSigUInt64ArrayType = 0x75693634L, /* 'ui64' */
- icSigUInt8ArrayType = 0x75693038L, /* 'ui08' */
- icSigViewingConditionsType = 0x76696577L, /* 'view' */
- icSigXYZType = 0x58595A20L, /* 'XYZ ' */
- icSigXYZArrayType = 0x58595A20L, /* 'XYZ ' */
- icSigNamedColor2Type = 0x6E636C32L, /* 'ncl2' */
- icSigCrdInfoType = 0x63726469L, /* 'crdi' */
- icMaxEnumType = 0xFFFFFFFFL
-} icTagTypeSignature;
-
-/*
- * Color Space Signatures
- * Note that only icSigXYZData and icSigLabData are valid
- * Profile Connection Spaces (PCSs)
- */
-typedef enum {
- icSigXYZData = 0x58595A20L, /* 'XYZ ' */
- icSigLabData = 0x4C616220L, /* 'Lab ' */
- icSigLuvData = 0x4C757620L, /* 'Luv ' */
- icSigYCbCrData = 0x59436272L, /* 'YCbr' */
- icSigYxyData = 0x59787920L, /* 'Yxy ' */
- icSigRgbData = 0x52474220L, /* 'RGB ' */
- icSigGrayData = 0x47524159L, /* 'GRAY' */
- icSigHsvData = 0x48535620L, /* 'HSV ' */
- icSigHlsData = 0x484C5320L, /* 'HLS ' */
- icSigCmykData = 0x434D594BL, /* 'CMYK' */
- icSigCmyData = 0x434D5920L, /* 'CMY ' */
- icSig2colorData = 0x32434C52L, /* '2CLR' */
- icSig3colorData = 0x33434C52L, /* '3CLR' */
- icSig4colorData = 0x34434C52L, /* '4CLR' */
- icSig5colorData = 0x35434C52L, /* '5CLR' */
- icSig6colorData = 0x36434C52L, /* '6CLR' */
- icSig7colorData = 0x37434C52L, /* '7CLR' */
- icSig8colorData = 0x38434C52L, /* '8CLR' */
- icSig9colorData = 0x39434C52L, /* '9CLR' */
- icSig10colorData = 0x41434C52L, /* 'ACLR' */
- icSig11colorData = 0x42434C52L, /* 'BCLR' */
- icSig12colorData = 0x43434C52L, /* 'CCLR' */
- icSig13colorData = 0x44434C52L, /* 'DCLR' */
- icSig14colorData = 0x45434C52L, /* 'ECLR' */
- icSig15colorData = 0x46434C52L, /* 'FCLR' */
- icMaxEnumData = 0xFFFFFFFFL
-} icColorSpaceSignature;
-
-/* profileClass enumerations */
-typedef enum {
- icSigInputClass = 0x73636E72L, /* 'scnr' */
- icSigDisplayClass = 0x6D6E7472L, /* 'mntr' */
- icSigOutputClass = 0x70727472L, /* 'prtr' */
- icSigLinkClass = 0x6C696E6BL, /* 'link' */
- icSigAbstractClass = 0x61627374L, /* 'abst' */
- icSigColorSpaceClass = 0x73706163L, /* 'spac' */
- icSigNamedColorClass = 0x6e6d636cL, /* 'nmcl' */
- icMaxEnumClass = 0xFFFFFFFFL
-} icProfileClassSignature;
-
-/* Platform Signatures */
-typedef enum {
- icSigMacintosh = 0x4150504CL, /* 'APPL' */
- icSigMicrosoft = 0x4D534654L, /* 'MSFT' */
- icSigSolaris = 0x53554E57L, /* 'SUNW' */
- icSigSGI = 0x53474920L, /* 'SGI ' */
- icSigTaligent = 0x54474E54L, /* 'TGNT' */
- icMaxEnumPlatform = 0xFFFFFFFFL
-} icPlatformSignature;
-
-/*------------------------------------------------------------------------*/
-/*
- * Other enums
- */
-
-/* Measurement Flare, used in the measurmentType tag */
-typedef enum {
- icFlare0 = 0x00000000L, /* 0% flare */
- icFlare100 = 0x00000001L, /* 100% flare */
- icMaxFlare = 0xFFFFFFFFL
-} icMeasurementFlare;
-
-/* Measurement Geometry, used in the measurmentType tag */
-typedef enum {
- icGeometryUnknown = 0x00000000L, /* Unknown */
- icGeometry045or450 = 0x00000001L, /* 0/45, 45/0 */
- icGeometry0dord0 = 0x00000002L, /* 0/d or d/0 */
- icMaxGeometry = 0xFFFFFFFFL
-} icMeasurementGeometry;
-
-/* Rendering Intents, used in the profile header */
-typedef enum {
- icPerceptual = 0,
- icRelativeColorimetric = 1,
- icSaturation = 2,
- icAbsoluteColorimetric = 3,
- icMaxEnumIntent = 0xFFFFFFFFL
-} icRenderingIntent;
-
-/* Different Spot Shapes currently defined, used for screeningType */
-typedef enum {
- icSpotShapeUnknown = 0,
- icSpotShapePrinterDefault = 1,
- icSpotShapeRound = 2,
- icSpotShapeDiamond = 3,
- icSpotShapeEllipse = 4,
- icSpotShapeLine = 5,
- icSpotShapeSquare = 6,
- icSpotShapeCross = 7,
- icMaxEnumSpot = 0xFFFFFFFFL
-} icSpotShape;
-
-/* Standard Observer, used in the measurmentType tag */
-typedef enum {
- icStdObsUnknown = 0x00000000L, /* Unknown */
- icStdObs1931TwoDegrees = 0x00000001L, /* 2 deg */
- icStdObs1964TenDegrees = 0x00000002L, /* 10 deg */
- icMaxStdObs = 0xFFFFFFFFL
-} icStandardObserver;
-
-/* Pre-defined illuminants, used in measurement and viewing conditions type */
-typedef enum {
- icIlluminantUnknown = 0x00000000L,
- icIlluminantD50 = 0x00000001L,
- icIlluminantD65 = 0x00000002L,
- icIlluminantD93 = 0x00000003L,
- icIlluminantF2 = 0x00000004L,
- icIlluminantD55 = 0x00000005L,
- icIlluminantA = 0x00000006L,
- icIlluminantEquiPowerE = 0x00000007L,
- icIlluminantF8 = 0x00000008L,
- icMaxEnumIluminant = 0xFFFFFFFFL
-} icIlluminant;
-
-
-/*------------------------------------------------------------------------*/
-/*
- * Arrays of numbers
- */
-
-/* Int8 Array */
-typedef struct {
- icInt8Number data[icAny]; /* Variable array of values */
-} icInt8Array;
-
-/* UInt8 Array */
-typedef struct {
- icUInt8Number data[icAny]; /* Variable array of values */
-} icUInt8Array;
-
-/* uInt16 Array */
-typedef struct {
- icUInt16Number data[icAny]; /* Variable array of values */
-} icUInt16Array;
-
-/* Int16 Array */
-typedef struct {
- icInt16Number data[icAny]; /* Variable array of values */
-} icInt16Array;
-
-/* uInt32 Array */
-typedef struct {
- icUInt32Number data[icAny]; /* Variable array of values */
-} icUInt32Array;
-
-/* Int32 Array */
-typedef struct {
- icInt32Number data[icAny]; /* Variable array of values */
-} icInt32Array;
-
-/* UInt64 Array */
-typedef struct {
- icUInt64Number data[icAny]; /* Variable array of values */
-} icUInt64Array;
-
-/* Int64 Array */
-typedef struct {
- icInt64Number data[icAny]; /* Variable array of values */
-} icInt64Array;
-
-/* u16Fixed16 Array */
-typedef struct {
- icU16Fixed16Number data[icAny]; /* Variable array of values */
-} icU16Fixed16Array;
-
-/* s15Fixed16 Array */
-typedef struct {
- icS15Fixed16Number data[icAny]; /* Variable array of values */
-} icS15Fixed16Array;
-
-/* The base date time number */
-typedef struct {
- icUInt16Number year;
- icUInt16Number month;
- icUInt16Number day;
- icUInt16Number hours;
- icUInt16Number minutes;
- icUInt16Number seconds;
-} icDateTimeNumber;
-
-/* XYZ Number */
-typedef struct {
- icS15Fixed16Number X;
- icS15Fixed16Number Y;
- icS15Fixed16Number Z;
-} icXYZNumber;
-
-/* XYZ Array */
-typedef struct {
- icXYZNumber data[icAny]; /* Variable array of XYZ numbers */
-} icXYZArray;
-
-/* Curve */
-typedef struct {
- icUInt32Number count; /* Number of entries */
- icUInt16Number data[icAny]; /* The actual table data, real
- * number is determined by count
- * Interpretation depends on how
- * data is used with a given tag
- */
-} icCurve;
-
-/* Data */
-typedef struct {
- icUInt32Number dataFlag; /* 0 = ascii, 1 = binary */
- icInt8Number data[icAny]; /* Data, size from tag */
-} icData;
-
-/* lut16 */
-typedef struct {
- icUInt8Number inputChan; /* Number of input channels */
- icUInt8Number outputChan; /* Number of output channels */
- icUInt8Number clutPoints; /* Number of grid points */
- icInt8Number pad; /* Padding for byte alignment */
- icS15Fixed16Number e00; /* e00 in the 3 * 3 */
- icS15Fixed16Number e01; /* e01 in the 3 * 3 */
- icS15Fixed16Number e02; /* e02 in the 3 * 3 */
- icS15Fixed16Number e10; /* e10 in the 3 * 3 */
- icS15Fixed16Number e11; /* e11 in the 3 * 3 */
- icS15Fixed16Number e12; /* e12 in the 3 * 3 */
- icS15Fixed16Number e20; /* e20 in the 3 * 3 */
- icS15Fixed16Number e21; /* e21 in the 3 * 3 */
- icS15Fixed16Number e22; /* e22 in the 3 * 3 */
- icUInt16Number inputEnt; /* Num of in-table entries */
- icUInt16Number outputEnt; /* Num of out-table entries */
- icUInt16Number data[icAny]; /* Data follows see spec */
-/*
- * Data that follows is of this form
- *
- * icUInt16Number inputTable[inputChan][icAny]; * The in-table
- * icUInt16Number clutTable[icAny]; * The clut
- * icUInt16Number outputTable[outputChan][icAny]; * The out-table
- */
-} icLut16;
-
-/* lut8, input & output tables are always 256 bytes in length */
-typedef struct {
- icUInt8Number inputChan; /* Num of input channels */
- icUInt8Number outputChan; /* Num of output channels */
- icUInt8Number clutPoints; /* Num of grid points */
- icInt8Number pad;
- icS15Fixed16Number e00; /* e00 in the 3 * 3 */
- icS15Fixed16Number e01; /* e01 in the 3 * 3 */
- icS15Fixed16Number e02; /* e02 in the 3 * 3 */
- icS15Fixed16Number e10; /* e10 in the 3 * 3 */
- icS15Fixed16Number e11; /* e11 in the 3 * 3 */
- icS15Fixed16Number e12; /* e12 in the 3 * 3 */
- icS15Fixed16Number e20; /* e20 in the 3 * 3 */
- icS15Fixed16Number e21; /* e21 in the 3 * 3 */
- icS15Fixed16Number e22; /* e22 in the 3 * 3 */
- icUInt8Number data[icAny]; /* Data follows see spec */
-/*
- * Data that follows is of this form
- *
- * icUInt8Number inputTable[inputChan][256]; * The in-table
- * icUInt8Number clutTable[icAny]; * The clut
- * icUInt8Number outputTable[outputChan][256]; * The out-table
- */
-} icLut8;
-
-/* Measurement Data */
-typedef struct {
- icStandardObserver stdObserver; /* Standard observer */
- icXYZNumber backing; /* XYZ for backing */
- icMeasurementGeometry geometry; /* Meas. geometry */
- icMeasurementFlare flare; /* Measurement flare */
- icIlluminant illuminant; /* Illuminant */
-} icMeasurement;
-
-/* Named color */
-
-/*
- * icNamedColor2 takes the place of icNamedColor
- */
-typedef struct {
- icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */
- icUInt32Number count; /* Count of named colors */
- icUInt32Number nDeviceCoords; /* Num of device coordinates */
- icInt8Number prefix[32]; /* Prefix for each color name */
- icInt8Number suffix[32]; /* Suffix for each color name */
- icInt8Number data[icAny]; /* Named color data follows */
-/*
- * Data that follows is of this form
- *
- * icInt8Number root1[32]; * Root name for 1st color
- * icUInt16Number pcsCoords1[icAny]; * PCS coords of 1st color
- * icUInt16Number deviceCoords1[icAny]; * Dev coords of 1st color
- * icInt8Number root2[32]; * Root name for 2nd color
- * icUInt16Number pcsCoords2[icAny]; * PCS coords of 2nd color
- * icUInt16Number deviceCoords2[icAny]; * Dev coords of 2nd color
- * :
- * :
- * Repeat for name and PCS and device color coordinates up to (count-1)
- *
- * NOTES:
- * PCS and device space can be determined from the header.
- *
- * PCS coordinates are icUInt16 numbers and are described in Annex A of
- * the ICC spec. Only 16 bit L*a*b* and XYZ are allowed. The number of
- * coordinates is consistent with the headers PCS.
- *
- * Device coordinates are icUInt16 numbers where 0x0000 represents
- * the minimum value and 0xFFFF represents the maximum value.
- * If the nDeviceCoords value is 0 this field is not given.
- */
-} icNamedColor2;
-
-/* Profile sequence structure */
-typedef struct {
- icSignature deviceMfg; /* Dev Manufacturer */
- icSignature deviceModel; /* Dev Model */
- icUInt64Number attributes; /* Dev attributes */
- icTechnologySignature technology; /* Technology sig */
- icInt8Number data[icAny]; /* Desc text follows */
-/*
- * Data that follows is of this form, this is an icInt8Number
- * to avoid problems with a compiler generating bad code as
- * these arrays are variable in length.
- *
- * icTextDescription deviceMfgDesc; * Manufacturer text
- * icTextDescription modelDesc; * Model text
- */
-} icDescStruct;
-
-/* Profile sequence description */
-typedef struct {
- icUInt32Number count; /* Number of descriptions */
- icUInt8Number data[icAny]; /* Array of desc structs */
-} icProfileSequenceDesc;
-
-/* textDescription */
-typedef struct {
- icUInt32Number count; /* Description length */
- icInt8Number data[icAny]; /* Descriptions follow */
-/*
- * Data that follows is of this form
- *
- * icInt8Number desc[count] * NULL terminated ascii string
- * icUInt32Number ucLangCode; * UniCode language code
- * icUInt32Number ucCount; * UniCode description length
- * icInt16Number ucDesc[ucCount];* The UniCode description
- * icUInt16Number scCode; * ScriptCode code
- * icUInt8Number scCount; * ScriptCode count
- * icInt8Number scDesc[67]; * ScriptCode Description
- */
-} icTextDescription;
-
-/* Screening Data */
-typedef struct {
- icS15Fixed16Number frequency; /* Frequency */
- icS15Fixed16Number angle; /* Screen angle */
- icSpotShape spotShape; /* Spot Shape encodings below */
-} icScreeningData;
-
-typedef struct {
- icUInt32Number screeningFlag; /* Screening flag */
- icUInt32Number channels; /* Number of channels */
- icScreeningData data[icAny]; /* Array of screening data */
-} icScreening;
-
-/* Text Data */
-typedef struct {
- icInt8Number data[icAny]; /* Variable array of chars */
-} icText;
-
-/* Structure describing either a UCR or BG curve */
-typedef struct {
- icUInt32Number count; /* Curve length */
- icUInt16Number curve[icAny]; /* The array of curve values */
-} icUcrBgCurve;
-
-/* Under color removal, black generation */
-typedef struct {
- icInt8Number data[icAny]; /* The Ucr BG data */
-/*
- * Data that follows is of this form, this is a icInt8Number
- * to avoid problems with a compiler generating bad code as
- * these arrays are variable in length.
- *
- * icUcrBgCurve ucr; * Ucr curve
- * icUcrBgCurve bg; * Bg curve
- * icInt8Number string; * UcrBg description
- */
-} icUcrBg;
-
-/* viewingConditionsType */
-typedef struct {
- icXYZNumber illuminant; /* In candelas per sq. meter */
- icXYZNumber surround; /* In candelas per sq. meter */
- icIlluminant stdIluminant; /* See icIlluminant defines */
-} icViewingCondition;
-
-/* CrdInfo type */
-typedef struct {
- icUInt32Number count; /* Char count includes NULL */
- icInt8Number desc[icAny]; /* Null terminated string */
-} icCrdInfo;
-
-/*------------------------------------------------------------------------*/
-/*
- * Tag Type definitions
- */
-
-/*
- * Many of the structures contain variable length arrays. This
- * is represented by the use of the convention.
- *
- * type data[icAny];
- */
-
-/* The base part of each tag */
-typedef struct {
- icTagTypeSignature sig; /* Signature */
- icInt8Number reserved[4]; /* Reserved, set to 0 */
-} icTagBase;
-
-/* curveType */
-typedef struct {
- icTagBase base; /* Signature, "curv" */
- icCurve curve; /* The curve data */
-} icCurveType;
-
-/* dataType */
-typedef struct {
- icTagBase base; /* Signature, "data" */
- icData data; /* The data structure */
-} icDataType;
-
-/* dateTimeType */
-typedef struct {
- icTagBase base; /* Signature, "dtim" */
- icDateTimeNumber date; /* The date */
-} icDateTimeType;
-
-/* lut16Type */
-typedef struct {
- icTagBase base; /* Signature, "mft2" */
- icLut16 lut; /* Lut16 data */
-} icLut16Type;
-
-/* lut8Type, input & output tables are always 256 bytes in length */
-typedef struct {
- icTagBase base; /* Signature, "mft1" */
- icLut8 lut; /* Lut8 data */
-} icLut8Type;
-
-/* Measurement Type */
-typedef struct {
- icTagBase base; /* Signature, "meas" */
- icMeasurement measurement; /* Measurement data */
-} icMeasurementType;
-
-/* Named color type */
-/* icNamedColor2Type, replaces icNamedColorType */
-typedef struct {
- icTagBase base; /* Signature, "ncl2" */
- icNamedColor2 ncolor; /* Named color data */
-} icNamedColor2Type;
-
-/* Profile sequence description type */
-typedef struct {
- icTagBase base; /* Signature, "pseq" */
- icProfileSequenceDesc desc; /* The seq description */
-} icProfileSequenceDescType;
-
-/* textDescriptionType */
-typedef struct {
- icTagBase base; /* Signature, "desc" */
- icTextDescription desc; /* The description */
-} icTextDescriptionType;
-
-/* s15Fixed16Type */
-typedef struct {
- icTagBase base; /* Signature, "sf32" */
- icS15Fixed16Array data; /* Array of values */
-} icS15Fixed16ArrayType;
-
-typedef struct {
- icTagBase base; /* Signature, "scrn" */
- icScreening screen; /* Screening structure */
-} icScreeningType;
-
-/* sigType */
-typedef struct {
- icTagBase base; /* Signature, "sig" */
- icSignature signature; /* The signature data */
-} icSignatureType;
-
-/* textType */
-typedef struct {
- icTagBase base; /* Signature, "text" */
- icText data; /* Variable array of chars */
-} icTextType;
-
-/* u16Fixed16Type */
-typedef struct {
- icTagBase base; /* Signature, "uf32" */
- icU16Fixed16Array data; /* Variable array of values */
-} icU16Fixed16ArrayType;
-
-/* Under color removal, black generation type */
-typedef struct {
- icTagBase base; /* Signature, "bfd " */
- icUcrBg data; /* ucrBg structure */
-} icUcrBgType;
-
-/* uInt16Type */
-typedef struct {
- icTagBase base; /* Signature, "ui16" */
- icUInt16Array data; /* Variable array of values */
-} icUInt16ArrayType;
-
-/* uInt32Type */
-typedef struct {
- icTagBase base; /* Signature, "ui32" */
- icUInt32Array data; /* Variable array of values */
-} icUInt32ArrayType;
-
-/* uInt64Type */
-typedef struct {
- icTagBase base; /* Signature, "ui64" */
- icUInt64Array data; /* Variable array of values */
-} icUInt64ArrayType;
-
-/* uInt8Type */
-typedef struct {
- icTagBase base; /* Signature, "ui08" */
- icUInt8Array data; /* Variable array of values */
-} icUInt8ArrayType;
-
-/* viewingConditionsType */
-typedef struct {
- icTagBase base; /* Signature, "view" */
- icViewingCondition view; /* Viewing conditions */
-} icViewingConditionType;
-
-/* XYZ Type */
-typedef struct {
- icTagBase base; /* Signature, "XYZ" */
- icXYZArray data; /* Variable array of XYZ nums */
-} icXYZType;
-
-/* CRDInfoType where [0] is the CRD product name count and string and
- * [1] -[5] are the rendering intents 0-4 counts and strings
- */
-typedef struct {
- icTagBase base; /* Signature, "crdi" */
- icCrdInfo info; /* 5 sets of counts & strings */
-}icCrdInfoType;
- /* icCrdInfo productName; PS product count/string */
- /* icCrdInfo CRDName0; CRD name for intent 0 */
- /* icCrdInfo CRDName1; CRD name for intent 1 */
- /* icCrdInfo CRDName2; CRD name for intent 2 */
- /* icCrdInfo CRDName3; CRD name for intent 3 */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Lists of tags, tags, profile header and profile structure
- */
-
-/* A tag */
-typedef struct {
- icTagSignature sig; /* The tag signature */
- icUInt32Number offset; /* Start of tag relative to
- * start of header, Spec
- * Clause 5 */
- icUInt32Number size; /* Size in bytes */
-} icTag;
-
-/* A Structure that may be used independently for a list of tags */
-typedef struct {
- icUInt32Number count; /* Num tags in the profile */
- icTag tags[icAny]; /* Variable array of tags */
-} icTagList;
-
-/* The Profile header */
-typedef struct {
- icUInt32Number size; /* Prof size in bytes */
- icSignature cmmId; /* CMM for profile */
- icUInt32Number version; /* Format version */
- icProfileClassSignature deviceClass; /* Type of profile */
- icColorSpaceSignature colorSpace; /* Clr space of data */
- icColorSpaceSignature pcs; /* PCS, XYZ or Lab */
- icDateTimeNumber date; /* Creation Date */
- icSignature magic; /* icMagicNumber */
- icPlatformSignature platform; /* Primary Platform */
- icUInt32Number flags; /* Various bits */
- icSignature manufacturer; /* Dev manufacturer */
- icUInt32Number model; /* Dev model number */
- icUInt64Number attributes; /* Device attributes */
- icUInt32Number renderingIntent;/* Rendering intent */
- icXYZNumber illuminant; /* Profile illuminant */
- icSignature creator; /* Profile creator */
- icInt8Number reserved[44]; /* Reserved */
-} icHeader;
-
-/*
- * A profile,
- * we can't use icTagList here because its not at the end of the structure
- */
-typedef struct {
- icHeader header; /* The header */
- icUInt32Number count; /* Num tags in the profile */
- icInt8Number data[icAny]; /* The tagTable and tagData */
-/*
- * Data that follows is of the form
- *
- * icTag tagTable[icAny]; * The tag table
- * icInt8Number tagData[icAny]; * The tag data
- */
-} icProfile;
-
-/*------------------------------------------------------------------------*/
-/* Obsolete entries */
-
-/* icNamedColor was replaced with icNamedColor2 */
-typedef struct {
- icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */
- icUInt32Number count; /* Count of named colors */
- icInt8Number data[icAny]; /* Named color data follows */
-/*
- * Data that follows is of this form
- *
- * icInt8Number prefix[icAny]; * Prefix
- * icInt8Number suffix[icAny]; * Suffix
- * icInt8Number root1[icAny]; * Root name
- * icInt8Number coords1[icAny]; * Color coordinates
- * icInt8Number root2[icAny]; * Root name
- * icInt8Number coords2[icAny]; * Color coordinates
- * :
- * :
- * Repeat for root name and color coordinates up to (count-1)
- */
-} icNamedColor;
-
-/* icNamedColorType was replaced by icNamedColor2Type */
-typedef struct {
- icTagBase base; /* Signature, "ncol" */
- icNamedColor ncolor; /* Named color data */
-} icNamedColorType;
-
-#endif /* ICC_H */
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms.h Wed Jul 05 17:21:58 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2099 +0,0 @@
-/*
- * 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// This file is available under and governed by the GNU General Public
-// License version 2 only, as published by the Free Software Foundation.
-// However, the following notice accompanied the original version of this
-// file:
-//
-//
-// Little cms
-// Copyright (C) 1998-2007 Marti Maria
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software
-// is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// Version 1.18
-
-#ifndef __cms_H
-
-// ********** Configuration toggles ****************************************
-
-// Optimization mode.
-//
-// Note that USE_ASSEMBLER Is fastest by far, but it is limited to Pentium.
-// USE_FLOAT are the generic floating-point routines. USE_C should work on
-// virtually any machine.
-
-//#define USE_FLOAT 1
-// #define USE_C 1
-#define USE_ASSEMBLER 1
-
-// Define this if you are using this package as a DLL (windows only)
-
-// #define LCMS_DLL 1
-// #define LCMS_DLL_BUILD 1
-
-// Uncomment if you are trying the engine in a non-windows environment
-// like linux, SGI, VAX, FreeBSD, BeOS, etc.
-#define NON_WINDOWS 1
-
-// Uncomment this one if you are using big endian machines (only meaningful
-// when NON_WINDOWS is used)
-// #define USE_BIG_ENDIAN 1
-
-// Uncomment this one if your compiler/machine does support the
-// "long long" type This will speedup fixed point math. (USE_C only)
-#define USE_INT64 1
-
-// Some machines does not have a reliable 'swab' function. Usually
-// leave commented unless the testbed diagnoses the contrary.
-// #define USE_CUSTOM_SWAB 1
-
-// Uncomment this if your compiler supports inline
-#define USE_INLINE 1
-
-// Uncomment this if your compiler doesn't work with fast floor function
-// #define USE_DEFAULT_FLOOR_CONVERSION 1
-
-// Uncomment this line on multithreading environments
-// #define USE_PTHREADS 1
-
-// Uncomment this line if you want lcms to use the black point tag in profile,
-// if commented, lcms will compute the black point by its own.
-// It is safer to leve it commented out
-// #define HONOR_BLACK_POINT_TAG 1
-
-// ********** End of configuration toggles ******************************
-
-#define LCMS_VERSION 118
-
-// Microsoft VisualC++
-
-// Deal with Microsoft's attempt at deprecating C standard runtime functions
-#ifdef _MSC_VER
-# undef NON_WINDOWS
-# if (_MSC_VER >= 1400)
-# ifndef _CRT_SECURE_NO_DEPRECATE
-# define _CRT_SECURE_NO_DEPRECATE 1
-# endif
-# endif
-#endif
-
-// Borland C
-
-#ifdef __BORLANDC__
-# undef NON_WINDOWS
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <time.h>
-
-// Metroworks CodeWarrior
-#ifdef __MWERKS__
-# define unlink remove
-# if WIN32
-# define USE_CUSTOM_SWAB 1
-# undef NON_WINDOWS
-# else
-# define NON_WINDOWS 1
-# endif
-#endif
-
-
-// Here comes the Non-Windows settings
-
-#ifdef NON_WINDOWS
-
-// Non windows environments. Also avoid indentation on includes.
-
-#ifdef USE_PTHREADS
-# include <pthread.h>
-typedef pthread_rwlock_t LCMS_RWLOCK_T;
-# define LCMS_CREATE_LOCK(x) pthread_rwlock_init((x), NULL)
-# define LCMS_FREE_LOCK(x) pthread_rwlock_destroy((x))
-# define LCMS_READ_LOCK(x) pthread_rwlock_rdlock((x))
-# define LCMS_WRITE_LOCK(x) pthread_rwlock_wrlock((x))
-# define LCMS_UNLOCK(x) pthread_rwlock_unlock((x))
-#endif
-
-#undef LCMS_DLL
-
-#ifdef USE_ASSEMBLER
-# undef USE_ASSEMBLER
-# define USE_C 1
-#endif
-
-#ifdef _HOST_BIG_ENDIAN
-# define USE_BIG_ENDIAN 1
-#endif
-
-#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) || defined(__s390__) || defined(__s390x__)
-# define USE_BIG_ENDIAN 1
-#endif
-
-#if TARGET_CPU_PPC
-# define USE_BIG_ENDIAN 1
-#endif
-
-#if macintosh
-# ifndef __LITTLE_ENDIAN__
-# define USE_BIG_ENDIAN 1
-# endif
-#endif
-
-#ifdef __BIG_ENDIAN__
-# define USE_BIG_ENDIAN 1
-#endif
-
-#ifdef WORDS_BIGENDIAN
-# define USE_BIG_ENDIAN 1
-#endif
-
-#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
-# include <sys/types.h>
-# define USE_INT64 1
-# define LCMSSLONGLONG int64_t
-# define LCMSULONGLONG u_int64_t
-#endif
-
-#ifdef USE_INT64
-# ifndef LCMSULONGLONG
-# define LCMSULONGLONG unsigned long long
-# define LCMSSLONGLONG long long
-# endif
-#endif
-
-#if !defined(__INTEGRITY)
-# include <memory.h>
-#endif
-
-#include <string.h>
-
-#if defined(__GNUC__) || defined(__FreeBSD__)
-# include <unistd.h>
-#endif
-
-#ifndef LCMS_WIN_TYPES_ALREADY_DEFINED
-
-typedef unsigned char BYTE, *LPBYTE;
-typedef unsigned short WORD, *LPWORD;
-typedef unsigned long DWORD, *LPDWORD;
-typedef char *LPSTR;
-typedef void *LPVOID;
-
-#define ZeroMemory(p,l) memset((p),0,(l))
-#define CopyMemory(d,s,l) memcpy((d),(s),(l))
-#define FAR
-
-#ifndef stricmp
-# define stricmp strcasecmp
-#endif
-
-
-#ifndef FALSE
-# define FALSE 0
-#endif
-#ifndef TRUE
-# define TRUE 1
-#endif
-
-#define LOWORD(l) ((WORD)(l))
-#define HIWORD(l) ((WORD)((DWORD)(l) >> 16))
-
-#ifndef MAX_PATH
-# define MAX_PATH (256)
-#endif
-
-#define cdecl
-#endif
-
-// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999).
-
-#define LCMS_INLINE static inline
-
-#else
-
-// Win32 stuff
-
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#include <windows.h>
-
-#ifdef _WIN64
-# ifdef USE_ASSEMBLER
-# undef USE_ASSEMBLER
-# define USE_C 1
-# endif
-#endif
-
-#ifdef USE_INT64
-# ifndef LCMSULONGLONG
-# define LCMSULONGLONG unsigned __int64
-# define LCMSSLONGLONG __int64
-# endif
-#endif
-
-// This works for both VC & BorlandC
-#define LCMS_INLINE __inline
-
-#ifdef USE_PTHREADS
-typedef CRITICAL_SECTION LCMS_RWLOCK_T;
-# define LCMS_CREATE_LOCK(x) InitializeCriticalSection((x))
-# define LCMS_FREE_LOCK(x) DeleteCriticalSection((x))
-# define LCMS_READ_LOCK(x) EnterCriticalSection((x))
-# define LCMS_WRITE_LOCK(x) EnterCriticalSection((x))
-# define LCMS_UNLOCK(x) LeaveCriticalSection((x))
-#endif
-
-#endif
-
-#ifndef USE_PTHREADS
-typedef int LCMS_RWLOCK_T;
-# define LCMS_CREATE_LOCK(x)
-# define LCMS_FREE_LOCK(x)
-# define LCMS_READ_LOCK(x)
-# define LCMS_WRITE_LOCK(x)
-# define LCMS_UNLOCK(x)
-#endif
-
-// Base types
-
-typedef int LCMSBOOL;
-typedef void* LCMSHANDLE;
-
-#include "icc34.h" // ICC header file
-
-
-// Some tag & type additions
-
-#define lcmsSignature ((icSignature) 0x6c636d73L)
-
-#define icSigLuvKData ((icColorSpaceSignature) 0x4C75764BL) // 'LuvK'
-
-#define icSigHexachromeData ((icColorSpaceSignature) 0x4d434836L) // MCH6
-#define icSigHeptachromeData ((icColorSpaceSignature) 0x4d434837L) // MCH7
-#define icSigOctachromeData ((icColorSpaceSignature) 0x4d434838L) // MCH8
-
-#define icSigMCH5Data ((icColorSpaceSignature) 0x4d434835L) // MCH5
-#define icSigMCH6Data ((icColorSpaceSignature) 0x4d434836L) // MCH6
-#define icSigMCH7Data ((icColorSpaceSignature) 0x4d434837L) // MCH7
-#define icSigMCH8Data ((icColorSpaceSignature) 0x4d434838L) // MCH8
-#define icSigMCH9Data ((icColorSpaceSignature) 0x4d434839L) // MCH9
-#define icSigMCHAData ((icColorSpaceSignature) 0x4d434841L) // MCHA
-#define icSigMCHBData ((icColorSpaceSignature) 0x4d434842L) // MCHB
-#define icSigMCHCData ((icColorSpaceSignature) 0x4d434843L) // MCHC
-#define icSigMCHDData ((icColorSpaceSignature) 0x4d434844L) // MCHD
-#define icSigMCHEData ((icColorSpaceSignature) 0x4d434845L) // MCHE
-#define icSigMCHFData ((icColorSpaceSignature) 0x4d434846L) // MCHF
-
-#define icSigChromaticityTag ((icTagSignature) 0x6368726dL) // As per Addendum 2 to Spec. ICC.1:1998-09
-#define icSigChromaticAdaptationTag ((icTagSignature) 0x63686164L) // 'chad'
-#define icSigColorantTableTag ((icTagSignature) 0x636c7274L) // 'clrt'
-#define icSigColorantTableOutTag ((icTagSignature) 0x636c6f74L) // 'clot'
-
-#define icSigParametricCurveType ((icTagTypeSignature) 0x70617261L) // parametric (ICC 4.0)
-#define icSigMultiLocalizedUnicodeType ((icTagTypeSignature) 0x6D6C7563L)
-#define icSigS15Fixed16ArrayType ((icTagTypeSignature) 0x73663332L)
-#define icSigChromaticityType ((icTagTypeSignature) 0x6368726dL)
-#define icSiglutAtoBType ((icTagTypeSignature) 0x6d414220L) // mAB
-#define icSiglutBtoAType ((icTagTypeSignature) 0x6d424120L) // mBA
-#define icSigColorantTableType ((icTagTypeSignature) 0x636c7274L) // clrt
-
-
-typedef struct {
- icUInt8Number gridPoints[16]; // Number of grid points in each dimension.
- icUInt8Number prec; // Precision of data elements in bytes.
- icUInt8Number pad1;
- icUInt8Number pad2;
- icUInt8Number pad3;
- /*icUInt8Number data[icAny]; Data follows see spec for size */
-} icCLutStruct;
-
-// icLutAtoB
-typedef struct {
- icUInt8Number inputChan; // Number of input channels
- icUInt8Number outputChan; // Number of output channels
- icUInt8Number pad1;
- icUInt8Number pad2;
- icUInt32Number offsetB; // Offset to first "B" curve
- icUInt32Number offsetMat; // Offset to matrix
- icUInt32Number offsetM; // Offset to first "M" curve
- icUInt32Number offsetC; // Offset to CLUT
- icUInt32Number offsetA; // Offset to first "A" curve
- /*icUInt8Number data[icAny]; Data follows see spec for size */
-} icLutAtoB;
-
-// icLutBtoA
-typedef struct {
- icUInt8Number inputChan; // Number of input channels
- icUInt8Number outputChan; // Number of output channels
- icUInt8Number pad1;
- icUInt8Number pad2;
- icUInt32Number offsetB; // Offset to first "B" curve
- icUInt32Number offsetMat; // Offset to matrix
- icUInt32Number offsetM; // Offset to first "M" curve
- icUInt32Number offsetC; // Offset to CLUT
- icUInt32Number offsetA; // Offset to first "A" curve
- /*icUInt8Number data[icAny]; Data follows see spec for size */
-} icLutBtoA;
-
-
-
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Calling convention
-
-#ifdef NON_WINDOWS
-# define LCMSEXPORT
-# define LCMSAPI
-#else
-# ifdef LCMS_DLL
-# ifdef __BORLANDC__
-# define LCMSEXPORT __stdcall _export
-# define LCMSAPI
-# else
- // VC++
-# define LCMSEXPORT _stdcall
-# ifdef LCMS_DLL_BUILD
-# define LCMSAPI __declspec(dllexport)
-# else
-# define LCMSAPI __declspec(dllimport)
-# endif
-# endif
-# else
-# define LCMSEXPORT cdecl
-# define LCMSAPI
-# endif
-#endif
-
-#ifdef USE_ASSEMBLER
-#ifdef __BORLANDC__
-
-# define ASM asm
-# define RET(v) return(v)
-#else
- // VC++
-# define ASM __asm
-# define RET(v) return
-#endif
-#endif
-
-#ifdef _MSC_VER
-#ifndef stricmp
-# define stricmp _stricmp
-#endif
-#ifndef unlink
-# define unlink _unlink
-#endif
-#ifndef swab
-# define swab _swab
-#endif
-#ifndef itoa
-# define itoa _itoa
-#endif
-#ifndef fileno
-# define fileno _fileno
-#endif
-#ifndef strupr
-# define strupr _strupr
-#endif
-#ifndef hypot
-# define hypot _hypot
-#endif
-#ifndef snprintf
-# define snprintf _snprintf
-#endif
-#ifndef vsnprintf
-# define vsnprintf _vsnprintf
-#endif
-
-
-#endif
-
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-
-#ifndef LOGE
-# define LOGE 0.4342944819
-#endif
-
-// ********** Little cms API ***************************************************
-
-typedef LCMSHANDLE cmsHPROFILE; // Opaque typedefs to hide internals
-typedef LCMSHANDLE cmsHTRANSFORM;
-
-#define MAXCHANNELS 16 // Maximum number of channels
-
-// Format of pixel is defined by one DWORD, using bit fields as follows
-//
-// D TTTTT U Y F P X S EEE CCCC BBB
-//
-// D: Use dither (8 bits only)
-// T: Pixeltype
-// F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla)
-// P: Planar? 0=Chunky, 1=Planar
-// X: swap 16 bps endianess?
-// S: Do swap? ie, BGR, KYMC
-// E: Extra samples
-// C: Channels (Samples per pixel)
-// B: Bytes per sample
-// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK
-
-
-#define DITHER_SH(s) ((s) << 22)
-#define COLORSPACE_SH(s) ((s) << 16)
-#define SWAPFIRST_SH(s) ((s) << 14)
-#define FLAVOR_SH(s) ((s) << 13)
-#define PLANAR_SH(p) ((p) << 12)
-#define ENDIAN16_SH(e) ((e) << 11)
-#define DOSWAP_SH(e) ((e) << 10)
-#define EXTRA_SH(e) ((e) << 7)
-#define CHANNELS_SH(c) ((c) << 3)
-#define BYTES_SH(b) (b)
-
-// Pixel types
-
-#define PT_ANY 0 // Don't check colorspace
- // 1 & 2 are reserved
-#define PT_GRAY 3
-#define PT_RGB 4
-#define PT_CMY 5
-#define PT_CMYK 6
-#define PT_YCbCr 7
-#define PT_YUV 8 // Lu'v'
-#define PT_XYZ 9
-#define PT_Lab 10
-#define PT_YUVK 11 // Lu'v'K
-#define PT_HSV 12
-#define PT_HLS 13
-#define PT_Yxy 14
-#define PT_HiFi 15
-#define PT_HiFi7 16
-#define PT_HiFi8 17
-#define PT_HiFi9 18
-#define PT_HiFi10 19
-#define PT_HiFi11 20
-#define PT_HiFi12 21
-#define PT_HiFi13 22
-#define PT_HiFi14 23
-#define PT_HiFi15 24
-
-#define NOCOLORSPACECHECK(x) ((x) & 0xFFFF)
-
-// Some (not all!) representations
-
-#ifndef TYPE_RGB_8 // TYPE_RGB_8 is a very common identifier, so don't include ours
- // if user has it already defined.
-
-#define TYPE_GRAY_8 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1))
-#define TYPE_GRAY_8_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1))
-#define TYPE_GRAY_16 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2))
-#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1))
-#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1))
-#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2))
-#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1))
-
-#define TYPE_RGB_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_RGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_BGR_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_BGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1))
-#define TYPE_RGB_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_RGB_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_RGB_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_BGR_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_BGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
-#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-
-#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
-
-#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
-#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-
-#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1))
-
-#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_CMY_8_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_CMY_16 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_CMY_16_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_CMY_16_SE (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-#define TYPE_CMYK_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1))
-#define TYPE_CMYKA_8 (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(1))
-#define TYPE_CMYK_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1))
-#define TYPE_YUVK_8 TYPE_CMYK_8_REV
-#define TYPE_CMYK_8_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_CMYK_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2))
-#define TYPE_CMYK_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1))
-#define TYPE_YUVK_16 TYPE_CMYK_16_REV
-#define TYPE_CMYK_16_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_CMYK_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-#define TYPE_KYMC_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-
-#define TYPE_KCMY_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_KCMY_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_KCMY_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1))
-#define TYPE_KCMY_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)|SWAPFIRST_SH(1))
-#define TYPE_KCMY_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1))
-
-
-// HiFi separations, Thanks to Steven Greaves for providing the code,
-// the colorspace is not checked
-#define TYPE_CMYK5_8 (CHANNELS_SH(5)|BYTES_SH(1))
-#define TYPE_CMYK5_16 (CHANNELS_SH(5)|BYTES_SH(2))
-#define TYPE_CMYK5_16_SE (CHANNELS_SH(5)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC5_8 (CHANNELS_SH(5)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC5_16 (CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC5_16_SE (CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-
-#define TYPE_CMYKcm_8 (CHANNELS_SH(6)|BYTES_SH(1))
-#define TYPE_CMYKcm_8_PLANAR (CHANNELS_SH(6)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_CMYKcm_16 (CHANNELS_SH(6)|BYTES_SH(2))
-#define TYPE_CMYKcm_16_PLANAR (CHANNELS_SH(6)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_CMYKcm_16_SE (CHANNELS_SH(6)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-// Separations with more than 6 channels aren't very standarized,
-// Except most start with CMYK and add other colors, so I just used
-// then total number of channels after CMYK i.e CMYK8_8
-
-#define TYPE_CMYK7_8 (CHANNELS_SH(7)|BYTES_SH(1))
-#define TYPE_CMYK7_16 (CHANNELS_SH(7)|BYTES_SH(2))
-#define TYPE_CMYK7_16_SE (CHANNELS_SH(7)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC7_8 (CHANNELS_SH(7)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC7_16 (CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC7_16_SE (CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-#define TYPE_CMYK8_8 (CHANNELS_SH(8)|BYTES_SH(1))
-#define TYPE_CMYK8_16 (CHANNELS_SH(8)|BYTES_SH(2))
-#define TYPE_CMYK8_16_SE (CHANNELS_SH(8)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC8_8 (CHANNELS_SH(8)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC8_16 (CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC8_16_SE (CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-#define TYPE_CMYK9_8 (CHANNELS_SH(9)|BYTES_SH(1))
-#define TYPE_CMYK9_16 (CHANNELS_SH(9)|BYTES_SH(2))
-#define TYPE_CMYK9_16_SE (CHANNELS_SH(9)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC9_8 (CHANNELS_SH(9)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC9_16 (CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC9_16_SE (CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-#define TYPE_CMYK10_8 (CHANNELS_SH(10)|BYTES_SH(1))
-#define TYPE_CMYK10_16 (CHANNELS_SH(10)|BYTES_SH(2))
-#define TYPE_CMYK10_16_SE (CHANNELS_SH(10)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC10_8 (CHANNELS_SH(10)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC10_16 (CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC10_16_SE (CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-#define TYPE_CMYK11_8 (CHANNELS_SH(11)|BYTES_SH(1))
-#define TYPE_CMYK11_16 (CHANNELS_SH(11)|BYTES_SH(2))
-#define TYPE_CMYK11_16_SE (CHANNELS_SH(11)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC11_8 (CHANNELS_SH(11)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC11_16 (CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC11_16_SE (CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-#define TYPE_CMYK12_8 (CHANNELS_SH(12)|BYTES_SH(1))
-#define TYPE_CMYK12_16 (CHANNELS_SH(12)|BYTES_SH(2))
-#define TYPE_CMYK12_16_SE (CHANNELS_SH(12)|BYTES_SH(2)|ENDIAN16_SH(1))
-#define TYPE_KYMC12_8 (CHANNELS_SH(12)|BYTES_SH(1)|DOSWAP_SH(1))
-#define TYPE_KYMC12_16 (CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1))
-#define TYPE_KYMC12_16_SE (CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
-
-// Colorimetric
-
-#define TYPE_XYZ_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_Lab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1))
-#define TYPE_Lab_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_Yxy_16 (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2))
-
-// YCbCr
-
-#define TYPE_YCbCr_8 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_YCbCr_8_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_YCbCr_16 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_YCbCr_16_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_YCbCr_16_SE (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-// YUV
-
-#define TYPE_YUV_8 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_YUV_8_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_YUV_16 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_YUV_16_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_YUV_16_SE (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-// HLS
-
-#define TYPE_HLS_8 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_HLS_8_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_HLS_16 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_HLS_16_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_HLS_16_SE (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-
-// HSV
-
-#define TYPE_HSV_8 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1))
-#define TYPE_HSV_8_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
-#define TYPE_HSV_16 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2))
-#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
-#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-
-// Named color index. Only 16 bits allowed (don't check colorspace)
-
-#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2))
-
-// Double values. Painful slow, but sometimes helpful. NOTE THAT 'BYTES' FIELD IS SET TO ZERO!
-
-#define TYPE_XYZ_DBL (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(0))
-#define TYPE_Lab_DBL (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0))
-#define TYPE_GRAY_DBL (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0))
-#define TYPE_RGB_DBL (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
-#define TYPE_CMYK_DBL (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0))
-
-#endif
-
-
-// Gamma table parameters
-
-typedef struct {
-
- unsigned int Crc32; // Has my table been touched?
-
- // Keep initial parameters for further serialization
-
- int Type;
- double Params[10];
-
- } LCMSGAMMAPARAMS, FAR* LPLCMSGAMMAPARAMS;
-
-// Gamma tables.
-
-typedef struct {
-
- LCMSGAMMAPARAMS Seed; // Parameters used for table creation
-
- // Table-based representation follows
-
- int nEntries;
- WORD GammaTable[1];
-
- } GAMMATABLE;
-
-typedef GAMMATABLE FAR* LPGAMMATABLE;
-
-// Sampled curves (1D)
-typedef struct {
-
- int nItems;
- double* Values;
-
- } SAMPLEDCURVE;
-
-typedef SAMPLEDCURVE FAR* LPSAMPLEDCURVE;
-
-// Vectors
-typedef struct { // Float Vector
-
- double n[3];
-
- } VEC3;
-
-typedef VEC3 FAR* LPVEC3;
-
-
-typedef struct { // Matrix
-
- VEC3 v[3];
-
- } MAT3;
-
-typedef MAT3 FAR* LPMAT3;
-
-// Colorspace values
-typedef struct {
-
- double X;
- double Y;
- double Z;
-
- } cmsCIEXYZ;
-
-typedef cmsCIEXYZ FAR* LPcmsCIEXYZ;
-
-typedef struct {
-
- double x;
- double y;
- double Y;
-
- } cmsCIExyY;
-
-typedef cmsCIExyY FAR* LPcmsCIExyY;
-
-typedef struct {
-
- double L;
- double a;
- double b;
-
- } cmsCIELab;
-
-typedef cmsCIELab FAR* LPcmsCIELab;
-
-typedef struct {
-
- double L;
- double C;
- double h;
-
- } cmsCIELCh;
-
-typedef cmsCIELCh FAR* LPcmsCIELCh;
-
-typedef struct {
-
- double J;
- double C;
- double h;
-
- } cmsJCh;
-
-typedef cmsJCh FAR* LPcmsJCh;
-
-// Primaries
-typedef struct {
-
- cmsCIEXYZ Red;
- cmsCIEXYZ Green;
- cmsCIEXYZ Blue;
-
- } cmsCIEXYZTRIPLE;
-
-typedef cmsCIEXYZTRIPLE FAR* LPcmsCIEXYZTRIPLE;
-
-
-typedef struct {
-
- cmsCIExyY Red;
- cmsCIExyY Green;
- cmsCIExyY Blue;
-
- } cmsCIExyYTRIPLE;
-
-typedef cmsCIExyYTRIPLE FAR* LPcmsCIExyYTRIPLE;
-
-
-
-// Following ICC spec
-
-#define D50X (0.9642)
-#define D50Y (1.0)
-#define D50Z (0.8249)
-
-#define PERCEPTUAL_BLACK_X (0.00336)
-#define PERCEPTUAL_BLACK_Y (0.0034731)
-#define PERCEPTUAL_BLACK_Z (0.00287)
-
-// Does return pointers to constant structs
-
-LCMSAPI LPcmsCIEXYZ LCMSEXPORT cmsD50_XYZ(void);
-LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void);
-
-
-// Input/Output
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess);
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile);
-
-// Predefined run-time profiles
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateRGBProfile(LPcmsCIExyY WhitePoint,
- LPcmsCIExyYTRIPLE Primaries,
- LPGAMMATABLE TransferFunction[3]);
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateGrayProfile(LPcmsCIExyY WhitePoint,
- LPGAMMATABLE TransferFunction);
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature ColorSpace,
- LPGAMMATABLE TransferFunctions[]);
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature ColorSpace,
- double Limit);
-
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint);
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint);
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void);
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void);
-
-
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
- double Bright,
- double Contrast,
- double Hue,
- double Saturation,
- int TempSrc,
- int TempDest);
-
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void);
-
-
-// Colorimetric space conversions
-
-LCMSAPI void LCMSEXPORT cmsXYZ2xyY(LPcmsCIExyY Dest, const cmsCIEXYZ* Source);
-LCMSAPI void LCMSEXPORT cmsxyY2XYZ(LPcmsCIEXYZ Dest, const cmsCIExyY* Source);
-LCMSAPI void LCMSEXPORT cmsXYZ2Lab(LPcmsCIEXYZ WhitePoint, LPcmsCIELab Lab, const cmsCIEXYZ* xyz);
-LCMSAPI void LCMSEXPORT cmsLab2XYZ(LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ xyz, const cmsCIELab* Lab);
-LCMSAPI void LCMSEXPORT cmsLab2LCh(LPcmsCIELCh LCh, const cmsCIELab* Lab);
-LCMSAPI void LCMSEXPORT cmsLCh2Lab(LPcmsCIELab Lab, const cmsCIELCh* LCh);
-
-
-// CIELab handling
-
-LCMSAPI double LCMSEXPORT cmsDeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2);
-LCMSAPI double LCMSEXPORT cmsCIE94DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2);
-LCMSAPI double LCMSEXPORT cmsBFDdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2);
-LCMSAPI double LCMSEXPORT cmsCMCdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2);
-LCMSAPI double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2, double Kl, double Kc, double Kh);
-
-LCMSAPI void LCMSEXPORT cmsClampLab(LPcmsCIELab Lab, double amax, double amin, double bmax, double bmin);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result,
- LPcmsCIEXYZ SourceWhitePt,
- LPcmsCIEXYZ Illuminant,
- LPcmsCIEXYZ Value);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r,
- LPcmsCIExyY WhitePoint,
- LPcmsCIExyYTRIPLE Primaries);
-
-// Viewing conditions
-
-#define AVG_SURROUND_4 0
-#define AVG_SURROUND 1
-#define DIM_SURROUND 2
-#define DARK_SURROUND 3
-#define CUTSHEET_SURROUND 4
-
-#define D_CALCULATE (-1)
-#define D_CALCULATE_DISCOUNT (-2)
-
-typedef struct {
-
- cmsCIEXYZ whitePoint;
- double Yb;
- double La;
- int surround;
- double D_value;
-
- } cmsViewingConditions;
-
-typedef cmsViewingConditions FAR* LPcmsViewingConditions;
-
-// CIECAM97s
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC2);
-LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel);
-LCMSAPI void LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut);
-
-
-// CIECAM02
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC);
-LCMSAPI void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel);
-LCMSAPI void LCMSEXPORT cmsCIECAM02Forward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut);
-
-
-// Gamma
-
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries);
-LCMSAPI void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma);
-LCMSAPI void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3]);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda);
-LCMSAPI double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t);
-LCMSAPI double LCMSEXPORT cmsEstimateGammaEx(LPWORD Table, int nEntries, double Thereshold);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig);
-LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSignature sig);
-
-// Access to Profile data.
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile);
-LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderFlags(cmsHPROFILE hProfile);
-LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderAttributes(cmsHPROFILE hProfile);
-
-LCMSAPI void LCMSEXPORT cmsSetLanguage(const char LanguageCode[4], const char CountryCode[4]);
-LCMSAPI const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile);
-LCMSAPI const char* LCMSEXPORT cmsTakeProductDesc(cmsHPROFILE hProfile);
-LCMSAPI const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile);
-LCMSAPI const char* LCMSEXPORT cmsTakeManufacturer(cmsHPROFILE hProfile);
-LCMSAPI const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile);
-LCMSAPI const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile);
-LCMSAPI const BYTE* LCMSEXPORT cmsTakeProfileID(cmsHPROFILE hProfile);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig);
-LCMSAPI int LCMSEXPORT cmsTakeRenderingIntent(cmsHPROFILE hProfile);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len);
-
-LCMSAPI int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Text, size_t size);
-LCMSAPI int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Text);
-
-
-#define LCMS_DESC_MAX 512
-
-typedef struct {
-
- icSignature deviceMfg;
- icSignature deviceModel;
- icUInt32Number attributes[2];
- icTechnologySignature technology;
-
- char Manufacturer[LCMS_DESC_MAX];
- char Model[LCMS_DESC_MAX];
-
- } cmsPSEQDESC, FAR *LPcmsPSEQDESC;
-
-typedef struct {
-
- int n;
- cmsPSEQDESC seq[1];
-
- } cmsSEQ, FAR *LPcmsSEQ;
-
-
-LCMSAPI LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile);
-LCMSAPI void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq);
-
-
-// Translate form/to our notation to ICC
-LCMSAPI icColorSpaceSignature LCMSEXPORT _cmsICCcolorSpace(int OurNotation);
-LCMSAPI int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace);
-LCMSAPI int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile);
-
-// How profiles may be used
-#define LCMS_USED_AS_INPUT 0
-#define LCMS_USED_AS_OUTPUT 1
-#define LCMS_USED_AS_PROOF 2
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection);
-
-LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetPCS(cmsHPROFILE hProfile);
-LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile);
-LCMSAPI icProfileClassSignature LCMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile);
-LCMSAPI DWORD LCMSEXPORT cmsGetProfileICCversion(cmsHPROFILE hProfile);
-LCMSAPI void LCMSEXPORT cmsSetProfileICCversion(cmsHPROFILE hProfile, DWORD Version);
-LCMSAPI icInt32Number LCMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile);
-LCMSAPI icTagSignature LCMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, icInt32Number n);
-
-
-LCMSAPI void LCMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, icProfileClassSignature sig);
-LCMSAPI void LCMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, icColorSpaceSignature sig);
-LCMSAPI void LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs);
-LCMSAPI void LCMSEXPORT cmsSetRenderingIntent(cmsHPROFILE hProfile, int RenderingIntent);
-LCMSAPI void LCMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, DWORD Flags);
-LCMSAPI void LCMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, DWORD Flags);
-LCMSAPI void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID);
-
-// Intents
-
-#define INTENT_PERCEPTUAL 0
-#define INTENT_RELATIVE_COLORIMETRIC 1
-#define INTENT_SATURATION 2
-#define INTENT_ABSOLUTE_COLORIMETRIC 3
-
-// Flags
-
-#define cmsFLAGS_MATRIXINPUT 0x0001
-#define cmsFLAGS_MATRIXOUTPUT 0x0002
-#define cmsFLAGS_MATRIXONLY (cmsFLAGS_MATRIXINPUT|cmsFLAGS_MATRIXOUTPUT)
-
-#define cmsFLAGS_NOWHITEONWHITEFIXUP 0x0004 // Don't hot fix scum dot
-#define cmsFLAGS_NOPRELINEARIZATION 0x0010 // Don't create prelinearization tables
- // on precalculated transforms (internal use)
-
-#define cmsFLAGS_GUESSDEVICECLASS 0x0020 // Guess device class (for transform2devicelink)
-
-#define cmsFLAGS_NOTCACHE 0x0040 // Inhibit 1-pixel cache
-
-#define cmsFLAGS_NOTPRECALC 0x0100
-#define cmsFLAGS_NULLTRANSFORM 0x0200 // Don't transform anyway
-#define cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better accurancy
-#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resouces
-
-
-#define cmsFLAGS_WHITEBLACKCOMPENSATION 0x2000
-#define cmsFLAGS_BLACKPOINTCOMPENSATION cmsFLAGS_WHITEBLACKCOMPENSATION
-
-// Proofing flags
-
-#define cmsFLAGS_GAMUTCHECK 0x1000 // Out of Gamut alarm
-#define cmsFLAGS_SOFTPROOFING 0x4000 // Do softproofing
-
-// Black preservation
-
-#define cmsFLAGS_PRESERVEBLACK 0x8000
-
-// CRD special
-
-#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x01000000
-
-// Gridpoints
-
-#define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16)
-
-
-// Transforms
-
-LCMSAPI cmsHTRANSFORM LCMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
- DWORD InputFormat,
- cmsHPROFILE Output,
- DWORD OutputFormat,
- int Intent,
- DWORD dwFlags);
-
-LCMSAPI cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE Input,
- DWORD InputFormat,
- cmsHPROFILE Output,
- DWORD OutputFormat,
- cmsHPROFILE Proofing,
- int Intent,
- int ProofingIntent,
- DWORD dwFlags);
-
-LCMSAPI cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
- int nProfiles,
- DWORD InputFormat,
- DWORD OutputFormat,
- int Intent,
- DWORD dwFlags);
-
-LCMSAPI void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform);
-
-LCMSAPI void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
- LPVOID InputBuffer,
- LPVOID OutputBuffer,
- unsigned int Size);
-
-LCMSAPI void LCMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, DWORD InputFormat, DWORD dwOutputFormat);
-
-LCMSAPI void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b);
-LCMSAPI void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b);
-
-
-// Adaptation state for absolute colorimetric intent
-
-LCMSAPI double LCMSEXPORT cmsSetAdaptationState(double d);
-
-
-// Primary preservation strategy
-
-#define LCMS_PRESERVE_PURE_K 0
-#define LCMS_PRESERVE_K_PLANE 1
-
-LCMSAPI int LCMSEXPORT cmsSetCMYKPreservationStrategy(int n);
-
-// Named color support
-typedef struct {
- char Name[MAX_PATH];
- WORD PCS[3];
- WORD DeviceColorant[MAXCHANNELS];
-
-
- } cmsNAMEDCOLOR, FAR* LPcmsNAMEDCOLOR;
-
-typedef struct {
- int nColors;
- int Allocated;
- int ColorantCount;
- char Prefix[33];
- char Suffix[33];
-
- cmsNAMEDCOLOR List[1];
-
- } cmsNAMEDCOLORLIST, FAR* LPcmsNAMEDCOLORLIST;
-
-// Named color support
-
-LCMSAPI int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix);
-LCMSAPI int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name);
-
-// Colorant tables
-
-LCMSAPI LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagSignature sig);
-
-// Profile creation
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* data);
-
-// Converts a transform to a devicelink profile
-LCMSAPI cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags);
-
-// Set the 'save as 8-bit' flag
-LCMSAPI void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth);
-
-
-// Save profile
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr,
- size_t* BytesNeeded);
-
-
-
-// PostScript ColorRenderingDictionary and ColorSpaceArray
-
-LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen);
-LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRD(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen);
-LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, int Intent, DWORD dwFlags, LPVOID Buffer, DWORD dwBufferLen);
-
-
-// Error handling
-
-#define LCMS_ERROR_ABORT 0
-#define LCMS_ERROR_SHOW 1
-#define LCMS_ERROR_IGNORE 2
-
-LCMSAPI int LCMSEXPORT cmsErrorAction(int nAction);
-
-#define LCMS_ERRC_WARNING 0x1000
-#define LCMS_ERRC_RECOVERABLE 0x2000
-#define LCMS_ERRC_ABORTED 0x3000
-
-typedef int (* cmsErrorHandlerFunction)(int ErrorCode, const char *ErrorText);
-
-LCMSAPI void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn);
-
-
-// LUT manipulation
-
-
-typedef struct _lcms_LUT_struc LUT, FAR* LPLUT; // opaque pointer
-
-LCMSAPI LPLUT LCMSEXPORT cmsAllocLUT(void);
-LCMSAPI LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nTable);
-LCMSAPI LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT Lut, int clutPoints, int inputChan, int outputChan);
-LCMSAPI LPLUT LCMSEXPORT cmsSetMatrixLUT(LPLUT Lut, LPMAT3 M);
-LCMSAPI LPLUT LCMSEXPORT cmsSetMatrixLUT4(LPLUT Lut, LPMAT3 M, LPVEC3 off, DWORD dwFlags);
-LCMSAPI void LCMSEXPORT cmsFreeLUT(LPLUT Lut);
-LCMSAPI void LCMSEXPORT cmsEvalLUT(LPLUT Lut, WORD In[], WORD Out[]);
-LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Result[], LPWORD Hint);
-LCMSAPI LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig);
-LCMSAPI LPLUT LCMSEXPORT cmsDupLUT(LPLUT Orig);
-
-
-// LUT Sampling
-
-typedef int (* _cmsSAMPLER)(register WORD In[],
- register WORD Out[],
- register LPVOID Cargo);
-
-#define SAMPLER_HASTL1 LUT_HASTL1
-#define SAMPLER_HASTL2 LUT_HASTL2
-#define SAMPLER_INSPECT 0x01000000
-
-LCMSAPI int LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags);
-
-// Formatters
-
-typedef unsigned char* (* cmsFORMATTER)(register void* CMMcargo,
- register WORD ToUnroll[],
- register LPBYTE Buffer);
-
-LCMSAPI void LCMSEXPORT cmsSetUserFormatters(cmsHTRANSFORM hTransform, DWORD dwInput, cmsFORMATTER Input,
- DWORD dwOutput, cmsFORMATTER Output);
-
-LCMSAPI void LCMSEXPORT cmsGetUserFormatters(cmsHTRANSFORM hTransform,
- LPDWORD InputFormat, cmsFORMATTER* Input,
- LPDWORD OutputFormat, cmsFORMATTER* Output);
-
-
-// IT8.7 / CGATS.17-200x handling
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void);
-LCMSAPI void LCMSEXPORT cmsIT8Free(LCMSHANDLE IT8);
-
-// Tables
-
-LCMSAPI int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE IT8);
-LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable);
-
-// Persistence
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName);
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded);
-
-// Properties
-LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer);
-
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp);
-LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp);
-LCMSAPI const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp);
-LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames);
-LCMSAPI int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames);
-
-// Datasets
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col);
-LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int row, int col);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col,
- const char* Val);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col,
- double Val);
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample);
-
-
-LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch,
- const char* cSample,
- const char *Val);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch,
- const char* cSample,
- double Val);
-
-LCMSAPI int LCMSEXPORT cmsIT8GetDataFormat(LCMSHANDLE hIT8, const char* cSample);
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample);
-LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames);
-
-
-LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer);
-LCMSAPI int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cSample);
-
-// The LABEL extension
-
-LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType);
-
-LCMSAPI LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample);
-
-// Formatter for double
-LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter);
-
-
-// ***************************************************************************
-// End of Little cms API From here functions are private
-// You can use them only if using static libraries, and at your own risk of
-// be stripped or changed at futures releases.
-
-#ifndef LCMS_APIONLY
-
-
-// Compatibility with anterior versions-- not needed anymore
-// -- Morge
-
-LCMSAPI void LCMSEXPORT cmsLabEncoded2Float(LPcmsCIELab Lab, const WORD wLab[3]);
-LCMSAPI void LCMSEXPORT cmsLabEncoded2Float4(LPcmsCIELab Lab, const WORD wLab[3]);
-LCMSAPI void LCMSEXPORT cmsFloat2LabEncoded(WORD wLab[3], const cmsCIELab* Lab);
-LCMSAPI void LCMSEXPORT cmsFloat2LabEncoded4(WORD wLab[3], const cmsCIELab* Lab);
-LCMSAPI void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fxyz, const WORD XYZ[3]);
-LCMSAPI void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXYZ* fXYZ);
-
-
-// Profiling Extensions --- Would be removed from API in future revisions
-
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ PSeq);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc);
-LCMSAPI LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat);
-
-// --------------------------------------------------------------------------------------------------- Inline functions
-
-// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon
-// note than this only works in the range ..-32767...+32767 because
-// mantissa is interpreted as 15.16 fixed point.
-// The union is to avoid pointer aliasing overoptimization.
-
-LCMS_INLINE int _cmsQuickFloor(double val)
-{
-#ifdef USE_DEFAULT_FLOOR_CONVERSION
- return (int) floor(val);
-#else
- const double _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor
- union {
- double val;
- int halves[2];
- } temp;
-
- temp.val = val + _lcms_double2fixmagic;
-
-
-#ifdef USE_BIG_ENDIAN
- return temp.halves[1] >> 16;
-#else
- return temp.halves[0] >> 16;
-#endif
-#endif
-}
-
-
-
-// Clamp with saturation
-
-LCMS_INLINE WORD _cmsClampWord(int in)
-{
- if (in < 0) return 0;
- if (in > 0xFFFF) return 0xFFFFU; // Including marker
- return (WORD) in;
-}
-
-#ifndef LCMS_USER_ALLOC
-
-// Low-level alloc hook
-
-LCMS_INLINE void* _cmsMalloc(size_t size)
-{
- if (size > ((size_t) 1024*1024*500)) return NULL; // Never allow over 500Mb
- if (size < 0) return NULL; // Prevent signed size_t exploits
-
- return (void*) malloc(size);
-}
-
-LCMS_INLINE void* _cmsCalloc(size_t nmemb, size_t size)
-{
- size_t alloc = nmemb * size;
-
- if (size == 0) {
- return _cmsMalloc(0);
- }
- if (alloc / size != nmemb) {
- return NULL;
- }
- return _cmsMalloc(alloc);
-}
-
-LCMS_INLINE void _cmsFree(void *Ptr)
-{
- if (Ptr) free(Ptr);
-}
-
-#endif
-
-// ------------------------------------------------------------------------------------------- end of inline functions
-
-// Signal error from inside lcms code
-
-void cdecl cmsSignalError(int ErrorCode, const char *ErrorText, ...);
-
-// Alignment handling (needed in ReadLUT16 and ReadLUT8)
-
-typedef struct {
- icS15Fixed16Number a;
- icUInt16Number b;
-
- } _cmsTestAlign16;
-
-#define SIZEOF_UINT16_ALIGNED (sizeof(_cmsTestAlign16) - sizeof(icS15Fixed16Number))
-
-typedef struct {
- icS15Fixed16Number a;
- icUInt8Number b;
-
- } _cmsTestAlign8;
-
-#define SIZEOF_UINT8_ALIGNED (sizeof(_cmsTestAlign8) - sizeof(icS15Fixed16Number))
-
-
-// Fixed point
-
-
-typedef icInt32Number Fixed32; // Fixed 15.16 whith sign
-
-#define INT_TO_FIXED(x) ((x)<<16)
-#define DOUBLE_TO_FIXED(x) ((Fixed32) ((x)*65536.0+0.5))
-#define FIXED_TO_INT(x) ((x)>>16)
-#define FIXED_REST_TO_INT(x) ((x)& 0xFFFFU)
-#define FIXED_TO_DOUBLE(x) (((double)x)/65536.0)
-#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16)
-
-
-Fixed32 cdecl FixedMul(Fixed32 a, Fixed32 b);
-Fixed32 cdecl FixedSquare(Fixed32 a);
-
-
-#ifdef USE_INLINE
-
-LCMS_INLINE Fixed32 ToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); }
-LCMS_INLINE int FromFixedDomain(Fixed32 a) { return a - ((a + 0x7fff) >> 16); }
-
-#else
-
-Fixed32 cdecl ToFixedDomain(int a); // (a * 65536.0 / 65535.0)
-int cdecl FromFixedDomain(Fixed32 a); // (a * 65535.0 + .5)
-
-#endif
-
-Fixed32 cdecl FixedLERP(Fixed32 a, Fixed32 l, Fixed32 h);
-WORD cdecl FixedScale(WORD a, Fixed32 s);
-
-// Vector & Matrix operations. I'm using the notation frequently found in
-// literature. Mostly 'Graphic Gems' samples. Not to be same routines.
-
-// Vector members
-
-#define VX 0
-#define VY 1
-#define VZ 2
-
-typedef struct { // Fixed 15.16 bits vector
- Fixed32 n[3];
- } WVEC3, FAR* LPWVEC3;
-
-typedef struct { // Matrix (Fixed 15.16)
- WVEC3 v[3];
- } WMAT3, FAR* LPWMAT3;
-
-
-
-void cdecl VEC3init(LPVEC3 r, double x, double y, double z); // double version
-void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z); // Fix32 version
-void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v);
-void cdecl VEC3fromFix(LPVEC3 r, LPWVEC3 v);
-void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale);
-void cdecl VEC3swap(LPVEC3 a, LPVEC3 b);
-void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d);
-void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d);
-void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b);
-void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b);
-LCMSBOOL cdecl VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance);
-LCMSBOOL cdecl VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance);
-void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d);
-void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v);
-void cdecl VEC3saturate(LPVEC3 v);
-double cdecl VEC3distance(LPVEC3 a, LPVEC3 b);
-double cdecl VEC3length(LPVEC3 a);
-
-void cdecl MAT3identity(LPMAT3 a);
-void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b);
-void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d);
-int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b);
-LCMSBOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b);
-double cdecl MAT3det(LPMAT3 m);
-void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v);
-void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v);
-void cdecl MAT3fromFix(LPMAT3 r, LPWMAT3 v);
-void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v);
-LCMSBOOL cdecl MAT3isIdentity(LPWMAT3 a, double Tolerance);
-void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d);
-
-// Is a table linear?
-
-int cdecl cmsIsLinear(WORD Table[], int nEntries);
-
-// I hold this structures describing domain
-// details mainly for optimization purposes.
-
-struct _lcms_l16params_struc;
-
-typedef void (* _cms3DLERP)(WORD Input[],
- WORD Output[],
- WORD LutTable[],
- struct _lcms_l16params_struc* p);
-
-
-
-typedef struct _lcms_l8opt_struc { // Used on 8 bit interpolations
-
- unsigned int X0[256], Y0[256], Z0[256];
- WORD rx[256], ry[256], rz[256];
-
- } L8PARAMS, FAR* LPL8PARAMS;
-
-typedef struct _lcms_l16params_struc { // Used on 16 bits interpolations
-
- int nSamples; // Valid on all kinds of tables
- int nInputs; // != 1 only in 3D interpolation
- int nOutputs; // != 1 only in 3D interpolation
-
- WORD Domain;
-
- int opta1, opta2;
- int opta3, opta4; // Optimization for 3D LUT
- int opta5, opta6;
- int opta7, opta8;
-
- _cms3DLERP Interp3D; // The interpolation routine
-
- LPL8PARAMS p8; // Points to some tables for 8-bit speedup
-
- } L16PARAMS, *LPL16PARAMS;
-
-
-void cdecl cmsCalcL16Params(int nSamples, LPL16PARAMS p);
-void cdecl cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p);
-void cdecl cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan,
- LCMSBOOL lUseTetrahedral, LPL16PARAMS p);
-
-WORD cdecl cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p);
-Fixed32 cdecl cmsLinearInterpFixed(WORD Value1, WORD LutTable[], LPL16PARAMS p);
-WORD cdecl cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p);
-
-void cdecl cmsTrilinearInterp16(WORD Input[],
- WORD Output[],
- WORD LutTable[],
- LPL16PARAMS p);
-
-void cdecl cmsTetrahedralInterp16(WORD Input[],
- WORD Output[],
- WORD LutTable[], LPL16PARAMS p);
-
-void cdecl cmsTetrahedralInterp8(WORD Input[],
- WORD Output[],
- WORD LutTable[], LPL16PARAMS p);
-
-// LUT handling
-
-#define LUT_HASMATRIX 0x0001 // Do-op Flags
-#define LUT_HASTL1 0x0002
-#define LUT_HASTL2 0x0008
-#define LUT_HAS3DGRID 0x0010
-
-// New in rev 4.0 of ICC spec
-
-#define LUT_HASMATRIX3 0x0020 // Matrix + offset for LutAToB
-#define LUT_HASMATRIX4 0x0040 // Matrix + offset for LutBToA
-
-#define LUT_HASTL3 0x0100 // '3' curves for LutAToB
-#define LUT_HASTL4 0x0200 // '4' curves for LutBToA
-
-// V4 emulation
-
-#define LUT_V4_OUTPUT_EMULATE_V2 0x10000 // Is a V4 output LUT, emulating V2
-#define LUT_V4_INPUT_EMULATE_V2 0x20000 // Is a V4 input LUT, emulating V2
-#define LUT_V2_OUTPUT_EMULATE_V4 0x40000 // Is a V2 output LUT, emulating V4
-#define LUT_V2_INPUT_EMULATE_V4 0x80000 // Is a V2 input LUT, emulating V4
-
-
-struct _lcms_LUT_struc {
-
- DWORD wFlags;
- WMAT3 Matrix; // 15fixed16 matrix
-
- unsigned int InputChan;
- unsigned int OutputChan;
- unsigned int InputEntries;
- unsigned int OutputEntries;
- unsigned int cLutPoints;
-
-
- LPWORD L1[MAXCHANNELS]; // First linearization
- LPWORD L2[MAXCHANNELS]; // Last linearization
-
- LPWORD T; // 3D CLUT
- unsigned int Tsize; // CLUT size in bytes
-
- // Parameters & Optimizations
-
- L16PARAMS In16params;
- L16PARAMS Out16params;
- L16PARAMS CLut16params;
-
- int Intent; // Accomplished intent
-
- // New for Rev 4.0 of spec (reserved)
-
- WMAT3 Mat3;
- WVEC3 Ofs3;
- LPWORD L3[MAXCHANNELS];
- L16PARAMS L3params;
- unsigned int L3Entries;
-
- WMAT3 Mat4;
- WVEC3 Ofs4;
- LPWORD L4[MAXCHANNELS];
- L16PARAMS L4params;
- unsigned int L4Entries;
-
- // Gray axes fixup. Only on v2 8-bit Lab LUT
-
- LCMSBOOL FixGrayAxes;
-
-
- // Parameters used for curve creation
-
- LCMSGAMMAPARAMS LCurvesSeed[4][MAXCHANNELS];
-
-
- }; // LUT, FAR* LPLUT;
-
-
-LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nEntries);
-
-
-// CRC of gamma tables
-
-unsigned int _cmsCrc32OfGammaTable(LPGAMMATABLE Table);
-
-// Sampled curves
-
-LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems);
-void cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p);
-LPSAMPLEDCURVE cdecl cmsDupSampledCurve(LPSAMPLEDCURVE p);
-
-LPSAMPLEDCURVE cdecl cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints);
-LPGAMMATABLE cdecl cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, double Max);
-
-void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max);
-void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max);
-LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda);
-void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints);
-
-LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints);
-
-// Shaper/Matrix handling
-
-#define MATSHAPER_HASMATRIX 0x0001 // Do-ops flags
-#define MATSHAPER_HASSHAPER 0x0002
-#define MATSHAPER_INPUT 0x0004 // Behaviour
-#define MATSHAPER_OUTPUT 0x0008
-#define MATSHAPER_HASINPSHAPER 0x0010
-#define MATSHAPER_ALLSMELTED (MATSHAPER_INPUT|MATSHAPER_OUTPUT)
-
-
-typedef struct {
- DWORD dwFlags;
-
- WMAT3 Matrix;
-
- L16PARAMS p16; // Primary curve
- LPWORD L[3];
-
- L16PARAMS p2_16; // Secondary curve (used as input in smelted ones)
- LPWORD L2[3];
-
- } MATSHAPER, FAR* LPMATSHAPER;
-
-LPMATSHAPER cdecl cmsAllocMatShaper(LPMAT3 matrix, LPGAMMATABLE Shaper[], DWORD Behaviour);
-LPMATSHAPER cdecl cmsAllocMatShaper2(LPMAT3 matrix, LPGAMMATABLE In[], LPGAMMATABLE Out[], DWORD Behaviour);
-
-void cdecl cmsFreeMatShaper(LPMATSHAPER MatShaper);
-void cdecl cmsEvalMatShaper(LPMATSHAPER MatShaper, WORD In[], WORD Out[]);
-
-LCMSBOOL cdecl cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile);
-
-LPMATSHAPER cdecl cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile);
-LPMATSHAPER cdecl cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile);
-
-
-
-// White Point & Primary chromas handling
-LCMSBOOL cdecl cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll);
-LCMSBOOL cdecl cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt);
-LCMSBOOL cdecl cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt);
-
-LCMSBOOL cdecl cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile);
-
-// Inter-PCS conversion routines. They assume D50 as white point.
-void cdecl cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3]);
-void cdecl cmsLab2XYZEncoded(WORD Lab[3], WORD XYZ[3]);
-
-// Retrieve text representation of WP
-void cdecl _cmsIdentifyWhitePoint(char *Buffer, LPcmsCIEXYZ WhitePt);
-
-// Quantize to WORD in a (MaxSamples - 1) domain
-WORD cdecl _cmsQuantizeVal(double i, int MaxSamples);
-
-LPcmsNAMEDCOLORLIST cdecl cmsAllocNamedColorList(int n);
-int cdecl cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSignature sig);
-void cdecl cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST List);
-LCMSBOOL cdecl cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]);
-
-
-// I/O
-
-#define MAX_TABLE_TAG 100
-
-// This is the internal struct holding profile details.
-
-typedef struct _lcms_iccprofile_struct {
-
- void* stream; // Associated stream. If NULL,
- // tags are supposed to be in
- // memory rather than in a file.
-
- // Only most important items found in ICC profile
-
- icProfileClassSignature DeviceClass;
- icColorSpaceSignature ColorSpace;
- icColorSpaceSignature PCS;
- icRenderingIntent RenderingIntent;
- icUInt32Number flags;
- icUInt32Number attributes;
- cmsCIEXYZ Illuminant;
-
- // Additions for V4 profiles
-
- icUInt32Number Version;
- MAT3 ChromaticAdaptation;
- cmsCIEXYZ MediaWhitePoint;
- cmsCIEXYZ MediaBlackPoint;
- BYTE ProfileID[16];
-
-
- // Dictionary
-
- icInt32Number TagCount;
- icTagSignature TagNames[MAX_TABLE_TAG];
- size_t TagSizes[MAX_TABLE_TAG];
- size_t TagOffsets[MAX_TABLE_TAG];
- LPVOID TagPtrs[MAX_TABLE_TAG];
-
- char PhysicalFile[MAX_PATH];
-
- LCMSBOOL IsWrite;
- LCMSBOOL SaveAs8Bits;
-
- struct tm Created;
-
- // I/O handlers
-
- size_t (* Read)(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc);
-
- LCMSBOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset);
- LCMSBOOL (* Close)(struct _lcms_iccprofile_struct* Icc);
- size_t (* Tell)(struct _lcms_iccprofile_struct* Icc);
- LCMSBOOL (* Grow)(struct _lcms_iccprofile_struct* Icc, size_t amount);
-
- // Writting
-
- LCMSBOOL (* Write)(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr);
-
- size_t UsedSpace;
-
-
- } LCMSICCPROFILE, FAR* LPLCMSICCPROFILE;
-
-
-// Create an empty template for virtual profiles
-cmsHPROFILE cdecl _cmsCreateProfilePlaceholder(void);
-
-// Search into tag dictionary
-icInt32Number cdecl _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError);
-
-// Search for a particular tag, replace if found or add new one else
-LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const void* Init);
-
-
-LPLCMSICCPROFILE cdecl _cmsCreateProfileFromFilePlaceholder(const char* FileName);
-LPLCMSICCPROFILE cdecl _cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr, DWORD dwSize);
-
-void _cmsSetSaveToDisk(LPLCMSICCPROFILE Icc, const char* FileName);
-void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize);
-
-
-
-// These macros unpack format specifiers into integers
-
-#define T_DITHER(s) (((s)>>22)&1)
-#define T_COLORSPACE(s) (((s)>>16)&31)
-#define T_SWAPFIRST(s) (((s)>>14)&1)
-#define T_FLAVOR(s) (((s)>>13)&1)
-#define T_PLANAR(p) (((p)>>12)&1)
-#define T_ENDIAN16(e) (((e)>>11)&1)
-#define T_DOSWAP(e) (((e)>>10)&1)
-#define T_EXTRA(e) (((e)>>7)&7)
-#define T_CHANNELS(c) (((c)>>3)&15)
-#define T_BYTES(b) ((b)&7)
-
-
-
-// Internal XFORM struct
-struct _cmstransform_struct;
-
-// Full xform
-typedef void (* _cmsCOLORCALLBACKFN)(struct _cmstransform_struct *Transform,
- LPVOID InputBuffer,
- LPVOID OutputBuffer, unsigned int Size);
-
-// intermediate pass, from WORD[] to WORD[]
-
-typedef void (* _cmsADJFN)(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 b);
-
-typedef void (* _cmsTRANSFN)(struct _cmstransform_struct *Transform,
- WORD In[], WORD Out[]);
-
-typedef void (* _cmsCNVRT)(WORD In[], WORD Out[]);
-
-typedef LPBYTE (* _cmsFIXFN)(register struct _cmstransform_struct *info,
- register WORD ToUnroll[],
- register LPBYTE Buffer);
-
-
-
-// Transformation
-typedef struct _cmstransform_struct {
-
- // Keep formats for further reference
- DWORD InputFormat, OutputFormat;
-
- DWORD StrideIn, StrideOut; // Planar support
-
- int Intent, ProofIntent;
- int DoGamutCheck;
-
-
- cmsHPROFILE InputProfile;
- cmsHPROFILE OutputProfile;
- cmsHPROFILE PreviewProfile;
-
- icColorSpaceSignature EntryColorSpace;
- icColorSpaceSignature ExitColorSpace;
-
- DWORD dwOriginalFlags; // Flags as specified by user
-
- WMAT3 m1, m2; // Matrix holding inter PCS operation
- WVEC3 of1, of2; // Offset terms
-
- _cmsCOLORCALLBACKFN xform;
-
- // Steps in xFORM
-
- _cmsFIXFN FromInput;
- _cmsTRANSFN FromDevice;
- _cmsADJFN Stage1;
- _cmsADJFN Stage2;
- _cmsTRANSFN ToDevice;
- _cmsFIXFN ToOutput;
-
- // LUTs
-
- LPLUT Device2PCS;
- LPLUT PCS2Device;
- LPLUT Gamut; // Gamut check
- LPLUT Preview; // Preview (Proof)
-
- LPLUT DeviceLink; // Precalculated grid - device link profile
- LPLUT GamutCheck; // Precalculated device -> gamut check
-
- // Matrix/Shapers
-
- LPMATSHAPER InMatShaper;
- LPMATSHAPER OutMatShaper;
- LPMATSHAPER SmeltMatShaper;
-
- // Phase of Lab/XYZ, Abs/Rel
-
- int Phase1, Phase2, Phase3;
-
- // Named color table
-
- LPcmsNAMEDCOLORLIST NamedColorList;
-
- // Flag for transform involving v4 profiles
-
- LCMSBOOL lInputV4Lab, lOutputV4Lab;
-
-
- // 1-pixel cache
-
- WORD CacheIn[MAXCHANNELS];
- WORD CacheOut[MAXCHANNELS];
-
- double AdaptationState; // Figure for v4 incomplete state of adaptation
-
- LCMS_RWLOCK_T rwlock;
-
- } _cmsTRANSFORM,FAR *_LPcmsTRANSFORM;
-
-
-
-// Packing & Unpacking
-
-_cmsFIXFN cdecl _cmsIdentifyInputFormat(_LPcmsTRANSFORM xform, DWORD dwInput);
-_cmsFIXFN cdecl _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput);
-
-
-// Conversion
-
-#define XYZRel 0
-#define LabRel 1
-
-
-int cdecl cmsChooseCnvrt(int Absolute,
- int Phase1, LPcmsCIEXYZ BlackPointIn,
- LPcmsCIEXYZ WhitePointIn,
- LPcmsCIEXYZ IlluminantIn,
- LPMAT3 ChromaticAdaptationMatrixIn,
-
- int Phase2, LPcmsCIEXYZ BlackPointOut,
- LPcmsCIEXYZ WhitePointOut,
- LPcmsCIEXYZ IlluminantOut,
- LPMAT3 ChromaticAdaptationMatrixOut,
- int DoBPC,
- double AdaptationState,
- _cmsADJFN *fn1,
- LPWMAT3 wm, LPWVEC3 wof);
-
-
-
-// Clamping & Gamut handling
-
-LCMSBOOL cdecl _cmsEndPointsBySpace(icColorSpaceSignature Space,
- WORD **White, WORD **Black, int *nOutputs);
-
-WORD * cdecl _cmsWhiteBySpace(icColorSpaceSignature Space);
-
-
-
-WORD cdecl Clamp_L(Fixed32 in);
-WORD cdecl Clamp_ab(Fixed32 in);
-
-// Detection of black point
-
-#define LCMS_BPFLAGS_D50_ADAPTED 0x0001
-
-int cdecl cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent, DWORD dwFlags);
-
-// choose reasonable resolution
-int cdecl _cmsReasonableGridpointsByColorspace(icColorSpaceSignature Colorspace, DWORD dwFlags);
-
-// Precalculate device link
-LPLUT cdecl _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags);
-
-// Precalculate black preserving device link
-LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD dwFlags);
-
-// Precalculate gamut check
-LPLUT cdecl _cmsPrecalculateGamutCheck(cmsHTRANSFORM h);
-
-// Hot fixes bad profiles
-LCMSBOOL cdecl _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p);
-
-// Marks LUT as 8 bit on input
-LPLUT cdecl _cmsBlessLUT8(LPLUT Lut);
-
-// Compute gamut boundary
-LPLUT cdecl _cmsComputeGamutLUT(cmsHPROFILE hProfile, int Intent);
-
-// Compute softproof
-LPLUT cdecl _cmsComputeSoftProofLUT(cmsHPROFILE hProfile, int nIntent);
-
-// Find a suitable prelinearization tables, matching the given transform
-void cdecl _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransforms, LPLUT Grid);
-
-
-// Build a tone curve for K->K' if possible (only works on CMYK)
-LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints);
-
-// Validates a LUT
-LCMSBOOL cdecl _cmsValidateLUT(LPLUT NewLUT);
-
-
-// These are two VITAL macros, from converting between 8 and 16 bit
-// representation.
-
-#define RGB_8_TO_16(rgb) (WORD) ((((WORD) (rgb)) << 8)|(rgb))
-#define RGB_16_TO_8(rgb) (BYTE) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF)
-
-
-#endif // LCMS_APIONLY
-
-
-#define __cms_H
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,1751 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+// Version 2.0
+//
+
+#ifndef _lcms2_H
+
+// ********** Configuration toggles ****************************************
+
+// Uncomment this one if you are using big endian machines
+// #define CMS_USE_BIG_ENDIAN 1
+
+// Uncomment this one if your compiler/machine does NOT support the
+// "long long" type.
+// #define CMS_DONT_USE_INT64 1
+
+// Uncomment this if your compiler doesn't work with fast floor function
+// #define CMS_DONT_USE_FAST_FLOOR 1
+
+// Uncomment this line if your system does not support multithreading
+#define CMS_DONT_USE_PTHREADS 1
+
+// Uncomment this line if you want lcms to use the black point tag in profile,
+// if commented, lcms will compute the black point by its own.
+// It is safer to leave it commented out
+// #define CMS_USE_PROFILE_BLACK_POINT_TAG 1
+
+// Uncomment this line if you are compiling as C++ and want a C++ API
+// #define CMS_USE_CPP_API
+
+// Uncomment this line if you need strict CGATS syntax. Makes CGATS files to
+// require "KEYWORD" on undefined identifiers, keep it comented out unless needed
+// #define CMS_STRICT_CGATS 1
+
+// ********** End of configuration toggles ******************************
+
+// Needed for streams
+#include <stdio.h>
+
+// Needed for portability (C99 per 7.1.2)
+#include <limits.h>
+#include <time.h>
+#include <stddef.h>
+
+#ifndef CMS_USE_CPP_API
+# ifdef __cplusplus
+extern "C" {
+# endif
+#endif
+
+// Version/release
+#define LCMS_VERSION 2000
+
+// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
+#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
+
+// Base types
+typedef unsigned char cmsUInt8Number; // That is guaranteed by the C99 spec
+typedef signed char cmsInt8Number; // That is guaranteed by the C99 spec
+
+// IEEE float storage numbers
+typedef float cmsFloat32Number;
+typedef double cmsFloat64Number;
+
+// 16-bit base types
+#if (USHRT_MAX == 65535U)
+ typedef unsigned short cmsUInt16Number;
+#elif (UINT_MAX == 65535U)
+ typedef unsigned int cmsUInt16Number;
+#else
+# error "Unable to find 16 bits unsigned type, unsupported compiler"
+#endif
+
+#if (SHRT_MAX == 32767)
+ typedef short cmsInt16Number;
+#elif (INT_MAX == 32767)
+ typedef int cmsInt16Number;
+#else
+# error "Unable to find 16 bits signed type, unsupported compiler"
+#endif
+
+// 32-bit base type
+#if (UINT_MAX == 4294967295U)
+ typedef unsigned int cmsUInt32Number;
+#elif (ULONG_MAX == 4294967295U)
+ typedef unsigned long cmsUInt32Number;
+#else
+# error "Unable to find 32 bit unsigned type, unsupported compiler"
+#endif
+
+#if (INT_MAX == +2147483647)
+ typedef int cmsInt32Number;
+#elif (LONG_MAX == +2147483647)
+ typedef long cmsInt32Number;
+#else
+# error "Unable to find 32 bit signed type, unsupported compiler"
+#endif
+
+// 64-bit base types
+#ifndef CMS_DONT_USE_INT64
+# if (ULONG_MAX == 18446744073709551615U)
+ typedef unsigned long cmsUInt64Number;
+# elif (ULLONG_MAX == 18446744073709551615U)
+ typedef unsigned long long cmsUInt64Number;
+# else
+# define CMS_DONT_USE_INT64 1
+# endif
+# if (LONG_MAX == +9223372036854775807)
+ typedef long cmsInt64Number;
+# elif (LLONG_MAX == +9223372036854775807)
+ typedef long long cmsInt64Number;
+# else
+# define CMS_DONT_USE_INT64 1
+# endif
+#endif
+#endif
+
+// In the case 64 bit numbers are not supported by the compiler
+#ifdef CMS_DONT_USE_INT64
+ typedef cmsUInt32Number cmsUInt64Number[2];
+ typedef cmsInt32Number cmsInt64Number[2];
+#endif
+
+// Derivative types
+typedef cmsUInt32Number cmsSignature;
+typedef cmsUInt16Number cmsU8Fixed8Number;
+typedef cmsInt32Number cmsS15Fixed16Number;
+typedef cmsUInt32Number cmsU16Fixed16Number;
+
+// Boolean type, which will be using the native integer
+typedef int cmsBool;
+
+// Try to detect windows
+#if defined (_WIN32) || defined(_WIN64) || defined(WIN32) || defined(_WIN32_)
+# define CMS_IS_WINDOWS_ 1
+#endif
+
+#ifdef _MSC_VER
+# define CMS_IS_WINDOWS_ 1
+#endif
+
+#ifdef __BORLANDC__
+# define CMS_IS_WINDOWS_ 1
+#endif
+
+// Try to detect big endian platforms. This list can be endless, so only some checks are performed over here.
+// you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar
+
+#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN)
+# define CMS_USE_BIG_ENDIAN 1
+#endif
+
+#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc)
+# define CMS_USE_BIG_ENDIAN 1
+#endif
+
+#if defined(__ppc__) || defined(__s390__) || defined(__s390x__)
+# define CMS_USE_BIG_ENDIAN 1
+#endif
+
+#ifdef TARGET_CPU_PPC
+# define CMS_USE_BIG_ENDIAN 1
+#endif
+
+#ifdef macintosh
+# ifndef __LITTLE_ENDIAN__
+# define CMS_USE_BIG_ENDIAN 1
+# endif
+#endif
+
+// Calling convention -- this is hardly platform and compiler dependent
+#ifdef CMS_IS_WINDOWS_
+# if defined(CMS_DLL) || defined(CMS_DLL_BUILD)
+# ifdef __BORLANDC__
+# define CMSEXPORT __stdcall _export
+# define CMSAPI
+# else
+# define CMSEXPORT _stdcall
+# ifdef CMS_DLL_BUILD
+# define CMSAPI __declspec(dllexport)
+# else
+# define CMSAPI __declspec(dllimport)
+# endif
+# endif
+# else
+# define CMSEXPORT
+# define CMSAPI
+# endif
+#else
+# define CMSEXPORT
+# define CMSAPI
+#endif
+
+// Some common definitions
+#define cmsMAX_PATH 256
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+// D50 XYZ normalized to Y=1.0
+#define cmsD50X 0.9642
+#define cmsD50Y 1.0
+#define cmsD50Z 0.8249
+
+// V4 perceptual black
+#define cmsPERCEPTUAL_BLACK_X 0.00336
+#define cmsPERCEPTUAL_BLACK_Y 0.0034731
+#define cmsPERCEPTUAL_BLACK_Z 0.00287
+
+// Definitions in ICC spec
+#define cmsMagicNumber 0x61637370 // 'acsp'
+#define lcmsSignature 0x6c636d73 // 'lcms'
+
+
+// Base ICC type definitions
+typedef enum {
+ cmsSigChromaticityType = 0x6368726D, // 'chrm'
+ cmsSigColorantOrderType = 0x636C726F, // 'clro'
+ cmsSigColorantTableType = 0x636C7274, // 'clrt'
+ cmsSigCrdInfoType = 0x63726469, // 'crdi'
+ cmsSigCurveType = 0x63757276, // 'curv'
+ cmsSigDataType = 0x64617461, // 'data'
+ cmsSigDateTimeType = 0x6474696D, // 'dtim'
+ cmsSigDeviceSettingsType = 0x64657673, // 'devs'
+ cmsSigLut16Type = 0x6d667432, // 'mft2'
+ cmsSigLut8Type = 0x6d667431, // 'mft1'
+ cmsSigLutAtoBType = 0x6d414220, // 'mAB '
+ cmsSigLutBtoAType = 0x6d424120, // 'mBA '
+ cmsSigMeasurementType = 0x6D656173, // 'meas'
+ cmsSigMultiLocalizedUnicodeType = 0x6D6C7563, // 'mluc'
+ cmsSigMultiProcessElementType = 0x6D706574, // 'mpet'
+ cmsSigNamedColorType = 0x6E636f6C, // 'ncol' -- DEPRECATED!
+ cmsSigNamedColor2Type = 0x6E636C32, // 'ncl2'
+ cmsSigParametricCurveType = 0x70617261, // 'para'
+ cmsSigProfileSequenceDescType = 0x70736571, // 'pseq'
+ cmsSigProfileSequenceIdType = 0x70736964, // 'psid'
+ cmsSigResponseCurveSet16Type = 0x72637332, // 'rcs2'
+ cmsSigS15Fixed16ArrayType = 0x73663332, // 'sf32'
+ cmsSigScreeningType = 0x7363726E, // 'scrn'
+ cmsSigSignatureType = 0x73696720, // 'sig '
+ cmsSigTextType = 0x74657874, // 'text'
+ cmsSigTextDescriptionType = 0x64657363, // 'desc'
+ cmsSigU16Fixed16ArrayType = 0x75663332, // 'uf32'
+ cmsSigUcrBgType = 0x62666420, // 'bfd '
+ cmsSigUInt16ArrayType = 0x75693136, // 'ui16'
+ cmsSigUInt32ArrayType = 0x75693332, // 'ui32'
+ cmsSigUInt64ArrayType = 0x75693634, // 'ui64'
+ cmsSigUInt8ArrayType = 0x75693038, // 'ui08'
+ cmsSigViewingConditionsType = 0x76696577, // 'view'
+ cmsSigXYZType = 0x58595A20, // 'XYZ '
+ cmsSigVcgtType = 0x76636774 // 'vcgt'
+
+} cmsTagTypeSignature;
+
+// Base ICC tag definitions
+typedef enum {
+ cmsSigAToB0Tag = 0x41324230, // 'A2B0'
+ cmsSigAToB1Tag = 0x41324231, // 'A2B1'
+ cmsSigAToB2Tag = 0x41324232, // 'A2B2'
+ cmsSigBlueColorantTag = 0x6258595A, // 'bXYZ'
+ cmsSigBlueMatrixColumnTag = 0x6258595A, // 'bXYZ'
+ cmsSigBlueTRCTag = 0x62545243, // 'bTRC'
+ cmsSigBToA0Tag = 0x42324130, // 'B2A0'
+ cmsSigBToA1Tag = 0x42324131, // 'B2A1'
+ cmsSigBToA2Tag = 0x42324132, // 'B2A2'
+ cmsSigCalibrationDateTimeTag = 0x63616C74, // 'calt'
+ cmsSigCharTargetTag = 0x74617267, // 'targ'
+ cmsSigChromaticAdaptationTag = 0x63686164, // 'chad'
+ cmsSigChromaticityTag = 0x6368726D, // 'chrm'
+ cmsSigColorantOrderTag = 0x636C726F, // 'clro'
+ cmsSigColorantTableTag = 0x636C7274, // 'clrt'
+ cmsSigColorantTableOutTag = 0x636C6F74, // 'clot'
+ cmsSigColorimetricIntentImageStateTag = 0x63696973, // 'ciis'
+ cmsSigCopyrightTag = 0x63707274, // 'cprt'
+ cmsSigCrdInfoTag = 0x63726469, // 'crdi'
+ cmsSigDataTag = 0x64617461, // 'data'
+ cmsSigDateTimeTag = 0x6474696D, // 'dtim'
+ cmsSigDeviceMfgDescTag = 0x646D6E64, // 'dmnd'
+ cmsSigDeviceModelDescTag = 0x646D6464, // 'dmdd'
+ cmsSigDeviceSettingsTag = 0x64657673, // 'devs'
+ cmsSigDToB0Tag = 0x44324230, // 'D2B0'
+ cmsSigDToB1Tag = 0x44324231, // 'D2B1'
+ cmsSigDToB2Tag = 0x44324232, // 'D2B2'
+ cmsSigDToB3Tag = 0x44324233, // 'D2B3'
+ cmsSigBToD0Tag = 0x42324430, // 'B2D0'
+ cmsSigBToD1Tag = 0x42324431, // 'B2D1'
+ cmsSigBToD2Tag = 0x42324432, // 'B2D2'
+ cmsSigBToD3Tag = 0x42324433, // 'B2D3'
+ cmsSigGamutTag = 0x67616D74, // 'gamt'
+ cmsSigGrayTRCTag = 0x6b545243, // 'kTRC'
+ cmsSigGreenColorantTag = 0x6758595A, // 'gXYZ'
+ cmsSigGreenMatrixColumnTag = 0x6758595A, // 'gXYZ'
+ cmsSigGreenTRCTag = 0x67545243, // 'gTRC'
+ cmsSigLuminanceTag = 0x6C756d69, // 'lumi'
+ cmsSigMeasurementTag = 0x6D656173, // 'meas'
+ cmsSigMediaBlackPointTag = 0x626B7074, // 'bkpt'
+ cmsSigMediaWhitePointTag = 0x77747074, // 'wtpt'
+ cmsSigNamedColorTag = 0x6E636f6C, // 'ncol' // Deprecated by the ICC
+ cmsSigNamedColor2Tag = 0x6E636C32, // 'ncl2'
+ cmsSigOutputResponseTag = 0x72657370, // 'resp'
+ cmsSigPerceptualRenderingIntentGamutTag = 0x72696730, // 'rig0'
+ cmsSigPreview0Tag = 0x70726530, // 'pre0'
+ cmsSigPreview1Tag = 0x70726531, // 'pre1'
+ cmsSigPreview2Tag = 0x70726532, // 'pre2'
+ cmsSigProfileDescriptionTag = 0x64657363, // 'desc'
+ cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq'
+ cmsSigProfileSequenceIdTag = 0x70736964, // 'psid'
+ cmsSigPs2CRD0Tag = 0x70736430, // 'psd0'
+ cmsSigPs2CRD1Tag = 0x70736431, // 'psd1'
+ cmsSigPs2CRD2Tag = 0x70736432, // 'psd2'
+ cmsSigPs2CRD3Tag = 0x70736433, // 'psd3'
+ cmsSigPs2CSATag = 0x70733273, // 'ps2s'
+ cmsSigPs2RenderingIntentTag = 0x70733269, // 'ps2i'
+ cmsSigRedColorantTag = 0x7258595A, // 'rXYZ'
+ cmsSigRedMatrixColumnTag = 0x7258595A, // 'rXYZ'
+ cmsSigRedTRCTag = 0x72545243, // 'rTRC'
+ cmsSigSaturationRenderingIntentGamutTag = 0x72696732, // 'rig2'
+ cmsSigScreeningDescTag = 0x73637264, // 'scrd'
+ cmsSigScreeningTag = 0x7363726E, // 'scrn'
+ cmsSigTechnologyTag = 0x74656368, // 'tech'
+ cmsSigUcrBgTag = 0x62666420, // 'bfd '
+ cmsSigViewingCondDescTag = 0x76756564, // 'vued'
+ cmsSigViewingConditionsTag = 0x76696577, // 'view'
+ cmsSigVcgtTag = 0x76636774 // 'vcgt'
+
+} cmsTagSignature;
+
+
+// ICC Technology tag
+typedef enum {
+ cmsSigDigitalCamera = 0x6463616D, // 'dcam'
+ cmsSigFilmScanner = 0x6673636E, // 'fscn'
+ cmsSigReflectiveScanner = 0x7273636E, // 'rscn'
+ cmsSigInkJetPrinter = 0x696A6574, // 'ijet'
+ cmsSigThermalWaxPrinter = 0x74776178, // 'twax'
+ cmsSigElectrophotographicPrinter = 0x6570686F, // 'epho'
+ cmsSigElectrostaticPrinter = 0x65737461, // 'esta'
+ cmsSigDyeSublimationPrinter = 0x64737562, // 'dsub'
+ cmsSigPhotographicPaperPrinter = 0x7270686F, // 'rpho'
+ cmsSigFilmWriter = 0x6670726E, // 'fprn'
+ cmsSigVideoMonitor = 0x7669646D, // 'vidm'
+ cmsSigVideoCamera = 0x76696463, // 'vidc'
+ cmsSigProjectionTelevision = 0x706A7476, // 'pjtv'
+ cmsSigCRTDisplay = 0x43525420, // 'CRT '
+ cmsSigPMDisplay = 0x504D4420, // 'PMD '
+ cmsSigAMDisplay = 0x414D4420, // 'AMD '
+ cmsSigPhotoCD = 0x4B504344, // 'KPCD'
+ cmsSigPhotoImageSetter = 0x696D6773, // 'imgs'
+ cmsSigGravure = 0x67726176, // 'grav'
+ cmsSigOffsetLithography = 0x6F666673, // 'offs'
+ cmsSigSilkscreen = 0x73696C6B, // 'silk'
+ cmsSigFlexography = 0x666C6578, // 'flex'
+ cmsSigMotionPictureFilmScanner = 0x6D706673, // 'mpfs'
+ cmsSigMotionPictureFilmRecorder = 0x6D706672, // 'mpfr'
+ cmsSigDigitalMotionPictureCamera = 0x646D7063, // 'dmpc'
+ cmsSigDigitalCinemaProjector = 0x64636A70, // 'dcpj'
+
+} cmsTechnologySignature;
+
+
+// ICC Color spaces
+typedef enum {
+ cmsSigXYZData = 0x58595A20, // 'XYZ '
+ cmsSigLabData = 0x4C616220, // 'Lab '
+ cmsSigLuvData = 0x4C757620, // 'Luv '
+ cmsSigYCbCrData = 0x59436272, // 'YCbr'
+ cmsSigYxyData = 0x59787920, // 'Yxy '
+ cmsSigRgbData = 0x52474220, // 'RGB '
+ cmsSigGrayData = 0x47524159, // 'GRAY'
+ cmsSigHsvData = 0x48535620, // 'HSV '
+ cmsSigHlsData = 0x484C5320, // 'HLS '
+ cmsSigCmykData = 0x434D594B, // 'CMYK'
+ cmsSigCmyData = 0x434D5920, // 'CMY '
+ cmsSigMCH1Data = 0x4D434831, // 'MCH1'
+ cmsSigMCH2Data = 0x4D434832, // 'MCH2'
+ cmsSigMCH3Data = 0x4D434833, // 'MCH3'
+ cmsSigMCH4Data = 0x4D434834, // 'MCH4'
+ cmsSigMCH5Data = 0x4D434835, // 'MCH5'
+ cmsSigMCH6Data = 0x4D434836, // 'MCH6'
+ cmsSigMCH7Data = 0x4D434837, // 'MCH7'
+ cmsSigMCH8Data = 0x4D434838, // 'MCH8'
+ cmsSigMCH9Data = 0x4D434839, // 'MCH9'
+ cmsSigMCHAData = 0x4D43483A, // 'MCHA'
+ cmsSigMCHBData = 0x4D43483B, // 'MCHB'
+ cmsSigMCHCData = 0x4D43483C, // 'MCHC'
+ cmsSigMCHDData = 0x4D43483D, // 'MCHD'
+ cmsSigMCHEData = 0x4D43483E, // 'MCHE'
+ cmsSigMCHFData = 0x4D43483F, // 'MCHF'
+ cmsSigNamedData = 0x6e6d636c, // 'nmcl'
+ cmsSig1colorData = 0x31434C52, // '1CLR'
+ cmsSig2colorData = 0x32434C52, // '2CLR'
+ cmsSig3colorData = 0x33434C52, // '3CLR'
+ cmsSig4colorData = 0x34434C52, // '4CLR'
+ cmsSig5colorData = 0x35434C52, // '5CLR'
+ cmsSig6colorData = 0x36434C52, // '6CLR'
+ cmsSig7colorData = 0x37434C52, // '7CLR'
+ cmsSig8colorData = 0x38434C52, // '8CLR'
+ cmsSig9colorData = 0x39434C52, // '9CLR'
+ cmsSig10colorData = 0x41434C52, // 'ACLR'
+ cmsSig11colorData = 0x42434C52, // 'BCLR'
+ cmsSig12colorData = 0x43434C52, // 'CCLR'
+ cmsSig13colorData = 0x44434C52, // 'DCLR'
+ cmsSig14colorData = 0x45434C52, // 'ECLR'
+ cmsSig15colorData = 0x46434C52, // 'FCLR'
+ cmsSigLuvKData = 0x4C75764B // 'LuvK'
+
+} cmsColorSpaceSignature;
+
+// ICC Profile Class
+typedef enum {
+ cmsSigInputClass = 0x73636E72, // 'scnr'
+ cmsSigDisplayClass = 0x6D6E7472, // 'mntr'
+ cmsSigOutputClass = 0x70727472, // 'prtr'
+ cmsSigLinkClass = 0x6C696E6B, // 'link'
+ cmsSigAbstractClass = 0x61627374, // 'abst'
+ cmsSigColorSpaceClass = 0x73706163, // 'spac'
+ cmsSigNamedColorClass = 0x6e6d636c, // 'nmcl'
+
+} cmsProfileClassSignature;
+
+// ICC Platforms
+typedef enum {
+ cmsSigMacintosh = 0x4150504C, // 'APPL'
+ cmsSigMicrosoft = 0x4D534654, // 'MSFT'
+ cmsSigSolaris = 0x53554E57, // 'SUNW'
+ cmsSigSGI = 0x53474920, // 'SGI '
+ cmsSigTaligent = 0x54474E54, // 'TGNT'
+ cmsSigUnices = 0x2A6E6978 // '*nix' // From argyll -- Not official
+
+} cmsPlatformSignature;
+
+// Reference gamut
+#define cmsSigPerceptualReferenceMediumGamut 0x70726d67 //'prmg'
+
+// For cmsSigColorimetricIntentImageStateTag
+#define cmsSigSceneColorimetryEstimates 0x73636F65 //'scoe'
+#define cmsSigSceneAppearanceEstimates 0x73617065 //'sape'
+#define cmsSigFocalPlaneColorimetryEstimates 0x66706365 //'fpce'
+#define cmsSigReflectionHardcopyOriginalColorimetry 0x72686F63 //'rhoc'
+#define cmsSigReflectionPrintOutputColorimetry 0x72706F63 //'rpoc'
+
+// Multi process elements types
+typedef enum {
+ cmsSigCurveSetElemType = 0x63767374, //'cvst'
+ cmsSigMatrixElemType = 0x6D617466, //'matf'
+ cmsSigCLutElemType = 0x636C7574, //'clut'
+
+ cmsSigBAcsElemType = 0x62414353, // 'bACS'
+ cmsSigEAcsElemType = 0x65414353, // 'eACS'
+
+ // Custom from here, not in the ICC Spec
+ cmsSigXYZ2LabElemType = 0x6C327820, // 'l2x '
+ cmsSigLab2XYZElemType = 0x78326C20, // 'x2l '
+ cmsSigNamedColorElemType = 0x6E636C20, // 'ncl '
+ cmsSigLabV2toV4 = 0x32203420, // '2 4 '
+ cmsSigLabV4toV2 = 0x34203220, // '4 2 '
+
+ // Identities
+ cmsSigIdentityElemType = 0x69646E20 // 'idn '
+
+} cmsStageSignature;
+
+// Types of CurveElements
+typedef enum {
+
+ cmsSigFormulaCurveSeg = 0x70617266, // 'parf'
+ cmsSigSampledCurveSeg = 0x73616D66, // 'samf'
+ cmsSigSegmentedCurve = 0x63757266 // 'curf'
+
+} cmsCurveSegSignature;
+
+// Used in ResponseCurveType
+#define cmsSigStatusA 0x53746141 //'StaA'
+#define cmsSigStatusE 0x53746145 //'StaE'
+#define cmsSigStatusI 0x53746149 //'StaI'
+#define cmsSigStatusT 0x53746154 //'StaT'
+#define cmsSigStatusM 0x5374614D //'StaM'
+#define cmsSigDN 0x444E2020 //'DN '
+#define cmsSigDNP 0x444E2050 //'DN P'
+#define cmsSigDNN 0x444E4E20 //'DNN '
+#define cmsSigDNNP 0x444E4E50 //'DNNP'
+
+// Device attributes, currently defined values correspond to the low 4 bytes
+// of the 8 byte attribute quantity
+#define cmsReflective 0
+#define cmsTransparency 1
+#define cmsGlossy 0
+#define cmsMatte 2
+
+// Common structures in ICC tags
+typedef struct {
+ cmsUInt32Number len;
+ cmsUInt32Number flag;
+ cmsUInt8Number data[1];
+
+} cmsICCData;
+
+// ICC date time
+typedef struct {
+ cmsUInt16Number year;
+ cmsUInt16Number month;
+ cmsUInt16Number day;
+ cmsUInt16Number hours;
+ cmsUInt16Number minutes;
+ cmsUInt16Number seconds;
+
+} cmsDateTimeNumber;
+
+// ICC XYZ
+typedef struct {
+ cmsS15Fixed16Number X;
+ cmsS15Fixed16Number Y;
+ cmsS15Fixed16Number Z;
+
+} cmsEncodedXYZNumber;
+
+
+// Profile ID as computed by MD5 algorithm
+typedef union {
+ cmsUInt8Number ID8[16];
+ cmsUInt16Number ID16[8];
+ cmsUInt32Number ID32[4];
+
+} cmsProfileID;
+
+
+// ----------------------------------------------------------------------------------------------
+// ICC profile internal base types. Strictly, shouldn't be declared in this header, but maybe
+// somebody want to use this info for accessing profile header directly, so here it is.
+
+// Profile header -- it is 32-bit aligned, so no issues are expected on alignment
+typedef struct {
+ cmsUInt32Number size; // Profile size in bytes
+ cmsSignature cmmId; // CMM for this profile
+ cmsUInt32Number version; // Format version number
+ cmsProfileClassSignature deviceClass; // Type of profile
+ cmsColorSpaceSignature colorSpace; // Color space of data
+ cmsColorSpaceSignature pcs; // PCS, XYZ or Lab only
+ cmsDateTimeNumber date; // Date profile was created
+ cmsSignature magic; // Magic Number to identify an ICC profile
+ cmsPlatformSignature platform; // Primary Platform
+ cmsUInt32Number flags; // Various bit settings
+ cmsSignature manufacturer; // Device manufacturer
+ cmsUInt32Number model; // Device model number
+ cmsUInt64Number attributes; // Device attributes
+ cmsUInt32Number renderingIntent;// Rendering intent
+ cmsEncodedXYZNumber illuminant; // Profile illuminant
+ cmsSignature creator; // Profile creator
+ cmsProfileID profileID; // Profile ID using MD5
+ cmsInt8Number reserved[28]; // Reserved for future use
+
+} cmsICCHeader;
+
+// ICC base tag
+typedef struct {
+ cmsTagTypeSignature sig;
+ cmsInt8Number reserved[4];
+
+} cmsTagBase;
+
+// A tag entry in directory
+typedef struct {
+ cmsTagSignature sig; // The tag signature
+ cmsUInt32Number offset; // Start of tag
+ cmsUInt32Number size; // Size in bytes
+
+} cmsTagEntry;
+
+// ----------------------------------------------------------------------------------------------
+
+// Little CMS specific typedefs
+
+typedef void* cmsContext; // Context identifier for multithreaded environments
+typedef void* cmsHANDLE ; // Generic handle
+typedef void* cmsHPROFILE; // Opaque typedefs to hide internals
+typedef void* cmsHTRANSFORM;
+
+#define cmsMAXCHANNELS 16 // Maximum number of channels in ICC profiles
+
+// Format of pixel is defined by one cmsUInt32Number, using bit fields as follows
+//
+// A O TTTTT U Y F P X S EEE CCCC BBB
+//
+// A: Floating point -- With this flag we can differentiate 16 bits as float and as int
+// O: Optimized -- previous optimization already returns the final 8-bit value
+// T: Pixeltype
+// F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla)
+// P: Planar? 0=Chunky, 1=Planar
+// X: swap 16 bps endianess?
+// S: Do swap? ie, BGR, KYMC
+// E: Extra samples
+// C: Channels (Samples per pixel)
+// B: bytes per sample
+// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK
+
+#define FLOAT_SH(a) ((a) << 22)
+#define OPTIMIZED_SH(s) ((s) << 21)
+#define COLORSPACE_SH(s) ((s) << 16)
+#define SWAPFIRST_SH(s) ((s) << 14)
+#define FLAVOR_SH(s) ((s) << 13)
+#define PLANAR_SH(p) ((p) << 12)
+#define ENDIAN16_SH(e) ((e) << 11)
+#define DOSWAP_SH(e) ((e) << 10)
+#define EXTRA_SH(e) ((e) << 7)
+#define CHANNELS_SH(c) ((c) << 3)
+#define BYTES_SH(b) (b)
+
+// These macros unpack format specifiers into integers
+#define T_FLOAT(a) (((a)>>22)&1)
+#define T_OPTIMIZED(o) (((o)>>21)&1)
+#define T_COLORSPACE(s) (((s)>>16)&31)
+#define T_SWAPFIRST(s) (((s)>>14)&1)
+#define T_FLAVOR(s) (((s)>>13)&1)
+#define T_PLANAR(p) (((p)>>12)&1)
+#define T_ENDIAN16(e) (((e)>>11)&1)
+#define T_DOSWAP(e) (((e)>>10)&1)
+#define T_EXTRA(e) (((e)>>7)&7)
+#define T_CHANNELS(c) (((c)>>3)&15)
+#define T_BYTES(b) ((b)&7)
+
+
+// Pixel types
+#define PT_ANY 0 // Don't check colorspace
+ // 1 & 2 are reserved
+#define PT_GRAY 3
+#define PT_RGB 4
+#define PT_CMY 5
+#define PT_CMYK 6
+#define PT_YCbCr 7
+#define PT_YUV 8 // Lu'v'
+#define PT_XYZ 9
+#define PT_Lab 10
+#define PT_YUVK 11 // Lu'v'K
+#define PT_HSV 12
+#define PT_HLS 13
+#define PT_Yxy 14
+
+#define PT_MCH1 15
+#define PT_MCH2 16
+#define PT_MCH3 17
+#define PT_MCH4 18
+#define PT_MCH5 19
+#define PT_MCH6 20
+#define PT_MCH7 21
+#define PT_MCH8 22
+#define PT_MCH9 23
+#define PT_MCH10 24
+#define PT_MCH11 25
+#define PT_MCH12 26
+#define PT_MCH13 27
+#define PT_MCH14 28
+#define PT_MCH15 29
+
+#define PT_LabV2 30 // Identical to PT_Lab, but using the V2 old encoding
+
+// Some (not all!) representations
+
+#ifndef TYPE_RGB_8 // TYPE_RGB_8 is a very common identifier, so don't include ours
+ // if user has it already defined.
+
+#define TYPE_GRAY_8 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1))
+#define TYPE_GRAY_8_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1))
+#define TYPE_GRAY_16 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2))
+#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1))
+#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1))
+#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2))
+#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1))
+
+#define TYPE_RGB_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_RGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_BGR_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_BGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1))
+#define TYPE_RGB_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_RGB_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_RGB_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_BGR_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_BGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
+#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+
+#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
+
+#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
+#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+
+#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1))
+
+#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_CMY_8_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_CMY_16 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_CMY_16_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_CMY_16_SE (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+#define TYPE_CMYK_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1))
+#define TYPE_CMYKA_8 (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(1))
+#define TYPE_CMYK_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1))
+#define TYPE_YUVK_8 TYPE_CMYK_8_REV
+#define TYPE_CMYK_8_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_CMYK_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2))
+#define TYPE_CMYK_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1))
+#define TYPE_YUVK_16 TYPE_CMYK_16_REV
+#define TYPE_CMYK_16_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_CMYK_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+#define TYPE_KYMC_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+
+#define TYPE_KCMY_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_KCMY_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_KCMY_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1))
+#define TYPE_KCMY_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_KCMY_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1))
+
+#define TYPE_CMYK5_8 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(1))
+#define TYPE_CMYK5_16 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2))
+#define TYPE_CMYK5_16_SE (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC5_8 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC5_16 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC5_16_SE (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+#define TYPE_CMYK6_8 (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(1))
+#define TYPE_CMYK6_8_PLANAR (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_CMYK6_16 (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2))
+#define TYPE_CMYK6_16_PLANAR (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_CMYK6_16_SE (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_CMYK7_8 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(1))
+#define TYPE_CMYK7_16 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2))
+#define TYPE_CMYK7_16_SE (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC7_8 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC7_16 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC7_16_SE (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+#define TYPE_CMYK8_8 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(1))
+#define TYPE_CMYK8_16 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2))
+#define TYPE_CMYK8_16_SE (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC8_8 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC8_16 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC8_16_SE (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+#define TYPE_CMYK9_8 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(1))
+#define TYPE_CMYK9_16 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2))
+#define TYPE_CMYK9_16_SE (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC9_8 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC9_16 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC9_16_SE (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+#define TYPE_CMYK10_8 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(1))
+#define TYPE_CMYK10_16 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2))
+#define TYPE_CMYK10_16_SE (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC10_8 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC10_16 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC10_16_SE (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+#define TYPE_CMYK11_8 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(1))
+#define TYPE_CMYK11_16 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2))
+#define TYPE_CMYK11_16_SE (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC11_8 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC11_16 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC11_16_SE (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+#define TYPE_CMYK12_8 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(1))
+#define TYPE_CMYK12_16 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2))
+#define TYPE_CMYK12_16_SE (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|ENDIAN16_SH(1))
+#define TYPE_KYMC12_8 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_KYMC12_16 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_KYMC12_16_SE (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
+
+// Colorimetric
+#define TYPE_XYZ_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_Lab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_LabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1))
+
+#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1))
+#define TYPE_ALabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1))
+#define TYPE_Lab_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_LabV2_16 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_Yxy_16 (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2))
+
+// YCbCr
+#define TYPE_YCbCr_8 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_YCbCr_8_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_YCbCr_16 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_YCbCr_16_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_YCbCr_16_SE (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+// YUV
+#define TYPE_YUV_8 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_YUV_8_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_YUV_16 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_YUV_16_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_YUV_16_SE (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+// HLS
+#define TYPE_HLS_8 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_HLS_8_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_HLS_16 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_HLS_16_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_HLS_16_SE (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+// HSV
+#define TYPE_HSV_8 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_HSV_8_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
+#define TYPE_HSV_16 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
+#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
+
+// Named color index. Only 16 bits allowed (don't check colorspace)
+#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2))
+
+// Float formatters.
+#define TYPE_XYZ_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4))
+#define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4))
+#define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4))
+#define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4))
+#define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4))
+
+// Floating point formatters.
+// NOTE THAT 'BYTES' FIELD IS SET TO ZERO ON DLB because 8 bytes overflows the bitfield
+#define TYPE_XYZ_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(0))
+#define TYPE_Lab_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0))
+#define TYPE_GRAY_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0))
+#define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
+#define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0))
+
+#endif
+
+// Colorspaces
+typedef struct {
+ cmsFloat64Number X;
+ cmsFloat64Number Y;
+ cmsFloat64Number Z;
+
+ } cmsCIEXYZ;
+
+typedef struct {
+ cmsFloat64Number x;
+ cmsFloat64Number y;
+ cmsFloat64Number Y;
+
+ } cmsCIExyY;
+
+typedef struct {
+ cmsFloat64Number L;
+ cmsFloat64Number a;
+ cmsFloat64Number b;
+
+ } cmsCIELab;
+
+typedef struct {
+ cmsFloat64Number L;
+ cmsFloat64Number C;
+ cmsFloat64Number h;
+
+ } cmsCIELCh;
+
+typedef struct {
+ cmsFloat64Number J;
+ cmsFloat64Number C;
+ cmsFloat64Number h;
+
+ } cmsJCh;
+
+typedef struct {
+ cmsCIEXYZ Red;
+ cmsCIEXYZ Green;
+ cmsCIEXYZ Blue;
+
+ } cmsCIEXYZTRIPLE;
+
+typedef struct {
+ cmsCIExyY Red;
+ cmsCIExyY Green;
+ cmsCIExyY Blue;
+
+ } cmsCIExyYTRIPLE;
+
+// Illuminant types for structs below
+#define cmsILLUMINANT_TYPE_UNKNOWN 0x0000000
+#define cmsILLUMINANT_TYPE_D50 0x0000001
+#define cmsILLUMINANT_TYPE_D65 0x0000002
+#define cmsILLUMINANT_TYPE_D93 0x0000003
+#define cmsILLUMINANT_TYPE_F2 0x0000004
+#define cmsILLUMINANT_TYPE_D55 0x0000005
+#define cmsILLUMINANT_TYPE_A 0x0000006
+#define cmsILLUMINANT_TYPE_E 0x0000007
+#define cmsILLUMINANT_TYPE_F8 0x0000008
+
+typedef struct {
+ cmsUInt32Number Observer; // 0 = unknown, 1=CIE 1931, 2=CIE 1964
+ cmsCIEXYZ Backing; // Value of backing
+ cmsUInt32Number Geometry; // 0=unknown, 1=45/0, 0/45 2=0d, d/0
+ cmsFloat64Number Flare; // 0..1.0
+ cmsUInt32Number IlluminantType;
+
+ } cmsICCMeasurementConditions;
+
+typedef struct {
+ cmsCIEXYZ IlluminantXYZ; // Not the same struct as CAM02,
+ cmsCIEXYZ SurroundXYZ; // This is for storing the tag
+ cmsUInt32Number IlluminantType; // viewing condition
+
+ } cmsICCViewingConditions;
+
+// Support of non-standard functions --------------------------------------------------------------------------------------
+
+CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2);
+CMSAPI long int CMSEXPORT cmsfilelength(FILE* f);
+
+// Plug-In registering ---------------------------------------------------------------------------------------------------
+
+CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin);
+CMSAPI void CMSEXPORT cmsUnregisterPlugins(void);
+
+// Error logging ----------------------------------------------------------------------------------------------------------
+
+// There is no error handling at all. When a function fails, it returns proper value.
+// For example, all create functions does return NULL on failure. Other may return FALSE.
+// It may be interesting, for the developer, to know why the function is failing.
+// for that reason, lcms2 does offer a logging function. This function will get
+// an ENGLISH string with some clues on what is going wrong. You can show this
+// info to the end user if you wish, or just create some sort of log on disk.
+// The logging function should NOT terminate the program, as this obviously can leave
+// unfreed resources. It is the programmer's responsibility to check each function
+// return code to make sure it didn't fail.
+
+#define cmsERROR_UNDEFINED 0
+#define cmsERROR_FILE 1
+#define cmsERROR_RANGE 2
+#define cmsERROR_INTERNAL 3
+#define cmsERROR_NULL 4
+#define cmsERROR_READ 5
+#define cmsERROR_SEEK 6
+#define cmsERROR_WRITE 7
+#define cmsERROR_UNKNOWN_EXTENSION 8
+#define cmsERROR_COLORSPACE_CHECK 9
+#define cmsERROR_ALREADY_DEFINED 10
+#define cmsERROR_BAD_SIGNATURE 11
+#define cmsERROR_CORRUPTION_DETECTED 12
+#define cmsERROR_NOT_SUITABLE 13
+
+// Error logger is called with the ContextID when a message is raised. This gives the
+// chance to know which thread is responsible of the warning and any environment associated
+// with it. Non-multithreading applications may safely ignore this parameter.
+// Note that under certain special circumstances, ContextID may be NULL.
+typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
+
+// Allows user to set any specific logger
+CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn);
+
+// Conversions --------------------------------------------------------------------------------------------------------------
+
+// Returns pointers to constant structs
+CMSAPI const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void);
+CMSAPI const cmsCIExyY* CMSEXPORT cmsD50_xyY(void);
+
+// Colorimetric space conversions
+CMSAPI void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source);
+CMSAPI void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source);
+CMSAPI void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz);
+CMSAPI void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab);
+CMSAPI void CMSEXPORT cmsLab2LCh(cmsCIELCh*LCh, const cmsCIELab* Lab);
+CMSAPI void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh);
+
+// Encoding /Decoding on PCS
+CMSAPI void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]);
+CMSAPI void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]);
+CMSAPI void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* Lab);
+CMSAPI void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* Lab);
+CMSAPI void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fxyz, const cmsUInt16Number XYZ[3]);
+CMSAPI void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ);
+
+// DeltaE metrics
+CMSAPI cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2);
+CMSAPI cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2);
+CMSAPI cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2);
+CMSAPI cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c);
+CMSAPI cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh);
+
+// Temperature <-> Chromaticity (Black body)
+CMSAPI cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK);
+CMSAPI cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint);
+
+// Chromatic adaptation
+CMSAPI cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, const cmsCIEXYZ* SourceWhitePt,
+ const cmsCIEXYZ* Illuminant,
+ const cmsCIEXYZ* Value);
+
+// CIECAM02 ---------------------------------------------------------------------------------------------------
+
+// Viewing conditions. Please note those are CAM model viewing conditions, and not the ICC tag viewing
+// conditions, which I'm naming cmsICCViewingConditions to make differences evident. Unfortunately, the tag
+// cannot deal with surround La, Yb and D value so is basically useless to store CAM02 viewing conditions.
+
+
+#define AVG_SURROUND 1
+#define DIM_SURROUND 2
+#define DARK_SURROUND 3
+#define CUTSHEET_SURROUND 4
+
+#define D_CALCULATE (-1)
+
+typedef struct {
+ cmsCIEXYZ whitePoint;
+ cmsFloat64Number Yb;
+ cmsFloat64Number La;
+ int surround;
+ cmsFloat64Number D_value;
+
+ } cmsViewingConditions;
+
+CMSAPI cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC);
+CMSAPI void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel);
+CMSAPI void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut);
+CMSAPI void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut);
+
+
+// Tone curves -----------------------------------------------------------------------------------------
+
+// This describes a curve segment. For a table of supported types, see the manual. User can increase the number of
+// available types by using a proper plug-in. Parametric segments allow 10 parameters at most
+
+typedef struct {
+ cmsFloat32Number x0, x1; // Domain; for x0 < x <= x1
+ cmsInt32Number Type; // Parametric type, Type == 0 means sampled segment. Negative values are reserved
+ cmsFloat64Number Params[10]; // Parameters if Type != 0
+ cmsUInt32Number nGridPoints; // Number of grid points if Type == 0
+ cmsFloat32Number* SampledPoints; // Points to an array of floats if Type == 0
+
+} cmsCurveSegment;
+
+// The internal representation is none of your business.
+typedef struct _cms_curve_struct cmsToneCurve;
+
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, cmsInt32Number nSegments, const cmsCurveSegment Segments[]);
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]);
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma);
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number values[]);
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]);
+CMSAPI void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve);
+CMSAPI void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]);
+CMSAPI cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* Src);
+CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma);
+CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InGamma);
+CMSAPI cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, const cmsToneCurve* X, const cmsToneCurve* Y, cmsUInt32Number nPoints);
+CMSAPI cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda);
+CMSAPI cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v);
+CMSAPI cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v);
+CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* InGamma);
+CMSAPI cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve);
+CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t);
+CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t);
+CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t);
+CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision);
+
+
+// Implements pipelines of multi-processing elements -------------------------------------------------------------
+
+// Nothing to see here, move along
+typedef struct _cmsPipeline_struct cmsPipeline;
+typedef struct _cmsStage_struct cmsStage;
+
+// Those are hi-level pipelines
+CMSAPI cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels);
+CMSAPI void CMSEXPORT cmsPipelineFree(cmsPipeline* lut);
+CMSAPI cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* Orig);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut);
+CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut);
+CMSAPI cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut);
+CMSAPI cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut);
+
+CMSAPI void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut);
+CMSAPI void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut);
+CMSAPI cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], cmsFloat32Number Result[], cmsFloat32Number Hint[], const cmsPipeline* lut);
+CMSAPI cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2);
+CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On);
+
+// Where to place/locate the stages in the pipeline chain
+typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc;
+
+CMSAPI void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe);
+CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe);
+
+// This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements
+// that conform the Pipeline. It should be called with the Pipeline, the number of expected elements and
+// then a list of expected types followed with a list of double pointers to Stage elements. If
+// the function founds a match with current pipeline, it fills the pointers and returns TRUE
+// if not, returns FALSE without touching anything.
+CMSAPI cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...);
+
+// Matrix has double precision and CLUT has only float precision. That is because an ICC profile can encode
+// matrices with far more precision that CLUTS
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels);
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]);
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset);
+
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, cmsUInt32Number nGridPoints, cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsUInt16Number* Table);
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, cmsUInt32Number nGridPoints, cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table);
+
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsUInt16Number* Table);
+CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table);
+
+CMSAPI cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe);
+CMSAPI void CMSEXPORT cmsStageFree(cmsStage* mpe);
+CMSAPI cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe);
+CMSAPI cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe);
+CMSAPI cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe);
+CMSAPI void* CMSEXPORT cmsStageData(const cmsStage* mpe);
+
+// Sampling
+typedef cmsInt32Number (* cmsSAMPLER16) (register const cmsUInt16Number In[],
+ register cmsUInt16Number Out[],
+ register void * Cargo);
+
+typedef cmsInt32Number (* cmsSAMPLERFLOAT)(register const cmsFloat32Number In[],
+ register cmsFloat32Number Out[],
+ register void * Cargo);
+
+// Use this flag to prevent changes being written to destination
+#define SAMPLER_INSPECT 0x01000000
+
+// For CLUT only
+CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags);
+CMSAPI cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags);
+
+
+// Slicers
+CMSAPI cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
+ cmsSAMPLER16 Sampler, void * Cargo);
+
+CMSAPI cmsBool CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
+ cmsSAMPLERFLOAT Sampler, void * Cargo);
+
+// Multilocalized Unicode management ---------------------------------------------------------------------------------------
+
+typedef struct _cms_MLU_struct cmsMLU;
+
+#define cmsNoLanguage "\0\0"
+#define cmsNoCountry "\0\0"
+
+CMSAPI cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems);
+CMSAPI void CMSEXPORT cmsMLUfree(cmsMLU* mlu);
+CMSAPI cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu);
+
+CMSAPI cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ const char* ASCIIString);
+CMSAPI cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ const wchar_t* WideString);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ char* Buffer, cmsUInt32Number BufferSize);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ wchar_t* Buffer, cmsUInt32Number BufferSize);
+
+CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ char ObtainedLanguage[3], char ObtainedCountry[3]);
+
+// Undercolorremoval & black generation -------------------------------------------------------------------------------------
+
+typedef struct {
+ cmsToneCurve* Ucr;
+ cmsToneCurve* Bg;
+ cmsMLU* Desc;
+
+} cmsUcrBg;
+
+// Screening ----------------------------------------------------------------------------------------------------------------
+
+#define cmsPRINTER_DEFAULT_SCREENS 0x0001
+#define cmsFREQUENCE_UNITS_LINES_CM 0x0000
+#define cmsFREQUENCE_UNITS_LINES_INCH 0x0002
+
+#define cmsSPOT_UNKNOWN 0
+#define cmsSPOT_PRINTER_DEFAULT 1
+#define cmsSPOT_ROUND 2
+#define cmsSPOT_DIAMOND 3
+#define cmsSPOT_ELLIPSE 4
+#define cmsSPOT_LINE 5
+#define cmsSPOT_SQUARE 6
+#define cmsSPOT_CROSS 7
+
+typedef struct {
+ cmsFloat64Number Frequency;
+ cmsFloat64Number ScreenAngle;
+ cmsUInt32Number SpotShape;
+
+} cmsScreeningChannel;
+
+typedef struct {
+ cmsUInt32Number Flag;
+ cmsUInt32Number nChannels;
+ cmsScreeningChannel Channels[cmsMAXCHANNELS];
+
+} cmsScreening;
+
+
+// Named color -----------------------------------------------------------------------------------------------------------------
+
+typedef struct _cms_NAMEDCOLORLIST_struct cmsNAMEDCOLORLIST;
+
+CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID,
+ cmsUInt32Number n,
+ cmsUInt32Number ColorantCount,
+ const char* Prefix, const char* Suffix);
+
+CMSAPI void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v);
+CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v);
+CMSAPI cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* v, const char* Name,
+ cmsUInt16Number PCS[3],
+ cmsUInt16Number Colorant[cmsMAXCHANNELS]);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* v);
+CMSAPI cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* v, const char* Name);
+
+CMSAPI cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
+ char* Name,
+ char* Prefix,
+ char* Suffix,
+ cmsUInt16Number* PCS,
+ cmsUInt16Number* Colorant);
+
+// Retrieve named color list from transform
+CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform);
+
+// Profile sequence -----------------------------------------------------------------------------------------------------
+
+// Profile sequence descriptor. Some fields come from profile sequence descriptor tag, others
+// come from Profile Sequence Identifier Tag
+typedef struct {
+ cmsSignature deviceMfg;
+ cmsSignature deviceModel;
+ cmsUInt64Number attributes;
+ cmsTechnologySignature technology;
+ cmsProfileID ProfileID;
+ cmsMLU* Manufacturer;
+ cmsMLU* Model;
+ cmsMLU* Description;
+
+} cmsPSEQDESC;
+
+typedef struct {
+
+ cmsUInt32Number n;
+ cmsContext ContextID;
+ cmsPSEQDESC* seq;
+
+} cmsSEQ;
+
+CMSAPI cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n);
+CMSAPI cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq);
+CMSAPI void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq);
+
+// Access to Profile data ----------------------------------------------------------------------------------------------
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID);
+
+CMSAPI cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile);
+CMSAPI cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile);
+CMSAPI cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n);
+CMSAPI cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig);
+
+// Read and write pre-formatted data
+CMSAPI void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig);
+CMSAPI cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data);
+CMSAPI cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest);
+
+// Read and write raw data
+CMSAPI cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize);
+CMSAPI cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size);
+
+// Access header data
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags);
+CMSAPI void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID);
+CMSAPI cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest);
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile);
+
+CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags);
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer);
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model);
+CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags);
+CMSAPI void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID);
+CMSAPI void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent);
+
+CMSAPI cmsColorSpaceSignature
+ CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs);
+CMSAPI cmsColorSpaceSignature
+ CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig);
+CMSAPI cmsProfileClassSignature
+ CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig);
+CMSAPI void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version);
+CMSAPI cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile);
+CMSAPI void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version);
+
+// How profiles may be used
+#define LCMS_USED_AS_INPUT 0
+#define LCMS_USED_AS_OUTPUT 1
+#define LCMS_USED_AS_PROOF 2
+
+CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection);
+CMSAPI cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile);
+CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection);
+
+// Translate form/to our notation to ICC
+CMSAPI cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation);
+CMSAPI int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace);
+
+// Build a suitable formatter for the colorspace of this profile
+CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat);
+CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat);
+
+
+// Localized info
+typedef enum {
+ cmsInfoDescription = 0,
+ cmsInfoManufacturer = 1,
+ cmsInfoModel = 2,
+ cmsInfoCopyright = 3
+} cmsInfoType;
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info,
+ const char LanguageCode[3], const char CountryCode[3],
+ wchar_t* Buffer, cmsUInt32Number BufferSize);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info,
+ const char LanguageCode[3], const char CountryCode[3],
+ char* Buffer, cmsUInt32Number BufferSize);
+
+// IO handlers ----------------------------------------------------------------------------------------------------------
+
+typedef struct _cms_io_handler cmsIOHANDLER;
+
+CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode);
+CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream);
+CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode);
+CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID);
+CMSAPI cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io);
+
+// MD5 message digest --------------------------------------------------------------------------------------------------
+
+CMSAPI cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile);
+
+// Profile high level funtions ------------------------------------------------------------------------------------------
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *ICCProfile, const char *sAccess);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char* sAccess);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char* sAccess);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io);
+CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile);
+
+CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName);
+CMSAPI cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream);
+CMSAPI cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded);
+CMSAPI cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io);
+
+// Predefined virtual profiles ------------------------------------------------------------------------------------------
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID,
+ const cmsCIExyY* WhitePoint,
+ const cmsCIExyYTRIPLE* Primaries,
+ cmsToneCurve* const TransferFunction[3]);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint,
+ const cmsCIExyYTRIPLE* Primaries,
+ cmsToneCurve* const TransferFunction[3]);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID,
+ const cmsCIExyY* WhitePoint,
+ const cmsToneCurve* TransferFunction);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint,
+ const cmsToneCurve* TransferFunction);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
+ cmsColorSpaceSignature ColorSpace,
+ cmsToneCurve* const TransferFunctions[]);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace,
+ cmsToneCurve* const TransferFunctions[]);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
+ cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit);
+
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint);
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint);
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint);
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID);
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID);
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
+ int nLUTPoints,
+ cmsFloat64Number Bright,
+ cmsFloat64Number Contrast,
+ cmsFloat64Number Hue,
+ cmsFloat64Number Saturation,
+ int TempSrc,
+ int TempDest);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
+ cmsFloat64Number Bright,
+ cmsFloat64Number Contrast,
+ cmsFloat64Number Hue,
+ cmsFloat64Number Saturation,
+ int TempSrc,
+ int TempDest);
+
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID);
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void);
+
+// Converts a transform to a devicelink profile
+CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags);
+
+// Intents ----------------------------------------------------------------------------------------------
+
+// ICC Intents
+#define INTENT_PERCEPTUAL 0
+#define INTENT_RELATIVE_COLORIMETRIC 1
+#define INTENT_SATURATION 2
+#define INTENT_ABSOLUTE_COLORIMETRIC 3
+
+// Non-ICC intents
+#define INTENT_PRESERVE_K_ONLY_PERCEPTUAL 10
+#define INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC 11
+#define INTENT_PRESERVE_K_ONLY_SATURATION 12
+#define INTENT_PRESERVE_K_PLANE_PERCEPTUAL 13
+#define INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC 14
+#define INTENT_PRESERVE_K_PLANE_SATURATION 15
+
+// Call with NULL as parameters to get the intent count
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions);
+
+// Flags
+
+#define cmsFLAGS_NOCACHE 0x0040 // Inhibit 1-pixel cache
+#define cmsFLAGS_NOOPTIMIZE 0x0100 // Inhibit optimizations
+#define cmsFLAGS_NULLTRANSFORM 0x0200 // Don't transform anyway
+
+
+// Proofing flags
+#define cmsFLAGS_GAMUTCHECK 0x1000 // Out of Gamut alarm
+#define cmsFLAGS_SOFTPROOFING 0x4000 // Do softproofing
+
+// Misc
+#define cmsFLAGS_BLACKPOINTCOMPENSATION 0x2000
+#define cmsFLAGS_NOWHITEONWHITEFIXUP 0x0004 // Don't fix scum dot
+#define cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better accurancy
+#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resouces
+
+// For devicelink creation
+#define cmsFLAGS_8BITS_DEVICELINK 0x0008 // Create 8 bits devicelinks
+#define cmsFLAGS_GUESSDEVICECLASS 0x0020 // Guess device class (for transform2devicelink)
+#define cmsFLAGS_KEEP_SEQUENCE 0x0080 // Keep profile sequence for devicelink creation
+
+// Specific to a particular optimizations
+#define cmsFLAGS_FORCE_CLUT 0x0002 // Force CLUT optimization
+#define cmsFLAGS_CLUT_POST_LINEARIZATION 0x0001 // create postlinearization tables if possible
+#define cmsFLAGS_CLUT_PRE_LINEARIZATION 0x0010 // create prelinearization tables if possible
+
+// Fine-tune control over number of gridpoints
+#define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16)
+
+// CRD special
+#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x01000000
+
+// Transforms ---------------------------------------------------------------------------------------------------
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
+ cmsHPROFILE Input,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE Output,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags);
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE Output,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags);
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
+ cmsHPROFILE Input,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE Output,
+ cmsUInt32Number OutputFormat,
+ cmsHPROFILE Proofing,
+ cmsUInt32Number Intent,
+ cmsUInt32Number ProofingIntent,
+ cmsUInt32Number dwFlags);
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE Input,
+ cmsUInt32Number InputFormat,
+ cmsHPROFILE Output,
+ cmsUInt32Number OutputFormat,
+ cmsHPROFILE Proofing,
+ cmsUInt32Number Intent,
+ cmsUInt32Number ProofingIntent,
+ cmsUInt32Number dwFlags);
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
+ cmsHPROFILE hProfiles[],
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags);
+
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags);
+
+
+CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
+ cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsUInt32Number Intents[],
+ cmsFloat64Number AdaptationStates[],
+ cmsHPROFILE hGamutProfile,
+ cmsUInt32Number nGamutPCSposition,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ cmsUInt32Number dwFlags);
+
+CMSAPI void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform);
+
+CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
+ const void * InputBuffer,
+ void * OutputBuffer,
+ cmsUInt32Number Size);
+
+CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
+CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
+
+// Adaptation state for absolute colorimetric intent
+CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d);
+
+CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform);
+
+
+// PostScript ColorRenderingDictionary and ColorSpaceArray ----------------------------------------------------
+
+typedef enum { cmsPS_RESOURCE_CSA, cmsPS_RESOURCE_CRD } cmsPSResourceType;
+
+// lcms2 unified method to access postscript color resources
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID,
+ cmsPSResourceType Type,
+ cmsHPROFILE hProfile,
+ cmsUInt32Number Intent,
+ cmsUInt32Number dwFlags,
+ cmsIOHANDLER* io);
+
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen);
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen);
+
+
+// IT8.7 / CGATS.17-200x handling -----------------------------------------------------------------------------
+
+CMSAPI cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID);
+CMSAPI void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8);
+
+// Tables
+CMSAPI cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8);
+CMSAPI cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE hIT8, cmsUInt32Number nTable);
+
+// Persistence
+CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName);
+CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len);
+// CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromIOhandler(cmsContext ContextID, cmsIOHANDLER* io);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName);
+CMSAPI cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded);
+
+// Properties
+CMSAPI const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8);
+CMSAPI cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* cComment);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* cProp, const char *Str);
+CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val);
+CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val);
+CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer);
+
+
+CMSAPI const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* cProp);
+CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp);
+CMSAPI cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames);
+
+// Datasets
+CMSAPI const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col);
+CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col,
+ const char* Val);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col,
+ cmsFloat64Number Val);
+
+CMSAPI const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample);
+
+
+CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE hIT8, const char* cPatch, const char* cSample);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch,
+ const char* cSample,
+ const char *Val);
+
+CMSAPI cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch,
+ const char* cSample,
+ cmsFloat64Number Val);
+
+CMSAPI int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample);
+CMSAPI cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE hIT8, int n, const char *Sample);
+CMSAPI int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames);
+
+CMSAPI const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer);
+
+// The LABEL extension
+CMSAPI int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType);
+
+// Formatter for double
+CMSAPI void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter);
+
+// Gamut boundary description routines ------------------------------------------------------------------------------
+
+CMSAPI cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID);
+CMSAPI void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD);
+CMSAPI cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab);
+CMSAPI cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGDB, cmsUInt32Number dwFlags);
+CMSAPI cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab);
+
+// Feature detection ----------------------------------------------------------------------------------------------
+
+// Estimate the black point
+CMSAPI cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags);
+
+// Estimate total area coverage
+CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile);
+
+
+// Poor man's gamut mapping
+CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
+ double amax, double amin,
+ double bmax, double bmin);
+
+#ifndef CMS_USE_CPP_API
+# ifdef __cplusplus
+ }
+# endif
+#endif
+
+#define _lcms2_H
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,678 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#ifndef _lcms_internal_H
+
+// Include plug-in foundation
+#ifndef _lcms_plugin_H
+# include "lcms2_plugin.h"
+#endif
+
+// ctype is part of C99 as per 7.1.2
+#include <ctype.h>
+
+// assert macro is part of C99 as per 7.2
+#include <assert.h>
+
+// Some needed constants
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_LOG10E
+# define M_LOG10E 0.434294481903251827651
+#endif
+
+// BorlandC 5.5 is broken on that
+#ifdef __BORLANDC__
+#define sinf(x) (float)sin((float)x)
+#define sqrtf(x) (float)sqrt((float)x)
+#endif
+
+
+// Alignment of ICC file format uses 4 bytes (cmsUInt32Number)
+#define _cmsSIZEOFLONGMINUS1 (sizeof(cmsUInt32Number)-1)
+#define _cmsALIGNLONG(x) (((x)+_cmsSIZEOFLONGMINUS1) & ~(_cmsSIZEOFLONGMINUS1))
+
+// Maximum encodeable values in floating point
+#define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0)
+#define MIN_ENCODEABLE_ab2 (-128.0)
+#define MAX_ENCODEABLE_ab2 ((65535.0/256.0) - 128.0)
+#define MIN_ENCODEABLE_ab4 (-128.0)
+#define MAX_ENCODEABLE_ab4 (127.0)
+
+// Maximum of channels for internal pipeline evaluation
+#define MAX_STAGE_CHANNELS 128
+
+// Unused parameter warning supression
+#define cmsUNUSED_PARAMETER(x) ((void)x)
+
+// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999).
+// unfortunately VisualC++ does not conform that
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+# define cmsINLINE __inline
+#else
+# define cmsINLINE static inline
+#endif
+
+// Other replacement functions
+#ifdef _MSC_VER
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+# ifndef vsnprintf
+# define vsnprintf _vsnprintf
+# endif
+#endif
+
+// Pthreads. In windows we use the native WIN32 API instead
+#ifdef CMS_DONT_USE_PTHREADS
+typedef int LCMS_RWLOCK_T;
+# define LCMS_CREATE_LOCK(x)
+# define LCMS_FREE_LOCK(x)
+# define LCMS_READ_LOCK(x)
+# define LCMS_WRITE_LOCK(x)
+# define LCMS_UNLOCK(x)
+#else
+#ifdef CMS_IS_WINDOWS_
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+ typedef CRITICAL_SECTION LCMS_RWLOCK_T;
+# define LCMS_CREATE_LOCK(x) InitializeCriticalSection((x))
+# define LCMS_FREE_LOCK(x) DeleteCriticalSection((x))
+# define LCMS_READ_LOCK(x) EnterCriticalSection((x))
+# define LCMS_WRITE_LOCK(x) EnterCriticalSection((x))
+# define LCMS_UNLOCK(x) LeaveCriticalSection((x))
+#else
+# include <pthread.h>
+ typedef pthread_rwlock_t LCMS_RWLOCK_T;
+# define LCMS_CREATE_LOCK(x) pthread_rwlock_init((x), NULL)
+# define LCMS_FREE_LOCK(x) pthread_rwlock_destroy((x))
+# define LCMS_READ_LOCK(x) pthread_rwlock_rdlock((x))
+# define LCMS_WRITE_LOCK(x) pthread_rwlock_wrlock((x))
+# define LCMS_UNLOCK(x) pthread_rwlock_unlock((x))
+#endif
+#endif
+
+// A fast way to convert from/to 16 <-> 8 bits
+#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb))
+#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF)
+
+// Code analysis is broken on asserts
+#ifdef _MSC_VER
+# if (_MSC_VER >= 1500)
+# define _cmsAssert(a) { assert((a)); __analysis_assume((a)); }
+# else
+# define _cmsAssert(a) assert((a))
+# endif
+#else
+# define _cmsAssert(a) assert((a))
+#endif
+
+//---------------------------------------------------------------------------------
+
+// Determinant lower than that are assumed zero (used on matrix invert)
+#define MATRIX_DET_TOLERANCE 0.0001
+
+//---------------------------------------------------------------------------------
+
+// Fixed point
+#define FIXED_TO_INT(x) ((x)>>16)
+#define FIXED_REST_TO_INT(x) ((x)&0xFFFFU)
+#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16)
+
+cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); }
+cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); }
+
+// -----------------------------------------------------------------------------------------------------------
+
+// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon
+// note than this only works in the range ..-32767...+32767 because
+// mantissa is interpreted as 15.16 fixed point.
+// The union is to avoid pointer aliasing overoptimization.
+cmsINLINE int _cmsQuickFloor(cmsFloat64Number val)
+{
+#ifdef CMS_DONT_USE_FAST_FLOOR
+ return (int) floor(val);
+#else
+ const cmsFloat64Number _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor
+ union {
+ cmsFloat64Number val;
+ int halves[2];
+ } temp;
+
+ temp.val = val + _lcms_double2fixmagic;
+
+#ifdef CMS_USE_BIG_ENDIAN
+ return temp.halves[1] >> 16;
+#else
+ return temp.halves[0] >> 16;
+#endif
+#endif
+}
+
+// Fast floor restricted to 0..65535.0
+cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d)
+{
+ return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U;
+}
+
+// Floor to word, taking care of saturation
+cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
+{
+ d += 0.5;
+ if (d <= 0) return 0;
+ if (d >= 65535.0) return 0xffff;
+
+ return _cmsQuickFloorWord(d);
+}
+
+// Plug-In registering ---------------------------------------------------------------
+
+// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once.
+void* _cmsPluginMalloc(cmsUInt32Number size);
+
+// Memory management
+cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
+
+// Interpolation
+cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin);
+
+// Parametric curves
+cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Plugin);
+
+// Formatters management
+cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Plugin);
+
+// Tag type management
+cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Plugin);
+
+// Tag management
+cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Plugin);
+
+// Intent management
+cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Plugin);
+
+// Multi Process elements
+cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin);
+
+// Optimization
+cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin);
+
+
+// ---------------------------------------------------------------------------------------------------------
+
+// Suballocators. Those are blocks of memory that is freed at the end on whole block.
+typedef struct _cmsSubAllocator_chunk_st {
+
+ cmsUInt8Number* Block;
+ cmsUInt32Number BlockSize;
+ cmsUInt32Number Used;
+
+ struct _cmsSubAllocator_chunk_st* next;
+
+} _cmsSubAllocator_chunk;
+
+
+typedef struct {
+
+ cmsContext ContextID;
+ _cmsSubAllocator_chunk* h;
+
+} _cmsSubAllocator;
+
+
+_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial);
+void _cmsSubAllocDestroy(_cmsSubAllocator* s);
+void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size);
+
+// ----------------------------------------------------------------------------------
+
+// MLU internal representation
+typedef struct {
+
+ cmsUInt16Number Language;
+ cmsUInt16Number Country;
+
+ cmsUInt32Number StrW; // Offset to current unicode string
+ cmsUInt32Number Len; // Lenght in bytes
+
+} _cmsMLUentry;
+
+struct _cms_MLU_struct {
+
+ cmsContext ContextID;
+
+ // The directory
+ int AllocatedEntries;
+ int UsedEntries;
+ _cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool
+
+ // The Pool
+ cmsUInt32Number PoolSize; // The maximum allocated size
+ cmsUInt32Number PoolUsed; // The used size
+ void* MemPool; // Pointer to begin of memory pool
+};
+
+// Named color list internal representation
+typedef struct {
+
+ char Name[cmsMAX_PATH];
+ cmsUInt16Number PCS[3];
+ cmsUInt16Number DeviceColorant[cmsMAXCHANNELS];
+
+} _cmsNAMEDCOLOR;
+
+struct _cms_NAMEDCOLORLIST_struct {
+
+ cmsUInt32Number nColors;
+ cmsUInt32Number Allocated;
+ cmsUInt32Number ColorantCount;
+
+ char Prefix[33]; // Prefix and suffix are defined to be 32 characters at most
+ char Suffix[33];
+
+ _cmsNAMEDCOLOR* List;
+
+ cmsContext ContextID;
+};
+
+
+// ----------------------------------------------------------------------------------
+
+// This is the internal struct holding profile details.
+
+// Maximum supported tags in a profile
+#define MAX_TABLE_TAG 100
+
+typedef struct _cms_iccprofile_struct {
+
+ // I/O handler
+ cmsIOHANDLER* IOhandler;
+
+ // The thread ID
+ cmsContext ContextID;
+
+ // Creation time
+ struct tm Created;
+
+ // Only most important items found in ICC profiles
+ cmsUInt32Number Version;
+ cmsProfileClassSignature DeviceClass;
+ cmsColorSpaceSignature ColorSpace;
+ cmsColorSpaceSignature PCS;
+ cmsUInt32Number RenderingIntent;
+ cmsUInt32Number flags;
+ cmsUInt32Number manufacturer, model;
+ cmsUInt64Number attributes;
+
+ cmsProfileID ProfileID;
+
+ // Dictionary
+ cmsUInt32Number TagCount;
+ cmsTagSignature TagNames[MAX_TABLE_TAG];
+ cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to wich is linked (0=none)
+ cmsUInt32Number TagSizes[MAX_TABLE_TAG]; // Size on disk
+ cmsUInt32Number TagOffsets[MAX_TABLE_TAG];
+ cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked
+ void * TagPtrs[MAX_TABLE_TAG];
+ cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types
+ // depending on profile version, so we keep track of the // type handler for each tag in the list.
+ // Special
+ cmsBool IsWrite;
+
+} _cmsICCPROFILE;
+
+// IO helpers for profiles
+cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc);
+cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace);
+int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks);
+
+// Tag types
+cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig);
+cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig);
+cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig);
+
+// Error logging ---------------------------------------------------------------------------------------------------------
+
+void _cmsTagSignature2String(char String[5], cmsTagSignature sig);
+
+// Interpolation ---------------------------------------------------------------------------------------------------------
+
+cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
+cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
+void _cmsFreeInterpParams(cmsInterpParams* p);
+
+// Curves ----------------------------------------------------------------------------------------------------------------
+
+// This struct holds information about a segment, plus a pointer to the function that implements the evaluation.
+// In the case of table-based, Eval pointer is set to NULL
+
+// The gamma function main structure
+struct _cms_curve_struct {
+
+ cmsInterpParams* InterpParams; // Private optimizations for interpolation
+
+ cmsUInt32Number nSegments; // Number of segments in the curve. Zero for a 16-bit based tables
+ cmsCurveSegment* Segments; // The segments
+ cmsInterpParams** SegInterp; // Array of private optimizations for interpolation in table-based segments
+
+ cmsParametricCurveEvaluator* Evals; // Evaluators (one per segment)
+
+ // 16 bit Table-based representation follows
+ cmsUInt32Number nEntries; // Number of table elements
+ cmsUInt16Number* Table16; // The table itself.
+};
+
+
+// Pipelines & Stages ---------------------------------------------------------------------------------------------
+
+// A single stage
+struct _cmsStage_struct {
+
+ cmsContext ContextID;
+
+ cmsStageSignature Type; // Identifies the stage
+ cmsStageSignature Implements; // Identifies the *function* of the stage (for optimizations)
+
+ cmsUInt32Number InputChannels; // Input channels -- for optimization purposes
+ cmsUInt32Number OutputChannels; // Output channels -- for optimization purposes
+
+ _cmsStageEvalFn EvalPtr; // Points to fn that evaluates the stage (always in floating point)
+ _cmsStageDupElemFn DupElemPtr; // Points to a fn that duplicates the *data* of the stage
+ _cmsStageFreeElemFn FreePtr; // Points to a fn that sets the *data* of the stage free
+
+ // A generic pointer to whatever memory needed by the stage
+ void* Data;
+
+ // Maintains linked list (used internally)
+ struct _cmsStage_struct* Next;
+};
+
+// Data kept in "Element" member of cmsStage
+
+// Curves
+typedef struct {
+ cmsUInt32Number nCurves;
+ cmsToneCurve** TheCurves;
+
+} _cmsStageToneCurvesData;
+
+// Matrix
+typedef struct {
+ cmsFloat64Number* Double; // floating point for the matrix
+ cmsFloat64Number* Offset; // The offset
+
+} _cmsStageMatrixData;
+
+// CLUT
+typedef struct {
+
+ union { // Can have only one of both representations at same time
+ cmsUInt16Number* T; // Points to the table 16 bits table
+ cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table
+
+ } Tab;
+
+ cmsInterpParams* Params;
+ cmsUInt32Number nEntries;
+ cmsBool HasFloatValues;
+
+} _cmsStageCLutData;
+
+
+// Special Stages (cannot be saved)
+cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID);
+cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID);
+cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID);
+cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID);
+cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID);
+cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID);
+cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList);
+cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels);
+cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan);
+
+// For curve set only
+cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
+
+
+// Pipeline Evaluator (in floating point)
+typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[],
+ cmsFloat32Number Out[],
+ const void* Data);
+
+struct _cmsPipeline_struct {
+
+ cmsStage* Elements; // Points to elements chain
+ cmsUInt32Number InputChannels, OutputChannels;
+
+ // Data & evaluators
+ void *Data;
+
+ _cmsOPTeval16Fn Eval16Fn;
+ _cmsPipelineEvalFloatFn EvalFloatFn;
+ _cmsOPTfreeDataFn FreeDataFn;
+ _cmsOPTdupDataFn DupDataFn;
+
+ cmsContext ContextID; // Environment
+
+ cmsBool SaveAs8Bits; // Implemntation-specific: save as 8 bits if possible
+};
+
+// LUT reading & creation -------------------------------------------------------------------------------------------
+
+// Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy
+// of the LUTS, since ownership of original is up to the profile. The user should free allocated resources.
+
+cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent);
+cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent);
+cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent);
+
+// Special values
+cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile);
+cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile);
+
+// Profile linker --------------------------------------------------------------------------------------------------
+
+cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number TheIntents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
+
+// Sequence --------------------------------------------------------------------------------------------------------
+
+cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile);
+cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq);
+cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]);
+
+
+// LUT optimization ------------------------------------------------------------------------------------------------
+
+cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples);
+int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
+
+cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
+ cmsUInt16Number **White,
+ cmsUInt16Number **Black,
+ cmsUInt32Number *nOutputs);
+
+cmsBool _cmsOptimizePipeline(cmsPipeline** Lut,
+ int Intent,
+ cmsUInt32Number* InputFormat,
+ cmsUInt32Number* OutputFormat,
+ cmsUInt32Number* dwFlags );
+
+
+// Hi level LUT building ----------------------------------------------------------------------------------------------
+
+cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsUInt32Number Intents[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number nGamutPCSposition,
+ cmsHPROFILE hGamut);
+
+
+// Formatters ------------------------------------------------------------------------------------------------------------
+
+cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type);
+cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type);
+
+cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+ cmsFormatterDirection Dir,
+ cmsUInt32Number dwFlags);
+
+
+// Transform logic ------------------------------------------------------------------------------------------------------
+
+struct _cmstransform_struct;
+
+// Full xform
+typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform,
+ const void* InputBuffer,
+ void* OutputBuffer, cmsUInt32Number Size);
+
+typedef struct {
+
+ cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
+ cmsUInt32Number StrideIn, StrideOut; // Planar support
+
+} cmsFormatterInfo;
+
+// Transformation
+typedef struct _cmstransform_struct {
+
+ cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
+
+ // Points to transform code
+ _cmsTransformFn xform;
+
+ // Formatters, cannot be embedded into LUT because cache
+ cmsFormatter16 FromInput;
+ cmsFormatter16 ToOutput;
+
+ cmsFormatterFloat FromInputFloat;
+ cmsFormatterFloat ToOutputFloat;
+
+ // 1-pixel cache (16 bits only)
+ cmsUInt16Number CacheIn[cmsMAXCHANNELS];
+ cmsUInt16Number CacheOut[cmsMAXCHANNELS];
+
+ // Semaphor for cache
+ LCMS_RWLOCK_T rwlock;
+
+ // A MPE LUT holding the full (optimized) transform
+ cmsPipeline* Lut;
+
+ // A MPE LUT holding the gamut check. It goes from the input space to bilevel
+ cmsPipeline* GamutCheck;
+
+ // Colorant tables
+ cmsNAMEDCOLORLIST* InputColorant; // Input Colorant table
+ cmsNAMEDCOLORLIST* OutputColorant; // Colorant table (for n chans > CMYK)
+
+ // Informational only
+ cmsColorSpaceSignature EntryColorSpace;
+ cmsColorSpaceSignature ExitColorSpace;
+
+ // Profiles used to create the transform
+ cmsSEQ* Sequence;
+
+ cmsUInt32Number dwOriginalFlags;
+ cmsFloat64Number AdaptationState;
+
+ // The intent of this transform. That is usually the last intent in the profilechain, but may differ
+ cmsUInt32Number RenderingIntent;
+
+ // An id that uniquely identifies the running context. May be null.
+ cmsContext ContextID;
+
+} _cmsTRANSFORM;
+
+// --------------------------------------------------------------------------------------------------
+
+cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
+
+
+cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
+ cmsUInt32Number nPoints,
+ cmsUInt32Number nProfiles,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
+
+cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll);
+
+cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
+
+
+#define _lcms_internal_H
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h Thu Sep 16 11:15:07 2010 -0700
@@ -0,0 +1,562 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+// This is the plug-in header file. Normal LittleCMS clients should not use it.
+// It is provided for plug-in writters that may want to access the support
+// functions to do low level operations. All plug-in related structures
+// are defined here. Including this file forces to include the standard API too.
+
+#ifndef _lcms_plugin_H
+
+// Deal with Microsoft's attempt at deprecating C standard runtime functions
+#ifdef _MSC_VER
+# if (_MSC_VER >= 1400)
+# ifndef _CRT_SECURE_NO_DEPRECATE
+# define _CRT_SECURE_NO_DEPRECATE
+# endif
+# ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS
+# endif
+# endif
+#endif
+
+#ifndef _lcms2_H
+#include "lcms2.h"
+#endif
+
+// We need some standard C functions.
+#include <stdlib.h>
+#include <math.h>
+#include <stdarg.h>
+#include <memory.h>
+#include <string.h>
+
+
+#ifndef CMS_USE_CPP_API
+# ifdef __cplusplus
+extern "C" {
+# endif
+#endif
+
+// Vector & Matrix operations -----------------------------------------------------------------------
+
+// Axis of the matrix/array. No specific meaning at all.
+#define VX 0
+#define VY 1
+#define VZ 2
+
+// Vectors
+typedef struct {
+ cmsFloat64Number n[3];
+
+ } cmsVEC3;
+
+// 3x3 Matrix
+typedef struct {
+ cmsVEC3 v[3];
+
+ } cmsMAT3;
+
+CMSAPI void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z);
+CMSAPI void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b);
+CMSAPI void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v);
+CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v);
+CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a);
+CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b);
+
+CMSAPI void CMSEXPORT _cmsMAT3identity(cmsMAT3* a);
+CMSAPI cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a);
+CMSAPI void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b);
+CMSAPI cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b);
+CMSAPI cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b);
+CMSAPI void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v);
+
+
+// Error logging -------------------------------------------------------------------------------------
+
+CMSAPI void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...);
+
+// Memory management ----------------------------------------------------------------------------------
+
+CMSAPI void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size);
+CMSAPI void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size);
+CMSAPI void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
+CMSAPI void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
+CMSAPI void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr);
+CMSAPI void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size);
+
+// I/O handler ----------------------------------------------------------------------------------
+
+struct _cms_io_handler {
+
+ void* stream; // Associated stream, which is implemented differently depending on media.
+
+ cmsContext ContextID;
+ cmsUInt32Number UsedSpace;
+ char PhysicalFile[cmsMAX_PATH];
+
+ cmsUInt32Number (* Read)(struct _cms_io_handler* iohandler, void *Buffer,
+ cmsUInt32Number size,
+ cmsUInt32Number count);
+ cmsBool (* Seek)(struct _cms_io_handler* iohandler, cmsUInt32Number offset);
+ cmsBool (* Close)(struct _cms_io_handler* iohandler);
+ cmsUInt32Number (* Tell)(struct _cms_io_handler* iohandler);
+ cmsBool (* Write)(struct _cms_io_handler* iohandler, cmsUInt32Number size,
+ const void* Buffer);
+};
+
+// Endianess adjust functions
+CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word);
+CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value);
+CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord);
+
+// Helper IO functions
+CMSAPI cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n);
+CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n);
+CMSAPI cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n);
+CMSAPI cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n);
+CMSAPI cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n);
+CMSAPI cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n);
+CMSAPI cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ);
+CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array);
+
+CMSAPI cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n);
+CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n);
+CMSAPI cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n);
+CMSAPI cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n);
+CMSAPI cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n);
+CMSAPI cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n);
+CMSAPI cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ);
+CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array);
+
+// ICC base tag
+typedef struct {
+ cmsTagTypeSignature sig;
+ cmsInt8Number reserved[4];
+
+} _cmsTagBase;
+
+// Type base helper functions
+CMSAPI cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io);
+CMSAPI cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig);
+
+// Alignment functions
+CMSAPI cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io);
+CMSAPI cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io);
+
+// To deal with text streams. 2K at most
+CMSAPI cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...);
+
+// Fixed point helper functions
+CMSAPI cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8);
+CMSAPI cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val);
+
+CMSAPI cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32);
+CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v);
+
+// Date/time helper functions
+CMSAPI void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source);
+CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest);
+
+
+//----------------------------------------------------------------------------------------------------------
+
+// Plug-in foundation
+#define cmsPluginMagicNumber 0x61637070 // 'acpp'
+
+#define cmsPluginMemHandlerSig 0x6D656D48 // 'memH'
+#define cmsPluginInterpolationSig 0x696E7048 // 'inpH'
+#define cmsPluginParametricCurveSig 0x70617248 // 'parH'
+#define cmsPluginFormattersSig 0x66726D48 // 'frmH
+#define cmsPluginTagTypeSig 0x74797048 // 'typH'
+#define cmsPluginTagSig 0x74616748 // 'tagH'
+#define cmsPluginRenderingIntentSig 0x696E7448 // 'intH'
+#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH'
+#define cmsPluginOptimizationSig 0x6F707448 // 'optH'
+
+typedef struct _cmsPluginBaseStruct {
+
+ cmsUInt32Number Magic; // 'acpp' signature
+ cmsUInt32Number ExpectedVersion; // Expected version of LittleCMS
+ cmsUInt32Number Type; // Type of plug-in
+ struct _cmsPluginBaseStruct* Next; // For multiple plugin definition. NULL for end of list.
+
+} cmsPluginBase;
+
+// Maximum number of types in a plugin array
+#define MAX_TYPES_IN_LCMS_PLUGIN 20
+
+//----------------------------------------------------------------------------------------------------------
+
+// Memory handler. Each new plug-in type replaces current behaviour
+typedef struct {
+
+ cmsPluginBase base;
+
+ // Required
+ void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size);
+ void (* FreePtr)(cmsContext ContextID, void *Ptr);
+ void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
+
+ // Optional
+ void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size);
+ void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
+ void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size);
+
+} cmsPluginMemHandler;
+
+
+// ------------------------------------------------------------------------------------------------------------------
+
+// Interpolation. 16 bits and floating point versions.
+struct _cms_interp_struc;
+
+// Interpolation callbacks
+
+// 16 bits forward interpolation. This function performs precision-limited linear interpolation
+// and is supposed to be quite fast. Implementation may be tetrahedral or trilinear, and plug-ins may
+// choose to implement any other interpolation algorithm.
+typedef void (* _cmsInterpFn16)(register const cmsUInt16Number Input[],
+ register cmsUInt16Number Output[],
+ register const struct _cms_interp_struc* p);
+
+// Floating point forward interpolation. Full precision interpolation using floats. This is not a
+// time critical function. Implementation may be tetrahedral or trilinear, and plug-ins may
+// choose to implement any other interpolation algorithm.
+typedef void (* _cmsInterpFnFloat)(cmsFloat32Number const Input[],
+ cmsFloat32Number Output[],
+ const struct _cms_interp_struc* p);
+
+
+
+// This type holds a pointer to an interpolator that can be either 16 bits or float
+typedef union {
+ _cmsInterpFn16 Lerp16; // Forward interpolation in 16 bits
+ _cmsInterpFnFloat LerpFloat; // Forward interpolation in floating point
+} cmsInterpFunction;
+
+// Flags for interpolator selection
+#define CMS_LERP_FLAGS_16BITS 0x0000 // The default
+#define CMS_LERP_FLAGS_FLOAT 0x0001 // Requires different implementation
+#define CMS_LERP_FLAGS_TRILINEAR 0x0100 // Hint only
+
+
+#define MAX_INPUT_DIMENSIONS 8
+
+typedef struct _cms_interp_struc { // Used on all interpolations. Supplied by lcms2 when calling the interpolation function
+
+ cmsContext ContextID; // The calling thread
+
+ cmsUInt32Number dwFlags; // Keep original flags
+ cmsUInt32Number nInputs; // != 1 only in 3D interpolation
+ cmsUInt32Number nOutputs; // != 1 only in 3D interpolation
+
+ cmsUInt32Number nSamples[MAX_INPUT_DIMENSIONS]; // Valid on all kinds of tables
+ cmsUInt32Number Domain[MAX_INPUT_DIMENSIONS]; // Domain = nSamples - 1
+
+ cmsUInt32Number opta[MAX_INPUT_DIMENSIONS]; // Optimization for 3D CLUT. This is the number of nodes premultiplied for each
+ // dimension. For example, in 7 nodes, 7, 7^2 , 7^3, 7^4, etc. On non-regular
+ // Samplings may vary according of the number of nodes for each dimension.
+
+ const void *Table; // Points to the actual interpolation table
+ cmsInterpFunction Interpolation; // Points to the function to do the interpolation
+
+ } cmsInterpParams;
+
+// Interpolators factory
+typedef cmsInterpFunction (* cmsInterpFnFactory)(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
+
+// The plug-in
+typedef struct {
+ cmsPluginBase base;
+
+ // Points to a user-supplied function which implements the factory
+ cmsInterpFnFactory InterpolatorsFactory;
+
+} cmsPluginInterpolation;
+
+//----------------------------------------------------------------------------------------------------------
+
+// Parametric curves. A negative type means same function but analytically inverted. Max. number of params is 10
+
+// Evaluator callback for user-suplied parametric curves. May implement more than one type
+typedef cmsFloat64Number (* cmsParametricCurveEvaluator)(cmsInt32Number Type, const cmsFloat64Number Params[10], cmsFloat64Number R);
+
+// Plug-in may implement an arbitrary number of parametric curves
+typedef struct {
+ cmsPluginBase base;
+
+ cmsUInt32Number nFunctions; // Number of supported functions
+ cmsUInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types
+ cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function
+
+ cmsParametricCurveEvaluator Evaluator; // The evaluator
+
+} cmsPluginParametricCurves;
+//----------------------------------------------------------------------------------------------------------
+
+// Formatters. This plug-in adds new handlers, replacing them if they already exist. Formatters dealing with
+// cmsFloat32Number (bps = 4) or double (bps = 0) types are requested via FormatterFloat callback. Others come across
+// Formatter16 callback
+
+struct _cmstransform_struct;
+
+typedef cmsUInt8Number* (* cmsFormatter16)(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride);
+
+typedef cmsUInt8Number* (* cmsFormatterFloat)(struct _cmstransform_struct* CMMcargo,
+ cmsFloat32Number Values[],
+ cmsUInt8Number* Buffer,
+ cmsUInt32Number Stride);
+
+// This type holds a pointer to a formatter that can be either 16 bits or cmsFloat32Number
+typedef union {
+ cmsFormatter16 Fmt16;
+ cmsFormatterFloat FmtFloat;
+
+} cmsFormatter;
+
+#define CMS_PACK_FLAGS_16BITS 0x0000
+#define CMS_PACK_FLAGS_FLOAT 0x0001
+
+typedef enum { cmsFormatterInput=0, cmsFormatterOutput=1 } cmsFormatterDirection;
+
+typedef cmsFormatter (* cmsFormatterFactory)(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+ cmsFormatterDirection Dir,
+ cmsUInt32Number dwFlags); // precision
+
+// Plug-in may implement an arbitrary number of formatters
+typedef struct {
+ cmsPluginBase base;
+ cmsFormatterFactory FormattersFactory;
+
+} cmsPluginFormatters;
+
+//----------------------------------------------------------------------------------------------------------
+
+// Tag type handler. Each type is free to return anything it wants, and it is up to the caller to
+// know in advance what is the type contained in the tag.
+typedef struct _cms_typehandler_struct {
+
+ cmsTagTypeSignature Signature; // The signature of the type
+
+ // Allocates and reads items
+ void * (* ReadPtr)(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ cmsUInt32Number* nItems,
+ cmsUInt32Number SizeOfTag);
+
+ // Writes n Items
+ cmsBool (* WritePtr)(struct _cms_typehandler_struct* self,
+ cmsIOHANDLER* io,
+ void* Ptr,
+ cmsUInt32Number nItems);
+
+ // Duplicate an item or array of items
+ void* (* DupPtr)(struct _cms_typehandler_struct* self,
+ const void *Ptr,
+ cmsUInt32Number n);
+
+ // Free all resources
+ void (* FreePtr)(struct _cms_typehandler_struct* self,
+ void *Ptr);
+
+ // The calling thread
+ cmsContext ContextID;
+
+} cmsTagTypeHandler;
+
+// Each plug-in implements a single type
+typedef struct {
+ cmsPluginBase base;
+ cmsTagTypeHandler Handler;
+
+} cmsPluginTagType;
+
+//----------------------------------------------------------------------------------------------------------
+
+// This is the tag plugin, which identifies tags. For writing, a pointer to function is provided.
+// This function should return the desired type for this tag, given the version of profile
+// and the data being serialized.
+typedef struct {
+
+ cmsUInt32Number ElemCount; // If this tag needs an array, how many elements should keep
+
+ // For reading.
+ cmsUInt32Number nSupportedTypes; // In how many types this tag can come (MAX_TYPES_IN_LCMS_PLUGIN maximum)
+ cmsTagTypeSignature SupportedTypes[MAX_TYPES_IN_LCMS_PLUGIN];
+
+ // For writting
+ cmsTagTypeSignature (* DecideType)(cmsFloat64Number ICCVersion, const void *Data);
+
+} cmsTagDescriptor;
+
+// Plug-in implements a single tag
+typedef struct {
+ cmsPluginBase base;
+
+ cmsTagSignature Signature;
+ cmsTagDescriptor Descriptor;
+
+} cmsPluginTag;
+
+//----------------------------------------------------------------------------------------------------------
+
+// Custom intents. This function should join all profiles specified in the array in
+// a single LUT. Any custom intent in the chain redirects to custom function. If more than
+// one custom intent is found, the one located first is invoked. Usually users should use only one
+// custom intent, so mixing custom intents in same multiprofile transform is not supported.
+
+typedef cmsPipeline* (* cmsIntentFn)( cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number Intents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
+
+
+// Each plug-in defines a single intent number.
+typedef struct {
+ cmsPluginBase base;
+ cmsUInt32Number Intent;
+ cmsIntentFn Link;
+ char Description[256];
+
+} cmsPluginRenderingIntent;
+
+
+// The default ICC intents (perceptual, saturation, rel.col and abs.col)
+CMSAPI cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number Intents[],
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags);
+
+
+//----------------------------------------------------------------------------------------------------------
+
+// Pipelines, Multi Process Elements.
+
+typedef void (* _cmsStageEvalFn) (const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage* mpe);
+typedef void*(* _cmsStageDupElemFn) (cmsStage* mpe);
+typedef void (* _cmsStageFreeElemFn) (cmsStage* mpe);
+
+
+// This function allocates a generic MPE
+CMSAPI cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID,
+ cmsStageSignature Type,
+ cmsUInt32Number InputChannels,
+ cmsUInt32Number OutputChannels,
+ _cmsStageEvalFn EvalPtr, // Points to fn that evaluates the element (always in floating point)
+ _cmsStageDupElemFn DupElemPtr, // Points to a fn that duplicates the stage
+ _cmsStageFreeElemFn FreePtr, // Points to a fn that sets the element free
+ void* Data); // A generic pointer to whatever memory needed by the element
+typedef struct {
+ cmsPluginBase base;
+ cmsTagTypeHandler Handler;
+
+} cmsPluginMultiProcessElement;
+
+//----------------------------------------------------------------------------------------------------------
+// Optimization. Using this plug-in, additional optimization strategies may be implemented.
+// The function should return TRUE if any optimization is done on the LUT, this terminates
+// the optimization search. Or FALSE if it is unable to optimize and want to give a chance
+// to the rest of optimizers.
+
+typedef void (* _cmsOPTeval16Fn)(register const cmsUInt16Number In[],
+ register cmsUInt16Number Out[],
+ register const void* Data);
+
+typedef void (* _cmsOPTfreeDataFn)(cmsContext ContextID, void* Data);
+typedef void* (* _cmsOPTdupDataFn)(cmsContext ContextID, const void* Data);
+
+
+typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut,
+ cmsUInt32Number Intent,
+ cmsUInt32Number* InputFormat,
+ cmsUInt32Number* OutputFormat,
+ cmsUInt32Number* dwFlags);
+
+// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional
+// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality.
+
+CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
+ _cmsOPTeval16Fn Eval16,
+ void* PrivateData,
+ _cmsOPTfreeDataFn FreePrivateDataFn,
+ _cmsOPTdupDataFn DupPrivateDataFn);
+
+typedef struct {
+ cmsPluginBase base;
+
+ // Optimize entry point
+ _cmsOPToptimizeFn OptimizePtr;
+
+} cmsPluginOptimization;
+
+//----------------------------------------------------------------------------------------------------------
+
+#ifndef CMS_USE_CPP_API
+# ifdef __cplusplus
+ }
+# endif
+#endif
+
+#define _lcms_plugin_H
+#endif
--- a/jdk/test/javax/imageio/CachePremissionsTest/CachePermissionsTest.java Wed Jul 05 17:21:58 2017 +0200
+++ b/jdk/test/javax/imageio/CachePremissionsTest/CachePermissionsTest.java Thu Sep 16 11:15:07 2010 -0700
@@ -50,9 +50,9 @@
* -Djava.security.debug=access can be used to verify file permissions.
*
* @run main CachePermissionsTest true
- * @run main/othervm/policy=w.policy CachePermissionsTest false
- * @run main/othervm/policy=rw.policy CachePermissionsTest false
- * @run main/othervm/policy=rwd.policy CachePermissionsTest true
+ * @run main/othervm CachePermissionsTest false w.policy
+ * @run main/othervm CachePermissionsTest false rw.policy
+ * @run main/othervm CachePermissionsTest true rwd.policy
*/
import java.io.File;
@@ -73,6 +73,17 @@
System.out.println("java.io.tmpdir is " + System.getProperty("java.io.tmpdir"));
+ if (args.length > 1) {
+ String testsrc = System.getProperty("test.src", ".");
+ String policy = testsrc + File.separator + args[1];
+
+ System.out.println("Policy file: " + policy);
+ System.setProperty("java.security.policy", policy);
+
+ System.out.println("Install security manager...");
+ System.setSecurityManager(new SecurityManager());
+ }
+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {