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