Path: blob/master/src/java.desktop/share/native/liblcms/LCMS.c
41149 views
/*1* Copyright (c) 2007, 2021, 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 <lcms2_plugin.h>34#include "jlong.h"3536#define SigMake(a,b,c,d) \37( ( ((int) ((unsigned char) (a))) << 24) | \38( ((int) ((unsigned char) (b))) << 16) | \39( ((int) ((unsigned char) (c))) << 8) | \40(int) ((unsigned char) (d)))4142#define TagIdConst(a, b, c, d) \43((int) SigMake ((a), (b), (c), (d)))4445#define SigHead TagIdConst('h','e','a','d')4647#define DT_BYTE 048#define DT_SHORT 149#define DT_INT 250#define DT_DOUBLE 35152/* Default temp profile list size */53#define DF_ICC_BUF_SIZE 325455#define ERR_MSG_SIZE 2565657#ifdef _MSC_VER58# ifndef snprintf59# define snprintf _snprintf60# endif61#endif6263typedef struct lcmsProfile_s {64cmsHPROFILE pf;65} lcmsProfile_t, *lcmsProfile_p;6667typedef union {68cmsTagSignature cms;69jint j;70} TagSignature_t, *TagSignature_p;7172static jfieldID Trans_renderType_fID;73static jfieldID Trans_ID_fID;74static jfieldID IL_isIntPacked_fID;75static jfieldID IL_dataType_fID;76static jfieldID IL_pixelType_fID;77static jfieldID IL_dataArray_fID;78static jfieldID IL_offset_fID;79static jfieldID IL_nextRowOffset_fID;80static jfieldID IL_width_fID;81static jfieldID IL_height_fID;82static jfieldID IL_imageAtOnce_fID;8384JavaVM *javaVM;8586void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode,87const char *errorText) {88JNIEnv *env;89char errMsg[ERR_MSG_SIZE];9091int count = snprintf(errMsg, ERR_MSG_SIZE,92"LCMS error %d: %s", errorCode, errorText);93if (count < 0 || count >= ERR_MSG_SIZE) {94count = ERR_MSG_SIZE - 1;95}96errMsg[count] = 0;9798(*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);99JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg);100}101102JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *jvm, void *reserved) {103javaVM = jvm;104105cmsSetLogErrorHandler(errorHandler);106return JNI_VERSION_1_6;107}108109void LCMS_freeProfile(JNIEnv *env, jlong ptr) {110lcmsProfile_p p = (lcmsProfile_p)jlong_to_ptr(ptr);111112if (p != NULL) {113if (p->pf != NULL) {114cmsCloseProfile(p->pf);115}116free(p);117}118}119120void LCMS_freeTransform(JNIEnv *env, jlong ID)121{122cmsHTRANSFORM sTrans = jlong_to_ptr(ID);123/* Passed ID is always valid native ref so there is no check for zero */124cmsDeleteTransform(sTrans);125}126127/*128* Class: sun_java2d_cmm_lcms_LCMS129* Method: createNativeTransform130* Signature: ([JIIZIZLjava/lang/Object;)J131*/132JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform133(JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType,134jint inFormatter, jboolean isInIntPacked,135jint outFormatter, jboolean isOutIntPacked, jobject disposerRef)136{137cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];138cmsHPROFILE *iccArray = &_iccArray[0];139cmsHTRANSFORM sTrans = NULL;140int i, j, size;141jlong* ids;142143size = (*env)->GetArrayLength (env, profileIDs);144ids = (*env)->GetLongArrayElements(env, profileIDs, 0);145if (ids == NULL) {146// An exception should have already been thrown.147return 0L;148}149150#ifdef _LITTLE_ENDIAN151/* Reversing data packed into int for LE archs */152if (isInIntPacked) {153inFormatter ^= DOSWAP_SH(1);154}155if (isOutIntPacked) {156outFormatter ^= DOSWAP_SH(1);157}158#endif159160if (DF_ICC_BUF_SIZE < size*2) {161iccArray = (cmsHPROFILE*) malloc(162size*2*sizeof(cmsHPROFILE));163if (iccArray == NULL) {164(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);165166J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");167return 0L;168}169}170171j = 0;172for (i = 0; i < size; i++) {173cmsColorSpaceSignature cs;174lcmsProfile_p profilePtr = (lcmsProfile_p)jlong_to_ptr(ids[i]);175cmsHPROFILE icc = profilePtr->pf;176177iccArray[j++] = icc;178179/* Middle non-abstract profiles should be doubled before passing to180* the cmsCreateMultiprofileTransform function181*/182183cs = cmsGetColorSpace(icc);184if (size > 2 && i != 0 && i != size - 1 &&185cs != cmsSigXYZData && cs != cmsSigLabData)186{187iccArray[j++] = icc;188}189}190191sTrans = cmsCreateMultiprofileTransform(iccArray, j,192inFormatter, outFormatter, renderType, cmsFLAGS_COPY_ALPHA);193194(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);195196if (sTrans == NULL) {197J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "198"sTrans == NULL");199if ((*env)->ExceptionOccurred(env) == NULL) {200JNU_ThrowByName(env, "java/awt/color/CMMException",201"Cannot get color transform");202}203} else {204Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, ptr_to_jlong(sTrans));205}206207if (iccArray != &_iccArray[0]) {208free(iccArray);209}210return ptr_to_jlong(sTrans);211}212213214/*215* Class: sun_java2d_cmm_lcms_LCMS216* Method: loadProfileNative217* Signature: ([BLjava/lang/Object;)J218*/219JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative220(JNIEnv *env, jclass cls, jbyteArray data, jobject disposerRef)221{222jbyte* dataArray;223jint dataSize;224lcmsProfile_p sProf = NULL;225cmsHPROFILE pf;226227if (JNU_IsNull(env, data)) {228JNU_ThrowIllegalArgumentException(env, "Invalid profile data");229return 0L;230}231232dataArray = (*env)->GetByteArrayElements (env, data, 0);233if (dataArray == NULL) {234// An exception should have already been thrown.235return 0L;236}237238dataSize = (*env)->GetArrayLength (env, data);239240pf = cmsOpenProfileFromMem((const void *)dataArray,241(cmsUInt32Number) dataSize);242243(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);244245if (pf == NULL) {246JNU_ThrowIllegalArgumentException(env, "Invalid profile data");247} else {248/* Sanity check: try to save the profile in order249* to force basic validation.250*/251cmsUInt32Number pfSize = 0;252if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||253pfSize < sizeof(cmsICCHeader))254{255JNU_ThrowIllegalArgumentException(env, "Invalid profile data");256257cmsCloseProfile(pf);258pf = NULL;259}260}261262if (pf != NULL) {263// create profile holder264sProf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));265if (sProf != NULL) {266// register the disposer record267sProf->pf = pf;268Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, ptr_to_jlong(sProf));269} else {270cmsCloseProfile(pf);271}272}273274return ptr_to_jlong(sProf);275}276277/*278* Class: sun_java2d_cmm_lcms_LCMS279* Method: getProfileDataNative280* Signature: (J)[B281*/282JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative283(JNIEnv *env, jclass cls, jlong id)284{285lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);286cmsUInt32Number pfSize = 0;287288// determine actual profile size289if (!cmsSaveProfileToMem(sProf->pf, NULL, &pfSize)) {290JNU_ThrowByName(env, "java/awt/color/CMMException",291"Can not access specified profile.");292return NULL;293}294295jbyteArray data = (*env)->NewByteArray(env, pfSize);296if (data == NULL) {297// An exception should have already been thrown.298return NULL;299}300301jbyte* dataArray = (*env)->GetByteArrayElements(env, data, 0);302if (dataArray == NULL) {303// An exception should have already been thrown.304return NULL;305}306307cmsBool status = cmsSaveProfileToMem(sProf->pf, dataArray, &pfSize);308309(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);310311if (!status) {312JNU_ThrowByName(env, "java/awt/color/CMMException",313"Can not access specified profile.");314return NULL;315}316return data;317}318319/* Get profile header info */320static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);321static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);322static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);323324325/*326* Class: sun_java2d_cmm_lcms_LCMS327* Method: getTagNative328* Signature: (JI)[B329*/330JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative331(JNIEnv *env, jclass cls, jlong id, jint tagSig)332{333lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);334TagSignature_t sig;335cmsUInt32Number tagSize;336337jbyte* dataArray = NULL;338jbyteArray data = NULL;339340cmsUInt32Number bufSize;341342sig.j = tagSig;343344if (tagSig == SigHead) {345cmsBool status;346347// allocate java array348bufSize = sizeof(cmsICCHeader);349data = (*env)->NewByteArray(env, bufSize);350351if (data == NULL) {352// An exception should have already been thrown.353return NULL;354}355356dataArray = (*env)->GetByteArrayElements (env, data, 0);357358if (dataArray == NULL) {359// An exception should have already been thrown.360return NULL;361}362363status = _getHeaderInfo(sProf->pf, dataArray, bufSize);364365(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);366367if (!status) {368JNU_ThrowByName(env, "java/awt/color/CMMException",369"ICC Profile header not found");370return NULL;371}372373return data;374}375376if (cmsIsTag(sProf->pf, sig.cms)) {377tagSize = cmsReadRawTag(sProf->pf, sig.cms, NULL, 0);378} else {379JNU_ThrowByName(env, "java/awt/color/CMMException",380"ICC profile tag not found");381return NULL;382}383384// allocate java array385data = (*env)->NewByteArray(env, tagSize);386if (data == NULL) {387// An exception should have already been thrown.388return NULL;389}390391dataArray = (*env)->GetByteArrayElements (env, data, 0);392393if (dataArray == NULL) {394// An exception should have already been thrown.395return NULL;396}397398bufSize = cmsReadRawTag(sProf->pf, sig.cms, dataArray, tagSize);399400(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);401402if (bufSize != tagSize) {403JNU_ThrowByName(env, "java/awt/color/CMMException",404"Can not get tag data.");405return NULL;406}407return data;408}409410/*411* Class: sun_java2d_cmm_lcms_LCMS412* Method: setTagDataNative413* Signature: (JI[B)V414*/415JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative416(JNIEnv *env, jclass cls, jlong id, jint tagSig, jbyteArray data)417{418lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);419cmsHPROFILE pfReplace = NULL;420421TagSignature_t sig;422cmsBool status = FALSE;423jbyte* dataArray;424int tagSize;425426sig.j = tagSig;427428if (JNU_IsNull(env, data)) {429JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");430return;431}432433tagSize =(*env)->GetArrayLength(env, data);434435dataArray = (*env)->GetByteArrayElements(env, data, 0);436437if (dataArray == NULL) {438// An exception should have already been thrown.439return;440}441442if (tagSig == SigHead) {443status = _setHeaderInfo(sProf->pf, dataArray, tagSize);444} else {445/*446* New strategy for generic tags: create a place holder,447* dump all existing tags there, dump externally supplied448* tag, and return the new profile to the java.449*/450pfReplace = _writeCookedTag(sProf->pf, sig.cms, dataArray, tagSize);451status = (pfReplace != NULL);452}453454(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);455456if (!status) {457JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");458} else if (pfReplace != NULL) {459cmsCloseProfile(sProf->pf);460sProf->pf = pfReplace;461}462}463464void* getILData (JNIEnv *env, jobject img, jint* pDataType,465jobject* pDataObject) {466void* result = NULL;467*pDataType = (*env)->GetIntField (env, img, IL_dataType_fID);468*pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID);469switch (*pDataType) {470case DT_BYTE:471result = (*env)->GetByteArrayElements (env, *pDataObject, 0);472break;473case DT_SHORT:474result = (*env)->GetShortArrayElements (env, *pDataObject, 0);475break;476case DT_INT:477result = (*env)->GetIntArrayElements (env, *pDataObject, 0);478break;479case DT_DOUBLE:480result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0);481break;482}483484return result;485}486487void releaseILData (JNIEnv *env, void* pData, jint dataType,488jobject dataObject) {489switch (dataType) {490case DT_BYTE:491(*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0);492break;493case DT_SHORT:494(*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0);495break;496case DT_INT:497(*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0);498break;499case DT_DOUBLE:500(*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData,5010);502break;503}504}505506/*507* Class: sun_java2d_cmm_lcms_LCMS508* Method: colorConvert509* Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V510*/511JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert512(JNIEnv *env, jclass cls, jobject trans, jobject src, jobject dst)513{514cmsHTRANSFORM sTrans = NULL;515int srcDType, dstDType;516int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;517int width, height, i;518void* inputBuffer;519void* outputBuffer;520char* inputRow;521char* outputRow;522jobject srcData, dstData;523jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE;524525srcOffset = (*env)->GetIntField (env, src, IL_offset_fID);526srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID);527dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID);528dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID);529width = (*env)->GetIntField (env, src, IL_width_fID);530height = (*env)->GetIntField (env, src, IL_height_fID);531532srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID);533dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID);534535sTrans = jlong_to_ptr((*env)->GetLongField (env, trans, Trans_ID_fID));536537if (sTrans == NULL) {538J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");539JNU_ThrowByName(env, "java/awt/color/CMMException",540"Cannot get color transform");541return;542}543544545inputBuffer = getILData (env, src, &srcDType, &srcData);546547if (inputBuffer == NULL) {548J2dRlsTraceLn(J2D_TRACE_ERROR, "");549// An exception should have already been thrown.550return;551}552553outputBuffer = getILData (env, dst, &dstDType, &dstData);554555if (outputBuffer == NULL) {556releaseILData(env, inputBuffer, srcDType, srcData);557// An exception should have already been thrown.558return;559}560561inputRow = (char*)inputBuffer + srcOffset;562outputRow = (char*)outputBuffer + dstOffset;563564if (srcAtOnce && dstAtOnce) {565cmsDoTransform(sTrans, inputRow, outputRow, width * height);566} else {567for (i = 0; i < height; i++) {568cmsDoTransform(sTrans, inputRow, outputRow, width);569inputRow += srcNextRowOffset;570outputRow += dstNextRowOffset;571}572}573574releaseILData(env, inputBuffer, srcDType, srcData);575releaseILData(env, outputBuffer, dstDType, dstData);576}577578/*579* Class: sun_java2d_cmm_lcms_LCMS580* Method: getProfileID581* Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile;582*/583JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID584(JNIEnv *env, jclass cls, jobject pf)585{586if (pf == NULL) {587return NULL;588}589jclass pcls = (*env)->GetObjectClass(env, pf);590if (pcls == NULL) {591return NULL;592}593jmethodID mid = (*env)->GetMethodID(env, pcls, "cmmProfile",594"()Lsun/java2d/cmm/Profile;");595if (mid == NULL) {596return NULL;597}598jobject cmmProfile = (*env)->CallObjectMethod(env, pf, mid);599if ((*env)->ExceptionOccurred(env)) {600return NULL;601}602jclass lcmsPCls = (*env)->FindClass(env, "sun/java2d/cmm/lcms/LCMSProfile");603if (lcmsPCls == NULL) {604return NULL;605}606if ((*env)->IsInstanceOf(env, cmmProfile, lcmsPCls)) {607return cmmProfile;608}609return NULL;610}611612/*613* Class: sun_java2d_cmm_lcms_LCMS614* Method: initLCMS615* Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V616*/617JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS618(JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf)619{620/* TODO: move initialization of the IDs to the static blocks of621* corresponding classes to avoid problems with invalidating ids by class622* unloading623*/624Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I");625if (Trans_renderType_fID == NULL) {626return;627}628Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J");629if (Trans_ID_fID == NULL) {630return;631}632633IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z");634if (IL_isIntPacked_fID == NULL) {635return;636}637IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I");638if (IL_dataType_fID == NULL) {639return;640}641IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I");642if (IL_pixelType_fID == NULL) {643return;644}645IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray",646"Ljava/lang/Object;");647if (IL_dataArray_fID == NULL) {648return;649}650IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I");651if (IL_width_fID == NULL) {652return;653}654IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I");655if (IL_height_fID == NULL) {656return;657}658IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");659if (IL_offset_fID == NULL) {660return;661}662IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");663if (IL_imageAtOnce_fID == NULL) {664return;665}666IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");667if (IL_nextRowOffset_fID == NULL) {668return;669}670}671672static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)673{674cmsUInt32Number pfSize = 0;675cmsUInt8Number* pfBuffer = NULL;676cmsBool status = FALSE;677678if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||679pfSize < sizeof(cmsICCHeader) ||680bufferSize < (jint)sizeof(cmsICCHeader))681{682return FALSE;683}684685pfBuffer = malloc(pfSize);686if (pfBuffer == NULL) {687return FALSE;688}689690// load raw profile data into the buffer691if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {692memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));693status = TRUE;694}695free(pfBuffer);696return status;697}698699static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)700{701cmsICCHeader pfHeader;702703if (pBuffer == NULL || bufferSize < (jint)sizeof(cmsICCHeader)) {704return FALSE;705}706707memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader));708709// now set header fields, which we can access using the lcms2 public API710cmsSetHeaderFlags(pf, _cmsAdjustEndianess32(pfHeader.flags));711cmsSetHeaderManufacturer(pf, _cmsAdjustEndianess32(pfHeader.manufacturer));712cmsSetHeaderModel(pf, _cmsAdjustEndianess32(pfHeader.model));713cmsUInt64Number attributes;714_cmsAdjustEndianess64(&attributes, &pfHeader.attributes);715cmsSetHeaderAttributes(pf, attributes);716cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID));717cmsSetHeaderRenderingIntent(pf, _cmsAdjustEndianess32(pfHeader.renderingIntent));718cmsSetPCS(pf, _cmsAdjustEndianess32(pfHeader.pcs));719cmsSetColorSpace(pf, _cmsAdjustEndianess32(pfHeader.colorSpace));720cmsSetDeviceClass(pf, _cmsAdjustEndianess32(pfHeader.deviceClass));721cmsSetEncodedICCversion(pf, _cmsAdjustEndianess32(pfHeader.version));722723return TRUE;724}725726/* Returns new profile handler, if it was created successfully,727NULL otherwise.728*/729static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,730const cmsTagSignature sig,731jbyte *pData, jint size)732{733cmsUInt32Number pfSize = 0;734const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);735cmsInt32Number i;736cmsHPROFILE pfSanity = NULL;737738cmsICCHeader hdr;739740cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);741742if (NULL == p) {743return NULL;744}745memset(&hdr, 0, sizeof(cmsICCHeader));746747// Populate the placeholder's header according to target profile748hdr.flags = cmsGetHeaderFlags(pfTarget);749hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);750hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);751hdr.model = cmsGetHeaderModel(pfTarget);752hdr.pcs = cmsGetPCS(pfTarget);753hdr.colorSpace = cmsGetColorSpace(pfTarget);754hdr.deviceClass = cmsGetDeviceClass(pfTarget);755hdr.version = cmsGetEncodedICCversion(pfTarget);756cmsGetHeaderAttributes(pfTarget, &hdr.attributes);757cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);758759cmsSetHeaderFlags(p, hdr.flags);760cmsSetHeaderManufacturer(p, hdr.manufacturer);761cmsSetHeaderModel(p, hdr.model);762cmsSetHeaderAttributes(p, hdr.attributes);763cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));764cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);765cmsSetPCS(p, hdr.pcs);766cmsSetColorSpace(p, hdr.colorSpace);767cmsSetDeviceClass(p, hdr.deviceClass);768cmsSetEncodedICCversion(p, hdr.version);769770// now write the user supplied tag771if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {772cmsCloseProfile(p);773return NULL;774}775776// copy tags from the original profile777for (i = 0; i < tagCount; i++) {778cmsBool isTagReady = FALSE;779const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);780const cmsUInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);781782if (s == sig) {783// skip the user supplied tag784continue;785}786787// read raw tag from the original profile788if (tagSize > 0) {789cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);790if (buf != NULL) {791if (tagSize == cmsReadRawTag(pfTarget, s, buf, tagSize)) {792// now we are ready to write the tag793isTagReady = cmsWriteRawTag(p, s, buf, tagSize);794}795free(buf);796}797}798799if (!isTagReady) {800cmsCloseProfile(p);801return NULL;802}803}804805// now we have all tags moved to the new profile.806// do some sanity checks: write it to a memory buffer and read again.807if (cmsSaveProfileToMem(p, NULL, &pfSize)) {808void* buf = malloc(pfSize);809if (buf != NULL) {810// load raw profile data into the buffer811if (cmsSaveProfileToMem(p, buf, &pfSize)) {812pfSanity = cmsOpenProfileFromMem(buf, pfSize);813}814free(buf);815}816}817818if (pfSanity == NULL) {819// for some reason, we failed to save and read the updated profile820// It likely indicates that the profile is not correct, so we report821// a failure here.822cmsCloseProfile(p);823p = NULL;824} else {825// do final check whether we can read and handle the target tag.826const void* pTag = cmsReadTag(pfSanity, sig);827if (pTag == NULL) {828// the tag can not be cooked829cmsCloseProfile(p);830p = NULL;831}832cmsCloseProfile(pfSanity);833pfSanity = NULL;834}835836return p;837}838839840