Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c
38918 views
/*1* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdio.h>26#include <stdlib.h>27#include <memory.h>28#include "sun_java2d_cmm_lcms_LCMS.h"29#include "jni_util.h"30#include "Trace.h"31#include "Disposer.h"32#include "lcms2.h"33#include "jlong.h"343536#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary3738#ifdef USE_BIG_ENDIAN39#define AdjustEndianess32(a)40#else4142static43void AdjustEndianess32(cmsUInt8Number *pByte)44{45cmsUInt8Number temp1;46cmsUInt8Number temp2;4748temp1 = *pByte++;49temp2 = *pByte++;50*(pByte-1) = *pByte;51*pByte++ = temp2;52*(pByte-3) = *pByte;53*pByte = temp1;54}5556#endif5758// Transports to properly encoded values - note that icc profiles does use59// big endian notation.6061static62cmsInt32Number TransportValue32(cmsInt32Number Value)63{64cmsInt32Number Temp = Value;6566AdjustEndianess32((cmsUInt8Number*) &Temp);67return Temp;68}6970#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)))7576#define TagIdConst(a, b, c, d) \77((int) SigMake ((a), (b), (c), (d)))7879#define SigHead TagIdConst('h','e','a','d')8081#define DT_BYTE 082#define DT_SHORT 183#define DT_INT 284#define DT_DOUBLE 38586/* Default temp profile list size */87#define DF_ICC_BUF_SIZE 328889#define ERR_MSG_SIZE 2569091#ifdef _MSC_VER92# ifndef snprintf93# define snprintf _snprintf94# endif95#endif9697typedef struct lcmsProfile_s {98cmsHPROFILE pf;99} lcmsProfile_t, *lcmsProfile_p;100101typedef union {102cmsTagSignature cms;103jint j;104} TagSignature_t, *TagSignature_p;105106static jfieldID Trans_renderType_fID;107static jfieldID Trans_ID_fID;108static jfieldID IL_isIntPacked_fID;109static jfieldID IL_dataType_fID;110static jfieldID IL_pixelType_fID;111static jfieldID IL_dataArray_fID;112static jfieldID IL_offset_fID;113static jfieldID IL_nextRowOffset_fID;114static jfieldID IL_width_fID;115static jfieldID IL_height_fID;116static jfieldID IL_imageAtOnce_fID;117118JavaVM *javaVM;119120void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode,121const char *errorText) {122JNIEnv *env;123char errMsg[ERR_MSG_SIZE];124125int count = snprintf(errMsg, ERR_MSG_SIZE,126"LCMS error %d: %s", errorCode, errorText);127if (count < 0 || count >= ERR_MSG_SIZE) {128count = ERR_MSG_SIZE - 1;129}130errMsg[count] = 0;131132(*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);133JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg);134}135136JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {137javaVM = jvm;138139cmsSetLogErrorHandler(errorHandler);140return JNI_VERSION_1_6;141}142143void LCMS_freeProfile(JNIEnv *env, jlong ptr) {144lcmsProfile_p p = (lcmsProfile_p)jlong_to_ptr(ptr);145146if (p != NULL) {147if (p->pf != NULL) {148cmsCloseProfile(p->pf);149}150free(p);151}152}153154void LCMS_freeTransform(JNIEnv *env, jlong ID)155{156cmsHTRANSFORM sTrans = jlong_to_ptr(ID);157/* Passed ID is always valid native ref so there is no check for zero */158cmsDeleteTransform(sTrans);159}160161/*162* Class: sun_java2d_cmm_lcms_LCMS163* Method: createNativeTransform164* Signature: ([JI)J165*/166JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform167(JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType,168jint inFormatter, jboolean isInIntPacked,169jint outFormatter, jboolean isOutIntPacked, jobject disposerRef)170{171cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];172cmsHPROFILE *iccArray = &_iccArray[0];173cmsHTRANSFORM sTrans = NULL;174int i, j, size;175jlong* ids;176177size = (*env)->GetArrayLength (env, profileIDs);178ids = (*env)->GetLongArrayElements(env, profileIDs, 0);179if (ids == NULL) {180// An exception should have already been thrown.181return 0L;182}183184#ifdef _LITTLE_ENDIAN185/* Reversing data packed into int for LE archs */186if (isInIntPacked) {187inFormatter ^= DOSWAP_SH(1);188}189if (isOutIntPacked) {190outFormatter ^= DOSWAP_SH(1);191}192#endif193194if (DF_ICC_BUF_SIZE < size*2) {195iccArray = (cmsHPROFILE*) malloc(196size*2*sizeof(cmsHPROFILE));197if (iccArray == NULL) {198(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);199200J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");201return 0L;202}203}204205j = 0;206for (i = 0; i < size; i++) {207cmsColorSpaceSignature cs;208lcmsProfile_p profilePtr = (lcmsProfile_p)jlong_to_ptr(ids[i]);209cmsHPROFILE icc = profilePtr->pf;210211iccArray[j++] = icc;212213/* Middle non-abstract profiles should be doubled before passing to214* the cmsCreateMultiprofileTransform function215*/216217cs = cmsGetColorSpace(icc);218if (size > 2 && i != 0 && i != size - 1 &&219cs != cmsSigXYZData && cs != cmsSigLabData)220{221iccArray[j++] = icc;222}223}224225sTrans = cmsCreateMultiprofileTransform(iccArray, j,226inFormatter, outFormatter, renderType, 0);227228(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);229230if (sTrans == NULL) {231J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "232"sTrans == NULL");233if ((*env)->ExceptionOccurred(env) == NULL) {234JNU_ThrowByName(env, "java/awt/color/CMMException",235"Cannot get color transform");236}237} else {238Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, ptr_to_jlong(sTrans));239}240241if (iccArray != &_iccArray[0]) {242free(iccArray);243}244return ptr_to_jlong(sTrans);245}246247248/*249* Class: sun_java2d_cmm_lcms_LCMS250* Method: loadProfile251* Signature: ([B,Lsun/java2d/cmm/lcms/LCMSProfile;)V252*/253JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative254(JNIEnv *env, jobject obj, jbyteArray data, jobject disposerRef)255{256jbyte* dataArray;257jint dataSize;258lcmsProfile_p sProf = NULL;259cmsHPROFILE pf;260261if (JNU_IsNull(env, data)) {262JNU_ThrowIllegalArgumentException(env, "Invalid profile data");263return 0L;264}265266dataArray = (*env)->GetByteArrayElements (env, data, 0);267if (dataArray == NULL) {268// An exception should have already been thrown.269return 0L;270}271272dataSize = (*env)->GetArrayLength (env, data);273274pf = cmsOpenProfileFromMem((const void *)dataArray,275(cmsUInt32Number) dataSize);276277(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);278279if (pf == NULL) {280JNU_ThrowIllegalArgumentException(env, "Invalid profile data");281} else {282/* Sanity check: try to save the profile in order283* to force basic validation.284*/285cmsUInt32Number pfSize = 0;286if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||287pfSize < sizeof(cmsICCHeader))288{289JNU_ThrowIllegalArgumentException(env, "Invalid profile data");290291cmsCloseProfile(pf);292pf = NULL;293}294}295296if (pf != NULL) {297// create profile holder298sProf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));299if (sProf != NULL) {300// register the disposer record301sProf->pf = pf;302Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, ptr_to_jlong(sProf));303} else {304cmsCloseProfile(pf);305}306}307308return ptr_to_jlong(sProf);309}310311/*312* Class: sun_java2d_cmm_lcms_LCMS313* Method: getProfileSizeNative314* Signature: (J)I315*/316JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative317(JNIEnv *env, jobject obj, jlong id)318{319lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);320cmsUInt32Number pfSize = 0;321322if (cmsSaveProfileToMem(sProf->pf, NULL, &pfSize) && ((jint)pfSize > 0)) {323return (jint)pfSize;324} else {325JNU_ThrowByName(env, "java/awt/color/CMMException",326"Can not access specified profile.");327return -1;328}329}330331/*332* Class: sun_java2d_cmm_lcms_LCMS333* Method: getProfileDataNative334* Signature: (J[B)V335*/336JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative337(JNIEnv *env, jobject obj, jlong id, jbyteArray data)338{339lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);340jint size;341jbyte* dataArray;342cmsUInt32Number pfSize = 0;343cmsBool status;344345// determine actual profile size346if (!cmsSaveProfileToMem(sProf->pf, NULL, &pfSize)) {347JNU_ThrowByName(env, "java/awt/color/CMMException",348"Can not access specified profile.");349return;350}351352// verify java buffer capacity353size = (*env)->GetArrayLength(env, data);354if (0 >= size || pfSize > (cmsUInt32Number)size) {355JNU_ThrowByName(env, "java/awt/color/CMMException",356"Insufficient buffer capacity.");357return;358}359360dataArray = (*env)->GetByteArrayElements (env, data, 0);361if (dataArray == NULL) {362// An exception should have already been thrown.363return;364}365366status = cmsSaveProfileToMem(sProf->pf, dataArray, &pfSize);367368(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);369370if (!status) {371JNU_ThrowByName(env, "java/awt/color/CMMException",372"Can not access specified profile.");373return;374}375}376377/* Get profile header info */378static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);379static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);380static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);381382383/*384* Class: sun_java2d_cmm_lcms_LCMS385* Method: getTagData386* Signature: (JI[B)V387*/388JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative389(JNIEnv *env, jobject obj, jlong id, jint tagSig)390{391lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);392TagSignature_t sig;393cmsUInt32Number tagSize;394395jbyte* dataArray = NULL;396jbyteArray data = NULL;397398cmsUInt32Number bufSize;399400sig.j = tagSig;401402if (tagSig == SigHead) {403cmsBool status;404405// allocate java array406bufSize = sizeof(cmsICCHeader);407data = (*env)->NewByteArray(env, bufSize);408409if (data == NULL) {410// An exception should have already been thrown.411return NULL;412}413414dataArray = (*env)->GetByteArrayElements (env, data, 0);415416if (dataArray == NULL) {417// An exception should have already been thrown.418return NULL;419}420421status = _getHeaderInfo(sProf->pf, dataArray, bufSize);422423(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);424425if (!status) {426JNU_ThrowByName(env, "java/awt/color/CMMException",427"ICC Profile header not found");428return NULL;429}430431return data;432}433434if (cmsIsTag(sProf->pf, sig.cms)) {435tagSize = cmsReadRawTag(sProf->pf, sig.cms, NULL, 0);436} else {437JNU_ThrowByName(env, "java/awt/color/CMMException",438"ICC profile tag not found");439return NULL;440}441442// allocate java array443data = (*env)->NewByteArray(env, tagSize);444if (data == NULL) {445// An exception should have already been thrown.446return NULL;447}448449dataArray = (*env)->GetByteArrayElements (env, data, 0);450451if (dataArray == NULL) {452// An exception should have already been thrown.453return NULL;454}455456bufSize = cmsReadRawTag(sProf->pf, sig.cms, dataArray, tagSize);457458(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);459460if (bufSize != tagSize) {461JNU_ThrowByName(env, "java/awt/color/CMMException",462"Can not get tag data.");463return NULL;464}465return data;466}467468/*469* Class: sun_java2d_cmm_lcms_LCMS470* Method: setTagData471* Signature: (JI[B)V472*/473JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative474(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)475{476lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);477cmsHPROFILE pfReplace = NULL;478479TagSignature_t sig;480cmsBool status = FALSE;481jbyte* dataArray;482int tagSize;483484sig.j = tagSig;485486if (JNU_IsNull(env, data)) {487JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");488return;489}490491tagSize =(*env)->GetArrayLength(env, data);492493dataArray = (*env)->GetByteArrayElements(env, data, 0);494495if (dataArray == NULL) {496// An exception should have already been thrown.497return;498}499500if (tagSig == SigHead) {501status = _setHeaderInfo(sProf->pf, dataArray, tagSize);502} else {503/*504* New strategy for generic tags: create a place holder,505* dump all existing tags there, dump externally supplied506* tag, and return the new profile to the java.507*/508pfReplace = _writeCookedTag(sProf->pf, sig.cms, dataArray, tagSize);509status = (pfReplace != NULL);510}511512(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);513514if (!status) {515JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");516} else if (pfReplace != NULL) {517cmsCloseProfile(sProf->pf);518sProf->pf = pfReplace;519}520}521522void* getILData (JNIEnv *env, jobject img, jint* pDataType,523jobject* pDataObject) {524void* result = NULL;525*pDataType = (*env)->GetIntField (env, img, IL_dataType_fID);526*pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID);527switch (*pDataType) {528case DT_BYTE:529result = (*env)->GetByteArrayElements (env, *pDataObject, 0);530break;531case DT_SHORT:532result = (*env)->GetShortArrayElements (env, *pDataObject, 0);533break;534case DT_INT:535result = (*env)->GetIntArrayElements (env, *pDataObject, 0);536break;537case DT_DOUBLE:538result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0);539break;540}541542return result;543}544545void releaseILData (JNIEnv *env, void* pData, jint dataType,546jobject dataObject) {547switch (dataType) {548case DT_BYTE:549(*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0);550break;551case DT_SHORT:552(*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0);553break;554case DT_INT:555(*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0);556break;557case DT_DOUBLE:558(*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData,5590);560break;561}562}563564/*565* Class: sun_java2d_cmm_lcms_LCMS566* Method: colorConvert567* Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V568*/569JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert570(JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst)571{572cmsHTRANSFORM sTrans = NULL;573int srcDType, dstDType;574int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;575int width, height, i;576void* inputBuffer;577void* outputBuffer;578char* inputRow;579char* outputRow;580jobject srcData, dstData;581jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE;582583srcOffset = (*env)->GetIntField (env, src, IL_offset_fID);584srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID);585dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID);586dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID);587width = (*env)->GetIntField (env, src, IL_width_fID);588height = (*env)->GetIntField (env, src, IL_height_fID);589590srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID);591dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID);592593sTrans = jlong_to_ptr((*env)->GetLongField (env, trans, Trans_ID_fID));594595if (sTrans == NULL) {596J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");597JNU_ThrowByName(env, "java/awt/color/CMMException",598"Cannot get color transform");599return;600}601602603inputBuffer = getILData (env, src, &srcDType, &srcData);604605if (inputBuffer == NULL) {606J2dRlsTraceLn(J2D_TRACE_ERROR, "");607// An exception should have already been thrown.608return;609}610611outputBuffer = getILData (env, dst, &dstDType, &dstData);612613if (outputBuffer == NULL) {614releaseILData(env, inputBuffer, srcDType, srcData);615// An exception should have already been thrown.616return;617}618619inputRow = (char*)inputBuffer + srcOffset;620outputRow = (char*)outputBuffer + dstOffset;621622if (srcAtOnce && dstAtOnce) {623cmsDoTransform(sTrans, inputRow, outputRow, width * height);624} else {625for (i = 0; i < height; i++) {626cmsDoTransform(sTrans, inputRow, outputRow, width);627inputRow += srcNextRowOffset;628outputRow += dstNextRowOffset;629}630}631632releaseILData(env, inputBuffer, srcDType, srcData);633releaseILData(env, outputBuffer, dstDType, dstData);634}635636/*637* Class: sun_java2d_cmm_lcms_LCMS638* Method: getProfileID639* Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile640*/641JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID642(JNIEnv *env, jclass cls, jobject pf)643{644jclass clsLcmsProfile;645jobject cmmProfile;646jfieldID fid;647648if (pf == NULL) {649return NULL;650}651fid = (*env)->GetFieldID (env,652(*env)->GetObjectClass(env, pf),653"cmmProfile", "Lsun/java2d/cmm/Profile;");654if (fid == NULL) {655return NULL;656}657658clsLcmsProfile = (*env)->FindClass(env,659"sun/java2d/cmm/lcms/LCMSProfile");660if (clsLcmsProfile == NULL) {661return NULL;662}663664cmmProfile = (*env)->GetObjectField (env, pf, fid);665666if (JNU_IsNull(env, cmmProfile)) {667return NULL;668}669if ((*env)->IsInstanceOf(env, cmmProfile, clsLcmsProfile)) {670return cmmProfile;671}672return NULL;673}674675/*676* Class: sun_java2d_cmm_lcms_LCMS677* Method: initLCMS678* Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V679*/680JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS681(JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf)682{683/* TODO: move initialization of the IDs to the static blocks of684* corresponding classes to avoid problems with invalidating ids by class685* unloading686*/687Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I");688if (Trans_renderType_fID == NULL) {689return;690}691Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J");692if (Trans_ID_fID == NULL) {693return;694}695696IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z");697if (IL_isIntPacked_fID == NULL) {698return;699}700IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I");701if (IL_dataType_fID == NULL) {702return;703}704IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I");705if (IL_pixelType_fID == NULL) {706return;707}708IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray",709"Ljava/lang/Object;");710if (IL_dataArray_fID == NULL) {711return;712}713IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I");714if (IL_width_fID == NULL) {715return;716}717IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I");718if (IL_height_fID == NULL) {719return;720}721IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");722if (IL_offset_fID == NULL) {723return;724}725IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");726if (IL_imageAtOnce_fID == NULL) {727return;728}729IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");730if (IL_nextRowOffset_fID == NULL) {731return;732}733}734735static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)736{737cmsUInt32Number pfSize = 0;738cmsUInt8Number* pfBuffer = NULL;739cmsBool status = FALSE;740741if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||742pfSize < sizeof(cmsICCHeader) ||743bufferSize < (jint)sizeof(cmsICCHeader))744{745return FALSE;746}747748pfBuffer = malloc(pfSize);749if (pfBuffer == NULL) {750return FALSE;751}752753// load raw profile data into the buffer754if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {755memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));756status = TRUE;757}758free(pfBuffer);759return status;760}761762static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)763{764cmsICCHeader pfHeader;765766if (pBuffer == NULL || bufferSize < (jint)sizeof(cmsICCHeader)) {767return FALSE;768}769770memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader));771772// now set header fields, which we can access using the lcms2 public API773cmsSetHeaderFlags(pf, pfHeader.flags);774cmsSetHeaderManufacturer(pf, pfHeader.manufacturer);775cmsSetHeaderModel(pf, pfHeader.model);776cmsSetHeaderAttributes(pf, pfHeader.attributes);777cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID));778cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent);779cmsSetPCS(pf, pfHeader.pcs);780cmsSetColorSpace(pf, pfHeader.colorSpace);781cmsSetDeviceClass(pf, pfHeader.deviceClass);782cmsSetEncodedICCversion(pf, pfHeader.version);783784return TRUE;785}786787/* Returns new profile handler, if it was created successfully,788NULL otherwise.789*/790static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,791const cmsTagSignature sig,792jbyte *pData, jint size)793{794cmsUInt32Number pfSize = 0;795const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);796cmsInt32Number i;797cmsHPROFILE pfSanity = NULL;798799cmsICCHeader hdr;800801cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);802803if (NULL == p) {804return NULL;805}806memset(&hdr, 0, sizeof(cmsICCHeader));807808// Populate the placeholder's header according to target profile809hdr.flags = cmsGetHeaderFlags(pfTarget);810hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);811hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);812hdr.model = cmsGetHeaderModel(pfTarget);813hdr.pcs = cmsGetPCS(pfTarget);814hdr.colorSpace = cmsGetColorSpace(pfTarget);815hdr.deviceClass = cmsGetDeviceClass(pfTarget);816hdr.version = cmsGetEncodedICCversion(pfTarget);817cmsGetHeaderAttributes(pfTarget, &hdr.attributes);818cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);819820cmsSetHeaderFlags(p, hdr.flags);821cmsSetHeaderManufacturer(p, hdr.manufacturer);822cmsSetHeaderModel(p, hdr.model);823cmsSetHeaderAttributes(p, hdr.attributes);824cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));825cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);826cmsSetPCS(p, hdr.pcs);827cmsSetColorSpace(p, hdr.colorSpace);828cmsSetDeviceClass(p, hdr.deviceClass);829cmsSetEncodedICCversion(p, hdr.version);830831// now write the user supplied tag832if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {833cmsCloseProfile(p);834return NULL;835}836837// copy tags from the original profile838for (i = 0; i < tagCount; i++) {839cmsBool isTagReady = FALSE;840const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);841const cmsUInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);842843if (s == sig) {844// skip the user supplied tag845continue;846}847848// read raw tag from the original profile849if (tagSize > 0) {850cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);851if (buf != NULL) {852if (tagSize == cmsReadRawTag(pfTarget, s, buf, tagSize)) {853// now we are ready to write the tag854isTagReady = cmsWriteRawTag(p, s, buf, tagSize);855}856free(buf);857}858}859860if (!isTagReady) {861cmsCloseProfile(p);862return NULL;863}864}865866// now we have all tags moved to the new profile.867// do some sanity checks: write it to a memory buffer and read again.868if (cmsSaveProfileToMem(p, NULL, &pfSize)) {869void* buf = malloc(pfSize);870if (buf != NULL) {871// load raw profile data into the buffer872if (cmsSaveProfileToMem(p, buf, &pfSize)) {873pfSanity = cmsOpenProfileFromMem(buf, pfSize);874}875free(buf);876}877}878879if (pfSanity == NULL) {880// for some reason, we failed to save and read the updated profile881// It likely indicates that the profile is not correct, so we report882// a failure here.883cmsCloseProfile(p);884p = NULL;885} else {886// do final check whether we can read and handle the the target tag.887const void* pTag = cmsReadTag(pfSanity, sig);888if (pTag == NULL) {889// the tag can not be cooked890cmsCloseProfile(p);891p = NULL;892}893cmsCloseProfile(pfSanity);894pfSanity = NULL;895}896897return p;898}899900901