Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gsicc_create.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* This is the code that is used to convert the various PDF and PS CIE
18
   based color spaces to ICC profiles.  This enables the use of an
19
   external CMS that is ICC centric to be used for ALL color management.
20
21
   The following spaces are handled:
22
23
   From PDF
24
25
   % Input Spaces
26
27
   CalRGB      -->  ICC 1-D LUTS and Matrix
28
   CalGray     -->  ICC 1-D LUT
29
   LAB         -->  ICC MLUT with a 2x2 sized table
30
31
   From PS
32
33
   %% Input Spaces
34
35
   CIEBasedABC  --> ICC 1-D LUTs and Matrix
36
   CIEBasedA    --> ICC 1-D LUT
37
   CIEBasedDEF  --> 3-D MLUT plus 1-D LUTs
38
   CIEBasedDEFG --> 4-D MLUT pluse 1-D LUTs
39
40
   %% Output Spaces
41
42
   Type1 CRD -->  ICC will have MLUT if render table present.
43
44
   A few notes:
45
46
   Required Tags for ALL profiles include:
47
48
       profileDescriptionTag
49
       copyrightTag
50
       mediaWhatePointTag
51
       chromaticAdaptationTag (V4 -  when measurement data is for other than D50)
52
53
   For color input profiles:
54
55
       Required if N-component LUT-based:
56
57
          AToB0Tag   (NOTE ONE WAY! BtoA0Tag is optional. Not true for
58
                          display profiles.)
59
60
       Required if 3 component matrix based:
61
62
           redMatrixColumnTag
63
           greenMatrixColumnTag
64
           blueMatrixColumnTag
65
           redTRCTag
66
           greenTRCTag
67
           blueTRCTag
68
69
       Notes:
70
71
       3-component can include AToB0Tag.
72
       Only CIEXYZ encoding can be used with matrix/TRC models.
73
       If CIELAB encoding is to be used, we must use LUT-based.
74
75
    For Monochrome input:
76
77
       Required:
78
           grayTRCTag
79
80
       Optional
81
           AToB0Tag
82
83
    For Color Display Profiles:
84
85
        Required if N-Component LUT-Based
86
87
            AtoB0Tag
88
            BToA0Tag   (Note inverse required here).
89
90
        Required if 3 component matrix based display profiles
91
92
            redMatrixColumnTag
93
            greenMatrixColumnTag
94
            blueMatrixColumnTag
95
            redTRCTag
96
            greenTRCTag
97
            blueTRCTag
98
99
        Optional
100
101
            AtoB0Tag
102
            BToA0Tag   (Note inverse required here).
103
104
    For Monochrome Display Profiles
105
106
        Required
107
108
            grayTRCTag
109
110
        Optional
111
112
            AtoB0Tag
113
            BtoA0Tag
114
115
Note: All profile data must be encoded as big-endian
116
117
   */
118
119
#include "icc34.h"   /* Note this header is needed even if lcms is not
120
                            compiled as default CMS */
121
#include "std.h"
122
#include "string_.h"
123
#include "gsmemory.h"
124
#include "gx.h"
125
#include "gp.h"
126
127
#include "gxgstate.h"
128
#include "gstypes.h"
129
#include "gscspace.h"
130
#include "gscie.h"
131
#include "gsicc_create.h"
132
#include "gxarith.h"
133
#include "gsicc_manage.h"
134
#include "gsicc_cache.h"
135
#include "math_.h"
136
#include "gscolor2.h"
137
#include "gxcie.h"
138
139
static void
140
add_xyzdata(unsigned char *input_ptr, icS15Fixed16Number temp_XYZ[]);
141
142
#define SAVEICCPROFILE 0
143
7.15k
#define HEADER_SIZE 128
144
7.15k
#define TAG_SIZE 12
145
11.3k
#define XYZPT_SIZE 12
146
36.3k
#define DATATYPE_SIZE 8
147
288
#define CURVE_SIZE 512
148
114
#define IDENT_CURVE_SIZE 0
149
9.53k
#define NUMBER_COMMON_TAGS 2
150
4.76k
#define icMultiUnicodeText 0x6d6c7563           /* 'mluc' v4 text type */
151
23
#define icMultiFunctionAtoBType 0x6d414220      /* 'mAB ' v4 lutAtoBtype type */
152
4.80k
#define D50_X 0.9642f
153
4.80k
#define D50_Y 1.0f
154
4.80k
#define D50_Z 0.8249f
155
0
#define DEFAULT_TABLE_NSIZE 9
156
0
#define FORWARD_V2_TABLE_SIZE 9
157
0
#define BACKWARD_V2_TABLE_SIZE 33
158
0
#define DEFAULT_TABLE_GRAYSIZE 128
159
0
#define V2_COMMON_TAGS NUMBER_COMMON_TAGS + 1
160
161
typedef unsigned short u1Fixed15Number;
162
#if SAVEICCPROFILE
163
unsigned int icc_debug_index = 0;
164
#endif
165
166
typedef struct cielab_s {
167
    float lstar;
168
    float astar;
169
    float bstar;
170
} cielab_t;
171
172
static const char desc_name[] = "Ghostscript Internal Profile";
173
static const char copy_right[] = "Copyright Artifex Software 2009-2023";
174
175
typedef struct {
176
    icTagSignature      sig;            /* The tag signature */
177
    icUInt32Number      offset;         /* Start of tag relative to
178
                                         * start of header, Spec
179
                                         * Clause 5 */
180
    icUInt32Number      size;           /* Size in bytes */
181
    unsigned char       byte_padding;
182
} gsicc_tag;
183
/* In generating 2x2x2 approximations as well as cases
184
   where we will need to squash components together we
185
   will go to float and then to 16 bit tables, hence the
186
   float pointer.  Otherwise we will keep the data
187
   in the existing byte form that it is in the CIEDEF(G)
188
   tables of postscript */
189
typedef struct {
190
    unsigned short *data_short;
191
    unsigned char *data_byte;  /* Used for cases where we can
192
                                   use the table as is */
193
    int     clut_dims[4];
194
    int     clut_num_input;
195
    int     clut_num_output;
196
    int     clut_num_entries;   /* Number of entries */
197
    int     clut_word_width;    /* Word width of table, 1 or 2 */
198
} gsicc_clut;
199
200
typedef struct {
201
    float   *a_curves;
202
    gsicc_clut *clut;
203
    float   *m_curves;
204
    gs_matrix3 *matrix;
205
    float   *b_curves;
206
    int num_in;
207
    int num_out;
208
    gs_vector3 *white_point;
209
    gs_vector3 *black_point;
210
    float *cam;
211
} gsicc_lutatob;
212
213
static int
214
get_padding(int x)
215
22.9k
{
216
22.9k
    return (4 -x%4)%4;
217
22.9k
}
218
219
/* For some weird reason I cant link to the one in gscie.c */
220
static void
221
gsicc_matrix_init(register gs_matrix3 * mat)
222
16
{
223
16
    mat->is_identity =
224
16
        mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
225
8
        mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
226
8
        mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
227
16
}
228
229
static void
230
gsicc_make_diag_matrix(gs_matrix3 *matrix, gs_vector3 * vec)
231
0
{
232
0
    matrix->cu.u = vec->u;
233
0
    matrix->cv.v = vec->v;
234
0
    matrix->cw.w = vec->w;
235
0
    matrix->cu.v = 0;
236
0
    matrix->cu.w = 0;
237
0
    matrix->cw.u = 0;
238
0
    matrix->cw.v = 0;
239
0
    matrix->cv.u = 0;
240
0
    matrix->cv.w = 0;
241
0
    matrix->is_identity = (vec->u == 1.0)&&(vec->v == 1.0)&&(vec->w == 1.0);
242
0
}
243
244
/* This function maps a gs matrix type to an ICC CLUT. This is required due to the
245
   multiple matrix and 1-D LUT forms for postscript management, which the ICC does not
246
   support (at least the older versions).  clut is allocated externally */
247
static void
248
gsicc_matrix3_to_mlut(gs_matrix3 *mat, unsigned short *clut)
249
0
{
250
    /* Step through the grid values */
251
0
    float grid_points[8][3]={{0,0,0},
252
0
                             {0,0,1},
253
0
                             {0,1,0},
254
0
                             {0,1,1},
255
0
                             {1,0,0},
256
0
                             {1,0,1},
257
0
                             {1,1,0},
258
0
                             {1,1,1}};
259
0
    int k;
260
0
    gs_vector3 input,output;
261
0
    unsigned short *curr_ptr = clut, value;
262
0
    float valueflt;
263
264
0
    for (k = 0; k < 8; k++) {
265
0
        input.u = grid_points[k][0];
266
0
        input.v = grid_points[k][1];
267
0
        input.w = grid_points[k][2];
268
0
        cie_mult3(&input, mat, &output);
269
0
        valueflt = output.u;
270
0
        if (valueflt < 0) valueflt = 0;
271
0
        if (valueflt > 1) valueflt = 1;
272
0
        value = (unsigned short) (valueflt*65535.0);
273
0
        *curr_ptr ++= value;
274
0
        valueflt = output.v;
275
0
        if (valueflt < 0) valueflt = 0;
276
0
        if (valueflt > 1) valueflt = 1;
277
0
        value = (unsigned short) (valueflt*65535.0);
278
0
        *curr_ptr ++= value;
279
0
        valueflt = output.w;
280
0
        if (valueflt < 0) valueflt = 0;
281
0
        if (valueflt > 1) valueflt = 1;
282
0
        value = (unsigned short) (valueflt*65535.0);
283
0
        *curr_ptr ++= value;
284
0
    }
285
0
}
286
287
static void
288
apply_adaption(float matrix[], float in[], float out[])
289
8.96k
{
290
8.96k
    out[0] = matrix[0] * in[0] + matrix[1] * in[1] + matrix[2] * in[2];
291
8.96k
    out[1] = matrix[3] * in[0] + matrix[4] * in[1] + matrix[5] * in[2];
292
8.96k
    out[2] = matrix[6] * in[0] + matrix[7] * in[1] + matrix[8] * in[2];
293
8.96k
}
294
295
/* This function mashes all the elements together into a single CLUT
296
   for the ICC profile.  This is an approach of last resort, but
297
   guaranteed to work. */
298
static int
299
gsicc_create_clut(const gs_color_space *pcs, gsicc_clut *clut, gs_range *ranges,
300
                  gs_vector3 *white_point, bool range_adjust, float cam[],
301
                  gs_memory_t *memory)
302
0
{
303
0
    gs_gstate *pgs;
304
0
    int code;
305
0
    int num_points = clut->clut_num_entries;
306
0
    int table_size = clut->clut_dims[0]; /* Same resolution in each direction*/
307
0
    int num_components = clut->clut_num_input;
308
0
    int j,i,index;
309
0
    float *input_samples[4], *fltptr;
310
0
    gs_range *curr_range;
311
0
    unsigned short *ptr_short;
312
0
    gs_client_color cc;
313
0
    frac xyz[3];
314
0
    float xyz_float[3];
315
0
    float temp;
316
0
    gs_color_space_index cs_index;
317
318
    /* This completes the joint cache inefficiently so that
319
       we can sample through it and get our table entries */
320
0
    code = gx_cie_to_xyz_alloc(&pgs, pcs, memory);
321
0
    if (code < 0)
322
0
        return gs_rethrow(code, "Allocation of cie to xyz transform failed");
323
0
    cs_index = gs_color_space_get_index(pcs);
324
325
    /* Create the sample indices across the input ranges
326
       for each color component.  When the concretization/remap occurs
327
       to be fed into this icc profile, we may will need to apply a linear
328
       map to the input if the range is something other than 0 to 1 */
329
0
    for (i = 0; i < num_components; i++) {
330
0
        input_samples[i] = (float*) gs_alloc_bytes(memory,
331
0
                                sizeof(float) * (size_t)table_size,"gsicc_create_clut");
332
0
        if (input_samples[i] == NULL) {
333
0
            for (j = 0; j < i; j++) {
334
0
                gs_free_object(memory, input_samples[j], "gsicc_create_clut");
335
0
            }
336
0
            return gs_throw(gs_error_VMerror, "Allocation of input_sample arrays failed");
337
0
        }
338
0
        fltptr = input_samples[i];
339
0
        curr_range = &(ranges[i]);
340
0
        for (j = 0; j < table_size; j++ ) {
341
0
            *fltptr ++= ((float) j/ (float) (table_size-1)) *
342
0
                (curr_range->rmax - curr_range->rmin) + curr_range->rmin;
343
0
        }
344
0
    }
345
    /* Go through all the entries.
346
       Uniformly from min range to max range */
347
0
    ptr_short = clut->data_short;
348
0
    for (i = 0; i < num_points; i++) {
349
0
        switch (num_components) {
350
0
        case 1:
351
            /* Get the input vector value */
352
0
            fltptr = input_samples[0];
353
0
            index = i%table_size;
354
0
            cc.paint.values[0] = fltptr[index];
355
0
            break;
356
0
        case 3:
357
            /* The first channel varies least rapidly in the ICC table */
358
0
            fltptr = input_samples[2];
359
0
            index = i%table_size;
360
0
            cc.paint.values[2] = fltptr[index];
361
0
            fltptr = input_samples[1];
362
0
            index = (unsigned int) floor((float) i/(float) table_size)%table_size;
363
0
            cc.paint.values[1] = fltptr[index];
364
0
            fltptr = input_samples[0];
365
0
            index = (unsigned int) floor((float) i/(float) (table_size*
366
0
                                                        table_size))%table_size;
367
0
            cc.paint.values[0] = fltptr[index];
368
0
            break;
369
0
        case 4:
370
            /* The first channel varies least rapidly in the ICC table */
371
0
            fltptr = input_samples[3];
372
0
            index = i%table_size;
373
0
            cc.paint.values[3] = fltptr[index];
374
0
            fltptr = input_samples[2];
375
0
            index = (unsigned int) floor((float) i/(float) table_size)%table_size;
376
0
            cc.paint.values[2] = fltptr[index];
377
0
            fltptr = input_samples[1];
378
0
            index = (unsigned int) floor((float) i/(float) (table_size*
379
0
                                                        table_size))%table_size;
380
0
            cc.paint.values[1] = fltptr[index];
381
0
            fltptr = input_samples[0];
382
0
            index = (unsigned int) floor((float) i/(float) (table_size*
383
0
                                        table_size*table_size))%table_size;
384
0
            cc.paint.values[0] = fltptr[index];
385
0
            break;
386
0
        default:
387
0
            return_error(gs_error_rangecheck); /* Should never happen */
388
0
        }
389
        /* These special concretizations functions do not go through
390
           the ICC mapping like the procs associated with the color space */
391
0
        switch (cs_index) {
392
0
            case gs_color_space_index_CIEA:
393
0
                gx_psconcretize_CIEA(&cc, pcs, xyz, xyz_float, pgs);
394
                /* AR forces this case to always be achromatic.  We will
395
                   do the same even though it does not match the PS
396
                   specification */
397
                /* Use the resulting Y value to scale the D50 Illumination.
398
                   note that we scale to the whitepoint here.  Matrix out
399
                   handles mapping to CIE D50 */
400
0
                xyz_float[0] = white_point->u * xyz_float[1];
401
0
                xyz_float[2] = white_point->w * xyz_float[1];
402
0
                break;
403
0
            case gs_color_space_index_CIEABC:
404
0
                gx_psconcretize_CIEABC(&cc, pcs, xyz, xyz_float, pgs);
405
0
                break;
406
0
            case gs_color_space_index_CIEDEF:
407
0
                gx_psconcretize_CIEDEF(&cc, pcs, xyz, xyz_float, pgs);
408
0
                break;
409
0
            case gs_color_space_index_CIEDEFG:
410
0
               gx_psconcretize_CIEDEFG(&cc, pcs, xyz, xyz_float, pgs);
411
0
               break;
412
0
            default:
413
0
                return gs_throw(-1, "Invalid gs_color_space_index when creating ICC profile");
414
0
        }
415
        /* We need to map these values to D50 illuminant so that things work
416
           correctly with ICC profile */
417
        /* apply_adaption(cam, xyz_float, xyz_adapt); */
418
419
        /* Correct for range of ICC CIEXYZ table data */
420
0
        for (j = 0; j < 3; j++) {
421
0
            temp = xyz_float[j]/(1 + 32767.0/32768);
422
0
            if (temp < 0) temp = 0;
423
0
            if (temp > 1) temp = 1;
424
0
           *ptr_short ++= (unsigned int)(temp * 65535);
425
0
        }
426
0
    }
427
0
    gx_cie_to_xyz_free(pgs); /* Free the joint cache we created */
428
0
    for (i = 0; i < num_components; i++) {
429
0
        gs_free_object(memory, input_samples[i], "gsicc_create_clut");
430
0
    }
431
0
    return 0;
432
0
}
433
434
/* This function maps a gs vector type to an ICC CLUT.
435
   This is used in the CIEA type.  clut is allocated
436
   externally. We may need to replace this with a range value.
437
   For now we are mapping to an output between 0 and the vector */
438
static void
439
gsicc_vec_to_mlut(gs_vector3 *vec, unsigned short *clut)
440
15
{
441
15
    unsigned short *curr_ptr = clut;
442
15
    int temp;
443
444
15
    *curr_ptr ++= 0;
445
15
    *curr_ptr ++= 0;
446
15
    *curr_ptr ++= 0;
447
15
    temp = (int)(vec->u * 65535);
448
15
    if (temp > 65535) temp = 65535;
449
15
    if (temp < 0) temp = 0;
450
15
    *curr_ptr ++= temp;
451
15
    temp = (int)(vec->v * 65535);
452
15
    if (temp > 65535) temp = 65535;
453
15
    if (temp < 0) temp = 0;
454
15
    *curr_ptr ++= temp;
455
15
    temp = (int)(vec->w * 65535);
456
15
    if (temp > 65535) temp = 65535;
457
15
    if (temp < 0) temp = 0;
458
15
    *curr_ptr ++= temp;
459
15
}
460
461
#if SAVEICCPROFILE
462
/* Debug dump of internally created ICC profile for testing */
463
static void
464
save_profile(const gs_memory_t *mem, unsigned char *buffer, char filename[], int buffer_size)
465
{
466
    char full_file_name[50];
467
    gp_file *fid;
468
469
    gs_snprintf(full_file_name,sizeof(full_file_name),"%d)Profile_%s.icc",icc_debug_index,filename);
470
    fid = gp_fopen(mem, full_file_name,"wb");
471
    gp_fwrite(buffer,sizeof(unsigned char),buffer_size,fid);
472
    gp_fclose(fid);
473
    icc_debug_index++;
474
}
475
#endif
476
477
static void
478
write_bigendian_4bytes(unsigned char *curr_ptr,ulong input)
479
178k
{
480
178k
   *curr_ptr++ = (0xff & (input >> 24));
481
178k
   *curr_ptr++ = (0xff & (input >> 16));
482
178k
   *curr_ptr++ = (0xff & (input >> 8));
483
178k
   *curr_ptr++ = (0xff & input);
484
178k
}
485
486
static void
487
write_bigendian_2bytes(unsigned char *curr_ptr,ushort input)
488
43.5k
{
489
43.5k
   *curr_ptr++ = (0xff & (input >> 8));
490
43.5k
   *curr_ptr++ = (0xff & input);
491
43.5k
}
492
493
static void
494
setdatetime(icDateTimeNumber *datetime)
495
2.39k
{
496
2.39k
    datetime->day = 0;
497
2.39k
    datetime->hours = 0;
498
2.39k
    datetime->minutes = 0;
499
2.39k
    datetime->month = 0;
500
2.39k
    datetime->seconds = 0;
501
2.39k
    datetime->year = 0;
502
2.39k
}
503
504
static icS15Fixed16Number
505
double2XYZtype(float number_in)
506
41.2k
{
507
41.2k
    short s;
508
41.2k
    unsigned short m;
509
510
41.2k
    if (number_in < 0) {
511
1.80k
        number_in = 0;
512
#ifdef DEBUG
513
        gs_warn("Negative CIEXYZ in created ICC Profile");
514
#endif
515
1.80k
    }
516
517
41.2k
    s = (short) number_in;
518
41.2k
    m = (unsigned short) ((number_in - s) * 65536.0);
519
41.2k
    return (icS15Fixed16Number) ((s << 16) | m);
520
41.2k
}
521
522
static icS15Fixed16Number
523
double2icS15Fixed16Number(float number_in)
524
207
{
525
207
    short s;
526
207
    unsigned short m;
527
207
    icS15Fixed16Number temp;
528
207
    float number;
529
530
207
    if (number_in < 0) {
531
0
        number = -number_in;
532
0
        s = (short) number;
533
0
        m = (unsigned short) ((number - s) * 65536.0);
534
0
        temp = (icS15Fixed16Number) ((s << 16) | m);
535
0
        temp = -temp;
536
0
        return temp;
537
207
    } else {
538
207
        s = (short) number_in;
539
207
        m = (unsigned short) ((number_in - s) * 65536.0);
540
207
        return (icS15Fixed16Number) ((s << 16) | m);
541
207
    }
542
207
}
543
544
static unsigned short
545
float2u8Fixed8(float number_in)
546
6.76k
{
547
6.76k
    return (unsigned short) (number_in * 256);
548
6.76k
}
549
550
static
551
void init_common_tags(gsicc_tag tag_list[],int num_tags, int *last_tag)
552
2.38k
{
553
 /*    profileDescriptionTag
554
       copyrightTag  */
555
556
2.38k
    int curr_tag, temp_size;
557
558
2.38k
    if (*last_tag < 0)
559
2.38k
        curr_tag = 0;
560
0
    else
561
0
        curr_tag = (*last_tag)+1;
562
563
2.38k
    tag_list[curr_tag].offset = HEADER_SIZE+num_tags*TAG_SIZE + 4;
564
2.38k
    tag_list[curr_tag].sig = icSigProfileDescriptionTag;
565
    /* temp_size = DATATYPE_SIZE + 4 + strlen(desc_name) + 1 + 4 + 4 + 3 + 67; */
566
2.38k
    temp_size = 2*strlen(desc_name) + 28;
567
    /* +1 for NULL + 4 + 4 for unicode + 3 + 67 script code */
568
2.38k
    tag_list[curr_tag].byte_padding = get_padding(temp_size);
569
2.38k
    tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
570
571
2.38k
    curr_tag++;
572
573
2.38k
    tag_list[curr_tag].offset = tag_list[curr_tag-1].offset +
574
2.38k
                                                    tag_list[curr_tag-1].size;
575
2.38k
    tag_list[curr_tag].sig = icSigCopyrightTag;
576
    /* temp_size = DATATYPE_SIZE + strlen(copy_right) + 1; */
577
2.38k
    temp_size = 2*strlen(copy_right) + 28;
578
2.38k
    tag_list[curr_tag].byte_padding = get_padding(temp_size);
579
2.38k
    tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
580
2.38k
    *last_tag = curr_tag;
581
2.38k
}
582
583
/* Code to write out v4 text type which is a table of unicode text
584
   for different regions */
585
static void
586
add_v4_text_tag(unsigned char *buffer,const char text[], gsicc_tag tag_list[],
587
                int curr_tag)
588
4.76k
{
589
4.76k
    unsigned char *curr_ptr;
590
4.76k
    int k;
591
592
4.76k
    curr_ptr = buffer;
593
4.76k
    write_bigendian_4bytes(curr_ptr,icMultiUnicodeText);
594
4.76k
    curr_ptr += 4;
595
4.76k
    memset(curr_ptr,0,4);
596
4.76k
    curr_ptr += 4;
597
4.76k
    write_bigendian_4bytes(curr_ptr,1); /* Number of names */
598
4.76k
    curr_ptr += 4;
599
4.76k
    write_bigendian_4bytes(curr_ptr,12); /* Record size */
600
4.76k
    curr_ptr += 4;
601
4.76k
    write_bigendian_2bytes(curr_ptr,0x656e); /* ISO 639-1, en */
602
4.76k
    curr_ptr += 2;
603
4.76k
    write_bigendian_2bytes(curr_ptr,0x5553); /* ISO 3166, US */
604
4.76k
    curr_ptr += 2;
605
4.76k
    write_bigendian_4bytes(curr_ptr,2*strlen(text)); /* String length */
606
4.76k
    curr_ptr += 4;
607
4.76k
    write_bigendian_4bytes(curr_ptr,28); /* Offset to string */
608
4.76k
    curr_ptr += 4;
609
    /* String written as UTF-16BE. No NULL */
610
157k
    for (k = 0; k < strlen(text); k++) {
611
152k
        *curr_ptr ++= 0;
612
152k
        *curr_ptr ++= text[k];
613
152k
    }
614
4.76k
    memset(curr_ptr,0,tag_list[curr_tag].byte_padding);  /* padding */
615
4.76k
}
616
617
static void
618
add_desc_tag(unsigned char *buffer, const char text[], gsicc_tag tag_list[],
619
                int curr_tag)
620
0
{
621
0
    unsigned char *curr_ptr;
622
0
    int len = strlen(text) + 1;
623
0
    int k;
624
625
0
    curr_ptr = buffer;
626
0
    write_bigendian_4bytes(curr_ptr, icSigTextDescriptionType);
627
0
    curr_ptr += 4;
628
0
    memset(curr_ptr, 0, 4);
629
0
    curr_ptr += 4;
630
0
    write_bigendian_4bytes(curr_ptr, len);
631
0
    curr_ptr += 4;
632
0
    for (k = 0; k < strlen(text); k++) {
633
0
        *curr_ptr++ = text[k];
634
0
    }
635
0
    memset(curr_ptr, 0, 12 + 67 + 1);
636
0
    memset(curr_ptr, 0, tag_list[curr_tag].byte_padding);  /* padding */
637
0
}
638
639
static void
640
add_text_tag(unsigned char *buffer, const char text[], gsicc_tag tag_list[],
641
            int curr_tag)
642
0
{
643
0
    unsigned char *curr_ptr;
644
0
    int k;
645
646
0
    curr_ptr = buffer;
647
0
    write_bigendian_4bytes(curr_ptr, icSigTextType);
648
0
    curr_ptr += 4;
649
0
    memset(curr_ptr, 0, 4);
650
0
    curr_ptr += 4;
651
0
    for (k = 0; k < strlen(text); k++) {
652
0
        *curr_ptr++ = text[k];
653
0
    }
654
0
    memset(curr_ptr, 0, 1);
655
0
    memset(curr_ptr, 0, tag_list[curr_tag].byte_padding);  /* padding */
656
0
}
657
658
static void
659
add_common_tag_data(unsigned char *buffer,gsicc_tag tag_list[], int vers)
660
2.38k
{
661
2.38k
    unsigned char *curr_ptr;
662
2.38k
    curr_ptr = buffer;
663
664
2.38k
    if (vers == 4) {
665
2.38k
        add_v4_text_tag(curr_ptr, desc_name, tag_list, 0);
666
2.38k
        curr_ptr += tag_list[0].size;
667
2.38k
        add_v4_text_tag(curr_ptr, copy_right, tag_list, 1);
668
2.38k
    } else {
669
0
        add_desc_tag(curr_ptr, desc_name, tag_list, 0);
670
0
        curr_ptr += tag_list[0].size;
671
0
        add_text_tag(curr_ptr, copy_right, tag_list, 1);
672
0
    }
673
2.38k
}
674
675
static
676
void  init_tag(gsicc_tag tag_list[], int *last_tag, icTagSignature tagsig,
677
               int datasize)
678
18.1k
{
679
    /* This should never be called first. Common tags should be taken care of */
680
681
18.1k
    int curr_tag = (*last_tag)+1;
682
683
18.1k
    tag_list[curr_tag].offset = tag_list[curr_tag-1].offset +
684
18.1k
                                                    tag_list[curr_tag-1].size;
685
18.1k
    tag_list[curr_tag].sig = tagsig;
686
18.1k
    tag_list[curr_tag].byte_padding = get_padding(DATATYPE_SIZE + datasize);
687
18.1k
    tag_list[curr_tag].size = DATATYPE_SIZE + datasize +
688
18.1k
                                            tag_list[curr_tag].byte_padding;
689
18.1k
    *last_tag = curr_tag;
690
18.1k
}
691
692
static void
693
setheader_common(icHeader *header, int vers)
694
2.39k
{
695
    /* This needs to all be predefined for a simple copy. MJV todo */
696
2.39k
    header->cmmId = 0;
697
2.39k
    if (vers == 4)
698
2.38k
        header->version = 0x04200000;
699
6
    else
700
6
        header->version = 0x02200000;
701
2.39k
    setdatetime(&(header->date));
702
2.39k
    header->magic = icMagicNumber;
703
2.39k
    header->platform = icSigMacintosh;
704
2.39k
    header->flags = 0;
705
2.39k
    header->manufacturer = 0;
706
2.39k
    header->model = 0;
707
2.39k
    header->attributes[0] = 0;
708
2.39k
    header->attributes[1] = 0;
709
2.39k
    header->renderingIntent = 3;
710
2.39k
    header->illuminant.X = double2XYZtype((float) 0.9642);
711
2.39k
    header->illuminant.Y = double2XYZtype((float) 1.0);
712
2.39k
    header->illuminant.Z = double2XYZtype((float) 0.8249);
713
2.39k
    header->creator = 0;
714
    /* Version 4 includes a profile id, field which is an md5 sum */
715
2.39k
    memset(header->reserved,0,44);
716
2.39k
}
717
718
static void
719
copy_header(unsigned char *buffer,icHeader *header)
720
2.38k
{
721
2.38k
    unsigned char *curr_ptr;
722
723
2.38k
    curr_ptr = buffer;
724
2.38k
    write_bigendian_4bytes(curr_ptr,header->size);
725
2.38k
    curr_ptr += 4;
726
2.38k
    memset(curr_ptr,0,4);
727
2.38k
    curr_ptr += 4;
728
2.38k
    write_bigendian_4bytes(curr_ptr,header->version);
729
2.38k
    curr_ptr += 4;
730
2.38k
    write_bigendian_4bytes(curr_ptr,header->deviceClass);
731
2.38k
    curr_ptr += 4;
732
2.38k
    write_bigendian_4bytes(curr_ptr,header->colorSpace);
733
2.38k
    curr_ptr += 4;
734
2.38k
    write_bigendian_4bytes(curr_ptr,header->pcs);
735
2.38k
    curr_ptr += 4;
736
737
    /* Date and time */
738
2.38k
    memset(curr_ptr,0,12);
739
2.38k
    curr_ptr += 12;
740
2.38k
    write_bigendian_4bytes(curr_ptr,header->magic);
741
2.38k
    curr_ptr += 4;
742
2.38k
    write_bigendian_4bytes(curr_ptr,header->platform);
743
2.38k
    curr_ptr += 4;
744
2.38k
    memset(curr_ptr,0,24);
745
2.38k
    curr_ptr += 24;
746
2.38k
    write_bigendian_4bytes(curr_ptr,header->illuminant.X);
747
2.38k
    curr_ptr += 4;
748
2.38k
    write_bigendian_4bytes(curr_ptr,header->illuminant.Y);
749
2.38k
    curr_ptr += 4;
750
2.38k
    write_bigendian_4bytes(curr_ptr,header->illuminant.Z);
751
2.38k
    curr_ptr += 4;
752
2.38k
    memset(curr_ptr,0,48);
753
2.38k
}
754
755
static void
756
copy_tagtable(unsigned char *buffer,gsicc_tag *tag_list, ulong num_tags)
757
2.38k
{
758
2.38k
    unsigned int k;
759
2.38k
    unsigned char *curr_ptr;
760
761
2.38k
    curr_ptr = buffer;
762
2.38k
    write_bigendian_4bytes(curr_ptr,num_tags);
763
2.38k
    curr_ptr += 4;
764
25.3k
    for (k = 0; k < num_tags; k++) {
765
22.9k
        write_bigendian_4bytes(curr_ptr,tag_list[k].sig);
766
22.9k
        curr_ptr += 4;
767
22.9k
        write_bigendian_4bytes(curr_ptr,tag_list[k].offset);
768
22.9k
        curr_ptr += 4;
769
22.9k
        write_bigendian_4bytes(curr_ptr,tag_list[k].size);
770
22.9k
        curr_ptr += 4;
771
22.9k
    }
772
2.38k
}
773
774
static void
775
get_D50(icS15Fixed16Number XYZ[])
776
2.38k
{
777
2.38k
    XYZ[0] = double2XYZtype(D50_X);
778
2.38k
    XYZ[1] = double2XYZtype(D50_Y);
779
2.38k
    XYZ[2] = double2XYZtype(D50_Z);
780
2.38k
}
781
782
static void
783
get_XYZ(icS15Fixed16Number XYZ[], gs_vector3 *vector)
784
23
{
785
23
    XYZ[0] = double2XYZtype(vector->u);
786
23
    XYZ[1] = double2XYZtype(vector->v);
787
23
    XYZ[2] = double2XYZtype(vector->w);
788
23
}
789
790
static void
791
get_XYZ_doubletr(icS15Fixed16Number XYZ[], float *vector)
792
8.96k
{
793
8.96k
    XYZ[0] = double2XYZtype(vector[0]);
794
8.96k
    XYZ[1] = double2XYZtype(vector[1]);
795
8.96k
    XYZ[2] = double2XYZtype(vector[2]);
796
8.96k
}
797
798
static void
799
scale_matrix(float *matrix_input,float scale_factor)
800
8
{
801
8
    int k;
802
803
80
    for (k = 0; k < 9; k++) {
804
72
        matrix_input[k] = matrix_input[k]/2.0;
805
72
    }
806
8
}
807
808
static void
809
add_gammadata(unsigned char *input_ptr, unsigned short gamma,
810
              icTagTypeSignature curveType)
811
6.76k
{
812
6.76k
    unsigned char *curr_ptr;
813
814
6.76k
    curr_ptr = input_ptr;
815
6.76k
    write_bigendian_4bytes(curr_ptr,curveType);
816
6.76k
    curr_ptr += 4;
817
6.76k
    memset(curr_ptr,0,4);
818
6.76k
    curr_ptr += 4;
819
820
    /* one entry for gamma */
821
6.76k
    write_bigendian_4bytes(curr_ptr, 1);
822
6.76k
    curr_ptr += 4;
823
824
    /* The encode (8frac8) gamma, with padding */
825
6.76k
    write_bigendian_2bytes(curr_ptr, gamma);
826
6.76k
    curr_ptr += 2;
827
828
    /* pad two bytes */
829
6.76k
    memset(curr_ptr,0,2);
830
6.76k
}
831
832
static void
833
add_xyzdata(unsigned char *input_ptr, icS15Fixed16Number temp_XYZ[])
834
11.3k
{
835
11.3k
    int j;
836
11.3k
    unsigned char *curr_ptr;
837
838
11.3k
    curr_ptr = input_ptr;
839
11.3k
    write_bigendian_4bytes(curr_ptr,icSigXYZType);
840
11.3k
    curr_ptr += 4;
841
11.3k
    memset(curr_ptr,0,4);
842
11.3k
    curr_ptr += 4;
843
45.4k
    for (j = 0; j < 3; j++) {
844
34.1k
        write_bigendian_4bytes(curr_ptr, temp_XYZ[j]);
845
34.1k
        curr_ptr += 4;
846
34.1k
    }
847
11.3k
}
848
849
/* If abc matrix is identity the abc and lmn curves can be mashed together  */
850
static void
851
merge_abc_lmn_curves(gx_cie_vector_cache *DecodeABC_caches,
852
                     gx_cie_scalar_cache *DecodeLMN)
853
0
{
854
855
0
}
856
857
static void
858
add_matrixwithbias(unsigned char *input_ptr, float *float_ptr_in, bool has_bias)
859
23
{
860
23
    unsigned char *curr_ptr;
861
23
    float *float_ptr = float_ptr_in;
862
23
    int k;
863
864
    /* GS Matrix is coming in with data arranged in row ordered form */
865
23
    curr_ptr = input_ptr;
866
230
    for (k = 0; k < 9; k++ ){
867
207
        write_bigendian_4bytes(curr_ptr, double2icS15Fixed16Number(*float_ptr));
868
207
        curr_ptr += 4;
869
207
        float_ptr++;
870
207
    }
871
23
    if (has_bias){
872
23
        memset(curr_ptr,0,4*3);
873
23
    }
874
23
}
875
876
static void
877
matrixmult(float leftmatrix[], int nlrow, int nlcol,
878
           float rightmatrix[], int nrrow, int nrcol, float result[])
879
9.65k
{
880
9.65k
    float *curr_row;
881
9.65k
    int k,l,j,ncols,nrows;
882
9.65k
    float sum;
883
884
9.65k
    nrows = nlrow;
885
9.65k
    ncols = nrcol;
886
9.65k
    if (nlcol == nrrow) {
887
38.6k
        for (k = 0; k < nrows; k++) {
888
28.9k
            curr_row = &(leftmatrix[k*nlcol]);
889
86.9k
            for (l = 0; l < ncols; l++) {
890
57.9k
                sum = 0.0;
891
231k
                for (j = 0; j < nlcol; j++) {
892
173k
                    sum = sum + curr_row[j] * rightmatrix[j*nrcol+l];
893
173k
                }
894
57.9k
                result[k*ncols+l] = sum;
895
57.9k
            }
896
28.9k
        }
897
9.65k
    }
898
9.65k
}
899
900
static void
901
gsicc_create_copy_matrix3(float *src, float *des)
902
0
{
903
0
    memcpy(des,src,9*sizeof(float));
904
0
}
905
906
static void
907
gsicc_create_compute_cam( gs_vector3 *white_src, gs_vector3 *white_des,
908
                                float *cam)
909
2.40k
{
910
2.40k
    float cat02matrix[] = {0.7328f, 0.4296f, -0.1624f,
911
2.40k
                            -0.7036f, 1.6975f, 0.0061f,
912
2.40k
                             0.003f, 0.0136f, 0.9834f};
913
2.40k
    float cat02matrixinv[] = {1.0961f, -0.2789f, 0.1827f,
914
2.40k
                              0.4544f, 0.4735f, 0.0721f,
915
2.40k
                             -0.0096f, -0.0057f, 1.0153f};
916
2.40k
    float vonkries_diag[9];
917
2.40k
    float temp_matrix[9];
918
2.40k
    float lms_wp_src[3], lms_wp_des[3];
919
2.40k
    int k;
920
921
2.40k
    matrixmult(cat02matrix,3,3,&(white_src->u),3,1,&(lms_wp_src[0]));
922
2.40k
    matrixmult(cat02matrix,3,3,&(white_des->u),3,1,&(lms_wp_des[0]));
923
2.40k
    memset(&(vonkries_diag[0]),0,sizeof(float)*9);
924
925
9.62k
    for (k = 0; k < 3; k++) {
926
7.22k
        if (lms_wp_src[k] > 0 ) {
927
7.21k
            vonkries_diag[k*3+k] = lms_wp_des[k]/lms_wp_src[k];
928
7.21k
        } else {
929
2
            vonkries_diag[k*3+k] = 1;
930
2
        }
931
7.22k
    }
932
2.40k
    matrixmult(&(vonkries_diag[0]), 3, 3, &(cat02matrix[0]), 3, 3,
933
2.40k
                &(temp_matrix[0]));
934
2.40k
    matrixmult(&(cat02matrixinv[0]), 3, 3, &(temp_matrix[0]), 3, 3, &(cam[0]));
935
2.40k
}
936
937
static int
938
gsicc_compute_cam(gsicc_lutatob *icc_luta2bparts, gs_memory_t *memory)
939
23
{
940
23
    gs_vector3 d50;
941
942
23
    d50.u = D50_X;
943
23
    d50.v = D50_Y;
944
23
    d50.w = D50_Z;
945
946
    /* Calculate the chromatic adaptation matrix */
947
23
    icc_luta2bparts->cam = (float*) gs_alloc_bytes(memory,
948
23
                                        9 * sizeof(float), "gsicc_compute_cam");
949
23
    if (icc_luta2bparts->cam == NULL) {
950
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC cam failed");
951
0
    }
952
23
    gsicc_create_compute_cam(icc_luta2bparts->white_point, &(d50), icc_luta2bparts->cam);
953
23
    return 0;
954
23
}
955
956
/* Compute the CAT02 transformation to get us from the Cal White
957
   point to the D50 white point.  We could pack this in a chad tag
958
   and let the CMM worry about applying but it is safer if we just
959
   take care of it ourselves by mapping the primaries.  This is what is
960
   also done for the table based data */
961
static float*
962
gsicc_get_cat02_cam(float *curr_wp, gs_memory_t *memory)
963
2.36k
{
964
2.36k
    gs_vector3 d50;
965
2.36k
    gs_vector3 wp;
966
2.36k
    float *cam;
967
968
2.36k
    wp.u = curr_wp[0];
969
2.36k
    wp.v = curr_wp[1];
970
2.36k
    wp.w = curr_wp[2];
971
972
2.36k
    d50.u = D50_X;
973
2.36k
    d50.v = D50_Y;
974
2.36k
    d50.w = D50_Z;
975
976
2.36k
    cam = (float*)gs_alloc_bytes(memory, 9 * sizeof(float), "gsicc_get_cat02_cam");
977
2.36k
    if (cam == NULL) {
978
0
        gs_throw(gs_error_VMerror, "Allocation of cat02 matrix failed");
979
0
        return NULL;
980
0
    }
981
2.36k
    gsicc_create_compute_cam(&wp, &(d50), cam);
982
983
2.36k
    return cam;
984
2.36k
}
985
986
static void
987
add_ident_curves(unsigned char *input_ptr,int number_of_curves)
988
38
{
989
38
    unsigned char *curr_ptr;
990
38
    int k;
991
992
38
    curr_ptr = input_ptr;
993
138
    for (k = 0; k < number_of_curves; k++) {
994
       /* Signature */
995
100
        write_bigendian_4bytes(curr_ptr,icSigCurveType);
996
100
        curr_ptr += 4;
997
        /* Reserved */
998
100
        memset(curr_ptr,0,4);
999
100
        curr_ptr += 4;
1000
        /* Count */
1001
100
        write_bigendian_4bytes(curr_ptr, 0);
1002
100
        curr_ptr += 4;
1003
100
    }
1004
38
}
1005
1006
static void
1007
add_clutAtoB(unsigned char *input_ptr, gsicc_clut *clut)
1008
15
{
1009
15
    unsigned char *curr_ptr = input_ptr;
1010
15
    int k;
1011
15
    int num_channels_in = clut->clut_num_input;
1012
15
    int number_samples = clut->clut_num_entries;
1013
1014
    /* First write out the dimensions for each channel */
1015
30
    for (k = 0; k < num_channels_in; k++) {
1016
15
        memset(curr_ptr, clut->clut_dims[k], 1);
1017
15
        curr_ptr++;
1018
15
    }
1019
    /* Set the remainder of the dimenensions */
1020
15
    memset(curr_ptr, 0, 16-num_channels_in);
1021
15
    curr_ptr += (16-num_channels_in);
1022
    /* word size */
1023
15
    memset(curr_ptr, clut->clut_word_width, 1);
1024
15
    curr_ptr++;
1025
    /* padding */
1026
15
    memset(curr_ptr, 0, 3);
1027
15
    curr_ptr += 3;
1028
15
    if (clut->data_byte != NULL) {
1029
        /* A byte table */
1030
0
        memcpy(curr_ptr,clut->data_byte,number_samples*3);
1031
15
    } else {
1032
        /* A float table */
1033
105
        for ( k = 0; k < number_samples*3; k++ ) {
1034
90
            write_bigendian_2bytes(curr_ptr,clut->data_short[k]);
1035
90
            curr_ptr += 2;
1036
90
        }
1037
15
    }
1038
15
}
1039
1040
static void
1041
add_curve(unsigned char *input_ptr, float *curve_data, int num_samples)
1042
53
{
1043
53
    unsigned char *curr_ptr;
1044
53
    unsigned short value;
1045
53
    int k;
1046
1047
   /* Signature */
1048
53
    curr_ptr = input_ptr;
1049
53
    write_bigendian_4bytes(curr_ptr,icSigCurveType);
1050
53
    curr_ptr += 4;
1051
    /* Reserved */
1052
53
    memset(curr_ptr,0,4);
1053
53
    curr_ptr += 4;
1054
    /* Count */
1055
53
    write_bigendian_4bytes(curr_ptr, num_samples);
1056
53
    curr_ptr += 4;
1057
    /* Now the data uInt16 Number 0 to 65535.  For now assume input is 0 to 1.
1058
            Need to fix this.  MJV */
1059
27.1k
    for (k = 0; k < num_samples; k++) {
1060
27.1k
        if (curve_data[k] < 0) curve_data[k] = 0;
1061
27.1k
        if (curve_data[k] > 1) curve_data[k] = 1;
1062
27.1k
        value = (unsigned int) (curve_data[k]*65535.0);
1063
27.1k
        write_bigendian_2bytes(curr_ptr,value);
1064
27.1k
        curr_ptr+=2;
1065
27.1k
    }
1066
53
}
1067
1068
/* See comments before add_lutAtoBtype about allowable forms, which will
1069
    explain much of these size calculations */
1070
static int
1071
getsize_lutAtoBtype(gsicc_lutatob *lutatobparts)
1072
23
{
1073
23
    int data_offset, mlut_size;
1074
23
    int numout = lutatobparts->num_out;
1075
23
    int numin = lutatobparts->num_in;
1076
23
    int pad_bytes;
1077
1078
23
    data_offset = 32;
1079
    /* B curves always present */
1080
23
    if (lutatobparts->b_curves != NULL) {
1081
0
        data_offset += (numout*(CURVE_SIZE*2+12));
1082
23
    } else {
1083
23
        data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1084
23
    }
1085
    /* M curves present if Matrix is present */
1086
23
    if (lutatobparts->matrix != NULL ) {
1087
23
        data_offset += (12*4);
1088
        /* M curves */
1089
23
        if (lutatobparts->m_curves != NULL) {
1090
15
            data_offset += (numout*(CURVE_SIZE*2+12));
1091
15
        } else {
1092
8
            data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1093
8
        }
1094
23
    }
1095
    /* A curves present if clut is present */
1096
23
    if (lutatobparts->clut != NULL) {
1097
        /* We may need to pad the clut to make sure we are on a 4 byte boundary */
1098
15
        mlut_size = lutatobparts->clut->clut_num_entries *
1099
15
                            lutatobparts->clut->clut_word_width * 3;
1100
15
        pad_bytes = (4 - mlut_size%4)%4;
1101
15
        data_offset += (mlut_size + pad_bytes + 20);
1102
15
        if (lutatobparts->a_curves != NULL) {
1103
8
            data_offset += (numin*(CURVE_SIZE*2+12));
1104
8
        } else {
1105
7
            data_offset += (numin*(IDENT_CURVE_SIZE*2+12));
1106
7
        }
1107
15
    }
1108
23
    return data_offset;
1109
23
}
1110
1111
/* Note:  ICC V4 fomat allows ONLY these forms
1112
B
1113
M - Matrix - B
1114
A - CLUT - B
1115
A - CLUT - M - Matrix - B
1116
Other forms are created by making some of these items identity.  In other words
1117
the B curves must always be included.  If CLUT is present, A curves must be present.
1118
Also, if Matrix is present M curves must be present.  A curves cannot be
1119
present if CLUT is not present. */
1120
static void
1121
add_lutAtoBtype(unsigned char *input_ptr, gsicc_lutatob *lutatobparts)
1122
23
{
1123
/* We need to figure out all the offsets to the various objects based upon
1124
    which ones are actually present */
1125
23
    unsigned char *curr_ptr;
1126
23
    long mlut_size = 0;     /* silence compiler warning */
1127
23
    int data_offset;
1128
23
    int k;
1129
23
    int numout = lutatobparts->num_out;
1130
23
    int numin = lutatobparts->num_in;
1131
23
    int pad_bytes = 0;
1132
1133
    /* Signature */
1134
23
    curr_ptr = input_ptr;
1135
23
    write_bigendian_4bytes(curr_ptr,icMultiFunctionAtoBType);
1136
23
    curr_ptr += 4;
1137
    /* Reserved */
1138
23
    memset(curr_ptr,0,4);
1139
23
    curr_ptr += 4;
1140
    /* Padded sizes */
1141
23
    *curr_ptr++ = numin;
1142
23
    *curr_ptr++ = numout;
1143
23
    memset(curr_ptr,0,2);
1144
23
    curr_ptr += 2;
1145
    /* Note if data offset is zero, element is not present */
1146
    /* offset to B curves (last curves) */
1147
23
    data_offset = 32;
1148
23
    if (lutatobparts->b_curves == NULL) {
1149
        /* identity curve must be present */
1150
23
        write_bigendian_4bytes(curr_ptr,data_offset);
1151
23
        data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1152
23
    } else {
1153
0
        write_bigendian_4bytes(curr_ptr,data_offset);
1154
0
        data_offset += (numout*(CURVE_SIZE*2+12));
1155
0
    }
1156
23
    curr_ptr += 4;
1157
    /* offset to matrix and M curves */
1158
23
    if (lutatobparts->matrix == NULL) {
1159
0
        memset(curr_ptr,0,4);  /* Matrix */
1160
0
        curr_ptr += 4;
1161
0
        memset(curr_ptr,0,4);  /* M curves */
1162
23
    } else {
1163
23
        write_bigendian_4bytes(curr_ptr,data_offset);
1164
23
        data_offset += (12*4);
1165
23
        curr_ptr += 4;
1166
        /* offset to M curves (Matrix curves -- only come with matrix) */
1167
23
        if (lutatobparts->m_curves == NULL) {
1168
            /* identity curve must be present */
1169
8
            write_bigendian_4bytes(curr_ptr,data_offset);
1170
8
            data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1171
15
        } else {
1172
15
            write_bigendian_4bytes(curr_ptr,data_offset);
1173
15
            data_offset += (numout*(CURVE_SIZE*2+12));
1174
15
        }
1175
23
    }
1176
23
    curr_ptr += 4;
1177
    /* offset to CLUT and A curves */
1178
23
    if (lutatobparts->clut == NULL) {
1179
8
        memset(curr_ptr,0,4); /* CLUT */
1180
8
        curr_ptr += 4;
1181
8
        memset(curr_ptr,0,4); /* A curves */
1182
15
    } else {
1183
15
        write_bigendian_4bytes(curr_ptr,data_offset);
1184
15
        mlut_size = (long)lutatobparts->clut->clut_num_entries *
1185
15
                          lutatobparts->clut->clut_word_width * 3;
1186
15
        pad_bytes = (4 - mlut_size%4)%4;
1187
15
        data_offset += (mlut_size + pad_bytes + 20);
1188
15
        curr_ptr += 4;
1189
        /* offset to A curves (first curves) */
1190
15
        if (lutatobparts->a_curves == NULL || lutatobparts->clut == NULL) {
1191
            /* identity curve must be present */
1192
7
            write_bigendian_4bytes(curr_ptr,data_offset);
1193
7
            data_offset += (numin*(IDENT_CURVE_SIZE*2+12));
1194
8
        } else {
1195
8
            write_bigendian_4bytes(curr_ptr,data_offset);
1196
8
            data_offset += (numin*(CURVE_SIZE*2+12));
1197
8
        }
1198
15
    }
1199
23
    curr_ptr += 4;
1200
    /* Header is completed */
1201
    /* Now write out the various parts (i.e. curves, matrix and clut) */
1202
    /* First the B curves */
1203
23
    if (lutatobparts->b_curves != NULL) {
1204
0
        for (k = 0; k < numout; k++) {
1205
0
            add_curve(curr_ptr, (lutatobparts->b_curves)+k*CURVE_SIZE, CURVE_SIZE);
1206
0
            curr_ptr += (12 + CURVE_SIZE*2);
1207
0
        }
1208
23
    } else {
1209
23
        add_ident_curves(curr_ptr,numout);
1210
23
        curr_ptr += numout*(12 + IDENT_CURVE_SIZE*2);
1211
23
    }
1212
    /* Then the matrix */
1213
23
    if (lutatobparts->matrix != NULL) {
1214
23
        add_matrixwithbias(curr_ptr,(float*) lutatobparts->matrix,true);
1215
23
        curr_ptr += (12*4);
1216
        /* M curves */
1217
23
        if (lutatobparts->m_curves != NULL) {
1218
60
            for (k = 0; k < numout; k++) {
1219
45
                add_curve(curr_ptr, (lutatobparts->m_curves)+k*CURVE_SIZE, CURVE_SIZE);
1220
45
                curr_ptr += (12 + CURVE_SIZE*2);
1221
45
            }
1222
15
        } else {
1223
8
            add_ident_curves(curr_ptr,numout);
1224
8
            curr_ptr += numout*(12 + IDENT_CURVE_SIZE*2);
1225
8
        }
1226
23
    }
1227
    /* Then the clut */
1228
23
    if (lutatobparts->clut != NULL) {
1229
15
        add_clutAtoB(curr_ptr, lutatobparts->clut);
1230
15
        curr_ptr += (20 + mlut_size);
1231
15
        memset(curr_ptr,0,pad_bytes); /* 4 byte boundary */
1232
15
        curr_ptr += pad_bytes;
1233
        /* The A curves */
1234
15
        if (lutatobparts->a_curves != NULL) {
1235
16
            for (k = 0; k < numin; k++) {
1236
8
                add_curve(curr_ptr, (lutatobparts->a_curves)+k*CURVE_SIZE,
1237
8
                            CURVE_SIZE);
1238
8
                curr_ptr += (12 + CURVE_SIZE*2);
1239
8
            }
1240
8
        } else {
1241
7
            add_ident_curves(curr_ptr,numin);
1242
7
            curr_ptr += numin*(12 + IDENT_CURVE_SIZE*2);
1243
7
        }
1244
1245
15
    }
1246
23
}
1247
1248
/* This creates an ICC profile from the PDF calGray and calRGB definitions */
1249
cmm_profile_t*
1250
gsicc_create_from_cal(float *white, float *black, float *gamma, float *matrix,
1251
                      gs_memory_t *memory, int num_colors)
1252
2.36k
{
1253
2.36k
    icProfile iccprofile;
1254
2.36k
    icHeader  *header = &(iccprofile.header);
1255
2.36k
    int profile_size,k;
1256
2.36k
    int num_tags;
1257
2.36k
    gsicc_tag *tag_list;
1258
2.36k
    unsigned short encode_gamma;
1259
2.36k
    unsigned char *curr_ptr;
1260
2.36k
    int last_tag;
1261
2.36k
    icS15Fixed16Number temp_XYZ[3];
1262
2.36k
    int tag_location;
1263
2.36k
    icTagSignature TRC_Tags[3] = {icSigRedTRCTag, icSigGreenTRCTag,
1264
2.36k
                                  icSigBlueTRCTag};
1265
2.36k
    int trc_tag_size;
1266
2.36k
    unsigned char *buffer;
1267
2.36k
    cmm_profile_t *result;
1268
2.36k
    float *cat02;
1269
2.36k
    float black_adapt[3];
1270
1271
    /* Fill in the common stuff */
1272
2.36k
    setheader_common(header, 4);
1273
2.36k
    header->pcs = icSigXYZData;
1274
2.36k
    profile_size = HEADER_SIZE;
1275
2.36k
    header->deviceClass = icSigInputClass;
1276
2.36k
    if (num_colors == 3) {
1277
2.20k
        header->colorSpace = icSigRgbData;
1278
2.20k
        num_tags = 10;  /* common (2) + rXYZ,gXYZ,bXYZ,rTRC,gTRC,bTRC,bkpt,wtpt */
1279
2.20k
    } else if (num_colors == 1) {
1280
159
        header->colorSpace = icSigGrayData;
1281
159
        num_tags = 5;  /* common (2) + GrayTRC,bkpt,wtpt */
1282
159
        TRC_Tags[0] = icSigGrayTRCTag;
1283
159
    } else {
1284
0
        return NULL;
1285
0
    }
1286
2.36k
    tag_list = (gsicc_tag*) gs_alloc_bytes(memory,
1287
2.36k
                    sizeof(gsicc_tag)*(size_t)num_tags,"gsicc_create_from_cal");
1288
2.36k
    if (tag_list == NULL)
1289
0
        return NULL;
1290
    /* Let us precompute the sizes of everything and all our offsets */
1291
2.36k
    profile_size += TAG_SIZE*num_tags;
1292
2.36k
    profile_size += 4; /* number of tags.... */
1293
2.36k
    last_tag = -1;
1294
2.36k
    init_common_tags(tag_list, num_tags, &last_tag);
1295
2.36k
    if (num_colors == 3) {
1296
2.20k
        init_tag(tag_list, &last_tag, icSigRedColorantTag, XYZPT_SIZE);
1297
2.20k
        init_tag(tag_list, &last_tag, icSigGreenColorantTag, XYZPT_SIZE);
1298
2.20k
        init_tag(tag_list, &last_tag, icSigBlueColorantTag, XYZPT_SIZE);
1299
2.20k
    }
1300
2.36k
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
1301
2.36k
    init_tag(tag_list, &last_tag, icSigMediaBlackPointTag, XYZPT_SIZE);
1302
    /* 4 for count, 2 for gamma, Extra 2 bytes for 4 byte alignment requirement */
1303
2.36k
    trc_tag_size = 8;
1304
9.12k
    for (k = 0; k < num_colors; k++) {
1305
6.76k
        init_tag(tag_list, &last_tag, TRC_Tags[k], trc_tag_size);
1306
6.76k
    }
1307
25.1k
    for(k = 0; k < num_tags; k++) {
1308
22.8k
        profile_size += tag_list[k].size;
1309
22.8k
    }
1310
    /* Now we can go ahead and fill our buffer with the data.  Profile
1311
       buffer data is in non-gc memory */
1312
2.36k
    buffer = gs_alloc_bytes(memory->non_gc_memory,
1313
2.36k
                            profile_size, "gsicc_create_from_cal");
1314
2.36k
    if (buffer == NULL) {
1315
0
        gs_free_object(memory, tag_list, "gsicc_create_from_cal");
1316
0
        return NULL;
1317
0
    }
1318
2.36k
    curr_ptr = buffer;
1319
    /* The header */
1320
2.36k
    header->size = profile_size;
1321
2.36k
    copy_header(curr_ptr,header);
1322
2.36k
    curr_ptr += HEADER_SIZE;
1323
    /* Tag table */
1324
2.36k
    copy_tagtable(curr_ptr,tag_list,num_tags);
1325
2.36k
    curr_ptr += TAG_SIZE*num_tags;
1326
2.36k
    curr_ptr += 4;
1327
    /* Now the data.  Must be in same order as we created the tag table */
1328
    /* First the common tags */
1329
2.36k
    add_common_tag_data(curr_ptr, tag_list, 4);
1330
7.08k
    for (k = 0; k< NUMBER_COMMON_TAGS; k++) {
1331
4.72k
        curr_ptr += tag_list[k].size;
1332
4.72k
    }
1333
2.36k
    tag_location = NUMBER_COMMON_TAGS;
1334
1335
    /* Get the cat02 matrix */
1336
2.36k
    cat02 = gsicc_get_cat02_cam(white, memory);
1337
2.36k
    if (cat02 == NULL)
1338
0
    {
1339
0
        gs_rethrow(gs_error_VMerror, "Creation of cat02 matrix / ICC profile failed");
1340
0
        return NULL;
1341
0
    }
1342
1343
    /* The matrix */
1344
2.36k
    if (num_colors == 3) {
1345
8.80k
        for ( k = 0; k < 3; k++ ) {
1346
6.60k
            float primary[3];
1347
            /* Apply the cat02 matrix to the primaries */
1348
6.60k
            apply_adaption(cat02, &(matrix[k * 3]), &(primary[0]));
1349
6.60k
            get_XYZ_doubletr(temp_XYZ, &(primary[0]));
1350
6.60k
            add_xyzdata(curr_ptr, temp_XYZ);
1351
6.60k
            curr_ptr += tag_list[tag_location].size;
1352
6.60k
            tag_location++;
1353
6.60k
        }
1354
2.20k
    }
1355
    /* White and black points.  WP is D50 */
1356
2.36k
    get_D50(temp_XYZ);
1357
2.36k
    add_xyzdata(curr_ptr,temp_XYZ);
1358
2.36k
    curr_ptr += tag_list[tag_location].size;
1359
2.36k
    tag_location++;
1360
    /* Black point.  Apply cat02*/
1361
2.36k
    apply_adaption(cat02, black, &(black_adapt[0]));
1362
2.36k
    get_XYZ_doubletr(temp_XYZ, &(black_adapt[0]));
1363
2.36k
    add_xyzdata(curr_ptr,temp_XYZ);
1364
2.36k
    curr_ptr += tag_list[tag_location].size;
1365
2.36k
    tag_location++;
1366
    /* Now the gamma values */
1367
9.12k
    for (k = 0; k < num_colors; k++) {
1368
6.76k
        encode_gamma = float2u8Fixed8(gamma[k]);
1369
6.76k
        add_gammadata(curr_ptr, encode_gamma, icSigCurveType);
1370
6.76k
        curr_ptr += tag_list[tag_location].size;
1371
6.76k
        tag_location++;
1372
6.76k
    }
1373
2.36k
    result = gsicc_profile_new(NULL, memory, NULL, 0);
1374
2.36k
    if (result == NULL)
1375
0
    {
1376
0
        gs_throw(gs_error_VMerror, "Creation of ICC profile failed");
1377
0
        return NULL;
1378
0
    }
1379
2.36k
    result->buffer = buffer;
1380
2.36k
    result->buffer_size = profile_size;
1381
2.36k
    result->num_comps = num_colors;
1382
2.36k
    if (num_colors == 3) {
1383
2.20k
        result->data_cs = gsRGB;
1384
2.20k
        result->default_match = CAL_RGB;
1385
2.20k
    } else {
1386
159
        result->data_cs = gsGRAY;
1387
159
        result->default_match = CAL_GRAY;
1388
159
    }
1389
    /* Set the hash code  */
1390
2.36k
    gsicc_get_icc_buff_hash(buffer, &(result->hashcode), result->buffer_size);
1391
2.36k
    result->hash_is_valid = true;
1392
    /* Free up the tag list */
1393
2.36k
    gs_free_object(memory, tag_list, "gsicc_create_from_cal");
1394
2.36k
    gs_free_object(memory, cat02, "gsicc_create_from_cal");
1395
1396
#if SAVEICCPROFILE
1397
    /* Dump the buffer to a file for testing if its a valid ICC profile */
1398
    if (num_colors == 3)
1399
        save_profile(memory,buffer,"from_calRGB",profile_size);
1400
    else
1401
        save_profile(memory,buffer,"from_calGray",profile_size);
1402
#endif
1403
2.36k
    return result;
1404
2.36k
}
1405
1406
static void
1407
gsicc_create_free_luta2bpart(gs_memory_t *memory, gsicc_lutatob *icc_luta2bparts)
1408
23
{
1409
    /* Note that white_point, black_point and matrix are not allocated but
1410
       are on the local stack */
1411
23
    gs_free_object(memory, icc_luta2bparts->a_curves,
1412
23
                    "gsicc_create_free_luta2bpart");
1413
23
    gs_free_object(memory, icc_luta2bparts->b_curves,
1414
23
                    "gsicc_create_free_luta2bpart");
1415
23
    gs_free_object(memory, icc_luta2bparts->m_curves,
1416
23
                    "gsicc_create_free_luta2bpart");
1417
23
    gs_free_object(memory, icc_luta2bparts->cam,
1418
23
                    "gsicc_create_free_luta2bpart");
1419
23
    if (icc_luta2bparts->clut) {
1420
        /* Note, data_byte is handled externally.  We do not free that member here */
1421
15
        gs_free_object(memory, icc_luta2bparts->clut->data_short,
1422
15
                        "gsicc_create_free_luta2bpart");
1423
15
        gs_free_object(memory, icc_luta2bparts->clut,
1424
15
                        "gsicc_create_free_luta2bpart");
1425
15
    }
1426
23
}
1427
1428
static void
1429
gsicc_create_init_luta2bpart(gsicc_lutatob *icc_luta2bparts)
1430
23
{
1431
23
    icc_luta2bparts->a_curves = NULL;
1432
23
    icc_luta2bparts->b_curves = NULL;
1433
23
    icc_luta2bparts->clut = NULL;
1434
23
    icc_luta2bparts->m_curves = NULL;
1435
23
    icc_luta2bparts->cam = NULL;
1436
23
    icc_luta2bparts->matrix = NULL;
1437
23
    icc_luta2bparts->white_point = NULL;
1438
23
    icc_luta2bparts->black_point = NULL;
1439
23
    icc_luta2bparts->num_in = 0;
1440
23
    icc_luta2bparts->num_out = 0;
1441
23
}
1442
1443
static void
1444
gsicc_create_initialize_clut(gsicc_clut *clut)
1445
15
{
1446
15
    int k;
1447
15
    int64_t entries = 0;
1448
1449
15
    clut->clut_num_entries = entries = clut->clut_dims[0];
1450
1451
15
    for (k = 1; k < clut->clut_num_input; k++) {
1452
0
        entries = (int64_t)clut->clut_num_entries * clut->clut_dims[k];
1453
0
        if (entries > INT_MAX || entries / clut->clut_num_entries != clut->clut_dims[k]) {
1454
0
            clut->clut_num_entries = 0;
1455
0
            break;
1456
0
        }
1457
0
        clut->clut_num_entries = entries;
1458
0
    }
1459
15
    clut->data_byte =  NULL;
1460
15
    clut->data_short = NULL;
1461
15
}
1462
1463
/* A common form used for most of the PS CIE color spaces */
1464
static int
1465
create_lutAtoBprofile(unsigned char **pp_buffer_in, icHeader *header,
1466
                      gsicc_lutatob *lutatobparts, bool yonly, bool mashedLUT,
1467
                      gs_memory_t *memory)
1468
23
{
1469
23
    int num_tags = 5;  /* common (2), AToB0Tag,bkpt, wtpt */
1470
23
    int k;
1471
23
    gsicc_tag *tag_list;
1472
23
    int profile_size, last_tag, tag_location, tag_size;
1473
23
    unsigned char *buffer,*curr_ptr;
1474
23
    icS15Fixed16Number temp_XYZ[3];
1475
23
    gs_vector3 d50;
1476
23
    float *cam;
1477
23
    gs_matrix3 temp_matrix;
1478
23
    float lmn_vector[3],d50_cieA[3];
1479
1480
23
    profile_size = HEADER_SIZE;
1481
23
    tag_list = (gsicc_tag*) gs_alloc_bytes(memory, sizeof(gsicc_tag) * (size_t)num_tags,
1482
23
                                            "create_lutAtoBprofile");
1483
23
    if (tag_list == NULL)
1484
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC tag list failed");
1485
1486
    /* Let us precompute the sizes of everything and all our offsets */
1487
23
    profile_size += TAG_SIZE*num_tags;
1488
23
    profile_size += 4; /* number of tags.... */
1489
23
    last_tag = -1;
1490
23
    init_common_tags(tag_list, num_tags, &last_tag);
1491
23
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
1492
23
    init_tag(tag_list, &last_tag, icSigMediaBlackPointTag, XYZPT_SIZE);
1493
1494
    /* Get the tag size of the A2B0 with the lutAtoBType */
1495
    /* Compensate for init_tag() adding DATATYPE_SIZE */
1496
23
    tag_size = getsize_lutAtoBtype(lutatobparts) - DATATYPE_SIZE;
1497
23
    init_tag(tag_list, &last_tag, icSigAToB0Tag, tag_size);
1498
    /* Add all the tag sizes to get the new profile size */
1499
138
    for(k = 0; k < num_tags; k++) {
1500
115
        profile_size += tag_list[k].size;
1501
115
    }
1502
    /* End of tag table information */
1503
    /* Now we can go ahead and fill our buffer with the data.  Profile
1504
       is in non-gc memory */
1505
23
    buffer = gs_alloc_bytes(memory->non_gc_memory, profile_size,
1506
23
                            "create_lutAtoBprofile");
1507
23
    if (buffer == NULL) {
1508
0
        gs_free_object(memory, tag_list, "create_lutAtoBprofile");
1509
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC buffer failed");
1510
0
    }
1511
23
    curr_ptr = buffer;
1512
    /* The header */
1513
23
    header->size = profile_size;
1514
23
    copy_header(curr_ptr,header);
1515
23
    curr_ptr += HEADER_SIZE;
1516
    /* Tag table */
1517
23
    copy_tagtable(curr_ptr, tag_list, num_tags);
1518
23
    curr_ptr += TAG_SIZE * num_tags;
1519
23
    curr_ptr += 4;
1520
    /* Now the data.  Must be in same order as we created the tag table */
1521
    /* First the common tags */
1522
23
    add_common_tag_data(curr_ptr, tag_list, 4);
1523
69
    for (k = 0; k< NUMBER_COMMON_TAGS; k++) {
1524
46
        curr_ptr += tag_list[k].size;
1525
46
    }
1526
23
    tag_location = NUMBER_COMMON_TAGS;
1527
    /* Here we take care of chromatic adapatation.  Compute the
1528
       matrix.  We will need to hit the data with the matrix and
1529
       store it in the profile. */
1530
23
    d50.u = D50_X;
1531
23
    d50.v = D50_Y;
1532
23
    d50.w = D50_Z;
1533
23
    cam = (float*) gs_alloc_bytes(memory, 9 * sizeof(float), "create_lutAtoBprofile");
1534
23
    if (cam == NULL) {
1535
0
        gs_free_object(memory, tag_list, "create_lutAtoBprofile");
1536
0
        gs_free_object(memory->non_gc_memory, buffer, "create_lutAtoBprofile");
1537
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC cam failed");
1538
0
    }
1539
23
    gsicc_create_compute_cam(lutatobparts->white_point, &(d50), cam);
1540
23
    gs_free_object(memory, lutatobparts->cam, "create_lutAtoBprofile");
1541
23
    lutatobparts->cam = cam;
1542
23
    get_D50(temp_XYZ); /* See Appendix D6 in spec */
1543
23
    add_xyzdata(curr_ptr, temp_XYZ);
1544
23
    curr_ptr += tag_list[tag_location].size;
1545
23
    tag_location++;
1546
23
    get_XYZ(temp_XYZ, lutatobparts->black_point);
1547
23
    add_xyzdata(curr_ptr, temp_XYZ);
1548
23
    curr_ptr += tag_list[tag_location].size;
1549
23
    tag_location++;
1550
    /* Multiply the matrix in the AtoB object by the cam so that the data
1551
       is in D50 */
1552
23
    if (lutatobparts->matrix == NULL) {
1553
0
        gsicc_create_copy_matrix3(cam, (float*) &temp_matrix);
1554
0
        lutatobparts->matrix = &temp_matrix;
1555
23
    } else {
1556
23
        if (yonly) {
1557
            /* Used for CIEBaseA case.  Studies of CIEBasedA spaces
1558
               and AR rendering of these reveals that they only look
1559
               at the product sum of the MatrixA and the 2nd column of
1560
               the LM Matrix (if there is one).  This is used as a Y
1561
               decode value from which to map between the black point
1562
               and the white point.  The black point is actually ignored
1563
               and a black point of 0 is used. Essentialy we have
1564
               weighted versions of D50 in each column of the matrix
1565
               which ensures we stay on the achromatic axis */
1566
15
            lmn_vector[0] = lutatobparts->matrix->cv.u;
1567
15
            lmn_vector[1] = lutatobparts->matrix->cv.v;
1568
15
            lmn_vector[2] = lutatobparts->matrix->cv.w;
1569
15
            if (mashedLUT) {
1570
                /* Table data already scaled */
1571
0
                d50_cieA[0] = D50_X;
1572
0
                d50_cieA[1] = D50_Y;
1573
0
                d50_cieA[2] = D50_Z;
1574
15
            } else {
1575
                /* Need to do final scaling to ICC CIEXYZ range */
1576
15
                d50_cieA[0] = (float)(D50_X / (1.0 + (32767.0/32768.0)));
1577
15
                d50_cieA[1] = (float)(D50_Y / (1.0 + (32767.0/32768.0)));
1578
15
                d50_cieA[2] = (float)(D50_Z / (1.0 + (32767.0/32768.0)));
1579
15
            }
1580
15
            matrixmult(&(d50_cieA[0]), 3, 1, &(lmn_vector[0]), 1, 3,
1581
15
                        &(lutatobparts->matrix->cu.u));
1582
15
        } else {
1583
8
            matrixmult(cam, 3, 3, &(lutatobparts->matrix->cu.u), 3, 3,
1584
8
                    &(temp_matrix.cu.u));
1585
8
            lutatobparts->matrix = &temp_matrix;
1586
8
        }
1587
23
    }
1588
    /* Now the AToB0Tag Data. Here this will include the M curves, the matrix
1589
       and the B curves. We may need to do some adustements with respect
1590
       to encode and decode.  For now assume all is between 0 and 1. */
1591
23
    add_lutAtoBtype(curr_ptr, lutatobparts);
1592
23
    *pp_buffer_in = buffer;
1593
23
    gs_free_object(memory, tag_list, "create_lutAtoBprofile");
1594
23
    return 0;
1595
23
}
1596
1597
/* Shared code between all the PS types whereby we mash together all the
1598
   components into a single CLUT.  Not preferable in general but necessary
1599
   when the PS components do not map easily into the ICC forms */
1600
static int
1601
gsicc_create_mashed_clut(gsicc_lutatob *icc_luta2bparts,
1602
                         icHeader *header, gx_color_lookup_table *Table,
1603
                         const gs_color_space *pcs, gs_range *ranges,
1604
                         unsigned char **pp_buffer_in, int *profile_size_out,
1605
                         bool range_adjust, gs_memory_t* memory)
1606
0
{
1607
0
    int k;
1608
0
    int code;
1609
0
    gsicc_clut *clut;
1610
0
    gs_matrix3 ident_matrix;
1611
0
    gs_vector3 ones_vec;
1612
1613
   /* A table is going to be mashed form of all the transform */
1614
    /* Allocate space for the clut */
1615
0
    clut = (gsicc_clut*) gs_alloc_bytes(memory, sizeof(gsicc_clut),
1616
0
                                "gsicc_create_mashed_clut");
1617
0
    if (clut == NULL)
1618
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC clut failed");
1619
0
    icc_luta2bparts->clut = clut;
1620
0
    if ( icc_luta2bparts->num_in == 1 ) {
1621
        /* Use a larger sample for 1-D input */
1622
0
        clut->clut_dims[0] = DEFAULT_TABLE_GRAYSIZE;
1623
0
    } else {
1624
0
        for (k = 0; k < icc_luta2bparts->num_in; k++) {
1625
0
            if (Table != NULL && Table->dims[k] > DEFAULT_TABLE_NSIZE ) {
1626
                /* If it has a table use the existing table size if
1627
                   it is larger than our default size */
1628
0
                clut->clut_dims[k] = Table->dims[k];
1629
0
            } else {
1630
                /* If not, then use a default size */
1631
0
                clut->clut_dims[k] = DEFAULT_TABLE_NSIZE;
1632
0
            }
1633
0
        }
1634
0
    }
1635
0
    clut->clut_num_input = icc_luta2bparts->num_in;
1636
0
    clut->clut_num_output = 3;  /* CIEXYZ */
1637
0
    clut->clut_word_width = 2;  /* 16 bit */
1638
0
    gsicc_create_initialize_clut(clut);
1639
    /* Allocate space for the table data */
1640
0
    clut->data_short = (unsigned short*) gs_alloc_bytes(memory,
1641
0
        (size_t)clut->clut_num_entries*3*(size_t)sizeof(unsigned short),"gsicc_create_mashed_clut");
1642
0
    if (clut->data_short == NULL) {
1643
0
        gs_free_object(memory, clut, "gsicc_create_mashed_clut");
1644
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC clut short data failed");
1645
0
    }
1646
    /* Create the table */
1647
0
    code = gsicc_create_clut(pcs, clut, ranges, icc_luta2bparts->white_point,
1648
0
                             range_adjust, icc_luta2bparts->cam, memory);
1649
0
    if (code < 0) {
1650
0
        gs_free_object(memory, clut, "gsicc_create_mashed_clut");
1651
0
        return gs_rethrow(code, "Creation of ICC clut failed");
1652
0
    }
1653
    /* Initialize other parts. Also make sure acurves are reset since
1654
       they have been mashed into the table. */
1655
0
    gs_free_object(memory, icc_luta2bparts->a_curves, "gsicc_create_mashed_clut");
1656
0
    icc_luta2bparts->a_curves = NULL;
1657
0
    icc_luta2bparts->b_curves = NULL;
1658
0
    icc_luta2bparts->m_curves = NULL;
1659
0
    ones_vec.u = 1;
1660
0
    ones_vec.v = 1;
1661
0
    ones_vec.w = 1;
1662
0
    gsicc_make_diag_matrix(&ident_matrix,&ones_vec);
1663
0
    icc_luta2bparts->matrix = &ident_matrix;
1664
    /* Now create the profile */
1665
0
    if (icc_luta2bparts->num_in == 1 ) {
1666
0
        code = create_lutAtoBprofile(pp_buffer_in, header, icc_luta2bparts, true,
1667
0
                                     true, memory);
1668
0
    } else {
1669
0
        code = create_lutAtoBprofile(pp_buffer_in, header, icc_luta2bparts, false,
1670
0
                                     true, memory);
1671
0
    }
1672
0
    return code;
1673
0
}
1674
1675
/* Shared code by ABC, DEF and DEFG compaction of ABC/LMN parts.  This is used
1676
   when either MatrixABC is identity, LMN Decode is identity or MatrixLMN
1677
   is identity.  This allows us to map into the ICC form and not have to mash
1678
   into a full CLUT */
1679
static int
1680
gsicc_create_abc_merge(gsicc_lutatob *atob_parts, gs_matrix3 *matrixLMN,
1681
                       gs_matrix3 *matrixABC, bool has_abc_procs,
1682
                       bool has_lmn_procs, gx_cie_vector_cache *abc_caches,
1683
                       gx_cie_scalar_cache *lmn_caches, gs_memory_t *memory)
1684
8
{
1685
8
    gs_matrix3 temp_matrix;
1686
8
    gs_matrix3 *matrix_ptr;
1687
8
    float *curr_pos;
1688
1689
    /* Determine the matrix that we will be using */
1690
8
    if (!(matrixLMN->is_identity) && !(matrixABC->is_identity)){
1691
        /* Use the product of the ABC and LMN matrices, since lmn_procs identity.
1692
           Product must be LMN_Matrix*ABC_Matrix */
1693
0
        cie_matrix_mult3(matrixLMN, matrixABC, &temp_matrix);
1694
0
        cie_matrix_transpose3(&temp_matrix, atob_parts->matrix);
1695
8
    } else {
1696
        /* Either ABC matrix or LMN matrix is identity */
1697
8
        if (matrixABC->is_identity) {
1698
8
            matrix_ptr = matrixLMN;
1699
8
        } else {
1700
0
            matrix_ptr = matrixABC;
1701
0
        }
1702
8
        cie_matrix_transpose3(matrix_ptr, atob_parts->matrix);
1703
8
    }
1704
    /* Merge the curves */
1705
8
    if (has_abc_procs && has_lmn_procs && matrixABC->is_identity) {
1706
        /* Merge the curves into the abc curves. no b curves */
1707
0
        merge_abc_lmn_curves(abc_caches, lmn_caches);
1708
0
        has_lmn_procs = false;
1709
0
    }
1710
    /* Figure out what curves get mapped to where.  The only time we will use the b
1711
       curves is if matrixABC is not the identity and we have lmn procs */
1712
8
    if ( !(matrixABC->is_identity) && has_lmn_procs) {
1713
        /* A matrix followed by a curve */
1714
0
        atob_parts->b_curves = (float*) gs_alloc_bytes(memory,
1715
0
                            3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_abc_merge");
1716
0
        if (atob_parts->b_curves == NULL)
1717
0
            return gs_throw(gs_error_VMerror, "Allocation of ICC b curves failed");
1718
0
        curr_pos = atob_parts->b_curves;
1719
0
        memcpy(curr_pos,&(lmn_caches[0].floats.values[0]),CURVE_SIZE*sizeof(float));
1720
0
        curr_pos += CURVE_SIZE;
1721
0
        memcpy(curr_pos,&(lmn_caches[1].floats.values[0]),CURVE_SIZE*sizeof(float));
1722
0
        curr_pos += CURVE_SIZE;
1723
0
        memcpy(curr_pos,&(lmn_caches[2].floats.values[0]),CURVE_SIZE*sizeof(float));
1724
0
        if (has_abc_procs) {
1725
            /* Also a curve before the matrix */
1726
0
            atob_parts->m_curves = (float*) gs_alloc_bytes(memory,
1727
0
                            3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_abc_merge");
1728
0
            if (atob_parts->m_curves == NULL) {
1729
0
                gs_free_object(memory, atob_parts->b_curves, "gsicc_create_abc_merge");
1730
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC m curves failed");
1731
0
            }
1732
0
            curr_pos = atob_parts->m_curves;
1733
0
            memcpy(curr_pos,&(abc_caches[0].floats.values[0]),CURVE_SIZE*sizeof(float));
1734
0
            curr_pos += CURVE_SIZE;
1735
0
            memcpy(curr_pos,&(abc_caches[1].floats.values[0]),CURVE_SIZE*sizeof(float));
1736
0
            curr_pos += CURVE_SIZE;
1737
0
            memcpy(curr_pos,&(abc_caches[2].floats.values[0]),CURVE_SIZE*sizeof(float));
1738
0
        }
1739
8
    } else {
1740
        /* Only one set of curves before a matrix.  Need to check this to make sure
1741
           there is not an issue here and we have has_abc_procs true and
1742
           has_lmn_procs true */
1743
8
        if (has_abc_procs) {
1744
0
            atob_parts->m_curves = (float*) gs_alloc_bytes(memory,
1745
0
                            3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_abc_merge");
1746
0
            if (atob_parts->m_curves == NULL)
1747
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC m curves failed");
1748
0
            curr_pos = atob_parts->m_curves;
1749
0
            memcpy(curr_pos,&(abc_caches[0].floats.values[0]),CURVE_SIZE*sizeof(float));
1750
0
            curr_pos += CURVE_SIZE;
1751
0
            memcpy(curr_pos,&(abc_caches[1].floats.values[0]),CURVE_SIZE*sizeof(float));
1752
0
            curr_pos += CURVE_SIZE;
1753
0
            memcpy(curr_pos,&(abc_caches[2].floats.values[0]),CURVE_SIZE*sizeof(float));
1754
0
        }
1755
8
        if (has_lmn_procs) {
1756
8
            atob_parts->m_curves = (float*) gs_alloc_bytes(memory,
1757
8
                                3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_abc_merge");
1758
8
            if (atob_parts->m_curves == NULL)
1759
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC m curves failed");
1760
8
            curr_pos = atob_parts->m_curves;
1761
8
            memcpy(curr_pos,&(lmn_caches[0].floats.values[0]),CURVE_SIZE*sizeof(float));
1762
8
            curr_pos += CURVE_SIZE;
1763
8
            memcpy(curr_pos,&(lmn_caches[1].floats.values[0]),CURVE_SIZE*sizeof(float));
1764
8
            curr_pos += CURVE_SIZE;
1765
8
            memcpy(curr_pos,&(lmn_caches[2].floats.values[0]),CURVE_SIZE*sizeof(float));
1766
8
        }
1767
8
    }
1768
    /* Note that if the b_curves are null and we have a matrix we need to scale
1769
       the matrix values by 2. Otherwise an input value of 50% gray, which is
1770
       32767 would get mapped to 32767 by the matrix.  This will be interpreted
1771
       as a max XYZ value (s15.16) when it is eventually mapped to u16.16 due
1772
       to the mapping of X=Y by the identity table.  If there are b_curves
1773
       these have an output that is 16 bit. */
1774
8
    if (atob_parts->b_curves == NULL) {
1775
8
        scale_matrix((float*) atob_parts->matrix, 2.0);
1776
8
    }
1777
8
    return 0;
1778
8
}
1779
1780
/* The ABC color space is modeled using the V4 lutAtoBType which has the
1781
   flexibility to model  the various parameters.  Simplified versions are used
1782
   it possible when certain parameters in the ABC color space definition are
1783
   the identity. */
1784
int
1785
gsicc_create_fromabc(const gs_color_space *pcs, unsigned char **pp_buffer_in,
1786
                     int *profile_size_out, gs_memory_t *memory,
1787
                     gx_cie_vector_cache *abc_caches,
1788
                     gx_cie_scalar_cache *lmn_caches, bool *islab)
1789
8
{
1790
8
    icProfile iccprofile;
1791
8
    icHeader  *header = &(iccprofile.header);
1792
#if SAVEICCPROFILE
1793
    int debug_catch = 1;
1794
#endif
1795
8
    int k;
1796
8
    gs_matrix3 matrix_input_trans;
1797
8
    gsicc_lutatob icc_luta2bparts;
1798
8
    float *curr_pos;
1799
8
    bool has_abc_procs = !((abc_caches->floats.params.is_identity &&
1800
8
                         (abc_caches)[1].floats.params.is_identity &&
1801
8
                         (abc_caches)[2].floats.params.is_identity));
1802
8
    bool has_lmn_procs = !((lmn_caches->floats.params.is_identity &&
1803
0
                         (lmn_caches)[1].floats.params.is_identity &&
1804
0
                         (lmn_caches)[2].floats.params.is_identity));
1805
8
    gs_cie_abc *pcie = pcs->params.abc;
1806
8
    bool input_range_ok;
1807
8
    int code;
1808
1809
8
    gsicc_create_init_luta2bpart(&icc_luta2bparts);
1810
8
    gsicc_matrix_init(&(pcie->common.MatrixLMN));  /* Need this set now */
1811
8
    gsicc_matrix_init(&(pcie->MatrixABC));          /* Need this set now */
1812
    /* Fill in the common stuff */
1813
8
    setheader_common(header, 4);
1814
1815
    /* We will use an input type class which keeps us from having to
1816
       create an inverse.  We will keep the data a generic 3 color.
1817
       Since we are doing PS color management the PCS is XYZ */
1818
8
    header->colorSpace = icSigRgbData;
1819
8
    header->deviceClass = icSigInputClass;
1820
8
    header->pcs = icSigXYZData;
1821
8
    icc_luta2bparts.num_in = 3;
1822
8
    icc_luta2bparts.num_out = 3;
1823
8
    icc_luta2bparts.white_point = &(pcie->common.points.WhitePoint);
1824
8
    icc_luta2bparts.black_point = &(pcie->common.points.BlackPoint);
1825
1826
    /* Calculate the chromatic adaptation matrix */
1827
8
    code = gsicc_compute_cam(&icc_luta2bparts, memory);
1828
8
    if (code < 0) {
1829
0
        return gs_rethrow(code, "Create ICC from CIEABC failed");
1830
0
    }
1831
1832
    /* Detect if the space is CIELAB. We don't have access to pgs here though */
1833
    /* *islab = cie_is_lab(pcie); This is not working yet */
1834
8
    *islab = false;
1835
1836
    /* Check what combination we have with respect to the various
1837
       LMN and ABC parameters. Depending upon the situation we
1838
       may be able to use a standard 3 channel input profile type. If we
1839
       do not have the LMN decode we can mash together the ABC and LMN
1840
       matrix. Also, if ABC is identity we can mash the ABC and LMN
1841
       decode procs.  If we have an ABC matrix, LMN procs and an LMN
1842
       matrix we will need to create a small (2x2x2) CLUT for the ICC format. */
1843
8
    input_range_ok = check_range(&(pcie->RangeABC.ranges[0]), 3);
1844
8
    if (!input_range_ok) {
1845
        /* We have a range problem at input */
1846
0
        code = gsicc_create_mashed_clut(&icc_luta2bparts, header, NULL, pcs,
1847
0
                                 &(pcie->RangeABC.ranges[0]), pp_buffer_in,
1848
0
                                 profile_size_out, true, memory);
1849
0
        if (code < 0)
1850
0
            return gs_rethrow(code, "Failed in ICC creation from ABC mashed. CLUT");
1851
8
    } else {
1852
8
        if (pcie->MatrixABC.is_identity || !has_lmn_procs ||
1853
8
                            pcie->common.MatrixLMN.is_identity) {
1854
            /* The merging of these parts into the curves/matrix/curves of the
1855
               lutAtoBtype portion can be used by abc, def and defg */
1856
8
            icc_luta2bparts.matrix = &matrix_input_trans;
1857
8
            code = gsicc_create_abc_merge(&(icc_luta2bparts), &(pcie->common.MatrixLMN),
1858
8
                                    &(pcie->MatrixABC), has_abc_procs,
1859
8
                                    has_lmn_procs, pcie->caches.DecodeABC.caches,
1860
8
                                    pcie->common.caches.DecodeLMN, memory);
1861
8
            if (code < 0)
1862
0
                return gs_rethrow(code, "Failed in ICC creation from ABC. Merge");
1863
8
            icc_luta2bparts.clut =  NULL;
1864
            /* Create the profile.  This is for the common generic form we will use
1865
               for almost everything. */
1866
8
            code = create_lutAtoBprofile(pp_buffer_in, header, &icc_luta2bparts, false,
1867
8
                                         false, memory);
1868
8
            if (code < 0)
1869
0
                return gs_rethrow(code, "Failed in ICC creation from ABC. Profile");
1870
8
        } else {
1871
            /* This will be a bit more complex as we have an ABC matrix, LMN decode
1872
               and an LMN matrix.  We will need to create an MLUT to handle this properly.
1873
               Any ABC decode will be handled as the A curves.  ABC matrix will be the
1874
               MLUT, LMN decode will be the M curves.  LMN matrix will be the Matrix
1875
               and b curves will be identity. */
1876
0
            if (has_abc_procs) {
1877
0
                icc_luta2bparts.a_curves = (float*) gs_alloc_bytes(memory,
1878
0
                                3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_fromabc");
1879
0
                if (icc_luta2bparts.a_curves == NULL)
1880
0
                    return gs_throw(gs_error_VMerror, "Allocation of ICC a curves failed");
1881
1882
0
                curr_pos = icc_luta2bparts.a_curves;
1883
0
                memcpy(curr_pos,&(pcie->caches.DecodeABC.caches->floats.values[0]),
1884
0
                                CURVE_SIZE*sizeof(float));
1885
0
                curr_pos += CURVE_SIZE;
1886
0
                memcpy(curr_pos,&((pcie->caches.DecodeABC.caches[1]).floats.values[0]),
1887
0
                                CURVE_SIZE*sizeof(float));
1888
0
                curr_pos += CURVE_SIZE;
1889
0
                memcpy(curr_pos,&((pcie->caches.DecodeABC.caches[2]).floats.values[0]),
1890
0
                                CURVE_SIZE*sizeof(float));
1891
0
            }
1892
0
            if (has_lmn_procs) {
1893
0
                icc_luta2bparts.m_curves = (float*) gs_alloc_bytes(memory,
1894
0
                                3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_fromabc");
1895
0
                if (icc_luta2bparts.m_curves == NULL) {
1896
0
                    gs_free_object(memory, icc_luta2bparts.a_curves,
1897
0
                                   "gsicc_create_fromabc");
1898
0
                    return gs_throw(gs_error_VMerror, "Allocation of ICC m curves failed");
1899
0
                }
1900
0
                curr_pos = icc_luta2bparts.m_curves;
1901
0
                memcpy(curr_pos,&(pcie->common.caches.DecodeLMN->floats.values[0]),
1902
0
                                CURVE_SIZE*sizeof(float));
1903
0
                curr_pos += CURVE_SIZE;
1904
0
                memcpy(curr_pos,&((pcie->common.caches.DecodeLMN[1]).floats.values[0]),
1905
0
                                CURVE_SIZE*sizeof(float));
1906
0
                curr_pos += CURVE_SIZE;
1907
0
                memcpy(curr_pos,&((pcie->common.caches.DecodeLMN[2]).floats.values[0]),
1908
0
                                CURVE_SIZE*sizeof(float));
1909
0
            }
1910
            /* Convert ABC matrix to 2x2x2 MLUT type */
1911
0
            icc_luta2bparts.clut = (gsicc_clut*) gs_alloc_bytes(memory,
1912
0
                                        sizeof(gsicc_clut),"gsicc_create_fromabc");
1913
0
            if (icc_luta2bparts.clut == NULL) {
1914
0
                gs_free_object(memory, icc_luta2bparts.a_curves,
1915
0
                               "gsicc_create_fromabc");
1916
0
                gs_free_object(memory, icc_luta2bparts.m_curves,
1917
0
                               "gsicc_create_fromabc");
1918
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC clut failed");
1919
0
            }
1920
0
            for (k = 0; k < 3; k++) {
1921
0
                icc_luta2bparts.clut->clut_dims[k] = 2;
1922
0
            }
1923
0
            icc_luta2bparts.clut->clut_num_input = 3;
1924
0
            icc_luta2bparts.clut->clut_num_output = 3;
1925
0
            icc_luta2bparts.clut->clut_word_width = 2;
1926
0
            gsicc_create_initialize_clut(icc_luta2bparts.clut);
1927
            /* 8 grid points, 3 outputs */
1928
0
            icc_luta2bparts.clut->data_short =
1929
0
                            (unsigned short*) gs_alloc_bytes(memory,
1930
0
                            8*3*(size_t)sizeof(short),"gsicc_create_fromabc");
1931
0
            if (icc_luta2bparts.clut->data_short == NULL) {
1932
0
                gs_free_object(memory, icc_luta2bparts.a_curves,
1933
0
                               "gsicc_create_fromabc");
1934
0
                gs_free_object(memory, icc_luta2bparts.m_curves,
1935
0
                               "gsicc_create_fromabc");
1936
0
                gs_free_object(memory, icc_luta2bparts.clut,
1937
0
                               "gsicc_create_fromabc");
1938
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC clut data failed");
1939
0
            }
1940
0
            gsicc_matrix3_to_mlut(&(pcie->MatrixABC), icc_luta2bparts.clut->data_short);
1941
            /* LMN Matrix */
1942
0
            cie_matrix_transpose3(&(pcie->common.MatrixLMN), &matrix_input_trans);
1943
0
            icc_luta2bparts.matrix = &matrix_input_trans;
1944
            /* Create the profile */
1945
0
            code = create_lutAtoBprofile(pp_buffer_in, header, &icc_luta2bparts,
1946
0
                                         false, false, memory);
1947
0
            if (code < 0)
1948
0
                return code;
1949
0
        }
1950
8
    }
1951
8
    gsicc_create_free_luta2bpart(memory, &icc_luta2bparts);
1952
8
    *profile_size_out = header->size;
1953
#if SAVEICCPROFILE
1954
    /* Dump the buffer to a file for testing if its a valid ICC profile */
1955
    if(debug_catch)
1956
        save_profile(memory,*pp_buffer_in,"fromabc",header->size);
1957
#endif
1958
8
    return 0;
1959
8
}
1960
1961
int
1962
gsicc_create_froma(const gs_color_space *pcs, unsigned char **pp_buffer_in,
1963
                   int *profile_size_out, gs_memory_t *memory,
1964
                   gx_cie_vector_cache *a_cache, gx_cie_scalar_cache *lmn_caches)
1965
15
{
1966
15
    icProfile iccprofile;
1967
15
    icHeader  *header = &(iccprofile.header);
1968
#if SAVEICCPROFILE
1969
    int debug_catch = 1;
1970
#endif
1971
15
    gs_matrix3 matrix_input;
1972
15
    float *curr_pos;
1973
15
    bool has_a_proc = !(a_cache->floats.params.is_identity);
1974
15
    bool has_lmn_procs = !(lmn_caches->floats.params.is_identity &&
1975
8
                         (lmn_caches)[1].floats.params.is_identity &&
1976
8
                         (lmn_caches)[2].floats.params.is_identity);
1977
15
    gsicc_lutatob icc_luta2bparts;
1978
15
    bool common_range_ok;
1979
15
    gs_cie_a *pcie = pcs->params.a;
1980
15
    bool input_range_ok;
1981
15
    int code;
1982
1983
15
    gsicc_create_init_luta2bpart(&icc_luta2bparts);
1984
    /* Fill in the common stuff */
1985
15
    setheader_common(header, 4);
1986
    /* We will use an input type class which keeps us from having to
1987
       create an inverse.  We will keep the data a generic 3 color.
1988
       Since we are doing PS color management the PCS is XYZ */
1989
15
    header->colorSpace = icSigGrayData;
1990
15
    header->deviceClass = icSigInputClass;
1991
15
    header->pcs = icSigXYZData;
1992
15
    icc_luta2bparts.num_out = 3;
1993
15
    icc_luta2bparts.num_in = 1;
1994
15
    icc_luta2bparts.white_point = &(pcie->common.points.WhitePoint);
1995
15
    icc_luta2bparts.black_point = &(pcie->common.points.BlackPoint);
1996
1997
15
    code = gsicc_compute_cam(&icc_luta2bparts, memory);
1998
15
    if (code < 0) {
1999
0
        return gs_rethrow(code, "Create from CIEA failed");
2000
0
    }
2001
2002
    /* Check the range values.  If the internal ranges are outside of
2003
       0 to 1 then we will need to sample as a full CLUT.  The input
2004
       range can be different, but we we will correct for this.  Finally
2005
       we need to worry about enforcing the achromatic constraint for the
2006
       CLUT if we are creating the entire thing. */
2007
15
    common_range_ok = check_range(&(pcie->common.RangeLMN.ranges[0]),3);
2008
15
    if (!common_range_ok) {
2009
0
        input_range_ok = check_range(&(pcie->RangeA),1);
2010
0
        code = gsicc_create_mashed_clut(&icc_luta2bparts, header, NULL, pcs,
2011
0
                                 &(pcie->RangeA), pp_buffer_in, profile_size_out,
2012
0
                                 !input_range_ok, memory);
2013
0
        if (code < 0)
2014
0
            return gs_rethrow(code, "Failed to create ICC mashed CLUT");
2015
15
    } else {
2016
        /* We do not need to create a massive CLUT.  Try to maintain
2017
           the objects as best we can */
2018
        /* Since we are going from 1 gray input to 3 XYZ values, we will need
2019
           to include the MLUT for the 1 to 3 conversion applied by the matrix A.
2020
           Depending upon the other parameters we may have simpiler forms, but this
2021
           is required even when Matrix A is the identity. */
2022
15
        if (has_a_proc) {
2023
8
            icc_luta2bparts.a_curves = (float*) gs_alloc_bytes(memory,
2024
8
                CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_froma");
2025
8
            if (icc_luta2bparts.a_curves == NULL)
2026
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC a curves failed");
2027
8
            memcpy(icc_luta2bparts.a_curves,
2028
8
                    &(pcie->caches.DecodeA.floats.values[0]),
2029
8
                    CURVE_SIZE*sizeof(float));
2030
8
        }
2031
15
        if (has_lmn_procs) {
2032
7
            icc_luta2bparts.m_curves = (float*) gs_alloc_bytes(memory,
2033
7
                3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_froma");
2034
7
            if (icc_luta2bparts.m_curves == NULL) {
2035
0
                gs_free_object(memory, icc_luta2bparts.a_curves, "gsicc_create_froma");
2036
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC m curves failed");
2037
0
            }
2038
7
            curr_pos = icc_luta2bparts.m_curves;
2039
7
            memcpy(curr_pos,&(pcie->common.caches.DecodeLMN->floats.values[0]),
2040
7
                        CURVE_SIZE*sizeof(float));
2041
7
            curr_pos += CURVE_SIZE;
2042
7
            memcpy(curr_pos,&((pcie->common.caches.DecodeLMN[1]).floats.values[0]),
2043
7
                        CURVE_SIZE*sizeof(float));
2044
7
            curr_pos += CURVE_SIZE;
2045
7
            memcpy(curr_pos,&((pcie->common.caches.DecodeLMN[2]).floats.values[0]),
2046
7
                        CURVE_SIZE*sizeof(float));
2047
7
        }
2048
        /* Convert diagonal A matrix to 2x1 MLUT type */
2049
15
        icc_luta2bparts.clut = (gsicc_clut*) gs_alloc_bytes(memory,
2050
15
            sizeof(gsicc_clut),"gsicc_create_froma"); /* 2 grid points 3 outputs */
2051
15
        if (icc_luta2bparts.clut == NULL) {
2052
0
            gs_free_object(memory, icc_luta2bparts.a_curves, "gsicc_create_froma");
2053
0
            gs_free_object(memory, icc_luta2bparts.m_curves, "gsicc_create_froma");
2054
0
            return gs_throw(gs_error_VMerror, "Allocation of ICC clut failed");
2055
0
        }
2056
15
        icc_luta2bparts.clut->clut_dims[0] = 2;
2057
15
        icc_luta2bparts.clut->clut_num_input = 1;
2058
15
        icc_luta2bparts.clut->clut_num_output = 3;
2059
15
        icc_luta2bparts.clut->clut_word_width = 2;
2060
15
        gsicc_create_initialize_clut(icc_luta2bparts.clut);
2061
        /* 2 grid points 3 outputs */
2062
15
        icc_luta2bparts.clut->data_short = (unsigned short*)
2063
15
                    gs_alloc_bytes(memory, 2 * 3 * sizeof(short),
2064
15
                   "gsicc_create_froma");
2065
15
        if (icc_luta2bparts.clut->data_short == NULL) {
2066
0
            gs_free_object(memory, icc_luta2bparts.a_curves, "gsicc_create_froma");
2067
0
            gs_free_object(memory, icc_luta2bparts.m_curves, "gsicc_create_froma");
2068
0
            gs_free_object(memory, icc_luta2bparts.clut, "gsicc_create_froma");
2069
0
            return gs_throw(gs_error_VMerror, "Allocation of ICC clut data failed");
2070
0
        }
2071
        /*  Studies of CIEBasedA spaces
2072
            and AR rendering of these reveals that they only look
2073
            at the product sum of the MatrixA and the 2nd column of
2074
            the LM Matrix (if there is one).  This is used as a Y
2075
            decode value from which to map between the black point
2076
            and the white point.  The black point is actually ignored
2077
            and a black point of 0 is used. */
2078
15
        gsicc_vec_to_mlut(&(pcie->MatrixA), icc_luta2bparts.clut->data_short);
2079
15
        cie_matrix_transpose3(&(pcie->common.MatrixLMN), &matrix_input);
2080
        /* Encoding to ICC range happens in create_lutAtoBprofile */
2081
15
        icc_luta2bparts.matrix = &matrix_input;
2082
15
        icc_luta2bparts.num_in = 1;
2083
15
        icc_luta2bparts.num_out = 3;
2084
        /* Create the profile */
2085
        /* Note Adobe only looks at the Y value for CIEBasedA spaces.
2086
           we will do the same */
2087
15
        code = create_lutAtoBprofile(pp_buffer_in, header, &icc_luta2bparts, true,
2088
15
                                     false, memory);
2089
15
        if (code < 0)
2090
0
            return gs_rethrow(code, "Failed to create ICC AtoB Profile");
2091
15
    }
2092
15
    *profile_size_out = header->size;
2093
15
    gsicc_create_free_luta2bpart(memory, &icc_luta2bparts);
2094
#if SAVEICCPROFILE
2095
    /* Dump the buffer to a file for testing if its a valid ICC profile */
2096
    if(debug_catch)
2097
        save_profile(memory,*pp_buffer_in,"froma",header->size);
2098
#endif
2099
15
    return 0;
2100
15
}
2101
2102
/* Common code shared by def and defg generation */
2103
static int
2104
gsicc_create_defg_common(gs_cie_abc *pcie, gsicc_lutatob *icc_luta2bparts,
2105
                         bool has_lmn_procs, bool has_abc_procs,
2106
                         icHeader *header, gx_color_lookup_table *Table,
2107
                         const gs_color_space *pcs, gs_range *ranges,
2108
                         unsigned char **pp_buffer_in, int *profile_size_out,
2109
                         gs_memory_t* memory)
2110
0
{
2111
0
    gs_matrix3 matrix_input_trans;
2112
0
    int k;
2113
0
    bool input_range_ok;
2114
0
    int code;
2115
2116
0
    gsicc_matrix_init(&(pcie->common.MatrixLMN));  /* Need this set now */
2117
0
    gsicc_matrix_init(&(pcie->MatrixABC));          /* Need this set now */
2118
0
    setheader_common(header, 4);
2119
2120
    /* We will use an input type class which keeps us from having to
2121
       create an inverse.  We will keep the data a generic 3 color.
2122
       Since we are doing PS color management the PCS is XYZ */
2123
0
    header->deviceClass = icSigInputClass;
2124
0
    header->pcs = icSigXYZData;
2125
0
    icc_luta2bparts->num_out = 3;
2126
0
    icc_luta2bparts->white_point = &(pcie->common.points.WhitePoint);
2127
0
    icc_luta2bparts->black_point = &(pcie->common.points.BlackPoint);
2128
2129
    /* Calculate the chromatic adaptation matrix */
2130
0
    code = gsicc_compute_cam(icc_luta2bparts, memory);
2131
0
    if (code < 0) {
2132
0
        return gs_rethrow(code, "Create ICC from CIEABC failed");
2133
0
    }
2134
2135
    /* question now is, can we keep the table as it is, or do we need to merge
2136
     some of the def(g) parts.  Some merging or operators into the table must occur
2137
     if we have MatrixABC, LMN Decode and Matrix LMN, otherwise we can encode
2138
     the table directly and squash the rest into the curves matrix curve portion
2139
     of the ICC form */
2140
0
    if ( (!(pcie->MatrixABC.is_identity) && has_lmn_procs &&
2141
0
                   !(pcie->common.MatrixLMN.is_identity)) || 1 ) {
2142
        /* Table must take over some of the other elements. We are going to
2143
           go to a 16 bit table in this case.  For now, we are going to
2144
           mash all the elements in the table.  We may want to revisit this later. */
2145
        /* We must complete the defg or def decode function such that it is within
2146
           the HIJ(K) range AND is scaled to index into the CLUT properly */
2147
0
        if (gs_color_space_get_index(pcs) == gs_color_space_index_CIEDEF) {
2148
0
            input_range_ok = check_range(&(pcs->params.def->RangeDEF.ranges[0]),3);
2149
0
        } else {
2150
0
            input_range_ok = check_range(&(pcs->params.defg->RangeDEFG.ranges[0]),4);
2151
0
        }
2152
0
        code = gsicc_create_mashed_clut(icc_luta2bparts, header, Table,
2153
0
                            pcs, ranges, pp_buffer_in, profile_size_out,
2154
0
                            !input_range_ok, memory);
2155
0
        if (code < 0)
2156
0
            return gs_rethrow(code, "Failed to create ICC clut");
2157
0
    } else {
2158
        /* Table can stay as is. Handle the ABC/LMN portions via the curves
2159
           matrix curves operation */
2160
0
        icc_luta2bparts->matrix = &matrix_input_trans;
2161
0
        code = gsicc_create_abc_merge(icc_luta2bparts, &(pcie->common.MatrixLMN),
2162
0
                                &(pcie->MatrixABC), has_abc_procs,
2163
0
                                has_lmn_procs, pcie->caches.DecodeABC.caches,
2164
0
                                pcie->common.caches.DecodeLMN, memory);
2165
0
        if (code < 0)
2166
0
            return gs_rethrow(code, "Failed to create ICC abc merge");
2167
2168
        /* Get the table data */
2169
0
        icc_luta2bparts->clut = (gsicc_clut*) gs_alloc_bytes(memory,
2170
0
                            sizeof(gsicc_clut),"gsicc_create_defg_common");
2171
0
        if (icc_luta2bparts->clut == NULL)
2172
0
            return gs_throw(gs_error_VMerror, "Allocation of ICC clut failed");
2173
2174
0
        for (k = 0; k < icc_luta2bparts->num_in; k++) {
2175
0
            icc_luta2bparts->clut->clut_dims[k] = Table->dims[k];
2176
0
        }
2177
0
        icc_luta2bparts->clut->clut_num_input = icc_luta2bparts->num_in;
2178
0
        icc_luta2bparts->clut->clut_num_output = 3;
2179
0
        icc_luta2bparts->clut->clut_word_width = 1;
2180
0
        gsicc_create_initialize_clut(icc_luta2bparts->clut);
2181
        /* Get the PS table data directly */
2182
0
        icc_luta2bparts->clut->data_byte = (byte*) Table->table->data;
2183
        /* Create the profile. */
2184
0
        code = create_lutAtoBprofile(pp_buffer_in, header, icc_luta2bparts, false,
2185
0
                                     false, memory);
2186
0
        if (code < 0)
2187
0
            return gs_rethrow(code, "Failed to create ICC lutAtoB");
2188
0
    }
2189
0
    gsicc_create_free_luta2bpart(memory, icc_luta2bparts);
2190
0
    *profile_size_out = header->size;
2191
0
    return 0;
2192
0
}
2193
2194
/* If we have an ABC matrix, a DecodeLMN and an LMN matrix we have to mash
2195
   together the table, Decode ABC (if present) and ABC matrix. */
2196
int
2197
gsicc_create_fromdefg(const gs_color_space *pcs, unsigned char **pp_buffer_in,
2198
                      int *profile_size_out, gs_memory_t *memory,
2199
                      gx_cie_vector_cache *abc_caches,
2200
                      gx_cie_scalar_cache *lmn_caches,
2201
                      gx_cie_scalar_cache *defg_caches)
2202
0
{
2203
0
    gs_cie_defg *pcie = pcs->params.defg;
2204
0
    gsicc_lutatob icc_luta2bparts;
2205
0
    icProfile iccprofile;
2206
0
    icHeader  *header = &(iccprofile.header);
2207
#if SAVEICCPROFILE
2208
    int debug_catch = 1;
2209
#endif
2210
0
    float *curr_pos;
2211
0
    bool has_abc_procs = !((abc_caches->floats.params.is_identity &&
2212
0
                         (abc_caches)[1].floats.params.is_identity &&
2213
0
                         (abc_caches)[2].floats.params.is_identity));
2214
0
    bool has_lmn_procs = !((lmn_caches->floats.params.is_identity &&
2215
0
                         (lmn_caches)[1].floats.params.is_identity &&
2216
0
                         (lmn_caches)[2].floats.params.is_identity));
2217
0
    bool has_defg_procs = !((defg_caches->floats.params.is_identity &&
2218
0
                         (defg_caches)[1].floats.params.is_identity &&
2219
0
                         (defg_caches)[2].floats.params.is_identity &&
2220
0
                         (defg_caches)[3].floats.params.is_identity));
2221
0
    int code;
2222
2223
    /* Fill in the uncommon stuff */
2224
0
    gsicc_create_init_luta2bpart(&icc_luta2bparts);
2225
0
    header->colorSpace = icSigCmykData;
2226
0
    icc_luta2bparts.num_in = 4;
2227
2228
    /* The a curves stored as def procs */
2229
0
    if (has_defg_procs) {
2230
0
        icc_luta2bparts.a_curves = (float*) gs_alloc_bytes(memory,
2231
0
            4*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_fromdefg");
2232
0
        if (icc_luta2bparts.a_curves == NULL)
2233
0
            return gs_throw(gs_error_VMerror, "Allocation of ICC a curves failed");
2234
0
        curr_pos = icc_luta2bparts.a_curves;
2235
0
        memcpy(curr_pos,&(pcie->caches_defg.DecodeDEFG->floats.values[0]),
2236
0
                CURVE_SIZE*sizeof(float));
2237
0
        curr_pos += CURVE_SIZE;
2238
0
        memcpy(curr_pos,&((pcie->caches_defg.DecodeDEFG[1]).floats.values[0]),
2239
0
                CURVE_SIZE*sizeof(float));
2240
0
        curr_pos += CURVE_SIZE;
2241
0
        memcpy(curr_pos,&((pcie->caches_defg.DecodeDEFG[2]).floats.values[0]),
2242
0
                CURVE_SIZE*sizeof(float));
2243
0
        curr_pos += CURVE_SIZE;
2244
0
        memcpy(curr_pos,&((pcie->caches_defg.DecodeDEFG[3]).floats.values[0]),
2245
0
                CURVE_SIZE*sizeof(float));
2246
0
    }
2247
    /* Note the recast.  Should be OK since we only access common stuff in there */
2248
0
    code = gsicc_create_defg_common((gs_cie_abc*) pcie, &icc_luta2bparts,
2249
0
                                    has_lmn_procs, has_abc_procs,
2250
0
                                    header, &(pcie->Table), pcs,
2251
0
                                    &(pcie->RangeDEFG.ranges[0]),
2252
0
                                    pp_buffer_in, profile_size_out, memory);
2253
#if SAVEICCPROFILE
2254
    /* Dump the buffer to a file for testing if its a valid ICC profile */
2255
    if(debug_catch)
2256
        save_profile(memory,*pp_buffer_in,"fromdefg",header->size);
2257
#endif
2258
0
    return code;
2259
0
}
2260
2261
int
2262
gsicc_create_fromdef(const gs_color_space *pcs, unsigned char **pp_buffer_in,
2263
                     int *profile_size_out, gs_memory_t *memory,
2264
                     gx_cie_vector_cache *abc_caches,
2265
                     gx_cie_scalar_cache *lmn_caches,
2266
                     gx_cie_scalar_cache *def_caches)
2267
0
{
2268
0
    gs_cie_def *pcie = pcs->params.def;
2269
0
    gsicc_lutatob icc_luta2bparts;
2270
0
    icProfile iccprofile;
2271
0
    icHeader  *header = &(iccprofile.header);
2272
#if SAVEICCPROFILE
2273
    int debug_catch = 1;
2274
#endif
2275
0
    float *curr_pos;
2276
0
    bool has_abc_procs = !((abc_caches->floats.params.is_identity &&
2277
0
                         (abc_caches)[1].floats.params.is_identity &&
2278
0
                         (abc_caches)[2].floats.params.is_identity));
2279
0
    bool has_lmn_procs = !((lmn_caches->floats.params.is_identity &&
2280
0
                         (lmn_caches)[1].floats.params.is_identity &&
2281
0
                         (lmn_caches)[2].floats.params.is_identity));
2282
0
    bool has_def_procs = !((def_caches->floats.params.is_identity &&
2283
0
                         (def_caches)[1].floats.params.is_identity &&
2284
0
                         (def_caches)[2].floats.params.is_identity));
2285
0
    int code;
2286
2287
0
    gsicc_create_init_luta2bpart(&icc_luta2bparts);
2288
2289
0
    header->colorSpace = icSigRgbData;
2290
0
    icc_luta2bparts.num_in = 3;
2291
2292
    /* The a curves stored as def procs */
2293
0
    if (has_def_procs) {
2294
0
        icc_luta2bparts.a_curves = (float*) gs_alloc_bytes(memory,
2295
0
                        3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_fromdef");
2296
0
        if (icc_luta2bparts.a_curves == NULL)
2297
0
            return gs_throw(gs_error_VMerror, "Allocation of ICC a curves failed");
2298
0
        curr_pos = icc_luta2bparts.a_curves;
2299
0
        memcpy(curr_pos,&(pcie->caches_def.DecodeDEF->floats.values[0]),
2300
0
                CURVE_SIZE*sizeof(float));
2301
0
        curr_pos += CURVE_SIZE;
2302
0
        memcpy(curr_pos,&((pcie->caches_def.DecodeDEF[1]).floats.values[0]),
2303
0
                CURVE_SIZE*sizeof(float));
2304
0
        curr_pos += CURVE_SIZE;
2305
0
        memcpy(curr_pos,&((pcie->caches_def.DecodeDEF[2]).floats.values[0]),
2306
0
                CURVE_SIZE*sizeof(float));
2307
0
    }
2308
0
    code = gsicc_create_defg_common((gs_cie_abc*) pcie, &icc_luta2bparts,
2309
0
                                    has_lmn_procs, has_abc_procs, header,
2310
0
                                    &(pcie->Table), pcs, &(pcie->RangeDEF.ranges[0]),
2311
0
                                    pp_buffer_in, profile_size_out, memory);
2312
#if SAVEICCPROFILE
2313
    /* Dump the buffer to a file for testing if its a valid ICC profile */
2314
    if(debug_catch)
2315
        save_profile(memory,*pp_buffer_in,"fromdef",header->size);
2316
#endif
2317
0
    return code;
2318
0
}
2319
2320
void
2321
gsicc_create_fromcrd(unsigned char *buffer, gs_memory_t *memory)
2322
0
{
2323
0
    icProfile iccprofile;
2324
0
    icHeader  *header = &(iccprofile.header);
2325
2326
0
    setheader_common(header, 4);
2327
0
}
2328
2329
/* V2 creation from current profile */
2330
2331
0
#define TRC_V2_SIZE 256
2332
2333
static void
2334
init_common_tagsv2(gsicc_tag tag_list[], int num_tags, int *last_tag)
2335
0
{
2336
    /*    profileDescriptionTag copyrightTag  */
2337
0
    int curr_tag, temp_size;
2338
2339
0
    if (*last_tag < 0)
2340
0
        curr_tag = 0;
2341
0
    else
2342
0
        curr_tag = (*last_tag) + 1;
2343
2344
0
    tag_list[curr_tag].offset = HEADER_SIZE + num_tags * TAG_SIZE + 4;
2345
0
    tag_list[curr_tag].sig = icSigProfileDescriptionTag;
2346
0
    temp_size = DATATYPE_SIZE + 4 + strlen(desc_name) + 1 + 12 + 67;
2347
0
    tag_list[curr_tag].byte_padding = get_padding(temp_size);
2348
0
    tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
2349
2350
0
    curr_tag++;
2351
2352
0
    tag_list[curr_tag].offset = tag_list[curr_tag - 1].offset +
2353
0
        tag_list[curr_tag - 1].size;
2354
0
    tag_list[curr_tag].sig = icSigCopyrightTag;
2355
0
    temp_size = DATATYPE_SIZE + strlen(copy_right) + 1;
2356
0
    tag_list[curr_tag].byte_padding = get_padding(temp_size);
2357
0
    tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
2358
0
    *last_tag = curr_tag;
2359
0
}
2360
2361
static int
2362
getsize_lut16Type(int tablesize, int num_inputs, int num_outputs)
2363
0
{
2364
0
    int clutsize;
2365
2366
    /* Header (-8 as we already include the type later)
2367
       plus linear curves (2 points each of 2 bytes) */
2368
0
    int size = 52 - 8 + 4 * num_inputs + 4 * num_outputs;
2369
0
    clutsize = (int) pow(tablesize, num_inputs) * num_outputs * 2;
2370
0
    return size + clutsize;
2371
0
}
2372
2373
static int
2374
getsize_lut8Type(int tablesize, int num_inputs, int num_outputs)
2375
0
{
2376
0
    int clutsize;
2377
2378
    /* Header (-8 as we already include the type later)
2379
       plus linear curves (2 points each of 2 bytes) */
2380
0
    int size = 48 - 8 + 256 * num_inputs + 256 * num_outputs;
2381
0
    clutsize = (int)pow(tablesize, num_inputs) * num_outputs;
2382
0
    return size + clutsize;
2383
0
}
2384
2385
2386
static byte*
2387
write_v2_common_data(byte *buffer, int profile_size, icHeader *header,
2388
    gsicc_tag *tag_list, int num_tags, byte *mediawhitept)
2389
0
{
2390
0
    byte *curr_ptr = buffer;
2391
0
    int k;
2392
2393
    /* The header */
2394
0
    header->size = profile_size;
2395
0
    copy_header(curr_ptr, header);
2396
0
    curr_ptr += HEADER_SIZE;
2397
2398
    /* Tag table */
2399
0
    copy_tagtable(curr_ptr, tag_list, num_tags);
2400
0
    curr_ptr += TAG_SIZE*num_tags;
2401
0
    curr_ptr += 4;
2402
2403
    /* Common tags */
2404
0
    add_common_tag_data(curr_ptr, tag_list, 2);
2405
0
    for (k = 0; k< NUMBER_COMMON_TAGS; k++) {
2406
0
        curr_ptr += tag_list[k].size;
2407
0
    }
2408
2409
    /* Media white point. Get from current profile */
2410
0
    write_bigendian_4bytes(curr_ptr, icSigXYZType);
2411
0
    curr_ptr += 4;
2412
0
    memset(curr_ptr, 0, 4);
2413
0
    curr_ptr += 4;
2414
0
    memcpy(curr_ptr, mediawhitept, 12);
2415
0
    curr_ptr += 12;
2416
2417
0
    return curr_ptr;
2418
0
}
2419
2420
static gsicc_link_t*
2421
get_link(const gs_gstate *pgs, cmm_profile_t *src_profile,
2422
    cmm_profile_t *des_profile, gsicc_rendering_intents_t intent)
2423
0
{
2424
0
    gsicc_rendering_param_t rendering_params;
2425
2426
    /* Now the main colorants. Get them and the TRC data from using the link
2427
    between the source profile and the CIEXYZ profile */
2428
0
    rendering_params.black_point_comp = gsBLACKPTCOMP_OFF;
2429
0
    rendering_params.override_icc = false;
2430
0
    rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
2431
0
    rendering_params.rendering_intent = intent;
2432
0
    rendering_params.cmm = gsCMM_DEFAULT;
2433
0
    return gsicc_get_link_profile(pgs, NULL, src_profile, des_profile,
2434
0
        &rendering_params, pgs->memory, false);
2435
0
}
2436
2437
static void
2438
get_colorant(int index, gsicc_link_t *link, icS15Fixed16Number XYZ_Data[])
2439
0
{
2440
0
    unsigned short des[3], src[3];
2441
0
    int k;
2442
2443
0
    src[0] = 0;
2444
0
    src[1] = 0;
2445
0
    src[2] = 0;
2446
0
    src[index] = 65535;
2447
0
    (link->procs.map_color)(NULL, link, &src, &des, 2);
2448
0
    for (k = 0; k < 3; k++) {
2449
0
        XYZ_Data[k] = double2XYZtype((float)des[k] / 65535.0);
2450
0
    }
2451
0
}
2452
2453
static void
2454
get_trc(int index, gsicc_link_t *link, float **htrc, int trc_size)
2455
0
{
2456
0
    unsigned short des[3], src[3];
2457
0
    float max;
2458
0
    float *ptrc = *htrc;
2459
0
    int k;
2460
2461
0
    src[0] = 0;
2462
0
    src[1] = 0;
2463
0
    src[2] = 0;
2464
2465
    /* First get the max value for Y on the range */
2466
0
    src[index] = 65535;
2467
0
    (link->procs.map_color)(NULL, link, &src, &des, 2);
2468
0
    max = des[1];
2469
2470
0
    for (k = 0; k < trc_size; k++) {
2471
0
        src[index] = (unsigned short)((double)k * (double)65535 / (double)(trc_size - 1));
2472
0
        (link->procs.map_color)(NULL, link, &src, &des, 2);
2473
        /* Use Y */
2474
0
        ptrc[k] = (float)des[1] / max;
2475
0
    }
2476
0
}
2477
2478
static void
2479
clean_lut(gsicc_clut *clut, gs_memory_t *memory)
2480
0
{
2481
0
    if (clut->clut_word_width == 2)
2482
0
        gs_free_object(memory, clut->data_short, "clean_lut");
2483
0
    else
2484
0
        gs_free_object(memory, clut->data_byte, "clean_lut");
2485
0
}
2486
2487
/* This is used for the A2B0 type table and B2A0. */
2488
static int
2489
create_clut_v2(gsicc_clut *clut, gsicc_link_t *link, int num_in,
2490
        int num_out, int table_size, gs_memory_t *memory, int bitdepth)
2491
0
{
2492
0
    unsigned short *input_samples, *indexptr;
2493
0
    unsigned short *ptr_short;
2494
0
    byte *ptr_byte;
2495
0
    int num_points, index;
2496
0
    unsigned short input[4], output[4];
2497
0
    int kk, j, i;
2498
2499
0
    clut->clut_num_input = num_in;
2500
0
    clut->clut_num_output = num_out;
2501
0
    clut->clut_word_width = bitdepth;
2502
0
    for (kk = 0; kk < num_in; kk++)
2503
0
        clut->clut_dims[kk] = table_size;
2504
0
    clut->clut_num_entries = (int) pow(table_size, num_in);
2505
0
    num_points = clut->clut_num_entries;
2506
0
    if (bitdepth == 2) {
2507
0
        clut->data_byte = NULL;
2508
0
        clut->data_short = (unsigned short*)gs_alloc_bytes(memory,
2509
0
                              (size_t)clut->clut_num_entries * num_out *
2510
0
                                                 sizeof(unsigned short),
2511
0
                              "create_clut_v2");
2512
0
        if (clut->data_short == NULL)
2513
0
            return -1;
2514
0
    } else {
2515
0
        clut->data_short = NULL;
2516
0
        clut->data_byte = (byte*)gs_alloc_bytes(memory,
2517
0
                               (size_t)clut->clut_num_entries * num_out,
2518
0
                               "create_clut_v2");
2519
0
        if (clut->data_byte == NULL)
2520
0
            return -1;
2521
0
    }
2522
2523
    /* Create the sample indices */
2524
0
    input_samples = (unsigned short*) gs_alloc_bytes(memory,
2525
0
        sizeof(unsigned short)*(size_t)table_size, "create_clut_v2");
2526
0
    if (input_samples == NULL) {
2527
0
        return -1;
2528
0
    }
2529
0
    indexptr = input_samples;
2530
0
    for (j = 0; j < table_size; j++)
2531
0
        *indexptr++ = (unsigned short)(((double)j / (double)(table_size - 1)) * 65535.0);
2532
2533
    /* Now populate the table. Index 1 goes the slowest (e.g. R) */
2534
0
    ptr_short = clut->data_short;
2535
0
    ptr_byte = clut->data_byte;
2536
0
    for (i = 0; i < num_points; i++) {
2537
0
        if (num_in == 1) {
2538
0
            index = i%table_size;
2539
0
            input[0] = input_samples[index];
2540
0
        }
2541
0
        if (num_in == 3) {
2542
0
            index = i%table_size;
2543
0
            input[2] = input_samples[index];
2544
0
            index = (unsigned int)floor((float)i / (float)table_size) % table_size;
2545
0
            input[1] = input_samples[index];
2546
0
            index = (unsigned int)floor((float)i / (float)(table_size*
2547
0
                table_size)) % table_size;
2548
0
            input[0] = input_samples[index];
2549
0
        }
2550
0
        if (num_in == 4) {
2551
0
            index = i%table_size;
2552
0
            input[3] = input_samples[index];
2553
0
            index = (unsigned int)floor((float)i / (float)table_size) % table_size;
2554
0
            input[2] = input_samples[index];
2555
0
            index = (unsigned int)floor((float)i / (float)(table_size*
2556
0
                table_size)) % table_size;
2557
0
            input[1] = input_samples[index];
2558
0
            index = (unsigned int)floor((float)i / (float)(table_size*
2559
0
                table_size*table_size)) % table_size;
2560
0
            input[0] = input_samples[index];
2561
0
        }
2562
0
        if (link == NULL) {
2563
            /* gamut table case */
2564
0
            for (j = 0; j < num_out; j++) {
2565
0
                if (bitdepth == 2)
2566
0
                    *ptr_short++ = 1;
2567
0
                else
2568
0
                    *ptr_byte++ = 1;
2569
0
            }
2570
0
        } else {
2571
0
            double temp;
2572
0
            (link->procs.map_color)(NULL, link, input, output, 2);
2573
2574
            /* Note.  We are using 16 bit for the forward table
2575
               (colorant to lab) and 8 bit for the backward table
2576
               (lab to colorant).  A larger table is used for the backward
2577
               table to reduce quantization */
2578
2579
0
            if (bitdepth == 2) {
2580
                /* Output is LAB 16 bit */
2581
                /* Apply offset of 128 on a and b */
2582
0
                output[1] = output[1] - 128;
2583
0
                output[2] = output[2] - 128;
2584
                /* Scale L to range 0 to 0xFF00 */
2585
0
                temp = (double)output[0] / 65535.0;
2586
0
                temp = temp * 65280.0;
2587
0
                output[0] = (unsigned short)temp;
2588
0
                for (j = 0; j < num_out; j++)
2589
0
                    *ptr_short++ = output[j];
2590
0
            } else {
2591
                /* Output is colorant and 8 bit */
2592
0
                for (j = 0; j < num_out; j++) {
2593
0
                    double temp = (double)output[j] * 255.0 / 65535.0;
2594
0
                    *ptr_byte++ = (byte) temp;
2595
0
                }
2596
0
            }
2597
0
        }
2598
0
    }
2599
0
    gs_free_object(memory, input_samples, "create_clut_v2");
2600
0
    return 0;
2601
0
}
2602
2603
2604
/* Here we write out the lut16Type or lut8Type data V2. Curves are always linear,
2605
   matrix is the identity.  Table data is unique and could be a forward
2606
   or inverse table */
2607
static byte*
2608
add_lutType(byte *input_ptr, gsicc_clut *lut)
2609
0
{
2610
0
    byte *curr_ptr;
2611
0
    unsigned char numout = lut->clut_num_output;
2612
0
    unsigned char numin = lut->clut_num_input;
2613
0
    unsigned char tablesize = lut->clut_dims[0];
2614
0
    float ident[9] = { 1.0, 0, 0, 0, 1.0, 0, 0, 0, 1.0 };
2615
0
    int clut_size = lut->clut_num_entries * numout, k, j;
2616
2617
    /* Signature */
2618
0
    curr_ptr = input_ptr;
2619
0
    if (lut->clut_word_width == 2)
2620
0
        write_bigendian_4bytes(curr_ptr, icSigLut16Type);
2621
0
    else
2622
0
        write_bigendian_4bytes(curr_ptr, icSigLut8Type);
2623
0
    curr_ptr += 4;
2624
    /* Reserved */
2625
0
    memset(curr_ptr, 0, 4);
2626
0
    curr_ptr += 4;
2627
    /* Sizes padded */
2628
0
    *curr_ptr++ = numin;
2629
0
    *curr_ptr++ = numout;
2630
0
    *curr_ptr++ = tablesize;
2631
0
    *curr_ptr++ = 0;
2632
2633
    /* Now the identity matrix */
2634
0
    add_matrixwithbias(curr_ptr, &(ident[0]), false);
2635
0
    curr_ptr += (9 * 4);
2636
2637
    /* Input TRC are linear.  16 bit can have 2 points. 8 bit need 256 */
2638
0
    if (lut->clut_word_width == 2) {
2639
        /* Sizes */
2640
0
        write_bigendian_2bytes(curr_ptr, 2);
2641
0
        curr_ptr += 2;
2642
0
        write_bigendian_2bytes(curr_ptr, 2);
2643
0
        curr_ptr += 2;
2644
2645
        /* Input table data. Linear. */
2646
0
        for (k = 0; k < numin; k++) {
2647
0
            write_bigendian_2bytes(curr_ptr, 0);
2648
0
            curr_ptr += 2;
2649
0
            write_bigendian_2bytes(curr_ptr, 65535);
2650
0
            curr_ptr += 2;
2651
0
        }
2652
0
    } else {
2653
        /* Input table data. Linear. */
2654
0
        for (k = 0; k < numin; k++)
2655
0
            for (j = 0; j < 256; j++)
2656
0
                *curr_ptr++ = j;
2657
0
    }
2658
2659
    /* The CLUT. Write out each entry. */
2660
0
    if (lut->clut_word_width == 2) {
2661
0
        for (k = 0; k < clut_size; k++) {
2662
0
            write_bigendian_2bytes(curr_ptr, lut->data_short[k]);
2663
0
            curr_ptr += 2;
2664
0
        }
2665
0
    } else {
2666
0
        for (k = 0; k < clut_size; k++)
2667
0
            *curr_ptr++ = lut->data_byte[k];
2668
0
    }
2669
2670
    /* Output table data. Linear. */
2671
0
    if (lut->clut_word_width == 2) {
2672
0
        for (k = 0; k < numout; k++) {
2673
0
            write_bigendian_2bytes(curr_ptr, 0);
2674
0
            curr_ptr += 2;
2675
0
            write_bigendian_2bytes(curr_ptr, 65535);
2676
0
            curr_ptr += 2;
2677
0
        }
2678
0
    } else {
2679
0
        for (k = 0; k < numout; k++)
2680
0
            for (j = 0; j < 256; j++)
2681
0
                *curr_ptr++ = j;
2682
0
    }
2683
0
    return curr_ptr;
2684
0
}
2685
2686
static int
2687
create_write_table_intent(const gs_gstate *pgs, gsicc_rendering_intents_t intent,
2688
        cmm_profile_t *src_profile, cmm_profile_t *des_profile, byte *curr_ptr,
2689
        int table_size, int bit_depth, int padding)
2690
0
{
2691
0
    gsicc_link_t *link;
2692
0
    int code;
2693
0
    gsicc_clut clut;
2694
2695
0
    link = get_link(pgs, src_profile, des_profile, intent);
2696
0
    if (link == NULL)
2697
0
        return_error(gs_error_undefined);
2698
0
    code = create_clut_v2(&clut, link, src_profile->num_comps,
2699
0
        des_profile->num_comps, table_size, pgs->memory, bit_depth);
2700
0
    if (code < 0)
2701
0
        return code;
2702
0
    curr_ptr = add_lutType(curr_ptr, &clut);
2703
0
    memset(curr_ptr, 0, padding);
2704
0
    clean_lut(&clut, pgs->memory);
2705
0
    gsicc_release_link(link);
2706
0
    return 0;
2707
0
}
2708
2709
static void
2710
gsicc_create_v2input(const gs_gstate *pgs, icHeader *header, cmm_profile_t *src_profile,
2711
                byte *mediawhitept, cmm_profile_t *lab_profile)
2712
0
{
2713
    /* Need to create the forward table only (Gray, RGB, CMYK to LAB) */
2714
0
    int num_tags = 4; /* 2 common + white + A2B0 */
2715
0
    int profile_size = HEADER_SIZE;
2716
0
    gsicc_tag *tag_list;
2717
0
    gs_memory_t *memory = src_profile->memory;
2718
0
    int last_tag = -1;
2719
0
    byte *buffer, *curr_ptr;
2720
0
    gsicc_link_t *link;
2721
0
    int tag_size;
2722
0
    gsicc_clut clut;
2723
0
    int code, k;
2724
2725
    /* Profile description tag, copyright tag white point and grayTRC */
2726
0
    tag_list = (gsicc_tag*)gs_alloc_bytes(memory,
2727
0
        sizeof(gsicc_tag)*(size_t)num_tags, "gsicc_create_v2input");
2728
0
    if (tag_list == NULL)
2729
0
        return;
2730
    /* Let us precompute the sizes of everything and all our offsets */
2731
0
    profile_size += TAG_SIZE * num_tags;
2732
0
    profile_size += 4; /* number of tags.... */
2733
2734
    /* Common tags */
2735
0
    init_common_tagsv2(tag_list, num_tags, &last_tag);
2736
0
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
2737
2738
    /* Get the tag size of the A2B0 with the lut16Type */
2739
0
    tag_size = getsize_lut16Type(FORWARD_V2_TABLE_SIZE, src_profile->num_comps, 3);
2740
0
    init_tag(tag_list, &last_tag, icSigAToB0Tag, tag_size);
2741
2742
    /* Now get the profile size */
2743
0
    for (k = 0; k < num_tags; k++) {
2744
0
        profile_size += tag_list[k].size;
2745
0
    }
2746
2747
    /* Allocate buffer */
2748
0
    buffer = gs_alloc_bytes(memory, profile_size, "gsicc_create_v2input");
2749
0
    if (buffer == NULL) {
2750
0
        gs_free_object(memory, tag_list, "gsicc_create_v2input");
2751
0
        return;
2752
0
    }
2753
2754
    /* Write out data */
2755
0
    curr_ptr = write_v2_common_data(buffer, profile_size, header, tag_list,
2756
0
        num_tags, mediawhitept);
2757
2758
    /* Now the A2B0 Tag */
2759
0
    link = get_link(pgs, src_profile, lab_profile, gsPERCEPTUAL);
2760
0
    if (link == NULL) {
2761
0
        gs_free_object(memory, tag_list, "gsicc_create_v2input");
2762
0
        gs_free_object(memory, buffer, "gsicc_create_v2input");
2763
0
        return;
2764
0
    }
2765
2766
    /* First create the data */
2767
0
    code = create_clut_v2(&clut, link, src_profile->num_comps, 3,
2768
0
        FORWARD_V2_TABLE_SIZE, pgs->memory, 2);
2769
0
    if (code < 0) {
2770
0
        gs_free_object(memory, tag_list, "gsicc_create_v2input");
2771
0
        gs_free_object(memory, buffer, "gsicc_create_v2input");
2772
0
        return;
2773
0
    }
2774
2775
    /* Now write it out */
2776
0
    curr_ptr = add_lutType(curr_ptr, &clut);
2777
0
    memset(curr_ptr, 0, tag_list[last_tag].byte_padding);  /* padding */
2778
2779
    /* Clean up */
2780
0
    gsicc_release_link(link);
2781
0
    clean_lut(&clut, pgs->memory);
2782
0
    gs_free_object(memory, tag_list, "gsicc_create_v2input");
2783
    /* Save the v2 data */
2784
0
    src_profile->v2_data = buffer;
2785
0
    src_profile->v2_size = profile_size;
2786
2787
#if SAVEICCPROFILE
2788
    /* Dump the buffer to a file for testing if its a valid ICC profile */
2789
    save_profile(memory,buffer, "V2InputType", profile_size);
2790
#endif
2791
0
}
2792
2793
static void
2794
gsicc_create_v2output(const gs_gstate *pgs, icHeader *header, cmm_profile_t *src_profile,
2795
                byte *mediawhitept, cmm_profile_t *lab_profile)
2796
0
{
2797
    /* Need to create forward and backward table (Gray, RGB, CMYK to LAB and back)
2798
       and need to do this for all the intents */
2799
0
    int num_tags = 10; /* 2 common + white + A2B0 + B2A0 + A2B1 + B2A1 + A2B2 + B2A2 + gamut */
2800
0
    int profile_size = HEADER_SIZE;
2801
0
    gsicc_tag *tag_list;
2802
0
    gs_memory_t *memory = src_profile->memory;
2803
0
    int last_tag = -1;
2804
0
    byte *buffer, *curr_ptr;
2805
0
    int tag_location;
2806
0
    int tag_size;
2807
0
    gsicc_clut gamutlut;
2808
0
    int code, k;
2809
2810
    /* Profile description tag, copyright tag white point and grayTRC */
2811
0
    tag_list = (gsicc_tag*)gs_alloc_bytes(memory,
2812
0
        sizeof(gsicc_tag)*(size_t)num_tags, "gsicc_create_v2output");
2813
0
    if (tag_list == NULL)
2814
0
        return;
2815
    /* Let us precompute the sizes of everything and all our offsets */
2816
0
    profile_size += TAG_SIZE * num_tags;
2817
0
    profile_size += 4; /* number of tags.... */
2818
2819
    /* Common tags */
2820
0
    init_common_tagsv2(tag_list, num_tags, &last_tag);
2821
0
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
2822
2823
    /* Get the tag size of the cluts with the lut16Type */
2824
    /* Perceptual */
2825
0
    tag_size = getsize_lut16Type(FORWARD_V2_TABLE_SIZE, src_profile->num_comps, 3);
2826
0
    init_tag(tag_list, &last_tag, icSigAToB0Tag, tag_size);
2827
0
    tag_size = getsize_lut8Type(BACKWARD_V2_TABLE_SIZE, 3, src_profile->num_comps);
2828
0
    init_tag(tag_list, &last_tag, icSigBToA0Tag, tag_size);
2829
2830
    /* Relative Colorimetric */
2831
0
    tag_size = getsize_lut16Type(FORWARD_V2_TABLE_SIZE, src_profile->num_comps, 3);
2832
0
    init_tag(tag_list, &last_tag, icSigAToB1Tag, tag_size);
2833
0
    tag_size = getsize_lut8Type(BACKWARD_V2_TABLE_SIZE, 3, src_profile->num_comps);
2834
0
    init_tag(tag_list, &last_tag, icSigBToA1Tag, tag_size);
2835
2836
    /* Saturation */
2837
0
    tag_size = getsize_lut16Type(FORWARD_V2_TABLE_SIZE, src_profile->num_comps, 3);
2838
0
    init_tag(tag_list, &last_tag, icSigAToB2Tag, tag_size);
2839
0
    tag_size = getsize_lut8Type(BACKWARD_V2_TABLE_SIZE, 3, src_profile->num_comps);
2840
0
    init_tag(tag_list, &last_tag, icSigBToA2Tag, tag_size);
2841
2842
    /* And finally the Gamut Tag.  Since we can't determine gamut here this
2843
       is essentially a required place holder. Make it small */
2844
0
    tag_size = getsize_lut8Type(2, src_profile->num_comps, 1);
2845
0
    init_tag(tag_list, &last_tag, icSigGamutTag, tag_size);
2846
2847
    /* Now get the profile size */
2848
0
    for (k = 0; k < num_tags; k++) {
2849
0
        profile_size += tag_list[k].size;
2850
0
    }
2851
2852
    /* Allocate buffer */
2853
0
    buffer = gs_alloc_bytes(memory, profile_size, "gsicc_create_v2output");
2854
0
    if (buffer == NULL) {
2855
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2856
0
        return;
2857
0
    }
2858
2859
    /* Write out data */
2860
0
    curr_ptr = write_v2_common_data(buffer, profile_size, header, tag_list,
2861
0
        num_tags, mediawhitept);
2862
0
    tag_location = V2_COMMON_TAGS;
2863
2864
    /* A2B0 */
2865
0
    if (create_write_table_intent(pgs, gsPERCEPTUAL, src_profile, lab_profile,
2866
0
        curr_ptr, FORWARD_V2_TABLE_SIZE, 2,
2867
0
        tag_list[tag_location].byte_padding) < 0) {
2868
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2869
0
        return;
2870
0
    }
2871
0
    curr_ptr += tag_list[tag_location].size;
2872
0
    tag_location++;
2873
2874
    /* B2A0 */
2875
0
    if (create_write_table_intent(pgs, gsPERCEPTUAL, lab_profile, src_profile,
2876
0
        curr_ptr, BACKWARD_V2_TABLE_SIZE, 1,
2877
0
        tag_list[tag_location].byte_padding) < 0) {
2878
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2879
0
        return;
2880
0
    }
2881
0
    curr_ptr += tag_list[tag_location].size;
2882
0
    tag_location++;
2883
2884
    /* A2B1 */
2885
0
    if (create_write_table_intent(pgs, gsRELATIVECOLORIMETRIC, src_profile,
2886
0
        lab_profile, curr_ptr, FORWARD_V2_TABLE_SIZE, 2,
2887
0
        tag_list[tag_location].byte_padding) < 0) {
2888
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2889
0
        return;
2890
0
    }
2891
0
    curr_ptr += tag_list[tag_location].size;
2892
0
    tag_location++;
2893
2894
    /* B2A1 */
2895
0
    if (create_write_table_intent(pgs, gsRELATIVECOLORIMETRIC, lab_profile,
2896
0
        src_profile, curr_ptr, BACKWARD_V2_TABLE_SIZE, 1,
2897
0
        tag_list[tag_location].byte_padding) < 0) {
2898
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2899
0
        return;
2900
0
    }
2901
0
    curr_ptr += tag_list[tag_location].size;
2902
0
    tag_location++;
2903
2904
    /* A2B2 */
2905
0
    if (create_write_table_intent(pgs, gsSATURATION, src_profile, lab_profile,
2906
0
        curr_ptr, FORWARD_V2_TABLE_SIZE, 2,
2907
0
        tag_list[tag_location].byte_padding) < 0) {
2908
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2909
0
        return;
2910
0
    }
2911
0
    curr_ptr += tag_list[tag_location].size;
2912
0
    tag_location++;
2913
2914
    /* B2A2 */
2915
0
    if (create_write_table_intent(pgs, gsSATURATION, lab_profile, src_profile,
2916
0
        curr_ptr, BACKWARD_V2_TABLE_SIZE, 1,
2917
0
        tag_list[tag_location].byte_padding) < 0) {
2918
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2919
0
        return;
2920
0
    }
2921
0
    curr_ptr += tag_list[tag_location].size;
2922
0
    tag_location++;
2923
2924
    /* Gamut tag, which is bogus */
2925
0
    code = create_clut_v2(&gamutlut, NULL, src_profile->num_comps, 1, 2, pgs->memory, 1);
2926
0
    if (code < 0) {
2927
0
        gs_free_object(memory, tag_list, "gsicc_create_v2output");
2928
0
        return;
2929
0
    }
2930
2931
    /* Now write it out */
2932
0
    curr_ptr = add_lutType(curr_ptr, &gamutlut);
2933
0
    memset(curr_ptr, 0, tag_list[tag_location].byte_padding);
2934
2935
    /* Done */
2936
0
    gs_free_object(memory, tag_list, "gsicc_create_v2output");
2937
0
    clean_lut(&gamutlut, pgs->memory);
2938
2939
    /* Save the v2 data */
2940
0
    src_profile->v2_data = buffer;
2941
0
    src_profile->v2_size = profile_size;
2942
2943
#if SAVEICCPROFILE
2944
    /* Dump the buffer to a file for testing if its a valid ICC profile */
2945
    save_profile(memory,buffer, "V2OutputType", profile_size);
2946
#endif
2947
0
}
2948
2949
static void
2950
gsicc_create_v2displaygray(const gs_gstate *pgs, icHeader *header, cmm_profile_t *src_profile,
2951
            byte *mediawhitept, cmm_profile_t *xyz_profile)
2952
0
{
2953
0
    int num_tags = 4;
2954
0
    int profile_size = HEADER_SIZE;
2955
0
    gsicc_tag *tag_list;
2956
0
    gs_memory_t *memory = src_profile->memory;
2957
0
    int last_tag = -1;
2958
    /* 4 for name, 4 reserved, 4 for number entries, 2*num_entries */
2959
0
    int trc_tag_size = 12 + 2 * TRC_V2_SIZE;
2960
0
    byte *buffer, *curr_ptr;
2961
0
    unsigned short des[3], src;
2962
0
    float *trc;
2963
0
    int tag_location;
2964
0
    gsicc_link_t *link;
2965
0
    float max;
2966
0
    int k;
2967
2968
    /* Profile description tag, copyright tag white point and grayTRC */
2969
0
    tag_list = (gsicc_tag*)gs_alloc_bytes(memory,
2970
0
        sizeof(gsicc_tag)*(size_t)num_tags, "gsicc_createv2display_gray");
2971
0
    if (tag_list == NULL)
2972
0
        return;
2973
    /* Let us precompute the sizes of everything and all our offsets */
2974
0
    profile_size += TAG_SIZE * num_tags;
2975
0
    profile_size += 4; /* number of tags.... */
2976
2977
    /* Common tags */
2978
0
    init_common_tagsv2(tag_list, num_tags, &last_tag);
2979
0
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
2980
0
    init_tag(tag_list, &last_tag, icSigGrayTRCTag, trc_tag_size);
2981
2982
    /* Now get the profile size */
2983
0
    for (k = 0; k < num_tags; k++) {
2984
0
        profile_size += tag_list[k].size;
2985
0
    }
2986
    /* Allocate buffer */
2987
0
    buffer = gs_alloc_bytes(memory, profile_size, "gsicc_createv2display_gray");
2988
0
    if (buffer == NULL) {
2989
0
        gs_free_object(memory, tag_list, "gsicc_createv2display_gray");
2990
0
        return;
2991
0
    }
2992
2993
    /* Start writing out data to buffer */
2994
0
    curr_ptr = write_v2_common_data(buffer, profile_size, header, tag_list,
2995
0
        num_tags, mediawhitept);
2996
0
    tag_location = V2_COMMON_TAGS;
2997
2998
    /* Now the TRC. First collect the curve data and then write it out */
2999
    /* Get the link between our gray profile and XYZ profile */
3000
0
    link = get_link(pgs, src_profile, xyz_profile, gsPERCEPTUAL);
3001
0
    if (link == NULL) {
3002
0
        gs_free_object(memory, tag_list, "gsicc_createv2display_gray");
3003
0
        gs_free_object(memory, buffer, "gsicc_createv2display_gray");
3004
0
        return;
3005
0
    }
3006
3007
    /* First get the max value for Y on the range */
3008
0
    src = 65535;
3009
0
    (link->procs.map_color)(NULL, link, &src, &(des[0]), 2);
3010
0
    max = des[1];
3011
3012
0
    trc = (float*) gs_alloc_bytes(memory, TRC_V2_SIZE * (size_t)sizeof(float), "gsicc_createv2display_gray");
3013
0
    if (trc == NULL) {
3014
0
        gsicc_release_link(link);
3015
0
        gs_free_object(memory, tag_list, "gsicc_createv2display_gray");
3016
0
        gs_free_object(memory, buffer, "gsicc_createv2display_gray");
3017
0
        return;
3018
0
    }
3019
0
    for (k = 0; k < TRC_V2_SIZE; k++) {
3020
0
        src = (unsigned short)((double)k * (double)65535 / (double)(TRC_V2_SIZE - 1));
3021
0
        (link->procs.map_color)(NULL, link, &src, &(des[0]), 2);
3022
0
        trc[k] = (float)des[1] / max;
3023
0
    }
3024
0
    add_curve(curr_ptr, trc, TRC_V2_SIZE);
3025
0
    curr_ptr += tag_list[tag_location].size;
3026
3027
    /* Clean up */
3028
0
    gsicc_release_link(link);
3029
0
    gs_free_object(memory, tag_list, "gsicc_createv2display_gray");
3030
0
    gs_free_object(memory, trc, "gsicc_createv2display_gray");
3031
    /* Save the v2 data */
3032
0
    src_profile->v2_data = buffer;
3033
0
    src_profile->v2_size = profile_size;
3034
3035
#if SAVEICCPROFILE
3036
    /* Dump the buffer to a file for testing if its a valid ICC profile */
3037
    save_profile(memory, buffer, "V2FromGray", profile_size);
3038
#endif
3039
0
}
3040
3041
static void
3042
gsicc_create_v2displayrgb(const gs_gstate *pgs, icHeader *header, cmm_profile_t *src_profile,
3043
        byte *mediawhitept, cmm_profile_t *xyz_profile)
3044
0
{
3045
0
    int num_tags = 9;
3046
0
    int profile_size = HEADER_SIZE;
3047
0
    gsicc_tag *tag_list;
3048
0
    gs_memory_t *memory = src_profile->memory;
3049
0
    int last_tag = -1;
3050
    /* 4 for name, 4 reserved, 4 for number entries, 2*num_entries */
3051
0
    int trc_tag_size = 12 + 2 * TRC_V2_SIZE;
3052
0
    byte *buffer, *curr_ptr;
3053
0
    float *trc;
3054
0
    int tag_location;
3055
0
    icS15Fixed16Number XYZ_Data[3];
3056
0
    gsicc_link_t *link;
3057
0
    int k;
3058
3059
    /* Profile description tag, copyright tag white point RGB colorants and
3060
       RGB TRCs */
3061
0
    tag_list = (gsicc_tag*)gs_alloc_bytes(memory,
3062
0
        sizeof(gsicc_tag)*(size_t)num_tags, "gsicc_create_v2displayrgb");
3063
0
    if (tag_list == NULL)
3064
0
        return;
3065
    /* Let us precompute the sizes of everything and all our offsets */
3066
0
    profile_size += TAG_SIZE * num_tags;
3067
0
    profile_size += 4; /* number of tags.... */
3068
3069
    /* Common tags + white point + RGB colorants + RGB TRCs */
3070
0
    init_common_tagsv2(tag_list, num_tags, &last_tag);
3071
0
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
3072
0
    init_tag(tag_list, &last_tag, icSigRedColorantTag, XYZPT_SIZE);
3073
0
    init_tag(tag_list, &last_tag, icSigGreenColorantTag, XYZPT_SIZE);
3074
0
    init_tag(tag_list, &last_tag, icSigBlueColorantTag, XYZPT_SIZE);
3075
0
    init_tag(tag_list, &last_tag, icSigRedTRCTag, trc_tag_size);
3076
0
    init_tag(tag_list, &last_tag, icSigGreenTRCTag, trc_tag_size);
3077
0
    init_tag(tag_list, &last_tag, icSigBlueTRCTag, trc_tag_size);
3078
3079
    /* Now get the profile size */
3080
0
    for (k = 0; k < num_tags; k++) {
3081
0
        profile_size += tag_list[k].size;
3082
0
    }
3083
3084
    /* Allocate buffer */
3085
0
    buffer = gs_alloc_bytes(memory, profile_size, "gsicc_create_v2displayrgb");
3086
0
    if (buffer == NULL) {
3087
0
        gs_free_object(memory, tag_list, "gsicc_create_v2displayrgb");
3088
0
        return;
3089
0
    }
3090
3091
    /* Start writing out data to buffer */
3092
0
    curr_ptr = write_v2_common_data(buffer, profile_size, header, tag_list,
3093
0
        num_tags, mediawhitept);
3094
0
    tag_location = V2_COMMON_TAGS;
3095
3096
    /* Now the main colorants. Get them and the TRC data from using the link
3097
        between the source profile and the CIEXYZ profile */
3098
0
    link = get_link(pgs, src_profile, xyz_profile, gsPERCEPTUAL);
3099
0
    if (link == NULL) {
3100
0
        gs_free_object(memory, tag_list, "gsicc_create_v2displayrgb");
3101
0
        gs_free_object(memory, buffer, "gsicc_create_v2displayrgb");
3102
0
        return;
3103
0
    }
3104
3105
    /* Get the Red, Green and Blue colorants */
3106
0
    for (k = 0; k < 3; k++) {
3107
0
        get_colorant(k, link, XYZ_Data);
3108
0
        add_xyzdata(curr_ptr, XYZ_Data);
3109
0
        curr_ptr += tag_list[tag_location].size;
3110
0
        tag_location++;
3111
0
    }
3112
3113
    /* Now the TRCs */
3114
0
    trc = (float*) gs_alloc_bytes(memory, TRC_V2_SIZE * (size_t)sizeof(float), "gsicc_create_v2displayrgb");
3115
0
    if (trc == NULL) {
3116
0
        gsicc_release_link(link);
3117
0
        gs_free_object(memory, tag_list, "gsicc_create_v2displayrgb");
3118
0
        gs_free_object(memory, buffer, "gsicc_create_v2displayrgb");
3119
0
        return;
3120
0
    }
3121
3122
0
    for (k = 0; k < 3; k++) {
3123
0
        get_trc(k, link, &trc, TRC_V2_SIZE);
3124
0
        add_curve(curr_ptr, trc, TRC_V2_SIZE);
3125
0
        curr_ptr += tag_list[tag_location].size;
3126
0
    }
3127
3128
    /* Clean up */
3129
0
    gsicc_release_link(link);
3130
0
    gs_free_object(memory, tag_list, "gsicc_create_v2displayrgb");
3131
0
    gs_free_object(memory, trc, "gsicc_create_v2displayrgb");
3132
    /* Save the v2 data */
3133
0
    src_profile->v2_data = buffer;
3134
0
    src_profile->v2_size = profile_size;
3135
3136
#if SAVEICCPROFILE
3137
    /* Dump the buffer to a file for testing if its a valid ICC profile */
3138
    save_profile(memory,buffer, "V2FromRGB", profile_size);
3139
#endif
3140
0
}
3141
3142
static void
3143
gsicc_create_v2display(const gs_gstate *pgs, icHeader *header, cmm_profile_t *src_profile,
3144
                    byte *mediawhitept, cmm_profile_t *xyz_profile)
3145
0
{
3146
    /* Need to create matrix with the TRCs.  Have to worry about gray
3147
       and RGB cases. */
3148
0
    if (header->colorSpace == icSigGrayData)
3149
0
        gsicc_create_v2displaygray(pgs, header, src_profile, mediawhitept, xyz_profile);
3150
0
    else
3151
0
        gsicc_create_v2displayrgb(pgs, header, src_profile, mediawhitept, xyz_profile);
3152
0
}
3153
3154
static int
3155
readint32(byte *buff)
3156
39
{
3157
39
    int out = 0;
3158
39
    byte *ptr = buff;
3159
39
    int k;
3160
3161
195
    for (k = 0; k < 4; k++) {
3162
156
        int temp = ptr[k];
3163
156
        int shift = (3 - k) * 8;
3164
156
        out += temp << shift;
3165
156
    }
3166
39
    return out;
3167
39
}
3168
3169
/* Create special profile for going to/from CIEXYZ color space.  We will use
3170
   this with lcms and the current profile to construct the structures in
3171
   a new V2 profile */
3172
static int
3173
get_xyzprofile(cmm_profile_t *xyz_profile)
3174
0
{
3175
0
    icProfile iccprofile;
3176
0
    icHeader *header = &(iccprofile.header);
3177
0
    int num_tags = 9;  /* common (2) + rXYZ,gXYZ,bXYZ,rTRC,gTRC,bTRC,wtpt */
3178
0
    int profile_size = HEADER_SIZE;
3179
0
    gsicc_tag *tag_list;
3180
0
    int last_tag = -1;
3181
    /* 4 for name, 4 reserved, 4 for number entries. 0 entries implies linear */
3182
0
    int trc_tag_size = 12;
3183
0
    byte *buffer, *curr_ptr, *tempptr;
3184
0
    int tag_location;
3185
0
    gs_memory_t *memory = xyz_profile->memory;
3186
0
    icS15Fixed16Number temp_XYZ[3];
3187
0
    byte mediawhitept[12];
3188
0
    icS15Fixed16Number one, zero;
3189
0
    int k, j;
3190
0
    int code;
3191
3192
    /* Fill in the common stuff */
3193
0
    setheader_common(header, 2);
3194
    /* If we have to create a table we will do it in XYZ.  If it is a matrix,
3195
    it is still XYZ */
3196
0
    header->pcs = icSigXYZData;
3197
0
    header->colorSpace = icSigRgbData;
3198
0
    header->deviceClass = icSigDisplayClass;
3199
3200
    /* Profile description tag, copyright tag white point and grayTRC */
3201
0
    tag_list = (gsicc_tag*)gs_alloc_bytes(memory,
3202
0
        sizeof(gsicc_tag) * (size_t)num_tags, "get_xyzprofile");
3203
0
    if (tag_list == NULL)
3204
0
        return -1;
3205
    /* Let us precompute the sizes of everything and all our offsets */
3206
0
    profile_size += TAG_SIZE * num_tags;
3207
0
    profile_size += 4; /* number of tags.... */
3208
3209
    /* Common tags + white point + RGB colorants + RGB TRCs */
3210
0
    init_common_tagsv2(tag_list, num_tags, &last_tag);
3211
0
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
3212
0
    init_tag(tag_list, &last_tag, icSigRedColorantTag, XYZPT_SIZE);
3213
0
    init_tag(tag_list, &last_tag, icSigGreenColorantTag, XYZPT_SIZE);
3214
0
    init_tag(tag_list, &last_tag, icSigBlueColorantTag, XYZPT_SIZE);
3215
0
    init_tag(tag_list, &last_tag, icSigRedTRCTag, trc_tag_size);
3216
0
    init_tag(tag_list, &last_tag, icSigGreenTRCTag, trc_tag_size);
3217
0
    init_tag(tag_list, &last_tag, icSigBlueTRCTag, trc_tag_size);
3218
3219
    /* Now get the profile size */
3220
0
    for (k = 0; k < num_tags; k++) {
3221
0
        profile_size += tag_list[k].size;
3222
0
    }
3223
3224
    /* Allocate buffer */
3225
0
    buffer = gs_alloc_bytes(memory, profile_size, "get_xyzprofile");
3226
0
    if (buffer == NULL) {
3227
0
        gs_free_object(memory, tag_list, "get_xyzprofile");
3228
0
        return -1;
3229
0
    }
3230
3231
    /* Media white point for this profile is D50 */
3232
0
    get_D50(temp_XYZ); /* See Appendix D6 in spec */
3233
0
    tempptr = mediawhitept;
3234
0
    for (j = 0; j < 3; j++) {
3235
0
        write_bigendian_4bytes(tempptr, temp_XYZ[j]);
3236
0
        tempptr += 4;
3237
0
    }
3238
3239
    /* Start writing out data to buffer */
3240
0
    curr_ptr = write_v2_common_data(buffer, profile_size, header, tag_list,
3241
0
        num_tags, mediawhitept);
3242
0
    tag_location = V2_COMMON_TAGS;
3243
    /* Now lets add the Red Green and Blue colorant information */
3244
0
    one = double2XYZtype(1);
3245
0
    zero = double2XYZtype(0);
3246
3247
0
    temp_XYZ[0] = one;
3248
0
    temp_XYZ[1] = zero;
3249
0
    temp_XYZ[2] = zero;
3250
0
    add_xyzdata(curr_ptr, temp_XYZ);
3251
0
    curr_ptr += tag_list[tag_location].size;
3252
0
    tag_location++;
3253
3254
0
    temp_XYZ[0] = zero;
3255
0
    temp_XYZ[1] = one;
3256
0
    add_xyzdata(curr_ptr, temp_XYZ);
3257
0
    curr_ptr += tag_list[tag_location].size;
3258
0
    tag_location++;
3259
3260
0
    temp_XYZ[1] = zero;
3261
0
    temp_XYZ[2] = one;
3262
0
    add_xyzdata(curr_ptr, temp_XYZ);
3263
0
    curr_ptr += tag_list[tag_location].size;
3264
0
    tag_location++;
3265
3266
    /* And now the TRCs */
3267
0
    add_curve(curr_ptr, NULL, 0);
3268
0
    curr_ptr += tag_list[tag_location].size;
3269
0
    tag_location++;
3270
0
    add_curve(curr_ptr, NULL, 0);
3271
0
    curr_ptr += tag_list[tag_location].size;
3272
0
    tag_location++;
3273
0
    add_curve(curr_ptr, NULL, 0);
3274
3275
    /* Done */
3276
0
    gs_free_object(memory, tag_list, "get_xyzprofile");
3277
0
    xyz_profile->buffer = buffer;
3278
0
    xyz_profile->buffer_size = profile_size;
3279
0
    code = gsicc_init_profile_info(xyz_profile);
3280
#if SAVEICCPROFILE
3281
    /* Dump the buffer to a file for testing if its a valid ICC profile */
3282
    save_profile(memory,buffer, "XYZProfile", profile_size);
3283
#endif
3284
0
    return code;
3285
0
}
3286
3287
static bool
3288
get_mediawp(cmm_profile_t *src_profile, byte *mediawhitept)
3289
6
{
3290
6
    byte *buffer = &(src_profile->buffer[128]);
3291
6
    int num_tags = readint32(buffer);
3292
6
    int tag_signature = -1;
3293
6
    int offset;
3294
6
    int k;
3295
6
    int buffer_left = src_profile->buffer_size;
3296
3297
6
    if (buffer_left < 128)
3298
0
        return false;
3299
6
    buffer_left -= 128;
3300
3301
6
    if (buffer_left < 4)
3302
0
        return false;
3303
3304
6
    buffer += 4;
3305
6
    buffer_left -= 4;
3306
3307
    /* Get to the tag table */
3308
27
    for (k = 0; k < num_tags; k++) {
3309
27
        if (buffer_left < 12)
3310
0
            return false;
3311
3312
27
        tag_signature = readint32(buffer);
3313
27
        if (tag_signature == icSigMediaWhitePointTag)
3314
6
            break;
3315
21
        buffer += 12;
3316
21
        buffer_left -= 12;
3317
21
    }
3318
6
    if (tag_signature != icSigMediaWhitePointTag)
3319
0
        return false;
3320
3321
6
    if (buffer_left < 4)
3322
0
        return false;
3323
3324
6
    buffer += 4;
3325
6
    buffer_left -= 4;
3326
3327
6
    offset = readint32(buffer);
3328
3329
6
    if (buffer_left < offset + 8 || offset < 0)
3330
6
        return false;
3331
3332
0
    buffer = &(src_profile->buffer[offset + 8]);  /* Add offset of 8 for XYZ tag and padding */
3333
0
    buffer_left = src_profile->buffer_size - (offset + 8);
3334
3335
    /* Data is already in the proper format. Just get the bytes */
3336
0
    if (buffer_left < 12)
3337
0
        return false;
3338
3339
0
    memcpy(mediawhitept, buffer, 12);
3340
0
    return true;
3341
0
}
3342
3343
static void
3344
gsicc_create_v2(const gs_gstate *pgs, cmm_profile_t *src_profile)
3345
6
{
3346
6
    icProfile iccprofile;
3347
6
    icHeader *header = &(iccprofile.header);
3348
6
    byte mediawhitept[12];
3349
6
    cmm_profile_t *xyz_profile;
3350
3351
6
    if (src_profile->v2_data != NULL)
3352
0
        return;
3353
3354
    /* Fill in the common stuff */
3355
6
    setheader_common(header, 2);
3356
3357
    /* Get the data_cs of current profile */
3358
6
    switch (src_profile->data_cs) {
3359
3
        case gsGRAY:
3360
3
            header->colorSpace = icSigGrayData;
3361
3
        break;
3362
3
        case gsRGB:
3363
3
            header->colorSpace = icSigRgbData;
3364
3
            break;
3365
0
        case gsCMYK:
3366
0
            header->colorSpace = icSigCmykData;
3367
0
            break;
3368
0
        default:
3369
#ifdef DEBUG
3370
            gs_warn("Failed in creating V2 ICC profile");
3371
#endif
3372
0
            return;
3373
0
            break;
3374
6
    }
3375
3376
    /* Use the deviceClass from the source profile. */
3377
6
    header->deviceClass = gsicc_get_device_class(src_profile);
3378
3379
    /* Unfortunately we have to get the media white point also. lcms wrapped
3380
       up the method internally when it went to release 2 so we will do our
3381
       own*/
3382
6
    if (!get_mediawp(src_profile, &(mediawhitept[0]))) {
3383
#ifdef DEBUG
3384
        gs_warn("Failed in creating V2 ICC profile");
3385
#endif
3386
6
        return;
3387
6
    }
3388
3389
    /* Also, we will want to create an XYZ ICC profile that we can use for
3390
       creating our data with lcms.  If already created, this profile is
3391
       stored in the manager */
3392
0
    if (pgs->icc_manager->xyz_profile != NULL) {
3393
0
        xyz_profile = pgs->icc_manager->xyz_profile;
3394
0
    } else {
3395
0
        xyz_profile = gsicc_profile_new(NULL, pgs->memory, NULL, 0);
3396
0
        if (xyz_profile == NULL) {
3397
#ifdef DEBUG
3398
            gs_warn("Failed in creating V2 ICC profile");
3399
#endif
3400
0
            return;
3401
0
        }
3402
0
        if (get_xyzprofile(xyz_profile) != 0) {
3403
#ifdef DEBUG
3404
            gs_warn("Failed in creating V2 ICC profile");
3405
#endif
3406
0
            return;
3407
0
        }
3408
0
        pgs->icc_manager->xyz_profile = xyz_profile;
3409
0
    }
3410
3411
    /* The type of stuff that we need to create */
3412
0
    switch (header->deviceClass) {
3413
0
        case icSigInputClass:
3414
0
            header->pcs = icSigLabData;
3415
0
            gsicc_create_v2input(pgs, header, src_profile, mediawhitept,
3416
0
                pgs->icc_manager->lab_profile);
3417
0
            break;
3418
0
        case icSigDisplayClass:
3419
0
            header->pcs = icSigXYZData;
3420
0
            gsicc_create_v2display(pgs, header, src_profile, mediawhitept,
3421
0
                xyz_profile);
3422
0
            break;
3423
0
        case icSigOutputClass:
3424
0
            header->pcs = icSigLabData;
3425
0
            gsicc_create_v2output(pgs, header, src_profile, mediawhitept,
3426
0
                pgs->icc_manager->lab_profile);
3427
0
            break;
3428
0
        default:
3429
#ifdef DEBUG
3430
            gs_warn("Failed in creating V2 ICC profile");
3431
#endif
3432
0
            return;
3433
0
            break;
3434
0
    }
3435
0
    return;
3436
0
}
3437
3438
/* While someone could create something that was not valid for now we will
3439
   just trust the version information in the header.  Allow anything with
3440
   major version 2 */
3441
static bool
3442
gsicc_create_isv2(cmm_profile_t *profile)
3443
1.20k
{
3444
1.20k
    if (profile->vers == ICCVERS_UNKNOWN) {
3445
1.20k
        int majorvers = profile->buffer[8];
3446
3447
1.20k
        if (majorvers == 2) {
3448
1.19k
            profile->vers = ICCVERS_2;
3449
1.19k
            return true;
3450
1.19k
        } else {
3451
6
            profile->vers = ICCVERS_NOT2;
3452
6
            return false;
3453
6
        }
3454
1.20k
    }
3455
0
    if (profile->vers == ICCVERS_2)
3456
0
        return true;
3457
0
    else
3458
0
        return false;
3459
0
}
3460
3461
byte*
3462
gsicc_create_getv2buffer(const gs_gstate *pgs, cmm_profile_t *srcprofile,
3463
                        int *size)
3464
1.20k
{
3465
1.20k
    if (gsicc_create_isv2(srcprofile)) {
3466
1.19k
        *size = srcprofile->buffer_size;
3467
1.19k
        return srcprofile->buffer;
3468
1.19k
    }
3469
3470
6
    if (srcprofile->profile_handle == NULL)
3471
0
        srcprofile->profile_handle =
3472
0
        gsicc_get_profile_handle_buffer(srcprofile->buffer,
3473
0
        srcprofile->buffer_size, pgs->memory);
3474
3475
    /* Need to create v2 profile */
3476
6
    gsicc_create_v2(pgs, srcprofile);
3477
3478
6
    *size = srcprofile->v2_size;
3479
6
    return srcprofile->v2_data;
3480
1.20k
}