Coverage Report

Created: 2022-10-31 07:00

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