//
// GfxState.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <stddef.h>
#include <math.h>
-#include <string.h> // for memcpy()
+#include <string.h>
#include "gmem.h"
#include "Error.h"
#include "Object.h"
#include "Array.h"
+#include "Page.h"
#include "GfxState.h"
+#include "cmyk.h"
//------------------------------------------------------------------------
+static inline GfxColorComp clip01(GfxColorComp x) {
+ return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
+}
+
static inline double clip01(double x) {
- return (x < 0) ? 0 : ((x > 1) ? 1 : x);
+ return (x < 0) ? 0 : (x > 1) ? 1 : x;
}
//------------------------------------------------------------------------
+
+static struct {
+ char *name;
+ GfxBlendMode mode;
+} gfxBlendModeNames[] = {
+ { "Normal", gfxBlendNormal },
+ { "Compatible", gfxBlendNormal },
+ { "Multiply", gfxBlendMultiply },
+ { "Screen", gfxBlendScreen },
+ { "Overlay", gfxBlendOverlay },
+ { "Darken", gfxBlendDarken },
+ { "Lighten", gfxBlendLighten },
+ { "ColorDodge", gfxBlendColorDodge },
+ { "ColorBurn", gfxBlendColorBurn },
+ { "HardLight", gfxBlendHardLight },
+ { "SoftLight", gfxBlendSoftLight },
+ { "Difference", gfxBlendDifference },
+ { "Exclusion", gfxBlendExclusion },
+ { "Hue", gfxBlendHue },
+ { "Saturation", gfxBlendSaturation },
+ { "Color", gfxBlendColor },
+ { "Luminosity", gfxBlendLuminosity }
+};
+
+#define nGfxBlendModeNames \
+ ((int)((sizeof(gfxBlendModeNames) / sizeof(char *))))
+
+//------------------------------------------------------------------------
+
+// NB: This must match the GfxColorSpaceMode enum defined in
+// GfxState.h
+static char *gfxColorSpaceModeNames[] = {
+ "DeviceGray",
+ "CalGray",
+ "DeviceRGB",
+ "CalRGB",
+ "DeviceCMYK",
+ "Lab",
+ "ICCBased",
+ "Indexed",
+ "Separation",
+ "DeviceN",
+ "Pattern"
+};
+
+#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
+
+//------------------------------------------------------------------------
// GfxColorSpace
//------------------------------------------------------------------------
} else if (obj1.isName("Pattern")) {
cs = GfxPatternColorSpace::parse(csObj->getArray());
} else {
- error(-1, "Bad color space '%s'", csObj->getName());
+ error(-1, "Bad color space");
}
obj1.free();
} else {
}
}
+int GfxColorSpace::getNumColorSpaceModes() {
+ return nGfxColorSpaceModes;
+}
+
+char *GfxColorSpace::getColorSpaceModeName(int idx) {
+ return gfxColorSpaceModeNames[idx];
+}
+
//------------------------------------------------------------------------
// GfxDeviceGrayColorSpace
//------------------------------------------------------------------------
return new GfxDeviceGrayColorSpace();
}
-void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
*gray = clip01(color->c[0]);
}
void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
cmyk->c = cmyk->m = cmyk->y = 0;
- cmyk->k = clip01(1 - color->c[0]);
+ cmyk->k = clip01(gfxColorComp1 - color->c[0]);
}
//------------------------------------------------------------------------
return cs;
}
-void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
*gray = clip01(color->c[0]);
}
void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
cmyk->c = cmyk->m = cmyk->y = 0;
- cmyk->k = clip01(1 - color->c[0]);
+ cmyk->k = clip01(gfxColorComp1 - color->c[0]);
}
//------------------------------------------------------------------------
return new GfxDeviceRGBColorSpace();
}
-void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
- *gray = clip01(0.299 * color->c[0] +
- 0.587 * color->c[1] +
- 0.114 * color->c[2]);
+void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(0.3 * color->c[0] +
+ 0.59 * color->c[1] +
+ 0.11 * color->c[2] + 0.5));
}
void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
}
void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
- double c, m, y, k;
+ GfxColorComp c, m, y, k;
- c = clip01(1 - color->c[0]);
- m = clip01(1 - color->c[1]);
- y = clip01(1 - color->c[2]);
+ c = clip01(gfxColorComp1 - color->c[0]);
+ m = clip01(gfxColorComp1 - color->c[1]);
+ y = clip01(gfxColorComp1 - color->c[2]);
k = c;
if (m < k) {
k = m;
whiteX = whiteY = whiteZ = 1;
blackX = blackY = blackZ = 0;
gammaR = gammaG = gammaB = 1;
- m[0] = 1; m[1] = 0; m[2] = 0;
- m[3] = 0; m[4] = 1; m[5] = 0;
- m[6] = 0; m[7] = 0; m[8] = 1;
+ mat[0] = 1; mat[1] = 0; mat[2] = 0;
+ mat[3] = 0; mat[4] = 1; mat[5] = 0;
+ mat[6] = 0; mat[7] = 0; mat[8] = 1;
}
GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
cs->gammaG = gammaG;
cs->gammaB = gammaB;
for (i = 0; i < 9; ++i) {
- cs->m[i] = m[i];
+ cs->mat[i] = mat[i];
}
return cs;
}
obj2.arrayGetLength() == 9) {
for (i = 0; i < 9; ++i) {
obj2.arrayGet(i, &obj3);
- cs->m[i] = obj3.getNum();
+ cs->mat[i] = obj3.getNum();
obj3.free();
}
}
return cs;
}
-void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
- *gray = clip01(0.299 * color->c[0] +
- 0.587 * color->c[1] +
- 0.114 * color->c[2]);
+void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
+ 0.587 * color->c[1] +
+ 0.114 * color->c[2] + 0.5));
}
void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
}
void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
- double c, m, y, k;
+ GfxColorComp c, m, y, k;
- c = clip01(1 - color->c[0]);
- m = clip01(1 - color->c[1]);
- y = clip01(1 - color->c[2]);
+ c = clip01(gfxColorComp1 - color->c[0]);
+ m = clip01(gfxColorComp1 - color->c[1]);
+ y = clip01(gfxColorComp1 - color->c[2]);
k = c;
if (m < k) {
k = m;
return new GfxDeviceCMYKColorSpace();
}
-void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
- *gray = clip01(1 - color->c[3]
- - 0.299 * color->c[0]
- - 0.587 * color->c[1]
- - 0.114 * color->c[2]);
+void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
+ - 0.3 * color->c[0]
+ - 0.59 * color->c[1]
+ - 0.11 * color->c[2] + 0.5));
}
+/*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ unsigned char r,g,b;
+ float c = color->c[0];
+ float m = color->c[1];
+ float y = color->c[2];
+ float k = color->c[3];
+ convert_cmyk2rgb(c,m,y,k, &r,&g,&b);
+ rgb->r = r/255.0;
+ rgb->g = g/255.0;
+ rgb->b = b/255.0;
+}*/
+
void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
- rgb->r = clip01(1 - (color->c[0] + color->c[3]));
- rgb->g = clip01(1 - (color->c[1] + color->c[3]));
- rgb->b = clip01(1 - (color->c[2] + color->c[3]));
+ double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
+
+ c = colToDbl(color->c[0]);
+ m = colToDbl(color->c[1]);
+ y = colToDbl(color->c[2]);
+ k = colToDbl(color->c[3]);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ // this is a matrix multiplication, unrolled for performance
+ // C M Y K
+ x = c1 * m1 * y1 * k1; // 0 0 0 0
+ r = g = b = x;
+ x = c1 * m1 * y1 * k; // 0 0 0 1
+ r += 0.1373 * x;
+ g += 0.1216 * x;
+ b += 0.1255 * x;
+ x = c1 * m1 * y * k1; // 0 0 1 0
+ r += x;
+ g += 0.9490 * x;
+ x = c1 * m1 * y * k; // 0 0 1 1
+ r += 0.1098 * x;
+ g += 0.1020 * x;
+ x = c1 * m * y1 * k1; // 0 1 0 0
+ r += 0.9255 * x;
+ b += 0.5490 * x;
+ x = c1 * m * y1 * k; // 0 1 0 1
+ r += 0.1412 * x;
+ x = c1 * m * y * k1; // 0 1 1 0
+ r += 0.9294 * x;
+ g += 0.1098 * x;
+ b += 0.1412 * x;
+ x = c1 * m * y * k; // 0 1 1 1
+ r += 0.1333 * x;
+ x = c * m1 * y1 * k1; // 1 0 0 0
+ g += 0.6784 * x;
+ b += 0.9373 * x;
+ x = c * m1 * y1 * k; // 1 0 0 1
+ g += 0.0588 * x;
+ b += 0.1412 * x;
+ x = c * m1 * y * k1; // 1 0 1 0
+ g += 0.6510 * x;
+ b += 0.3137 * x;
+ x = c * m1 * y * k; // 1 0 1 1
+ g += 0.0745 * x;
+ x = c * m * y1 * k1; // 1 1 0 0
+ r += 0.1804 * x;
+ g += 0.1922 * x;
+ b += 0.5725 * x;
+ x = c * m * y1 * k; // 1 1 0 1
+ b += 0.0078 * x;
+ x = c * m * y * k1; // 1 1 1 0
+ r += 0.2118 * x;
+ g += 0.2119 * x;
+ b += 0.2235 * x;
+ rgb->r = clip01(dblToCol(r));
+ rgb->g = clip01(dblToCol(g));
+ rgb->b = clip01(dblToCol(b));
}
void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
return cs;
}
-void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
GfxRGB rgb;
getRGB(color, &rgb);
- *gray = clip01(0.299 * rgb.r +
- 0.587 * rgb.g +
- 0.114 * rgb.b);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
}
void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
double r, g, b;
// convert L*a*b* to CIE 1931 XYZ color space
- t1 = (color->c[0] + 16) / 116;
- t2 = t1 + color->c[1] / 500;
+ t1 = (colToDbl(color->c[0]) + 16) / 116;
+ t2 = t1 + colToDbl(color->c[1]) / 500;
if (t2 >= (6.0 / 29.0)) {
X = t2 * t2 * t2;
} else {
Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
}
Y *= whiteY;
- t2 = t1 - color->c[2] / 200;
+ t2 = t1 - colToDbl(color->c[2]) / 200;
if (t2 >= (6.0 / 29.0)) {
Z = t2 * t2 * t2;
} else {
r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
- rgb->r = pow(clip01(r * kr), 0.5);
- rgb->g = pow(clip01(g * kg), 0.5);
- rgb->b = pow(clip01(b * kb), 0.5);
+ rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+ rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+ rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
}
void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
GfxRGB rgb;
- double c, m, y, k;
+ GfxColorComp c, m, y, k;
getRGB(color, &rgb);
- c = clip01(1 - rgb.r);
- m = clip01(1 - rgb.g);
- y = clip01(1 - rgb.b);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
k = c;
if (m < k) {
k = m;
// GfxICCBasedColorSpace
//------------------------------------------------------------------------
-GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
- Ref *iccProfileStream) {
- this->nComps = nComps;
- this->alt = alt;
- this->iccProfileStream = *iccProfileStream;
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA) {
+ nComps = nCompsA;
+ alt = altA;
+ iccProfileStream = *iccProfileStreamA;
rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
}
GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
GfxICCBasedColorSpace *cs;
- Ref iccProfileStream;
- int nComps;
- GfxColorSpace *alt;
+ Ref iccProfileStreamA;
+ int nCompsA;
+ GfxColorSpace *altA;
Dict *dict;
Object obj1, obj2, obj3;
int i;
arr->getNF(1, &obj1);
if (obj1.isRef()) {
- iccProfileStream = obj1.getRef();
+ iccProfileStreamA = obj1.getRef();
} else {
- iccProfileStream.num = 0;
- iccProfileStream.gen = 0;
+ iccProfileStreamA.num = 0;
+ iccProfileStreamA.gen = 0;
}
obj1.free();
arr->get(1, &obj1);
obj1.free();
return NULL;
}
- nComps = obj2.getInt();
+ nCompsA = obj2.getInt();
obj2.free();
+ if (nCompsA > gfxColorMaxComps) {
+ error(-1, "ICCBased color space with too many (%d > %d) components",
+ nCompsA, gfxColorMaxComps);
+ nCompsA = gfxColorMaxComps;
+ }
if (dict->lookup("Alternate", &obj2)->isNull() ||
- !(alt = GfxColorSpace::parse(&obj2))) {
- switch (nComps) {
+ !(altA = GfxColorSpace::parse(&obj2))) {
+ switch (nCompsA) {
case 1:
- alt = new GfxDeviceGrayColorSpace();
+ altA = new GfxDeviceGrayColorSpace();
break;
case 3:
- alt = new GfxDeviceRGBColorSpace();
+ altA = new GfxDeviceRGBColorSpace();
break;
case 4:
- alt = new GfxDeviceCMYKColorSpace();
+ altA = new GfxDeviceCMYKColorSpace();
break;
default:
error(-1, "Bad ICCBased color space - invalid N");
}
}
obj2.free();
- cs = new GfxICCBasedColorSpace(nComps, alt, &iccProfileStream);
+ cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
if (dict->lookup("Range", &obj2)->isArray() &&
- obj2.arrayGetLength() == 2 * nComps) {
- for (i = 0; i < nComps; ++i) {
+ obj2.arrayGetLength() == 2 * nCompsA) {
+ for (i = 0; i < nCompsA; ++i) {
obj2.arrayGet(2*i, &obj3);
cs->rangeMin[i] = obj3.getNum();
obj3.free();
return cs;
}
-void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
alt->getGray(color, gray);
}
void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
double *decodeRange,
int maxImgPixel) {
+ alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
+
+#if 0
+ // this is nominally correct, but some PDF files don't set the
+ // correct ranges in the ICCBased dict
int i;
for (i = 0; i < nComps; ++i) {
decodeLow[i] = rangeMin[i];
decodeRange[i] = rangeMax[i] - rangeMin[i];
}
+#endif
}
//------------------------------------------------------------------------
// GfxIndexedColorSpace
//------------------------------------------------------------------------
-GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *base,
- int indexHigh) {
- this->base = base;
- this->indexHigh = indexHigh;
- this->lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
- sizeof(Guchar));
+GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
+ int indexHighA) {
+ base = baseA;
+ indexHigh = indexHighA;
+ lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
+ sizeof(Guchar));
}
GfxIndexedColorSpace::~GfxIndexedColorSpace() {
GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
GfxIndexedColorSpace *cs;
- GfxColorSpace *base;
- int indexHigh;
+ GfxColorSpace *baseA;
+ int indexHighA;
Object obj1;
int x;
char *s;
goto err1;
}
arr->get(1, &obj1);
- if (!(base = GfxColorSpace::parse(&obj1))) {
+ if (!(baseA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Indexed color space (base color space)");
goto err2;
}
obj1.free();
if (!arr->get(2, &obj1)->isInt()) {
error(-1, "Bad Indexed color space (hival)");
+ delete baseA;
+ goto err2;
+ }
+ indexHighA = obj1.getInt();
+ if (indexHighA < 0 || indexHighA > 255) {
+ // the PDF spec requires indexHigh to be in [0,255] -- allowing
+ // values larger than 255 creates a security hole: if nComps *
+ // indexHigh is greater than 2^31, the loop below may overwrite
+ // past the end of the array
+ error(-1, "Bad Indexed color space (invalid indexHigh value)");
+ delete baseA;
goto err2;
}
- indexHigh = obj1.getInt();
obj1.free();
- cs = new GfxIndexedColorSpace(base, indexHigh);
+ cs = new GfxIndexedColorSpace(baseA, indexHighA);
arr->get(3, &obj1);
- n = base->getNComps();
+ n = baseA->getNComps();
if (obj1.isStream()) {
obj1.streamReset();
- for (i = 0; i <= indexHigh; ++i) {
+ for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
if ((x = obj1.streamGetChar()) == EOF) {
error(-1, "Bad Indexed color space (lookup table stream too short)");
}
obj1.streamClose();
} else if (obj1.isString()) {
- if (obj1.getString()->getLength() < (indexHigh + 1) * n) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
error(-1, "Bad Indexed color space (lookup table string too short)");
goto err3;
}
s = obj1.getString()->getCString();
- for (i = 0; i <= indexHigh; ++i) {
+ for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
cs->lookup[i*n + j] = (Guchar)*s++;
}
return NULL;
}
-void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
+GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
+ GfxColor *baseColor) {
Guchar *p;
- GfxColor color2;
+ double low[gfxColorMaxComps], range[gfxColorMaxComps];
int n, i;
n = base->getNComps();
- p = &lookup[(int)(color->c[0] + 0.5) * n];
+ base->getDefaultRanges(low, range, indexHigh);
+ p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n];
for (i = 0; i < n; ++i) {
- color2.c[i] = p[i] / 255.0;
+ baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
}
- base->getGray(&color2, gray);
+ return baseColor;
+}
+
+void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxColor color2;
+
+ base->getGray(mapColorToBase(color, &color2), gray);
}
void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
- Guchar *p;
GfxColor color2;
- int n, i;
- n = base->getNComps();
- p = &lookup[(int)(color->c[0] + 0.5) * n];
- for (i = 0; i < n; ++i) {
- color2.c[i] = p[i] / 255.0;
- }
- base->getRGB(&color2, rgb);
+ base->getRGB(mapColorToBase(color, &color2), rgb);
}
void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
- Guchar *p;
GfxColor color2;
- int n, i;
- n = base->getNComps();
- p = &lookup[(int)(color->c[0] + 0.5) * n];
- for (i = 0; i < n; ++i) {
- color2.c[i] = p[i] / 255.0;
- }
- base->getCMYK(&color2, cmyk);
+ base->getCMYK(mapColorToBase(color, &color2), cmyk);
}
void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
// GfxSeparationColorSpace
//------------------------------------------------------------------------
-GfxSeparationColorSpace::GfxSeparationColorSpace(GString *name,
- GfxColorSpace *alt,
- Function *func) {
- this->name = name;
- this->alt = alt;
- this->func = func;
+GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
}
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
//~ handle the 'All' and 'None' colorants
GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
GfxSeparationColorSpace *cs;
- GString *name;
- GfxColorSpace *alt;
- Function *func;
+ GString *nameA;
+ GfxColorSpace *altA;
+ Function *funcA;
Object obj1;
if (arr->getLength() != 4) {
error(-1, "Bad Separation color space (name)");
goto err2;
}
- name = new GString(obj1.getName());
+ nameA = new GString(obj1.getName());
obj1.free();
arr->get(2, &obj1);
- if (!(alt = GfxColorSpace::parse(&obj1))) {
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Separation color space (alternate color space)");
goto err3;
}
obj1.free();
- func = Function::parse(arr->get(3, &obj1));
- obj1.free();
- if (!func->isOk()) {
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
goto err4;
}
- cs = new GfxSeparationColorSpace(name, alt, func);
+ obj1.free();
+ cs = new GfxSeparationColorSpace(nameA, altA, funcA);
return cs;
err4:
- delete func;
- delete alt;
+ delete altA;
err3:
- delete name;
+ delete nameA;
err2:
obj1.free();
err1:
return NULL;
}
-void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ double x;
+ double c[gfxColorMaxComps];
GfxColor color2;
+ int i;
- func->transform(color->c, color2.c);
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
alt->getGray(&color2, gray);
}
void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double x;
+ double c[gfxColorMaxComps];
GfxColor color2;
+ int i;
- func->transform(color->c, color2.c);
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
alt->getRGB(&color2, rgb);
}
void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double x;
+ double c[gfxColorMaxComps];
GfxColor color2;
+ int i;
- func->transform(color->c, color2.c);
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
alt->getCMYK(&color2, cmyk);
}
// GfxDeviceNColorSpace
//------------------------------------------------------------------------
-GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
- GfxColorSpace *alt,
- Function *func) {
- this->nComps = nComps;
- this->alt = alt;
- this->func = func;
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
}
GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
//~ handle the 'None' colorant
GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
GfxDeviceNColorSpace *cs;
- int nComps;
- GString *names[gfxColorMaxComps];
- GfxColorSpace *alt;
- Function *func;
+ int nCompsA;
+ GString *namesA[gfxColorMaxComps];
+ GfxColorSpace *altA;
+ Function *funcA;
Object obj1, obj2;
int i;
error(-1, "Bad DeviceN color space (names)");
goto err2;
}
- nComps = obj1.arrayGetLength();
- for (i = 0; i < nComps; ++i) {
+ nCompsA = obj1.arrayGetLength();
+ if (nCompsA > gfxColorMaxComps) {
+ error(-1, "DeviceN color space with too many (%d > %d) components",
+ nCompsA, gfxColorMaxComps);
+ nCompsA = gfxColorMaxComps;
+ }
+ for (i = 0; i < nCompsA; ++i) {
if (!obj1.arrayGet(i, &obj2)->isName()) {
error(-1, "Bad DeviceN color space (names)");
obj2.free();
goto err2;
}
- names[i] = new GString(obj2.getName());
+ namesA[i] = new GString(obj2.getName());
obj2.free();
}
obj1.free();
arr->get(2, &obj1);
- if (!(alt = GfxColorSpace::parse(&obj1))) {
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad DeviceN color space (alternate color space)");
goto err3;
}
obj1.free();
- func = Function::parse(arr->get(3, &obj1));
- obj1.free();
- if (!func->isOk()) {
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
goto err4;
}
- cs = new GfxDeviceNColorSpace(nComps, alt, func);
- for (i = 0; i < nComps; ++i) {
- cs->names[i] = names[i];
+ obj1.free();
+ cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+ for (i = 0; i < nCompsA; ++i) {
+ cs->names[i] = namesA[i];
}
return cs;
err4:
- delete func;
- delete alt;
+ delete altA;
err3:
- for (i = 0; i < nComps; ++i) {
- delete names[i];
+ for (i = 0; i < nCompsA; ++i) {
+ delete namesA[i];
}
err2:
obj1.free();
return NULL;
}
-void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
GfxColor color2;
+ int i;
- func->transform(color->c, color2.c);
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
alt->getGray(&color2, gray);
}
void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
GfxColor color2;
+ int i;
- func->transform(color->c, color2.c);
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
alt->getRGB(&color2, rgb);
}
void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
GfxColor color2;
+ int i;
- func->transform(color->c, color2.c);
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
alt->getCMYK(&color2, cmyk);
}
// GfxPatternColorSpace
//------------------------------------------------------------------------
-GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
- this->under = under;
+GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
+ under = underA;
}
GfxPatternColorSpace::~GfxPatternColorSpace() {
GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
GfxPatternColorSpace *cs;
- GfxColorSpace *under;
+ GfxColorSpace *underA;
Object obj1;
if (arr->getLength() != 1 && arr->getLength() != 2) {
error(-1, "Bad Pattern color space");
return NULL;
}
- under = NULL;
+ underA = NULL;
if (arr->getLength() == 2) {
arr->get(1, &obj1);
- if (!(under = GfxColorSpace::parse(&obj1))) {
+ if (!(underA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Pattern color space (underlying color space)");
obj1.free();
return NULL;
}
obj1.free();
}
- cs = new GfxPatternColorSpace(under);
+ cs = new GfxPatternColorSpace(underA);
return cs;
}
-void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) {
*gray = 0;
}
// Pattern
//------------------------------------------------------------------------
-GfxPattern::GfxPattern(int type) {
- this->type = type;
+GfxPattern::GfxPattern(int typeA) {
+ type = typeA;
}
GfxPattern::~GfxPattern() {
GfxPattern *GfxPattern::parse(Object *obj) {
GfxPattern *pattern;
- Dict *dict;
Object obj1;
+ if (obj->isDict()) {
+ obj->dictLookup("PatternType", &obj1);
+ } else if (obj->isStream()) {
+ obj->streamGetDict()->lookup("PatternType", &obj1);
+ } else {
+ return NULL;
+ }
pattern = NULL;
- if (obj->isStream()) {
- dict = obj->streamGetDict();
- dict->lookup("PatternType", &obj1);
- if (obj1.isInt() && obj1.getInt() == 1) {
- pattern = new GfxTilingPattern(dict, obj);
- }
- obj1.free();
+ if (obj1.isInt() && obj1.getInt() == 1) {
+ pattern = GfxTilingPattern::parse(obj);
+ } else if (obj1.isInt() && obj1.getInt() == 2) {
+ pattern = GfxShadingPattern::parse(obj);
}
+ obj1.free();
return pattern;
}
// GfxTilingPattern
//------------------------------------------------------------------------
-GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
- GfxPattern(1)
-{
+GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
+ GfxTilingPattern *pat;
+ Dict *dict;
+ int paintTypeA, tilingTypeA;
+ double bboxA[4], matrixA[6];
+ double xStepA, yStepA;
+ Object resDictA;
Object obj1, obj2;
int i;
- if (streamDict->lookup("PaintType", &obj1)->isInt()) {
- paintType = obj1.getInt();
+ if (!patObj->isStream()) {
+ return NULL;
+ }
+ dict = patObj->streamGetDict();
+
+ if (dict->lookup("PaintType", &obj1)->isInt()) {
+ paintTypeA = obj1.getInt();
} else {
- paintType = 1;
+ paintTypeA = 1;
error(-1, "Invalid or missing PaintType in pattern");
}
obj1.free();
- if (streamDict->lookup("TilingType", &obj1)->isInt()) {
- tilingType = obj1.getInt();
+ if (dict->lookup("TilingType", &obj1)->isInt()) {
+ tilingTypeA = obj1.getInt();
} else {
- tilingType = 1;
+ tilingTypeA = 1;
error(-1, "Invalid or missing TilingType in pattern");
}
obj1.free();
- bbox[0] = bbox[1] = 0;
- bbox[2] = bbox[3] = 1;
- if (streamDict->lookup("BBox", &obj1)->isArray() &&
+ bboxA[0] = bboxA[1] = 0;
+ bboxA[2] = bboxA[3] = 1;
+ if (dict->lookup("BBox", &obj1)->isArray() &&
obj1.arrayGetLength() == 4) {
for (i = 0; i < 4; ++i) {
if (obj1.arrayGet(i, &obj2)->isNum()) {
- bbox[i] = obj2.getNum();
+ bboxA[i] = obj2.getNum();
}
obj2.free();
}
error(-1, "Invalid or missing BBox in pattern");
}
obj1.free();
- if (streamDict->lookup("XStep", &obj1)->isNum()) {
- xStep = obj1.getNum();
+ if (dict->lookup("XStep", &obj1)->isNum()) {
+ xStepA = obj1.getNum();
} else {
- xStep = 1;
+ xStepA = 1;
error(-1, "Invalid or missing XStep in pattern");
}
obj1.free();
- if (streamDict->lookup("YStep", &obj1)->isNum()) {
- yStep = obj1.getNum();
+ if (dict->lookup("YStep", &obj1)->isNum()) {
+ yStepA = obj1.getNum();
} else {
- yStep = 1;
+ yStepA = 1;
error(-1, "Invalid or missing YStep in pattern");
}
obj1.free();
- if (!streamDict->lookup("Resources", &resDict)->isDict()) {
- resDict.free();
- resDict.initNull();
+ if (!dict->lookup("Resources", &resDictA)->isDict()) {
+ resDictA.free();
+ resDictA.initNull();
error(-1, "Invalid or missing Resources in pattern");
}
- matrix[0] = 1; matrix[1] = 0;
- matrix[2] = 0; matrix[3] = 1;
- matrix[4] = 0; matrix[5] = 0;
- if (streamDict->lookup("Matrix", &obj1)->isArray() &&
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
obj1.arrayGetLength() == 6) {
for (i = 0; i < 6; ++i) {
if (obj1.arrayGet(i, &obj2)->isNum()) {
- matrix[i] = obj2.getNum();
+ matrixA[i] = obj2.getNum();
}
obj2.free();
}
}
obj1.free();
- stream->copy(&contentStream);
+
+ pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+ &resDictA, matrixA, patObj);
+ resDictA.free();
+ return pat;
+}
+
+GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA):
+ GfxPattern(1)
+{
+ int i;
+
+ paintType = paintTypeA;
+ tilingType = tilingTypeA;
+ for (i = 0; i < 4; ++i) {
+ bbox[i] = bboxA[i];
+ }
+ xStep = xStepA;
+ yStep = yStepA;
+ resDictA->copy(&resDict);
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ contentStreamA->copy(&contentStream);
}
GfxTilingPattern::~GfxTilingPattern() {
}
GfxPattern *GfxTilingPattern::copy() {
- return new GfxTilingPattern(this);
+ return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
+ &resDict, matrix, &contentStream);
}
-GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
- GfxPattern(1)
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
+ Dict *dict;
+ GfxShading *shadingA;
+ double matrixA[6];
+ Object obj1, obj2;
+ int i;
+
+ if (!patObj->isDict()) {
+ return NULL;
+ }
+ dict = patObj->getDict();
+
+ dict->lookup("Shading", &obj1);
+ shadingA = GfxShading::parse(&obj1);
+ obj1.free();
+ if (!shadingA) {
+ return NULL;
+ }
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrixA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return new GfxShadingPattern(shadingA, matrixA);
+}
+
+GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
+ GfxPattern(2)
{
- memcpy(this, pat, sizeof(GfxTilingPattern));
- pat->resDict.copy(&resDict);
- pat->contentStream.copy(&contentStream);
+ int i;
+
+ shading = shadingA;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+}
+
+GfxShadingPattern::~GfxShadingPattern() {
+ delete shading;
+}
+
+GfxPattern *GfxShadingPattern::copy() {
+ return new GfxShadingPattern(shading->copy(), matrix);
}
//------------------------------------------------------------------------
-// Function
+// GfxShading
//------------------------------------------------------------------------
-Function::Function() {
+GfxShading::GfxShading(int typeA) {
+ type = typeA;
+ colorSpace = NULL;
+}
+
+GfxShading::GfxShading(GfxShading *shading) {
+ int i;
+
+ type = shading->type;
+ colorSpace = shading->colorSpace->copy();
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = shading->background.c[i];
+ }
+ hasBackground = shading->hasBackground;
+ xMin = shading->xMin;
+ yMin = shading->yMin;
+ xMax = shading->xMax;
+ yMax = shading->yMax;
+ hasBBox = shading->hasBBox;
}
-Function::~Function() {
+GfxShading::~GfxShading() {
+ if (colorSpace) {
+ delete colorSpace;
+ }
}
-Function *Function::parse(Object *funcObj) {
- Function *func;
+GfxShading *GfxShading::parse(Object *obj) {
+ GfxShading *shading;
Dict *dict;
- int funcType;
+ int typeA;
Object obj1;
- if (funcObj->isStream()) {
- dict = funcObj->streamGetDict();
- } else if (funcObj->isDict()) {
- dict = funcObj->getDict();
+ if (obj->isDict()) {
+ dict = obj->getDict();
+ } else if (obj->isStream()) {
+ dict = obj->streamGetDict();
} else {
- error(-1, "Expected function dictionary or stream");
return NULL;
}
- if (!dict->lookup("FunctionType", &obj1)->isInt()) {
- error(-1, "Function type is missing or wrong type");
+ if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+ error(-1, "Invalid ShadingType in shading dictionary");
obj1.free();
return NULL;
}
- funcType = obj1.getInt();
+ typeA = obj1.getInt();
obj1.free();
- if (funcType == 0) {
- func = new SampledFunction(funcObj, dict);
- } else if (funcType == 2) {
- func = new ExponentialFunction(funcObj, dict);
- } else {
- error(-1, "Unimplemented function type");
- return NULL;
- }
- if (!func->isOk()) {
- delete func;
- return NULL;
+ switch (typeA) {
+ case 1:
+ shading = GfxFunctionShading::parse(dict);
+ break;
+ case 2:
+ shading = GfxAxialShading::parse(dict);
+ break;
+ case 3:
+ shading = GfxRadialShading::parse(dict);
+ break;
+ case 4:
+ if (obj->isStream()) {
+ shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 4 shading object");
+ goto err1;
+ }
+ break;
+ case 5:
+ if (obj->isStream()) {
+ shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 5 shading object");
+ goto err1;
+ }
+ break;
+ case 6:
+ if (obj->isStream()) {
+ shading = GfxPatchMeshShading::parse(6, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 6 shading object");
+ goto err1;
+ }
+ break;
+ case 7:
+ if (obj->isStream()) {
+ shading = GfxPatchMeshShading::parse(7, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 7 shading object");
+ goto err1;
+ }
+ break;
+ default:
+ error(-1, "Unimplemented shading type %d", typeA);
+ goto err1;
}
- return func;
+ return shading;
+
+ err1:
+ return NULL;
}
-GBool Function::init(Dict *dict) {
+GBool GfxShading::init(Dict *dict) {
Object obj1, obj2;
int i;
- //----- Domain
- if (!dict->lookup("Domain", &obj1)->isArray()) {
- error(-1, "Function is missing domain");
- goto err2;
+ dict->lookup("ColorSpace", &obj1);
+ if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad color space in shading dictionary");
+ obj1.free();
+ return gFalse;
}
- m = obj1.arrayGetLength() / 2;
- if (m > funcMaxInputs) {
- error(-1, "Functions with more than %d inputs are unsupported",
- funcMaxInputs);
- goto err2;
+ obj1.free();
+
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = 0;
}
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function domain array");
- goto err1;
- }
- domain[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function domain array");
- goto err1;
+ hasBackground = gFalse;
+ if (dict->lookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpace->getNComps()) {
+ hasBackground = gTrue;
+ for (i = 0; i < colorSpace->getNComps(); ++i) {
+ background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
+ obj2.free();
+ }
+ } else {
+ error(-1, "Bad Background in shading dictionary");
}
- domain[i][1] = obj2.getNum();
- obj2.free();
}
obj1.free();
- //----- Range
- hasRange = gFalse;
- n = 0;
- if (dict->lookup("Range", &obj1)->isArray()) {
- hasRange = gTrue;
- n = obj1.arrayGetLength() / 2;
- if (n > funcMaxOutputs) {
- error(-1, "Functions with more than %d outputs are unsupported",
- funcMaxOutputs);
- goto err2;
- }
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function range array");
- goto err1;
- }
- range[i][0] = obj2.getNum();
+ xMin = yMin = xMax = yMax = 0;
+ hasBBox = gFalse;
+ if (dict->lookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ hasBBox = gTrue;
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function range array");
- goto err1;
- }
- range[i][1] = obj2.getNum();
+ yMin = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(2, &obj2)->getNum();
obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Bad BBox in shading dictionary");
}
- obj1.free();
}
+ obj1.free();
return gTrue;
-
- err1:
- obj2.free();
- err2:
- obj1.free();
- return gFalse;
}
//------------------------------------------------------------------------
-// SampledFunction
+// GfxFunctionShading
//------------------------------------------------------------------------
-SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
- Stream *str;
- int nSamples, sampleBits;
- double sampleMul;
- Object obj1, obj2;
- Guint buf, bitMask;
- int bits;
- int s;
+GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(1)
+{
int i;
- samples = NULL;
- ok = gFalse;
-
- //----- initialize the generic stuff
- if (!init(dict)) {
- goto err1;
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
}
- if (!hasRange) {
- error(-1, "Type 0 function is missing range");
- goto err1;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
}
+}
- //----- get the stream
- if (!funcObj->isStream()) {
- error(-1, "Type 0 function isn't a stream");
- goto err1;
+GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = shading->matrix[i];
+ }
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
}
- str = funcObj->getStream();
+}
- //----- Size
- if (!dict->lookup("Size", &obj1)->isArray() ||
- obj1.arrayGetLength() != m) {
- error(-1, "Function has missing or invalid size array");
- goto err2;
+GfxFunctionShading::~GfxFunctionShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
}
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(i, &obj2);
- if (!obj2.isInt()) {
- error(-1, "Illegal value in function size array");
- goto err3;
- }
- sampleSize[i] = obj2.getInt();
+}
+
+GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
+ GfxFunctionShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double matrixA[6];
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = 0;
+ x1A = y1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
obj2.free();
}
obj1.free();
- //----- BitsPerSample
- if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
- error(-1, "Function has missing or invalid BitsPerSample");
- goto err2;
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
}
- sampleBits = obj1.getInt();
- sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
obj1.free();
- //----- Encode
- if (dict->lookup("Encode", &obj1)->isArray() &&
- obj1.arrayGetLength() == 2*m) {
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function encode array");
- goto err3;
- }
- encode[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function encode array");
- goto err3;
- }
- encode[i][1] = obj2.getNum();
- obj2.free();
- }
- } else {
- for (i = 0; i < m; ++i) {
- encode[i][0] = 0;
- encode[i][1] = sampleSize[i] - 1;
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
}
- }
- obj1.free();
-
- //----- Decode
- if (dict->lookup("Decode", &obj1)->isArray() &&
- obj1.arrayGetLength() == 2*n) {
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function decode array");
- goto err3;
- }
- decode[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function decode array");
- goto err3;
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ goto err2;
}
- decode[i][1] = obj2.getNum();
obj2.free();
}
} else {
- for (i = 0; i < n; ++i) {
- decode[i][0] = range[i][0];
- decode[i][1] = range[i][1];
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ goto err1;
}
}
obj1.free();
- //----- samples
- nSamples = n;
- for (i = 0; i < m; ++i)
- nSamples *= sampleSize[i];
- samples = (double *)gmalloc(nSamples * sizeof(double));
- buf = 0;
- bits = 0;
- bitMask = (1 << sampleBits) - 1;
- str->reset();
- for (i = 0; i < nSamples; ++i) {
- if (sampleBits == 8) {
- s = str->getChar();
- } else if (sampleBits == 16) {
- s = str->getChar();
- s = (s << 8) + str->getChar();
- } else if (sampleBits == 32) {
- s = str->getChar();
- s = (s << 8) + str->getChar();
- s = (s << 8) + str->getChar();
- s = (s << 8) + str->getChar();
- } else {
- while (bits < sampleBits) {
- buf = (buf << 8) | (str->getChar() & 0xff);
- bits += 8;
- }
- s = (buf >> (bits - sampleBits)) & bitMask;
- bits -= sampleBits;
- }
- samples[i] = (double)s * sampleMul;
+ shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
}
- str->close();
-
- ok = gTrue;
- return;
+ return shading;
- err3:
- obj2.free();
err2:
- obj1.free();
+ obj2.free();
err1:
- return;
+ obj1.free();
+ return NULL;
+}
+
+GfxShading *GfxFunctionShading::copy() {
+ return new GfxFunctionShading(this);
}
-SampledFunction::~SampledFunction() {
- if (samples) {
- gfree(samples);
+void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
+ double in[2], out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ in[0] = x;
+ in[1] = y;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(in, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
}
}
-SampledFunction::SampledFunction(SampledFunction *func) {
- int nSamples, i;
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
- memcpy(this, func, sizeof(SampledFunction));
+GfxAxialShading::GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxShading(2)
+{
+ int i;
- nSamples = n;
- for (i = 0; i < m; ++i) {
- nSamples *= sampleSize[i];
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
}
- samples = (double *)gmalloc(nSamples * sizeof(double));
- memcpy(samples, func->samples, nSamples * sizeof(double));
+ extend0 = extend0A;
+ extend1 = extend1A;
}
-void SampledFunction::transform(double *in, double *out) {
- double e[4];
- double s;
- double x0, x1;
- int e0, e1;
- double efrac;
+GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
+ GfxShading(shading)
+{
int i;
- // map input values into sample array
- for (i = 0; i < m; ++i) {
- e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
- (encode[i][1] - encode[i][0]) + encode[i][0];
- if (e[i] < 0) {
- e[i] = 0;
- } else if (e[i] > sampleSize[i] - 1) {
- e[i] = sampleSize[i] - 1;
- }
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ t0 = shading->t0;
+ y1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
}
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+}
- for (i = 0; i < n; ++i) {
+GfxAxialShading::~GfxAxialShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+ GfxAxialShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = x1A = y1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
+ }
+ obj1.free();
- // m-linear interpolation
- // (only m=1 is currently supported)
- e0 = (int)floor(e[0]);
- e1 = (int)ceil(e[0]);
- efrac = e[0] - e0;
- x0 = samples[e0 * n + i];
- x1 = samples[e1 * n + i];
- s = (1 - efrac) * x0 + efrac * x1;
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
- // map output values to range
- out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
- if (out[i] < range[i][0]) {
- out[i] = range[i][0];
- } else if (out[i] > range[i][1]) {
- out[i] = range[i][1];
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
}
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
+ }
+ obj1.free();
+
+ shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxAxialShading::copy() {
+ return new GfxAxialShading(this);
+}
+
+void GfxAxialShading::getColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
}
}
//------------------------------------------------------------------------
-// ExponentialFunction
+// GfxRadialShading
//------------------------------------------------------------------------
-ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
- Object obj1, obj2;
- GBool hasN;
+GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxShading(3)
+{
int i;
- ok = gFalse;
- hasN = gFalse;
+ x0 = x0A;
+ y0 = y0A;
+ r0 = r0A;
+ x1 = x1A;
+ y1 = y1A;
+ r1 = r1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+ extend0 = extend0A;
+ extend1 = extend1A;
+}
- //----- initialize the generic stuff
- if (!init(dict)) {
- goto err1;
+GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ r0 = shading->r0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ r1 = shading->r1;
+ t0 = shading->t0;
+ y1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+}
+
+GfxRadialShading::~GfxRadialShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
}
- if (m != 1) {
- error(-1, "Exponential function with more than one input");
+}
+
+GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
+ GfxRadialShading *shading;
+ double x0A, y0A, r0A, x1A, y1A, r1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = r0A = x1A = y1A = r1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ r0A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ r1A = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
goto err1;
}
+ obj1.free();
- //----- default values
- for (i = 0; i < funcMaxOutputs; ++i) {
- c0[i] = 0;
- c1[i] = 1;
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
}
+ obj1.free();
- //----- C0
- if (dict->lookup("C0", &obj1)->isArray()) {
- if (!hasN) {
- n = obj1.arrayGetLength();
- } else if (obj1.arrayGetLength() != n) {
- error(-1, "Function's C0 array is wrong length");
- goto err2;
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
}
- for (i = 0; i < n; ++i) {
+ for (i = 0; i < nFuncsA; ++i) {
obj1.arrayGet(i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function C0 array");
- goto err3;
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
}
- c0[i] = obj2.getNum();
obj2.free();
}
- obj1.free();
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
}
+ obj1.free();
- //----- C1
- if (dict->lookup("C1", &obj1)->isArray()) {
- if (!hasN) {
- n = obj1.arrayGetLength();
- } else if (obj1.arrayGetLength() != n) {
- error(-1, "Function's C1 array is wrong length");
- goto err2;
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
+ }
+ obj1.free();
+
+ shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxRadialShading::copy() {
+ return new GfxRadialShading(this);
+}
+
+void GfxRadialShading::getColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxShadingBitBuf
+//------------------------------------------------------------------------
+
+class GfxShadingBitBuf {
+public:
+
+ GfxShadingBitBuf(Stream *strA);
+ ~GfxShadingBitBuf();
+ GBool getBits(int n, Guint *val);
+ void flushBits();
+
+private:
+
+ Stream *str;
+ int bitBuf;
+ int nBits;
+};
+
+GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
+ str = strA;
+ str->reset();
+ bitBuf = 0;
+ nBits = 0;
+}
+
+GfxShadingBitBuf::~GfxShadingBitBuf() {
+ str->close();
+}
+
+GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
+ int x;
+
+ if (nBits >= n) {
+ x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
+ nBits -= n;
+ } else {
+ x = 0;
+ if (nBits > 0) {
+ x = bitBuf & ((1 << nBits) - 1);
+ n -= nBits;
+ nBits = 0;
}
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function C1 array");
- goto err3;
+ while (n > 0) {
+ if ((bitBuf = str->getChar()) == EOF) {
+ nBits = 0;
+ return gFalse;
+ }
+ if (n >= 8) {
+ x = (x << 8) | bitBuf;
+ n -= 8;
+ } else {
+ x = (x << n) | (bitBuf >> (8 - n));
+ nBits = 8 - n;
+ n = 0;
}
- c1[i] = obj2.getNum();
- obj2.free();
}
- obj1.free();
}
+ *val = x;
+ return gTrue;
+}
- //----- N (exponent)
- if (!dict->lookup("N", &obj1)->isNum()) {
- error(-1, "Function has missing or invalid N");
+void GfxShadingBitBuf::flushBits() {
+ bitBuf = 0;
+ nBits = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+ int typeA,
+ GfxGouraudVertex *verticesA, int nVerticesA,
+ int (*trianglesA)[3], int nTrianglesA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(typeA)
+{
+ int i;
+
+ vertices = verticesA;
+ nVertices = nVerticesA;
+ triangles = trianglesA;
+ nTriangles = nTrianglesA;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+ GfxGouraudTriangleShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ nVertices = shading->nVertices;
+ vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
+ memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
+ nTriangles = shading->nTriangles;
+ triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
+ memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
+ int i;
+
+ gfree(vertices);
+ gfree(triangles);
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA,
+ Dict *dict,
+ Stream *str) {
+ GfxGouraudTriangleShading *shading;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ int coordBits, compBits, flagBits, vertsPerRow, nRows;
+ double xMin, xMax, yMin, yMax;
+ double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+ double xMul, yMul;
+ double cMul[gfxColorMaxComps];
+ GfxGouraudVertex *verticesA;
+ int (*trianglesA)[3];
+ int nComps, nVerticesA, nTrianglesA, vertSize, triSize;
+ Guint x, y, flag;
+ Guint c[gfxColorMaxComps];
+ GfxShadingBitBuf *bitBuf;
+ Object obj1, obj2;
+ int i, j, k, state;
+
+ if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+ coordBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+ compBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ flagBits = vertsPerRow = 0; // make gcc happy
+ if (typeA == 4) {
+ if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+ flagBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ } else {
+ if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
+ vertsPerRow = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ }
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() >= 6) {
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+ yMin = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+ for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+ }
+ nComps = i;
+ } else {
+ error(-1, "Missing or invalid Decode array in shading dictionary");
goto err2;
}
- e = obj1.getNum();
obj1.free();
- ok = gTrue;
- return;
+ if (!dict->lookup("Function", &obj1)->isNull()) {
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ } else {
+ nFuncsA = 0;
+ }
+ obj1.free();
+
+ nVerticesA = nTrianglesA = 0;
+ verticesA = NULL;
+ trianglesA = NULL;
+ vertSize = triSize = 0;
+ state = 0;
+ flag = 0; // make gcc happy
+ bitBuf = new GfxShadingBitBuf(str);
+ while (1) {
+ if (typeA == 4) {
+ if (!bitBuf->getBits(flagBits, &flag)) {
+ break;
+ }
+ }
+ if (!bitBuf->getBits(coordBits, &x) ||
+ !bitBuf->getBits(coordBits, &y)) {
+ break;
+ }
+ for (i = 0; i < nComps; ++i) {
+ if (!bitBuf->getBits(compBits, &c[i])) {
+ break;
+ }
+ }
+ if (i < nComps) {
+ break;
+ }
+ if (nVerticesA == vertSize) {
+ vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
+ verticesA = (GfxGouraudVertex *)
+ greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
+ }
+ verticesA[nVerticesA].x = xMin + xMul * (double)x;
+ verticesA[nVerticesA].y = yMin + yMul * (double)y;
+ for (i = 0; i < nComps; ++i) {
+ verticesA[nVerticesA].color.c[i] =
+ dblToCol(cMin[i] + cMul[i] * (double)c[i]);
+ }
+ ++nVerticesA;
+ bitBuf->flushBits();
+ if (typeA == 4) {
+ if (state == 0 || state == 1) {
+ ++state;
+ } else if (state == 2 || flag > 0) {
+ if (nTrianglesA == triSize) {
+ triSize = (triSize == 0) ? 16 : 2 * triSize;
+ trianglesA = (int (*)[3])
+ greallocn(trianglesA, triSize * 3, sizeof(int));
+ }
+ if (state == 2) {
+ trianglesA[nTrianglesA][0] = nVerticesA - 3;
+ trianglesA[nTrianglesA][1] = nVerticesA - 2;
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ ++state;
+ } else if (flag == 1) {
+ trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
+ trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ } else { // flag == 2
+ trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
+ trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ }
+ ++nTrianglesA;
+ } else { // state == 3 && flag == 0
+ state = 1;
+ }
+ }
+ }
+ delete bitBuf;
+ if (typeA == 5) {
+ nRows = nVerticesA / vertsPerRow;
+ nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
+ trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
+ k = 0;
+ for (i = 0; i < nRows - 1; ++i) {
+ for (j = 0; j < vertsPerRow - 1; ++j) {
+ trianglesA[k][0] = i * vertsPerRow + j;
+ trianglesA[k][1] = i * vertsPerRow + j+1;
+ trianglesA[k][2] = (i+1) * vertsPerRow + j;
+ ++k;
+ trianglesA[k][0] = i * vertsPerRow + j+1;
+ trianglesA[k][1] = (i+1) * vertsPerRow + j;
+ trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
+ ++k;
+ }
+ }
+ }
+
+ shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
+ trianglesA, nTrianglesA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
- err3:
- obj2.free();
err2:
obj1.free();
err1:
- return;
+ return NULL;
}
-ExponentialFunction::~ExponentialFunction() {
+GfxShading *GfxGouraudTriangleShading::copy() {
+ return new GfxGouraudTriangleShading(this);
}
-ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
- memcpy(this, func, sizeof(ExponentialFunction));
+void GfxGouraudTriangleShading::getTriangle(
+ int i,
+ double *x0, double *y0, GfxColor *color0,
+ double *x1, double *y1, GfxColor *color1,
+ double *x2, double *y2, GfxColor *color2) {
+ double in;
+ double out[gfxColorMaxComps];
+ int v, j;
+
+ v = triangles[i][0];
+ *x0 = vertices[v].x;
+ *y0 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color0->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color0 = vertices[v].color;
+ }
+ v = triangles[i][1];
+ *x1 = vertices[v].x;
+ *y1 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color1->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color1 = vertices[v].color;
+ }
+ v = triangles[i][2];
+ *x2 = vertices[v].x;
+ *y2 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color2->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color2 = vertices[v].color;
+ }
}
-void ExponentialFunction::transform(double *in, double *out) {
- double x;
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
+ GfxPatch *patchesA, int nPatchesA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(typeA)
+{
+ int i;
+
+ patches = patchesA;
+ nPatches = nPatchesA;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
+ GfxShading(shading)
+{
int i;
- if (in[0] < domain[0][0]) {
- x = domain[0][0];
- } else if (in[0] > domain[0][1]) {
- x = domain[0][1];
+ nPatches = shading->nPatches;
+ patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
+ memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxPatchMeshShading::~GfxPatchMeshShading() {
+ int i;
+
+ gfree(patches);
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
+ Stream *str) {
+ GfxPatchMeshShading *shading;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ int coordBits, compBits, flagBits;
+ double xMin, xMax, yMin, yMax;
+ double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+ double xMul, yMul;
+ double cMul[gfxColorMaxComps];
+ GfxPatch *patchesA, *p;
+ int nComps, nPatchesA, patchesSize, nPts, nColors;
+ Guint flag;
+ double x[16], y[16];
+ Guint xi, yi;
+ GfxColorComp c[4][gfxColorMaxComps];
+ Guint ci[4];
+ GfxShadingBitBuf *bitBuf;
+ Object obj1, obj2;
+ int i, j;
+
+ if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+ coordBits = obj1.getInt();
} else {
- x = in[0];
+ error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+ goto err2;
}
- for (i = 0; i < n; ++i) {
- out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
- if (hasRange) {
- if (out[i] < range[i][0]) {
- out[i] = range[i][0];
- } else if (out[i] > range[i][1]) {
- out[i] = range[i][1];
+ obj1.free();
+ if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+ compBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+ flagBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() >= 6) {
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+ yMin = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+ for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+ }
+ nComps = i;
+ } else {
+ error(-1, "Missing or invalid Decode array in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Function", &obj1)->isNull()) {
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
}
}
+ } else {
+ nFuncsA = 0;
}
- return;
+ obj1.free();
+
+ nPatchesA = 0;
+ patchesA = NULL;
+ patchesSize = 0;
+ bitBuf = new GfxShadingBitBuf(str);
+ while (1) {
+ if (!bitBuf->getBits(flagBits, &flag)) {
+ break;
+ }
+ if (typeA == 6) {
+ switch (flag) {
+ case 0: nPts = 12; nColors = 4; break;
+ case 1:
+ case 2:
+ case 3:
+ default: nPts = 8; nColors = 2; break;
+ }
+ } else {
+ switch (flag) {
+ case 0: nPts = 16; nColors = 4; break;
+ case 1:
+ case 2:
+ case 3:
+ default: nPts = 12; nColors = 2; break;
+ }
+ }
+ for (i = 0; i < nPts; ++i) {
+ if (!bitBuf->getBits(coordBits, &xi) ||
+ !bitBuf->getBits(coordBits, &yi)) {
+ break;
+ }
+ x[i] = xMin + xMul * (double)xi;
+ y[i] = yMin + yMul * (double)yi;
+ }
+ if (i < nPts) {
+ break;
+ }
+ for (i = 0; i < nColors; ++i) {
+ for (j = 0; j < nComps; ++j) {
+ if (!bitBuf->getBits(compBits, &ci[j])) {
+ break;
+ }
+ c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
+ }
+ if (j < nComps) {
+ break;
+ }
+ }
+ if (i < nColors) {
+ break;
+ }
+ if (nPatchesA == patchesSize) {
+ patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
+ patchesA = (GfxPatch *)greallocn(patchesA,
+ patchesSize, sizeof(GfxPatch));
+ }
+ p = &patchesA[nPatchesA];
+ if (typeA == 6) {
+ switch (flag) {
+ case 0:
+ p->x[0][0] = x[0];
+ p->y[0][0] = y[0];
+ p->x[0][1] = x[1];
+ p->y[0][1] = y[1];
+ p->x[0][2] = x[2];
+ p->y[0][2] = y[2];
+ p->x[0][3] = x[3];
+ p->y[0][3] = y[3];
+ p->x[1][3] = x[4];
+ p->y[1][3] = y[4];
+ p->x[2][3] = x[5];
+ p->y[2][3] = y[5];
+ p->x[3][3] = x[6];
+ p->y[3][3] = y[6];
+ p->x[3][2] = x[7];
+ p->y[3][2] = y[7];
+ p->x[3][1] = x[8];
+ p->y[3][1] = y[8];
+ p->x[3][0] = x[9];
+ p->y[3][0] = y[9];
+ p->x[2][0] = x[10];
+ p->y[2][0] = y[10];
+ p->x[1][0] = x[11];
+ p->y[1][0] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = c[0][j];
+ p->color[0][1].c[j] = c[1][j];
+ p->color[1][1].c[j] = c[2][j];
+ p->color[1][0].c[j] = c[3][j];
+ }
+ break;
+ case 1:
+ p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+ p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+ p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+ p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 2:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+ p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+ p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+ p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 3:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+ p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+ p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+ p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+ p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+ p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ }
+ } else {
+ switch (flag) {
+ case 0:
+ p->x[0][0] = x[0];
+ p->y[0][0] = y[0];
+ p->x[0][1] = x[1];
+ p->y[0][1] = y[1];
+ p->x[0][2] = x[2];
+ p->y[0][2] = y[2];
+ p->x[0][3] = x[3];
+ p->y[0][3] = y[3];
+ p->x[1][3] = x[4];
+ p->y[1][3] = y[4];
+ p->x[2][3] = x[5];
+ p->y[2][3] = y[5];
+ p->x[3][3] = x[6];
+ p->y[3][3] = y[6];
+ p->x[3][2] = x[7];
+ p->y[3][2] = y[7];
+ p->x[3][1] = x[8];
+ p->y[3][1] = y[8];
+ p->x[3][0] = x[9];
+ p->y[3][0] = y[9];
+ p->x[2][0] = x[10];
+ p->y[2][0] = y[10];
+ p->x[1][0] = x[11];
+ p->y[1][0] = y[11];
+ p->x[1][1] = x[12];
+ p->y[1][1] = y[12];
+ p->x[1][2] = x[13];
+ p->y[1][2] = y[13];
+ p->x[2][2] = x[14];
+ p->y[2][2] = y[14];
+ p->x[2][1] = x[15];
+ p->y[2][1] = y[15];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = c[0][j];
+ p->color[0][1].c[j] = c[1][j];
+ p->color[1][1].c[j] = c[2][j];
+ p->color[1][0].c[j] = c[3][j];
+ }
+ break;
+ case 1:
+ p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+ p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+ p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+ p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 2:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+ p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+ p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+ p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 3:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+ p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+ p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+ p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+ p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+ p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ }
+ }
+ ++nPatchesA;
+ bitBuf->flushBits();
+ }
+ delete bitBuf;
+
+ if (typeA == 6) {
+ for (i = 0; i < nPatchesA; ++i) {
+ p = &patchesA[i];
+ p->x[1][1] = (-4 * p->x[0][0]
+ +6 * (p->x[0][1] + p->x[1][0])
+ -2 * (p->x[0][3] + p->x[3][0])
+ +3 * (p->x[3][1] + p->x[1][3])
+ - p->x[3][3]) / 9;
+ p->y[1][1] = (-4 * p->y[0][0]
+ +6 * (p->y[0][1] + p->y[1][0])
+ -2 * (p->y[0][3] + p->y[3][0])
+ +3 * (p->y[3][1] + p->y[1][3])
+ - p->y[3][3]) / 9;
+ p->x[1][2] = (-4 * p->x[0][3]
+ +6 * (p->x[0][2] + p->x[1][3])
+ -2 * (p->x[0][0] + p->x[3][3])
+ +3 * (p->x[3][2] + p->x[1][0])
+ - p->x[3][0]) / 9;
+ p->y[1][2] = (-4 * p->y[0][3]
+ +6 * (p->y[0][2] + p->y[1][3])
+ -2 * (p->y[0][0] + p->y[3][3])
+ +3 * (p->y[3][2] + p->y[1][0])
+ - p->y[3][0]) / 9;
+ p->x[2][1] = (-4 * p->x[3][0]
+ +6 * (p->x[3][1] + p->x[2][0])
+ -2 * (p->x[3][3] + p->x[0][0])
+ +3 * (p->x[0][1] + p->x[2][3])
+ - p->x[0][3]) / 9;
+ p->y[2][1] = (-4 * p->y[3][0]
+ +6 * (p->y[3][1] + p->y[2][0])
+ -2 * (p->y[3][3] + p->y[0][0])
+ +3 * (p->y[0][1] + p->y[2][3])
+ - p->y[0][3]) / 9;
+ p->x[2][2] = (-4 * p->x[3][3]
+ +6 * (p->x[3][2] + p->x[2][3])
+ -2 * (p->x[3][0] + p->x[0][3])
+ +3 * (p->x[0][2] + p->x[2][0])
+ - p->x[0][0]) / 9;
+ p->y[2][2] = (-4 * p->y[3][3]
+ +6 * (p->y[3][2] + p->y[2][3])
+ -2 * (p->y[3][0] + p->y[0][3])
+ +3 * (p->y[0][2] + p->y[2][0])
+ - p->y[0][0]) / 9;
+ }
+ }
+
+ shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxPatchMeshShading::copy() {
+ return new GfxPatchMeshShading(this);
}
//------------------------------------------------------------------------
// GfxImageColorMap
//------------------------------------------------------------------------
-GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
- GfxColorSpace *colorSpace) {
+GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
+ GfxColorSpace *colorSpaceA) {
GfxIndexedColorSpace *indexedCS;
GfxSeparationColorSpace *sepCS;
int maxPixel, indexHigh;
+ int maxPixelForAlloc;
Guchar *lookup2;
Function *sepFunc;
Object obj;
- double x;
+ double x[gfxColorMaxComps];
double y[gfxColorMaxComps];
int i, j, k;
ok = gTrue;
// bits per component and color space
- this->bits = bits;
+ bits = bitsA;
maxPixel = (1 << bits) - 1;
- this->colorSpace = colorSpace;
+ maxPixelForAlloc = (1 << (bits>8?bits:8));
+ colorSpace = colorSpaceA;
// get decode map
if (decode->isNull()) {
goto err1;
}
-#if 0 //~
- // handle the case where fewer than 2^n palette entries of an n-bit
- // indexed color space are populated (this happens, e.g., in files
- // optimized by Distiller)
- if (colorSpace->getMode() == csIndexed) {
- i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
- if (i < maxPixel) {
- maxPixel = i;
- }
- }
-#endif
-
// Construct a lookup table -- this stores pre-computed decoded
// values for each component, i.e., the result of applying the
// decode mapping to each possible image pixel component value.
// Optimization: for Indexed and Separation color spaces (which have
// only one component), we store color values in the lookup table
// rather than component values.
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
+ }
colorSpace2 = NULL;
nComps2 = 0;
if (colorSpace->getMode() == csIndexed) {
colorSpace2 = indexedCS->getBase();
indexHigh = indexedCS->getIndexHigh();
nComps2 = colorSpace2->getNComps();
- lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
lookup2 = indexedCS->getLookup();
- for (i = 0; i <= indexHigh; ++i) {
- j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
- for (k = 0; k < nComps2; ++k) {
- lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
+ colorSpace2->getDefaultRanges(x, y, indexHigh);
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
+ if (j < 0) {
+ j = 0;
+ } else if (j > indexHigh) {
+ j = indexHigh;
+ }
+ lookup[k][i] =
+ dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
}
}
} else if (colorSpace->getMode() == csSeparation) {
sepCS = (GfxSeparationColorSpace *)colorSpace;
colorSpace2 = sepCS->getAlt();
nComps2 = colorSpace2->getNComps();
- lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
sepFunc = sepCS->getFunc();
- for (i = 0; i <= maxPixel; ++i) {
- x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
- sepFunc->transform(&x, y);
- for (k = 0; k < nComps2; ++k) {
- lookup[i*nComps2 + k] = y[k];
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+ sepFunc->transform(x, y);
+ lookup[k][i] = dblToCol(y[k]);
}
}
} else {
- lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
- for (i = 0; i <= maxPixel; ++i) {
- for (k = 0; k < nComps; ++k) {
- lookup[i*nComps + k] = decodeLow[k] +
- (i * decodeRange[k]) / maxPixel;
+ for (k = 0; k < nComps; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ lookup[k][i] = dblToCol(decodeLow[k] +
+ (i * decodeRange[k]) / maxPixel);
}
}
}
ok = gFalse;
}
+GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
+ int n, i, k;
+
+ colorSpace = colorMap->colorSpace->copy();
+ bits = colorMap->bits;
+ nComps = colorMap->nComps;
+ nComps2 = colorMap->nComps2;
+ colorSpace2 = NULL;
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
+ }
+ n = 1 << bits;
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+ colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ } else {
+ for (k = 0; k < nComps; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ }
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = colorMap->decodeLow[i];
+ decodeRange[i] = colorMap->decodeRange[i];
+ }
+ ok = gTrue;
+}
+
GfxImageColorMap::~GfxImageColorMap() {
+ int i;
+
delete colorSpace;
- gfree(lookup);
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ gfree(lookup[i]);
+ }
}
-void GfxImageColorMap::getGray(Guchar *x, double *gray) {
+void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
GfxColor color;
- double *p;
int i;
if (colorSpace2) {
- p = &lookup[x[0] * nComps2];
for (i = 0; i < nComps2; ++i) {
- color.c[i] = *p++;
+ color.c[i] = lookup[i][x[0]];
}
colorSpace2->getGray(&color, gray);
} else {
for (i = 0; i < nComps; ++i) {
- color.c[i] = lookup[x[i] * nComps + i];
+ color.c[i] = lookup[i][x[i]];
}
colorSpace->getGray(&color, gray);
}
void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
GfxColor color;
- double *p;
int i;
if (colorSpace2) {
- p = &lookup[x[0] * nComps2];
for (i = 0; i < nComps2; ++i) {
- color.c[i] = *p++;
+ color.c[i] = lookup[i][x[0]];
}
colorSpace2->getRGB(&color, rgb);
} else {
for (i = 0; i < nComps; ++i) {
- color.c[i] = lookup[x[i] * nComps + i];
+ color.c[i] = lookup[i][x[i]];
}
colorSpace->getRGB(&color, rgb);
}
void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
GfxColor color;
- double *p;
int i;
if (colorSpace2) {
- p = &lookup[x[0] * nComps2];
for (i = 0; i < nComps2; ++i) {
- color.c[i] = *p++;
+ color.c[i] = lookup[i][x[0]];
}
colorSpace2->getCMYK(&color, cmyk);
} else {
for (i = 0; i < nComps; ++i) {
- color.c[i] = lookup[x[i] * nComps + i];
+ color.c[i] = lookup[i][x[i]];
}
colorSpace->getCMYK(&color, cmyk);
}
}
+void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
+ int maxPixel, i;
+
+ maxPixel = (1 << bits) - 1;
+ for (i = 0; i < nComps; ++i) {
+ color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel);
+ }
+}
+
//------------------------------------------------------------------------
// GfxSubpath and GfxPath
//------------------------------------------------------------------------
GfxSubpath::GfxSubpath(double x1, double y1) {
size = 16;
- x = (double *)gmalloc(size * sizeof(double));
- y = (double *)gmalloc(size * sizeof(double));
- curve = (GBool *)gmalloc(size * sizeof(GBool));
+ x = (double *)gmallocn(size, sizeof(double));
+ y = (double *)gmallocn(size, sizeof(double));
+ curve = (GBool *)gmallocn(size, sizeof(GBool));
n = 1;
x[0] = x1;
y[0] = y1;
GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
size = subpath->size;
n = subpath->n;
- x = (double *)gmalloc(size * sizeof(double));
- y = (double *)gmalloc(size * sizeof(double));
- curve = (GBool *)gmalloc(size * sizeof(GBool));
+ x = (double *)gmallocn(size, sizeof(double));
+ y = (double *)gmallocn(size, sizeof(double));
+ curve = (GBool *)gmallocn(size, sizeof(GBool));
memcpy(x, subpath->x, n * sizeof(double));
memcpy(y, subpath->y, n * sizeof(double));
memcpy(curve, subpath->curve, n * sizeof(GBool));
void GfxSubpath::lineTo(double x1, double y1) {
if (n >= size) {
size += 16;
- x = (double *)grealloc(x, size * sizeof(double));
- y = (double *)grealloc(y, size * sizeof(double));
- curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+ x = (double *)greallocn(x, size, sizeof(double));
+ y = (double *)greallocn(y, size, sizeof(double));
+ curve = (GBool *)greallocn(curve, size, sizeof(GBool));
}
x[n] = x1;
y[n] = y1;
double x3, double y3) {
if (n+3 > size) {
size += 16;
- x = (double *)grealloc(x, size * sizeof(double));
- y = (double *)grealloc(y, size * sizeof(double));
- curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+ x = (double *)greallocn(x, size, sizeof(double));
+ y = (double *)greallocn(y, size, sizeof(double));
+ curve = (GBool *)greallocn(curve, size, sizeof(GBool));
}
x[n] = x1;
y[n] = y1;
closed = gTrue;
}
+void GfxSubpath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ x[i] += dx;
+ y[i] += dy;
+ }
+}
+
GfxPath::GfxPath() {
justMoved = gFalse;
size = 16;
n = 0;
firstX = firstY = 0;
- subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+ subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
}
GfxPath::~GfxPath() {
firstY = firstY1;
size = size1;
n = n1;
- subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+ subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
for (i = 0; i < n; ++i)
subpaths[i] = subpaths1[i]->copy();
}
if (n >= size) {
size += 16;
subpaths = (GfxSubpath **)
- grealloc(subpaths, size * sizeof(GfxSubpath *));
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
}
subpaths[n] = new GfxSubpath(firstX, firstY);
++n;
if (n >= size) {
size += 16;
subpaths = (GfxSubpath **)
- grealloc(subpaths, size * sizeof(GfxSubpath *));
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
}
subpaths[n] = new GfxSubpath(firstX, firstY);
++n;
subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
}
+void GfxPath::close() {
+ // this is necessary to handle the pathological case of
+ // moveto/closepath/clip, which defines an empty clipping region
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->close();
+}
+
+void GfxPath::append(GfxPath *path) {
+ int i;
+
+ if (n + path->n > size) {
+ size = n + path->n;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ for (i = 0; i < path->n; ++i) {
+ subpaths[n++] = path->subpaths[i]->copy();
+ }
+ justMoved = gFalse;
+}
+
+void GfxPath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ subpaths[i]->offset(dx, dy);
+ }
+}
//------------------------------------------------------------------------
// GfxState
//------------------------------------------------------------------------
-GfxState::GfxState(double dpi, double px1a, double py1a,
- double px2a, double py2a, int rotate, GBool upsideDown) {
- double k;
-
- px1 = px1a;
- py1 = py1a;
- px2 = px2a;
- py2 = py2a;
- k = dpi / 72.0;
+GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
+ int rotateA, GBool upsideDown) {
+ double kx, ky;
+
+ rotate = rotateA;
+ px1 = pageBox->x1;
+ py1 = pageBox->y1;
+ px2 = pageBox->x2;
+ py2 = pageBox->y2;
+ kx = hDPI / 72.0;
+ ky = vDPI / 72.0;
if (rotate == 90) {
ctm[0] = 0;
- ctm[1] = upsideDown ? k : -k;
- ctm[2] = k;
+ ctm[1] = upsideDown ? ky : -ky;
+ ctm[2] = kx;
ctm[3] = 0;
- ctm[4] = -k * py1;
- ctm[5] = k * (upsideDown ? -px1 : px2);
- pageWidth = k * (py2 - py1);
- pageHeight = k * (px2 - px1);
+ ctm[4] = -kx * py1;
+ ctm[5] = ky * (upsideDown ? -px1 : px2);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
} else if (rotate == 180) {
- ctm[0] = -k;
+ ctm[0] = -kx;
ctm[1] = 0;
ctm[2] = 0;
- ctm[3] = upsideDown ? k : -k;
- ctm[4] = k * px2;
- ctm[5] = k * (upsideDown ? -py1 : py2);
- pageWidth = k * (px2 - px1);
- pageHeight = k * (py2 - py1);
+ ctm[3] = upsideDown ? ky : -ky;
+ ctm[4] = kx * px2;
+ ctm[5] = ky * (upsideDown ? -py1 : py2);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
} else if (rotate == 270) {
ctm[0] = 0;
- ctm[1] = upsideDown ? -k : k;
- ctm[2] = -k;
+ ctm[1] = upsideDown ? -ky : ky;
+ ctm[2] = -kx;
ctm[3] = 0;
- ctm[4] = k * py2;
- ctm[5] = k * (upsideDown ? px2 : -px1);
- pageWidth = k * (py2 - py1);
- pageHeight = k * (px2 - px1);
+ ctm[4] = kx * py2;
+ ctm[5] = ky * (upsideDown ? px2 : -px1);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
} else {
- ctm[0] = k;
+ ctm[0] = kx;
ctm[1] = 0;
ctm[2] = 0;
- ctm[3] = upsideDown ? -k : k;
- ctm[4] = -k * px1;
- ctm[5] = k * (upsideDown ? py2 : -py1);
- pageWidth = k * (px2 - px1);
- pageHeight = k * (py2 - py1);
+ ctm[3] = upsideDown ? -ky : ky;
+ ctm[4] = -kx * px1;
+ ctm[5] = ky * (upsideDown ? py2 : -py1);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
}
fillColorSpace = new GfxDeviceGrayColorSpace();
strokeColor.c[0] = 0;
fillPattern = NULL;
strokePattern = NULL;
+ blendMode = gfxBlendNormal;
fillOpacity = 1;
strokeOpacity = 1;
+ fillOverprint = gFalse;
+ strokeOverprint = gFalse;
lineWidth = 1;
lineDash = NULL;
lineDashLength = 0;
lineDashStart = 0;
- flatness = 0;
+ flatness = 1;
lineJoin = 0;
lineCap = 0;
miterLimit = 10;
curX = curY = 0;
lineX = lineY = 0;
+ clipXMin = 0;
+ clipYMin = 0;
+ clipXMax = pageWidth;
+ clipYMax = pageHeight;
+
saved = NULL;
}
delete strokePattern;
}
gfree(lineDash);
- delete path;
+ if (path) {
+ // this gets set to NULL by restore()
+ delete path;
+ }
if (saved) {
delete saved;
}
strokePattern = state->strokePattern->copy();
}
if (lineDashLength > 0) {
- lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
+ lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
}
- path = state->path->copy();
saved = NULL;
}
+void GfxState::setPath(GfxPath *pathA) {
+ delete path;
+ path = pathA;
+}
+
+void GfxState::getUserClipBBox(double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ double ictm[6];
+ double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
+
+ // invert the CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+
+ // transform all four corners of the clip bbox; find the min and max
+ // x and y values
+ xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+
+ *xMin = xMin1;
+ *yMin = yMin1;
+ *xMax = xMax1;
+ *yMax = yMax1;
+}
+
double GfxState::transformWidth(double w) {
double x, y;
void GfxState::setCTM(double a, double b, double c,
double d, double e, double f) {
+ int i;
+
ctm[0] = a;
ctm[1] = b;
ctm[2] = c;
ctm[3] = d;
ctm[4] = e;
ctm[5] = f;
+
+ // avoid FP exceptions on badly messed up PDF files
+ for (i = 0; i < 6; ++i) {
+ if (ctm[i] > 1e10) {
+ ctm[i] = 1e10;
+ } else if (ctm[i] < -1e10) {
+ ctm[i] = -1e10;
+ }
+ }
}
void GfxState::concatCTM(double a, double b, double c,
double b1 = ctm[1];
double c1 = ctm[2];
double d1 = ctm[3];
+ int i;
ctm[0] = a * a1 + b * c1;
ctm[1] = a * b1 + b * d1;
ctm[3] = c * b1 + d * d1;
ctm[4] = e * a1 + f * c1 + ctm[4];
ctm[5] = e * b1 + f * d1 + ctm[5];
+
+ // avoid FP exceptions on badly messed up PDF files
+ for (i = 0; i < 6; ++i) {
+ if (ctm[i] > 1e10) {
+ ctm[i] = 1e10;
+ } else if (ctm[i] < -1e10) {
+ ctm[i] = -1e10;
+ }
+ }
}
void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
path = new GfxPath();
}
-void GfxState::textShift(double tx) {
- double dx, dy;
-
- textTransformDelta(tx, 0, &dx, &dy);
- curX += dx;
- curY += dy;
+void GfxState::clip() {
+ double xMin, yMin, xMax, yMax, x, y;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
}
void GfxState::textShift(double tx, double ty) {
curY += dy;
}
+void GfxState::shift(double dx, double dy) {
+ curX += dx;
+ curY += dy;
+}
+
GfxState *GfxState::save() {
GfxState *newState;
if (saved) {
oldState = saved;
+
+ // these attributes aren't saved/restored by the q/Q operators
+ oldState->path = path;
+ oldState->curX = curX;
+ oldState->curY = curY;
+ oldState->lineX = lineX;
+ oldState->lineY = lineY;
+
+ path = NULL;
saved = NULL;
delete this;
+
} else {
oldState = this;
}
+
return oldState;
}
+
+GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
+ Object obj2;
+ int i, j;
+
+ if (obj->isName()) {
+ for (i = 0; i < nGfxBlendModeNames; ++i) {
+ if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
+ *mode = gfxBlendModeNames[i].mode;
+ return gTrue;
+ }
+ }
+ return gFalse;
+ } else if (obj->isArray()) {
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
+ obj->arrayGet(i, &obj2);
+ if (!obj2.isName()) {
+ obj2.free();
+ return gFalse;
+ }
+ for (j = 0; j < nGfxBlendModeNames; ++j) {
+ if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
+ obj2.free();
+ *mode = gfxBlendModeNames[j].mode;
+ return gTrue;
+ }
+ }
+ obj2.free();
+ }
+ *mode = gfxBlendNormal;
+ return gTrue;
+ } else {
+ return gFalse;
+ }
+}