summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdfm-x/pdfcolor.c
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2013-07-29 12:13:50 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2013-07-29 12:13:50 +0000
commitde569c5d3871e3aea62a0d01e2f86d50f1202591 (patch)
treee6a1bdc5157ce11b4259419dd95039fad8a54649 /Build/source/texk/dvipdfm-x/pdfcolor.c
parent73f00680f2596baff50bd68e9d639450da2c95d2 (diff)
dvipdfm-x: Merging dvipdfmx and xdvipdfmx, now just one set of source files
git-svn-id: svn://tug.org/texlive/trunk@31302 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm-x/pdfcolor.c')
-rw-r--r--Build/source/texk/dvipdfm-x/pdfcolor.c1589
1 files changed, 1589 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/pdfcolor.c b/Build/source/texk/dvipdfm-x/pdfcolor.c
new file mode 100644
index 00000000000..191e9236429
--- /dev/null
+++ b/Build/source/texk/dvipdfm-x/pdfcolor.c
@@ -0,0 +1,1589 @@
+/*
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team.
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+/* No page independence here...
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "system.h"
+#include "mem.h"
+#include "error.h"
+
+#include "dpxfile.h"
+
+#include "pdfdoc.h"
+#include "pdfdev.h"
+
+#include "pdfcolor.h"
+
+
+static int verbose = 0;
+void
+pdf_color_set_verbose (void)
+{
+ verbose++;
+}
+
+#ifndef XETEX
+/* This function returns PDF_COLORSPACE_TYPE_GRAY,
+ * PDF_COLORSPACE_TYPE_RGB or PDF_COLORSPACE_TYPE_CMYK.
+ */
+int
+pdf_color_type (const pdf_color *color)
+{
+ ASSERT(color);
+
+ return -color->num_components;
+}
+#endif
+
+int
+pdf_color_rgbcolor (pdf_color *color, double r, double g, double b)
+{
+ ASSERT(color);
+
+ if (r < 0.0 || r > 1.0) {
+ WARN("Invalid color value specified: red=%g", r);
+ return -1;
+ }
+ if (g < 0.0 || g > 1.0) {
+ WARN("Invalid color value specified: green=%g", g);
+ return -1;
+ }
+ if (b < 0.0 || b > 1.0) {
+ WARN("Invalid color value specified: blue=%g", b);
+ return -1;
+ }
+ color->values[0] = r;
+ color->values[1] = g;
+ color->values[2] = b;
+
+ color->num_components = 3;
+
+ return 0;
+}
+
+int
+pdf_color_cmykcolor (pdf_color *color,
+ double c, double m, double y, double k)
+{
+ ASSERT(color);
+
+ if (c < 0.0 || c > 1.0) {
+ WARN("Invalid color value specified: cyan=%g", c);
+ return -1;
+ }
+ if (m < 0.0 || m > 1.0) {
+ WARN("Invalid color value specified: magenta=%g", m);
+ return -1;
+ }
+ if (y < 0.0 || y > 1.0) {
+ WARN("Invalid color value specified: yellow=%g", y);
+ return -1;
+ }
+ if (k < 0.0 || k > 1.0) {
+ WARN("Invalid color value specified: black=%g", k);
+ return -1;
+ }
+
+ color->values[0] = c;
+ color->values[1] = m;
+ color->values[2] = y;
+ color->values[3] = k;
+
+ color->num_components = 4;
+
+ return 0;
+}
+
+int
+pdf_color_graycolor (pdf_color *color, double g)
+{
+ ASSERT(color);
+
+ if (g < 0.0 || g > 1.0) {
+ WARN("Invalid color value specified: gray=%g", g);
+ return -1;
+ }
+
+ color->values[0] = g;
+
+ color->num_components = 1;
+
+ return 0;
+}
+
+
+void
+pdf_color_copycolor (pdf_color *color1, const pdf_color *color2)
+{
+ ASSERT(color1 && color2);
+
+ memcpy(color1, color2, sizeof(pdf_color));
+}
+
+/* Brighten up a color. f == 0 means no change, f == 1 means white. */
+void
+pdf_color_brighten_color (pdf_color *dst, const pdf_color *src, double f)
+{
+ ASSERT(dst && src);
+
+ if (f == 1.0) {
+ pdf_color_white(dst);
+ } else {
+ double f0, f1;
+ int n;
+
+ n = dst->num_components = src->num_components;
+ f1 = n == 4 ? 0.0 : f; /* n == 4 is CMYK, others are RGB and Gray */
+ f0 = 1.0-f;
+
+ while (n--)
+ dst->values[n] = f0 * src->values[n] + f1;
+ }
+}
+
+int
+pdf_color_is_white (const pdf_color *color)
+{
+ int n;
+ double f;
+
+ ASSERT(color);
+
+ n = color->num_components;
+ switch (n) {
+ case 1: /* Gray */
+ case 3: /* RGB */
+ f = 1.0;
+ break;
+ case 4: /* CMYK */
+ f = 0.0;
+ break;
+ default:
+ return 0;
+ }
+
+ while (n--)
+ if (color->values[n] != f)
+ return 0;
+
+ return 1;
+}
+
+#ifndef XETEX
+int
+pdf_color_to_string (const pdf_color *color, char *buffer)
+{
+ int i, len = 0;
+
+ for (i = 0; i < color->num_components; i++) {
+ len += sprintf(buffer+len, " %g", ROUND(color->values[i], 0.001));
+ }
+ return len;
+}
+#endif
+
+pdf_color current_fill = {
+ 1,
+ {0.0, 0.0, 0.0, 0.0}
+};
+
+pdf_color current_stroke = {
+ 1,
+ {0.0, 0.0, 0.0, 0.0}
+};
+
+#ifndef XETEX
+/*
+ * This routine is not a real color matching.
+ */
+int
+pdf_color_compare (const pdf_color *color1, const pdf_color *color2)
+{
+ int n;
+
+ n = color1->num_components;
+ switch (n) {
+ case 1: /* Gray */
+ case 3: /* RGB */
+ case 4: /* CMYK */
+ break;
+ default:
+ return -1;
+ }
+
+ if (n != color2->num_components)
+ return -1;
+
+ while (n--)
+ if (color1->values[n] != color2->values[n])
+ return -1;
+
+ return 0;
+}
+#endif
+
+int
+pdf_color_is_valid (const pdf_color *color)
+{
+ int n;
+
+ n = color->num_components;
+ switch (n) {
+ case 1: /* Gray */
+ case 3: /* RGB */
+ case 4: /* CMYK */
+ break;
+ default:
+ return 0;
+ }
+
+ while (n--)
+ if (color->values[n] < 0.0 || color->values[n] > 1.0) {
+ WARN("Invalid color value: %g", color->values[n]);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Dvipdfm special */
+pdf_color default_color = {
+ 1,
+ {0.0, 0.0, 0.0, 0.0}
+};
+
+void
+pdf_color_set_default (const pdf_color *color)
+{
+ pdf_color_copycolor(&default_color, color);
+}
+
+#define DEV_COLOR_STACK_MAX 128
+
+static struct {
+ int current;
+ pdf_color stroke[DEV_COLOR_STACK_MAX];
+ pdf_color fill[DEV_COLOR_STACK_MAX];
+} color_stack = {
+ 0,
+};
+
+void
+pdf_color_clear_stack (void)
+{
+ if (color_stack.current > 0) {
+ WARN("You've mistakenly made a global color change within nested colors.");
+ }
+ color_stack.current = 0;
+#ifdef XETEX
+ pdf_color_copycolor(&color_stack.stroke[color_stack.current], &default_color);
+ pdf_color_copycolor(&color_stack.fill[color_stack.current], &default_color);
+#else
+ pdf_color_black(color_stack.stroke);
+ pdf_color_black(color_stack.fill);
+#endif
+ return;
+}
+
+void
+pdf_color_set (pdf_color *sc, pdf_color *fc)
+{
+ pdf_color_copycolor(&color_stack.stroke[color_stack.current], sc);
+ pdf_color_copycolor(&color_stack.fill[color_stack.current], fc);
+ pdf_dev_reset_color(0);
+}
+
+void
+pdf_color_push (pdf_color *sc, pdf_color *fc)
+{
+ if (color_stack.current >= DEV_COLOR_STACK_MAX-1) {
+ WARN("Color stack overflow. Just ignore.");
+ } else {
+ color_stack.current++;
+#ifdef XETEX
+ pdf_color_copycolor(&color_stack.stroke[color_stack.current], sc);
+ pdf_color_copycolor(&color_stack.fill[color_stack.current], fc);
+ pdf_dev_reset_color(0);
+#else
+ pdf_color_set(sc, fc);
+#endif
+ }
+ return;
+}
+
+void
+pdf_color_pop (void)
+{
+ if (color_stack.current <= 0) {
+ WARN("Color stack underflow. Just ignore.");
+ } else {
+ color_stack.current--;
+ pdf_dev_reset_color(0);
+ }
+ return;
+}
+
+void
+pdf_color_get_current (pdf_color **sc, pdf_color **fc)
+{
+ *sc = &color_stack.stroke[color_stack.current];
+ *fc = &color_stack.fill[color_stack.current];
+ return;
+}
+
+#if 0
+/* BUG (20060330): color change does not effect on the next page.
+ * The problem is due to the part of grestore because it restores
+ * the color values in the state of gsave which are not correct
+ * if the color values are changed inside of a page.
+ */
+void
+pdf_dev_preserve_color (void)
+{
+ if (color_stack.current > 0) {
+ current_stroke = color_stack.stroke[color_stack.current];
+ current_fill = color_stack.fill[color_stack.current];
+ }
+}
+#endif
+
+/***************************** COLOR SPACE *****************************/
+
+static int pdf_colorspace_defineresource (const char *ident,
+ int subtype,
+ void *cdata, pdf_obj *resource);
+
+static int pdf_colorspace_findresource (const char *ident,
+ int subtype, const void *cdata);
+
+#if 0
+struct calgray_cdata
+{
+ double white_point[3]; /* required, second component must
+ * be equal to 1.0
+ */
+ double black_point[3]; /* optional, default: [0 0 0] */
+ double gamma; /* optional, default: 1.0 */
+};
+
+struct calrgb_cdata
+{
+ double white_point[3]; /* required, second component must
+ * be equal to 1.0
+ */
+ double black_point[3]; /* optional, default: [0 0 0] */
+ double gamma[3]; /* optional, default: [1 1 1] */
+ double matrix[9]; /* optional, default: identity
+ * [1 0 0 0 1 0 0 0 1]
+ */
+};
+
+static void
+release_calrgb (void *cdata)
+{
+ struct calrgb_cdata *calrgb;
+
+ if (cdata) {
+ calrgb = (struct calrgb_cdata *) cdata;
+ RELEASE(calrgb);
+ }
+}
+
+static int
+compare_calrgb (const char *ident1, const void *cdata1,
+ const char *ident2, const void *cdata2)
+{
+ struct calrgb_cdata *calrgb1;
+ struct calrgb_cdata *calrgb2;
+
+ if (ident1 && ident2 &&
+ !strcmp(ident1, ident2)) {
+ return 0;
+ }
+}
+
+static void
+init_calrgb (struct calrgb_cdata *calrgb)
+{
+ ASSERT(calrgb);
+
+ calrgb->white_point[0] = 1.0;
+ calrgb->white_point[1] = 1.0;
+ calrgb->white_point[2] = 1.0;
+
+ calrgb->black_point[0] = 0.0;
+ calrgb->black_point[1] = 0.0;
+ calrgb->black_point[2] = 0.0;
+
+ calrgb->gamma[0] = 1.0;
+ calrgb->gamma[1] = 1.0;
+ calrgb->gamma[2] = 1.0;
+
+ calrgb->matrix[0] = 1.0;
+ calrgb->matrix[1] = 0.0;
+ calrgb->matrix[2] = 0.0;
+
+ calrgb->matrix[3] = 0.0;
+ calrgb->matrix[4] = 1.0;
+ calrgb->matrix[5] = 0.0;
+
+ calrgb->matrix[6] = 0.0;
+ calrgb->matrix[7] = 0.0;
+ calrgb->matrix[8] = 1.0;
+}
+
+static int
+valid_calrgb (struct calrgb_cdata *calrgb)
+{
+ if (calrgb->white_point[1] != 1.0 ||
+ calrgb->white_point[0] <= 0.0 ||
+ calrgb->white_point[2] <= 0.0)
+ return 0;
+
+ if (calrgb->black_point[0] < 0.0 ||
+ calrgb->black_point[1] < 0.0 ||
+ calrgb->black_point[2] < 0.0)
+ return 0;
+
+ if (calrgb->gamma[0] < 0.0 ||
+ calrgb->gamma[1] < 0.0 ||
+ calrgb->gamma[2] < 0.0)
+ return 0;
+
+ /* matrix should be invertible? */
+
+ return 1;
+}
+
+static pdf_obj *
+pdf_color_make_calrgb_resource (struct calrgb_cdata *calrgb)
+{
+ pdf_obj *colorspace;
+ pdf_obj *calparams, *tmp_array;
+
+ ASSERT(calrgb);
+
+ if (!valid_calrgb(calrgb))
+ return NULL;
+
+ colorspace = pdf_new_array();
+ calparams = pdf_new_dict();
+
+ tmp_array = pdf_new_array();
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->white_point[0], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(1.0));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->white_point[2], 0.001)));
+ pdf_add_dict(calparams, pdf_new_name("WhitePoint"), tmp_array);
+
+ if (calrgb->black_point[0] != 0.0 ||
+ calrgb->black_point[1] != 0.0 ||
+ calrgb->black_point[2] != 0.0) {
+ tmp_array = pdf_new_array();
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[0], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[1], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->black_point[2], 0.001)));
+ pdf_add_dict(calparams, pdf_new_name("BlackPoint"), tmp_array);
+ }
+
+ if (calrgb->gamma[0] != 1.0 ||
+ calrgb->gamma[1] != 1.0 ||
+ calrgb->gamma[2] != 1.0) {
+ tmp_array = pdf_new_array();
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[0], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[1], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->gamma[2], 0.001)));
+ pdf_add_dict(calparams, pdf_new_name("Gamma"), tmp_array);
+ }
+
+ if (calrgb->matrix[0] != 1.0 ||
+ calrgb->matrix[1] != 0.0 ||
+ calrgb->matrix[2] != 0.0 ||
+ calrgb->matrix[3] != 0.0 ||
+ calrgb->matrix[4] != 1.0 ||
+ calrgb->matrix[5] != 0.0 ||
+ calrgb->matrix[6] != 0.0 ||
+ calrgb->matrix[7] != 0.0 ||
+ calrgb->matrix[8] != 1.0) {
+ tmp_array = pdf_new_array();
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[0], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[1], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[2], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[3], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[4], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[5], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[6], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[7], 0.001)));
+ pdf_add_array(tmp_array, pdf_new_number(ROUND(calrgb->matrix[8], 0.001)));
+ pdf_add_dict(calparams, pdf_new_name("Matrix"), tmp_array);
+ }
+
+ pdf_add_array(colorspace, pdf_new_name("CalRGB"));
+ pdf_add_array(colorspace, calparams);
+
+ return colorspace;
+}
+#endif
+
+static unsigned char nullbytes16[16] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static struct
+{
+ int major;
+ int minor;
+} icc_versions[] = {
+ {0, 0}, /* PDF-1.0, we don't support them */
+ {0, 0}, /* PDF-1.1, we don't support them */
+ {0, 0}, /* PDF-1.2, we don't support them */
+ {0x02, 0x10}, /* PDF-1.3 */
+ {0x02, 0x20}, /* PDF-1.4 */
+ {0x04, 0x00} /* PDF-1.5 */
+};
+
+static int
+iccp_version_supported (int major, int minor)
+{
+ int pdf_ver;
+
+ pdf_ver = pdf_get_version();
+ if (pdf_ver < 6) {
+ if (icc_versions[pdf_ver].major < major)
+ return 0;
+ else if (icc_versions[pdf_ver].major == major &&
+ icc_versions[pdf_ver].minor < minor)
+ return 0;
+ else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+typedef unsigned long iccSig;
+static iccSig
+str2iccSig (const void *s)
+{
+ const char *p;
+
+ p = (const char *) s;
+
+ return (iccSig) ((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]);
+}
+
+typedef struct
+{
+ long X, Y, Z; /* s15Fixed16Numeber */
+} iccXYZNumber;
+
+typedef struct
+{
+ long size;
+ iccSig CMMType;
+ long version;
+ iccSig devClass;
+ iccSig colorSpace;
+ iccSig PCS; /* Profile Connection Space */
+ char creationDate[12];
+ iccSig acsp;
+ iccSig platform;
+ char flags[4];
+ iccSig devMnfct;
+ iccSig devModel;
+ char devAttr[8];
+ long intent;
+ iccXYZNumber illuminant;
+ iccSig creator;
+ unsigned char ID[16]; /* MD5 checksum with Rendering intent,
+ * Header attrs, Profile ID fields are
+ * set to zeros.
+ */
+ /* 28 bytes reserved - must be set to zeros */
+} iccHeader;
+
+#define iccNullSig 0
+static void
+iccp_init_iccHeader (iccHeader *icch)
+{
+ ASSERT(icch);
+
+ icch->size = 0;
+ icch->CMMType = iccNullSig;
+ icch->version = 0xFFFFFF;
+ icch->devClass = iccNullSig;
+ icch->colorSpace = iccNullSig;
+ icch->PCS = iccNullSig;
+ memset(icch->creationDate, 0, 12);
+ icch->acsp = str2iccSig("ascp");
+ icch->platform = iccNullSig;
+ memset(icch->flags, 0, 4);
+ icch->devMnfct = iccNullSig;
+ icch->devModel = iccNullSig;
+ memset(icch->devAttr, 0, 8);
+ icch->intent = 0;
+ icch->illuminant.X = 0;
+ icch->illuminant.Y = 0;
+ icch->illuminant.Z = 0;
+ icch->creator = iccNullSig;
+ memset(icch->ID, 0, 16);
+}
+
+#define ICC_INTENT_TYPE(n) ((int) (((n) >> 16) & 0xff))
+#define ICC_INTENT_PERCEPTUAL 0
+#define ICC_INTENT_RELATIVE 1
+#define ICC_INTENT_SATURATION 2
+#define ICC_INTENT_ABSOLUTE 3
+
+/*
+ * In ICC profile stream dicrionary, there is /Range whose values must
+ * "match the information in the profile". But where is those values in?
+ *
+ * How should I treat rendering intent?
+ */
+struct iccbased_cdata
+{
+ long sig; /* 'i' 'c' 'c' 'b' */
+
+ unsigned char checksum[16]; /* 16 bytes MD5 Checksum */
+ int colorspace; /* input colorspace:
+ * RGB, Gray, CMYK, (Lab?)
+ */
+ int alternate; /* alternate colorspace (id), unused */
+};
+
+#define check_sig(d,p,q,r,s) ((d) && (d)->sig == ((p)<<24|(q)<<16|(r)<<8|(s)))
+
+static void
+init_iccbased_cdata (struct iccbased_cdata *cdata)
+{
+ ASSERT(cdata);
+
+ cdata->sig = ('i' << 24|'c' << 16|'c' << 8|'b');
+ memset(cdata->checksum, 0, 16);
+ cdata->colorspace = PDF_COLORSPACE_TYPE_INVALID;
+ cdata->alternate = -1;
+
+ return;
+}
+
+static void
+release_iccbased_cdata (struct iccbased_cdata *cdata)
+{
+ ASSERT(check_sig(cdata, 'i', 'c', 'c', 'b'));
+
+ RELEASE(cdata);
+}
+
+static int
+get_num_components_iccbased (const struct iccbased_cdata *cdata)
+{
+ int num_components = 0;
+
+ ASSERT(check_sig(cdata, 'i', 'c', 'c', 'b'));
+
+ switch (cdata->colorspace) {
+ case PDF_COLORSPACE_TYPE_RGB:
+ num_components = 3;
+ break;
+ case PDF_COLORSPACE_TYPE_CMYK:
+ num_components = 4;
+ break;
+ case PDF_COLORSPACE_TYPE_GRAY:
+ num_components = 1;
+ break;
+ case PDF_COLORSPACE_TYPE_CIELAB:
+ num_components = 3;
+ break;
+ }
+
+ return num_components;
+}
+
+static int
+compare_iccbased (const char *ident1, const struct iccbased_cdata *cdata1,
+ const char *ident2, const struct iccbased_cdata *cdata2)
+{
+ if (cdata1 && cdata2) {
+
+ ASSERT(check_sig(cdata1, 'i', 'c', 'c', 'b'));
+ ASSERT(check_sig(cdata2, 'i', 'c', 'c', 'b'));
+
+ if (memcmp(cdata1->checksum, nullbytes16, 16) &&
+ memcmp(cdata2->checksum, nullbytes16, 16)) {
+ return memcmp(cdata1->checksum, cdata2->checksum, 16);
+ }
+ if (cdata1->colorspace != cdata2->colorspace) {
+ return (cdata1->colorspace - cdata2->colorspace);
+ }
+
+ /* Continue if checksum unknown and colorspace is same. */
+ }
+
+ if (ident1 && ident2)
+ return strcmp(ident1, ident2);
+
+ /* No way to compare */
+ return -1;
+}
+
+int
+iccp_check_colorspace (int colortype, const void *profile, long proflen)
+{
+ iccSig colorspace;
+ const unsigned char *p;
+
+ if (!profile || proflen < 128)
+ return -1;
+
+ p = (const unsigned char *) profile;
+
+ colorspace = str2iccSig(p + 16);
+
+ switch (colortype) {
+ case PDF_COLORSPACE_TYPE_CALRGB:
+ case PDF_COLORSPACE_TYPE_RGB:
+ if (colorspace != str2iccSig("RGB ")) {
+ return -1;
+ }
+ break;
+ case PDF_COLORSPACE_TYPE_CALGRAY:
+ case PDF_COLORSPACE_TYPE_GRAY:
+ if (colorspace != str2iccSig("GRAY")) {
+ return -1;
+ }
+ break;
+ case PDF_COLORSPACE_TYPE_CMYK:
+ if (colorspace != str2iccSig("CMYK")) {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+pdf_obj *
+iccp_get_rendering_intent (const void *profile, long proflen)
+{
+ pdf_obj *ri = NULL;
+ const unsigned char *p;
+ long intent;
+
+ if (!profile || proflen < 128)
+ return NULL;
+
+ p = (const unsigned char *) profile;
+
+ intent = (p[64] << 24)|(p[65] << 16)|(p[66] << 8)|p[67];
+ switch (ICC_INTENT_TYPE(intent)) {
+ case ICC_INTENT_SATURATION:
+ ri = pdf_new_name("Saturation");
+ break;
+ case ICC_INTENT_PERCEPTUAL:
+ ri = pdf_new_name("Perceptual");
+ break;
+ case ICC_INTENT_ABSOLUTE:
+ ri = pdf_new_name("AbsoluteColorimetric");
+ break;
+ case ICC_INTENT_RELATIVE:
+ ri = pdf_new_name("RelativeColorimetric");
+ break;
+ default:
+ WARN("Invalid rendering intent type: %d", ICC_INTENT_TYPE(intent));
+ ri = NULL;
+ }
+
+ return ri;
+}
+
+#define sget_signed_long(p) ((long) ((p)[0] << 24|(p)[1] << 16|(p)[2] << 8|(p)[3]))
+#define sget_signed_short(p) ((short) ((p)[0] << 8|(p)[1]))
+#define get_iccSig(p) ((iccSig) ((p)[0] << 24|(p)[1] << 16|(p)[2] << 8|(p)[3]))
+
+static int
+iccp_unpack_header (iccHeader *icch,
+ const void *profile, long proflen, int check_size)
+{
+ const unsigned char *p, *endptr;
+
+ if (check_size) {
+ if (!profile || proflen < 128 ||
+ proflen % 4 != 0) {
+ WARN("Profile size: %ld", proflen);
+ return -1;
+ }
+ }
+
+ p = (const unsigned char *) profile;
+ endptr = p + 128;
+
+ icch->size = sget_signed_long(p);
+ if (check_size) {
+ if (icch->size != proflen) {
+ WARN("ICC Profile size: %ld(header) != %ld", icch->size, proflen);
+ return -1;
+ }
+ }
+ p += 4;
+
+ icch->CMMType = str2iccSig(p);
+ p += 4;
+ icch->version = sget_signed_long(p);
+ p += 4;
+ icch->devClass = str2iccSig(p);
+ p += 4;
+ icch->colorSpace = str2iccSig(p);
+ p += 4;
+ icch->PCS = str2iccSig(p);
+ p += 4;
+ memcpy(icch->creationDate, p, 12);
+ p += 12;
+ icch->acsp = str2iccSig(p); /* acsp */
+ if (icch->acsp != str2iccSig("acsp")) {
+ WARN("Invalid ICC profile: not \"acsp\" - %c%c%c%c ",
+ p[0], p[1], p[2], p[3]);
+ return -1;
+ }
+ p += 4;
+ icch->platform = str2iccSig(p);
+ p += 4;
+ memcpy(icch->flags, p, 4);
+ p += 4;
+ icch->devMnfct = str2iccSig(p);
+ p += 4;
+ icch->devModel = str2iccSig(p);
+ p += 4;
+ memcpy(icch->devAttr, p, 8);
+ p += 8;
+ icch->intent = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
+ p += 4;
+ icch->illuminant.X = sget_signed_long(p);
+ p += 4;
+ icch->illuminant.Y = sget_signed_long(p);
+ p += 4;
+ icch->illuminant.Z = sget_signed_long(p);
+ p += 4;
+ icch->creator = str2iccSig(p);
+ p += 4;
+ memcpy(icch->ID, p, 16);
+ p += 16;
+
+ /* 28 bytes reserved - must be set to zeros */
+ for (; p < endptr; p++) {
+ if (*p != '\0') {
+ WARN("Reserved pad not zero: %02x (at offset %ld in ICC profile header.)",
+ *p, 128 - ((long) (endptr - p)));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* MD5 checksum with Rendering intent,
+ * Header attrs, Profile ID fields are
+ * set to zeros.
+ */
+#define ICC_HEAD_SECT1_START 0
+#define ICC_HEAD_SECT1_LENGTH 56
+/* 8 bytes devAttr, 4 bytes intent */
+#define ICC_HEAD_SECT2_START 68
+#define ICC_HEAD_SECT2_LENGTH 16
+/* 16 bytes ID (checksum) */
+#define ICC_HEAD_SECT3_START 100
+#define ICC_HEAD_SECT3_LENGTH 28
+
+#include "dpxcrypt.h"
+static void
+iccp_get_checksum (unsigned char *checksum, const void *profile, long proflen)
+{
+ const unsigned char *p;
+ MD5_CONTEXT md5;
+
+ p = (const unsigned char *) profile;
+
+ MD5_init (&md5);
+ MD5_write(&md5, p + ICC_HEAD_SECT1_START, ICC_HEAD_SECT1_LENGTH);
+ MD5_write(&md5, nullbytes16, 12);
+ MD5_write(&md5, p + ICC_HEAD_SECT2_START, ICC_HEAD_SECT2_LENGTH);
+ MD5_write(&md5, nullbytes16, 16);
+ MD5_write(&md5, p + ICC_HEAD_SECT3_START, ICC_HEAD_SECT3_LENGTH);
+
+ /* body */
+ MD5_write(&md5, p + 128, proflen - 128);
+
+ MD5_final(checksum, &md5);
+}
+
+static void
+print_iccp_header (iccHeader *icch, unsigned char *checksum)
+{
+ int i;
+
+ ASSERT(icch);
+
+#define print_iccSig(s,t) if ((s) == 0) {\
+ MESG("pdf_color>> %s:\t(null)\n", (t)); \
+ } else if (!isprint(((s) >> 24) & 0xff) || \
+ !isprint(((s) >> 16) & 0xff) || \
+ !isprint(((s) >> 8) & 0xff) || \
+ !isprint((s) & 0xff)) { \
+ MESG("pdf_color>> %s:\t(invalid)\n", (t)); \
+ } else { \
+ MESG("pdf_color>> %s:\t%c%c%c%c\n", (t), \
+ ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, \
+ ((s) >> 8) & 0xff, (s) & 0xff); \
+}
+
+ MESG("\n");
+ MESG("pdf_color>> ICC Profile Info\n");
+ MESG("pdf_color>> Profile Size:\t%ld bytes\n", icch->size);
+ print_iccSig(icch->CMMType, "CMM Type");
+ MESG("pdf_color>> Profile Version:\t%d.%01d.%01d\n",
+ (icch->version >> 24) & 0xff,
+ (icch->version >> 20) & 0x0f,
+ (icch->version >> 16) & 0x0f);
+ print_iccSig(icch->devClass, "Device Class");
+ print_iccSig(icch->colorSpace, "Color Space");
+ print_iccSig(icch->PCS, "Connection Space");
+ MESG("pdf_color>> Creation Date:\t");
+ for (i = 0; i < 12; i += 2) {
+ if (i == 0)
+ MESG("%04u",
+ sget_unsigned_pair((unsigned char *) icch->creationDate));
+ else {
+ MESG(":%02u",
+ sget_unsigned_pair((unsigned char *) (&icch->creationDate[i])));
+ }
+ }
+ MESG("\n");
+ print_iccSig(icch->platform, "Primary Platform");
+ MESG("pdf_color>> Profile Flags:\t%02x:%02x:%02x:%02x\n",
+ icch->flags[0], icch->flags[1], icch->flags[2], icch->flags[3]);
+ print_iccSig(icch->devMnfct, "Device Mnfct");
+ print_iccSig(icch->devModel, "Device Model");
+ MESG("pdf_color>> Device Attr:\t");
+ for (i = 0; i < 8; i++) {
+ if (i == 0)
+ MESG("%02x", icch->devAttr[i]);
+ else
+ MESG(":%02x", icch->devAttr[i]);
+ }
+ MESG("\n");
+ MESG("pdf_color>> Rendering Intent:\t");
+ switch (ICC_INTENT_TYPE(icch->intent)) {
+ case ICC_INTENT_SATURATION:
+ MESG("Saturation");
+ break;
+ case ICC_INTENT_PERCEPTUAL:
+ MESG("Perceptual");
+ break;
+ case ICC_INTENT_ABSOLUTE:
+ MESG("Absolute Colorimetric");
+ break;
+ case ICC_INTENT_RELATIVE:
+ MESG("Relative Colorimetric");
+ break;
+ default:
+ MESG("(invalid)");
+ break;
+ }
+ MESG("\n");
+ print_iccSig(icch->creator, "Creator");
+ MESG("pdf_color>> Illuminant (XYZ):\t");
+ MESG("%.3f %.3f %.3f\n",
+ (double) icch->illuminant.X / 0x10000,
+ (double) icch->illuminant.Y / 0x10000,
+ (double) icch->illuminant.Z / 0x10000);
+ MESG("pdf_color>> Checksum:\t");
+ if (!memcmp(icch->ID, nullbytes16, 16)) {
+ MESG("(null)");
+ } else {
+ for (i = 0; i < 16; i++) {
+ if (i == 0)
+ MESG("%02x", icch->ID[i]);
+ else
+ MESG(":%02x", icch->ID[i]);
+ }
+ }
+ MESG("\n");
+ if (checksum) {
+ MESG("pdf_color>> Calculated:\t");
+ for (i = 0; i < 16; i++) {
+ if (i == 0)
+ MESG("%02x", checksum[i]);
+ else
+ MESG(":%02x", checksum[i]);
+ }
+ MESG("\n");
+ }
+
+ return;
+}
+
+
+static int
+iccp_devClass_allowed (int dev_class)
+{
+ int colormode;
+
+ colormode = pdf_dev_get_param(PDF_DEV_PARAM_COLORMODE);
+
+ switch (colormode) {
+#if 0
+ case PDF_DEV_COLORMODE_PDFX1:
+ break;
+ case PDF_DEV_COLORMODE_PDFX3:
+ if (dev_class != str2iccSig("prtr")) {
+ return 0;
+ }
+ break;
+#endif
+ default:
+ if (dev_class != str2iccSig("scnr") &&
+ dev_class != str2iccSig("mntr") &&
+ dev_class != str2iccSig("prtr") &&
+ dev_class != str2iccSig("spac")) {
+ return 0;
+ }
+ break;
+ }
+
+
+ return 1;
+}
+
+int
+iccp_load_profile (const char *ident,
+ const void *profile, long proflen)
+{
+ int cspc_id;
+ pdf_obj *resource;
+ pdf_obj *stream;
+ pdf_obj *stream_dict;
+ iccHeader icch;
+ int colorspace;
+ unsigned char checksum[16];
+ struct iccbased_cdata *cdata;
+
+ iccp_init_iccHeader(&icch);
+ if (iccp_unpack_header(&icch, profile, proflen, 1) < 0) { /* check size */
+ WARN("Invalid ICC profile header in \"%s\"", ident);
+ print_iccp_header(&icch, NULL);
+ return -1;
+ }
+
+ if (!iccp_version_supported((icch.version >> 24) & 0xff,
+ (icch.version >> 16) & 0xff)) {
+ WARN("ICC profile format spec. version %d.%01d.%01d"
+ " not supported in current PDF version setting.",
+ (icch.version >> 24) & 0xff,
+ (icch.version >> 20) & 0x0f,
+ (icch.version >> 16) & 0x0f);
+ WARN("ICC profile not embedded.");
+ print_iccp_header(&icch, NULL);
+ return -1;
+ }
+
+ if (!iccp_devClass_allowed(icch.devClass)) {
+ WARN("Unsupported ICC Profile Device Class:");
+ print_iccp_header(&icch, NULL);
+ return -1;
+ }
+
+ if (icch.colorSpace == str2iccSig("RGB ")) {
+ colorspace = PDF_COLORSPACE_TYPE_RGB;
+ } else if (icch.colorSpace == str2iccSig("GRAY")) {
+ colorspace = PDF_COLORSPACE_TYPE_GRAY;
+ } else if (icch.colorSpace == str2iccSig("CMYK")) {
+ colorspace = PDF_COLORSPACE_TYPE_CMYK;
+ } else {
+ WARN("Unsupported input color space.");
+ print_iccp_header(&icch, NULL);
+ return -1;
+ }
+
+ iccp_get_checksum(checksum, profile, proflen);
+ if (memcmp(icch.ID, nullbytes16, 16) &&
+ memcmp(icch.ID, checksum, 16)) {
+ WARN("Invalid ICC profile: Inconsistent checksum.");
+ print_iccp_header(&icch, checksum);
+ return -1;
+ }
+
+ cdata = NEW(1, struct iccbased_cdata);
+ init_iccbased_cdata(cdata);
+ cdata->colorspace = colorspace;
+ memcpy(cdata->checksum, checksum, 16);
+
+ cspc_id = pdf_colorspace_findresource(ident,
+ PDF_COLORSPACE_TYPE_ICCBASED, cdata);
+ if (cspc_id >= 0) {
+ if (verbose)
+ MESG("(ICCP:[id=%d])", cspc_id);
+ release_iccbased_cdata(cdata);
+ return cspc_id;
+ }
+ if (verbose > 1) {
+ print_iccp_header(&icch, checksum);
+ }
+
+ resource = pdf_new_array();
+
+ stream = pdf_new_stream(STREAM_COMPRESS);
+ pdf_add_array(resource, pdf_new_name("ICCBased"));
+ pdf_add_array(resource, pdf_ref_obj (stream));
+
+ stream_dict = pdf_stream_dict(stream);
+ pdf_add_dict(stream_dict, pdf_new_name("N"),
+ pdf_new_number(get_num_components_iccbased(cdata)));
+
+ pdf_add_stream (stream, profile, proflen);
+ pdf_release_obj(stream);
+
+ cspc_id = pdf_colorspace_defineresource(ident,
+ PDF_COLORSPACE_TYPE_ICCBASED,
+ cdata, resource);
+
+ return cspc_id;
+}
+
+#ifdef XETEX
+#define WBUF_SIZE 4096
+static unsigned char wbuf[WBUF_SIZE];
+
+static pdf_obj *
+iccp_load_file_stream (unsigned char *checksum, long length, FILE *fp)
+{
+ pdf_obj *stream;
+ MD5_CONTEXT md5;
+ long nb_read;
+
+ rewind(fp);
+
+ if (fread(wbuf, 1, 128, fp) != 128) {
+ return NULL;
+ }
+ length -= 128;
+
+ stream = pdf_new_stream(STREAM_COMPRESS);
+
+ MD5_init (&md5);
+ MD5_write(&md5, wbuf + ICC_HEAD_SECT1_START, ICC_HEAD_SECT1_LENGTH);
+ MD5_write(&md5, nullbytes16, 12);
+ MD5_write(&md5, wbuf + ICC_HEAD_SECT2_START, ICC_HEAD_SECT2_LENGTH);
+ MD5_write(&md5, nullbytes16, 16);
+ MD5_write(&md5, wbuf + ICC_HEAD_SECT3_START, ICC_HEAD_SECT3_LENGTH);
+
+ pdf_add_stream(stream, wbuf, 128);
+
+ /* body */
+ while (length > 0) {
+ nb_read = fread(wbuf, 1, MIN(length, WBUF_SIZE), fp);
+ MD5_write(&md5, wbuf, nb_read);
+ pdf_add_stream(stream, wbuf, nb_read);
+ length -= nb_read;
+ }
+
+ MD5_final(checksum, &md5);
+
+
+ return stream;
+}
+
+int
+pdf_colorspace_load_ICCBased (const char *ident, const char *filename)
+{
+ int cspc_id;
+ FILE *fp;
+ pdf_obj *resource;
+ pdf_obj *stream;
+ pdf_obj *stream_dict;
+ iccHeader icch;
+ int colorspace;
+ long size;
+ unsigned char checksum[16];
+ struct iccbased_cdata *cdata;
+
+
+ fp = DPXFOPEN(filename, DPX_RES_TYPE_ICCPROFILE);
+ if (!fp)
+ return -1;
+
+ size = file_size(fp);
+ if (size < 128) {
+ MFCLOSE(fp);
+ return -1;
+ }
+ if (fread(wbuf, 1, 128, fp) != 128) {
+ DPXFCLOSE(fp);
+ return -1;
+ }
+
+ iccp_init_iccHeader(&icch);
+ if (iccp_unpack_header(&icch, wbuf, 128, 0) < 0) {
+ WARN("Invalid ICC profile header in \"%s\"", ident);
+ print_iccp_header(&icch, NULL);
+ DPXFCLOSE(fp);
+ return -1;
+ }
+ if (icch.size > size) {
+ WARN("File size smaller than recorded in header: %ld %ld",
+ icch.size, size);
+ DPXFCLOSE(fp);
+ return -1;
+ }
+
+ if (!iccp_version_supported((icch.version >> 24) & 0xff,
+ (icch.version >> 16) & 0xff)) {
+ WARN("ICC profile format spec. version %d.%01d.%01d"
+ " not supported in current PDF version setting.",
+ (icch.version >> 24) & 0xff,
+ (icch.version >> 20) & 0x0f,
+ (icch.version >> 16) & 0x0f);
+ WARN("ICC profile not embedded.");
+ print_iccp_header(&icch, NULL);
+ DPXFCLOSE(fp);
+ return -1;
+ }
+
+ if (!iccp_devClass_allowed(icch.devClass)) {
+ WARN("Unsupported ICC Profile Device Class:");
+ print_iccp_header(&icch, NULL);
+ DPXFCLOSE(fp);
+ return -1;
+ }
+
+ if (icch.colorSpace == str2iccSig("RGB ")) {
+ colorspace = PDF_COLORSPACE_TYPE_RGB;
+ } else if (icch.colorSpace == str2iccSig("GRAY")) {
+ colorspace = PDF_COLORSPACE_TYPE_GRAY;
+ } else if (icch.colorSpace == str2iccSig("CMYK")) {
+ colorspace = PDF_COLORSPACE_TYPE_CMYK;
+ } else {
+ WARN("Unsupported input color space.");
+ print_iccp_header(&icch, NULL);
+ DPXFCLOSE(fp);
+ return -1;
+ }
+
+ stream = iccp_load_file_stream(checksum, icch.size, fp);
+ DPXFCLOSE(fp);
+
+ if (!stream) {
+ WARN("Loading ICC Profile failed...: %s", filename);
+ return -1;
+ }
+
+ if (memcmp(icch.ID, nullbytes16, 16) &&
+ memcmp(icch.ID, checksum, 16)) {
+ WARN("Invalid ICC profile: Inconsistent checksum.");
+ print_iccp_header(&icch, NULL);
+ pdf_release_obj(stream);
+ return -1;
+ }
+
+ cdata = NEW(1, struct iccbased_cdata);
+ init_iccbased_cdata(cdata);
+ cdata->colorspace = colorspace;
+ memcpy(cdata->checksum, checksum, 16);
+
+ cspc_id = pdf_colorspace_findresource(ident,
+ PDF_COLORSPACE_TYPE_ICCBASED, cdata);
+ if (cspc_id >= 0) {
+ if (verbose)
+ MESG("(ICCP:[id=%d])", cspc_id);
+ release_iccbased_cdata(cdata);
+ pdf_release_obj(stream);
+ return cspc_id;
+ }
+ if (verbose > 1) {
+ print_iccp_header(&icch, checksum);
+ }
+
+ resource = pdf_new_array();
+
+ pdf_add_array(resource, pdf_new_name("ICCBased"));
+ pdf_add_array(resource, pdf_ref_obj (stream));
+
+ stream_dict = pdf_stream_dict(stream);
+ pdf_add_dict(stream_dict, pdf_new_name("N"),
+ pdf_new_number(get_num_components_iccbased(cdata)));
+ pdf_release_obj(stream);
+
+ cspc_id = pdf_colorspace_defineresource(ident,
+ PDF_COLORSPACE_TYPE_ICCBASED,
+ cdata, resource);
+
+ return cspc_id;
+}
+#endif
+
+typedef struct {
+ char *ident;
+ int subtype;
+
+ pdf_obj *resource;
+ pdf_obj *reference;
+
+ void *cdata;
+} pdf_colorspace;
+
+static struct {
+ int count;
+ int capacity;
+ pdf_colorspace *colorspaces;
+} cspc_cache = {
+ 0, 0, NULL
+};
+
+int
+pdf_colorspace_findresource (const char *ident,
+ int type, const void *cdata)
+{
+ pdf_colorspace *colorspace;
+ int cspc_id, cmp = -1;
+
+ for (cspc_id = 0;
+ cmp && cspc_id < cspc_cache.count; cspc_id++) {
+ colorspace = &cspc_cache.colorspaces[cspc_id];
+ if (colorspace->subtype != type)
+ continue;
+
+ switch (colorspace->subtype) {
+ case PDF_COLORSPACE_TYPE_ICCBASED:
+ cmp = compare_iccbased(ident, cdata,
+ colorspace->ident, colorspace->cdata);
+ break;
+ }
+ if (!cmp)
+ return cspc_id;
+ }
+
+ return -1; /* not found */
+}
+
+static void
+pdf_init_colorspace_struct (pdf_colorspace *colorspace)
+{
+ ASSERT(colorspace);
+
+ colorspace->ident = NULL;
+ colorspace->subtype = PDF_COLORSPACE_TYPE_INVALID;
+
+ colorspace->resource = NULL;
+ colorspace->reference = NULL;
+ colorspace->cdata = NULL;
+
+ return;
+}
+
+static void
+pdf_clean_colorspace_struct (pdf_colorspace *colorspace)
+{
+ ASSERT(colorspace);
+
+ if (colorspace->ident)
+ RELEASE(colorspace->ident);
+ if (colorspace->resource)
+ pdf_release_obj(colorspace->resource);
+ if (colorspace->reference)
+ pdf_release_obj(colorspace->reference);
+ colorspace->resource = NULL;
+ colorspace->reference = NULL;
+
+ if (colorspace->cdata) {
+ switch (colorspace->subtype) {
+ case PDF_COLORSPACE_TYPE_ICCBASED:
+ release_iccbased_cdata(colorspace->cdata);
+ break;
+ }
+ }
+ colorspace->cdata = NULL;
+ colorspace->subtype = PDF_COLORSPACE_TYPE_INVALID;
+
+ return;
+}
+
+static void
+pdf_flush_colorspace (pdf_colorspace *colorspace)
+{
+ ASSERT(colorspace);
+
+ if (colorspace->resource)
+ pdf_release_obj(colorspace->resource);
+ if (colorspace->reference)
+ pdf_release_obj(colorspace->reference);
+
+ colorspace->resource = NULL;
+ colorspace->reference = NULL;
+}
+
+int
+pdf_colorspace_defineresource (const char *ident,
+ int subtype, void *cdata, pdf_obj *resource)
+{
+ int cspc_id;
+ pdf_colorspace *colorspace;
+
+ if (cspc_cache.count >= cspc_cache.capacity) {
+ cspc_cache.capacity += 16;
+ cspc_cache.colorspaces = RENEW(cspc_cache.colorspaces,
+ cspc_cache.capacity, pdf_colorspace);
+ }
+ cspc_id = cspc_cache.count;
+ colorspace = &cspc_cache.colorspaces[cspc_id];
+
+ pdf_init_colorspace_struct(colorspace);
+ if (ident) {
+ colorspace->ident = NEW(strlen(ident) + 1, char);
+ strcpy(colorspace->ident, ident);
+ }
+ colorspace->subtype = subtype;
+ colorspace->cdata = cdata;
+ colorspace->resource = resource;
+
+ if (verbose) {
+ MESG("(ColorSpace:%s", ident);
+ if (verbose > 1) {
+ switch (subtype) {
+ case PDF_COLORSPACE_TYPE_ICCBASED:
+ MESG("[ICCBased]");
+ break;
+ case PDF_COLORSPACE_TYPE_CALRGB:
+ MESG("[CalRGB]");
+ break;
+ case PDF_COLORSPACE_TYPE_CALGRAY:
+ MESG("[CalGray]");
+ break;
+ }
+ }
+ MESG(")");
+ }
+
+ cspc_cache.count++;
+
+ return cspc_id;
+}
+
+pdf_obj *
+pdf_get_colorspace_reference (int cspc_id)
+{
+ pdf_colorspace *colorspace;
+
+ colorspace = &cspc_cache.colorspaces[cspc_id];
+ if (!colorspace->reference) {
+ colorspace->reference = pdf_ref_obj(colorspace->resource);
+ pdf_release_obj(colorspace->resource); /* .... */
+ colorspace->resource = NULL;
+ }
+
+ return pdf_link_obj(colorspace->reference);
+}
+
+#if 0
+int
+pdf_get_colorspace_num_components (int cspc_id)
+{
+ pdf_colorspace *colorspace;
+ int num_components;
+
+ colorspace = &cspc_cache.colorspaces[cspc_id];
+
+ switch (colorspace->subtype) {
+ case PDF_COLORSPACE_TYPE_ICCBASED:
+ num_components = get_num_components_iccbased(colorspace->cdata);
+ break;
+ case PDF_COLORSPACE_TYPE_DEVICEGRAY:
+ num_components = 1;
+ break;
+ case PDF_COLORSPACE_TYPE_DEVICERGB:
+ num_components = 3;
+ break;
+ case PDF_COLORSPACE_TYPE_DEVICECMYK:
+ num_components = 4;
+ break;
+ case PDF_COLORSPACE_TYPE_CALRGB:
+ num_components = 3;
+ break;
+ case PDF_COLORSPACE_TYPE_CALGRAY:
+ num_components = 1;
+ break;
+ default:
+ num_components = 0;
+ break;
+ }
+
+ return num_components;
+}
+
+int
+pdf_get_colorspace_subtype (int cspc_id)
+{
+ pdf_colorspace *colorspace;
+
+ colorspace = &cspc_cache.colorspaces[cspc_id];
+
+ return colorspace->subtype;
+}
+#endif
+
+void
+pdf_init_colors (void)
+{
+ cspc_cache.count = 0;
+ cspc_cache.capacity = 0;
+ cspc_cache.colorspaces = NULL;
+}
+
+void
+pdf_close_colors (void)
+{
+ int i;
+
+ for (i = 0; i < cspc_cache.count; i++) {
+ pdf_colorspace *colorspace;
+
+ colorspace = &cspc_cache.colorspaces[i];
+ pdf_flush_colorspace(colorspace);
+ pdf_clean_colorspace_struct(colorspace);
+ }
+ RELEASE(cspc_cache.colorspaces);
+ cspc_cache.colorspaces = NULL;
+ cspc_cache.count = cspc_cache.capacity = 0;
+
+}
+
+#define PDF_COLORSPACE_FAMILY_DEVICE 0
+#define PDF_COLORSPACE_FAMILY_CIEBASED 1
+#define PDF_COLORSPACE_FAMILY_SPECIAL 2