Coverage Report

Created: 2026-08-08 08:00

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