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