3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 /* No page independence here...
44 static int verbose = 0;
46 pdf_color_set_verbose (void)
51 /* This function returns PDF_COLORSPACE_TYPE_GRAY,
52 * PDF_COLORSPACE_TYPE_RGB or PDF_COLORSPACE_TYPE_CMYK.
55 pdf_color_type (const pdf_color *color)
59 return -color->num_components;
63 pdf_color_rgbcolor (pdf_color *color, double r, double g, double b)
67 if (r < 0.0 || r > 1.0) {
68 WARN("Invalid color value specified: red=%g", r);
71 if (g < 0.0 || g > 1.0) {
72 WARN("Invalid color value specified: green=%g", g);
75 if (b < 0.0 || b > 1.0) {
76 WARN("Invalid color value specified: blue=%g", b);
83 color->num_components = 3;
89 pdf_color_cmykcolor (pdf_color *color,
90 double c, double m, double y, double k)
94 if (c < 0.0 || c > 1.0) {
95 WARN("Invalid color value specified: cyan=%g", c);
98 if (m < 0.0 || m > 1.0) {
99 WARN("Invalid color value specified: magenta=%g", m);
102 if (y < 0.0 || y > 1.0) {
103 WARN("Invalid color value specified: yellow=%g", y);
106 if (k < 0.0 || k > 1.0) {
107 WARN("Invalid color value specified: black=%g", k);
111 color->values[0] = c;
112 color->values[1] = m;
113 color->values[2] = y;
114 color->values[3] = k;
116 color->num_components = 4;
122 pdf_color_graycolor (pdf_color *color, double g)
126 if (g < 0.0 || g > 1.0) {
127 WARN("Invalid color value specified: gray=%g", g);
131 color->values[0] = g;
133 color->num_components = 1;
140 pdf_color_copycolor (pdf_color *color1, const pdf_color *color2)
142 ASSERT(color1 && color2);
144 memcpy(color1, color2, sizeof(pdf_color));
147 /* Brighten up a color. f == 0 means no change, f == 1 means white. */
149 pdf_color_brighten_color (pdf_color *dst, const pdf_color *src, double f)
154 pdf_color_white(dst);
159 n = dst->num_components = src->num_components;
160 f1 = n == 4 ? 0.0 : f; /* n == 4 is CMYK, others are RGB and Gray */
164 dst->values[n] = f0 * src->values[n] + f1;
169 pdf_color_is_white (const pdf_color *color)
176 n = color->num_components;
177 f = n == 4 ? 0.0 : 1.0; /* n == 4 is CMYK, others are RGB and Gray */
180 if (color->values[n] != f)
187 pdf_color_to_string (const pdf_color *color, char *buffer)
191 for (i = 0; i < color->num_components; i++) {
192 len += sprintf(buffer+len, " %g", ROUND(color->values[i], 0.001));
197 pdf_color current_fill = {
202 pdf_color current_stroke = {
208 * This routine is not a real color matching.
211 pdf_color_compare (const pdf_color *color1, const pdf_color *color2)
213 int n = color1->num_components;
215 if (n != color2->num_components)
219 if (color1->values[n] != color2->values[n])
226 pdf_color_is_valid (const pdf_color *color)
230 n = color->num_components;
231 if (n != 1 && n != 3 && n != 4)
235 if (color->values[n] < 0.0 || color->values[n] > 1.0)
241 /* Dvipdfm special */
242 #define DEV_COLOR_STACK_MAX 128
246 pdf_color stroke[DEV_COLOR_STACK_MAX];
247 pdf_color fill[DEV_COLOR_STACK_MAX];
251 pdf_color_clear_stack (void)
253 if (color_stack.current > 0) {
254 WARN("You've mistakenly made a global color change within nested colors.");
256 color_stack.current = 0;
257 pdf_color_black(color_stack.stroke);
258 pdf_color_black(color_stack.fill);
263 pdf_color_set (pdf_color *sc, pdf_color *fc)
265 pdf_color_copycolor(&color_stack.stroke[color_stack.current], sc);
266 pdf_color_copycolor(&color_stack.fill[color_stack.current], fc);
267 pdf_dev_reset_color(0);
271 pdf_color_push (pdf_color *sc, pdf_color *fc)
273 if (color_stack.current >= DEV_COLOR_STACK_MAX-1) {
274 WARN("Color stack overflow. Just ignore.");
276 color_stack.current++;
277 pdf_color_set(sc, fc);
285 if (color_stack.current <= 0) {
286 WARN("Color stack underflow. Just ignore.");
288 color_stack.current--;
289 pdf_dev_reset_color(0);
295 pdf_color_get_current (pdf_color **sc, pdf_color **fc)
297 *sc = &color_stack.stroke[color_stack.current];
298 *fc = &color_stack.fill[color_stack.current];
302 /***************************** COLOR SPACE *****************************/
304 static int pdf_colorspace_defineresource (const char *ident,
306 void *cdata, pdf_obj *resource);
308 static int pdf_colorspace_findresource (const char *ident,
309 int subtype, const void *cdata);
314 double white_point[3]; /* required, second component must
317 double black_point[3]; /* optional, default: [0 0 0] */
318 double gamma; /* optional, default: 1.0 */
323 double white_point[3]; /* required, second component must
326 double black_point[3]; /* optional, default: [0 0 0] */
327 double gamma[3]; /* optional, default: [1 1 1] */
328 double matrix[9]; /* optional, default: identity
329 * [1 0 0 0 1 0 0 0 1]
334 release_calrgb (void *cdata)
336 struct calrgb_cdata *calrgb;
339 calrgb = (struct calrgb_cdata *) cdata;
345 compare_calrgb (const char *ident1, const void *cdata1,
346 const char *ident2, const void *cdata2)
348 struct calrgb_cdata *calrgb1;
349 struct calrgb_cdata *calrgb2;
351 if (ident1 && ident2 &&
352 !strcmp(ident1, ident2)) {
358 init_calrgb (struct calrgb_cdata *calrgb)
362 calrgb->white_point[0] = 1.0;
363 calrgb->white_point[1] = 1.0;
364 calrgb->white_point[2] = 1.0;
366 calrgb->black_point[0] = 0.0;
367 calrgb->black_point[1] = 0.0;
368 calrgb->black_point[2] = 0.0;
370 calrgb->gamma[0] = 1.0;
371 calrgb->gamma[1] = 1.0;
372 calrgb->gamma[2] = 1.0;
374 calrgb->matrix[0] = 1.0;
375 calrgb->matrix[1] = 0.0;
376 calrgb->matrix[2] = 0.0;
378 calrgb->matrix[3] = 0.0;
379 calrgb->matrix[4] = 1.0;
380 calrgb->matrix[5] = 0.0;
382 calrgb->matrix[6] = 0.0;
383 calrgb->matrix[7] = 0.0;
384 calrgb->matrix[8] = 1.0;
388 valid_calrgb (struct calrgb_cdata *calrgb)
390 if (calrgb->white_point[1] != 1.0 ||
391 calrgb->white_point[0] <= 0.0 ||
392 calrgb->white_point[2] <= 0.0)
395 if (calrgb->black_point[0] < 0.0 ||
396 calrgb->black_point[1] < 0.0 ||
397 calrgb->black_point[2] < 0.0)
400 if (calrgb->gamma[0] < 0.0 ||
401 calrgb->gamma[1] < 0.0 ||
402 calrgb->gamma[2] < 0.0)
405 /* matrix should be invertible? */
411 pdf_color_make_calrgb_resource (struct calrgb_cdata *calrgb)
414 pdf_obj *calparams, *tmp_array;
418 if (!valid_calrgb(calrgb))
421 colorspace = pdf_new_array();
422 calparams = pdf_new_dict();
424 tmp_array = pdf_new_array();
425 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->white_point[0], 0.001)));
426 pdf_add_array(tmp_array, pdf_new_number(1.0));
427 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->white_point[2], 0.001)));
428 pdf_add_dict(calparams, pdf_new_name("WhitePoint"), tmp_array);
430 if (calrgb->black_point[0] != 0.0 ||
431 calrgb->black_point[1] != 0.0 ||
432 calrgb->black_point[2] != 0.0) {
433 tmp_array = pdf_new_array();
434 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[0], 0.001)));
435 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[1], 0.001)));
436 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[2], 0.001)));
437 pdf_add_dict(calparams, pdf_new_name("BlackPoint"), tmp_array);
440 if (calrgb->gamma[0] != 1.0 ||
441 calrgb->gamma[1] != 1.0 ||
442 calrgb->gamma[2] != 1.0) {
443 tmp_array = pdf_new_array();
444 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[0], 0.001)));
445 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[1], 0.001)));
446 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[2], 0.001)));
447 pdf_add_dict(calparams, pdf_new_name("Gamma"), tmp_array);
450 if (calrgb->matrix[0] != 1.0 ||
451 calrgb->matrix[1] != 0.0 ||
452 calrgb->matrix[2] != 0.0 ||
453 calrgb->matrix[3] != 0.0 ||
454 calrgb->matrix[4] != 1.0 ||
455 calrgb->matrix[5] != 0.0 ||
456 calrgb->matrix[6] != 0.0 ||
457 calrgb->matrix[7] != 0.0 ||
458 calrgb->matrix[8] != 1.0) {
459 tmp_array = pdf_new_array();
460 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[0], 0.001)));
461 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[1], 0.001)));
462 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[2], 0.001)));
463 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[3], 0.001)));
464 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[4], 0.001)));
465 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[5], 0.001)));
466 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[6], 0.001)));
467 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[7], 0.001)));
468 pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[8], 0.001)));
469 pdf_add_dict(calparams, pdf_new_name("Matrix"), tmp_array);
472 pdf_add_array(colorspace, pdf_new_name("CalRGB"));
473 pdf_add_array(colorspace, calparams);
479 static unsigned char nullbytes16[16] = {
480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
488 {0, 0}, /* PDF-1.0, we don't support them */
489 {0, 0}, /* PDF-1.1, we don't support them */
490 {0, 0}, /* PDF-1.2, we don't support them */
491 {0x02, 0x10}, /* PDF-1.3 */
492 {0x02, 0x20}, /* PDF-1.4 */
493 {0x04, 0x00} /* PDF-1.5 */
497 iccp_version_supported (int major, int minor)
501 pdf_ver = pdf_get_version();
503 if (icc_versions[pdf_ver].major < major)
505 else if (icc_versions[pdf_ver].major == major &&
506 icc_versions[pdf_ver].minor < minor)
516 typedef unsigned long iccSig;
518 str2iccSig (const void *s)
522 p = (const char *) s;
524 return (iccSig) ((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]);
529 long X, Y, Z; /* s15Fixed16Numeber */
539 iccSig PCS; /* Profile Connection Space */
540 char creationDate[12];
548 iccXYZNumber illuminant;
550 unsigned char ID[16]; /* MD5 checksum with Rendering intent,
551 * Header attrs, Profile ID fields are
554 /* 28 bytes reserved - must be set to zeros */
559 iccp_init_iccHeader (iccHeader *icch)
564 icch->CMMType = iccNullSig;
565 icch->version = 0xFFFFFF;
566 icch->devClass = iccNullSig;
567 icch->colorSpace = iccNullSig;
568 icch->PCS = iccNullSig;
569 memset(icch->creationDate, 0, 12);
570 icch->acsp = str2iccSig("ascp");
571 icch->platform = iccNullSig;
572 memset(icch->flags, 0, 4);
573 icch->devMnfct = iccNullSig;
574 icch->devModel = iccNullSig;
575 memset(icch->devAttr, 0, 8);
577 icch->illuminant.X = 0;
578 icch->illuminant.Y = 0;
579 icch->illuminant.Z = 0;
580 icch->creator = iccNullSig;
581 memset(icch->ID, 0, 16);
584 #define ICC_INTENT_TYPE(n) ((int) (((n) >> 16) & 0xff))
585 #define ICC_INTENT_PERCEPTUAL 0
586 #define ICC_INTENT_RELATIVE 1
587 #define ICC_INTENT_SATURATION 2
588 #define ICC_INTENT_ABSOLUTE 3
591 * In ICC profile stream dicrionary, there is /Range whose values must
592 * "match the information in the profile". But where is those values in?
594 * How should I treat rendering intent?
596 struct iccbased_cdata
598 long sig; /* 'i' 'c' 'c' 'b' */
600 unsigned char checksum[16]; /* 16 bytes MD5 Checksum */
601 int colorspace; /* input colorspace:
602 * RGB, Gray, CMYK, (Lab?)
604 int alternate; /* alternate colorspace (id), unused */
607 #define check_sig(d,p,q,r,s) ((d) && (d)->sig == ((p)<<24|(q)<<16|(r)<<8|(s)))
610 init_iccbased_cdata (struct iccbased_cdata *cdata)
614 cdata->sig = ('i' << 24|'c' << 16|'c' << 8|'b');
615 memset(cdata->checksum, 0, 16);
616 cdata->colorspace = PDF_COLORSPACE_TYPE_INVALID;
617 cdata->alternate = -1;
623 release_iccbased_cdata (struct iccbased_cdata *cdata)
625 ASSERT(check_sig(cdata, 'i', 'c', 'c', 'b'));
631 get_num_components_iccbased (const struct iccbased_cdata *cdata)
633 int num_components = 0;
635 ASSERT(check_sig(cdata, 'i', 'c', 'c', 'b'));
637 switch (cdata->colorspace) {
638 case PDF_COLORSPACE_TYPE_RGB:
641 case PDF_COLORSPACE_TYPE_CMYK:
644 case PDF_COLORSPACE_TYPE_GRAY:
647 case PDF_COLORSPACE_TYPE_CIELAB:
652 return num_components;
656 compare_iccbased (const char *ident1, const struct iccbased_cdata *cdata1,
657 const char *ident2, const struct iccbased_cdata *cdata2)
659 if (cdata1 && cdata2) {
661 ASSERT(check_sig(cdata1, 'i', 'c', 'c', 'b'));
662 ASSERT(check_sig(cdata2, 'i', 'c', 'c', 'b'));
664 if (memcmp(cdata1->checksum, nullbytes16, 16) &&
665 memcmp(cdata2->checksum, nullbytes16, 16)) {
666 return memcmp(cdata1->checksum, cdata2->checksum, 16);
668 if (cdata1->colorspace != cdata2->colorspace) {
669 return (cdata1->colorspace - cdata2->colorspace);
672 /* Continue if checksum unknown and colorspace is same. */
675 if (ident1 && ident2)
676 return strcmp(ident1, ident2);
678 /* No way to compare */
683 iccp_check_colorspace (int colortype, const void *profile, long proflen)
686 const unsigned char *p;
688 if (!profile || proflen < 128)
691 p = (const unsigned char *) profile;
693 colorspace = str2iccSig(p + 16);
696 case PDF_COLORSPACE_TYPE_CALRGB:
697 case PDF_COLORSPACE_TYPE_RGB:
698 if (colorspace != str2iccSig("RGB ")) {
702 case PDF_COLORSPACE_TYPE_CALGRAY:
703 case PDF_COLORSPACE_TYPE_GRAY:
704 if (colorspace != str2iccSig("GRAY")) {
708 case PDF_COLORSPACE_TYPE_CMYK:
709 if (colorspace != str2iccSig("CMYK")) {
722 iccp_get_rendering_intent (const void *profile, long proflen)
725 const unsigned char *p;
728 if (!profile || proflen < 128)
731 p = (const unsigned char *) profile;
733 intent = (p[64] << 24)|(p[65] << 16)|(p[66] << 8)|p[67];
734 switch (ICC_INTENT_TYPE(intent)) {
735 case ICC_INTENT_SATURATION:
736 ri = pdf_new_name("Saturation");
738 case ICC_INTENT_PERCEPTUAL:
739 ri = pdf_new_name("Perceptual");
741 case ICC_INTENT_ABSOLUTE:
742 ri = pdf_new_name("AbsoluteColorimetric");
744 case ICC_INTENT_RELATIVE:
745 ri = pdf_new_name("RelativeColorimetric");
748 WARN("Invalid rendering intent type: %d", ICC_INTENT_TYPE(intent));
755 #define sget_signed_long(p) ((long) ((p)[0] << 24|(p)[1] << 16|(p)[2] << 8|(p)[3]))
756 #define sget_signed_short(p) ((short) ((p)[0] << 8|(p)[1]))
757 #define get_iccSig(p) ((iccSig) ((p)[0] << 24|(p)[1] << 16|(p)[2] << 8|(p)[3]))
760 iccp_unpack_header (iccHeader *icch,
761 const void *profile, long proflen, int check_size)
763 const unsigned char *p, *endptr;
766 if (!profile || proflen < 128 ||
768 WARN("Profile size: %ld", proflen);
773 p = (const unsigned char *) profile;
776 icch->size = sget_signed_long(p);
778 if (icch->size != proflen) {
779 WARN("ICC Profile size: %ld(header) != %ld", icch->size, proflen);
785 icch->CMMType = str2iccSig(p);
787 icch->version = sget_signed_long(p);
789 icch->devClass = str2iccSig(p);
791 icch->colorSpace = str2iccSig(p);
793 icch->PCS = str2iccSig(p);
795 memcpy(icch->creationDate, p, 12);
797 icch->acsp = str2iccSig(p); /* acsp */
798 if (icch->acsp != str2iccSig("acsp")) {
799 WARN("Invalid ICC profile: not \"acsp\" - %c%c%c%c ",
800 p[0], p[1], p[2], p[3]);
804 icch->platform = str2iccSig(p);
806 memcpy(icch->flags, p, 4);
808 icch->devMnfct = str2iccSig(p);
810 icch->devModel = str2iccSig(p);
812 memcpy(icch->devAttr, p, 8);
814 icch->intent = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
816 icch->illuminant.X = sget_signed_long(p);
818 icch->illuminant.Y = sget_signed_long(p);
820 icch->illuminant.Z = sget_signed_long(p);
822 icch->creator = str2iccSig(p);
824 memcpy(icch->ID, p, 16);
827 /* 28 bytes reserved - must be set to zeros */
828 for (; p < endptr; p++) {
830 WARN("Reserved pad not zero: %02x (at offset %ld in ICC profile header.)",
831 *p, 128 - ((long) (endptr - p)));
839 /* MD5 checksum with Rendering intent,
840 * Header attrs, Profile ID fields are
843 #define ICC_HEAD_SECT1_START 0
844 #define ICC_HEAD_SECT1_LENGTH 56
845 /* 8 bytes devAttr, 4 bytes intent */
846 #define ICC_HEAD_SECT2_START 68
847 #define ICC_HEAD_SECT2_LENGTH 16
848 /* 16 bytes ID (checksum) */
849 #define ICC_HEAD_SECT3_START 100
850 #define ICC_HEAD_SECT3_LENGTH 28
852 #include "dpxcrypt.h"
854 iccp_get_checksum (unsigned char *checksum, const void *profile, long proflen)
856 const unsigned char *p;
859 p = (const unsigned char *) profile;
862 MD5_write(&md5, p + ICC_HEAD_SECT1_START, ICC_HEAD_SECT1_LENGTH);
863 MD5_write(&md5, nullbytes16, 12);
864 MD5_write(&md5, p + ICC_HEAD_SECT2_START, ICC_HEAD_SECT2_LENGTH);
865 MD5_write(&md5, nullbytes16, 16);
866 MD5_write(&md5, p + ICC_HEAD_SECT3_START, ICC_HEAD_SECT3_LENGTH);
869 MD5_write(&md5, p + 128, proflen - 128);
871 MD5_final(checksum, &md5);
875 print_iccp_header (iccHeader *icch, unsigned char *checksum)
881 #define print_iccSig(s,t) if ((s) == 0) {\
882 MESG("pdf_color>> %s:\t(null)\n", (t)); \
883 } else if (!isprint(((s) >> 24) & 0xff) || \
884 !isprint(((s) >> 16) & 0xff) || \
885 !isprint(((s) >> 8) & 0xff) || \
886 !isprint((s) & 0xff)) { \
887 MESG("pdf_color>> %s:\t(invalid)\n", (t)); \
889 MESG("pdf_color>> %s:\t%c%c%c%c\n", (t), \
890 ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, \
891 ((s) >> 8) & 0xff, (s) & 0xff); \
895 MESG("pdf_color>> ICC Profile Info\n");
896 MESG("pdf_color>> Profile Size:\t%ld bytes\n", icch->size);
897 print_iccSig(icch->CMMType, "CMM Type");
898 MESG("pdf_color>> Profile Version:\t%d.%01d.%01d\n",
899 (icch->version >> 24) & 0xff,
900 (icch->version >> 20) & 0x0f,
901 (icch->version >> 16) & 0x0f);
902 print_iccSig(icch->devClass, "Device Class");
903 print_iccSig(icch->colorSpace, "Color Space");
904 print_iccSig(icch->PCS, "Connection Space");
905 MESG("pdf_color>> Creation Date:\t");
906 for (i = 0; i < 12; i += 2) {
909 sget_unsigned_pair((unsigned char *) icch->creationDate));
912 sget_unsigned_pair((unsigned char *) (&icch->creationDate[i])));
916 print_iccSig(icch->platform, "Primary Platform");
917 MESG("pdf_color>> Profile Flags:\t%02x:%02x:%02x:%02x\n",
918 icch->flags[0], icch->flags[1], icch->flags[2], icch->flags[3]);
919 print_iccSig(icch->devMnfct, "Device Mnfct");
920 print_iccSig(icch->devModel, "Device Model");
921 MESG("pdf_color>> Device Attr:\t");
922 for (i = 0; i < 8; i++) {
924 MESG("%02x", icch->devAttr[i]);
926 MESG(":%02x", icch->devAttr[i]);
929 MESG("pdf_color>> Rendering Intent:\t");
930 switch (ICC_INTENT_TYPE(icch->intent)) {
931 case ICC_INTENT_SATURATION:
934 case ICC_INTENT_PERCEPTUAL:
937 case ICC_INTENT_ABSOLUTE:
938 MESG("Absolute Colorimetric");
940 case ICC_INTENT_RELATIVE:
941 MESG("Relative Colorimetric");
948 print_iccSig(icch->creator, "Creator");
949 MESG("pdf_color>> Illuminant (XYZ):\t");
950 MESG("%.3f %.3f %.3f\n",
951 (double) icch->illuminant.X / 0x10000,
952 (double) icch->illuminant.Y / 0x10000,
953 (double) icch->illuminant.Z / 0x10000);
954 MESG("pdf_color>> Checksum:\t");
955 if (!memcmp(icch->ID, nullbytes16, 16)) {
958 for (i = 0; i < 16; i++) {
960 MESG("%02x", icch->ID[i]);
962 MESG(":%02x", icch->ID[i]);
967 MESG("pdf_color>> Calculated:\t");
968 for (i = 0; i < 16; i++) {
970 MESG("%02x", checksum[i]);
972 MESG(":%02x", checksum[i]);
982 iccp_devClass_allowed (int dev_class)
986 colormode = pdf_dev_get_param(PDF_DEV_PARAM_COLORMODE);
990 case PDF_DEV_COLORMODE_PDFX1:
992 case PDF_DEV_COLORMODE_PDFX3:
993 if (dev_class != str2iccSig("prtr")) {
999 if (dev_class != str2iccSig("scnr") &&
1000 dev_class != str2iccSig("mntr") &&
1001 dev_class != str2iccSig("prtr") &&
1002 dev_class != str2iccSig("spac")) {
1013 iccp_load_profile (const char *ident,
1014 const void *profile, long proflen)
1019 pdf_obj *stream_dict;
1022 unsigned char checksum[16];
1023 struct iccbased_cdata *cdata;
1025 iccp_init_iccHeader(&icch);
1026 if (iccp_unpack_header(&icch, profile, proflen, 1) < 0) { /* check size */
1027 WARN("Invalid ICC profile header in \"%s\"", ident);
1028 print_iccp_header(&icch, NULL);
1032 if (!iccp_version_supported((icch.version >> 24) & 0xff,
1033 (icch.version >> 16) & 0xff)) {
1034 WARN("ICC profile format spec. version %d.%01d.%01d"
1035 " not supported in current PDF version setting.",
1036 (icch.version >> 24) & 0xff,
1037 (icch.version >> 20) & 0x0f,
1038 (icch.version >> 16) & 0x0f);
1039 WARN("ICC profile not embedded.");
1040 print_iccp_header(&icch, NULL);
1044 if (!iccp_devClass_allowed(icch.devClass)) {
1045 WARN("Unsupported ICC Profile Device Class:");
1046 print_iccp_header(&icch, NULL);
1050 if (icch.colorSpace == str2iccSig("RGB ")) {
1051 colorspace = PDF_COLORSPACE_TYPE_RGB;
1052 } else if (icch.colorSpace == str2iccSig("GRAY")) {
1053 colorspace = PDF_COLORSPACE_TYPE_GRAY;
1054 } else if (icch.colorSpace == str2iccSig("CMYK")) {
1055 colorspace = PDF_COLORSPACE_TYPE_CMYK;
1057 WARN("Unsupported input color space.");
1058 print_iccp_header(&icch, NULL);
1062 iccp_get_checksum(checksum, profile, proflen);
1063 if (memcmp(icch.ID, nullbytes16, 16) &&
1064 memcmp(icch.ID, checksum, 16)) {
1065 WARN("Invalid ICC profile: Inconsistent checksum.");
1066 print_iccp_header(&icch, checksum);
1070 cdata = NEW(1, struct iccbased_cdata);
1071 init_iccbased_cdata(cdata);
1072 cdata->colorspace = colorspace;
1073 memcpy(cdata->checksum, checksum, 16);
1075 cspc_id = pdf_colorspace_findresource(ident,
1076 PDF_COLORSPACE_TYPE_ICCBASED, cdata);
1079 MESG("(ICCP:[id=%d])", cspc_id);
1080 release_iccbased_cdata(cdata);
1084 print_iccp_header(&icch, checksum);
1087 resource = pdf_new_array();
1089 stream = pdf_new_stream(STREAM_COMPRESS);
1090 pdf_add_array(resource, pdf_new_name("ICCBased"));
1091 pdf_add_array(resource, pdf_ref_obj (stream));
1093 stream_dict = pdf_stream_dict(stream);
1094 pdf_add_dict(stream_dict, pdf_new_name("N"),
1095 pdf_new_number(get_num_components_iccbased(cdata)));
1097 pdf_add_stream (stream, profile, proflen);
1098 pdf_release_obj(stream);
1100 cspc_id = pdf_colorspace_defineresource(ident,
1101 PDF_COLORSPACE_TYPE_ICCBASED,
1108 #define WBUF_SIZE 4096
1109 static unsigned char wbuf[WBUF_SIZE];
1112 iccp_load_file_stream (unsigned char *checksum, long length, FILE *fp)
1120 if (fread(wbuf, 1, 128, fp) != 128) {
1125 stream = pdf_new_stream(STREAM_COMPRESS);
1128 MD5_write(&md5, wbuf + ICC_HEAD_SECT1_START, ICC_HEAD_SECT1_LENGTH);
1129 MD5_write(&md5, nullbytes16, 12);
1130 MD5_write(&md5, wbuf + ICC_HEAD_SECT2_START, ICC_HEAD_SECT2_LENGTH);
1131 MD5_write(&md5, nullbytes16, 16);
1132 MD5_write(&md5, wbuf + ICC_HEAD_SECT3_START, ICC_HEAD_SECT3_LENGTH);
1134 pdf_add_stream(stream, wbuf, 128);
1137 while (length > 0) {
1138 nb_read = fread(wbuf, 1, MIN(length, WBUF_SIZE), fp);
1139 MD5_write(&md5, wbuf, nb_read);
1140 pdf_add_stream(stream, wbuf, nb_read);
1144 MD5_final(checksum, &md5);
1151 pdf_colorspace_load_ICCBased (const char *ident, const char *filename)
1157 pdf_obj *stream_dict;
1161 unsigned char checksum[16];
1162 struct iccbased_cdata *cdata;
1165 fp = DPXFOPEN(filename, DPX_RES_TYPE_ICCPROFILE);
1169 size = file_size(fp);
1174 if (fread(wbuf, 1, 128, fp) != 128) {
1179 iccp_init_iccHeader(&icch);
1180 if (iccp_unpack_header(&icch, wbuf, 128, 0) < 0) {
1181 WARN("Invalid ICC profile header in \"%s\"", ident);
1182 print_iccp_header(&icch, NULL);
1186 if (icch.size > size) {
1187 WARN("File size smaller than recorded in header: %ld %ld",
1193 if (!iccp_version_supported((icch.version >> 24) & 0xff,
1194 (icch.version >> 16) & 0xff)) {
1195 WARN("ICC profile format spec. version %d.%01d.%01d"
1196 " not supported in current PDF version setting.",
1197 (icch.version >> 24) & 0xff,
1198 (icch.version >> 20) & 0x0f,
1199 (icch.version >> 16) & 0x0f);
1200 WARN("ICC profile not embedded.");
1201 print_iccp_header(&icch, NULL);
1206 if (!iccp_devClass_allowed(icch.devClass)) {
1207 WARN("Unsupported ICC Profile Device Class:");
1208 print_iccp_header(&icch, NULL);
1213 if (icch.colorSpace == str2iccSig("RGB ")) {
1214 colorspace = PDF_COLORSPACE_TYPE_RGB;
1215 } else if (icch.colorSpace == str2iccSig("GRAY")) {
1216 colorspace = PDF_COLORSPACE_TYPE_GRAY;
1217 } else if (icch.colorSpace == str2iccSig("CMYK")) {
1218 colorspace = PDF_COLORSPACE_TYPE_CMYK;
1220 WARN("Unsupported input color space.");
1221 print_iccp_header(&icch, NULL);
1226 stream = iccp_load_file_stream(checksum, icch.size, fp);
1230 WARN("Loading ICC Profile failed...: %s", filename);
1234 if (memcmp(icch.ID, nullbytes16, 16) &&
1235 memcmp(icch.ID, checksum, 16)) {
1236 WARN("Invalid ICC profile: Inconsistent checksum.");
1237 print_iccp_header(&icch, NULL);
1238 pdf_release_obj(stream);
1242 cdata = NEW(1, struct iccbased_cdata);
1243 init_iccbased_cdata(cdata);
1244 cdata->colorspace = colorspace;
1245 memcpy(cdata->checksum, checksum, 16);
1247 cspc_id = pdf_colorspace_findresource(ident,
1248 PDF_COLORSPACE_TYPE_ICCBASED, cdata);
1251 MESG("(ICCP:[id=%d])", cspc_id);
1252 release_iccbased_cdata(cdata);
1253 pdf_release_obj(stream);
1257 print_iccp_header(&icch, checksum);
1260 resource = pdf_new_array();
1262 pdf_add_array(resource, pdf_new_name("ICCBased"));
1263 pdf_add_array(resource, pdf_ref_obj (stream));
1265 stream_dict = pdf_stream_dict(stream);
1266 pdf_add_dict(stream_dict, pdf_new_name("N"),
1267 pdf_new_number(get_num_components_iccbased(cdata)));
1268 pdf_release_obj(stream);
1270 cspc_id = pdf_colorspace_defineresource(ident,
1271 PDF_COLORSPACE_TYPE_ICCBASED,
1291 pdf_colorspace *colorspaces;
1297 pdf_colorspace_findresource (const char *ident,
1298 int type, const void *cdata)
1300 pdf_colorspace *colorspace;
1301 int cspc_id, cmp = -1;
1304 cmp && cspc_id < cspc_cache.count; cspc_id++) {
1305 colorspace = &cspc_cache.colorspaces[cspc_id];
1306 if (colorspace->subtype != type)
1309 switch (colorspace->subtype) {
1310 case PDF_COLORSPACE_TYPE_ICCBASED:
1311 cmp = compare_iccbased(ident, cdata,
1312 colorspace->ident, colorspace->cdata);
1319 return -1; /* not found */
1323 pdf_init_colorspace_struct (pdf_colorspace *colorspace)
1327 colorspace->ident = NULL;
1328 colorspace->subtype = PDF_COLORSPACE_TYPE_INVALID;
1330 colorspace->resource = NULL;
1331 colorspace->reference = NULL;
1332 colorspace->cdata = NULL;
1338 pdf_clean_colorspace_struct (pdf_colorspace *colorspace)
1342 if (colorspace->ident)
1343 RELEASE(colorspace->ident);
1344 if (colorspace->resource)
1345 pdf_release_obj(colorspace->resource);
1346 if (colorspace->reference)
1347 pdf_release_obj(colorspace->reference);
1348 colorspace->resource = NULL;
1349 colorspace->reference = NULL;
1351 if (colorspace->cdata) {
1352 switch (colorspace->subtype) {
1353 case PDF_COLORSPACE_TYPE_ICCBASED:
1354 release_iccbased_cdata(colorspace->cdata);
1358 colorspace->cdata = NULL;
1359 colorspace->subtype = PDF_COLORSPACE_TYPE_INVALID;
1365 pdf_flush_colorspace (pdf_colorspace *colorspace)
1369 if (colorspace->resource)
1370 pdf_release_obj(colorspace->resource);
1371 if (colorspace->reference)
1372 pdf_release_obj(colorspace->reference);
1374 colorspace->resource = NULL;
1375 colorspace->reference = NULL;
1379 pdf_colorspace_defineresource (const char *ident,
1380 int subtype, void *cdata, pdf_obj *resource)
1383 pdf_colorspace *colorspace;
1385 if (cspc_cache.count >= cspc_cache.capacity) {
1386 cspc_cache.capacity += 16;
1387 cspc_cache.colorspaces = RENEW(cspc_cache.colorspaces,
1388 cspc_cache.capacity, pdf_colorspace);
1390 cspc_id = cspc_cache.count;
1391 colorspace = &cspc_cache.colorspaces[cspc_id];
1393 pdf_init_colorspace_struct(colorspace);
1395 colorspace->ident = NEW(strlen(ident) + 1, char);
1396 strcpy(colorspace->ident, ident);
1398 colorspace->subtype = subtype;
1399 colorspace->cdata = cdata;
1400 colorspace->resource = resource;
1403 MESG("(ColorSpace:%s", ident);
1406 case PDF_COLORSPACE_TYPE_ICCBASED:
1409 case PDF_COLORSPACE_TYPE_CALRGB:
1412 case PDF_COLORSPACE_TYPE_CALGRAY:
1426 pdf_get_colorspace_reference (int cspc_id)
1428 pdf_colorspace *colorspace;
1430 colorspace = &cspc_cache.colorspaces[cspc_id];
1431 if (!colorspace->reference) {
1432 colorspace->reference = pdf_ref_obj(colorspace->resource);
1433 pdf_release_obj(colorspace->resource); /* .... */
1434 colorspace->resource = NULL;
1437 return pdf_link_obj(colorspace->reference);
1442 pdf_get_colorspace_num_components (int cspc_id)
1444 pdf_colorspace *colorspace;
1447 colorspace = &cspc_cache.colorspaces[cspc_id];
1449 switch (colorspace->subtype) {
1450 case PDF_COLORSPACE_TYPE_ICCBASED:
1451 num_components = get_num_components_iccbased(colorspace->cdata);
1453 case PDF_COLORSPACE_TYPE_DEVICEGRAY:
1456 case PDF_COLORSPACE_TYPE_DEVICERGB:
1459 case PDF_COLORSPACE_TYPE_DEVICECMYK:
1462 case PDF_COLORSPACE_TYPE_CALRGB:
1465 case PDF_COLORSPACE_TYPE_CALGRAY:
1473 return num_components;
1477 pdf_get_colorspace_subtype (int cspc_id)
1479 pdf_colorspace *colorspace;
1481 colorspace = &cspc_cache.colorspaces[cspc_id];
1483 return colorspace->subtype;
1488 pdf_init_colors (void)
1490 cspc_cache.count = 0;
1491 cspc_cache.capacity = 0;
1492 cspc_cache.colorspaces = NULL;
1496 pdf_close_colors (void)
1500 for (i = 0; i < cspc_cache.count; i++) {
1501 pdf_colorspace *colorspace;
1503 colorspace = &cspc_cache.colorspaces[i];
1504 pdf_flush_colorspace(colorspace);
1505 pdf_clean_colorspace_struct(colorspace);
1507 RELEASE(cspc_cache.colorspaces);
1508 cspc_cache.colorspaces = NULL;
1509 cspc_cache.count = cspc_cache.capacity = 0;
1513 #define PDF_COLORSPACE_FAMILY_DEVICE 0
1514 #define PDF_COLORSPACE_FAMILY_CIEBASED 1
1515 #define PDF_COLORSPACE_FAMILY_SPECIAL 2