29
#include "sun_java2d_cmm_lcms_LCMS.h"
30
#include "sun_java2d_cmm_lcms_LCMSImageLayout.h"
35
#include <lcms2_plugin.h>
38
#define SigMake(a,b,c,d) \
39
( ( ((int) ((unsigned char) (a))) << 24) | \
40
( ((int) ((unsigned char) (b))) << 16) | \
41
( ((int) ((unsigned char) (c))) << 8) | \
42
(int) ((unsigned char) (d)))
44
#define TagIdConst(a, b, c, d) \
45
((int) SigMake ((a), (b), (c), (d)))
47
#define SigHead TagIdConst('h','e','a','d')
49
#define DT_BYTE sun_java2d_cmm_lcms_LCMSImageLayout_DT_BYTE
50
#define DT_SHORT sun_java2d_cmm_lcms_LCMSImageLayout_DT_SHORT
51
#define DT_INT sun_java2d_cmm_lcms_LCMSImageLayout_DT_INT
54
#define DF_ICC_BUF_SIZE 32
56
#define ERR_MSG_SIZE 256
58
typedef struct lcmsProfile_s {
60
} lcmsProfile_t, *lcmsProfile_p;
65
} TagSignature_t, *TagSignature_p;
69
void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode,
70
const char *errorText) {
72
char errMsg[ERR_MSG_SIZE] = {0};
74
snprintf(errMsg, ERR_MSG_SIZE, "LCMS error %d: %s", errorCode, errorText);
76
(*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);
77
if (!(*env)->ExceptionCheck(env)) {
78
JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg);
82
JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *jvm, void *reserved) {
85
cmsSetLogErrorHandler(errorHandler);
86
return JNI_VERSION_1_6;
89
void LCMS_freeProfile(JNIEnv *env, jlong ptr) {
90
lcmsProfile_p p = (lcmsProfile_p)jlong_to_ptr(ptr);
94
cmsCloseProfile(p->pf);
100
void LCMS_freeTransform(JNIEnv *env, jlong ID)
102
cmsHTRANSFORM sTrans = jlong_to_ptr(ID);
104
cmsDeleteTransform(sTrans);
110
static void ThrowIllegalArgumentException(JNIEnv *env, const char *msg) {
111
jthrowable cause = (*env)->ExceptionOccurred(env);
113
(*env)->ExceptionClear(env);
115
jstring str = JNU_NewStringPlatform(env, msg);
117
jobject iae = JNU_NewObjectByName(env,
118
"java/lang/IllegalArgumentException",
119
"(Ljava/lang/String;Ljava/lang/Throwable;)V",
122
(*env)->Throw(env, iae);
132
JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
133
(JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderingIntent,
134
jint inFormatter, jint outFormatter, jobject disposerRef)
136
cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];
137
cmsHPROFILE *iccArray = &_iccArray[0];
138
cmsHTRANSFORM sTrans = NULL;
142
size = (*env)->GetArrayLength (env, profileIDs);
143
ids = (*env)->GetLongArrayElements(env, profileIDs, 0);
149
if (DF_ICC_BUF_SIZE < size*2) {
150
iccArray = (cmsHPROFILE*) malloc(
151
size*2*sizeof(cmsHPROFILE));
152
if (iccArray == NULL) {
153
(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
155
J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
161
for (i = 0; i < size; i++) {
162
cmsColorSpaceSignature cs;
163
lcmsProfile_p profilePtr = (lcmsProfile_p)jlong_to_ptr(ids[i]);
164
cmsHPROFILE icc = profilePtr->pf;
172
cs = cmsGetColorSpace(icc);
173
if (size > 2 && i != 0 && i != size - 1 &&
174
cs != cmsSigXYZData && cs != cmsSigLabData)
180
cmsUInt32Number dwFlags = 0;
181
if (T_EXTRA(inFormatter) > 0 && T_EXTRA(outFormatter) > 0) {
182
dwFlags |= cmsFLAGS_COPY_ALPHA;
185
sTrans = cmsCreateMultiprofileTransform(iccArray, j,
186
inFormatter, outFormatter, renderingIntent, dwFlags);
188
(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
190
if (sTrans == NULL) {
191
J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "
193
if (!(*env)->ExceptionCheck(env)) {
194
JNU_ThrowByName(env, "java/awt/color/CMMException",
195
"Cannot get color transform");
198
Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, ptr_to_jlong(sTrans));
201
if (iccArray != &_iccArray[0]) {
204
return ptr_to_jlong(sTrans);
213
JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative
214
(JNIEnv *env, jclass cls, jbyteArray data, jobject disposerRef)
218
lcmsProfile_p sProf = NULL;
221
if (JNU_IsNull(env, data)) {
222
ThrowIllegalArgumentException(env, "Invalid profile data");
226
dataArray = (*env)->GetByteArrayElements (env, data, 0);
227
if (dataArray == NULL) {
232
dataSize = (*env)->GetArrayLength (env, data);
234
pf = cmsOpenProfileFromMem((const void *)dataArray,
235
(cmsUInt32Number) dataSize);
237
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
240
ThrowIllegalArgumentException(env, "Invalid profile data");
245
cmsUInt32Number pfSize = 0;
246
if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
247
pfSize < sizeof(cmsICCHeader))
249
ThrowIllegalArgumentException(env, "Invalid profile data");
257
sProf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));
261
Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, ptr_to_jlong(sProf));
267
return ptr_to_jlong(sProf);
275
JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative
276
(JNIEnv *env, jclass cls, jlong id)
278
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
279
cmsUInt32Number pfSize = 0;
282
if (!cmsSaveProfileToMem(sProf->pf, NULL, &pfSize)) {
283
if (!(*env)->ExceptionCheck(env)) {
284
JNU_ThrowByName(env, "java/awt/color/CMMException",
285
"Can not access specified profile.");
290
jbyteArray data = (*env)->NewByteArray(env, pfSize);
296
jbyte* dataArray = (*env)->GetByteArrayElements(env, data, 0);
297
if (dataArray == NULL) {
302
cmsBool status = cmsSaveProfileToMem(sProf->pf, dataArray, &pfSize);
304
(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
307
if (!(*env)->ExceptionCheck(env)) {
308
JNU_ThrowByName(env, "java/awt/color/CMMException",
309
"Can not access specified profile.");
317
static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
318
static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
319
static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
327
JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative
328
(JNIEnv *env, jclass cls, jlong id, jint tagSig)
330
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
332
cmsUInt32Number tagSize;
334
jbyte* dataArray = NULL;
335
jbyteArray data = NULL;
337
cmsUInt32Number bufSize;
341
if (tagSig == SigHead) {
345
bufSize = sizeof(cmsICCHeader);
346
data = (*env)->NewByteArray(env, bufSize);
353
dataArray = (*env)->GetByteArrayElements (env, data, 0);
355
if (dataArray == NULL) {
360
status = _getHeaderInfo(sProf->pf, dataArray, bufSize);
362
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
365
if (!(*env)->ExceptionCheck(env)) {
366
JNU_ThrowByName(env, "java/awt/color/CMMException",
367
"ICC Profile header not found");
375
if (cmsIsTag(sProf->pf, sig.cms)) {
376
tagSize = cmsReadRawTag(sProf->pf, sig.cms, NULL, 0);
378
if (!(*env)->ExceptionCheck(env)) {
379
JNU_ThrowByName(env, "java/awt/color/CMMException",
380
"ICC profile tag not found");
386
data = (*env)->NewByteArray(env, tagSize);
392
dataArray = (*env)->GetByteArrayElements (env, data, 0);
394
if (dataArray == NULL) {
399
bufSize = cmsReadRawTag(sProf->pf, sig.cms, dataArray, tagSize);
401
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
403
if (bufSize != tagSize) {
404
if (!(*env)->ExceptionCheck(env)) {
405
JNU_ThrowByName(env, "java/awt/color/CMMException",
406
"Can not get tag data.");
418
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative
419
(JNIEnv *env, jclass cls, jlong id, jint tagSig, jbyteArray data)
421
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
422
cmsHPROFILE pfReplace = NULL;
425
cmsBool status = FALSE;
431
if (JNU_IsNull(env, data)) {
432
ThrowIllegalArgumentException(env, "Can not write tag data.");
436
tagSize =(*env)->GetArrayLength(env, data);
438
dataArray = (*env)->GetByteArrayElements(env, data, 0);
440
if (dataArray == NULL) {
445
if (tagSig == SigHead) {
446
status = _setHeaderInfo(sProf->pf, dataArray, tagSize);
453
pfReplace = _writeCookedTag(sProf->pf, sig.cms, dataArray, tagSize);
454
status = (pfReplace != NULL);
457
(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
460
ThrowIllegalArgumentException(env, "Can not write tag data.");
461
} else if (pfReplace != NULL) {
462
cmsCloseProfile(sProf->pf);
463
sProf->pf = pfReplace;
467
static void *getILData(JNIEnv *env, jobject data, jint type) {
470
return (*env)->GetByteArrayElements(env, data, 0);
472
return (*env)->GetShortArrayElements(env, data, 0);
474
return (*env)->GetIntArrayElements(env, data, 0);
480
static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data,
484
(*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, mode);
487
(*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, mode);
490
(*env)->ReleaseIntArrayElements(env, data, (jint *) pData, mode);
500
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
501
(JNIEnv *env, jclass cls, jlong ID, jint width, jint height, jint srcOffset,
502
jint srcNextRowOffset, jint dstOffset, jint dstNextRowOffset,
503
jobject srcData, jobject dstData, jint srcDType, jint dstDType)
505
cmsHTRANSFORM sTrans = jlong_to_ptr(ID);
507
if (sTrans == NULL) {
508
J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
509
JNU_ThrowByName(env, "java/awt/color/CMMException",
510
"Cannot get color transform");
514
void *inputBuffer = getILData(env, srcData, srcDType);
515
if (inputBuffer == NULL) {
516
J2dRlsTraceLn(J2D_TRACE_ERROR, "");
521
void *outputBuffer = getILData(env, dstData, dstDType);
522
if (outputBuffer == NULL) {
523
releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
528
char *input = (char *) inputBuffer + srcOffset;
529
char *output = (char *) outputBuffer + dstOffset;
531
cmsDoTransformLineStride(sTrans, input, output, width, height,
532
srcNextRowOffset, dstNextRowOffset, 0, 0);
534
releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
535
releaseILData(env, outputBuffer, dstDType, dstData, 0);
538
static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
540
cmsUInt32Number pfSize = 0;
541
cmsUInt8Number* pfBuffer = NULL;
542
cmsBool status = FALSE;
544
if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
545
pfSize < sizeof(cmsICCHeader) ||
546
bufferSize < (jint)sizeof(cmsICCHeader))
551
pfBuffer = malloc(pfSize);
552
if (pfBuffer == NULL) {
557
if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {
558
memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));
565
static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
567
cmsICCHeader pfHeader;
569
if (pBuffer == NULL || bufferSize < (jint)sizeof(cmsICCHeader)) {
573
memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader));
576
cmsSetHeaderFlags(pf, _cmsAdjustEndianess32(pfHeader.flags));
577
cmsSetHeaderManufacturer(pf, _cmsAdjustEndianess32(pfHeader.manufacturer));
578
cmsSetHeaderModel(pf, _cmsAdjustEndianess32(pfHeader.model));
579
cmsUInt64Number attributes;
580
_cmsAdjustEndianess64(&attributes, &pfHeader.attributes);
581
cmsSetHeaderAttributes(pf, attributes);
582
cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID));
583
cmsSetHeaderRenderingIntent(pf, _cmsAdjustEndianess32(pfHeader.renderingIntent));
584
cmsSetPCS(pf, _cmsAdjustEndianess32(pfHeader.pcs));
585
cmsSetColorSpace(pf, _cmsAdjustEndianess32(pfHeader.colorSpace));
586
cmsSetDeviceClass(pf, _cmsAdjustEndianess32(pfHeader.deviceClass));
587
cmsSetEncodedICCversion(pf, _cmsAdjustEndianess32(pfHeader.version));
595
static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,
596
const cmsTagSignature sig,
597
jbyte *pData, jint size)
599
cmsUInt32Number pfSize = 0;
600
const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);
602
cmsHPROFILE pfSanity = NULL;
606
cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);
611
memset(&hdr, 0, sizeof(cmsICCHeader));
614
hdr.flags = cmsGetHeaderFlags(pfTarget);
615
hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
616
hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
617
hdr.model = cmsGetHeaderModel(pfTarget);
618
hdr.pcs = cmsGetPCS(pfTarget);
619
hdr.colorSpace = cmsGetColorSpace(pfTarget);
620
hdr.deviceClass = cmsGetDeviceClass(pfTarget);
621
hdr.version = cmsGetEncodedICCversion(pfTarget);
622
cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
623
cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
625
cmsSetHeaderFlags(p, hdr.flags);
626
cmsSetHeaderManufacturer(p, hdr.manufacturer);
627
cmsSetHeaderModel(p, hdr.model);
628
cmsSetHeaderAttributes(p, hdr.attributes);
629
cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
630
cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
631
cmsSetPCS(p, hdr.pcs);
632
cmsSetColorSpace(p, hdr.colorSpace);
633
cmsSetDeviceClass(p, hdr.deviceClass);
634
cmsSetEncodedICCversion(p, hdr.version);
637
if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {
643
for (i = 0; i < tagCount; i++) {
644
cmsBool isTagReady = FALSE;
645
const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);
646
const cmsUInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
655
cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);
657
if (tagSize == cmsReadRawTag(pfTarget, s, buf, tagSize)) {
659
isTagReady = cmsWriteRawTag(p, s, buf, tagSize);
674
if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
675
buf = malloc(pfSize);
678
if (cmsSaveProfileToMem(p, buf, &pfSize)) {
679
pfSanity = cmsOpenProfileFromMem(buf, pfSize);
686
if (pfSanity == NULL) {
694
const void* pTag = cmsReadTag(pfSanity, sig);
698
cmsCloseProfile(pfSanity);
707
cmsCloseProfile(pfSanity);
708
pfSanity = cmsOpenProfileFromMem(buf, pfSize);