Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/liblcms/LCMS.c
41149 views
1
/*
2
* Copyright (c) 2007, 2021, 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
#include <lcms2_plugin.h>
35
#include "jlong.h"
36
37
#define SigMake(a,b,c,d) \
38
( ( ((int) ((unsigned char) (a))) << 24) | \
39
( ((int) ((unsigned char) (b))) << 16) | \
40
( ((int) ((unsigned char) (c))) << 8) | \
41
(int) ((unsigned char) (d)))
42
43
#define TagIdConst(a, b, c, d) \
44
((int) SigMake ((a), (b), (c), (d)))
45
46
#define SigHead TagIdConst('h','e','a','d')
47
48
#define DT_BYTE 0
49
#define DT_SHORT 1
50
#define DT_INT 2
51
#define DT_DOUBLE 3
52
53
/* Default temp profile list size */
54
#define DF_ICC_BUF_SIZE 32
55
56
#define ERR_MSG_SIZE 256
57
58
#ifdef _MSC_VER
59
# ifndef snprintf
60
# define snprintf _snprintf
61
# endif
62
#endif
63
64
typedef struct lcmsProfile_s {
65
cmsHPROFILE pf;
66
} lcmsProfile_t, *lcmsProfile_p;
67
68
typedef union {
69
cmsTagSignature cms;
70
jint j;
71
} TagSignature_t, *TagSignature_p;
72
73
static jfieldID Trans_renderType_fID;
74
static jfieldID Trans_ID_fID;
75
static jfieldID IL_isIntPacked_fID;
76
static jfieldID IL_dataType_fID;
77
static jfieldID IL_pixelType_fID;
78
static jfieldID IL_dataArray_fID;
79
static jfieldID IL_offset_fID;
80
static jfieldID IL_nextRowOffset_fID;
81
static jfieldID IL_width_fID;
82
static jfieldID IL_height_fID;
83
static jfieldID IL_imageAtOnce_fID;
84
85
JavaVM *javaVM;
86
87
void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode,
88
const char *errorText) {
89
JNIEnv *env;
90
char errMsg[ERR_MSG_SIZE];
91
92
int count = snprintf(errMsg, ERR_MSG_SIZE,
93
"LCMS error %d: %s", errorCode, errorText);
94
if (count < 0 || count >= ERR_MSG_SIZE) {
95
count = ERR_MSG_SIZE - 1;
96
}
97
errMsg[count] = 0;
98
99
(*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);
100
JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg);
101
}
102
103
JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *jvm, void *reserved) {
104
javaVM = jvm;
105
106
cmsSetLogErrorHandler(errorHandler);
107
return JNI_VERSION_1_6;
108
}
109
110
void LCMS_freeProfile(JNIEnv *env, jlong ptr) {
111
lcmsProfile_p p = (lcmsProfile_p)jlong_to_ptr(ptr);
112
113
if (p != NULL) {
114
if (p->pf != NULL) {
115
cmsCloseProfile(p->pf);
116
}
117
free(p);
118
}
119
}
120
121
void LCMS_freeTransform(JNIEnv *env, jlong ID)
122
{
123
cmsHTRANSFORM sTrans = jlong_to_ptr(ID);
124
/* Passed ID is always valid native ref so there is no check for zero */
125
cmsDeleteTransform(sTrans);
126
}
127
128
/*
129
* Class: sun_java2d_cmm_lcms_LCMS
130
* Method: createNativeTransform
131
* Signature: ([JIIZIZLjava/lang/Object;)J
132
*/
133
JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
134
(JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType,
135
jint inFormatter, jboolean isInIntPacked,
136
jint outFormatter, jboolean isOutIntPacked, jobject disposerRef)
137
{
138
cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];
139
cmsHPROFILE *iccArray = &_iccArray[0];
140
cmsHTRANSFORM sTrans = NULL;
141
int i, j, size;
142
jlong* ids;
143
144
size = (*env)->GetArrayLength (env, profileIDs);
145
ids = (*env)->GetLongArrayElements(env, profileIDs, 0);
146
if (ids == NULL) {
147
// An exception should have already been thrown.
148
return 0L;
149
}
150
151
#ifdef _LITTLE_ENDIAN
152
/* Reversing data packed into int for LE archs */
153
if (isInIntPacked) {
154
inFormatter ^= DOSWAP_SH(1);
155
}
156
if (isOutIntPacked) {
157
outFormatter ^= DOSWAP_SH(1);
158
}
159
#endif
160
161
if (DF_ICC_BUF_SIZE < size*2) {
162
iccArray = (cmsHPROFILE*) malloc(
163
size*2*sizeof(cmsHPROFILE));
164
if (iccArray == NULL) {
165
(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
166
167
J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
168
return 0L;
169
}
170
}
171
172
j = 0;
173
for (i = 0; i < size; i++) {
174
cmsColorSpaceSignature cs;
175
lcmsProfile_p profilePtr = (lcmsProfile_p)jlong_to_ptr(ids[i]);
176
cmsHPROFILE icc = profilePtr->pf;
177
178
iccArray[j++] = icc;
179
180
/* Middle non-abstract profiles should be doubled before passing to
181
* the cmsCreateMultiprofileTransform function
182
*/
183
184
cs = cmsGetColorSpace(icc);
185
if (size > 2 && i != 0 && i != size - 1 &&
186
cs != cmsSigXYZData && cs != cmsSigLabData)
187
{
188
iccArray[j++] = icc;
189
}
190
}
191
192
sTrans = cmsCreateMultiprofileTransform(iccArray, j,
193
inFormatter, outFormatter, renderType, cmsFLAGS_COPY_ALPHA);
194
195
(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
196
197
if (sTrans == NULL) {
198
J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "
199
"sTrans == NULL");
200
if ((*env)->ExceptionOccurred(env) == NULL) {
201
JNU_ThrowByName(env, "java/awt/color/CMMException",
202
"Cannot get color transform");
203
}
204
} else {
205
Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, ptr_to_jlong(sTrans));
206
}
207
208
if (iccArray != &_iccArray[0]) {
209
free(iccArray);
210
}
211
return ptr_to_jlong(sTrans);
212
}
213
214
215
/*
216
* Class: sun_java2d_cmm_lcms_LCMS
217
* Method: loadProfileNative
218
* Signature: ([BLjava/lang/Object;)J
219
*/
220
JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative
221
(JNIEnv *env, jclass cls, jbyteArray data, jobject disposerRef)
222
{
223
jbyte* dataArray;
224
jint dataSize;
225
lcmsProfile_p sProf = NULL;
226
cmsHPROFILE pf;
227
228
if (JNU_IsNull(env, data)) {
229
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
230
return 0L;
231
}
232
233
dataArray = (*env)->GetByteArrayElements (env, data, 0);
234
if (dataArray == NULL) {
235
// An exception should have already been thrown.
236
return 0L;
237
}
238
239
dataSize = (*env)->GetArrayLength (env, data);
240
241
pf = cmsOpenProfileFromMem((const void *)dataArray,
242
(cmsUInt32Number) dataSize);
243
244
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
245
246
if (pf == NULL) {
247
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
248
} else {
249
/* Sanity check: try to save the profile in order
250
* to force basic validation.
251
*/
252
cmsUInt32Number pfSize = 0;
253
if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
254
pfSize < sizeof(cmsICCHeader))
255
{
256
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
257
258
cmsCloseProfile(pf);
259
pf = NULL;
260
}
261
}
262
263
if (pf != NULL) {
264
// create profile holder
265
sProf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));
266
if (sProf != NULL) {
267
// register the disposer record
268
sProf->pf = pf;
269
Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, ptr_to_jlong(sProf));
270
} else {
271
cmsCloseProfile(pf);
272
}
273
}
274
275
return ptr_to_jlong(sProf);
276
}
277
278
/*
279
* Class: sun_java2d_cmm_lcms_LCMS
280
* Method: getProfileDataNative
281
* Signature: (J)[B
282
*/
283
JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative
284
(JNIEnv *env, jclass cls, jlong id)
285
{
286
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
287
cmsUInt32Number pfSize = 0;
288
289
// determine actual profile size
290
if (!cmsSaveProfileToMem(sProf->pf, NULL, &pfSize)) {
291
JNU_ThrowByName(env, "java/awt/color/CMMException",
292
"Can not access specified profile.");
293
return NULL;
294
}
295
296
jbyteArray data = (*env)->NewByteArray(env, pfSize);
297
if (data == NULL) {
298
// An exception should have already been thrown.
299
return NULL;
300
}
301
302
jbyte* dataArray = (*env)->GetByteArrayElements(env, data, 0);
303
if (dataArray == NULL) {
304
// An exception should have already been thrown.
305
return NULL;
306
}
307
308
cmsBool status = cmsSaveProfileToMem(sProf->pf, dataArray, &pfSize);
309
310
(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
311
312
if (!status) {
313
JNU_ThrowByName(env, "java/awt/color/CMMException",
314
"Can not access specified profile.");
315
return NULL;
316
}
317
return data;
318
}
319
320
/* Get profile header info */
321
static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
322
static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
323
static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
324
325
326
/*
327
* Class: sun_java2d_cmm_lcms_LCMS
328
* Method: getTagNative
329
* Signature: (JI)[B
330
*/
331
JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative
332
(JNIEnv *env, jclass cls, jlong id, jint tagSig)
333
{
334
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
335
TagSignature_t sig;
336
cmsUInt32Number tagSize;
337
338
jbyte* dataArray = NULL;
339
jbyteArray data = NULL;
340
341
cmsUInt32Number bufSize;
342
343
sig.j = tagSig;
344
345
if (tagSig == SigHead) {
346
cmsBool status;
347
348
// allocate java array
349
bufSize = sizeof(cmsICCHeader);
350
data = (*env)->NewByteArray(env, bufSize);
351
352
if (data == NULL) {
353
// An exception should have already been thrown.
354
return NULL;
355
}
356
357
dataArray = (*env)->GetByteArrayElements (env, data, 0);
358
359
if (dataArray == NULL) {
360
// An exception should have already been thrown.
361
return NULL;
362
}
363
364
status = _getHeaderInfo(sProf->pf, dataArray, bufSize);
365
366
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
367
368
if (!status) {
369
JNU_ThrowByName(env, "java/awt/color/CMMException",
370
"ICC Profile header not found");
371
return NULL;
372
}
373
374
return data;
375
}
376
377
if (cmsIsTag(sProf->pf, sig.cms)) {
378
tagSize = cmsReadRawTag(sProf->pf, sig.cms, NULL, 0);
379
} else {
380
JNU_ThrowByName(env, "java/awt/color/CMMException",
381
"ICC profile tag not found");
382
return NULL;
383
}
384
385
// allocate java array
386
data = (*env)->NewByteArray(env, tagSize);
387
if (data == NULL) {
388
// An exception should have already been thrown.
389
return NULL;
390
}
391
392
dataArray = (*env)->GetByteArrayElements (env, data, 0);
393
394
if (dataArray == NULL) {
395
// An exception should have already been thrown.
396
return NULL;
397
}
398
399
bufSize = cmsReadRawTag(sProf->pf, sig.cms, dataArray, tagSize);
400
401
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
402
403
if (bufSize != tagSize) {
404
JNU_ThrowByName(env, "java/awt/color/CMMException",
405
"Can not get tag data.");
406
return NULL;
407
}
408
return data;
409
}
410
411
/*
412
* Class: sun_java2d_cmm_lcms_LCMS
413
* Method: setTagDataNative
414
* Signature: (JI[B)V
415
*/
416
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative
417
(JNIEnv *env, jclass cls, jlong id, jint tagSig, jbyteArray data)
418
{
419
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
420
cmsHPROFILE pfReplace = NULL;
421
422
TagSignature_t sig;
423
cmsBool status = FALSE;
424
jbyte* dataArray;
425
int tagSize;
426
427
sig.j = tagSig;
428
429
if (JNU_IsNull(env, data)) {
430
JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");
431
return;
432
}
433
434
tagSize =(*env)->GetArrayLength(env, data);
435
436
dataArray = (*env)->GetByteArrayElements(env, data, 0);
437
438
if (dataArray == NULL) {
439
// An exception should have already been thrown.
440
return;
441
}
442
443
if (tagSig == SigHead) {
444
status = _setHeaderInfo(sProf->pf, dataArray, tagSize);
445
} else {
446
/*
447
* New strategy for generic tags: create a place holder,
448
* dump all existing tags there, dump externally supplied
449
* tag, and return the new profile to the java.
450
*/
451
pfReplace = _writeCookedTag(sProf->pf, sig.cms, dataArray, tagSize);
452
status = (pfReplace != NULL);
453
}
454
455
(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
456
457
if (!status) {
458
JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");
459
} else if (pfReplace != NULL) {
460
cmsCloseProfile(sProf->pf);
461
sProf->pf = pfReplace;
462
}
463
}
464
465
void* getILData (JNIEnv *env, jobject img, jint* pDataType,
466
jobject* pDataObject) {
467
void* result = NULL;
468
*pDataType = (*env)->GetIntField (env, img, IL_dataType_fID);
469
*pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID);
470
switch (*pDataType) {
471
case DT_BYTE:
472
result = (*env)->GetByteArrayElements (env, *pDataObject, 0);
473
break;
474
case DT_SHORT:
475
result = (*env)->GetShortArrayElements (env, *pDataObject, 0);
476
break;
477
case DT_INT:
478
result = (*env)->GetIntArrayElements (env, *pDataObject, 0);
479
break;
480
case DT_DOUBLE:
481
result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0);
482
break;
483
}
484
485
return result;
486
}
487
488
void releaseILData (JNIEnv *env, void* pData, jint dataType,
489
jobject dataObject) {
490
switch (dataType) {
491
case DT_BYTE:
492
(*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0);
493
break;
494
case DT_SHORT:
495
(*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0);
496
break;
497
case DT_INT:
498
(*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0);
499
break;
500
case DT_DOUBLE:
501
(*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData,
502
0);
503
break;
504
}
505
}
506
507
/*
508
* Class: sun_java2d_cmm_lcms_LCMS
509
* Method: colorConvert
510
* Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V
511
*/
512
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
513
(JNIEnv *env, jclass cls, jobject trans, jobject src, jobject dst)
514
{
515
cmsHTRANSFORM sTrans = NULL;
516
int srcDType, dstDType;
517
int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;
518
int width, height, i;
519
void* inputBuffer;
520
void* outputBuffer;
521
char* inputRow;
522
char* outputRow;
523
jobject srcData, dstData;
524
jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE;
525
526
srcOffset = (*env)->GetIntField (env, src, IL_offset_fID);
527
srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID);
528
dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID);
529
dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID);
530
width = (*env)->GetIntField (env, src, IL_width_fID);
531
height = (*env)->GetIntField (env, src, IL_height_fID);
532
533
srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID);
534
dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID);
535
536
sTrans = jlong_to_ptr((*env)->GetLongField (env, trans, Trans_ID_fID));
537
538
if (sTrans == NULL) {
539
J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
540
JNU_ThrowByName(env, "java/awt/color/CMMException",
541
"Cannot get color transform");
542
return;
543
}
544
545
546
inputBuffer = getILData (env, src, &srcDType, &srcData);
547
548
if (inputBuffer == NULL) {
549
J2dRlsTraceLn(J2D_TRACE_ERROR, "");
550
// An exception should have already been thrown.
551
return;
552
}
553
554
outputBuffer = getILData (env, dst, &dstDType, &dstData);
555
556
if (outputBuffer == NULL) {
557
releaseILData(env, inputBuffer, srcDType, srcData);
558
// An exception should have already been thrown.
559
return;
560
}
561
562
inputRow = (char*)inputBuffer + srcOffset;
563
outputRow = (char*)outputBuffer + dstOffset;
564
565
if (srcAtOnce && dstAtOnce) {
566
cmsDoTransform(sTrans, inputRow, outputRow, width * height);
567
} else {
568
for (i = 0; i < height; i++) {
569
cmsDoTransform(sTrans, inputRow, outputRow, width);
570
inputRow += srcNextRowOffset;
571
outputRow += dstNextRowOffset;
572
}
573
}
574
575
releaseILData(env, inputBuffer, srcDType, srcData);
576
releaseILData(env, outputBuffer, dstDType, dstData);
577
}
578
579
/*
580
* Class: sun_java2d_cmm_lcms_LCMS
581
* Method: getProfileID
582
* Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile;
583
*/
584
JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
585
(JNIEnv *env, jclass cls, jobject pf)
586
{
587
if (pf == NULL) {
588
return NULL;
589
}
590
jclass pcls = (*env)->GetObjectClass(env, pf);
591
if (pcls == NULL) {
592
return NULL;
593
}
594
jmethodID mid = (*env)->GetMethodID(env, pcls, "cmmProfile",
595
"()Lsun/java2d/cmm/Profile;");
596
if (mid == NULL) {
597
return NULL;
598
}
599
jobject cmmProfile = (*env)->CallObjectMethod(env, pf, mid);
600
if ((*env)->ExceptionOccurred(env)) {
601
return NULL;
602
}
603
jclass lcmsPCls = (*env)->FindClass(env, "sun/java2d/cmm/lcms/LCMSProfile");
604
if (lcmsPCls == NULL) {
605
return NULL;
606
}
607
if ((*env)->IsInstanceOf(env, cmmProfile, lcmsPCls)) {
608
return cmmProfile;
609
}
610
return NULL;
611
}
612
613
/*
614
* Class: sun_java2d_cmm_lcms_LCMS
615
* Method: initLCMS
616
* Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V
617
*/
618
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS
619
(JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf)
620
{
621
/* TODO: move initialization of the IDs to the static blocks of
622
* corresponding classes to avoid problems with invalidating ids by class
623
* unloading
624
*/
625
Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I");
626
if (Trans_renderType_fID == NULL) {
627
return;
628
}
629
Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J");
630
if (Trans_ID_fID == NULL) {
631
return;
632
}
633
634
IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z");
635
if (IL_isIntPacked_fID == NULL) {
636
return;
637
}
638
IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I");
639
if (IL_dataType_fID == NULL) {
640
return;
641
}
642
IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I");
643
if (IL_pixelType_fID == NULL) {
644
return;
645
}
646
IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray",
647
"Ljava/lang/Object;");
648
if (IL_dataArray_fID == NULL) {
649
return;
650
}
651
IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I");
652
if (IL_width_fID == NULL) {
653
return;
654
}
655
IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I");
656
if (IL_height_fID == NULL) {
657
return;
658
}
659
IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");
660
if (IL_offset_fID == NULL) {
661
return;
662
}
663
IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");
664
if (IL_imageAtOnce_fID == NULL) {
665
return;
666
}
667
IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");
668
if (IL_nextRowOffset_fID == NULL) {
669
return;
670
}
671
}
672
673
static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
674
{
675
cmsUInt32Number pfSize = 0;
676
cmsUInt8Number* pfBuffer = NULL;
677
cmsBool status = FALSE;
678
679
if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
680
pfSize < sizeof(cmsICCHeader) ||
681
bufferSize < (jint)sizeof(cmsICCHeader))
682
{
683
return FALSE;
684
}
685
686
pfBuffer = malloc(pfSize);
687
if (pfBuffer == NULL) {
688
return FALSE;
689
}
690
691
// load raw profile data into the buffer
692
if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {
693
memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));
694
status = TRUE;
695
}
696
free(pfBuffer);
697
return status;
698
}
699
700
static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
701
{
702
cmsICCHeader pfHeader;
703
704
if (pBuffer == NULL || bufferSize < (jint)sizeof(cmsICCHeader)) {
705
return FALSE;
706
}
707
708
memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader));
709
710
// now set header fields, which we can access using the lcms2 public API
711
cmsSetHeaderFlags(pf, _cmsAdjustEndianess32(pfHeader.flags));
712
cmsSetHeaderManufacturer(pf, _cmsAdjustEndianess32(pfHeader.manufacturer));
713
cmsSetHeaderModel(pf, _cmsAdjustEndianess32(pfHeader.model));
714
cmsUInt64Number attributes;
715
_cmsAdjustEndianess64(&attributes, &pfHeader.attributes);
716
cmsSetHeaderAttributes(pf, attributes);
717
cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID));
718
cmsSetHeaderRenderingIntent(pf, _cmsAdjustEndianess32(pfHeader.renderingIntent));
719
cmsSetPCS(pf, _cmsAdjustEndianess32(pfHeader.pcs));
720
cmsSetColorSpace(pf, _cmsAdjustEndianess32(pfHeader.colorSpace));
721
cmsSetDeviceClass(pf, _cmsAdjustEndianess32(pfHeader.deviceClass));
722
cmsSetEncodedICCversion(pf, _cmsAdjustEndianess32(pfHeader.version));
723
724
return TRUE;
725
}
726
727
/* Returns new profile handler, if it was created successfully,
728
NULL otherwise.
729
*/
730
static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,
731
const cmsTagSignature sig,
732
jbyte *pData, jint size)
733
{
734
cmsUInt32Number pfSize = 0;
735
const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);
736
cmsInt32Number i;
737
cmsHPROFILE pfSanity = NULL;
738
739
cmsICCHeader hdr;
740
741
cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);
742
743
if (NULL == p) {
744
return NULL;
745
}
746
memset(&hdr, 0, sizeof(cmsICCHeader));
747
748
// Populate the placeholder's header according to target profile
749
hdr.flags = cmsGetHeaderFlags(pfTarget);
750
hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
751
hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
752
hdr.model = cmsGetHeaderModel(pfTarget);
753
hdr.pcs = cmsGetPCS(pfTarget);
754
hdr.colorSpace = cmsGetColorSpace(pfTarget);
755
hdr.deviceClass = cmsGetDeviceClass(pfTarget);
756
hdr.version = cmsGetEncodedICCversion(pfTarget);
757
cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
758
cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
759
760
cmsSetHeaderFlags(p, hdr.flags);
761
cmsSetHeaderManufacturer(p, hdr.manufacturer);
762
cmsSetHeaderModel(p, hdr.model);
763
cmsSetHeaderAttributes(p, hdr.attributes);
764
cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
765
cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
766
cmsSetPCS(p, hdr.pcs);
767
cmsSetColorSpace(p, hdr.colorSpace);
768
cmsSetDeviceClass(p, hdr.deviceClass);
769
cmsSetEncodedICCversion(p, hdr.version);
770
771
// now write the user supplied tag
772
if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {
773
cmsCloseProfile(p);
774
return NULL;
775
}
776
777
// copy tags from the original profile
778
for (i = 0; i < tagCount; i++) {
779
cmsBool isTagReady = FALSE;
780
const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);
781
const cmsUInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
782
783
if (s == sig) {
784
// skip the user supplied tag
785
continue;
786
}
787
788
// read raw tag from the original profile
789
if (tagSize > 0) {
790
cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);
791
if (buf != NULL) {
792
if (tagSize == cmsReadRawTag(pfTarget, s, buf, tagSize)) {
793
// now we are ready to write the tag
794
isTagReady = cmsWriteRawTag(p, s, buf, tagSize);
795
}
796
free(buf);
797
}
798
}
799
800
if (!isTagReady) {
801
cmsCloseProfile(p);
802
return NULL;
803
}
804
}
805
806
// now we have all tags moved to the new profile.
807
// do some sanity checks: write it to a memory buffer and read again.
808
if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
809
void* buf = malloc(pfSize);
810
if (buf != NULL) {
811
// load raw profile data into the buffer
812
if (cmsSaveProfileToMem(p, buf, &pfSize)) {
813
pfSanity = cmsOpenProfileFromMem(buf, pfSize);
814
}
815
free(buf);
816
}
817
}
818
819
if (pfSanity == NULL) {
820
// for some reason, we failed to save and read the updated profile
821
// It likely indicates that the profile is not correct, so we report
822
// a failure here.
823
cmsCloseProfile(p);
824
p = NULL;
825
} else {
826
// do final check whether we can read and handle the target tag.
827
const void* pTag = cmsReadTag(pfSanity, sig);
828
if (pTag == NULL) {
829
// the tag can not be cooked
830
cmsCloseProfile(p);
831
p = NULL;
832
}
833
cmsCloseProfile(pfSanity);
834
pfSanity = NULL;
835
}
836
837
return p;
838
}
839
840