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 PF_ID_fID; 121 122 JavaVM *javaVM; 123 124 void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode, 125 const char *errorText) { 126 JNIEnv *env; 127 char errMsg[ERR_MSG_SIZE]; 128 129 int count = snprintf(errMsg, ERR_MSG_SIZE, 130 "LCMS error %d: %s", errorCode, errorText); 131 if (count < 0 || count >= ERR_MSG_SIZE) { 132 count = ERR_MSG_SIZE - 1; 133 } 134 errMsg[count] = 0; 135 136 (*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL); 137 JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg); 138 } 139 140 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 141 javaVM = jvm; 142 143 cmsSetLogErrorHandler(errorHandler); 144 return JNI_VERSION_1_6; 145 } 146 147 void LCMS_freeTransform(JNIEnv *env, jlong ID) 148 { 149 storeID_t sTrans; 150 sTrans.j = ID; 151 /* Passed ID is always valid native ref so there is no check for zero */ 152 cmsDeleteTransform(sTrans.xf); 153 } 154 155 /* 156 * Class: sun_java2d_cmm_lcms_LCMS 157 * Method: createNativeTransform 158 * Signature: ([JI)J 159 */ 160 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform 161 (JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType, 162 jint inFormatter, jboolean isInIntPacked, 163 jint outFormatter, jboolean isOutIntPacked, jobject disposerRef) 164 { 165 cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE]; 166 cmsHPROFILE *iccArray = &_iccArray[0]; 167 storeID_t sTrans; 168 int i, j, size; 169 jlong* ids; 170 171 size = (*env)->GetArrayLength (env, profileIDs); 172 ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0); 173 174 #ifdef _LITTLE_ENDIAN 175 /* Reversing data packed into int for LE archs */ 176 if (isInIntPacked) { 177 inFormatter ^= DOSWAP_SH(1); 178 } 179 if (isOutIntPacked) { 180 outFormatter ^= DOSWAP_SH(1); 181 } 182 #endif 183 184 if (DF_ICC_BUF_SIZE < size*2) { 185 iccArray = (cmsHPROFILE*) malloc( 186 size*2*sizeof(cmsHPROFILE)); 187 if (iccArray == NULL) { 188 J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL"); 189 return 0L; 190 } 191 } 192 193 j = 0; 194 for (i = 0; i < size; i++) { 195 cmsHPROFILE icc; 196 cmsColorSpaceSignature cs; 197 198 sTrans.j = ids[i]; 199 icc = sTrans.pf; 200 iccArray[j++] = icc; 201 202 /* Middle non-abstract profiles should be doubled before passing to 203 * the cmsCreateMultiprofileTransform function 204 */ 205 206 cs = cmsGetColorSpace(icc); 207 if (size > 2 && i != 0 && i != size - 1 && 208 cs != cmsSigXYZData && cs != cmsSigLabData) 209 { 210 iccArray[j++] = icc; 211 } 212 } 213 214 sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j, 215 inFormatter, outFormatter, renderType, 0); 216 217 (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0); 218 219 if (sTrans.xf == NULL) { 220 J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: " 221 "sTrans.xf == NULL"); 222 JNU_ThrowByName(env, "java/awt/color/CMMException", 223 "Cannot get color transform"); 224 } else { 225 Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j); 226 } 227 228 if (iccArray != &_iccArray[0]) { 229 free(iccArray); 230 } 231 return sTrans.j; 232 } 233 234 235 /* 236 * Class: sun_java2d_cmm_lcms_LCMS 237 * Method: loadProfile 238 * Signature: ([B)J 239 */ 240 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile 241 (JNIEnv *env, jobject obj, jbyteArray data) 242 { 243 jbyte* dataArray; 244 jint dataSize; 245 storeID_t sProf; 246 247 if (JNU_IsNull(env, data)) { 248 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 249 return 0L; 250 } 251 252 dataArray = (*env)->GetByteArrayElements (env, data, 0); 253 dataSize = (*env)->GetArrayLength (env, data); 254 255 if (dataArray == NULL) { 256 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 257 return 0L; 258 } 259 260 sProf.pf = cmsOpenProfileFromMem((const void *)dataArray, 261 (cmsUInt32Number) dataSize); 262 263 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 264 265 if (sProf.pf == NULL) { 266 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 267 } else { 268 /* Sanity check: try to save the profile in order 269 * to force basic validation. 270 */ 271 cmsUInt32Number pfSize = 0; 272 if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) || 273 pfSize < sizeof(cmsICCHeader)) 274 { 275 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 276 } 277 } 278 279 return sProf.j; 280 } 281 282 /* 283 * Class: sun_java2d_cmm_lcms_LCMS 284 * Method: freeProfile 285 * Signature: (J)V 286 */ 287 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfile 288 (JNIEnv *env, jobject obj, jlong id) 289 { 290 storeID_t sProf; 291 292 sProf.j = id; 293 if (cmsCloseProfile(sProf.pf) == 0) { 294 J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)" 295 "== 0", id); 296 JNU_ThrowByName(env, "java/awt/color/CMMException", 297 "Cannot close profile"); 298 } 299 300 } 301 302 /* 303 * Class: sun_java2d_cmm_lcms_LCMS 304 * Method: getProfileSize 305 * Signature: (J)I 306 */ 307 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize 308 (JNIEnv *env, jobject obj, jlong id) 309 { 310 storeID_t sProf; 311 cmsUInt32Number pfSize = 0; 312 sProf.j = id; 313 314 if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) { 315 return (jint)pfSize; 316 } else { 317 JNU_ThrowByName(env, "java/awt/color/CMMException", 318 "Can not access specified profile."); 319 return -1; 320 } 321 } 322 323 /* 324 * Class: sun_java2d_cmm_lcms_LCMS 325 * Method: getProfileData 326 * Signature: (J[B)V 327 */ 328 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData 329 (JNIEnv *env, jobject obj, jlong id, jbyteArray data) 330 { 331 storeID_t sProf; 332 jint size; 333 jbyte* dataArray; 334 cmsUInt32Number pfSize = 0; 335 cmsBool status; 336 337 sProf.j = id; 338 339 // determine actual profile size 340 if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) { 341 JNU_ThrowByName(env, "java/awt/color/CMMException", 342 "Can not access specified profile."); 343 return; 344 } 345 346 // verify java buffer capacity 347 size = (*env)->GetArrayLength(env, data); 348 if (0 >= size || pfSize > (cmsUInt32Number)size) { 349 JNU_ThrowByName(env, "java/awt/color/CMMException", 350 "Insufficient buffer capacity."); 351 return; 352 } 353 354 dataArray = (*env)->GetByteArrayElements (env, data, 0); 355 356 status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize); 357 358 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 359 360 if (!status) { 361 JNU_ThrowByName(env, "java/awt/color/CMMException", 362 "Can not access specified profile."); 363 return; 364 } 365 } 366 367 /* Get profile header info */ 368 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); 369 static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); 370 static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size); 371 372 /* 373 * Class: sun_java2d_cmm_lcms_LCMS 374 * Method: getTagSize 375 * Signature: (JI)I 376 */ 377 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize 378 (JNIEnv *env, jobject obj, jlong id, jint tagSig) 379 { 380 storeID_t sProf; 381 TagSignature_t sig; 382 jint result = -1; 383 384 sProf.j = id; 385 sig.j = tagSig; 386 387 if (tagSig == SigHead) { 388 result = sizeof(cmsICCHeader); 389 } else { 390 if (cmsIsTag(sProf.pf, sig.cms)) { 391 result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); 392 } else { 393 JNU_ThrowByName(env, "java/awt/color/CMMException", 394 "ICC profile tag not found"); 395 } 396 } 397 398 return result; 399 } 400 401 /* 402 * Class: sun_java2d_cmm_lcms_LCMS 403 * Method: getTagData 404 * Signature: (JI[B)V 405 */ 406 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData 407 (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) 408 { 409 storeID_t sProf; 410 TagSignature_t sig; 411 cmsInt32Number tagSize; 412 413 jbyte* dataArray; 414 jint bufSize; 415 416 sProf.j = id; 417 sig.j = tagSig; 418 419 if (tagSig == SigHead) { 420 cmsBool status; 421 422 bufSize =(*env)->GetArrayLength(env, data); 423 424 if (bufSize < sizeof(cmsICCHeader)) { 425 JNU_ThrowByName(env, "java/awt/color/CMMException", 426 "Insufficient buffer capacity"); 427 return; 428 } 429 430 dataArray = (*env)->GetByteArrayElements (env, data, 0); 431 432 if (dataArray == NULL) { 433 JNU_ThrowByName(env, "java/awt/color/CMMException", 434 "Unable to get buffer"); 435 return; 436 } 437 438 status = _getHeaderInfo(sProf.pf, dataArray, bufSize); 439 440 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 441 442 if (!status) { 443 JNU_ThrowByName(env, "java/awt/color/CMMException", 444 "ICC Profile header not found"); 445 } 446 447 return; 448 } 449 450 if (cmsIsTag(sProf.pf, sig.cms)) { 451 tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); 452 } else { 453 JNU_ThrowByName(env, "java/awt/color/CMMException", 454 "ICC profile tag not found"); 455 return; 456 } 457 458 // verify data buffer capacity 459 bufSize = (*env)->GetArrayLength(env, data); 460 461 if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) { 462 JNU_ThrowByName(env, "java/awt/color/CMMException", 463 "Insufficient buffer capacity."); 464 return; 465 } 466 467 dataArray = (*env)->GetByteArrayElements (env, data, 0); 468 469 if (dataArray == NULL) { 470 JNU_ThrowByName(env, "java/awt/color/CMMException", 471 "Unable to get buffer"); 472 return; 473 } 474 475 bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize); 476 477 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 478 479 if (bufSize != tagSize) { 480 JNU_ThrowByName(env, "java/awt/color/CMMException", 481 "Can not get tag data."); 482 } 483 return; 484 } 485 486 /* 487 * Class: sun_java2d_cmm_lcms_LCMS 488 * Method: setTagData 489 * Signature: (JI[B)V 490 */ 491 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData 492 (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) 493 { 494 storeID_t sProf; 495 TagSignature_t sig; 496 cmsBool status; 497 jbyte* dataArray; 498 int tagSize; 499 500 sProf.j = id; 501 sig.j = tagSig; 502 503 if (JNU_IsNull(env, data)) { 504 JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); 505 return; 506 } 507 508 tagSize =(*env)->GetArrayLength(env, data); 509 510 dataArray = (*env)->GetByteArrayElements(env, data, 0); 511 512 if (dataArray == NULL) { 513 JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); 514 return; 515 } 516 517 if (tagSig == SigHead) { 518 status = _setHeaderInfo(sProf.pf, dataArray, tagSize); 519 } else { 520 status = _writeCookedTag(sProf.pf, sig.cms, dataArray, tagSize); 521 } 522 523 (*env)->ReleaseByteArrayElements(env, data, dataArray, 0); 524 525 if (!status) { 526 JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); 527 } 528 } 529 530 void* getILData (JNIEnv *env, jobject img, jint* pDataType, 531 jobject* pDataObject) { 532 void* result = NULL; 533 *pDataType = (*env)->GetIntField (env, img, IL_dataType_fID); 534 *pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID); 535 switch (*pDataType) { 536 case DT_BYTE: 537 result = (*env)->GetByteArrayElements (env, *pDataObject, 0); 538 break; 539 case DT_SHORT: 540 result = (*env)->GetShortArrayElements (env, *pDataObject, 0); 541 break; 542 case DT_INT: 543 result = (*env)->GetIntArrayElements (env, *pDataObject, 0); 544 break; 545 case DT_DOUBLE: 546 result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0); 547 break; 548 } 549 550 return result; 551 } 552 553 void releaseILData (JNIEnv *env, void* pData, jint dataType, 554 jobject dataObject) { 555 switch (dataType) { 556 case DT_BYTE: 557 (*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0); 558 break; 559 case DT_SHORT: 560 (*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0); 561 break; 562 case DT_INT: 563 (*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0); 564 break; 565 case DT_DOUBLE: 566 (*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData, 567 0); 568 break; 569 } 570 } 571 572 /* 573 * Class: sun_java2d_cmm_lcms_LCMS 574 * Method: colorConvert 575 * Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V 576 */ 577 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert 578 (JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst) 579 { 580 storeID_t sTrans; 581 int srcDType, dstDType; 582 int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset; 583 int width, height, i; 584 void* inputBuffer; 585 void* outputBuffer; 586 char* inputRow; 587 char* outputRow; 588 jobject srcData, dstData; 589 590 srcOffset = (*env)->GetIntField (env, src, IL_offset_fID); 591 srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID); 592 dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID); 593 dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID); 594 width = (*env)->GetIntField (env, src, IL_width_fID); 595 height = (*env)->GetIntField (env, src, IL_height_fID); 596 597 sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID); 598 599 if (sTrans.xf == NULL) { 600 J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL"); 601 JNU_ThrowByName(env, "java/awt/color/CMMException", 602 "Cannot get color transform"); 603 return; 604 } 605 606 607 inputBuffer = getILData (env, src, &srcDType, &srcData); 608 609 if (inputBuffer == NULL) { 610 J2dRlsTraceLn(J2D_TRACE_ERROR, ""); 611 JNU_ThrowByName(env, "java/awt/color/CMMException", 612 "Cannot get input data"); 613 return; 614 } 615 616 outputBuffer = getILData (env, dst, &dstDType, &dstData); 617 618 if (outputBuffer == NULL) { 619 releaseILData(env, inputBuffer, srcDType, srcData); 620 JNU_ThrowByName(env, "java/awt/color/CMMException", 621 "Cannot get output data"); 622 return; 623 } 624 625 inputRow = (char*)inputBuffer + srcOffset; 626 outputRow = (char*)outputBuffer + dstOffset; 627 628 for (i = 0; i < height; i++) { 629 cmsDoTransform(sTrans.xf, inputRow, outputRow, width); 630 inputRow += srcNextRowOffset; 631 outputRow += dstNextRowOffset; 632 } 633 634 releaseILData(env, inputBuffer, srcDType, srcData); 635 releaseILData(env, outputBuffer, dstDType, dstData); 636 } 637 638 /* 639 * Class: sun_java2d_cmm_lcms_LCMS 640 * Method: getProfileID 641 * Signature: (Ljava/awt/color/ICC_Profile;)J 642 */ 643 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID 644 (JNIEnv *env, jclass cls, jobject pf) 645 { 646 return (*env)->GetLongField (env, pf, PF_ID_fID); 647 } 648 649 /* 650 * Class: sun_java2d_cmm_lcms_LCMS 651 * Method: initLCMS 652 * Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V 653 */ 654 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS 655 (JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf) 656 { 657 /* TODO: move initialization of the IDs to the static blocks of 658 * corresponding classes to avoid problems with invalidating ids by class 659 * unloading 660 */ 661 Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J"); 662 Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I"); 663 Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J"); 664 665 IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z"); 666 IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I"); 667 IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I"); 668 IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray", 669 "Ljava/lang/Object;"); 670 IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I"); 671 IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I"); 672 IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); 673 IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); 674 675 PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); 676 } 677 678 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) 679 { 680 cmsUInt32Number pfSize = 0; 681 cmsUInt8Number* pfBuffer = NULL; 682 cmsBool status = FALSE; 683 684 if (!cmsSaveProfileToMem(pf, NULL, &pfSize) || 685 pfSize < sizeof(cmsICCHeader) || 686 bufferSize < sizeof(cmsICCHeader)) 687 { 688 return FALSE; 689 } 690 691 pfBuffer = malloc(pfSize); 692 if (pfBuffer == NULL) { 693 return FALSE; 694 } 695 696 // load raw profile data into the buffer 697 if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) { 698 memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader)); 699 status = TRUE; 700 } 701 free(pfBuffer); 702 return status; 703 } 704 705 static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) 706 { 707 cmsICCHeader pfHeader = { 0 }; 708 709 if (pBuffer == NULL || bufferSize < sizeof(cmsICCHeader)) { 710 return FALSE; 711 } 712 713 memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader)); 714 715 // now set header fields, which we can access using the lcms2 public API 716 cmsSetHeaderFlags(pf, pfHeader.flags); 717 cmsSetHeaderManufacturer(pf, pfHeader.manufacturer); 718 cmsSetHeaderModel(pf, pfHeader.model); 719 cmsSetHeaderAttributes(pf, pfHeader.attributes); 720 cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID)); 721 cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent); 722 cmsSetPCS(pf, pfHeader.pcs); 723 cmsSetColorSpace(pf, pfHeader.colorSpace); 724 cmsSetDeviceClass(pf, pfHeader.deviceClass); 725 cmsSetEncodedICCversion(pf, pfHeader.version); 726 727 return TRUE; 728 } 729 730 static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, 731 cmsTagSignature sig, 732 jbyte *pData, jint size) 733 { 734 cmsBool status; 735 cmsUInt32Number pfSize = 0; 736 cmsUInt8Number* pfBuffer = NULL; 737 738 cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL); 739 if (NULL != p) { 740 cmsICCHeader hdr = { 0 }; 741 742 /* Populate the placeholder's header according to target profile */ 743 hdr.flags = cmsGetHeaderFlags(pfTarget); 744 hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget); 745 hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget); 746 hdr.model = cmsGetHeaderModel(pfTarget); 747 hdr.pcs = cmsGetPCS(pfTarget); 748 hdr.colorSpace = cmsGetColorSpace(pfTarget); 749 hdr.deviceClass = cmsGetDeviceClass(pfTarget); 750 hdr.version = cmsGetEncodedICCversion(pfTarget); 751 cmsGetHeaderAttributes(pfTarget, &hdr.attributes); 752 cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID); 753 754 cmsSetHeaderFlags(p, hdr.flags); 755 cmsSetHeaderManufacturer(p, hdr.manufacturer); 756 cmsSetHeaderModel(p, hdr.model); 757 cmsSetHeaderAttributes(p, hdr.attributes); 758 cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID)); 759 cmsSetHeaderRenderingIntent(p, hdr.renderingIntent); 760 cmsSetPCS(p, hdr.pcs); 761 cmsSetColorSpace(p, hdr.colorSpace); 762 cmsSetDeviceClass(p, hdr.deviceClass); 763 cmsSetEncodedICCversion(p, hdr.version); 764 765 766 if (cmsWriteRawTag(p, sig, pData, size)) { 767 if (cmsSaveProfileToMem(p, NULL, &pfSize)) { 768 pfBuffer = malloc(pfSize); 769 if (pfBuffer != NULL) { 770 /* load raw profile data into the buffer */ 771 if (!cmsSaveProfileToMem(p, pfBuffer, &pfSize)) { 772 free(pfBuffer); 773 pfBuffer = NULL; 774 } 775 } 776 } 777 } 778 cmsCloseProfile(p); 779 } 780 781 if (pfBuffer == NULL) { 782 return FALSE; 783 } 784 785 /* re-open the placeholder profile */ 786 p = cmsOpenProfileFromMem(pfBuffer, pfSize); 787 free(pfBuffer); 788 status = FALSE; 789 790 if (p != NULL) { 791 /* Note that pCookedTag points to internal structures of the placeholder, 792 * so this data is valid only while the placeholder is open. 793 */ 794 void *pCookedTag = cmsReadTag(p, sig); 795 if (pCookedTag != NULL) { 796 status = cmsWriteTag(pfTarget, sig, pCookedTag); 797 } 798 pCookedTag = NULL; 799 cmsCloseProfile(p); 800 } 801 return status; 802 }