1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2
3 Copyright (C) 2002-2015 by Jin-Hwan Cho and Shunsaku Hirata,
4 the dvipdfmx project team.
5
6 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 /* No page independence here...
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include "system.h"
31 #include "mem.h"
32 #include "error.h"
33
34 #include "dpxfile.h"
35
36 #include "pdfdoc.h"
37 #include "pdfdev.h"
38
39 #include "pdfcolor.h"
40
41 static int verbose = 0;
42 void
pdf_color_set_verbose(void)43 pdf_color_set_verbose (void)
44 {
45 verbose++;
46 }
47
48 /* This function returns PDF_COLORSPACE_TYPE_GRAY,
49 * PDF_COLORSPACE_TYPE_RGB, PDF_COLORSPACE_TYPE_CMYK or
50 * PDF_COLORSPACE_TYPE_SPOT.
51 */
52 int
pdf_color_type(const pdf_color * color)53 pdf_color_type (const pdf_color *color)
54 {
55 ASSERT(color);
56
57 return -color->num_components;
58 }
59
60 int
pdf_color_rgbcolor(pdf_color * color,double r,double g,double b)61 pdf_color_rgbcolor (pdf_color *color, double r, double g, double b)
62 {
63 ASSERT(color);
64
65 if (r < 0.0 || r > 1.0) {
66 WARN("Invalid color value specified: red=%g", r);
67 return -1;
68 }
69 if (g < 0.0 || g > 1.0) {
70 WARN("Invalid color value specified: green=%g", g);
71 return -1;
72 }
73 if (b < 0.0 || b > 1.0) {
74 WARN("Invalid color value specified: blue=%g", b);
75 return -1;
76 }
77 color->values[0] = r;
78 color->values[1] = g;
79 color->values[2] = b;
80
81 color->num_components = 3;
82
83 color->spot_color_name = NULL;
84
85 return 0;
86 }
87
88 int
pdf_color_cmykcolor(pdf_color * color,double c,double m,double y,double k)89 pdf_color_cmykcolor (pdf_color *color,
90 double c, double m, double y, double k)
91 {
92 ASSERT(color);
93
94 if (c < 0.0 || c > 1.0) {
95 WARN("Invalid color value specified: cyan=%g", c);
96 return -1;
97 }
98 if (m < 0.0 || m > 1.0) {
99 WARN("Invalid color value specified: magenta=%g", m);
100 return -1;
101 }
102 if (y < 0.0 || y > 1.0) {
103 WARN("Invalid color value specified: yellow=%g", y);
104 return -1;
105 }
106 if (k < 0.0 || k > 1.0) {
107 WARN("Invalid color value specified: black=%g", k);
108 return -1;
109 }
110
111 color->values[0] = c;
112 color->values[1] = m;
113 color->values[2] = y;
114 color->values[3] = k;
115
116 color->num_components = 4;
117
118 color->spot_color_name = NULL;
119
120 return 0;
121 }
122
123 int
pdf_color_graycolor(pdf_color * color,double g)124 pdf_color_graycolor (pdf_color *color, double g)
125 {
126 ASSERT(color);
127
128 if (g < 0.0 || g > 1.0) {
129 WARN("Invalid color value specified: gray=%g", g);
130 return -1;
131 }
132
133 color->values[0] = g;
134
135 color->num_components = 1;
136
137 color->spot_color_name = NULL;
138
139 return 0;
140 }
141
142 int
pdf_color_spotcolor(pdf_color * color,char * name,double c)143 pdf_color_spotcolor (pdf_color *color, char* name, double c)
144 {
145 ASSERT(color);
146
147 if (c < 0.0 || c > 1.0) {
148 WARN("Invalid color value specified: grade=%g", c);
149 return -1;
150 }
151
152 color->values[0] = c;
153 color->values[1] = 0.0; /* Dummy */
154
155 color->num_components = 2;
156
157 color->spot_color_name = name;
158
159 return 0;
160 }
161
162
163 void
pdf_color_copycolor(pdf_color * color1,const pdf_color * color2)164 pdf_color_copycolor (pdf_color *color1, const pdf_color *color2)
165 {
166 ASSERT(color1 && color2);
167
168 memcpy(color1, color2, sizeof(pdf_color));
169 }
170
171 /* Brighten up a color. f == 0 means no change, f == 1 means white. */
172 void
pdf_color_brighten_color(pdf_color * dst,const pdf_color * src,double f)173 pdf_color_brighten_color (pdf_color *dst, const pdf_color *src, double f)
174 {
175 ASSERT(dst && src);
176
177 if (f == 1.0) {
178 pdf_color_white(dst);
179 } else {
180 double f0, f1;
181 int n;
182
183 n = dst->num_components = src->num_components;
184 f1 = n == 4 ? 0.0 : f; /* n == 4 is CMYK, others are RGB and Gray */
185 f0 = 1.0-f;
186
187 while (n--)
188 dst->values[n] = f0 * src->values[n] + f1;
189 }
190 }
191
192 int
pdf_color_is_white(const pdf_color * color)193 pdf_color_is_white (const pdf_color *color)
194 {
195 int n;
196 double f;
197
198 ASSERT(color);
199
200 n = color->num_components;
201 switch (n) {
202 case 1: /* Gray */
203 case 3: /* RGB */
204 f = 1.0;
205 break;
206 case 4: /* CMYK */
207 f = 0.0;
208 break;
209 default:
210 return 0;
211 }
212
213 while (n--)
214 if (color->values[n] != f)
215 return 0;
216
217 return 1;
218 }
219
220 int
pdf_color_to_string(const pdf_color * color,char * buffer,char mask)221 pdf_color_to_string (const pdf_color *color, char *buffer, char mask)
222 {
223 int i, len = 0;
224
225 if (pdf_color_type(color) == PDF_COLORSPACE_TYPE_SPOT) {
226 len = sprintf(buffer, " /%s %c%c %g %c%c",
227 color->spot_color_name,
228 'C' | mask, 'S' | mask,
229 ROUND(color->values[0], 0.001),
230 'S' | mask, 'C' | mask);
231 } else {
232 for (i = 0; i < color->num_components; i++) {
233 len += sprintf(buffer+len, " %g", ROUND(color->values[i], 0.001));
234 }
235 }
236
237 return len;
238 }
239
240 pdf_color current_fill = {
241 1,
242 NULL,
243 {0.0, 0.0, 0.0, 0.0}
244 };
245
246 pdf_color current_stroke = {
247 1,
248 NULL,
249 {0.0, 0.0, 0.0, 0.0}
250 };
251
252 /*
253 * This routine is not a real color matching.
254 */
255 int
pdf_color_compare(const pdf_color * color1,const pdf_color * color2)256 pdf_color_compare (const pdf_color *color1, const pdf_color *color2)
257 {
258 int n;
259
260 n = color1->num_components;
261 switch (n) {
262 case 1: /* Gray */
263 case 2: /* Spot */
264 case 3: /* RGB */
265 case 4: /* CMYK */
266 break;
267 default:
268 return -1;
269 }
270
271 if (n != color2->num_components)
272 return -1;
273
274 while (n--)
275 if (color1->values[n] != color2->values[n])
276 return -1;
277
278 if (color1->spot_color_name && color2->spot_color_name)
279 return strcmp(color1->spot_color_name, color2->spot_color_name);
280
281 return 0;
282 }
283
284 int
pdf_color_is_valid(const pdf_color * color)285 pdf_color_is_valid (const pdf_color *color)
286 {
287 int n;
288
289 n = color->num_components;
290 switch (n) {
291 case 1: /* Gray */
292 case 2: /* Spot */
293 case 3: /* RGB */
294 case 4: /* CMYK */
295 break;
296 default:
297 return 0;
298 }
299
300 while (n--)
301 if (color->values[n] < 0.0 || color->values[n] > 1.0) {
302 WARN("Invalid color value: %g", color->values[n]);
303 return 0;
304 }
305
306 if (pdf_color_type(color) == PDF_COLORSPACE_TYPE_SPOT) {
307 if (!color->spot_color_name || color->spot_color_name[0] == '\0') {
308 WARN("Invalid spot color: empty name");
309 return 0;
310 }
311 }
312
313 return 1;
314 }
315
316 /* Dvipdfm special */
317 pdf_color default_color = {
318 1,
319 NULL,
320 {0.0, 0.0, 0.0, 0.0}
321 };
322
323 void
pdf_color_set_default(const pdf_color * color)324 pdf_color_set_default (const pdf_color *color)
325 {
326 pdf_color_copycolor(&default_color, color);
327 }
328
329 #define DEV_COLOR_STACK_MAX 128
330
331 static struct {
332 int current;
333 pdf_color stroke[DEV_COLOR_STACK_MAX];
334 pdf_color fill[DEV_COLOR_STACK_MAX];
335 } color_stack = {
336 0,
337 };
338
339 void
pdf_color_clear_stack(void)340 pdf_color_clear_stack (void)
341 {
342 if (color_stack.current > 0) {
343 WARN("You've mistakenly made a global color change within nested colors.");
344 }
345 while (color_stack.current--) {
346 free(color_stack.stroke[color_stack.current].spot_color_name);
347 free(color_stack.fill[color_stack.current].spot_color_name);
348 }
349 color_stack.current = 0;
350 pdf_color_black(color_stack.stroke);
351 pdf_color_black(color_stack.fill);
352 return;
353 }
354
355 void
pdf_color_set(pdf_color * sc,pdf_color * fc)356 pdf_color_set (pdf_color *sc, pdf_color *fc)
357 {
358 pdf_color_copycolor(&color_stack.stroke[color_stack.current], sc);
359 pdf_color_copycolor(&color_stack.fill[color_stack.current], fc);
360 pdf_dev_reset_color(0);
361 }
362
363 void
pdf_color_push(pdf_color * sc,pdf_color * fc)364 pdf_color_push (pdf_color *sc, pdf_color *fc)
365 {
366 if (color_stack.current >= DEV_COLOR_STACK_MAX-1) {
367 WARN("Color stack overflow. Just ignore.");
368 } else {
369 color_stack.current++;
370 pdf_color_set(sc, fc);
371 }
372 return;
373 }
374
375 void
pdf_color_pop(void)376 pdf_color_pop (void)
377 {
378 if (color_stack.current <= 0) {
379 WARN("Color stack underflow. Just ignore.");
380 } else {
381 color_stack.current--;
382 pdf_dev_reset_color(0);
383 }
384 return;
385 }
386
387 void
pdf_color_get_current(pdf_color ** sc,pdf_color ** fc)388 pdf_color_get_current (pdf_color **sc, pdf_color **fc)
389 {
390 *sc = &color_stack.stroke[color_stack.current];
391 *fc = &color_stack.fill[color_stack.current];
392 return;
393 }
394
395 #if 0
396 /* BUG (20060330): color change does not effect on the next page.
397 * The problem is due to the part of grestore because it restores
398 * the color values in the state of gsave which are not correct
399 * if the color values are changed inside of a page.
400 */
401 void
402 pdf_dev_preserve_color (void)
403 {
404 if (color_stack.current > 0) {
405 current_stroke = color_stack.stroke[color_stack.current];
406 current_fill = color_stack.fill[color_stack.current];
407 }
408 }
409 #endif
410
411 /***************************** COLOR SPACE *****************************/
412
413 static int pdf_colorspace_defineresource (const char *ident,
414 int subtype,
415 void *cdata, pdf_obj *resource);
416
417 static int pdf_colorspace_findresource (const char *ident,
418 int subtype, const void *cdata);
419
420 #if 0
421 struct calgray_cdata
422 {
423 double white_point[3]; /* required, second component must
424 * be equal to 1.0
425 */
426 double black_point[3]; /* optional, default: [0 0 0] */
427 double gamma; /* optional, default: 1.0 */
428 };
429
430 struct calrgb_cdata
431 {
432 double white_point[3]; /* required, second component must
433 * be equal to 1.0
434 */
435 double black_point[3]; /* optional, default: [0 0 0] */
436 double gamma[3]; /* optional, default: [1 1 1] */
437 double matrix[9]; /* optional, default: identity
438 * [1 0 0 0 1 0 0 0 1]
439 */
440 };
441
442 static void
443 release_calrgb (void *cdata)
444 {
445 struct calrgb_cdata *calrgb;
446
447 if (cdata) {
448 calrgb = (struct calrgb_cdata *) cdata;
449 RELEASE(calrgb);
450 }
451 }
452
453 static int
454 compare_calrgb (const char *ident1, const void *cdata1,
455 const char *ident2, const void *cdata2)
456 {
457 struct calrgb_cdata *calrgb1;
458 struct calrgb_cdata *calrgb2;
459
460 if (ident1 && ident2 &&
461 !strcmp(ident1, ident2)) {
462 return 0;
463 }
464 }
465
466 static void
467 init_calrgb (struct calrgb_cdata *calrgb)
468 {
469 ASSERT(calrgb);
470
471 calrgb->white_point[0] = 1.0;
472 calrgb->white_point[1] = 1.0;
473 calrgb->white_point[2] = 1.0;
474
475 calrgb->black_point[0] = 0.0;
476 calrgb->black_point[1] = 0.0;
477 calrgb->black_point[2] = 0.0;
478
479 calrgb->gamma[0] = 1.0;
480 calrgb->gamma[1] = 1.0;
481 calrgb->gamma[2] = 1.0;
482
483 calrgb->matrix[0] = 1.0;
484 calrgb->matrix[1] = 0.0;
485 calrgb->matrix[2] = 0.0;
486
487 calrgb->matrix[3] = 0.0;
488 calrgb->matrix[4] = 1.0;
489 calrgb->matrix[5] = 0.0;
490
491 calrgb->matrix[6] = 0.0;
492 calrgb->matrix[7] = 0.0;
493 calrgb->matrix[8] = 1.0;
494 }
495
496 static int
497 valid_calrgb (struct calrgb_cdata *calrgb)
498 {
499 if (calrgb->white_point[1] != 1.0 ||
500 calrgb->white_point[0] <= 0.0 ||
501 calrgb->white_point[2] <= 0.0)
502 return 0;
503
504 if (calrgb->black_point[0] < 0.0 ||
505 calrgb->black_point[1] < 0.0 ||
506 calrgb->black_point[2] < 0.0)
507 return 0;
508
509 if (calrgb->gamma[0] < 0.0 ||
510 calrgb->gamma[1] < 0.0 ||
511 calrgb->gamma[2] < 0.0)
512 return 0;
513
514 /* matrix should be invertible? */
515
516 return 1;
517 }
518
519 static pdf_obj *
520 pdf_color_make_calrgb_resource (struct calrgb_cdata *calrgb)
521 {
522 pdf_obj *colorspace;
523 pdf_obj *calparams, *tmp_array;
524
525 ASSERT(calrgb);
526
527 if (!valid_calrgb(calrgb))
528 return NULL;
529
530 colorspace = pdf_new_array();
531 calparams = pdf_new_dict();
532
533 tmp_array = pdf_new_array();
534 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->white_point[0], 0.001)));
535 pdf_add_array(tmp_array, pdf_new_number(1.0));
536 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->white_point[2], 0.001)));
537 pdf_add_dict(calparams, pdf_new_name("WhitePoint"), tmp_array);
538
539 if (calrgb->black_point[0] != 0.0 ||
540 calrgb->black_point[1] != 0.0 ||
541 calrgb->black_point[2] != 0.0) {
542 tmp_array = pdf_new_array();
543 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[0], 0.001)));
544 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[1], 0.001)));
545 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[2], 0.001)));
546 pdf_add_dict(calparams, pdf_new_name("BlackPoint"), tmp_array);
547 }
548
549 if (calrgb->gamma[0] != 1.0 ||
550 calrgb->gamma[1] != 1.0 ||
551 calrgb->gamma[2] != 1.0) {
552 tmp_array = pdf_new_array();
553 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[0], 0.001)));
554 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[1], 0.001)));
555 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[2], 0.001)));
556 pdf_add_dict(calparams, pdf_new_name("Gamma"), tmp_array);
557 }
558
559 if (calrgb->matrix[0] != 1.0 ||
560 calrgb->matrix[1] != 0.0 ||
561 calrgb->matrix[2] != 0.0 ||
562 calrgb->matrix[3] != 0.0 ||
563 calrgb->matrix[4] != 1.0 ||
564 calrgb->matrix[5] != 0.0 ||
565 calrgb->matrix[6] != 0.0 ||
566 calrgb->matrix[7] != 0.0 ||
567 calrgb->matrix[8] != 1.0) {
568 tmp_array = pdf_new_array();
569 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[0], 0.001)));
570 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[1], 0.001)));
571 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[2], 0.001)));
572 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[3], 0.001)));
573 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[4], 0.001)));
574 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[5], 0.001)));
575 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[6], 0.001)));
576 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[7], 0.001)));
577 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[8], 0.001)));
578 pdf_add_dict(calparams, pdf_new_name("Matrix"), tmp_array);
579 }
580
581 pdf_add_array(colorspace, pdf_new_name("CalRGB"));
582 pdf_add_array(colorspace, calparams);
583
584 return colorspace;
585 }
586 #endif
587
588 static unsigned char nullbytes16[16] = {
589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
590 };
591
592 static struct
593 {
594 int major;
595 int minor;
596 } icc_versions[] = {
597 {0, 0}, /* PDF-1.0, we don't support them */
598 {0, 0}, /* PDF-1.1, we don't support them */
599 {0, 0}, /* PDF-1.2, we don't support them */
600 {0x02, 0x10}, /* PDF-1.3 */
601 {0x02, 0x20}, /* PDF-1.4 */
602 {0x04, 0x00}, /* PDF-1.5 */
603 {0x04, 0x00}, /* PDF-1.6 */
604 {0x04, 0x20}, /* PDF-1.7 */
605 };
606
607 static int
iccp_version_supported(int major,int minor)608 iccp_version_supported (int major, int minor)
609 {
610 int pdf_ver;
611
612 pdf_ver = pdf_get_version();
613 if (pdf_ver < 8) {
614 if (icc_versions[pdf_ver].major < major)
615 return 0;
616 else if (icc_versions[pdf_ver].major == major &&
617 icc_versions[pdf_ver].minor < minor)
618 return 0;
619 else {
620 return 1;
621 }
622 }
623
624 return 0;
625 }
626
627 typedef unsigned long iccSig;
628 static iccSig
str2iccSig(const void * s)629 str2iccSig (const void *s)
630 {
631 const char *p;
632
633 p = (const char *) s;
634
635 return (iccSig) ((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]);
636 }
637
638 typedef struct
639 {
640 long X, Y, Z; /* s15Fixed16Numeber */
641 } iccXYZNumber;
642
643 typedef struct
644 {
645 long size;
646 iccSig CMMType;
647 long version;
648 iccSig devClass;
649 iccSig colorSpace;
650 iccSig PCS; /* Profile Connection Space */
651 char creationDate[12];
652 iccSig acsp;
653 iccSig platform;
654 char flags[4];
655 iccSig devMnfct;
656 iccSig devModel;
657 char devAttr[8];
658 long intent;
659 iccXYZNumber illuminant;
660 iccSig creator;
661 unsigned char ID[16]; /* MD5 checksum with Rendering intent,
662 * Header attrs, Profile ID fields are
663 * set to zeros.
664 */
665 /* 28 bytes reserved - must be set to zeros */
666 } iccHeader;
667
668 #define iccNullSig 0
669 static void
iccp_init_iccHeader(iccHeader * icch)670 iccp_init_iccHeader (iccHeader *icch)
671 {
672 ASSERT(icch);
673
674 icch->size = 0;
675 icch->CMMType = iccNullSig;
676 icch->version = 0xFFFFFF;
677 icch->devClass = iccNullSig;
678 icch->colorSpace = iccNullSig;
679 icch->PCS = iccNullSig;
680 memset(icch->creationDate, 0, 12);
681 icch->acsp = str2iccSig("ascp");
682 icch->platform = iccNullSig;
683 memset(icch->flags, 0, 4);
684 icch->devMnfct = iccNullSig;
685 icch->devModel = iccNullSig;
686 memset(icch->devAttr, 0, 8);
687 icch->intent = 0;
688 icch->illuminant.X = 0;
689 icch->illuminant.Y = 0;
690 icch->illuminant.Z = 0;
691 icch->creator = iccNullSig;
692 memset(icch->ID, 0, 16);
693 }
694
695 #define ICC_INTENT_TYPE(n) ((int) (((n) >> 16) & 0xff))
696 #define ICC_INTENT_PERCEPTUAL 0
697 #define ICC_INTENT_RELATIVE 1
698 #define ICC_INTENT_SATURATION 2
699 #define ICC_INTENT_ABSOLUTE 3
700
701 /*
702 * In ICC profile stream dicrionary, there is /Range whose values must
703 * "match the information in the profile". But where is those values in?
704 *
705 * How should I treat rendering intent?
706 */
707 struct iccbased_cdata
708 {
709 long sig; /* 'i' 'c' 'c' 'b' */
710
711 unsigned char checksum[16]; /* 16 bytes MD5 Checksum */
712 int colorspace; /* input colorspace:
713 * RGB, Gray, CMYK, (Lab?)
714 */
715 int alternate; /* alternate colorspace (id), unused */
716 };
717
718 #define check_sig(d,p,q,r,s) ((d) && (d)->sig == ((p)<<24|(q)<<16|(r)<<8|(s)))
719
720 static void
init_iccbased_cdata(struct iccbased_cdata * cdata)721 init_iccbased_cdata (struct iccbased_cdata *cdata)
722 {
723 ASSERT(cdata);
724
725 cdata->sig = ('i' << 24|'c' << 16|'c' << 8|'b');
726 memset(cdata->checksum, 0, 16);
727 cdata->colorspace = PDF_COLORSPACE_TYPE_INVALID;
728 cdata->alternate = -1;
729
730 return;
731 }
732
733 static void
release_iccbased_cdata(struct iccbased_cdata * cdata)734 release_iccbased_cdata (struct iccbased_cdata *cdata)
735 {
736 ASSERT(check_sig(cdata, 'i', 'c', 'c', 'b'));
737
738 RELEASE(cdata);
739 }
740
741 static int
get_num_components_iccbased(const struct iccbased_cdata * cdata)742 get_num_components_iccbased (const struct iccbased_cdata *cdata)
743 {
744 int num_components = 0;
745
746 ASSERT(check_sig(cdata, 'i', 'c', 'c', 'b'));
747
748 switch (cdata->colorspace) {
749 case PDF_COLORSPACE_TYPE_RGB:
750 num_components = 3;
751 break;
752 case PDF_COLORSPACE_TYPE_CMYK:
753 num_components = 4;
754 break;
755 case PDF_COLORSPACE_TYPE_GRAY:
756 num_components = 1;
757 break;
758 case PDF_COLORSPACE_TYPE_CIELAB:
759 num_components = 3;
760 break;
761 }
762
763 return num_components;
764 }
765
766 static int
compare_iccbased(const char * ident1,const struct iccbased_cdata * cdata1,const char * ident2,const struct iccbased_cdata * cdata2)767 compare_iccbased (const char *ident1, const struct iccbased_cdata *cdata1,
768 const char *ident2, const struct iccbased_cdata *cdata2)
769 {
770 if (cdata1 && cdata2) {
771
772 ASSERT(check_sig(cdata1, 'i', 'c', 'c', 'b'));
773 ASSERT(check_sig(cdata2, 'i', 'c', 'c', 'b'));
774
775 if (memcmp(cdata1->checksum, nullbytes16, 16) &&
776 memcmp(cdata2->checksum, nullbytes16, 16)) {
777 return memcmp(cdata1->checksum, cdata2->checksum, 16);
778 }
779 if (cdata1->colorspace != cdata2->colorspace) {
780 return (cdata1->colorspace - cdata2->colorspace);
781 }
782
783 /* Continue if checksum unknown and colorspace is same. */
784 }
785
786 if (ident1 && ident2)
787 return strcmp(ident1, ident2);
788
789 /* No way to compare */
790 return -1;
791 }
792
793 int
iccp_check_colorspace(int colortype,const void * profile,long proflen)794 iccp_check_colorspace (int colortype, const void *profile, long proflen)
795 {
796 iccSig colorspace;
797 const unsigned char *p;
798
799 if (!profile || proflen < 128)
800 return -1;
801
802 p = (const unsigned char *) profile;
803
804 colorspace = str2iccSig(p + 16);
805
806 switch (colortype) {
807 case PDF_COLORSPACE_TYPE_CALRGB:
808 case PDF_COLORSPACE_TYPE_RGB:
809 if (colorspace != str2iccSig("RGB ")) {
810 return -1;
811 }
812 break;
813 case PDF_COLORSPACE_TYPE_CALGRAY:
814 case PDF_COLORSPACE_TYPE_GRAY:
815 if (colorspace != str2iccSig("GRAY")) {
816 return -1;
817 }
818 break;
819 case PDF_COLORSPACE_TYPE_CMYK:
820 if (colorspace != str2iccSig("CMYK")) {
821 return -1;
822 }
823 break;
824 default:
825 return -1;
826 }
827
828 return 0;
829 }
830
831 pdf_obj *
iccp_get_rendering_intent(const void * profile,long proflen)832 iccp_get_rendering_intent (const void *profile, long proflen)
833 {
834 pdf_obj *ri = NULL;
835 const unsigned char *p;
836 long intent;
837
838 if (!profile || proflen < 128)
839 return NULL;
840
841 p = (const unsigned char *) profile;
842
843 intent = (p[64] << 24)|(p[65] << 16)|(p[66] << 8)|p[67];
844 switch (ICC_INTENT_TYPE(intent)) {
845 case ICC_INTENT_SATURATION:
846 ri = pdf_new_name("Saturation");
847 break;
848 case ICC_INTENT_PERCEPTUAL:
849 ri = pdf_new_name("Perceptual");
850 break;
851 case ICC_INTENT_ABSOLUTE:
852 ri = pdf_new_name("AbsoluteColorimetric");
853 break;
854 case ICC_INTENT_RELATIVE:
855 ri = pdf_new_name("RelativeColorimetric");
856 break;
857 default:
858 WARN("Invalid rendering intent type: %d", ICC_INTENT_TYPE(intent));
859 ri = NULL;
860 }
861
862 return ri;
863 }
864
865 #define sget_signed_long(p) ((long) ((p)[0] << 24|(p)[1] << 16|(p)[2] << 8|(p)[3]))
866 #define sget_signed_short(p) ((short) ((p)[0] << 8|(p)[1]))
867 #define get_iccSig(p) ((iccSig) ((p)[0] << 24|(p)[1] << 16|(p)[2] << 8|(p)[3]))
868
869 static int
iccp_unpack_header(iccHeader * icch,const void * profile,long proflen,int check_size)870 iccp_unpack_header (iccHeader *icch,
871 const void *profile, long proflen, int check_size)
872 {
873 const unsigned char *p, *endptr;
874
875 if (check_size) {
876 if (!profile || proflen < 128 ||
877 proflen % 4 != 0) {
878 WARN("Profile size: %ld", proflen);
879 return -1;
880 }
881 }
882
883 p = (const unsigned char *) profile;
884 endptr = p + 128;
885
886 icch->size = sget_signed_long(p);
887 if (check_size) {
888 if (icch->size != proflen) {
889 WARN("ICC Profile size: %ld(header) != %ld", icch->size, proflen);
890 return -1;
891 }
892 }
893 p += 4;
894
895 icch->CMMType = str2iccSig(p);
896 p += 4;
897 icch->version = sget_signed_long(p);
898 p += 4;
899 icch->devClass = str2iccSig(p);
900 p += 4;
901 icch->colorSpace = str2iccSig(p);
902 p += 4;
903 icch->PCS = str2iccSig(p);
904 p += 4;
905 memcpy(icch->creationDate, p, 12);
906 p += 12;
907 icch->acsp = str2iccSig(p); /* acsp */
908 if (icch->acsp != str2iccSig("acsp")) {
909 WARN("Invalid ICC profile: not \"acsp\" - %c%c%c%c ",
910 p[0], p[1], p[2], p[3]);
911 return -1;
912 }
913 p += 4;
914 icch->platform = str2iccSig(p);
915 p += 4;
916 memcpy(icch->flags, p, 4);
917 p += 4;
918 icch->devMnfct = str2iccSig(p);
919 p += 4;
920 icch->devModel = str2iccSig(p);
921 p += 4;
922 memcpy(icch->devAttr, p, 8);
923 p += 8;
924 icch->intent = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
925 p += 4;
926 icch->illuminant.X = sget_signed_long(p);
927 p += 4;
928 icch->illuminant.Y = sget_signed_long(p);
929 p += 4;
930 icch->illuminant.Z = sget_signed_long(p);
931 p += 4;
932 icch->creator = str2iccSig(p);
933 p += 4;
934 memcpy(icch->ID, p, 16);
935 p += 16;
936
937 /* 28 bytes reserved - must be set to zeros */
938 for (; p < endptr; p++) {
939 if (*p != '\0') {
940 WARN("Reserved pad not zero: %02x (at offset %ld in ICC profile header.)",
941 *p, 128 - ((long) (endptr - p)));
942 return -1;
943 }
944 }
945
946 return 0;
947 }
948
949 /* MD5 checksum with Rendering intent,
950 * Header attrs, Profile ID fields are
951 * set to zeros.
952 */
953 #define ICC_HEAD_SECT1_START 0
954 #define ICC_HEAD_SECT1_LENGTH 56
955 /* 8 bytes devAttr, 4 bytes intent */
956 #define ICC_HEAD_SECT2_START 68
957 #define ICC_HEAD_SECT2_LENGTH 16
958 /* 16 bytes ID (checksum) */
959 #define ICC_HEAD_SECT3_START 100
960 #define ICC_HEAD_SECT3_LENGTH 28
961
962 #include "dpxcrypt.h"
963 static void
iccp_get_checksum(unsigned char * checksum,const void * profile,long proflen)964 iccp_get_checksum (unsigned char *checksum, const void *profile, long proflen)
965 {
966 const unsigned char *p;
967 MD5_CONTEXT md5;
968
969 p = (const unsigned char *) profile;
970
971 MD5_init (&md5);
972 MD5_write(&md5, p + ICC_HEAD_SECT1_START, ICC_HEAD_SECT1_LENGTH);
973 MD5_write(&md5, nullbytes16, 12);
974 MD5_write(&md5, p + ICC_HEAD_SECT2_START, ICC_HEAD_SECT2_LENGTH);
975 MD5_write(&md5, nullbytes16, 16);
976 MD5_write(&md5, p + ICC_HEAD_SECT3_START, ICC_HEAD_SECT3_LENGTH);
977
978 /* body */
979 MD5_write(&md5, p + 128, proflen - 128);
980
981 MD5_final(checksum, &md5);
982 }
983
984 static void
print_iccp_header(iccHeader * icch,unsigned char * checksum)985 print_iccp_header (iccHeader *icch, unsigned char *checksum)
986 {
987 int i;
988
989 ASSERT(icch);
990
991 #define print_iccSig(s,t) if ((s) == 0) {\
992 MESG("pdf_color>> %s:\t(null)\n", (t)); \
993 } else if (!isprint(((s) >> 24) & 0xff) || \
994 !isprint(((s) >> 16) & 0xff) || \
995 !isprint(((s) >> 8) & 0xff) || \
996 !isprint((s) & 0xff)) { \
997 MESG("pdf_color>> %s:\t(invalid)\n", (t)); \
998 } else { \
999 MESG("pdf_color>> %s:\t%c%c%c%c\n", (t), \
1000 ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, \
1001 ((s) >> 8) & 0xff, (s) & 0xff); \
1002 }
1003
1004 MESG("\n");
1005 MESG("pdf_color>> ICC Profile Info\n");
1006 MESG("pdf_color>> Profile Size:\t%ld bytes\n", icch->size);
1007 print_iccSig(icch->CMMType, "CMM Type");
1008 MESG("pdf_color>> Profile Version:\t%d.%01d.%01d\n",
1009 (icch->version >> 24) & 0xff,
1010 (icch->version >> 20) & 0x0f,
1011 (icch->version >> 16) & 0x0f);
1012 print_iccSig(icch->devClass, "Device Class");
1013 print_iccSig(icch->colorSpace, "Color Space");
1014 print_iccSig(icch->PCS, "Connection Space");
1015 MESG("pdf_color>> Creation Date:\t");
1016 for (i = 0; i < 12; i += 2) {
1017 if (i == 0)
1018 MESG("%04u",
1019 sget_unsigned_pair((unsigned char *) icch->creationDate));
1020 else {
1021 MESG(":%02u",
1022 sget_unsigned_pair((unsigned char *) (&icch->creationDate[i])));
1023 }
1024 }
1025 MESG("\n");
1026 print_iccSig(icch->platform, "Primary Platform");
1027 MESG("pdf_color>> Profile Flags:\t%02x:%02x:%02x:%02x\n",
1028 icch->flags[0], icch->flags[1], icch->flags[2], icch->flags[3]);
1029 print_iccSig(icch->devMnfct, "Device Mnfct");
1030 print_iccSig(icch->devModel, "Device Model");
1031 MESG("pdf_color>> Device Attr:\t");
1032 for (i = 0; i < 8; i++) {
1033 if (i == 0)
1034 MESG("%02x", icch->devAttr[i]);
1035 else
1036 MESG(":%02x", icch->devAttr[i]);
1037 }
1038 MESG("\n");
1039 MESG("pdf_color>> Rendering Intent:\t");
1040 switch (ICC_INTENT_TYPE(icch->intent)) {
1041 case ICC_INTENT_SATURATION:
1042 MESG("Saturation");
1043 break;
1044 case ICC_INTENT_PERCEPTUAL:
1045 MESG("Perceptual");
1046 break;
1047 case ICC_INTENT_ABSOLUTE:
1048 MESG("Absolute Colorimetric");
1049 break;
1050 case ICC_INTENT_RELATIVE:
1051 MESG("Relative Colorimetric");
1052 break;
1053 default:
1054 MESG("(invalid)");
1055 break;
1056 }
1057 MESG("\n");
1058 print_iccSig(icch->creator, "Creator");
1059 MESG("pdf_color>> Illuminant (XYZ):\t");
1060 MESG("%.3f %.3f %.3f\n",
1061 (double) icch->illuminant.X / 0x10000,
1062 (double) icch->illuminant.Y / 0x10000,
1063 (double) icch->illuminant.Z / 0x10000);
1064 MESG("pdf_color>> Checksum:\t");
1065 if (!memcmp(icch->ID, nullbytes16, 16)) {
1066 MESG("(null)");
1067 } else {
1068 for (i = 0; i < 16; i++) {
1069 if (i == 0)
1070 MESG("%02x", icch->ID[i]);
1071 else
1072 MESG(":%02x", icch->ID[i]);
1073 }
1074 }
1075 MESG("\n");
1076 if (checksum) {
1077 MESG("pdf_color>> Calculated:\t");
1078 for (i = 0; i < 16; i++) {
1079 if (i == 0)
1080 MESG("%02x", checksum[i]);
1081 else
1082 MESG(":%02x", checksum[i]);
1083 }
1084 MESG("\n");
1085 }
1086
1087 return;
1088 }
1089
1090
1091 static int
iccp_devClass_allowed(int dev_class)1092 iccp_devClass_allowed (int dev_class)
1093 {
1094 int colormode;
1095
1096 colormode = pdf_dev_get_param(PDF_DEV_PARAM_COLORMODE);
1097
1098 switch (colormode) {
1099 #if 0
1100 case PDF_DEV_COLORMODE_PDFX1:
1101 break;
1102 case PDF_DEV_COLORMODE_PDFX3:
1103 if (dev_class != str2iccSig("prtr")) {
1104 return 0;
1105 }
1106 break;
1107 #endif
1108 default:
1109 if (dev_class != str2iccSig("scnr") &&
1110 dev_class != str2iccSig("mntr") &&
1111 dev_class != str2iccSig("prtr") &&
1112 dev_class != str2iccSig("spac")) {
1113 return 0;
1114 }
1115 break;
1116 }
1117
1118
1119 return 1;
1120 }
1121
1122 int
iccp_load_profile(const char * ident,const void * profile,long proflen)1123 iccp_load_profile (const char *ident,
1124 const void *profile, long proflen)
1125 {
1126 int cspc_id;
1127 pdf_obj *resource;
1128 pdf_obj *stream;
1129 pdf_obj *stream_dict;
1130 iccHeader icch;
1131 int colorspace;
1132 unsigned char checksum[16];
1133 struct iccbased_cdata *cdata;
1134
1135 iccp_init_iccHeader(&icch);
1136 if (iccp_unpack_header(&icch, profile, proflen, 1) < 0) { /* check size */
1137 WARN("Invalid ICC profile header in \"%s\"", ident);
1138 print_iccp_header(&icch, NULL);
1139 return -1;
1140 }
1141
1142 if (!iccp_version_supported((icch.version >> 24) & 0xff,
1143 (icch.version >> 16) & 0xff)) {
1144 WARN("ICC profile format spec. version %d.%01d.%01d"
1145 " not supported in current PDF version setting.",
1146 (icch.version >> 24) & 0xff,
1147 (icch.version >> 20) & 0x0f,
1148 (icch.version >> 16) & 0x0f);
1149 WARN("ICC profile not embedded.");
1150 print_iccp_header(&icch, NULL);
1151 return -1;
1152 }
1153
1154 if (!iccp_devClass_allowed(icch.devClass)) {
1155 WARN("Unsupported ICC Profile Device Class:");
1156 print_iccp_header(&icch, NULL);
1157 return -1;
1158 }
1159
1160 if (icch.colorSpace == str2iccSig("RGB ")) {
1161 colorspace = PDF_COLORSPACE_TYPE_RGB;
1162 } else if (icch.colorSpace == str2iccSig("GRAY")) {
1163 colorspace = PDF_COLORSPACE_TYPE_GRAY;
1164 } else if (icch.colorSpace == str2iccSig("CMYK")) {
1165 colorspace = PDF_COLORSPACE_TYPE_CMYK;
1166 } else {
1167 WARN("Unsupported input color space.");
1168 print_iccp_header(&icch, NULL);
1169 return -1;
1170 }
1171
1172 iccp_get_checksum(checksum, profile, proflen);
1173 if (memcmp(icch.ID, nullbytes16, 16) &&
1174 memcmp(icch.ID, checksum, 16)) {
1175 WARN("Invalid ICC profile: Inconsistent checksum.");
1176 print_iccp_header(&icch, checksum);
1177 return -1;
1178 }
1179
1180 cdata = NEW(1, struct iccbased_cdata);
1181 init_iccbased_cdata(cdata);
1182 cdata->colorspace = colorspace;
1183 memcpy(cdata->checksum, checksum, 16);
1184
1185 cspc_id = pdf_colorspace_findresource(ident,
1186 PDF_COLORSPACE_TYPE_ICCBASED, cdata);
1187 if (cspc_id >= 0) {
1188 if (verbose)
1189 MESG("(ICCP:[id=%d])", cspc_id);
1190 release_iccbased_cdata(cdata);
1191 return cspc_id;
1192 }
1193 if (verbose > 1) {
1194 print_iccp_header(&icch, checksum);
1195 }
1196
1197 resource = pdf_new_array();
1198
1199 stream = pdf_new_stream(STREAM_COMPRESS);
1200 pdf_add_array(resource, pdf_new_name("ICCBased"));
1201 pdf_add_array(resource, pdf_ref_obj (stream));
1202
1203 stream_dict = pdf_stream_dict(stream);
1204 pdf_add_dict(stream_dict, pdf_new_name("N"),
1205 pdf_new_number(get_num_components_iccbased(cdata)));
1206
1207 pdf_add_stream (stream, profile, proflen);
1208 pdf_release_obj(stream);
1209
1210 cspc_id = pdf_colorspace_defineresource(ident,
1211 PDF_COLORSPACE_TYPE_ICCBASED,
1212 cdata, resource);
1213
1214 return cspc_id;
1215 }
1216
1217 #if 0
1218 #define WBUF_SIZE 4096
1219 static unsigned char wbuf[WBUF_SIZE];
1220
1221 static pdf_obj *
1222 iccp_load_file_stream (unsigned char *checksum, long length, FILE *fp)
1223 {
1224 pdf_obj *stream;
1225 MD5_CONTEXT md5;
1226 long nb_read;
1227
1228 rewind(fp);
1229
1230 if (fread(wbuf, 1, 128, fp) != 128) {
1231 return NULL;
1232 }
1233 length -= 128;
1234
1235 stream = pdf_new_stream(STREAM_COMPRESS);
1236
1237 MD5_init (&md5);
1238 MD5_write(&md5, wbuf + ICC_HEAD_SECT1_START, ICC_HEAD_SECT1_LENGTH);
1239 MD5_write(&md5, nullbytes16, 12);
1240 MD5_write(&md5, wbuf + ICC_HEAD_SECT2_START, ICC_HEAD_SECT2_LENGTH);
1241 MD5_write(&md5, nullbytes16, 16);
1242 MD5_write(&md5, wbuf + ICC_HEAD_SECT3_START, ICC_HEAD_SECT3_LENGTH);
1243
1244 pdf_add_stream(stream, wbuf, 128);
1245
1246 /* body */
1247 while (length > 0) {
1248 nb_read = fread(wbuf, 1, MIN(length, WBUF_SIZE), fp);
1249 MD5_write(&md5, wbuf, nb_read);
1250 pdf_add_stream(stream, wbuf, nb_read);
1251 length -= nb_read;
1252 }
1253
1254 MD5_final(checksum, &md5);
1255
1256
1257 return stream;
1258 }
1259
1260 int
1261 pdf_colorspace_load_ICCBased (const char *ident, const char *filename)
1262 {
1263 int cspc_id;
1264 FILE *fp;
1265 pdf_obj *resource;
1266 pdf_obj *stream;
1267 pdf_obj *stream_dict;
1268 iccHeader icch;
1269 int colorspace;
1270 long size;
1271 unsigned char checksum[16];
1272 struct iccbased_cdata *cdata;
1273
1274
1275 fp = DPXFOPEN(filename, DPX_RES_TYPE_ICCPROFILE);
1276 if (!fp)
1277 return -1;
1278
1279 size = file_size(fp);
1280 if (size < 128) {
1281 MFCLOSE(fp);
1282 return -1;
1283 }
1284 if (fread(wbuf, 1, 128, fp) != 128) {
1285 DPXFCLOSE(fp);
1286 return -1;
1287 }
1288
1289 iccp_init_iccHeader(&icch);
1290 if (iccp_unpack_header(&icch, wbuf, 128, 0) < 0) {
1291 WARN("Invalid ICC profile header in \"%s\"", ident);
1292 print_iccp_header(&icch, NULL);
1293 DPXFCLOSE(fp);
1294 return -1;
1295 }
1296 if (icch.size > size) {
1297 WARN("File size smaller than recorded in header: %ld %ld",
1298 icch.size, size);
1299 DPXFCLOSE(fp);
1300 return -1;
1301 }
1302
1303 if (!iccp_version_supported((icch.version >> 24) & 0xff,
1304 (icch.version >> 16) & 0xff)) {
1305 WARN("ICC profile format spec. version %d.%01d.%01d"
1306 " not supported in current PDF version setting.",
1307 (icch.version >> 24) & 0xff,
1308 (icch.version >> 20) & 0x0f,
1309 (icch.version >> 16) & 0x0f);
1310 WARN("ICC profile not embedded.");
1311 print_iccp_header(&icch, NULL);
1312 DPXFCLOSE(fp);
1313 return -1;
1314 }
1315
1316 if (!iccp_devClass_allowed(icch.devClass)) {
1317 WARN("Unsupported ICC Profile Device Class:");
1318 print_iccp_header(&icch, NULL);
1319 DPXFCLOSE(fp);
1320 return -1;
1321 }
1322
1323 if (icch.colorSpace == str2iccSig("RGB ")) {
1324 colorspace = PDF_COLORSPACE_TYPE_RGB;
1325 } else if (icch.colorSpace == str2iccSig("GRAY")) {
1326 colorspace = PDF_COLORSPACE_TYPE_GRAY;
1327 } else if (icch.colorSpace == str2iccSig("CMYK")) {
1328 colorspace = PDF_COLORSPACE_TYPE_CMYK;
1329 } else {
1330 WARN("Unsupported input color space.");
1331 print_iccp_header(&icch, NULL);
1332 DPXFCLOSE(fp);
1333 return -1;
1334 }
1335
1336 stream = iccp_load_file_stream(checksum, icch.size, fp);
1337 DPXFCLOSE(fp);
1338
1339 if (!stream) {
1340 WARN("Loading ICC Profile failed...: %s", filename);
1341 return -1;
1342 }
1343
1344 if (memcmp(icch.ID, nullbytes16, 16) &&
1345 memcmp(icch.ID, checksum, 16)) {
1346 WARN("Invalid ICC profile: Inconsistent checksum.");
1347 print_iccp_header(&icch, NULL);
1348 pdf_release_obj(stream);
1349 return -1;
1350 }
1351
1352 cdata = NEW(1, struct iccbased_cdata);
1353 init_iccbased_cdata(cdata);
1354 cdata->colorspace = colorspace;
1355 memcpy(cdata->checksum, checksum, 16);
1356
1357 cspc_id = pdf_colorspace_findresource(ident,
1358 PDF_COLORSPACE_TYPE_ICCBASED, cdata);
1359 if (cspc_id >= 0) {
1360 if (verbose)
1361 MESG("(ICCP:[id=%d])", cspc_id);
1362 release_iccbased_cdata(cdata);
1363 pdf_release_obj(stream);
1364 return cspc_id;
1365 }
1366 if (verbose > 1) {
1367 print_iccp_header(&icch, checksum);
1368 }
1369
1370 resource = pdf_new_array();
1371
1372 pdf_add_array(resource, pdf_new_name("ICCBased"));
1373 pdf_add_array(resource, pdf_ref_obj (stream));
1374
1375 stream_dict = pdf_stream_dict(stream);
1376 pdf_add_dict(stream_dict, pdf_new_name("N"),
1377 pdf_new_number(get_num_components_iccbased(cdata)));
1378 pdf_release_obj(stream);
1379
1380 cspc_id = pdf_colorspace_defineresource(ident,
1381 PDF_COLORSPACE_TYPE_ICCBASED,
1382 cdata, resource);
1383
1384 return cspc_id;
1385 }
1386 #endif
1387
1388 typedef struct {
1389 char *ident;
1390 int subtype;
1391
1392 pdf_obj *resource;
1393 pdf_obj *reference;
1394
1395 void *cdata;
1396 } pdf_colorspace;
1397
1398 static struct {
1399 int count;
1400 int capacity;
1401 pdf_colorspace *colorspaces;
1402 } cspc_cache = {
1403 0, 0, NULL
1404 };
1405
1406 int
pdf_colorspace_findresource(const char * ident,int type,const void * cdata)1407 pdf_colorspace_findresource (const char *ident,
1408 int type, const void *cdata)
1409 {
1410 pdf_colorspace *colorspace;
1411 int cspc_id, cmp = -1;
1412
1413 for (cspc_id = 0;
1414 cmp && cspc_id < cspc_cache.count; cspc_id++) {
1415 colorspace = &cspc_cache.colorspaces[cspc_id];
1416 if (colorspace->subtype != type)
1417 continue;
1418
1419 switch (colorspace->subtype) {
1420 case PDF_COLORSPACE_TYPE_ICCBASED:
1421 cmp = compare_iccbased(ident, cdata,
1422 colorspace->ident, colorspace->cdata);
1423 break;
1424 }
1425 if (!cmp)
1426 return cspc_id;
1427 }
1428
1429 return -1; /* not found */
1430 }
1431
1432 static void
pdf_init_colorspace_struct(pdf_colorspace * colorspace)1433 pdf_init_colorspace_struct (pdf_colorspace *colorspace)
1434 {
1435 ASSERT(colorspace);
1436
1437 colorspace->ident = NULL;
1438 colorspace->subtype = PDF_COLORSPACE_TYPE_INVALID;
1439
1440 colorspace->resource = NULL;
1441 colorspace->reference = NULL;
1442 colorspace->cdata = NULL;
1443
1444 return;
1445 }
1446
1447 static void
pdf_clean_colorspace_struct(pdf_colorspace * colorspace)1448 pdf_clean_colorspace_struct (pdf_colorspace *colorspace)
1449 {
1450 ASSERT(colorspace);
1451
1452 if (colorspace->ident)
1453 RELEASE(colorspace->ident);
1454 if (colorspace->resource)
1455 pdf_release_obj(colorspace->resource);
1456 if (colorspace->reference)
1457 pdf_release_obj(colorspace->reference);
1458 colorspace->resource = NULL;
1459 colorspace->reference = NULL;
1460
1461 if (colorspace->cdata) {
1462 switch (colorspace->subtype) {
1463 case PDF_COLORSPACE_TYPE_ICCBASED:
1464 release_iccbased_cdata(colorspace->cdata);
1465 break;
1466 }
1467 }
1468 colorspace->cdata = NULL;
1469 colorspace->subtype = PDF_COLORSPACE_TYPE_INVALID;
1470
1471 return;
1472 }
1473
1474 static void
pdf_flush_colorspace(pdf_colorspace * colorspace)1475 pdf_flush_colorspace (pdf_colorspace *colorspace)
1476 {
1477 ASSERT(colorspace);
1478
1479 if (colorspace->resource)
1480 pdf_release_obj(colorspace->resource);
1481 if (colorspace->reference)
1482 pdf_release_obj(colorspace->reference);
1483
1484 colorspace->resource = NULL;
1485 colorspace->reference = NULL;
1486 }
1487
1488 int
pdf_colorspace_defineresource(const char * ident,int subtype,void * cdata,pdf_obj * resource)1489 pdf_colorspace_defineresource (const char *ident,
1490 int subtype, void *cdata, pdf_obj *resource)
1491 {
1492 int cspc_id;
1493 pdf_colorspace *colorspace;
1494
1495 if (cspc_cache.count >= cspc_cache.capacity) {
1496 cspc_cache.capacity += 16;
1497 cspc_cache.colorspaces = RENEW(cspc_cache.colorspaces,
1498 cspc_cache.capacity, pdf_colorspace);
1499 }
1500 cspc_id = cspc_cache.count;
1501 colorspace = &cspc_cache.colorspaces[cspc_id];
1502
1503 pdf_init_colorspace_struct(colorspace);
1504 if (ident) {
1505 colorspace->ident = NEW(strlen(ident) + 1, char);
1506 strcpy(colorspace->ident, ident);
1507 }
1508 colorspace->subtype = subtype;
1509 colorspace->cdata = cdata;
1510 colorspace->resource = resource;
1511
1512 if (verbose) {
1513 MESG("(ColorSpace:%s", ident);
1514 if (verbose > 1) {
1515 switch (subtype) {
1516 case PDF_COLORSPACE_TYPE_ICCBASED:
1517 MESG("[ICCBased]");
1518 break;
1519 case PDF_COLORSPACE_TYPE_CALRGB:
1520 MESG("[CalRGB]");
1521 break;
1522 case PDF_COLORSPACE_TYPE_CALGRAY:
1523 MESG("[CalGray]");
1524 break;
1525 }
1526 }
1527 MESG(")");
1528 }
1529
1530 cspc_cache.count++;
1531
1532 return cspc_id;
1533 }
1534
1535 pdf_obj *
pdf_get_colorspace_reference(int cspc_id)1536 pdf_get_colorspace_reference (int cspc_id)
1537 {
1538 pdf_colorspace *colorspace;
1539
1540 colorspace = &cspc_cache.colorspaces[cspc_id];
1541 if (!colorspace->reference) {
1542 colorspace->reference = pdf_ref_obj(colorspace->resource);
1543 pdf_release_obj(colorspace->resource); /* .... */
1544 colorspace->resource = NULL;
1545 }
1546
1547 return pdf_link_obj(colorspace->reference);
1548 }
1549
1550 #if 0
1551 int
1552 pdf_get_colorspace_num_components (int cspc_id)
1553 {
1554 pdf_colorspace *colorspace;
1555 int num_components;
1556
1557 colorspace = &cspc_cache.colorspaces[cspc_id];
1558
1559 switch (colorspace->subtype) {
1560 case PDF_COLORSPACE_TYPE_ICCBASED:
1561 num_components = get_num_components_iccbased(colorspace->cdata);
1562 break;
1563 case PDF_COLORSPACE_TYPE_DEVICEGRAY:
1564 num_components = 1;
1565 break;
1566 case PDF_COLORSPACE_TYPE_DEVICERGB:
1567 num_components = 3;
1568 break;
1569 case PDF_COLORSPACE_TYPE_DEVICECMYK:
1570 num_components = 4;
1571 break;
1572 case PDF_COLORSPACE_TYPE_CALRGB:
1573 num_components = 3;
1574 break;
1575 case PDF_COLORSPACE_TYPE_CALGRAY:
1576 num_components = 1;
1577 break;
1578 default:
1579 num_components = 0;
1580 break;
1581 }
1582
1583 return num_components;
1584 }
1585
1586 int
1587 pdf_get_colorspace_subtype (int cspc_id)
1588 {
1589 pdf_colorspace *colorspace;
1590
1591 colorspace = &cspc_cache.colorspaces[cspc_id];
1592
1593 return colorspace->subtype;
1594 }
1595 #endif
1596
1597 void
pdf_init_colors(void)1598 pdf_init_colors (void)
1599 {
1600 cspc_cache.count = 0;
1601 cspc_cache.capacity = 0;
1602 cspc_cache.colorspaces = NULL;
1603 }
1604
1605 void
pdf_close_colors(void)1606 pdf_close_colors (void)
1607 {
1608 int i;
1609
1610 for (i = 0; i < cspc_cache.count; i++) {
1611 pdf_colorspace *colorspace;
1612
1613 colorspace = &cspc_cache.colorspaces[i];
1614 pdf_flush_colorspace(colorspace);
1615 pdf_clean_colorspace_struct(colorspace);
1616 }
1617 RELEASE(cspc_cache.colorspaces);
1618 cspc_cache.colorspaces = NULL;
1619 cspc_cache.count = cspc_cache.capacity = 0;
1620
1621 }
1622
1623 #define PDF_COLORSPACE_FAMILY_DEVICE 0
1624 #define PDF_COLORSPACE_FAMILY_CIEBASED 1
1625 #define PDF_COLORSPACE_FAMILY_SPECIAL 2
1626