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