1 /* 2 * Copyright (c) 2007, 2010, 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, jint outFormatter, jobject disposerRef) 163 { 164 cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE]; 165 cmsHPROFILE *iccArray = &_iccArray[0]; 166 storeID_t sTrans; 167 int i, j, size; 168 jlong* ids; 169 170 size = (*env)->GetArrayLength (env, profileIDs); 171 ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0); 172 173 if (DF_ICC_BUF_SIZE < size*2) { 174 iccArray = (cmsHPROFILE*) malloc( 175 size*2*sizeof(cmsHPROFILE)); 176 if (iccArray == NULL) { 177 J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL"); 178 return 0L; 179 } 180 } 181 182 j = 0; 183 for (i = 0; i < size; i++) { 184 cmsHPROFILE icc; 185 cmsColorSpaceSignature cs; 186 187 sTrans.j = ids[i]; 188 icc = sTrans.pf; 189 iccArray[j++] = icc; 190 191 /* Middle non-abstract profiles should be doubled before passing to 192 * the cmsCreateMultiprofileTransform function 193 */ 194 195 cs = cmsGetColorSpace(icc); 196 if (size > 2 && i != 0 && i != size - 1 && 197 cs != cmsSigXYZData && cs != cmsSigLabData) 198 { 199 iccArray[j++] = icc; 200 } 201 } 202 203 sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j, 204 inFormatter, outFormatter, renderType, 0); 205 206 (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0); 207 208 if (sTrans.xf == NULL) { 209 J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: " 210 "sTrans.xf == NULL"); 211 JNU_ThrowByName(env, "java/awt/color/CMMException", 212 "Cannot get color transform"); 213 } else { 214 Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j); 215 } 216 217 if (iccArray != &_iccArray[0]) { 218 free(iccArray); 219 } 220 return sTrans.j; 221 } 222 223 224 /* 225 * Class: sun_java2d_cmm_lcms_LCMS 226 * Method: loadProfile 227 * Signature: ([B)J 228 */ 229 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile 230 (JNIEnv *env, jobject obj, jbyteArray data) 231 { 232 jbyte* dataArray; 233 jint dataSize; 234 storeID_t sProf; 235 236 dataArray = (*env)->GetByteArrayElements (env, data, 0); 237 dataSize = (*env)->GetArrayLength (env, data); 238 239 sProf.pf = cmsOpenProfileFromMem((const void *)dataArray, 240 (cmsUInt32Number) dataSize); 241 242 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 243 244 if (sProf.pf == NULL) { 245 JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); 246 } 247 248 return sProf.j; 249 } 250 251 /* 252 * Class: sun_java2d_cmm_lcms_LCMS 253 * Method: freeProfile 254 * Signature: (J)V 255 */ 256 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfile 257 (JNIEnv *env, jobject obj, jlong id) 258 { 259 storeID_t sProf; 260 261 sProf.j = id; 262 if (cmsCloseProfile(sProf.pf) == 0) { 263 J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)" 264 "== 0", id); 265 JNU_ThrowByName(env, "java/awt/color/CMMException", 266 "Cannot close profile"); 267 } 268 269 } 270 271 /* 272 * Class: sun_java2d_cmm_lcms_LCMS 273 * Method: getProfileSize 274 * Signature: (J)I 275 */ 276 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize 277 (JNIEnv *env, jobject obj, jlong id) 278 { 279 storeID_t sProf; 280 cmsUInt32Number pfSize = 0; 281 sProf.j = id; 282 283 if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) { 284 return (jint)pfSize; 285 } else { 286 JNU_ThrowByName(env, "java/awt/color/CMMException", 287 "Can not access specified profile."); 288 return -1; 289 } 290 } 291 292 /* 293 * Class: sun_java2d_cmm_lcms_LCMS 294 * Method: getProfileData 295 * Signature: (J[B)V 296 */ 297 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData 298 (JNIEnv *env, jobject obj, jlong id, jbyteArray data) 299 { 300 storeID_t sProf; 301 jint size; 302 jbyte* dataArray; 303 cmsUInt32Number pfSize = 0; 304 cmsBool status; 305 306 sProf.j = id; 307 308 // determine actual profile size 309 if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) { 310 JNU_ThrowByName(env, "java/awt/color/CMMException", 311 "Can not access specified profile."); 312 return; 313 } 314 315 // verify java buffer capacity 316 size = (*env)->GetArrayLength(env, data); 317 if (0 >= size || pfSize > (cmsUInt32Number)size) { 318 JNU_ThrowByName(env, "java/awt/color/CMMException", 319 "Insufficient buffer capacity."); 320 return; 321 } 322 323 dataArray = (*env)->GetByteArrayElements (env, data, 0); 324 325 status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize); 326 327 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 328 329 if (!status) { 330 JNU_ThrowByName(env, "java/awt/color/CMMException", 331 "Can not access specified profile."); 332 return; 333 } 334 } 335 336 /* Get profile header info */ 337 cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); 338 cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); 339 340 /* 341 * Class: sun_java2d_cmm_lcms_LCMS 342 * Method: getTagSize 343 * Signature: (JI)I 344 */ 345 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize 346 (JNIEnv *env, jobject obj, jlong id, jint tagSig) 347 { 348 storeID_t sProf; 349 TagSignature_t sig; 350 jint result = -1; 351 352 sProf.j = id; 353 sig.j = tagSig; 354 355 if (tagSig == SigHead) { 356 result = sizeof(cmsICCHeader); 357 } else { 358 if (cmsIsTag(sProf.pf, sig.cms)) { 359 result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); 360 } else { 361 JNU_ThrowByName(env, "java/awt/color/CMMException", 362 "ICC profile tag not found"); 363 } 364 } 365 366 return result; 367 } 368 369 /* 370 * Class: sun_java2d_cmm_lcms_LCMS 371 * Method: getTagData 372 * Signature: (JI[B)V 373 */ 374 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData 375 (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) 376 { 377 storeID_t sProf; 378 TagSignature_t sig; 379 cmsInt32Number tagSize; 380 381 jbyte* dataArray; 382 jint bufSize; 383 384 sProf.j = id; 385 sig.j = tagSig; 386 387 if (tagSig == SigHead) { 388 cmsBool status; 389 390 bufSize =(*env)->GetArrayLength(env, data); 391 392 if (bufSize < sizeof(cmsICCHeader)) { 393 JNU_ThrowByName(env, "java/awt/color/CMMException", 394 "Insufficient buffer capacity"); 395 return; 396 } 397 398 dataArray = (*env)->GetByteArrayElements (env, data, 0); 399 400 if (dataArray == NULL) { 401 JNU_ThrowByName(env, "java/awt/color/CMMException", 402 "Unable to get buffer"); 403 return; 404 } 405 406 status = _getHeaderInfo(sProf.pf, dataArray, bufSize); 407 408 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 409 410 if (!status) { 411 JNU_ThrowByName(env, "java/awt/color/CMMException", 412 "ICC Profile header not found"); 413 } 414 415 return; 416 } 417 418 if (cmsIsTag(sProf.pf, sig.cms)) { 419 tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); 420 } else { 421 JNU_ThrowByName(env, "java/awt/color/CMMException", 422 "ICC profile tag not found"); 423 return; 424 } 425 426 // verify data buffer capacity 427 bufSize = (*env)->GetArrayLength(env, data); 428 429 if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) { 430 JNU_ThrowByName(env, "java/awt/color/CMMException", 431 "Insufficient buffer capacity."); 432 return; 433 } 434 435 dataArray = (*env)->GetByteArrayElements (env, data, 0); 436 437 if (dataArray == NULL) { 438 JNU_ThrowByName(env, "java/awt/color/CMMException", 439 "Unable to get buffer"); 440 return; 441 } 442 443 bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize); 444 445 (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); 446 447 if (bufSize != tagSize) { 448 JNU_ThrowByName(env, "java/awt/color/CMMException", 449 "Can not get tag data."); 450 } 451 return; 452 } 453 454 /* 455 * Class: sun_java2d_cmm_lcms_LCMS 456 * Method: setTagData 457 * Signature: (JI[B)V 458 */ 459 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData 460 (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) 461 { 462 storeID_t sProf; 463 TagSignature_t sig; 464 cmsBool status; 465 jbyte* dataArray; 466 int tagSize; 467 468 sProf.j = id; 469 sig.j = tagSig; 470 471 472 tagSize =(*env)->GetArrayLength(env, data); 473 474 dataArray = (*env)->GetByteArrayElements(env, data, 0); 475 476 if (tagSig == SigHead) { 477 status = _setHeaderInfo(sProf.pf, dataArray, tagSize); 478 } else { 479 status = cmsWriteRawTag(sProf.pf, sig.cms, dataArray, tagSize); 480 } 481 482 (*env)->ReleaseByteArrayElements(env, data, dataArray, 0); 483 484 if (!status) { 485 JNU_ThrowByName(env, "java/awt/color/CMMException", 486 "Can not write tag data."); 487 } 488 } 489 490 void* getILData (JNIEnv *env, jobject img, jint* pDataType, 491 jobject* pDataObject) { 492 void* result = NULL; 493 *pDataType = (*env)->GetIntField (env, img, IL_dataType_fID); 494 *pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID); 495 switch (*pDataType) { 496 case DT_BYTE: 497 result = (*env)->GetByteArrayElements (env, *pDataObject, 0); 498 break; 499 case DT_SHORT: 500 result = (*env)->GetShortArrayElements (env, *pDataObject, 0); 501 break; 502 case DT_INT: 503 result = (*env)->GetIntArrayElements (env, *pDataObject, 0); 504 break; 505 case DT_DOUBLE: 506 result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0); 507 break; 508 } 509 510 return result; 511 } 512 513 void releaseILData (JNIEnv *env, void* pData, jint dataType, 514 jobject dataObject) { 515 switch (dataType) { 516 case DT_BYTE: 517 (*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0); 518 break; 519 case DT_SHORT: 520 (*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0); 521 break; 522 case DT_INT: 523 (*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0); 524 break; 525 case DT_DOUBLE: 526 (*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData, 527 0); 528 break; 529 } 530 } 531 532 /* 533 * Class: sun_java2d_cmm_lcms_LCMS 534 * Method: colorConvert 535 * Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V 536 */ 537 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert 538 (JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst) 539 { 540 storeID_t sTrans; 541 int inFmt, outFmt, srcDType, dstDType; 542 int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset; 543 int width, height, i; 544 void* inputBuffer; 545 void* outputBuffer; 546 char* inputRow; 547 char* outputRow; 548 jobject srcData, dstData; 549 550 inFmt = (*env)->GetIntField (env, src, IL_pixelType_fID); 551 outFmt = (*env)->GetIntField (env, dst, IL_pixelType_fID); 552 srcOffset = (*env)->GetIntField (env, src, IL_offset_fID); 553 srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID); 554 dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID); 555 dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID); 556 width = (*env)->GetIntField (env, src, IL_width_fID); 557 height = (*env)->GetIntField (env, src, IL_height_fID); 558 #ifdef _LITTLE_ENDIAN 559 /* Reversing data packed into int for LE archs */ 560 if ((*env)->GetBooleanField (env, src, IL_isIntPacked_fID) == JNI_TRUE) { 561 inFmt ^= DOSWAP_SH(1); 562 } 563 if ((*env)->GetBooleanField (env, dst, IL_isIntPacked_fID) == JNI_TRUE) { 564 outFmt ^= DOSWAP_SH(1); 565 } 566 #endif 567 sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID); 568 569 if (sTrans.xf == NULL) { 570 J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL"); 571 JNU_ThrowByName(env, "java/awt/color/CMMException", 572 "Cannot get color transform"); 573 return; 574 } 575 576 577 inputBuffer = getILData (env, src, &srcDType, &srcData); 578 579 if (inputBuffer == NULL) { 580 J2dRlsTraceLn(J2D_TRACE_ERROR, ""); 581 JNU_ThrowByName(env, "java/awt/color/CMMException", 582 "Cannot get input data"); 583 return; 584 } 585 586 outputBuffer = getILData (env, dst, &dstDType, &dstData); 587 588 if (outputBuffer == NULL) { 589 releaseILData(env, inputBuffer, srcDType, srcData); 590 JNU_ThrowByName(env, "java/awt/color/CMMException", 591 "Cannot get output data"); 592 return; 593 } 594 595 inputRow = (char*)inputBuffer + srcOffset; 596 outputRow = (char*)outputBuffer + dstOffset; 597 598 for (i = 0; i < height; i++) { 599 cmsDoTransform(sTrans.xf, inputRow, outputRow, width); 600 inputRow += srcNextRowOffset; 601 outputRow += dstNextRowOffset; 602 } 603 604 releaseILData(env, inputBuffer, srcDType, srcData); 605 releaseILData(env, outputBuffer, dstDType, dstData); 606 } 607 608 /* 609 * Class: sun_java2d_cmm_lcms_LCMS 610 * Method: getProfileID 611 * Signature: (Ljava/awt/color/ICC_Profile;)J 612 */ 613 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID 614 (JNIEnv *env, jclass cls, jobject pf) 615 { 616 return (*env)->GetLongField (env, pf, PF_ID_fID); 617 } 618 619 /* 620 * Class: sun_java2d_cmm_lcms_LCMS 621 * Method: initLCMS 622 * Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V 623 */ 624 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS 625 (JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf) 626 { 627 /* TODO: move initialization of the IDs to the static blocks of 628 * corresponding classes to avoid problems with invalidating ids by class 629 * unloading 630 */ 631 Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J"); 632 Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I"); 633 Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J"); 634 635 IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z"); 636 IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I"); 637 IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I"); 638 IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray", 639 "Ljava/lang/Object;"); 640 IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I"); 641 IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I"); 642 IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); 643 IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); 644 645 PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); 646 } 647 648 cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) 649 { 650 cmsUInt32Number pfSize = 0; 651 cmsUInt8Number* pfBuffer = NULL; 652 cmsBool status = FALSE; 653 654 if (!cmsSaveProfileToMem(pf, NULL, &pfSize) || 655 pfSize < sizeof(cmsICCHeader) || 656 bufferSize < sizeof(cmsICCHeader)) 657 { 658 return FALSE; 659 } 660 661 pfBuffer = malloc(pfSize); 662 if (pfBuffer == NULL) { 663 return FALSE; 664 } 665 666 // load raw profile data into the buffer 667 if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) { 668 memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader)); 669 status = TRUE; 670 } 671 free(pfBuffer); 672 return status; 673 } 674 675 cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) 676 { 677 cmsICCHeader pfHeader = { 0 }; 678 679 if (pBuffer == NULL || bufferSize < sizeof(cmsICCHeader)) { 680 return FALSE; 681 } 682 683 memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader)); 684 685 // now set header fields, which we can access using the lcms2 public API 686 cmsSetHeaderFlags(pf, pfHeader.flags); 687 cmsSetHeaderManufacturer(pf, pfHeader.manufacturer); 688 cmsSetHeaderModel(pf, pfHeader.model); 689 cmsSetHeaderAttributes(pf, pfHeader.attributes); 690 cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID)); 691 cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent); 692 cmsSetPCS(pf, pfHeader.pcs); 693 cmsSetColorSpace(pf, pfHeader.colorSpace); 694 cmsSetDeviceClass(pf, pfHeader.deviceClass); 695 cmsSetEncodedICCversion(pf, pfHeader.version); 696 697 return TRUE; 698 }