Coverage Report

Created: 2026-07-24 07:44

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
7.70k
#define HEADER_SIZE 128
143
7.70k
#define TAG_SIZE 12
144
12.2k
#define XYZPT_SIZE 12
145
39.0k
#define DATATYPE_SIZE 8
146
326
#define CURVE_SIZE 512
147
129
#define IDENT_CURVE_SIZE 0
148
10.2k
#define NUMBER_COMMON_TAGS 2
149
5.13k
#define icMultiUnicodeText 0x6d6c7563           /* 'mluc' v4 text type */
150
26
#define icMultiFunctionAtoBType 0x6d414220      /* 'mAB ' v4 lutAtoBtype type */
151
5.18k
#define D50_X 0.9642f
152
5.18k
#define D50_Y 1.0f
153
5.18k
#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
24.6k
{
215
24.6k
    return (4 -x%4)%4;
216
24.6k
}
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
18
{
222
18
    mat->is_identity =
223
18
        mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
224
9
        mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
225
9
        mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
226
18
}
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
9.63k
{
289
9.63k
    out[0] = matrix[0] * in[0] + matrix[1] * in[1] + matrix[2] * in[2];
290
9.63k
    out[1] = matrix[3] * in[0] + matrix[4] * in[1] + matrix[5] * in[2];
291
9.63k
    out[2] = matrix[6] * in[0] + matrix[7] * in[1] + matrix[8] * in[2];
292
9.63k
}
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
17
{
440
17
    unsigned short *curr_ptr = clut;
441
17
    int temp;
442
443
17
    *curr_ptr ++= 0;
444
17
    *curr_ptr ++= 0;
445
17
    *curr_ptr ++= 0;
446
17
    temp = (int)(vec->u * 65535);
447
17
    if (temp > 65535) temp = 65535;
448
17
    if (temp < 0) temp = 0;
449
17
    *curr_ptr ++= temp;
450
17
    temp = (int)(vec->v * 65535);
451
17
    if (temp > 65535) temp = 65535;
452
17
    if (temp < 0) temp = 0;
453
17
    *curr_ptr ++= temp;
454
17
    temp = (int)(vec->w * 65535);
455
17
    if (temp > 65535) temp = 65535;
456
17
    if (temp < 0) temp = 0;
457
17
    *curr_ptr ++= temp;
458
17
}
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
192k
{
479
192k
   *curr_ptr++ = (0xff & (input >> 24));
480
192k
   *curr_ptr++ = (0xff & (input >> 16));
481
192k
   *curr_ptr++ = (0xff & (input >> 8));
482
192k
   *curr_ptr++ = (0xff & input);
483
192k
}
484
485
static void
486
write_bigendian_2bytes(unsigned char *curr_ptr,ushort input)
487
48.3k
{
488
48.3k
   *curr_ptr++ = (0xff & (input >> 8));
489
48.3k
   *curr_ptr++ = (0xff & input);
490
48.3k
}
491
492
static void
493
setdatetime(icDateTimeNumber *datetime)
494
2.58k
{
495
2.58k
    datetime->day = 0;
496
2.58k
    datetime->hours = 0;
497
2.58k
    datetime->minutes = 0;
498
2.58k
    datetime->month = 0;
499
2.58k
    datetime->seconds = 0;
500
2.58k
    datetime->year = 0;
501
2.58k
}
502
503
static icS15Fixed16Number
504
double2XYZtype(float number_in)
505
44.4k
{
506
44.4k
    short s;
507
44.4k
    unsigned short m;
508
509
44.4k
    if (number_in < 0) {
510
1.73k
        number_in = 0;
511
#ifdef DEBUG
512
        gs_warn("Negative CIEXYZ in created ICC Profile");
513
#endif
514
1.73k
    }
515
516
44.4k
    s = (short) number_in;
517
44.4k
    m = (unsigned short) ((number_in - s) * 65536.0);
518
44.4k
    return (icS15Fixed16Number) ((s << 16) | m);
519
44.4k
}
520
521
static icS15Fixed16Number
522
double2icS15Fixed16Number(float number_in)
523
234
{
524
234
    short s;
525
234
    unsigned short m;
526
234
    icS15Fixed16Number temp;
527
234
    float number;
528
529
234
    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
234
    } else {
537
234
        s = (short) number_in;
538
234
        m = (unsigned short) ((number_in - s) * 65536.0);
539
234
        return (icS15Fixed16Number) ((s << 16) | m);
540
234
    }
541
234
}
542
543
static unsigned short
544
float2u8Fixed8(float number_in)
545
7.27k
{
546
7.27k
    return (unsigned short) (number_in * 256);
547
7.27k
}
548
549
static
550
void init_common_tags(gsicc_tag tag_list[],int num_tags, int *last_tag)
551
2.56k
{
552
 /*    profileDescriptionTag
553
       copyrightTag  */
554
555
2.56k
    int curr_tag, temp_size;
556
557
2.56k
    if (*last_tag < 0)
558
2.56k
        curr_tag = 0;
559
0
    else
560
0
        curr_tag = (*last_tag)+1;
561
562
2.56k
    tag_list[curr_tag].offset = HEADER_SIZE+num_tags*TAG_SIZE + 4;
563
2.56k
    tag_list[curr_tag].sig = icSigProfileDescriptionTag;
564
    /* temp_size = DATATYPE_SIZE + 4 + strlen(desc_name) + 1 + 4 + 4 + 3 + 67; */
565
2.56k
    temp_size = 2*strlen(desc_name) + 28;
566
    /* +1 for NULL + 4 + 4 for unicode + 3 + 67 script code */
567
2.56k
    tag_list[curr_tag].byte_padding = get_padding(temp_size);
568
2.56k
    tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
569
570
2.56k
    curr_tag++;
571
572
2.56k
    tag_list[curr_tag].offset = tag_list[curr_tag-1].offset +
573
2.56k
                                                    tag_list[curr_tag-1].size;
574
2.56k
    tag_list[curr_tag].sig = icSigCopyrightTag;
575
    /* temp_size = DATATYPE_SIZE + strlen(copy_right) + 1; */
576
2.56k
    temp_size = 2*strlen(copy_right) + 28;
577
2.56k
    tag_list[curr_tag].byte_padding = get_padding(temp_size);
578
2.56k
    tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
579
2.56k
    *last_tag = curr_tag;
580
2.56k
}
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
5.13k
{
588
5.13k
    unsigned char *curr_ptr;
589
5.13k
    int k;
590
591
5.13k
    curr_ptr = buffer;
592
5.13k
    write_bigendian_4bytes(curr_ptr,icMultiUnicodeText);
593
5.13k
    curr_ptr += 4;
594
5.13k
    memset(curr_ptr,0,4);
595
5.13k
    curr_ptr += 4;
596
5.13k
    write_bigendian_4bytes(curr_ptr,1); /* Number of names */
597
5.13k
    curr_ptr += 4;
598
5.13k
    write_bigendian_4bytes(curr_ptr,12); /* Record size */
599
5.13k
    curr_ptr += 4;
600
5.13k
    write_bigendian_2bytes(curr_ptr,0x656e); /* ISO 639-1, en */
601
5.13k
    curr_ptr += 2;
602
5.13k
    write_bigendian_2bytes(curr_ptr,0x5553); /* ISO 3166, US */
603
5.13k
    curr_ptr += 2;
604
5.13k
    write_bigendian_4bytes(curr_ptr,2*strlen(text)); /* String length */
605
5.13k
    curr_ptr += 4;
606
5.13k
    write_bigendian_4bytes(curr_ptr,28); /* Offset to string */
607
5.13k
    curr_ptr += 4;
608
    /* String written as UTF-16BE. No NULL */
609
169k
    for (k = 0; k < strlen(text); k++) {
610
164k
        *curr_ptr ++= 0;
611
164k
        *curr_ptr ++= text[k];
612
164k
    }
613
5.13k
    memset(curr_ptr,0,tag_list[curr_tag].byte_padding);  /* padding */
614
5.13k
}
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.56k
{
660
2.56k
    unsigned char *curr_ptr;
661
2.56k
    curr_ptr = buffer;
662
663
2.56k
    if (vers == 4) {
664
2.56k
        add_v4_text_tag(curr_ptr, desc_name, tag_list, 0);
665
2.56k
        curr_ptr += tag_list[0].size;
666
2.56k
        add_v4_text_tag(curr_ptr, copy_right, tag_list, 1);
667
2.56k
    } 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.56k
}
673
674
static
675
void  init_tag(gsicc_tag tag_list[], int *last_tag, icTagSignature tagsig,
676
               int datasize)
677
19.5k
{
678
    /* This should never be called first. Common tags should be taken care of */
679
680
19.5k
    int curr_tag = (*last_tag)+1;
681
682
19.5k
    tag_list[curr_tag].offset = tag_list[curr_tag-1].offset +
683
19.5k
                                                    tag_list[curr_tag-1].size;
684
19.5k
    tag_list[curr_tag].sig = tagsig;
685
19.5k
    tag_list[curr_tag].byte_padding = get_padding(DATATYPE_SIZE + datasize);
686
19.5k
    tag_list[curr_tag].size = DATATYPE_SIZE + datasize +
687
19.5k
                                            tag_list[curr_tag].byte_padding;
688
19.5k
    *last_tag = curr_tag;
689
19.5k
}
690
691
static void
692
setheader_common(icHeader *header, int vers)
693
2.58k
{
694
    /* This needs to all be predefined for a simple copy. MJV todo */
695
2.58k
    header->cmmId = 0;
696
2.58k
    if (vers == 4)
697
2.56k
        header->version = 0x04200000;
698
14
    else
699
14
        header->version = 0x02200000;
700
2.58k
    setdatetime(&(header->date));
701
2.58k
    header->magic = icMagicNumber;
702
2.58k
    header->platform = icSigMacintosh;
703
2.58k
    header->flags = 0;
704
2.58k
    header->manufacturer = 0;
705
2.58k
    header->model = 0;
706
2.58k
    header->attributes[0] = 0;
707
2.58k
    header->attributes[1] = 0;
708
2.58k
    header->renderingIntent = 3;
709
2.58k
    header->illuminant.X = double2XYZtype((float) 0.9642);
710
2.58k
    header->illuminant.Y = double2XYZtype((float) 1.0);
711
2.58k
    header->illuminant.Z = double2XYZtype((float) 0.8249);
712
2.58k
    header->creator = 0;
713
    /* Version 4 includes a profile id, field which is an md5 sum */
714
2.58k
    memset(header->reserved,0,44);
715
2.58k
}
716
717
static void
718
copy_header(unsigned char *buffer,icHeader *header)
719
2.56k
{
720
2.56k
    unsigned char *curr_ptr;
721
722
2.56k
    curr_ptr = buffer;
723
2.56k
    write_bigendian_4bytes(curr_ptr,header->size);
724
2.56k
    curr_ptr += 4;
725
2.56k
    memset(curr_ptr,0,4);
726
2.56k
    curr_ptr += 4;
727
2.56k
    write_bigendian_4bytes(curr_ptr,header->version);
728
2.56k
    curr_ptr += 4;
729
2.56k
    write_bigendian_4bytes(curr_ptr,header->deviceClass);
730
2.56k
    curr_ptr += 4;
731
2.56k
    write_bigendian_4bytes(curr_ptr,header->colorSpace);
732
2.56k
    curr_ptr += 4;
733
2.56k
    write_bigendian_4bytes(curr_ptr,header->pcs);
734
2.56k
    curr_ptr += 4;
735
736
    /* Date and time */
737
2.56k
    memset(curr_ptr,0,12);
738
2.56k
    curr_ptr += 12;
739
2.56k
    write_bigendian_4bytes(curr_ptr,header->magic);
740
2.56k
    curr_ptr += 4;
741
2.56k
    write_bigendian_4bytes(curr_ptr,header->platform);
742
2.56k
    curr_ptr += 4;
743
2.56k
    memset(curr_ptr,0,24);
744
2.56k
    curr_ptr += 24;
745
2.56k
    write_bigendian_4bytes(curr_ptr,header->illuminant.X);
746
2.56k
    curr_ptr += 4;
747
2.56k
    write_bigendian_4bytes(curr_ptr,header->illuminant.Y);
748
2.56k
    curr_ptr += 4;
749
2.56k
    write_bigendian_4bytes(curr_ptr,header->illuminant.Z);
750
2.56k
    curr_ptr += 4;
751
2.56k
    memset(curr_ptr,0,48);
752
2.56k
}
753
754
static void
755
copy_tagtable(unsigned char *buffer,gsicc_tag *tag_list, ulong num_tags)
756
2.56k
{
757
2.56k
    unsigned int k;
758
2.56k
    unsigned char *curr_ptr;
759
760
2.56k
    curr_ptr = buffer;
761
2.56k
    write_bigendian_4bytes(curr_ptr,num_tags);
762
2.56k
    curr_ptr += 4;
763
27.2k
    for (k = 0; k < num_tags; k++) {
764
24.6k
        write_bigendian_4bytes(curr_ptr,tag_list[k].sig);
765
24.6k
        curr_ptr += 4;
766
24.6k
        write_bigendian_4bytes(curr_ptr,tag_list[k].offset);
767
24.6k
        curr_ptr += 4;
768
24.6k
        write_bigendian_4bytes(curr_ptr,tag_list[k].size);
769
24.6k
        curr_ptr += 4;
770
24.6k
    }
771
2.56k
}
772
773
static void
774
get_D50(icS15Fixed16Number XYZ[])
775
2.56k
{
776
2.56k
    XYZ[0] = double2XYZtype(D50_X);
777
2.56k
    XYZ[1] = double2XYZtype(D50_Y);
778
2.56k
    XYZ[2] = double2XYZtype(D50_Z);
779
2.56k
}
780
781
static void
782
get_XYZ(icS15Fixed16Number XYZ[], gs_vector3 *vector)
783
26
{
784
26
    XYZ[0] = double2XYZtype(vector->u);
785
26
    XYZ[1] = double2XYZtype(vector->v);
786
26
    XYZ[2] = double2XYZtype(vector->w);
787
26
}
788
789
static void
790
get_XYZ_doubletr(icS15Fixed16Number XYZ[], float *vector)
791
9.63k
{
792
9.63k
    XYZ[0] = double2XYZtype(vector[0]);
793
9.63k
    XYZ[1] = double2XYZtype(vector[1]);
794
9.63k
    XYZ[2] = double2XYZtype(vector[2]);
795
9.63k
}
796
797
static void
798
scale_matrix(float *matrix_input,float scale_factor)
799
9
{
800
9
    int k;
801
802
90
    for (k = 0; k < 9; k++) {
803
81
        matrix_input[k] = matrix_input[k]/2.0;
804
81
    }
805
9
}
806
807
static void
808
add_gammadata(unsigned char *input_ptr, unsigned short gamma,
809
              icTagTypeSignature curveType)
810
7.27k
{
811
7.27k
    unsigned char *curr_ptr;
812
813
7.27k
    curr_ptr = input_ptr;
814
7.27k
    write_bigendian_4bytes(curr_ptr,curveType);
815
7.27k
    curr_ptr += 4;
816
7.27k
    memset(curr_ptr,0,4);
817
7.27k
    curr_ptr += 4;
818
819
    /* one entry for gamma */
820
7.27k
    write_bigendian_4bytes(curr_ptr, 1);
821
7.27k
    curr_ptr += 4;
822
823
    /* The encode (8frac8) gamma, with padding */
824
7.27k
    write_bigendian_2bytes(curr_ptr, gamma);
825
7.27k
    curr_ptr += 2;
826
827
    /* pad two bytes */
828
7.27k
    memset(curr_ptr,0,2);
829
7.27k
}
830
831
static void
832
add_xyzdata(unsigned char *input_ptr, icS15Fixed16Number temp_XYZ[])
833
12.2k
{
834
12.2k
    int j;
835
12.2k
    unsigned char *curr_ptr;
836
837
12.2k
    curr_ptr = input_ptr;
838
12.2k
    write_bigendian_4bytes(curr_ptr,icSigXYZType);
839
12.2k
    curr_ptr += 4;
840
12.2k
    memset(curr_ptr,0,4);
841
12.2k
    curr_ptr += 4;
842
48.9k
    for (j = 0; j < 3; j++) {
843
36.6k
        write_bigendian_4bytes(curr_ptr, temp_XYZ[j]);
844
36.6k
        curr_ptr += 4;
845
36.6k
    }
846
12.2k
}
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
26
{
859
26
    unsigned char *curr_ptr;
860
26
    float *float_ptr = float_ptr_in;
861
26
    int k;
862
863
    /* GS Matrix is coming in with data arranged in row ordered form */
864
26
    curr_ptr = input_ptr;
865
260
    for (k = 0; k < 9; k++ ){
866
234
        write_bigendian_4bytes(curr_ptr, double2icS15Fixed16Number(*float_ptr));
867
234
        curr_ptr += 4;
868
234
        float_ptr++;
869
234
    }
870
26
    if (has_bias){
871
26
        memset(curr_ptr,0,4*3);
872
26
    }
873
26
}
874
875
static void
876
matrixmult(float leftmatrix[], int nlrow, int nlcol,
877
           float rightmatrix[], int nrrow, int nrcol, float result[])
878
10.4k
{
879
10.4k
    float *curr_row;
880
10.4k
    int k,l,j,ncols,nrows;
881
10.4k
    float sum;
882
883
10.4k
    nrows = nlrow;
884
10.4k
    ncols = nrcol;
885
10.4k
    if (nlcol == nrrow) {
886
41.6k
        for (k = 0; k < nrows; k++) {
887
31.2k
            curr_row = &(leftmatrix[k*nlcol]);
888
93.7k
            for (l = 0; l < ncols; l++) {
889
62.5k
                sum = 0.0;
890
249k
                for (j = 0; j < nlcol; j++) {
891
187k
                    sum = sum + curr_row[j] * rightmatrix[j*nrcol+l];
892
187k
                }
893
62.5k
                result[k*ncols+l] = sum;
894
62.5k
            }
895
31.2k
        }
896
10.4k
    }
897
10.4k
}
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.59k
{
909
2.59k
    float cat02matrix[] = {0.7328f, 0.4296f, -0.1624f,
910
2.59k
                            -0.7036f, 1.6975f, 0.0061f,
911
2.59k
                             0.003f, 0.0136f, 0.9834f};
912
2.59k
    float cat02matrixinv[] = {1.0961f, -0.2789f, 0.1827f,
913
2.59k
                              0.4544f, 0.4735f, 0.0721f,
914
2.59k
                             -0.0096f, -0.0057f, 1.0153f};
915
2.59k
    float vonkries_diag[9];
916
2.59k
    float temp_matrix[9];
917
2.59k
    float lms_wp_src[3], lms_wp_des[3];
918
2.59k
    int k;
919
920
2.59k
    matrixmult(cat02matrix,3,3,&(white_src->u),3,1,&(lms_wp_src[0]));
921
2.59k
    matrixmult(cat02matrix,3,3,&(white_des->u),3,1,&(lms_wp_des[0]));
922
2.59k
    memset(&(vonkries_diag[0]),0,sizeof(float)*9);
923
924
10.3k
    for (k = 0; k < 3; k++) {
925
7.78k
        if (lms_wp_src[k] > 0 ) {
926
7.77k
            vonkries_diag[k*3+k] = lms_wp_des[k]/lms_wp_src[k];
927
7.77k
        } else {
928
6
            vonkries_diag[k*3+k] = 1;
929
6
        }
930
7.78k
    }
931
2.59k
    matrixmult(&(vonkries_diag[0]), 3, 3, &(cat02matrix[0]), 3, 3,
932
2.59k
                &(temp_matrix[0]));
933
2.59k
    matrixmult(&(cat02matrixinv[0]), 3, 3, &(temp_matrix[0]), 3, 3, &(cam[0]));
934
2.59k
}
935
936
static int
937
gsicc_compute_cam(gsicc_lutatob *icc_luta2bparts, gs_memory_t *memory)
938
26
{
939
26
    gs_vector3 d50;
940
941
26
    d50.u = D50_X;
942
26
    d50.v = D50_Y;
943
26
    d50.w = D50_Z;
944
945
    /* Calculate the chromatic adaptation matrix */
946
26
    icc_luta2bparts->cam = (float*) gs_alloc_bytes(memory,
947
26
                                        9 * sizeof(float), "gsicc_compute_cam");
948
26
    if (icc_luta2bparts->cam == NULL) {
949
0
        return gs_throw(gs_error_VMerror, "Allocation of ICC cam failed");
950
0
    }
951
26
    gsicc_create_compute_cam(icc_luta2bparts->white_point, &(d50), icc_luta2bparts->cam);
952
26
    return 0;
953
26
}
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.54k
{
963
2.54k
    gs_vector3 d50;
964
2.54k
    gs_vector3 wp;
965
2.54k
    float *cam;
966
967
2.54k
    wp.u = curr_wp[0];
968
2.54k
    wp.v = curr_wp[1];
969
2.54k
    wp.w = curr_wp[2];
970
971
2.54k
    d50.u = D50_X;
972
2.54k
    d50.v = D50_Y;
973
2.54k
    d50.w = D50_Z;
974
975
2.54k
    cam = (float*)gs_alloc_bytes(memory, 9 * sizeof(float), "gsicc_get_cat02_cam");
976
2.54k
    if (cam == NULL) {
977
0
        gs_throw(gs_error_VMerror, "Allocation of cat02 matrix failed");
978
0
        return NULL;
979
0
    }
980
2.54k
    gsicc_create_compute_cam(&wp, &(d50), cam);
981
982
2.54k
    return cam;
983
2.54k
}
984
985
static void
986
add_ident_curves(unsigned char *input_ptr,int number_of_curves)
987
43
{
988
43
    unsigned char *curr_ptr;
989
43
    int k;
990
991
43
    curr_ptr = input_ptr;
992
156
    for (k = 0; k < number_of_curves; k++) {
993
       /* Signature */
994
113
        write_bigendian_4bytes(curr_ptr,icSigCurveType);
995
113
        curr_ptr += 4;
996
        /* Reserved */
997
113
        memset(curr_ptr,0,4);
998
113
        curr_ptr += 4;
999
        /* Count */
1000
113
        write_bigendian_4bytes(curr_ptr, 0);
1001
113
        curr_ptr += 4;
1002
113
    }
1003
43
}
1004
1005
static void
1006
add_clutAtoB(unsigned char *input_ptr, gsicc_clut *clut)
1007
17
{
1008
17
    unsigned char *curr_ptr = input_ptr;
1009
17
    int k;
1010
17
    int num_channels_in = clut->clut_num_input;
1011
17
    int number_samples = clut->clut_num_entries;
1012
1013
    /* First write out the dimensions for each channel */
1014
34
    for (k = 0; k < num_channels_in; k++) {
1015
17
        memset(curr_ptr, clut->clut_dims[k], 1);
1016
17
        curr_ptr++;
1017
17
    }
1018
    /* Set the remainder of the dimenensions */
1019
17
    memset(curr_ptr, 0, 16-num_channels_in);
1020
17
    curr_ptr += (16-num_channels_in);
1021
    /* word size */
1022
17
    memset(curr_ptr, clut->clut_word_width, 1);
1023
17
    curr_ptr++;
1024
    /* padding */
1025
17
    memset(curr_ptr, 0, 3);
1026
17
    curr_ptr += 3;
1027
17
    if (clut->data_byte != NULL) {
1028
        /* A byte table */
1029
0
        memcpy(curr_ptr,clut->data_byte,number_samples*3);
1030
17
    } else {
1031
        /* A float table */
1032
119
        for ( k = 0; k < number_samples*3; k++ ) {
1033
102
            write_bigendian_2bytes(curr_ptr,clut->data_short[k]);
1034
102
            curr_ptr += 2;
1035
102
        }
1036
17
    }
1037
17
}
1038
1039
static void
1040
add_curve(unsigned char *input_ptr, float *curve_data, int num_samples)
1041
60
{
1042
60
    unsigned char *curr_ptr;
1043
60
    unsigned short value;
1044
60
    int k;
1045
1046
   /* Signature */
1047
60
    curr_ptr = input_ptr;
1048
60
    write_bigendian_4bytes(curr_ptr,icSigCurveType);
1049
60
    curr_ptr += 4;
1050
    /* Reserved */
1051
60
    memset(curr_ptr,0,4);
1052
60
    curr_ptr += 4;
1053
    /* Count */
1054
60
    write_bigendian_4bytes(curr_ptr, num_samples);
1055
60
    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
30.7k
    for (k = 0; k < num_samples; k++) {
1059
30.7k
        if (curve_data[k] < 0) curve_data[k] = 0;
1060
30.7k
        if (curve_data[k] > 1) curve_data[k] = 1;
1061
30.7k
        value = (unsigned int) (curve_data[k]*65535.0);
1062
30.7k
        write_bigendian_2bytes(curr_ptr,value);
1063
30.7k
        curr_ptr+=2;
1064
30.7k
    }
1065
60
}
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
26
{
1072
26
    int data_offset, mlut_size;
1073
26
    int numout = lutatobparts->num_out;
1074
26
    int numin = lutatobparts->num_in;
1075
26
    int pad_bytes;
1076
1077
26
    data_offset = 32;
1078
    /* B curves always present */
1079
26
    if (lutatobparts->b_curves != NULL) {
1080
0
        data_offset += (numout*(CURVE_SIZE*2+12));
1081
26
    } else {
1082
26
        data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1083
26
    }
1084
    /* M curves present if Matrix is present */
1085
26
    if (lutatobparts->matrix != NULL ) {
1086
26
        data_offset += (12*4);
1087
        /* M curves */
1088
26
        if (lutatobparts->m_curves != NULL) {
1089
17
            data_offset += (numout*(CURVE_SIZE*2+12));
1090
17
        } else {
1091
9
            data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1092
9
        }
1093
26
    }
1094
    /* A curves present if clut is present */
1095
26
    if (lutatobparts->clut != NULL) {
1096
        /* We may need to pad the clut to make sure we are on a 4 byte boundary */
1097
17
        mlut_size = lutatobparts->clut->clut_num_entries *
1098
17
                            lutatobparts->clut->clut_word_width * 3;
1099
17
        pad_bytes = (4 - mlut_size%4)%4;
1100
17
        data_offset += (mlut_size + pad_bytes + 20);
1101
17
        if (lutatobparts->a_curves != NULL) {
1102
9
            data_offset += (numin*(CURVE_SIZE*2+12));
1103
9
        } else {
1104
8
            data_offset += (numin*(IDENT_CURVE_SIZE*2+12));
1105
8
        }
1106
17
    }
1107
26
    return data_offset;
1108
26
}
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
26
{
1122
/* We need to figure out all the offsets to the various objects based upon
1123
    which ones are actually present */
1124
26
    unsigned char *curr_ptr;
1125
26
    long mlut_size = 0;     /* silence compiler warning */
1126
26
    int data_offset;
1127
26
    int k;
1128
26
    int numout = lutatobparts->num_out;
1129
26
    int numin = lutatobparts->num_in;
1130
26
    int pad_bytes = 0;
1131
1132
    /* Signature */
1133
26
    curr_ptr = input_ptr;
1134
26
    write_bigendian_4bytes(curr_ptr,icMultiFunctionAtoBType);
1135
26
    curr_ptr += 4;
1136
    /* Reserved */
1137
26
    memset(curr_ptr,0,4);
1138
26
    curr_ptr += 4;
1139
    /* Padded sizes */
1140
26
    *curr_ptr++ = numin;
1141
26
    *curr_ptr++ = numout;
1142
26
    memset(curr_ptr,0,2);
1143
26
    curr_ptr += 2;
1144
    /* Note if data offset is zero, element is not present */
1145
    /* offset to B curves (last curves) */
1146
26
    data_offset = 32;
1147
26
    if (lutatobparts->b_curves == NULL) {
1148
        /* identity curve must be present */
1149
26
        write_bigendian_4bytes(curr_ptr,data_offset);
1150
26
        data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1151
26
    } else {
1152
0
        write_bigendian_4bytes(curr_ptr,data_offset);
1153
0
        data_offset += (numout*(CURVE_SIZE*2+12));
1154
0
    }
1155
26
    curr_ptr += 4;
1156
    /* offset to matrix and M curves */
1157
26
    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
26
    } else {
1162
26
        write_bigendian_4bytes(curr_ptr,data_offset);
1163
26
        data_offset += (12*4);
1164
26
        curr_ptr += 4;
1165
        /* offset to M curves (Matrix curves -- only come with matrix) */
1166
26
        if (lutatobparts->m_curves == NULL) {
1167
            /* identity curve must be present */
1168
9
            write_bigendian_4bytes(curr_ptr,data_offset);
1169
9
            data_offset += (numout*(IDENT_CURVE_SIZE*2+12));
1170
17
        } else {
1171
17
            write_bigendian_4bytes(curr_ptr,data_offset);
1172
17
            data_offset += (numout*(CURVE_SIZE*2+12));
1173
17
        }
1174
26
    }
1175
26
    curr_ptr += 4;
1176
    /* offset to CLUT and A curves */
1177
26
    if (lutatobparts->clut == NULL) {
1178
9
        memset(curr_ptr,0,4); /* CLUT */
1179
9
        curr_ptr += 4;
1180
9
        memset(curr_ptr,0,4); /* A curves */
1181
17
    } else {
1182
17
        write_bigendian_4bytes(curr_ptr,data_offset);
1183
17
        mlut_size = (long)lutatobparts->clut->clut_num_entries *
1184
17
                          lutatobparts->clut->clut_word_width * 3;
1185
17
        pad_bytes = (4 - mlut_size%4)%4;
1186
17
        data_offset += (mlut_size + pad_bytes + 20);
1187
17
        curr_ptr += 4;
1188
        /* offset to A curves (first curves) */
1189
17
        if (lutatobparts->a_curves == NULL || lutatobparts->clut == NULL) {
1190
            /* identity curve must be present */
1191
8
            write_bigendian_4bytes(curr_ptr,data_offset);
1192
8
            data_offset += (numin*(IDENT_CURVE_SIZE*2+12));
1193
9
        } else {
1194
9
            write_bigendian_4bytes(curr_ptr,data_offset);
1195
9
            data_offset += (numin*(CURVE_SIZE*2+12));
1196
9
        }
1197
17
    }
1198
26
    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
26
    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
26
    } else {
1208
26
        add_ident_curves(curr_ptr,numout);
1209
26
        curr_ptr += numout*(12 + IDENT_CURVE_SIZE*2);
1210
26
    }
1211
    /* Then the matrix */
1212
26
    if (lutatobparts->matrix != NULL) {
1213
26
        add_matrixwithbias(curr_ptr,(float*) lutatobparts->matrix,true);
1214
26
        curr_ptr += (12*4);
1215
        /* M curves */
1216
26
        if (lutatobparts->m_curves != NULL) {
1217
68
            for (k = 0; k < numout; k++) {
1218
51
                add_curve(curr_ptr, (lutatobparts->m_curves)+k*CURVE_SIZE, CURVE_SIZE);
1219
51
                curr_ptr += (12 + CURVE_SIZE*2);
1220
51
            }
1221
17
        } else {
1222
9
            add_ident_curves(curr_ptr,numout);
1223
9
            curr_ptr += numout*(12 + IDENT_CURVE_SIZE*2);
1224
9
        }
1225
26
    }
1226
    /* Then the clut */
1227
26
    if (lutatobparts->clut != NULL) {
1228
17
        add_clutAtoB(curr_ptr, lutatobparts->clut);
1229
17
        curr_ptr += (20 + mlut_size);
1230
17
        memset(curr_ptr,0,pad_bytes); /* 4 byte boundary */
1231
17
        curr_ptr += pad_bytes;
1232
        /* The A curves */
1233
17
        if (lutatobparts->a_curves != NULL) {
1234
18
            for (k = 0; k < numin; k++) {
1235
9
                add_curve(curr_ptr, (lutatobparts->a_curves)+k*CURVE_SIZE,
1236
9
                            CURVE_SIZE);
1237
9
                curr_ptr += (12 + CURVE_SIZE*2);
1238
9
            }
1239
9
        } else {
1240
8
            add_ident_curves(curr_ptr,numin);
1241
8
            curr_ptr += numin*(12 + IDENT_CURVE_SIZE*2);
1242
8
        }
1243
1244
17
    }
1245
26
}
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.54k
{
1252
2.54k
    icProfile iccprofile;
1253
2.54k
    icHeader  *header = &(iccprofile.header);
1254
2.54k
    int profile_size,k;
1255
2.54k
    int num_tags;
1256
2.54k
    gsicc_tag *tag_list;
1257
2.54k
    unsigned short encode_gamma;
1258
2.54k
    unsigned char *curr_ptr;
1259
2.54k
    int last_tag;
1260
2.54k
    icS15Fixed16Number temp_XYZ[3];
1261
2.54k
    int tag_location;
1262
2.54k
    icTagSignature TRC_Tags[3] = {icSigRedTRCTag, icSigGreenTRCTag,
1263
2.54k
                                  icSigBlueTRCTag};
1264
2.54k
    int trc_tag_size;
1265
2.54k
    unsigned char *buffer;
1266
2.54k
    cmm_profile_t *result;
1267
2.54k
    float *cat02;
1268
2.54k
    float black_adapt[3];
1269
1270
    /* Fill in the common stuff */
1271
2.54k
    setheader_common(header, 4);
1272
2.54k
    header->pcs = icSigXYZData;
1273
2.54k
    profile_size = HEADER_SIZE;
1274
2.54k
    header->deviceClass = icSigInputClass;
1275
2.54k
    if (num_colors == 3) {
1276
2.36k
        header->colorSpace = icSigRgbData;
1277
2.36k
        num_tags = 10;  /* common (2) + rXYZ,gXYZ,bXYZ,rTRC,gTRC,bTRC,bkpt,wtpt */
1278
2.36k
    } else if (num_colors == 1) {
1279
179
        header->colorSpace = icSigGrayData;
1280
179
        num_tags = 5;  /* common (2) + GrayTRC,bkpt,wtpt */
1281
179
        TRC_Tags[0] = icSigGrayTRCTag;
1282
179
    } else {
1283
0
        return NULL;
1284
0
    }
1285
2.54k
    tag_list = (gsicc_tag*) gs_alloc_bytes(memory,
1286
2.54k
                    sizeof(gsicc_tag)*(size_t)num_tags,"gsicc_create_from_cal");
1287
2.54k
    if (tag_list == NULL)
1288
0
        return NULL;
1289
    /* Let us precompute the sizes of everything and all our offsets */
1290
2.54k
    profile_size += TAG_SIZE*num_tags;
1291
2.54k
    profile_size += 4; /* number of tags.... */
1292
2.54k
    last_tag = -1;
1293
2.54k
    init_common_tags(tag_list, num_tags, &last_tag);
1294
2.54k
    if (num_colors == 3) {
1295
2.36k
        init_tag(tag_list, &last_tag, icSigRedColorantTag, XYZPT_SIZE);
1296
2.36k
        init_tag(tag_list, &last_tag, icSigGreenColorantTag, XYZPT_SIZE);
1297
2.36k
        init_tag(tag_list, &last_tag, icSigBlueColorantTag, XYZPT_SIZE);
1298
2.36k
    }
1299
2.54k
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
1300
2.54k
    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.54k
    trc_tag_size = 8;
1303
9.81k
    for (k = 0; k < num_colors; k++) {
1304
7.27k
        init_tag(tag_list, &last_tag, TRC_Tags[k], trc_tag_size);
1305
7.27k
    }
1306
27.0k
    for(k = 0; k < num_tags; k++) {
1307
24.5k
        profile_size += tag_list[k].size;
1308
24.5k
    }
1309
    /* Now we can go ahead and fill our buffer with the data.  Profile
1310
       buffer data is in non-gc memory */
1311
2.54k
    buffer = gs_alloc_bytes(memory->non_gc_memory,
1312
2.54k
                            profile_size, "gsicc_create_from_cal");
1313
2.54k
    if (buffer == NULL) {
1314
0
        gs_free_object(memory, tag_list, "gsicc_create_from_cal");
1315
0
        return NULL;
1316
0
    }
1317
2.54k
    curr_ptr = buffer;
1318
    /* The header */
1319
2.54k
    header->size = profile_size;
1320
2.54k
    copy_header(curr_ptr,header);
1321
2.54k
    curr_ptr += HEADER_SIZE;
1322
    /* Tag table */
1323
2.54k
    copy_tagtable(curr_ptr,tag_list,num_tags);
1324
2.54k
    curr_ptr += TAG_SIZE*num_tags;
1325
2.54k
    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.54k
    add_common_tag_data(curr_ptr, tag_list, 4);
1329
7.62k
    for (k = 0; k< NUMBER_COMMON_TAGS; k++) {
1330
5.08k
        curr_ptr += tag_list[k].size;
1331
5.08k
    }
1332
2.54k
    tag_location = NUMBER_COMMON_TAGS;
1333
1334
    /* Get the cat02 matrix */
1335
2.54k
    cat02 = gsicc_get_cat02_cam(white, memory);
1336
2.54k
    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.54k
    if (num_colors == 3) {
1344
9.45k
        for ( k = 0; k < 3; k++ ) {
1345
7.09k
            float primary[3];
1346
            /* Apply the cat02 matrix to the primaries */
1347
7.09k
            apply_adaption(cat02, &(matrix[k * 3]), &(primary[0]));
1348
7.09k
            get_XYZ_doubletr(temp_XYZ, &(primary[0]));
1349
7.09k
            add_xyzdata(curr_ptr, temp_XYZ);
1350
7.09k
            curr_ptr += tag_list[tag_location].size;
1351
7.09k
            tag_location++;
1352
7.09k
        }
1353
2.36k
    }
1354
    /* White and black points.  WP is D50 */
1355
2.54k
    get_D50(temp_XYZ);
1356
2.54k
    add_xyzdata(curr_ptr,temp_XYZ);
1357
2.54k
    curr_ptr += tag_list[tag_location].size;
1358
2.54k
    tag_location++;
1359
    /* Black point.  Apply cat02*/
1360
2.54k
    apply_adaption(cat02, black, &(black_adapt[0]));
1361
2.54k
    get_XYZ_doubletr(temp_XYZ, &(black_adapt[0]));
1362
2.54k
    add_xyzdata(curr_ptr,temp_XYZ);
1363
2.54k
    curr_ptr += tag_list[tag_location].size;
1364
2.54k
    tag_location++;
1365
    /* Now the gamma values */
1366
9.81k
    for (k = 0; k < num_colors; k++) {
1367
7.27k
        encode_gamma = float2u8Fixed8(gamma[k]);
1368
7.27k
        add_gammadata(curr_ptr, encode_gamma, icSigCurveType);
1369
7.27k
        curr_ptr += tag_list[tag_location].size;
1370
7.27k
        tag_location++;
1371
7.27k
    }
1372
2.54k
    result = gsicc_profile_new(NULL, memory, NULL, 0);
1373
2.54k
    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.54k
    result->buffer = buffer;
1379
2.54k
    result->buffer_size = profile_size;
1380
2.54k
    result->num_comps = num_colors;
1381
2.54k
    if (num_colors == 3) {
1382
2.36k
        result->data_cs = gsRGB;
1383
2.36k
        result->default_match = CAL_RGB;
1384
2.36k
    } else {
1385
179
        result->data_cs = gsGRAY;
1386
179
        result->default_match = CAL_GRAY;
1387
179
    }
1388
    /* Set the hash code  */
1389
2.54k
    gsicc_get_icc_buff_hash(buffer, &(result->hashcode), result->buffer_size);
1390
2.54k
    result->hash_is_valid = true;
1391
    /* Free up the tag list */
1392
2.54k
    gs_free_object(memory, tag_list, "gsicc_create_from_cal");
1393
2.54k
    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.54k
    return result;
1403
2.54k
}
1404
1405
static void
1406
gsicc_create_free_luta2bpart(gs_memory_t *memory, gsicc_lutatob *icc_luta2bparts)
1407
26
{
1408
    /* Note that white_point, black_point and matrix are not allocated but
1409
       are on the local stack */
1410
26
    gs_free_object(memory, icc_luta2bparts->a_curves,
1411
26
                    "gsicc_create_free_luta2bpart");
1412
26
    gs_free_object(memory, icc_luta2bparts->b_curves,
1413
26
                    "gsicc_create_free_luta2bpart");
1414
26
    gs_free_object(memory, icc_luta2bparts->m_curves,
1415
26
                    "gsicc_create_free_luta2bpart");
1416
26
    gs_free_object(memory, icc_luta2bparts->cam,
1417
26
                    "gsicc_create_free_luta2bpart");
1418
26
    if (icc_luta2bparts->clut) {
1419
        /* Note, data_byte is handled externally.  We do not free that member here */
1420
17
        gs_free_object(memory, icc_luta2bparts->clut->data_short,
1421
17
                        "gsicc_create_free_luta2bpart");
1422
17
        gs_free_object(memory, icc_luta2bparts->clut,
1423
17
                        "gsicc_create_free_luta2bpart");
1424
17
    }
1425
26
}
1426
1427
static void
1428
gsicc_create_init_luta2bpart(gsicc_lutatob *icc_luta2bparts)
1429
26
{
1430
26
    icc_luta2bparts->a_curves = NULL;
1431
26
    icc_luta2bparts->b_curves = NULL;
1432
26
    icc_luta2bparts->clut = NULL;
1433
26
    icc_luta2bparts->m_curves = NULL;
1434
26
    icc_luta2bparts->cam = NULL;
1435
26
    icc_luta2bparts->matrix = NULL;
1436
26
    icc_luta2bparts->white_point = NULL;
1437
26
    icc_luta2bparts->black_point = NULL;
1438
26
    icc_luta2bparts->num_in = 0;
1439
26
    icc_luta2bparts->num_out = 0;
1440
26
}
1441
1442
static void
1443
gsicc_create_initialize_clut(gsicc_clut *clut)
1444
17
{
1445
17
    int k;
1446
17
    int64_t entries = 0;
1447
1448
17
    clut->clut_num_entries = entries = clut->clut_dims[0];
1449
1450
17
    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
17
    clut->data_byte =  NULL;
1459
17
    clut->data_short = NULL;
1460
17
}
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
26
{
1468
26
    int num_tags = 5;  /* common (2), AToB0Tag,bkpt, wtpt */
1469
26
    int k;
1470
26
    gsicc_tag *tag_list;
1471
26
    int profile_size, last_tag, tag_location, tag_size;
1472
26
    unsigned char *buffer,*curr_ptr;
1473
26
    icS15Fixed16Number temp_XYZ[3];
1474
26
    gs_vector3 d50;
1475
26
    float *cam;
1476
26
    gs_matrix3 temp_matrix;
1477
26
    float lmn_vector[3],d50_cieA[3];
1478
1479
26
    profile_size = HEADER_SIZE;
1480
26
    tag_list = (gsicc_tag*) gs_alloc_bytes(memory, sizeof(gsicc_tag) * (size_t)num_tags,
1481
26
                                            "create_lutAtoBprofile");
1482
26
    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
26
    profile_size += TAG_SIZE*num_tags;
1487
26
    profile_size += 4; /* number of tags.... */
1488
26
    last_tag = -1;
1489
26
    init_common_tags(tag_list, num_tags, &last_tag);
1490
26
    init_tag(tag_list, &last_tag, icSigMediaWhitePointTag, XYZPT_SIZE);
1491
26
    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
26
    tag_size = getsize_lutAtoBtype(lutatobparts) - DATATYPE_SIZE;
1496
26
    init_tag(tag_list, &last_tag, icSigAToB0Tag, tag_size);
1497
    /* Add all the tag sizes to get the new profile size */
1498
156
    for(k = 0; k < num_tags; k++) {
1499
130
        profile_size += tag_list[k].size;
1500
130
    }
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
26
    buffer = gs_alloc_bytes(memory->non_gc_memory, profile_size,
1505
26
                            "create_lutAtoBprofile");
1506
26
    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
26
    curr_ptr = buffer;
1511
    /* The header */
1512
26
    header->size = profile_size;
1513
26
    copy_header(curr_ptr,header);
1514
26
    curr_ptr += HEADER_SIZE;
1515
    /* Tag table */
1516
26
    copy_tagtable(curr_ptr, tag_list, num_tags);
1517
26
    curr_ptr += TAG_SIZE * num_tags;
1518
26
    curr_ptr += 4;
1519
    /* Now the data.  Must be in same order as we created the tag table */
1520
    /* First the common tags */
1521
26
    add_common_tag_data(curr_ptr, tag_list, 4);
1522
78
    for (k = 0; k< NUMBER_COMMON_TAGS; k++) {
1523
52
        curr_ptr += tag_list[k].size;
1524
52
    }
1525
26
    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
26
    d50.u = D50_X;
1530
26
    d50.v = D50_Y;
1531
26
    d50.w = D50_Z;
1532
26
    cam = (float*) gs_alloc_bytes(memory, 9 * sizeof(float), "create_lutAtoBprofile");
1533
26
    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
26
    gsicc_create_compute_cam(lutatobparts->white_point, &(d50), cam);
1539
26
    gs_free_object(memory, lutatobparts->cam, "create_lutAtoBprofile");
1540
26
    lutatobparts->cam = cam;
1541
26
    get_D50(temp_XYZ); /* See Appendix D6 in spec */
1542
26
    add_xyzdata(curr_ptr, temp_XYZ);
1543
26
    curr_ptr += tag_list[tag_location].size;
1544
26
    tag_location++;
1545
26
    get_XYZ(temp_XYZ, lutatobparts->black_point);
1546
26
    add_xyzdata(curr_ptr, temp_XYZ);
1547
26
    curr_ptr += tag_list[tag_location].size;
1548
26
    tag_location++;
1549
    /* Multiply the matrix in the AtoB object by the cam so that the data
1550
       is in D50 */
1551
26
    if (lutatobparts->matrix == NULL) {
1552
0
        gsicc_create_copy_matrix3(cam, (float*) &temp_matrix);
1553
0
        lutatobparts->matrix = &temp_matrix;
1554
26
    } else {
1555
26
        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
17
            lmn_vector[0] = lutatobparts->matrix->cv.u;
1566
17
            lmn_vector[1] = lutatobparts->matrix->cv.v;
1567
17
            lmn_vector[2] = lutatobparts->matrix->cv.w;
1568
17
            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
17
            } else {
1574
                /* Need to do final scaling to ICC CIEXYZ range */
1575
17
                d50_cieA[0] = (float)(D50_X / (1.0 + (32767.0/32768.0)));
1576
17
                d50_cieA[1] = (float)(D50_Y / (1.0 + (32767.0/32768.0)));
1577
17
                d50_cieA[2] = (float)(D50_Z / (1.0 + (32767.0/32768.0)));
1578
17
            }
1579
17
            matrixmult(&(d50_cieA[0]), 3, 1, &(lmn_vector[0]), 1, 3,
1580
17
                        &(lutatobparts->matrix->cu.u));
1581
17
        } else {
1582
9
            matrixmult(cam, 3, 3, &(lutatobparts->matrix->cu.u), 3, 3,
1583
9
                    &(temp_matrix.cu.u));
1584
9
            lutatobparts->matrix = &temp_matrix;
1585
9
        }
1586
26
    }
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
26
    add_lutAtoBtype(curr_ptr, lutatobparts);
1591
26
    *pp_buffer_in = buffer;
1592
26
    gs_free_object(memory, tag_list, "create_lutAtoBprofile");
1593
26
    return 0;
1594
26
}
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
9
{
1684
9
    gs_matrix3 temp_matrix;
1685
9
    gs_matrix3 *matrix_ptr;
1686
9
    float *curr_pos;
1687
1688
    /* Determine the matrix that we will be using */
1689
9
    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
9
    } else {
1695
        /* Either ABC matrix or LMN matrix is identity */
1696
9
        if (matrixABC->is_identity) {
1697
9
            matrix_ptr = matrixLMN;
1698
9
        } else {
1699
0
            matrix_ptr = matrixABC;
1700
0
        }
1701
9
        cie_matrix_transpose3(matrix_ptr, atob_parts->matrix);
1702
9
    }
1703
    /* Merge the curves */
1704
9
    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
9
    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
9
    } 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
9
        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
9
        if (has_lmn_procs) {
1755
9
            atob_parts->m_curves = (float*) gs_alloc_bytes(memory,
1756
9
                                3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_abc_merge");
1757
9
            if (atob_parts->m_curves == NULL)
1758
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC m curves failed");
1759
9
            curr_pos = atob_parts->m_curves;
1760
9
            memcpy(curr_pos,&(lmn_caches[0].floats.values[0]),CURVE_SIZE*sizeof(float));
1761
9
            curr_pos += CURVE_SIZE;
1762
9
            memcpy(curr_pos,&(lmn_caches[1].floats.values[0]),CURVE_SIZE*sizeof(float));
1763
9
            curr_pos += CURVE_SIZE;
1764
9
            memcpy(curr_pos,&(lmn_caches[2].floats.values[0]),CURVE_SIZE*sizeof(float));
1765
9
        }
1766
9
    }
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
9
    if (atob_parts->b_curves == NULL) {
1774
9
        scale_matrix((float*) atob_parts->matrix, 2.0);
1775
9
    }
1776
9
    return 0;
1777
9
}
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
9
{
1789
9
    icProfile iccprofile;
1790
9
    icHeader  *header = &(iccprofile.header);
1791
#if SAVEICCPROFILE
1792
    int debug_catch = 1;
1793
#endif
1794
9
    int k;
1795
9
    gs_matrix3 matrix_input_trans;
1796
9
    gsicc_lutatob icc_luta2bparts;
1797
9
    float *curr_pos;
1798
9
    bool has_abc_procs = !((abc_caches->floats.params.is_identity &&
1799
9
                         (abc_caches)[1].floats.params.is_identity &&
1800
9
                         (abc_caches)[2].floats.params.is_identity));
1801
9
    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
9
    gs_cie_abc *pcie = pcs->params.abc;
1805
9
    bool input_range_ok;
1806
9
    int code;
1807
1808
9
    gsicc_create_init_luta2bpart(&icc_luta2bparts);
1809
9
    gsicc_matrix_init(&(pcie->common.MatrixLMN));  /* Need this set now */
1810
9
    gsicc_matrix_init(&(pcie->MatrixABC));          /* Need this set now */
1811
    /* Fill in the common stuff */
1812
9
    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
9
    header->colorSpace = icSigRgbData;
1818
9
    header->deviceClass = icSigInputClass;
1819
9
    header->pcs = icSigXYZData;
1820
9
    icc_luta2bparts.num_in = 3;
1821
9
    icc_luta2bparts.num_out = 3;
1822
9
    icc_luta2bparts.white_point = &(pcie->common.points.WhitePoint);
1823
9
    icc_luta2bparts.black_point = &(pcie->common.points.BlackPoint);
1824
1825
    /* Calculate the chromatic adaptation matrix */
1826
9
    code = gsicc_compute_cam(&icc_luta2bparts, memory);
1827
9
    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
9
    *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
9
    input_range_ok = check_range(&(pcie->RangeABC.ranges[0]), 3);
1843
9
    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
9
    } else {
1851
9
        if (pcie->MatrixABC.is_identity || !has_lmn_procs ||
1852
9
                            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
9
            icc_luta2bparts.matrix = &matrix_input_trans;
1856
9
            code = gsicc_create_abc_merge(&(icc_luta2bparts), &(pcie->common.MatrixLMN),
1857
9
                                    &(pcie->MatrixABC), has_abc_procs,
1858
9
                                    has_lmn_procs, pcie->caches.DecodeABC.caches,
1859
9
                                    pcie->common.caches.DecodeLMN, memory);
1860
9
            if (code < 0)
1861
0
                return gs_rethrow(code, "Failed in ICC creation from ABC. Merge");
1862
9
            icc_luta2bparts.clut =  NULL;
1863
            /* Create the profile.  This is for the common generic form we will use
1864
               for almost everything. */
1865
9
            code = create_lutAtoBprofile(pp_buffer_in, header, &icc_luta2bparts, false,
1866
9
                                         false, memory);
1867
9
            if (code < 0)
1868
0
                return gs_rethrow(code, "Failed in ICC creation from ABC. Profile");
1869
9
        } 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
9
    }
1950
9
    gsicc_create_free_luta2bpart(memory, &icc_luta2bparts);
1951
9
    *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
9
    return 0;
1958
9
}
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
17
{
1965
17
    icProfile iccprofile;
1966
17
    icHeader  *header = &(iccprofile.header);
1967
#if SAVEICCPROFILE
1968
    int debug_catch = 1;
1969
#endif
1970
17
    gs_matrix3 matrix_input;
1971
17
    float *curr_pos;
1972
17
    bool has_a_proc = !(a_cache->floats.params.is_identity);
1973
17
    bool has_lmn_procs = !(lmn_caches->floats.params.is_identity &&
1974
9
                         (lmn_caches)[1].floats.params.is_identity &&
1975
9
                         (lmn_caches)[2].floats.params.is_identity);
1976
17
    gsicc_lutatob icc_luta2bparts;
1977
17
    bool common_range_ok;
1978
17
    gs_cie_a *pcie = pcs->params.a;
1979
17
    bool input_range_ok;
1980
17
    int code;
1981
1982
17
    gsicc_create_init_luta2bpart(&icc_luta2bparts);
1983
    /* Fill in the common stuff */
1984
17
    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
17
    header->colorSpace = icSigGrayData;
1989
17
    header->deviceClass = icSigInputClass;
1990
17
    header->pcs = icSigXYZData;
1991
17
    icc_luta2bparts.num_out = 3;
1992
17
    icc_luta2bparts.num_in = 1;
1993
17
    icc_luta2bparts.white_point = &(pcie->common.points.WhitePoint);
1994
17
    icc_luta2bparts.black_point = &(pcie->common.points.BlackPoint);
1995
1996
17
    code = gsicc_compute_cam(&icc_luta2bparts, memory);
1997
17
    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
17
    common_range_ok = check_range(&(pcie->common.RangeLMN.ranges[0]),3);
2007
17
    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
17
    } 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
17
        if (has_a_proc) {
2022
9
            icc_luta2bparts.a_curves = (float*) gs_alloc_bytes(memory,
2023
9
                CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_froma");
2024
9
            if (icc_luta2bparts.a_curves == NULL)
2025
0
                return gs_throw(gs_error_VMerror, "Allocation of ICC a curves failed");
2026
9
            memcpy(icc_luta2bparts.a_curves,
2027
9
                    &(pcie->caches.DecodeA.floats.values[0]),
2028
9
                    CURVE_SIZE*sizeof(float));
2029
9
        }
2030
17
        if (has_lmn_procs) {
2031
8
            icc_luta2bparts.m_curves = (float*) gs_alloc_bytes(memory,
2032
8
                3*CURVE_SIZE*(size_t)sizeof(float),"gsicc_create_froma");
2033
8
            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
8
            curr_pos = icc_luta2bparts.m_curves;
2038
8
            memcpy(curr_pos,&(pcie->common.caches.DecodeLMN->floats.values[0]),
2039
8
                        CURVE_SIZE*sizeof(float));
2040
8
            curr_pos += CURVE_SIZE;
2041
8
            memcpy(curr_pos,&((pcie->common.caches.DecodeLMN[1]).floats.values[0]),
2042
8
                        CURVE_SIZE*sizeof(float));
2043
8
            curr_pos += CURVE_SIZE;
2044
8
            memcpy(curr_pos,&((pcie->common.caches.DecodeLMN[2]).floats.values[0]),
2045
8
                        CURVE_SIZE*sizeof(float));
2046
8
        }
2047
        /* Convert diagonal A matrix to 2x1 MLUT type */
2048
17
        icc_luta2bparts.clut = (gsicc_clut*) gs_alloc_bytes(memory,
2049
17
            sizeof(gsicc_clut),"gsicc_create_froma"); /* 2 grid points 3 outputs */
2050
17
        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
17
        icc_luta2bparts.clut->clut_dims[0] = 2;
2056
17
        icc_luta2bparts.clut->clut_num_input = 1;
2057
17
        icc_luta2bparts.clut->clut_num_output = 3;
2058
17
        icc_luta2bparts.clut->clut_word_width = 2;
2059
17
        gsicc_create_initialize_clut(icc_luta2bparts.clut);
2060
        /* 2 grid points 3 outputs */
2061
17
        icc_luta2bparts.clut->data_short = (unsigned short*)
2062
17
                    gs_alloc_bytes(memory, 2 * 3 * sizeof(short),
2063
17
                   "gsicc_create_froma");
2064
17
        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
17
        gsicc_vec_to_mlut(&(pcie->MatrixA), icc_luta2bparts.clut->data_short);
2078
17
        cie_matrix_transpose3(&(pcie->common.MatrixLMN), &matrix_input);
2079
        /* Encoding to ICC range happens in create_lutAtoBprofile */
2080
17
        icc_luta2bparts.matrix = &matrix_input;
2081
17
        icc_luta2bparts.num_in = 1;
2082
17
        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
17
        code = create_lutAtoBprofile(pp_buffer_in, header, &icc_luta2bparts, true,
2087
17
                                     false, memory);
2088
17
        if (code < 0)
2089
0
            return gs_rethrow(code, "Failed to create ICC AtoB Profile");
2090
17
    }
2091
17
    *profile_size_out = header->size;
2092
17
    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
17
    return 0;
2099
17
}
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
95
{
3156
95
    int out = 0;
3157
95
    byte *ptr = buff;
3158
95
    int k;
3159
3160
475
    for (k = 0; k < 4; k++) {
3161
380
        int temp = ptr[k];
3162
380
        int shift = (3 - k) * 8;
3163
380
        out += temp << shift;
3164
380
    }
3165
95
    return out;
3166
95
}
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
14
{
3289
14
    byte *buffer = &(src_profile->buffer[128]);
3290
14
    int num_tags = readint32(buffer);
3291
14
    int tag_signature = -1;
3292
14
    int offset;
3293
14
    int k;
3294
14
    int buffer_left = src_profile->buffer_size;
3295
3296
14
    if (buffer_left < 128)
3297
0
        return false;
3298
14
    buffer_left -= 128;
3299
3300
14
    if (buffer_left < 4)
3301
0
        return false;
3302
3303
14
    buffer += 4;
3304
14
    buffer_left -= 4;
3305
3306
    /* Get to the tag table */
3307
67
    for (k = 0; k < num_tags; k++) {
3308
67
        if (buffer_left < 12)
3309
0
            return false;
3310
3311
67
        tag_signature = readint32(buffer);
3312
67
        if (tag_signature == icSigMediaWhitePointTag)
3313
14
            break;
3314
53
        buffer += 12;
3315
53
        buffer_left -= 12;
3316
53
    }
3317
14
    if (tag_signature != icSigMediaWhitePointTag)
3318
0
        return false;
3319
3320
14
    if (buffer_left < 4)
3321
0
        return false;
3322
3323
14
    buffer += 4;
3324
14
    buffer_left -= 4;
3325
3326
14
    offset = readint32(buffer);
3327
3328
14
    if (buffer_left < offset + 8 || offset < 0)
3329
14
        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
14
{
3345
14
    icProfile iccprofile;
3346
14
    icHeader *header = &(iccprofile.header);
3347
14
    byte mediawhitept[12];
3348
14
    cmm_profile_t *xyz_profile;
3349
3350
14
    if (src_profile->v2_data != NULL)
3351
0
        return;
3352
3353
    /* Fill in the common stuff */
3354
14
    setheader_common(header, 2);
3355
3356
    /* Get the data_cs of current profile */
3357
14
    switch (src_profile->data_cs) {
3358
3
        case gsGRAY:
3359
3
            header->colorSpace = icSigGrayData;
3360
3
        break;
3361
11
        case gsRGB:
3362
11
            header->colorSpace = icSigRgbData;
3363
11
            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
14
    }
3374
3375
    /* Use the deviceClass from the source profile. */
3376
14
    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
14
    if (!get_mediawp(src_profile, &(mediawhitept[0]))) {
3382
#ifdef DEBUG
3383
        gs_warn("Failed in creating V2 ICC profile");
3384
#endif
3385
14
        return;
3386
14
    }
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.21k
{
3443
1.21k
    if (profile->vers == ICCVERS_UNKNOWN) {
3444
1.20k
        int majorvers = profile->buffer[8];
3445
3446
1.20k
        if (majorvers == 2) {
3447
1.19k
            profile->vers = ICCVERS_2;
3448
1.19k
            return true;
3449
1.19k
        } else {
3450
12
            profile->vers = ICCVERS_NOT2;
3451
12
            return false;
3452
12
        }
3453
1.20k
    }
3454
2
    if (profile->vers == ICCVERS_2)
3455
0
        return true;
3456
2
    else
3457
2
        return false;
3458
2
}
3459
3460
byte*
3461
gsicc_create_getv2buffer(const gs_gstate *pgs, cmm_profile_t *srcprofile,
3462
                        int *size)
3463
1.21k
{
3464
1.21k
    if (gsicc_create_isv2(srcprofile)) {
3465
1.19k
        *size = srcprofile->buffer_size;
3466
1.19k
        return srcprofile->buffer;
3467
1.19k
    }
3468
3469
14
    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
14
    gsicc_create_v2(pgs, srcprofile);
3476
3477
14
    *size = srcprofile->v2_size;
3478
14
    return srcprofile->v2_data;
3479
1.21k
}