1 /* 2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <memory.h> 29 #include "sun_java2d_cmm_lcms_LCMS.h" 30 #include "jni_util.h" 31 #include "Trace.h" 32 #include "Disposer.h" 33 #include "lcms2.h" 34 35 36 #define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary 37 38 #ifdef USE_BIG_ENDIAN 39 #define AdjustEndianess32(a) 40 #else 41 42 static 43 void AdjustEndianess32(cmsUInt8Number *pByte) 44 { 45 cmsUInt8Number temp1; 46 cmsUInt8Number temp2; 47 48 temp1 = *pByte++; 49 temp2 = *pByte++; 50 *(pByte-1) = *pByte; 51 *pByte++ = temp2; 52 *(pByte-3) = *pByte; 53 *pByte = temp1; 54 } 55 56 #endif 57 58 // Transports to properly encoded values - note that icc profiles does use 59 // big endian notation. 60 61 static 62 cmsInt32Number TransportValue32(cmsInt32Number Value) 63 { 64 cmsInt32Number Temp = Value; 65 66 AdjustEndianess32((cmsUInt8Number*) &Temp); 67 return Temp; 68 } 69 70 #define SigMake(a,b,c,d) \ 71 ( ( ((int) ((unsigned char) (a))) << 24) | \ 72 ( ((int) ((unsigned char) (b))) << 16) | \ 73 ( ((int) ((unsigned char) (c))) << 8) | \ 74 (int) ((unsigned char) (d))) 75 76 #define TagIdConst(a, b, c, d) \ 77 ((int) SigMake ((a), (b), (c), (d))) 78 79 #define SigHead TagIdConst('h','e','a','d') 80 81 #define DT_BYTE 0 82 #define DT_SHORT 1 83 #define DT_INT 2 84 #define DT_DOUBLE 3 85 86 /* Default temp profile list size */ 87 #define DF_ICC_BUF_SIZE 32 88 89 #define ERR_MSG_SIZE 256 90 91 #ifdef _MSC_VER 92 # ifndef snprintf 93 # define snprintf _snprintf 94 # endif 95 #endif 96 97 typedef union storeID_s { /* store SProfile stuff in a Java Long */ 98 cmsHPROFILE pf; 99 cmsHTRANSFORM xf; 100 jobject jobj; 101 jlong j; 102 } storeID_t, *storeID_p; 103 104 typedef union { 105 cmsTagSignature cms; 106 jint j; 107 } TagSignature_t, *TagSignature_p; 108 109 static jfieldID Trans_profileIDs_fID; 110 static jfieldID Trans_renderType_fID; 111 static jfieldID Trans_ID_fID; 112 static jfieldID IL_isIntPacked_fID; 113 static jfieldID IL_dataType_fID; 114 static jfieldID IL_pixelType_fID; 115 static jfieldID IL_dataArray_fID; 116 static jfieldID IL_offset_fID; 117 static jfieldID IL_nextRowOffset_fID; 118 static jfieldID IL_width_fID; 119 static jfieldID IL_height_fID; 120 static jfieldID IL_imageAtOnce_fID; 121 static jfieldID PF_ID_fID; 122 123 JavaVM *javaVM; 124 125 void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode, 126 const char *errorText) { 127 JNIEnv *env; 128 char errMsg[ERR_MSG_SIZE]; 129 130 int count = snprintf(errMsg, ERR_MSG_SIZE, 131 "LCMS error %d: %s", errorCode, errorText); 132 if (count < 0 || count >= ERR_MSG_SIZE) { 133 count = ERR_MSG_SIZE - 1; 134 } 135 errMsg[count] = 0; 136 137 (*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL); 138 JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg); 139 } 140 141 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 142 javaVM = jvm; 143 144 cmsSetLogErrorHandler(errorHandler); 145 return JNI_VERSION_1_6; 146 } 147 148 void LCMS_freeTransform(JNIEnv *env, jlong ID) 149 { 150 storeID_t sTrans; 151 sTrans.j = ID; 152 /* Passed ID is always valid native ref so there is no check for zero */ 153 cmsDeleteTransform(sTrans.xf); 154 } 155 156 /* 157 * Class: sun_java2d_cmm_lcms_LCMS 158 * Method: createNativeTransform 159 * Signature: ([JI)J 160 */ 161 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform 162 (JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType, 163 jint inFormatter, jboolean isInIntPacked, 164 jint outFormatter, jboolean isOutIntPacked, jobject disposerRef) 165 { 166 cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE]; 167 cmsHPROFILE *iccArray = &_iccArray[0]; 168 storeID_t sTrans; 169 int i, j, size; 170 jlong* ids; 171 172 size = (*env)->GetArrayLength (env, profileIDs); 173 ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0); 174 175 #ifdef _LITTLE_ENDIAN 176 /* Reversing data packed into int for LE archs */ 177 if (isInIntPacked) { 178 inFormatter ^= DOSWAP_SH(1); 179 } 180 if (isOutIntPacked) { 181 outFormatter ^= DOSWAP_SH(1); 182 } 183 #endif 184 185 if (DF_ICC_BUF_SIZE < size*2) { 186 iccArray = (cmsHPROFILE*) malloc( 187 size*2*sizeof(cmsHPROFILE)); 188 if (iccArray == NULL) { 189 J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL"); 190 return 0L; 191 } 192 } 193 194 j = 0; 195 for (i = 0; i < size; i++) { 196 cmsHPROFILE icc; 197 cmsColorSpaceSignature cs; 198 199 sTrans.j = ids[i]; 200 icc = sTrans.pf; 201 iccArray[j++] = icc; 202 203 /* Middle non-abstract profiles should be doubled before passing to 204 * the cmsCreateMultiprofileTransform function 205 */ 206 207 cs = cmsGetColorSpace(icc); 208 if (size > 2 && i != 0 && i != size - 1 && 209 cs != cmsSigXYZData && cs != cmsSigLabData) 210 { 211 iccArray[j++] = icc; 212 } 213 } 214 215 sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j, 216 inFormatter, outFormatter, renderType, 0); 217 218 (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0); 219 220 if (sTrans.xf == NULL) { 221 J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: " 222 "sTrans.xf == NULL"); 223 JNU_ThrowByName(env, "java/awt/color/CMMException", 224 "Cannot get color transform"); 225 } else { 226 Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j); 227 } 228 229 if (iccArray != &_iccArray[0]) { 230 free(iccArray); 231 } 232 return sTrans.j; 233 } 234 235 236 /* 237 * Class: sun_java2d_cmm_lcms_LCMS 238 * Method: loadProfile 239 * Signature: ([B)J 240 */ 241 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative 242 (JNIEnv *env, jobject obj, jbyteArray data) 243 { 244 jbyte* dataArray; 245 jint dataSize; 246 storeID_t sProf; 247 248 if (JNU_IsNull(env, data)) { 249 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 250 return 0L; 251 } 252 253 dataArray = (*env)->GetByteArrayElements (env, data, 0); 254 dataSize = (*env)->GetArrayLength (env, data); 255 256 if (dataArray == NULL) { 257 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 258 return 0L; 259 } 260 261 sProf.pf = cmsOpenProfileFromMem((const void *)dataArray, 262 (cmsUInt32Number) dataSize); 263 264 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 265 266 if (sProf.pf == NULL) { 267 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 268 } else { 269 /* Sanity check: try to save the profile in order 270 * to force basic validation. 271 */ 272 cmsUInt32Number pfSize = 0; 273 if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) || 274 pfSize < sizeof(cmsICCHeader)) 275 { 276 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 277 } 278 } 279 280 return sProf.j; 281 } 282 283 /* 284 * Class: sun_java2d_cmm_lcms_LCMS 285 * Method: freeProfile 286 * Signature: (J)V 287 */ 288 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative 289 (JNIEnv *env, jobject obj, jlong id) 290 { 291 storeID_t sProf; 292 293 sProf.j = id; 294 if (cmsCloseProfile(sProf.pf) == 0) { 295 J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)" 296 "== 0", id); 297 JNU_ThrowByName(env, "java/awt/color/CMMException", 298 "Cannot close profile"); 299 } 300 301 } 302 303 /* 304 * Class: sun_java2d_cmm_lcms_LCMS 305 * Method: getProfileSize 306 * Signature: (J)I 307 */ 308 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize 309 (JNIEnv *env, jobject obj, jlong id) 310 { 311 storeID_t sProf; 312 cmsUInt32Number pfSize = 0; 313 sProf.j = id; 314 315 if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) { 316 return (jint)pfSize; 317 } else { 318 JNU_ThrowByName(env, "java/awt/color/CMMException", 319 "Can not access specified profile."); 320 return -1; 321 } 322 } 323 324 /* 325 * Class: sun_java2d_cmm_lcms_LCMS 326 * Method: getProfileData 327 * Signature: (J[B)V 328 */ 329 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData 330 (JNIEnv *env, jobject obj, jlong id, jbyteArray data) 331 { 332 storeID_t sProf; 333 jint size; 334 jbyte* dataArray; 335 cmsUInt32Number pfSize = 0; 336 cmsBool status; 337 338 sProf.j = id; 339 340 // determine actual profile size 341 if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) { 342 JNU_ThrowByName(env, "java/awt/color/CMMException", 343 "Can not access specified profile."); 344 return; 345 } 346 347 // verify java buffer capacity 348 size = (*env)->GetArrayLength(env, data); 349 if (0 >= size || pfSize > (cmsUInt32Number)size) { 350 JNU_ThrowByName(env, "java/awt/color/CMMException", 351 "Insufficient buffer capacity."); 352 return; 353 } 354 355 dataArray = (*env)->GetByteArrayElements (env, data, 0); 356 357 status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize); 358 359 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 360 361 if (!status) { 362 JNU_ThrowByName(env, "java/awt/color/CMMException", 363 "Can not access specified profile."); 364 return; 365 } 366 } 367 368 /* Get profile header info */ 369 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); 370 static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); 371 static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size); 372 373 /* 374 * Class: sun_java2d_cmm_lcms_LCMS 375 * Method: getTagSize 376 * Signature: (JI)I 377 */ 378 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize 379 (JNIEnv *env, jobject obj, jlong id, jint tagSig) 380 { 381 storeID_t sProf; 382 TagSignature_t sig; 383 jint result = -1; 384 385 sProf.j = id; 386 sig.j = tagSig; 387 388 if (tagSig == SigHead) { 389 result = sizeof(cmsICCHeader); 390 } else { 391 if (cmsIsTag(sProf.pf, sig.cms)) { 392 result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); 393 } else { 394 JNU_ThrowByName(env, "java/awt/color/CMMException", 395 "ICC profile tag not found"); 396 } 397 } 398 399 return result; 400 } 401 402 /* 403 * Class: sun_java2d_cmm_lcms_LCMS 404 * Method: getTagData 405 * Signature: (JI[B)V 406 */ 407 JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative 408 (JNIEnv *env, jobject obj, jlong id, jint tagSig) 409 { 410 storeID_t sProf; 411 TagSignature_t sig; 412 cmsInt32Number tagSize; 413 414 jbyte* dataArray = NULL; 415 jbyteArray data = NULL; 416 417 jint bufSize; 418 419 sProf.j = id; 420 sig.j = tagSig; 421 422 if (tagSig == SigHead) { 423 cmsBool status; 424 425 // allocate java array 426 data = (*env)->NewByteArray(env, sizeof(cmsICCHeader)); 427 428 if (data == NULL) { 429 JNU_ThrowByName(env, "java/awt/color/CMMException", 430 "Unable to allocate buffer"); 431 return NULL; 432 } 433 434 dataArray = (*env)->GetByteArrayElements (env, data, 0); 435 436 if (dataArray == NULL) { 437 JNU_ThrowByName(env, "java/awt/color/CMMException", 438 "Unable to get buffer"); 439 return; 440 } 441 442 status = _getHeaderInfo(sProf.pf, dataArray, bufSize); 443 444 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 445 446 if (!status) { 447 JNU_ThrowByName(env, "java/awt/color/CMMException", 448 "ICC Profile header not found"); 449 return NULL; 450 } 451 452 return data; 453 } 454 455 if (cmsIsTag(sProf.pf, sig.cms)) { 456 tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); 457 } else { 458 JNU_ThrowByName(env, "java/awt/color/CMMException", 459 "ICC profile tag not found"); 460 return NULL; 461 } 462 463 // allocate java array 464 data = (*env)->NewByteArray(env, tagSize); 465 if (data == NULL) { 466 JNU_ThrowByName(env, "java/awt/color/CMMException", 467 "Unable to allocate buffer"); 468 return NULL; 469 } 470 471 dataArray = (*env)->GetByteArrayElements (env, data, 0); 472 473 if (dataArray == NULL) { 474 JNU_ThrowByName(env, "java/awt/color/CMMException", 475 "Unable to get buffer"); 476 return NULL; 477 } 478 479 bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize); 480 481 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 482 483 if (bufSize != tagSize) { 484 JNU_ThrowByName(env, "java/awt/color/CMMException", 485 "Can not get tag data."); 486 return NULL; 487 } 488 return data; 489 } 490 491 /* 492 * Class: sun_java2d_cmm_lcms_LCMS 493 * Method: setTagData 494 * Signature: (JI[B)V 495 */ 496 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative 497 (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) 498 { 499 storeID_t sProf; 500 TagSignature_t sig; 501 cmsBool status; 502 jbyte* dataArray; 503 int tagSize; 504 505 sProf.j = id; 506 sig.j = tagSig; 507 508 if (JNU_IsNull(env, data)) { 509 JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); 510 return; 511 } 512 513 tagSize =(*env)->GetArrayLength(env, data); 514 515 dataArray = (*env)->GetByteArrayElements(env, data, 0); 516 517 if (dataArray == NULL) { 518 JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); 519 return; 520 } 521 522 if (tagSig == SigHead) { 523 status = _setHeaderInfo(sProf.pf, dataArray, tagSize); 524 } else { 525 status = _writeCookedTag(sProf.pf, sig.cms, dataArray, tagSize); 526 } 527 528 (*env)->ReleaseByteArrayElements(env, data, dataArray, 0); 529 530 if (!status) { 531 JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); 532 } 533 } 534 535 void* getILData (JNIEnv *env, jobject img, jint* pDataType, 536 jobject* pDataObject) { 537 void* result = NULL; 538 *pDataType = (*env)->GetIntField (env, img, IL_dataType_fID); 539 *pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID); 540 switch (*pDataType) { 541 case DT_BYTE: 542 result = (*env)->GetByteArrayElements (env, *pDataObject, 0); 543 break; 544 case DT_SHORT: 545 result = (*env)->GetShortArrayElements (env, *pDataObject, 0); 546 break; 547 case DT_INT: 548 result = (*env)->GetIntArrayElements (env, *pDataObject, 0); 549 break; 550 case DT_DOUBLE: 551 result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0); 552 break; 553 } 554 555 return result; 556 } 557 558 void releaseILData (JNIEnv *env, void* pData, jint dataType, 559 jobject dataObject) { 560 switch (dataType) { 561 case DT_BYTE: 562 (*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0); 563 break; 564 case DT_SHORT: 565 (*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0); 566 break; 567 case DT_INT: 568 (*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0); 569 break; 570 case DT_DOUBLE: 571 (*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData, 572 0); 573 break; 574 } 575 } 576 577 /* 578 * Class: sun_java2d_cmm_lcms_LCMS 579 * Method: colorConvert 580 * Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V 581 */ 582 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert 583 (JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst) 584 { 585 storeID_t sTrans; 586 int srcDType, dstDType; 587 int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset; 588 int width, height, i; 589 void* inputBuffer; 590 void* outputBuffer; 591 char* inputRow; 592 char* outputRow; 593 jobject srcData, dstData; 594 jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE; 595 596 srcOffset = (*env)->GetIntField (env, src, IL_offset_fID); 597 srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID); 598 dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID); 599 dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID); 600 width = (*env)->GetIntField (env, src, IL_width_fID); 601 height = (*env)->GetIntField (env, src, IL_height_fID); 602 603 srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID); 604 dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID); 605 606 sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID); 607 608 if (sTrans.xf == NULL) { 609 J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL"); 610 JNU_ThrowByName(env, "java/awt/color/CMMException", 611 "Cannot get color transform"); 612 return; 613 } 614 615 616 inputBuffer = getILData (env, src, &srcDType, &srcData); 617 618 if (inputBuffer == NULL) { 619 J2dRlsTraceLn(J2D_TRACE_ERROR, ""); 620 JNU_ThrowByName(env, "java/awt/color/CMMException", 621 "Cannot get input data"); 622 return; 623 } 624 625 outputBuffer = getILData (env, dst, &dstDType, &dstData); 626 627 if (outputBuffer == NULL) { 628 releaseILData(env, inputBuffer, srcDType, srcData); 629 JNU_ThrowByName(env, "java/awt/color/CMMException", 630 "Cannot get output data"); 631 return; 632 } 633 634 inputRow = (char*)inputBuffer + srcOffset; 635 outputRow = (char*)outputBuffer + dstOffset; 636 637 if (srcAtOnce && dstAtOnce) { 638 cmsDoTransform(sTrans.xf, inputRow, outputRow, width * height); 639 } else { 640 for (i = 0; i < height; i++) { 641 cmsDoTransform(sTrans.xf, inputRow, outputRow, width); 642 inputRow += srcNextRowOffset; 643 outputRow += dstNextRowOffset; 644 } 645 } 646 647 releaseILData(env, inputBuffer, srcDType, srcData); 648 releaseILData(env, outputBuffer, dstDType, dstData); 649 } 650 651 /* 652 * Class: sun_java2d_cmm_lcms_LCMS 653 * Method: getProfileID 654 * Signature: (Ljava/awt/color/ICC_Profile;)J 655 */ 656 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID 657 (JNIEnv *env, jclass cls, jobject pf) 658 { 659 return (*env)->GetLongField (env, pf, PF_ID_fID); 660 } 661 662 /* 663 * Class: sun_java2d_cmm_lcms_LCMS 664 * Method: initLCMS 665 * Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V 666 */ 667 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS 668 (JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf) 669 { 670 /* TODO: move initialization of the IDs to the static blocks of 671 * corresponding classes to avoid problems with invalidating ids by class 672 * unloading 673 */ 674 Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J"); 675 Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I"); 676 Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J"); 677 678 IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z"); 679 IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I"); 680 IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I"); 681 IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray", 682 "Ljava/lang/Object;"); 683 IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I"); 684 IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I"); 685 IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); 686 IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z"); 687 IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); 688 689 PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); 690 } 691 692 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) 693 { 694 cmsUInt32Number pfSize = 0; 695 cmsUInt8Number* pfBuffer = NULL; 696 cmsBool status = FALSE; 697 698 if (!cmsSaveProfileToMem(pf, NULL, &pfSize) || 699 pfSize < sizeof(cmsICCHeader) || 700 bufferSize < sizeof(cmsICCHeader)) 701 { 702 return FALSE; 703 } 704 705 pfBuffer = malloc(pfSize); 706 if (pfBuffer == NULL) { 707 return FALSE; 708 } 709 710 // load raw profile data into the buffer 711 if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) { 712 memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader)); 713 status = TRUE; 714 } 715 free(pfBuffer); 716 return status; 717 } 718 719 static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) 720 { 721 cmsICCHeader pfHeader = { 0 }; 722 723 if (pBuffer == NULL || bufferSize < sizeof(cmsICCHeader)) { 724 return FALSE; 725 } 726 727 memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader)); 728 729 // now set header fields, which we can access using the lcms2 public API 730 cmsSetHeaderFlags(pf, pfHeader.flags); 731 cmsSetHeaderManufacturer(pf, pfHeader.manufacturer); 732 cmsSetHeaderModel(pf, pfHeader.model); 733 cmsSetHeaderAttributes(pf, pfHeader.attributes); 734 cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID)); 735 cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent); 736 cmsSetPCS(pf, pfHeader.pcs); 737 cmsSetColorSpace(pf, pfHeader.colorSpace); 738 cmsSetDeviceClass(pf, pfHeader.deviceClass); 739 cmsSetEncodedICCversion(pf, pfHeader.version); 740 741 return TRUE; 742 } 743 744 static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, 745 cmsTagSignature sig, 746 jbyte *pData, jint size) 747 { 748 cmsBool status; 749 cmsUInt32Number pfSize = 0; 750 cmsUInt8Number* pfBuffer = NULL; 751 752 cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL); 753 if (NULL != p) { 754 cmsICCHeader hdr = { 0 }; 755 756 /* Populate the placeholder's header according to target profile */ 757 hdr.flags = cmsGetHeaderFlags(pfTarget); 758 hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget); 759 hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget); 760 hdr.model = cmsGetHeaderModel(pfTarget); 761 hdr.pcs = cmsGetPCS(pfTarget); 762 hdr.colorSpace = cmsGetColorSpace(pfTarget); 763 hdr.deviceClass = cmsGetDeviceClass(pfTarget); 764 hdr.version = cmsGetEncodedICCversion(pfTarget); 765 cmsGetHeaderAttributes(pfTarget, &hdr.attributes); 766 cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID); 767 768 cmsSetHeaderFlags(p, hdr.flags); 769 cmsSetHeaderManufacturer(p, hdr.manufacturer); 770 cmsSetHeaderModel(p, hdr.model); 771 cmsSetHeaderAttributes(p, hdr.attributes); 772 cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID)); 773 cmsSetHeaderRenderingIntent(p, hdr.renderingIntent); 774 cmsSetPCS(p, hdr.pcs); 775 cmsSetColorSpace(p, hdr.colorSpace); 776 cmsSetDeviceClass(p, hdr.deviceClass); 777 cmsSetEncodedICCversion(p, hdr.version); 778 779 780 if (cmsWriteRawTag(p, sig, pData, size)) { 781 if (cmsSaveProfileToMem(p, NULL, &pfSize)) { 782 pfBuffer = malloc(pfSize); 783 if (pfBuffer != NULL) { 784 /* load raw profile data into the buffer */ 785 if (!cmsSaveProfileToMem(p, pfBuffer, &pfSize)) { 786 free(pfBuffer); 787 pfBuffer = NULL; 788 } 789 } 790 } 791 } 792 cmsCloseProfile(p); 793 } 794 795 if (pfBuffer == NULL) { 796 return FALSE; 797 } 798 799 /* re-open the placeholder profile */ 800 p = cmsOpenProfileFromMem(pfBuffer, pfSize); 801 free(pfBuffer); 802 status = FALSE; 803 804 if (p != NULL) { 805 /* Note that pCookedTag points to internal structures of the placeholder, 806 * so this data is valid only while the placeholder is open. 807 */ 808 void *pCookedTag = cmsReadTag(p, sig); 809 if (pCookedTag != NULL) { 810 status = cmsWriteTag(pfTarget, sig, pCookedTag); 811 } 812 pCookedTag = NULL; 813 cmsCloseProfile(p); 814 } 815 return status; 816 }