From 7aac8dc8533347e21311b15186e0af82f1b22fd6 Mon Sep 17 00:00:00 2001 From: Martin Kretzschmar Date: Wed, 18 Sep 2002 20:32:18 +0000 Subject: Synched with Xpdf 0.92 this adds "decryption" support testing this code after six weeks immediately gives me segfaults (image drawing) :-O must have fixed that later without knowing :-O --- (limited to 'pdf/xpdf/GfxState.cc') diff --git a/pdf/xpdf/GfxState.cc b/pdf/xpdf/GfxState.cc index c1b6090..1abf9a5 100644 --- a/pdf/xpdf/GfxState.cc +++ b/pdf/xpdf/GfxState.cc @@ -16,269 +16,1288 @@ #include "gmem.h" #include "Error.h" #include "Object.h" +#include "Array.h" #include "GfxState.h" //------------------------------------------------------------------------ -// GfxColor -//------------------------------------------------------------------------ -void GfxColor::setCMYK(double c, double m, double y, double k) { - if ((r = 1 - (c + k)) < 0) - r = 0; - if ((g = 1 - (m + k)) < 0) - g = 0; - if ((b = 1 - (y + k)) < 0) - b = 0; +static inline double clip01(double x) { + return (x < 0) ? 0 : ((x > 1) ? 1 : x); } //------------------------------------------------------------------------ // GfxColorSpace //------------------------------------------------------------------------ -GfxColorSpace::GfxColorSpace(Object *colorSpace) { - Object csObj; - Object obj, obj2; - char *s; - int x; - int i, j; +GfxColorSpace::GfxColorSpace() { +} - ok = gTrue; - lookup = NULL; - - // check for Separation, DeviceN, and Pattern colorspaces - colorSpace->copy(&csObj); - sepFunc = NULL; - if (colorSpace->isArray()) { - colorSpace->arrayGet(0, &obj); - if (obj.isName("Separation") || obj.isName("DeviceN")) { - csObj.free(); - colorSpace->arrayGet(2, &csObj); - sepFunc = new Function(colorSpace->arrayGet(3, &obj2)); - obj2.free(); - if (!sepFunc->isOk()) { - delete sepFunc; - sepFunc = NULL; - } - } else if (obj.isName("Pattern")) { - csObj.free(); - colorSpace->arrayGet(1, &csObj); - } - obj.free(); - } - - // get mode - indexed = gFalse; - if (csObj.isName()) { - setMode(&csObj); - } else if (csObj.isArray()) { - csObj.arrayGet(0, &obj); - if (obj.isName("Indexed") || obj.isName("I")) { - indexed = gTrue; - setMode(csObj.arrayGet(1, &obj2)); - obj2.free(); +GfxColorSpace::~GfxColorSpace() { +} + +GfxColorSpace *GfxColorSpace::parse(Object *csObj) { + GfxColorSpace *cs; + Object obj1; + + cs = NULL; + if (csObj->isName()) { + if (csObj->isName("DeviceGray") || csObj->isName("G")) { + cs = new GfxDeviceGrayColorSpace(); + } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) { + cs = new GfxDeviceRGBColorSpace(); + } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) { + cs = new GfxDeviceCMYKColorSpace(); + } else if (csObj->isName("Pattern")) { + cs = new GfxPatternColorSpace(NULL); } else { - setMode(&csObj); + error(-1, "Bad color space '%s'", csObj->getName()); } - obj.free(); + } else if (csObj->isArray()) { + csObj->arrayGet(0, &obj1); + if (obj1.isName("DeviceGray") || obj1.isName("G")) { + cs = new GfxDeviceGrayColorSpace(); + } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) { + cs = new GfxDeviceRGBColorSpace(); + } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { + cs = new GfxDeviceCMYKColorSpace(); + } else if (obj1.isName("CalGray")) { + cs = GfxCalGrayColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("CalRGB")) { + cs = GfxCalRGBColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Lab")) { + cs = GfxLabColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("ICCBased")) { + cs = GfxICCBasedColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Indexed") || obj1.isName("I")) { + cs = GfxIndexedColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Separation")) { + cs = GfxSeparationColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("DeviceN")) { + cs = GfxDeviceNColorSpace::parse(csObj->getArray()); + } else if (obj1.isName("Pattern")) { + cs = GfxPatternColorSpace::parse(csObj->getArray()); + } else { + error(-1, "Bad color space '%s'", csObj->getName()); + } + obj1.free(); } else { - goto err1; + error(-1, "Bad color space - expected name or array"); } - if (!ok) { - goto err1; + return cs; +} + +void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel) { + int i; + + for (i = 0; i < getNComps(); ++i) { + decodeLow[i] = 0; + decodeRange[i] = 1; } +} - // get lookup table for indexed colorspace - if (indexed) { - csObj.arrayGet(2, &obj); - if (!obj.isInt()) - goto err2; - indexHigh = obj.getInt(); - obj.free(); - lookup = (Guchar (*)[4])gmalloc((indexHigh + 1) * 4 * sizeof(Guchar)); - csObj.arrayGet(3, &obj); - if (obj.isStream()) { - obj.streamReset(); - for (i = 0; i <= indexHigh; ++i) { - for (j = 0; j < numComps; ++j) { - if ((x = obj.streamGetChar()) == EOF) - goto err2; - lookup[i][j] = (Guchar)x; - } - } - } else if (obj.isString()) { - s = obj.getString()->getCString(); - for (i = 0; i <= indexHigh; ++i) - for (j = 0; j < numComps; ++j) - lookup[i][j] = (Guchar)*s++; - } else { - goto err2; - } - obj.free(); +//------------------------------------------------------------------------ +// GfxDeviceGrayColorSpace +//------------------------------------------------------------------------ + +GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() { +} + +GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() { +} + +GfxColorSpace *GfxDeviceGrayColorSpace::copy() { + return new GfxDeviceGrayColorSpace(); +} + +void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) { + *gray = clip01(color->c[0]); +} + +void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = rgb->g = rgb->b = 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]); +} + +//------------------------------------------------------------------------ +// GfxCalGrayColorSpace +//------------------------------------------------------------------------ + +GfxCalGrayColorSpace::GfxCalGrayColorSpace() { + whiteX = whiteY = whiteZ = 1; + blackX = blackY = blackZ = 0; + gamma = 1; +} + +GfxCalGrayColorSpace::~GfxCalGrayColorSpace() { +} + +GfxColorSpace *GfxCalGrayColorSpace::copy() { + GfxCalGrayColorSpace *cs; + + cs = new GfxCalGrayColorSpace(); + cs->whiteX = whiteX; + cs->whiteY = whiteY; + cs->whiteZ = whiteZ; + cs->blackX = blackX; + cs->blackY = blackY; + cs->blackZ = blackZ; + cs->gamma = gamma; + return cs; +} + +GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { + GfxCalGrayColorSpace *cs; + Object obj1, obj2, obj3; + + arr->get(1, &obj1); + if (!obj1.isDict()) { + error(-1, "Bad CalGray color space"); + obj1.free(); + return NULL; } + cs = new GfxCalGrayColorSpace(); + if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->whiteX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->whiteY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->whiteZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->blackX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->blackY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->blackZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Gamma", &obj2)->isNum()) { + cs->gamma = obj2.getNum(); + } + obj2.free(); + obj1.free(); + return cs; +} - csObj.free(); - return; +void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) { + *gray = clip01(color->c[0]); +} - err2: - obj.free(); - err1: - csObj.free(); - ok = gFalse; +void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = rgb->g = rgb->b = 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]); +} + +//------------------------------------------------------------------------ +// GfxDeviceRGBColorSpace +//------------------------------------------------------------------------ + +GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() { +} + +GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() { +} + +GfxColorSpace *GfxDeviceRGBColorSpace::copy() { + 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]); } -GfxColorSpace::GfxColorSpace(GfxColorMode mode1) { - sepFunc = NULL; - mode = mode1; - indexed = gFalse; - switch (mode) { - case colorGray: numComps = 1; break; - case colorCMYK: numComps = 4; break; - case colorRGB: numComps = 3; break; +void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = clip01(color->c[0]); + rgb->g = clip01(color->c[1]); + rgb->b = clip01(color->c[2]); +} + +void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double c, m, y, k; + + c = clip01(1 - color->c[0]); + m = clip01(1 - color->c[1]); + y = clip01(1 - color->c[2]); + k = c; + if (m < k) { + k = m; } - lookup = NULL; - ok = gTrue; + if (y < k) { + k = y; + } + cmyk->c = c - k; + cmyk->m = m - k; + cmyk->y = y - k; + cmyk->k = k; } -GfxColorSpace::~GfxColorSpace() { - if (sepFunc) - delete sepFunc; - gfree(lookup); +//------------------------------------------------------------------------ +// GfxCalRGBColorSpace +//------------------------------------------------------------------------ + +GfxCalRGBColorSpace::GfxCalRGBColorSpace() { + 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; } -GfxColorSpace::GfxColorSpace(GfxColorSpace *colorSpace) { - int size; - - if (colorSpace->sepFunc) - sepFunc = colorSpace->sepFunc->copy(); - else - sepFunc = NULL; - mode = colorSpace->mode; - indexed = colorSpace->indexed; - numComps = colorSpace->numComps; - indexHigh = colorSpace->indexHigh; - if (indexed) { - size = (indexHigh + 1) * 4 * sizeof(Guchar); - lookup = (Guchar (*)[4])gmalloc(size); - memcpy(lookup, colorSpace->lookup, size); - } else { - lookup = NULL; +GfxCalRGBColorSpace::~GfxCalRGBColorSpace() { +} + +GfxColorSpace *GfxCalRGBColorSpace::copy() { + GfxCalRGBColorSpace *cs; + int i; + + cs = new GfxCalRGBColorSpace(); + cs->whiteX = whiteX; + cs->whiteY = whiteY; + cs->whiteZ = whiteZ; + cs->blackX = blackX; + cs->blackY = blackY; + cs->blackZ = blackZ; + cs->gammaR = gammaR; + cs->gammaG = gammaG; + cs->gammaB = gammaB; + for (i = 0; i < 9; ++i) { + cs->m[i] = m[i]; } - ok = gTrue; + return cs; } -void GfxColorSpace::setMode(Object *colorSpace) { - Object obj; +GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { + GfxCalRGBColorSpace *cs; + Object obj1, obj2, obj3; + int i; - if (colorSpace->isName("DeviceGray") || colorSpace->isName("G")) { - mode = colorGray; - numComps = 1; - } else if (colorSpace->isName("DeviceRGB") || colorSpace->isName("RGB")) { - mode = colorRGB; - numComps = 3; - } else if (colorSpace->isName("DeviceCMYK") || colorSpace->isName("CMYK")) { - mode = colorCMYK; - numComps = 4; - } else if (colorSpace->isArray()) { - colorSpace->arrayGet(0, &obj); - if (obj.isName("CalGray")) { - mode = colorGray; - numComps = 1; - } else if (obj.isName("CalRGB")) { - mode = colorRGB; - numComps = 3; - } else if (obj.isName("CalCMYK")) { - mode = colorCMYK; - numComps = 4; - } else { - ok = gFalse; + arr->get(1, &obj1); + if (!obj1.isDict()) { + error(-1, "Bad CalRGB color space"); + obj1.free(); + return NULL; + } + cs = new GfxCalRGBColorSpace(); + if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->whiteX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->whiteY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->whiteZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->blackX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->blackY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->blackZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Gamma", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->gammaR = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->gammaG = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->gammaB = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Matrix", &obj2)->isArray() && + obj2.arrayGetLength() == 9) { + for (i = 0; i < 9; ++i) { + obj2.arrayGet(i, &obj3); + cs->m[i] = obj3.getNum(); + obj3.free(); } - obj.free(); + } + obj2.free(); + obj1.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::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = clip01(color->c[0]); + rgb->g = clip01(color->c[1]); + rgb->b = clip01(color->c[2]); +} + +void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double c, m, y, k; + + c = clip01(1 - color->c[0]); + m = clip01(1 - color->c[1]); + y = clip01(1 - color->c[2]); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + cmyk->c = c - k; + cmyk->m = m - k; + cmyk->y = y - k; + cmyk->k = k; +} + +//------------------------------------------------------------------------ +// GfxDeviceCMYKColorSpace +//------------------------------------------------------------------------ + +GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() { +} + +GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() { +} + +GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { + 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::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])); +} + +void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + cmyk->c = clip01(color->c[0]); + cmyk->m = clip01(color->c[1]); + cmyk->y = clip01(color->c[2]); + cmyk->k = clip01(color->c[3]); +} + +//------------------------------------------------------------------------ +// GfxLabColorSpace +//------------------------------------------------------------------------ + +// This is the inverse of MatrixLMN in Example 4.10 from the PostScript +// Language Reference, Third Edition. +static double xyzrgb[3][3] = { + { 3.240449, -1.537136, -0.498531 }, + { -0.969265, 1.876011, 0.041556 }, + { 0.055643, -0.204026, 1.057229 } +}; + +GfxLabColorSpace::GfxLabColorSpace() { + whiteX = whiteY = whiteZ = 1; + blackX = blackY = blackZ = 0; + aMin = bMin = -100; + aMax = bMax = 100; +} + +GfxLabColorSpace::~GfxLabColorSpace() { +} + +GfxColorSpace *GfxLabColorSpace::copy() { + GfxLabColorSpace *cs; + + cs = new GfxLabColorSpace(); + cs->whiteX = whiteX; + cs->whiteY = whiteY; + cs->whiteZ = whiteZ; + cs->blackX = blackX; + cs->blackY = blackY; + cs->blackZ = blackZ; + cs->aMin = aMin; + cs->aMax = aMax; + cs->bMin = bMin; + cs->bMax = bMax; + cs->kr = kr; + cs->kg = kg; + cs->kb = kb; + return cs; +} + +GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { + GfxLabColorSpace *cs; + Object obj1, obj2, obj3; + + arr->get(1, &obj1); + if (!obj1.isDict()) { + error(-1, "Bad Lab color space"); + obj1.free(); + return NULL; + } + cs = new GfxLabColorSpace(); + if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->whiteX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->whiteY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->whiteZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && + obj2.arrayGetLength() == 3) { + obj2.arrayGet(0, &obj3); + cs->blackX = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->blackY = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->blackZ = obj3.getNum(); + obj3.free(); + } + obj2.free(); + if (obj1.dictLookup("Range", &obj2)->isArray() && + obj2.arrayGetLength() == 4) { + obj2.arrayGet(0, &obj3); + cs->aMin = obj3.getNum(); + obj3.free(); + obj2.arrayGet(1, &obj3); + cs->aMax = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2, &obj3); + cs->bMin = obj3.getNum(); + obj3.free(); + obj2.arrayGet(3, &obj3); + cs->bMax = obj3.getNum(); + obj3.free(); + } + obj2.free(); + obj1.free(); + + cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + + xyzrgb[0][1] * cs->whiteY + + xyzrgb[0][2] * cs->whiteZ); + cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + + xyzrgb[1][1] * cs->whiteY + + xyzrgb[1][2] * cs->whiteZ); + cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + + xyzrgb[2][1] * cs->whiteY + + xyzrgb[2][2] * cs->whiteZ); + + return cs; +} + +void GfxLabColorSpace::getGray(GfxColor *color, double *gray) { + GfxRGB rgb; + + getRGB(color, &rgb); + *gray = clip01(0.299 * rgb.r + + 0.587 * rgb.g + + 0.114 * rgb.b); +} + +void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double X, Y, Z; + double t1, t2; + 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; + if (t2 >= (6.0 / 29.0)) { + X = t2 * t2 * t2; + } else { + X = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); + } + X *= whiteX; + if (t1 >= (6.0 / 29.0)) { + Y = t1 * t1 * t1; + } else { + Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0)); + } + Y *= whiteY; + t2 = t1 - color->c[2] / 200; + if (t2 >= (6.0 / 29.0)) { + Z = t2 * t2 * t2; } else { - ok = gFalse; + Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); } + Z *= whiteZ; + + // convert XYZ to RGB, including gamut mapping and gamma correction + 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); } -void GfxColorSpace::getColor(double x[4], GfxColor *color) { - double y[4]; - Guchar *p; +void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxRGB rgb; + double c, m, y, k; + + getRGB(color, &rgb); + c = clip01(1 - rgb.r); + m = clip01(1 - rgb.g); + y = clip01(1 - rgb.b); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + cmyk->c = c - k; + cmyk->m = m - k; + cmyk->y = y - k; + cmyk->k = k; +} - if (sepFunc) { - sepFunc->transform(x, y); +void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel) { + decodeLow[0] = 0; + decodeRange[0] = 100; + decodeLow[1] = aMin; + decodeRange[1] = aMax - aMin; + decodeLow[2] = bMin; + decodeRange[2] = bMax - bMin; +} + +//------------------------------------------------------------------------ +// GfxICCBasedColorSpace +//------------------------------------------------------------------------ + +GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt, + Ref *iccProfileStream) { + this->nComps = nComps; + this->alt = alt; + this->iccProfileStream = *iccProfileStream; + rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0; + rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1; +} + +GfxICCBasedColorSpace::~GfxICCBasedColorSpace() { + delete alt; +} + +GfxColorSpace *GfxICCBasedColorSpace::copy() { + GfxICCBasedColorSpace *cs; + int i; + + cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream); + for (i = 0; i < 4; ++i) { + cs->rangeMin[i] = rangeMin[i]; + cs->rangeMax[i] = rangeMax[i]; + } + return cs; +} + +GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { + GfxICCBasedColorSpace *cs; + Ref iccProfileStream; + int nComps; + GfxColorSpace *alt; + Dict *dict; + Object obj1, obj2, obj3; + int i; + + arr->getNF(1, &obj1); + if (obj1.isRef()) { + iccProfileStream = obj1.getRef(); } else { - y[0] = x[0]; - y[1] = x[1]; - y[2] = x[2]; - y[3] = x[3]; - } - if (indexed) { - p = lookup[(int)(y[0] + 0.5)]; - switch (mode) { - case colorGray: - color->setGray(p[0] / 255.0); + iccProfileStream.num = 0; + iccProfileStream.gen = 0; + } + obj1.free(); + arr->get(1, &obj1); + if (!obj1.isStream()) { + error(-1, "Bad ICCBased color space (stream)"); + obj1.free(); + return NULL; + } + dict = obj1.streamGetDict(); + if (!dict->lookup("N", &obj2)->isInt()) { + error(-1, "Bad ICCBased color space (N)"); + obj2.free(); + obj1.free(); + return NULL; + } + nComps = obj2.getInt(); + obj2.free(); + if (dict->lookup("Alternate", &obj2)->isNull() || + !(alt = GfxColorSpace::parse(&obj2))) { + switch (nComps) { + case 1: + alt = new GfxDeviceGrayColorSpace(); break; - case colorCMYK: - color->setCMYK(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0, p[3] / 255.0); + case 3: + alt = new GfxDeviceRGBColorSpace(); break; - case colorRGB: - color->setRGB(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0); + case 4: + alt = new GfxDeviceCMYKColorSpace(); break; + default: + error(-1, "Bad ICCBased color space - invalid N"); + obj2.free(); + obj1.free(); + return NULL; + } + } + obj2.free(); + cs = new GfxICCBasedColorSpace(nComps, alt, &iccProfileStream); + if (dict->lookup("Range", &obj2)->isArray() && + obj2.arrayGetLength() == 2 * nComps) { + for (i = 0; i < nComps; ++i) { + obj2.arrayGet(2*i, &obj3); + cs->rangeMin[i] = obj3.getNum(); + obj3.free(); + obj2.arrayGet(2*i+1, &obj3); + cs->rangeMax[i] = obj3.getNum(); + obj3.free(); + } + } + obj2.free(); + obj1.free(); + return cs; +} + +void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) { + alt->getGray(color, gray); +} + +void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + alt->getRGB(color, rgb); +} + +void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + alt->getCMYK(color, cmyk); +} + +void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, + double *decodeRange, + int maxImgPixel) { + int i; + + for (i = 0; i < nComps; ++i) { + decodeLow[i] = rangeMin[i]; + decodeRange[i] = rangeMax[i] - rangeMin[i]; + } +} + +//------------------------------------------------------------------------ +// 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() { + delete base; + gfree(lookup); +} + +GfxColorSpace *GfxIndexedColorSpace::copy() { + GfxIndexedColorSpace *cs; + + cs = new GfxIndexedColorSpace(base->copy(), indexHigh); + memcpy(cs->lookup, lookup, + (indexHigh + 1) * base->getNComps() * sizeof(Guchar)); + return cs; +} + +GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { + GfxIndexedColorSpace *cs; + GfxColorSpace *base; + int indexHigh; + Object obj1; + int x; + char *s; + int n, i, j; + + if (arr->getLength() != 4) { + error(-1, "Bad Indexed color space"); + goto err1; + } + arr->get(1, &obj1); + if (!(base = 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)"); + goto err2; + } + indexHigh = obj1.getInt(); + obj1.free(); + cs = new GfxIndexedColorSpace(base, indexHigh); + arr->get(3, &obj1); + n = base->getNComps(); + if (obj1.isStream()) { + obj1.streamReset(); + for (i = 0; i <= indexHigh; ++i) { + for (j = 0; j < n; ++j) { + if ((x = obj1.streamGetChar()) == EOF) { + error(-1, "Bad Indexed color space (lookup table stream too short)"); + goto err3; + } + cs->lookup[i*n + j] = (Guchar)x; + } + } + obj1.streamClose(); + } else if (obj1.isString()) { + if (obj1.getString()->getLength() < (indexHigh + 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 (j = 0; j < n; ++j) { + cs->lookup[i*n + j] = (Guchar)*s++; + } } } else { - switch (mode) { - case colorGray: - color->setGray(y[0]); - break; - case colorCMYK: - color->setCMYK(y[0], y[1], y[2], y[3]); - break; - case colorRGB: - color->setRGB(y[0], y[1], y[2]); - break; + error(-1, "Bad Indexed color space (lookup table)"); + goto err3; + } + obj1.free(); + return cs; + + err3: + delete cs; + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) { + 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->getGray(&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); +} + +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); +} + +void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, + double *decodeRange, + int maxImgPixel) { + decodeLow[0] = 0; + decodeRange[0] = maxImgPixel; +} + +//------------------------------------------------------------------------ +// GfxSeparationColorSpace +//------------------------------------------------------------------------ + +GfxSeparationColorSpace::GfxSeparationColorSpace(GString *name, + GfxColorSpace *alt, + Function *func) { + this->name = name; + this->alt = alt; + this->func = func; +} + +GfxSeparationColorSpace::~GfxSeparationColorSpace() { + delete name; + delete alt; + delete func; +} + +GfxColorSpace *GfxSeparationColorSpace::copy() { + return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy()); +} + +//~ handle the 'All' and 'None' colorants +GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) { + GfxSeparationColorSpace *cs; + GString *name; + GfxColorSpace *alt; + Function *func; + Object obj1; + + if (arr->getLength() != 4) { + error(-1, "Bad Separation color space"); + goto err1; + } + if (!arr->get(1, &obj1)->isName()) { + error(-1, "Bad Separation color space (name)"); + goto err2; + } + name = new GString(obj1.getName()); + obj1.free(); + arr->get(2, &obj1); + if (!(alt = 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()) { + goto err4; + } + cs = new GfxSeparationColorSpace(name, alt, func); + return cs; + + err4: + delete func; + delete alt; + err3: + delete name; + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) { + GfxColor color2; + + func->transform(color->c, color2.c); + alt->getGray(&color2, gray); +} + +void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + GfxColor color2; + + func->transform(color->c, color2.c); + alt->getRGB(&color2, rgb); +} + +void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxColor color2; + + func->transform(color->c, color2.c); + 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 i; + + for (i = 0; i < nComps; ++i) { + delete names[i]; + } + delete alt; + delete func; +} + +GfxColorSpace *GfxDeviceNColorSpace::copy() { + GfxDeviceNColorSpace *cs; + int i; + + cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy()); + for (i = 0; i < nComps; ++i) { + cs->names[i] = names[i]->copy(); + } + return cs; +} + +//~ handle the 'None' colorant +GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { + GfxDeviceNColorSpace *cs; + int nComps; + GString *names[gfxColorMaxComps]; + GfxColorSpace *alt; + Function *func; + Object obj1, obj2; + int i; + + if (arr->getLength() != 4 && arr->getLength() != 5) { + error(-1, "Bad DeviceN color space"); + goto err1; + } + if (!arr->get(1, &obj1)->isArray()) { + error(-1, "Bad DeviceN color space (names)"); + goto err2; + } + nComps = obj1.arrayGetLength(); + for (i = 0; i < nComps; ++i) { + if (!obj1.arrayGet(i, &obj2)->isName()) { + error(-1, "Bad DeviceN color space (names)"); + obj2.free(); + goto err2; } + names[i] = new GString(obj2.getName()); + obj2.free(); } + obj1.free(); + arr->get(2, &obj1); + if (!(alt = 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()) { + goto err4; + } + cs = new GfxDeviceNColorSpace(nComps, alt, func); + for (i = 0; i < nComps; ++i) { + cs->names[i] = names[i]; + } + return cs; + + err4: + delete func; + delete alt; + err3: + for (i = 0; i < nComps; ++i) { + delete names[i]; + } + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) { + GfxColor color2; + + func->transform(color->c, color2.c); + alt->getGray(&color2, gray); +} + +void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + GfxColor color2; + + func->transform(color->c, color2.c); + alt->getRGB(&color2, rgb); +} + +void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxColor color2; + + func->transform(color->c, color2.c); + alt->getCMYK(&color2, cmyk); } //------------------------------------------------------------------------ -// Function +// GfxPatternColorSpace //------------------------------------------------------------------------ -Function::Function(Object *funcObj) { - Stream *str; +GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) { + this->under = under; +} + +GfxPatternColorSpace::~GfxPatternColorSpace() { + if (under) { + delete under; + } +} + +GfxColorSpace *GfxPatternColorSpace::copy() { + return new GfxPatternColorSpace(under ? under->copy() : + (GfxColorSpace *)NULL); +} + +GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) { + GfxPatternColorSpace *cs; + GfxColorSpace *under; + Object obj1; + + if (arr->getLength() != 1 && arr->getLength() != 2) { + error(-1, "Bad Pattern color space"); + return NULL; + } + under = NULL; + if (arr->getLength() == 2) { + arr->get(1, &obj1); + if (!(under = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad Pattern color space (underlying color space)"); + obj1.free(); + return NULL; + } + obj1.free(); + } + cs = new GfxPatternColorSpace(under); + return cs; +} + +void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) { + *gray = 0; +} + +void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + rgb->r = rgb->g = rgb->b = 0; +} + +void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + cmyk->c = cmyk->m = cmyk->y = 0; + cmyk->k = 1; +} + +//------------------------------------------------------------------------ +// Pattern +//------------------------------------------------------------------------ + +GfxPattern::GfxPattern(int type) { + this->type = type; +} + +GfxPattern::~GfxPattern() { +} + +GfxPattern *GfxPattern::parse(Object *obj) { + GfxPattern *pattern; Dict *dict; - int nSamples, sampleBits; - double sampleMul; + Object obj1; + + 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(); + } + return pattern; +} + +//------------------------------------------------------------------------ +// GfxTilingPattern +//------------------------------------------------------------------------ + +GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream): + GfxPattern(1) +{ Object obj1, obj2; - Guint buf, bitMask; - int bits; - int s; int i; - ok = gFalse; - samples = NULL; + if (streamDict->lookup("PaintType", &obj1)->isInt()) { + paintType = obj1.getInt(); + } else { + paintType = 1; + error(-1, "Invalid or missing PaintType in pattern"); + } + obj1.free(); + if (streamDict->lookup("TilingType", &obj1)->isInt()) { + tilingType = obj1.getInt(); + } else { + tilingType = 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() && + obj1.arrayGetLength() == 4) { + for (i = 0; i < 4; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + bbox[i] = obj2.getNum(); + } + obj2.free(); + } + } else { + error(-1, "Invalid or missing BBox in pattern"); + } + obj1.free(); + if (streamDict->lookup("XStep", &obj1)->isNum()) { + xStep = obj1.getNum(); + } else { + xStep = 1; + error(-1, "Invalid or missing XStep in pattern"); + } + obj1.free(); + if (streamDict->lookup("YStep", &obj1)->isNum()) { + yStep = obj1.getNum(); + } else { + yStep = 1; + error(-1, "Invalid or missing YStep in pattern"); + } + obj1.free(); + if (!streamDict->lookup("Resources", &resDict)->isDict()) { + resDict.free(); + resDict.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() && + obj1.arrayGetLength() == 6) { + for (i = 0; i < 6; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + matrix[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + stream->copy(&contentStream); +} - if (!funcObj->isStream()) { - error(-1, "Expected function dictionary"); - goto err3; +GfxTilingPattern::~GfxTilingPattern() { + resDict.free(); + contentStream.free(); +} + +GfxPattern *GfxTilingPattern::copy() { + return new GfxTilingPattern(this); +} + +GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat): + GfxPattern(1) +{ + memcpy(this, pat, sizeof(GfxTilingPattern)); + pat->resDict.copy(&resDict); + pat->contentStream.copy(&contentStream); +} + +//------------------------------------------------------------------------ +// Function +//------------------------------------------------------------------------ + +Function::Function() { +} + +Function::~Function() { +} + +Function *Function::parse(Object *funcObj) { + Function *func; + Dict *dict; + int funcType; + Object obj1; + + if (funcObj->isStream()) { + dict = funcObj->streamGetDict(); + } else if (funcObj->isDict()) { + dict = funcObj->getDict(); + } else { + error(-1, "Expected function dictionary or stream"); + return NULL; } - str = funcObj->getStream(); - dict = str->getDict(); - //----- FunctionType - if (!dict->lookup("FunctionType", &obj1)->isInt() || - obj1.getInt() != 0) { - error(-1, "Unknown function type"); - goto err2; + if (!dict->lookup("FunctionType", &obj1)->isInt()) { + error(-1, "Function type is missing or wrong type"); + obj1.free(); + return NULL; } + funcType = 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; + } + + return func; +} + +GBool Function::init(Dict *dict) { + Object obj1, obj2; + int i; + //----- Domain if (!dict->lookup("Domain", &obj1)->isArray()) { error(-1, "Function is missing domain"); goto err2; } m = obj1.arrayGetLength() / 2; - if (m > 4) { - error(-1, "Functions with more than 1 input are unsupported"); + if (m > funcMaxInputs) { + error(-1, "Functions with more than %d inputs are unsupported", + funcMaxInputs); goto err2; } for (i = 0; i < m; ++i) { @@ -300,32 +1319,76 @@ Function::Function(Object *funcObj) { obj1.free(); //----- Range - if (!dict->lookup("Range", &obj1)->isArray()) { - error(-1, "Function is missing range"); - goto err2; - } - n = obj1.arrayGetLength() / 2; - if (n > 4) { - error(-1, "Functions with more than 4 outputs are unsupported"); - 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; + 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; } - range[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function range array"); - goto err1; + 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(); + 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(); + obj2.free(); } - range[i][1] = obj2.getNum(); - obj2.free(); + obj1.free(); } + + return gTrue; + + err1: + obj2.free(); + err2: obj1.free(); + return gFalse; +} + +//------------------------------------------------------------------------ +// SampledFunction +//------------------------------------------------------------------------ + +SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { + Stream *str; + int nSamples, sampleBits; + double sampleMul; + Object obj1, obj2; + Guint buf, bitMask; + int bits; + int s; + int i; + + samples = NULL; + ok = gFalse; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (!hasRange) { + error(-1, "Type 0 function is missing range"); + goto err1; + } + + //----- get the stream + if (!funcObj->isStream()) { + error(-1, "Type 0 function isn't a stream"); + goto err1; + } + str = funcObj->getStream(); //----- Size if (!dict->lookup("Size", &obj1)->isArray() || @@ -337,7 +1400,7 @@ Function::Function(Object *funcObj) { obj1.arrayGet(i, &obj2); if (!obj2.isInt()) { error(-1, "Illegal value in function size array"); - goto err1; + goto err3; } sampleSize[i] = obj2.getInt(); obj2.free(); @@ -360,14 +1423,14 @@ Function::Function(Object *funcObj) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(-1, "Illegal value in function encode array"); - goto err1; + 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 err1; + goto err3; } encode[i][1] = obj2.getNum(); obj2.free(); @@ -387,14 +1450,14 @@ Function::Function(Object *funcObj) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(-1, "Illegal value in function decode array"); - goto err1; + 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 err1; + goto err3; } decode[i][1] = obj2.getNum(); obj2.free(); @@ -437,44 +1500,39 @@ Function::Function(Object *funcObj) { } samples[i] = (double)s * sampleMul; } + str->close(); ok = gTrue; return; - err1: + err3: obj2.free(); err2: obj1.free(); - err3: + err1: return; } -Function::Function(Function *func) { +SampledFunction::~SampledFunction() { + if (samples) { + gfree(samples); + } +} + +SampledFunction::SampledFunction(SampledFunction *func) { int nSamples, i; - m = func->m; - n = func->n; - memcpy(domain, func->domain, sizeof(domain)); - memcpy(range, func->range, sizeof(range)); - memcpy(sampleSize, func->sampleSize, sizeof(sampleSize)); - memcpy(encode, func->encode, sizeof(encode)); - memcpy(decode, func->decode, sizeof(decode)); + memcpy(this, func, sizeof(SampledFunction)); nSamples = n; - for (i = 0; i < m; ++i) + for (i = 0; i < m; ++i) { nSamples *= sampleSize[i]; + } samples = (double *)gmalloc(nSamples * sizeof(double)); memcpy(samples, func->samples, nSamples * sizeof(double)); - - ok = gTrue; -} - -Function::~Function() { - if (samples) - gfree(samples); } -void Function::transform(double *in, double *out) { +void SampledFunction::transform(double *in, double *out) { double e[4]; double s; double x0, x1; @@ -486,10 +1544,11 @@ void Function::transform(double *in, double *out) { 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) + if (e[i] < 0) { e[i] = 0; - else if (e[i] > sampleSize[i] - 1) + } else if (e[i] > sampleSize[i] - 1) { e[i] = sampleSize[i] - 1; + } } for (i = 0; i < n; ++i) { @@ -505,67 +1564,174 @@ void Function::transform(double *in, double *out) { // map output values to range out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0]; - if (out[i] < range[i][0]) + if (out[i] < range[i][0]) { out[i] = range[i][0]; - else if (out[i] > range[i][1]) + } else if (out[i] > range[i][1]) { out[i] = range[i][1]; + } } } //------------------------------------------------------------------------ +// ExponentialFunction +//------------------------------------------------------------------------ + +ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { + Object obj1, obj2; + GBool hasN; + int i; + + ok = gFalse; + hasN = gFalse; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (m != 1) { + error(-1, "Exponential function with more than one input"); + goto err1; + } + + //----- default values + for (i = 0; i < funcMaxOutputs; ++i) { + c0[i] = 0; + c1[i] = 1; + } + + //----- 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; + } + for (i = 0; i < n; ++i) { + obj1.arrayGet(i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function C0 array"); + goto err3; + } + c0[i] = obj2.getNum(); + obj2.free(); + } + 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; + } + for (i = 0; i < n; ++i) { + obj1.arrayGet(i, &obj2); + if (!obj2.isNum()) { + error(-1, "Illegal value in function C1 array"); + goto err3; + } + c1[i] = obj2.getNum(); + obj2.free(); + } + obj1.free(); + } + + //----- N (exponent) + if (!dict->lookup("N", &obj1)->isNum()) { + error(-1, "Function has missing or invalid N"); + goto err2; + } + e = obj1.getNum(); + obj1.free(); + + ok = gTrue; + return; + + err3: + obj2.free(); + err2: + obj1.free(); + err1: + return; +} + +ExponentialFunction::~ExponentialFunction() { +} + +ExponentialFunction::ExponentialFunction(ExponentialFunction *func) { + memcpy(this, func, sizeof(ExponentialFunction)); +} + +void ExponentialFunction::transform(double *in, double *out) { + double x; + int i; + + if (in[0] < domain[0][0]) { + x = domain[0][0]; + } else if (in[0] > domain[0][1]) { + x = domain[0][1]; + } else { + x = in[0]; + } + 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]; + } + } + } + return; +} + +//------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ -GfxImageColorMap::GfxImageColorMap(int bits1, Object *decode, - GfxColorSpace *colorSpace1) { - GfxColor color; - double x[4]; - int maxPixel; +GfxImageColorMap::GfxImageColorMap(int bits, Object *decode, + GfxColorSpace *colorSpace) { + GfxIndexedColorSpace *indexedCS; + GfxSeparationColorSpace *sepCS; + int maxPixel, indexHigh; + Guchar *lookup2; + Function *sepFunc; Object obj; - int i, j; + double x; + double y[gfxColorMaxComps]; + int i, j, k; ok = gTrue; - // bits per component and colorspace - bits = bits1; + // bits per component and color space + this->bits = bits; maxPixel = (1 << bits) - 1; - colorSpace = colorSpace1; - mode = colorSpace->getMode(); - - // work around a bug in Distiller (?) - if (colorSpace->isIndexed() && maxPixel > colorSpace->getIndexHigh()) { - maxPixel = colorSpace->getIndexHigh(); - } + this->colorSpace = colorSpace; // get decode map if (decode->isNull()) { - if (colorSpace->isIndexed()) { - indexed = gTrue; - numComps = 1; - decodeLow[0] = 0; - decodeRange[0] = maxPixel; - } else { - indexed = gFalse; - numComps = colorSpace->getNumPixelComps(); - for (i = 0; i < numComps; ++i) { - decodeLow[i] = 0; - decodeRange[i] = 1; - } - } + nComps = colorSpace->getNComps(); + colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); } else if (decode->isArray()) { - numComps = decode->arrayGetLength() / 2; - if (numComps != colorSpace->getNumPixelComps()) + nComps = decode->arrayGetLength() / 2; + if (nComps != colorSpace->getNComps()) { goto err1; - indexed = colorSpace->isIndexed(); - for (i = 0; i < numComps; ++i) { + } + for (i = 0; i < nComps; ++i) { decode->arrayGet(2*i, &obj); - if (!obj.isNum()) + if (!obj.isNum()) { goto err2; + } decodeLow[i] = obj.getNum(); obj.free(); decode->arrayGet(2*i+1, &obj); - if (!obj.isNum()) + if (!obj.isNum()) { goto err2; + } decodeRange[i] = obj.getNum() - decodeLow[i]; obj.free(); } @@ -573,20 +1739,64 @@ GfxImageColorMap::GfxImageColorMap(int bits1, Object *decode, goto err1; } - // construct lookup table - lookup = (double (*)[4])gmalloc((maxPixel + 1) * 4 * sizeof(double)); - if (indexed) { +#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. + colorSpace2 = NULL; + nComps2 = 0; + if (colorSpace->getMode() == csIndexed) { + // Note that indexHigh may not be the same as maxPixel -- + // Distiller will remove unused palette entries, resulting in + // indexHigh < maxPixel. + indexedCS = (GfxIndexedColorSpace *)colorSpace; + 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; + } + } + } 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[0] = (double)i; - colorSpace->getColor(x, &color); - lookup[i][0] = color.getR(); - lookup[i][1] = color.getG(); - lookup[i][2] = color.getB(); + x = decodeLow[0] + (i * decodeRange[0]) / maxPixel; + sepFunc->transform(&x, y); + for (k = 0; k < nComps2; ++k) { + lookup[i*nComps2 + k] = y[k]; + } } } else { - for (i = 0; i <= maxPixel; ++i) - for (j = 0; j < numComps; ++j) - lookup[i][j] = decodeLow[j] + (i * decodeRange[j]) / maxPixel; + 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; + } + } } return; @@ -602,25 +1812,60 @@ GfxImageColorMap::~GfxImageColorMap() { gfree(lookup); } -void GfxImageColorMap::getColor(Guchar x[4], GfxColor *color) { +void GfxImageColorMap::getGray(Guchar *x, double *gray) { + GfxColor color; double *p; + int i; - if (indexed) { - p = lookup[x[0]]; - color->setRGB(p[0], p[1], p[2]); + if (colorSpace2) { + p = &lookup[x[0] * nComps2]; + for (i = 0; i < nComps2; ++i) { + color.c[i] = *p++; + } + colorSpace2->getGray(&color, gray); } else { - switch (mode) { - case colorGray: - color->setGray(lookup[x[0]][0]); - break; - case colorCMYK: - color->setCMYK(lookup[x[0]][0], lookup[x[1]][1], - lookup[x[2]][2], lookup[x[3]][3]); - break; - case colorRGB: - color->setRGB(lookup[x[0]][0], lookup[x[1]][1], lookup[x[2]][2]); - break; + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[x[i] * nComps + 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++; } + colorSpace2->getRGB(&color, rgb); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[x[i] * nComps + 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++; + } + colorSpace2->getCMYK(&color, cmyk); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[x[i] * nComps + i]; + } + colorSpace->getCMYK(&color, cmyk); } } @@ -637,6 +1882,7 @@ GfxSubpath::GfxSubpath(double x1, double y1) { x[0] = x1; y[0] = y1; curve[0] = gFalse; + closed = gFalse; } GfxSubpath::~GfxSubpath() { @@ -655,6 +1901,7 @@ GfxSubpath::GfxSubpath(GfxSubpath *subpath) { memcpy(x, subpath->x, n * sizeof(double)); memcpy(y, subpath->y, n * sizeof(double)); memcpy(curve, subpath->curve, n * sizeof(GBool)); + closed = subpath->closed; } void GfxSubpath::lineTo(double x1, double y1) { @@ -689,10 +1936,18 @@ void GfxSubpath::curveTo(double x1, double y1, double x2, double y2, n += 3; } +void GfxSubpath::close() { + if (x[n-1] != x[0] || y[n-1] != y[0]) { + lineTo(x[0], y[0]); + } + closed = gTrue; +} + GfxPath::GfxPath() { justMoved = gFalse; size = 16; n = 0; + firstX = firstY = 0; subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *)); } @@ -759,15 +2014,15 @@ void GfxPath::curveTo(double x1, double y1, double x2, double y2, // GfxState //------------------------------------------------------------------------ -GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a, - int rotate, GBool upsideDown) { +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 = (double)dpi / 72.0; + k = dpi / 72.0; if (rotate == 90) { ctm[0] = 0; ctm[1] = upsideDown ? k : -k; @@ -775,8 +2030,8 @@ GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a, ctm[3] = 0; ctm[4] = -k * py1; ctm[5] = k * (upsideDown ? -px1 : px2); - pageWidth = (int)(k * (py2 - py1)); - pageHeight = (int)(k * (px2 - px1)); + pageWidth = k * (py2 - py1); + pageHeight = k * (px2 - px1); } else if (rotate == 180) { ctm[0] = -k; ctm[1] = 0; @@ -784,8 +2039,8 @@ GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a, ctm[3] = upsideDown ? k : -k; ctm[4] = k * px2; ctm[5] = k * (upsideDown ? -py1 : py2); - pageWidth = (int)(k * (px2 - px1)); - pageHeight = (int)(k * (py2 - py1)); + pageWidth = k * (px2 - px1); + pageHeight = k * (py2 - py1); } else if (rotate == 270) { ctm[0] = 0; ctm[1] = upsideDown ? -k : k; @@ -793,8 +2048,8 @@ GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a, ctm[3] = 0; ctm[4] = k * py2; ctm[5] = k * (upsideDown ? px2 : -px1); - pageWidth = (int)(k * (py2 - py1)); - pageHeight = (int)(k * (px2 - px1)); + pageWidth = k * (py2 - py1); + pageHeight = k * (px2 - px1); } else { ctm[0] = k; ctm[1] = 0; @@ -802,14 +2057,18 @@ GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a, ctm[3] = upsideDown ? -k : k; ctm[4] = -k * px1; ctm[5] = k * (upsideDown ? py2 : -py1); - pageWidth = (int)(k * (px2 - px1)); - pageHeight = (int)(k * (py2 - py1)); + pageWidth = k * (px2 - px1); + pageHeight = k * (py2 - py1); } - fillColorSpace = new GfxColorSpace(colorGray); - strokeColorSpace = new GfxColorSpace(colorGray); - fillColor.setGray(0); - strokeColor.setGray(0); + fillColorSpace = new GfxDeviceGrayColorSpace(); + strokeColorSpace = new GfxDeviceGrayColorSpace(); + fillColor.c[0] = 0; + strokeColor.c[0] = 0; + fillPattern = NULL; + strokePattern = NULL; + fillOpacity = 1; + strokeOpacity = 1; lineWidth = 1; lineDash = NULL; @@ -840,23 +2099,40 @@ GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a, } GfxState::~GfxState() { - if (fillColorSpace) + if (fillColorSpace) { delete fillColorSpace; - if (strokeColorSpace) + } + if (strokeColorSpace) { delete strokeColorSpace; + } + if (fillPattern) { + delete fillPattern; + } + if (strokePattern) { + delete strokePattern; + } gfree(lineDash); delete path; - if (saved) + if (saved) { delete saved; + } } // Used for copy(); GfxState::GfxState(GfxState *state) { memcpy(this, state, sizeof(GfxState)); - if (fillColorSpace) + if (fillColorSpace) { fillColorSpace = state->fillColorSpace->copy(); - if (strokeColorSpace) + } + if (strokeColorSpace) { strokeColorSpace = state->strokeColorSpace->copy(); + } + if (fillPattern) { + fillPattern = state->fillPattern->copy(); + } + if (strokePattern) { + strokePattern = state->strokePattern->copy(); + } if (lineDashLength > 0) { lineDash = (double *)gmalloc(lineDashLength * sizeof(double)); memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); @@ -891,6 +2167,16 @@ void GfxState::getFontTransMat(double *m11, double *m12, *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; } +void GfxState::setCTM(double a, double b, double c, + double d, double e, double f) { + ctm[0] = a; + ctm[1] = b; + ctm[2] = c; + ctm[3] = d; + ctm[4] = e; + ctm[5] = f; +} + void GfxState::concatCTM(double a, double b, double c, double d, double e, double f) { double a1 = ctm[0]; @@ -907,17 +2193,33 @@ void GfxState::concatCTM(double a, double b, double c, } void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { - if (fillColorSpace) + if (fillColorSpace) { delete fillColorSpace; + } fillColorSpace = colorSpace; } void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { - if (strokeColorSpace) + if (strokeColorSpace) { delete strokeColorSpace; + } strokeColorSpace = colorSpace; } +void GfxState::setFillPattern(GfxPattern *pattern) { + if (fillPattern) { + delete fillPattern; + } + fillPattern = pattern; +} + +void GfxState::setStrokePattern(GfxPattern *pattern) { + if (strokePattern) { + delete strokePattern; + } + strokePattern = pattern; +} + void GfxState::setLineDash(double *dash, int length, double start) { if (lineDash) gfree(lineDash); -- cgit v0.9.1