summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2004-10-19 04:51:11 +0200
committerTor Andersson <tor@ghostscript.com>2004-10-19 04:51:11 +0200
commit117725ec61dc4953f4070dacfb2aab7024a7df36 (patch)
treed4287e8e4ae99f71a154f0d2235c5b3bad71a033
parent3342d0657522d6b3acaae5216b7026165154ab52 (diff)
downloadmupdf-117725ec61dc4953f4070dacfb2aab7024a7df36.tar.xz
oops. forgot colorspace.c
-rw-r--r--mupdf/colorspace.c538
1 files changed, 538 insertions, 0 deletions
diff --git a/mupdf/colorspace.c b/mupdf/colorspace.c
new file mode 100644
index 00000000..4ec7e26e
--- /dev/null
+++ b/mupdf/colorspace.c
@@ -0,0 +1,538 @@
+#include <fitz.h>
+#include <mupdf.h>
+
+static void initcs(fz_colorspace *cs, char *name, int n,
+ void(*to)(fz_colorspace*,float*,float*),
+ void(*from)(fz_colorspace*,float*,float*),
+ void(*free)(fz_colorspace*))
+{
+ strlcpy(cs->name, name, sizeof cs->name);
+ cs->frozen = 0;
+ cs->n = n;
+ cs->toxyz = to;
+ cs->fromxyz = from;
+ cs->free = free;
+}
+
+static void mat3x3inv(float *dst, float *m)
+{
+ float det;
+ int i;
+
+#define M3(m,i,j) (m)[3*i+j]
+#define D2(a,b,c,d) (a * d - b * c)
+#define D3(a1,a2,a3,b1,b2,b3,c1,c2,c3) \
+ (a1 * D2(b2,b3,c2,c3)) - \
+ (b1 * D2(a2,a3,c2,c3)) + \
+ (c1 * D2(a2,a3,b2,b3))
+
+ det = D3(M3(m,0,0), M3(m,1,0), M3(m,2,0),
+ M3(m,0,1), M3(m,1,1), M3(m,2,1),
+ M3(m,0,2), M3(m,1,2), M3(m,2,2));
+ if (det == 0)
+ det = 1.0;
+ det = 1.0 / det;
+
+ M3(dst,0,0) = M3(m,1,1) * M3(m,2,2) - M3(m,1,2) * M3(m,2,1);
+ M3(dst,0,1) = -M3(m,0,1) * M3(m,2,2) + M3(m,0,2) * M3(m,2,1);
+ M3(dst,0,2) = M3(m,0,1) * M3(m,1,2) - M3(m,0,2) * M3(m,1,1);
+
+ M3(dst,1,0) = -M3(m,1,0) * M3(m,2,2) + M3(m,1,2) * M3(m,2,0);
+ M3(dst,1,1) = M3(m,0,0) * M3(m,2,2) - M3(m,0,2) * M3(m,2,0);
+ M3(dst,1,2) = -M3(m,0,0) * M3(m,1,2) + M3(m,0,2) * M3(m,1,0);
+
+ M3(dst,2,0) = M3(m,1,0) * M3(m,2,1) - M3(m,1,1) * M3(m,2,0);
+ M3(dst,2,1) = -M3(m,0,0) * M3(m,2,1) + M3(m,0,1) * M3(m,2,0);
+ M3(dst,2,2) = M3(m,0,0) * M3(m,1,1) - M3(m,0,1) * M3(m,1,0);
+
+ for (i = 0; i < 9; i++)
+ dst[i] *= det;
+}
+
+/*
+ * DeviceGray
+ */
+
+struct calgray
+{
+ fz_colorspace super;
+ float white[3];
+ float black[3];
+ float gamma;
+};
+
+static void graytoxyz(fz_colorspace *fzcs, float *gray, float *xyz)
+{
+ struct calgray *cs = (struct calgray *) fzcs;
+ xyz[0] = cs->white[0] * pow(gray[0], cs->gamma);
+ xyz[1] = cs->white[1] * pow(gray[0], cs->gamma);
+ xyz[2] = cs->white[2] * pow(gray[0], cs->gamma);
+}
+
+static void xyztogray(fz_colorspace *fzcs, float *xyz, float *gray)
+{
+ struct calgray *cs = (struct calgray *) fzcs;
+ float r = pow(xyz[0], 1.0 / cs->gamma);
+ float g = pow(xyz[1], 1.0 / cs->gamma);
+ float b = pow(xyz[2], 1.0 / cs->gamma);
+ gray[0] = r * 0.3 + g * 0.59 + b * 0.11;
+}
+
+static struct calgray kdevicegray =
+{
+ { "DeviceGray", 1, 1, graytoxyz, xyztogray, nil },
+ { 1.0000, 1.0000, 1.0000 },
+ { 0.0000, 0.0000, 0.0000 },
+ 2.2000
+};
+
+fz_colorspace *pdf_devicegray = &kdevicegray.super;
+
+static fz_error *
+newcalgray(fz_colorspace **csp, float *white, float *black, float gamma)
+{
+ struct calgray *cs;
+ int i;
+
+ cs = fz_malloc(sizeof(struct calgray));
+ if (!cs)
+ return fz_outofmem;
+
+ initcs((fz_colorspace*)cs, "CalGray", 1, graytoxyz, xyztogray, nil);
+
+ for (i = 0; i < 3; i++)
+ {
+ cs->white[i] = white[i];
+ cs->black[i] = black[i];
+ }
+
+ cs->gamma = gamma;
+
+ *csp = (fz_colorspace*) cs;
+ return nil;
+}
+
+/*
+ * DeviceRGB
+ */
+
+struct calrgb
+{
+ fz_colorspace super;
+ float white[3];
+ float black[3];
+ float gamma[3];
+ float matrix[9];
+ float invmat[9];
+};
+
+static void rgbtoxyz(fz_colorspace *fzcs, float *rgb, float *xyz)
+{
+ struct calrgb *cs = (struct calrgb *) fzcs;
+ float a = pow(rgb[0], cs->gamma[0]);
+ float b = pow(rgb[1], cs->gamma[1]);
+ float c = pow(rgb[2], cs->gamma[2]);
+ xyz[0] = a * cs->matrix[0] + b * cs->matrix[1] + c * cs->matrix[2];
+ xyz[1] = a * cs->matrix[3] + b * cs->matrix[4] + c * cs->matrix[5];
+ xyz[2] = a * cs->matrix[6] + b * cs->matrix[7] + c * cs->matrix[8];
+}
+
+static void xyztorgb(fz_colorspace *fzcs, float *xyz, float *rgb)
+{
+ struct calrgb *cs = (struct calrgb *) fzcs;
+ float a = xyz[0] * cs->invmat[0] + xyz[1] * cs->invmat[1] + xyz[2] * cs->invmat[2];
+ float b = xyz[0] * cs->invmat[3] + xyz[1] * cs->invmat[4] + xyz[2] * cs->invmat[5];
+ float c = xyz[0] * cs->invmat[6] + xyz[1] * cs->invmat[7] + xyz[2] * cs->invmat[8];
+ rgb[0] = pow(a, 1.0 / cs->gamma[0]);
+ rgb[1] = pow(b, 1.0 / cs->gamma[1]);
+ rgb[2] = pow(c, 1.0 / cs->gamma[2]);
+}
+
+static struct calrgb kdevicergb =
+{
+ { "DeviceRGB", 1, 3, rgbtoxyz, xyztorgb, nil },
+ { 1.0000, 1.0000, 1.0000 },
+ { 0.0000, 0.0000, 0.0000 },
+ { 2.2000, 2.2000, 2.2000 },
+ { 1.0000, 0.0000, 0.0000,
+ 0.0000, 1.0000, 0.0000,
+ 0.0000, 0.0000, 1.0000 },
+ { 1.0000, 0.0000, 0.0000,
+ 0.0000, 1.0000, 0.0000,
+ 0.0000, 0.0000, 1.0000 }
+};
+
+fz_colorspace *pdf_devicergb = &kdevicergb.super;
+
+static fz_error *
+newcalrgb(fz_colorspace **csp, float *white, float *black, float *gamma, float *matrix)
+{
+ struct calrgb *cs;
+ int i;
+
+ cs = fz_malloc(sizeof(struct calrgb));
+ if (!cs)
+ return fz_outofmem;
+
+ initcs((fz_colorspace*)cs, "CalRGB", 3, rgbtoxyz, xyztorgb, nil);
+
+ for (i = 0; i < 3; i++)
+ {
+ cs->white[i] = white[i];
+ cs->black[i] = black[i];
+ cs->gamma[i] = gamma[i];
+ }
+
+ for (i = 0; i < 9; i++)
+ cs->matrix[i] = matrix[i];
+
+ mat3x3inv(cs->invmat, cs->matrix);
+
+ *csp = (fz_colorspace*) cs;
+ return nil;
+}
+
+/*
+ * DeviceCMYK
+ */
+
+static void devicecmyktoxyz(fz_colorspace *cs, float *cmyk, float *xyz)
+{
+ float rgb[3];
+ rgb[0] = 1.0 - MIN(1.0, cmyk[0] + cmyk[3]);
+ rgb[1] = 1.0 - MIN(1.0, cmyk[1] + cmyk[3]);
+ rgb[2] = 1.0 - MIN(1.0, cmyk[2] + cmyk[3]);
+ rgbtoxyz(pdf_devicergb, rgb, xyz);
+}
+
+static void xyztodevicecmyk(fz_colorspace *cs, float *xyz, float *cmyk)
+{
+ float rgb[3];
+ xyztorgb(pdf_devicergb, xyz, rgb);
+ float c = 1.0 - rgb[0];
+ float m = 1.0 - rgb[0];
+ float y = 1.0 - rgb[0];
+ float k = MIN(c, MIN(y, k));
+ cmyk[0] = c - k;
+ cmyk[1] = m - k;
+ cmyk[2] = y - k;
+ cmyk[3] = k;
+}
+
+static fz_colorspace kdevicecmyk =
+{
+ "DeviceCMYK", 1, 4, devicecmyktoxyz, xyztodevicecmyk, nil
+};
+
+fz_colorspace *pdf_devicecmyk = &kdevicecmyk;
+
+/*
+ * CIE Lab
+ */
+
+struct cielab
+{
+ fz_colorspace super;
+ float white[3];
+ float black[3];
+ float range[4];
+};
+
+static inline float cielabg(float x)
+{
+ if (x >= 6.0 / 29.0)
+ return x * x * x;
+ return (108.0 / 841.0) * (x - (4.0 / 29.0));
+}
+
+static inline float cielabinvg(float x)
+{
+ if (x > 0.008856)
+ return pow(x, 1.0 / 3.0);
+ return (7.787 * x) + (16.0 / 116.0);
+}
+
+static void labtoxyz(fz_colorspace *fzcs, float *xyz, float *lab)
+{
+ struct cielab *cs = (struct cielab *) fzcs;
+ float lstar = lab[0];
+ float astar = MAX(MIN(lab[1], cs->range[1]), cs->range[0]);
+ float bstar = MAX(MIN(lab[2], cs->range[3]), cs->range[2]);
+ float l = ((lstar * 16.0) / 116.0) + (astar / 500.0);
+ float m = (lstar * 16.0) / 116.0;
+ float n = ((lstar * 16.0) / 116.0) - (bstar / 200.0);
+ xyz[0] = cs->white[0] * cielabg(l);
+ xyz[1] = cs->white[1] * cielabg(m);
+ xyz[2] = cs->white[2] * cielabg(n);
+}
+
+static void xyztolab(fz_colorspace *fzcs, float *xyz, float *lab)
+{
+ struct cielab *cs = (struct cielab *) fzcs;
+ float yyn = xyz[1] / cs->white[1];
+ if (yyn < 0.008856)
+ lab[0] = 116.0 * yyn * (1.0 / 3.0) - 16.0;
+ else
+ lab[0] = 903.3 * yyn;
+ lab[1] = 500 * (cielabinvg(xyz[0]/cs->white[0]) - cielabinvg(xyz[1]/cs->white[1]));
+ lab[2] = 200 * (cielabinvg(xyz[1]/cs->white[1]) - cielabinvg(xyz[2]/cs->white[2]));
+}
+
+static fz_error *
+newlab(fz_colorspace **csp, float *white, float *black, float *range)
+{
+ struct cielab *cs;
+ int i;
+
+ cs = fz_malloc(sizeof(struct cielab));
+ if (!cs)
+ return fz_outofmem;
+
+ initcs((fz_colorspace*)cs, "Lab", 3, labtoxyz, xyztolab, nil);
+
+ for (i = 0; i < 3; i++)
+ {
+ cs->white[i] = white[i];
+ cs->black[i] = black[i];
+ }
+
+ for (i = 0; i < 4; i++)
+ cs->range[i] = range[i];
+
+ *csp = (fz_colorspace*) cs;
+ return nil;
+}
+
+/*
+ * Load from PDF
+ */
+
+static fz_error *
+loadiccbased(fz_colorspace **csp, pdf_xref *xref, fz_obj *ref)
+{
+ fz_error *error;
+ fz_obj *dict;
+ int n;
+
+ error = pdf_loadindirect(&dict, xref, ref);
+ if (error)
+ return error;
+
+ n = fz_toint(fz_dictgets(dict, "N"));
+
+ fz_dropobj(dict);
+
+ switch (n)
+ {
+ case 1: *csp = pdf_devicegray; return nil;
+ case 3: *csp = pdf_devicergb; return nil;
+ case 4: *csp = pdf_devicecmyk; return nil;
+ }
+
+ return fz_throw("syntaxerror: ICCBased must have 1, 3 or 4 components");
+}
+
+/*
+ * Parse and create colorspace from PDF object.
+ */
+
+fz_error *
+pdf_loadcolorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
+{
+printf("loading colorspace: ");
+fz_debugobj(obj);
+printf("\n");
+
+ if (fz_isname(obj))
+ {
+ if (!strcmp(fz_toname(obj), "DeviceGray"))
+ {
+ *csp = pdf_devicegray;
+ return nil;
+ }
+
+ if (!strcmp(fz_toname(obj), "DeviceRGB"))
+ {
+ *csp = pdf_devicergb;
+ return nil;
+ }
+
+ if (!strcmp(fz_toname(obj), "DeviceCMYK"))
+ {
+ *csp = pdf_devicecmyk;
+ return nil;
+ }
+ }
+
+ else if (fz_isarray(obj))
+ {
+ fz_obj *name = fz_arrayget(obj, 0);
+
+ if (fz_isname(name))
+ {
+ if (!strcmp(fz_toname(name), "CalGray"))
+ {
+ fz_obj *dict = fz_arrayget(obj, 1);
+ fz_obj *tmp;
+
+ float white[3];
+ float black[3];
+ float gamma;
+
+ tmp = fz_dictgets(dict, "White");
+ if (!fz_isarray(tmp))
+ return fz_throw("syntaxerror: CalGray missing White");
+ white[0] = fz_toreal(fz_arrayget(tmp, 0));
+ white[1] = fz_toreal(fz_arrayget(tmp, 1));
+ white[2] = fz_toreal(fz_arrayget(tmp, 2));
+
+ tmp = fz_dictgets(dict, "Black");
+ if (fz_isarray(tmp))
+ {
+ black[0] = fz_toreal(fz_arrayget(tmp, 0));
+ black[1] = fz_toreal(fz_arrayget(tmp, 1));
+ black[2] = fz_toreal(fz_arrayget(tmp, 2));
+ }
+ else
+ {
+ black[0] = 0.0;
+ black[1] = 0.0;
+ black[2] = 0.0;
+ }
+
+ tmp = fz_dictgets(dict, "Gamma");
+ if (fz_isreal(tmp))
+ gamma = fz_toreal(tmp);
+ else
+ gamma = 1.0;
+
+ return newcalgray(csp, white, black, gamma);
+ }
+
+ if (!strcmp(fz_toname(name), "CalRGB"))
+ {
+ fz_obj *dict = fz_arrayget(obj, 1);
+ fz_obj *tmp;
+
+ float white[3];
+ float black[3];
+ float gamma[3];
+ float matrix[9];
+
+ tmp = fz_dictgets(dict, "White");
+ if (!fz_isarray(tmp))
+ return fz_throw("syntaxerror: CalRGB missing White");
+ white[0] = fz_toreal(fz_arrayget(tmp, 0));
+ white[1] = fz_toreal(fz_arrayget(tmp, 1));
+ white[2] = fz_toreal(fz_arrayget(tmp, 2));
+
+ tmp = fz_dictgets(dict, "Black");
+ if (fz_isarray(tmp))
+ {
+ black[0] = fz_toreal(fz_arrayget(tmp, 0));
+ black[1] = fz_toreal(fz_arrayget(tmp, 1));
+ black[2] = fz_toreal(fz_arrayget(tmp, 2));
+ }
+ else
+ {
+ black[0] = 0.0;
+ black[1] = 0.0;
+ black[2] = 0.0;
+ }
+
+ tmp = fz_dictgets(dict, "Gamma");
+ if (fz_isarray(tmp))
+ {
+ gamma[0] = fz_toreal(fz_arrayget(tmp, 0));
+ gamma[1] = fz_toreal(fz_arrayget(tmp, 1));
+ gamma[2] = fz_toreal(fz_arrayget(tmp, 2));
+ }
+ else
+ {
+ gamma[0] = 1.0;
+ gamma[1] = 1.0;
+ gamma[2] = 1.0;
+ }
+
+ tmp = fz_dictgets(dict, "Matrix");
+ if (fz_isarray(tmp))
+ {
+ int i;
+ for (i = 0; i < 9; i++)
+ matrix[i] = fz_toreal(fz_arrayget(tmp, i));
+ }
+ else
+ {
+ matrix[0] = 1.0; matrix[1] = 0.0; matrix[2] = 0.0;
+ matrix[3] = 0.0; matrix[4] = 1.0; matrix[5] = 0.0;
+ matrix[6] = 0.0; matrix[7] = 0.0; matrix[8] = 1.0;
+ }
+
+ return newcalrgb(csp, white, black, gamma, matrix);
+ }
+
+ if (!strcmp(fz_toname(name), "CalCMYK"))
+ {
+ *csp = pdf_devicecmyk;
+ return nil;
+ }
+
+ if (!strcmp(fz_toname(name), "Lab"))
+ {
+ fz_obj *dict = fz_arrayget(obj, 1);
+ fz_obj *tmp;
+
+ float white[3];
+ float black[3];
+ float range[4];
+
+ tmp = fz_dictgets(dict, "White");
+ if (!fz_isarray(tmp))
+ return fz_throw("syntaxerror: Lab missing White");
+ white[0] = fz_toreal(fz_arrayget(tmp, 0));
+ white[1] = fz_toreal(fz_arrayget(tmp, 1));
+ white[2] = fz_toreal(fz_arrayget(tmp, 2));
+
+ tmp = fz_dictgets(dict, "Black");
+ if (fz_isarray(tmp))
+ {
+ black[0] = fz_toreal(fz_arrayget(tmp, 0));
+ black[1] = fz_toreal(fz_arrayget(tmp, 1));
+ black[2] = fz_toreal(fz_arrayget(tmp, 2));
+ }
+ else
+ {
+ black[0] = 0.0;
+ black[1] = 0.0;
+ black[2] = 0.0;
+ }
+
+ tmp = fz_dictgets(dict, "Range");
+ if (fz_isarray(tmp))
+ {
+ range[0] = fz_toreal(fz_arrayget(tmp, 0));
+ range[1] = fz_toreal(fz_arrayget(tmp, 1));
+ range[2] = fz_toreal(fz_arrayget(tmp, 2));
+ range[3] = fz_toreal(fz_arrayget(tmp, 3));
+ }
+ else
+ {
+ range[0] = -100;
+ range[1] = 100;
+ range[2] = -100;
+ range[3] = 100;
+ }
+
+ return newlab(csp, white, black, range);
+ }
+
+ if (!strcmp(fz_toname(name), "ICCBased"))
+ {
+ return loadiccbased(csp, xref, fz_arrayget(obj, 1));
+ }
+ }
+ }
+
+ return fz_throw("syntaxerror: could not parse color space");
+}
+