diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index f2971d6..532219a 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -460,7 +460,7 @@ void GfxResources::lookupColorSpace(const char *name, Object *obj) { obj->initNull(); } -GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out) { +GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out, GfxState *state) { GfxResources *resPtr; GfxPattern *pattern; Object obj; @@ -468,7 +468,7 @@ GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out) { for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->patternDict.isDict()) { if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) { - pattern = GfxPattern::parse(&obj, out); + pattern = GfxPattern::parse(&obj, out, state); obj.free(); return pattern; } @@ -479,7 +479,7 @@ GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out) { return NULL; } -GfxShading *GfxResources::lookupShading(char *name, OutputDev *out) { +GfxShading *GfxResources::lookupShading(char *name, OutputDev *out, GfxState *state) { GfxResources *resPtr; GfxShading *shading; Object obj; @@ -487,7 +487,7 @@ GfxShading *GfxResources::lookupShading(char *name, OutputDev *out) { for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->shadingDict.isDict()) { if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) { - shading = GfxShading::parse(&obj, out); + shading = GfxShading::parse(&obj, out, state); obj.free(); return shading; } @@ -539,51 +539,20 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA, XRef *xrefA) { - int i; - doc = docA; xref = (xrefA == NULL) ? doc->getXRef() : xrefA; catalog = doc->getCatalog(); subPage = gFalse; - printCommands = globalParams->getPrintCommands(); - profileCommands = globalParams->getProfileCommands(); - mcStack = NULL; - parser = NULL; // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize - out = outA; - state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); - stackHeight = 1; - pushStateGuard(); - fontChanged = gFalse; - clip = clipNone; - ignoreUndef = 0; + init(hDPI, vDPI, rotate, outA, outA->upsideDown(), box, cropBox, + abortCheckCbkA, abortCheckCbkDataA); out->startPage(pageNum, state, xref); out->setDefaultCTM(state->getCTM()); out->updateAll(state); - for (i = 0; i < 6; ++i) { - baseMatrix[i] = state->getCTM()[i]; - } - formDepth = 0; - ocState = gTrue; - parser = NULL; - abortCheckCbk = abortCheckCbkA; - abortCheckCbkData = abortCheckCbkDataA; - - // set crop box - if (cropBox) { - state->moveTo(cropBox->x1, cropBox->y1); - state->lineTo(cropBox->x2, cropBox->y1); - state->lineTo(cropBox->x2, cropBox->y2); - state->lineTo(cropBox->x1, cropBox->y2); - state->closePath(); - state->clip(); - out->clip(state); - state->clearPath(); - } } Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, @@ -591,23 +560,40 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA, XRef *xrefA) { - int i; - doc = docA; xref = (xrefA == NULL) ? doc->getXRef() : xrefA; catalog = doc->getCatalog(); subPage = gTrue; - printCommands = globalParams->getPrintCommands(); - profileCommands = globalParams->getProfileCommands(); - mcStack = NULL; - parser = NULL; // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize + init(72, 72, 0, outA, gFalse, box, cropBox, + abortCheckCbkA, abortCheckCbkDataA); +} + +#ifdef USE_CMS + +#ifdef USE_LCMS1 +#include +#else +#include +#define LCMS_FLAGS cmsFLAGS_NOOPTIMIZE +#endif + +#endif + +void Gfx::init(double hDPI, double vDPI, int rotate, OutputDev *outA, + GBool upsideDown, PDFRectangle *box, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA) { + int i; + + printCommands = globalParams->getPrintCommands(); + profileCommands = globalParams->getProfileCommands(); + mcStack = NULL; out = outA; - state = new GfxState(72, 72, box, 0, gFalse); + state = new GfxState(hDPI, vDPI, box, rotate, upsideDown); stackHeight = 1; pushStateGuard(); fontChanged = gFalse; @@ -633,6 +619,39 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, out->clip(state); state->clearPath(); } +#ifdef USE_CMS + + Object catDict; + xref->getCatalog(&catDict); + if (catDict.isDict()) { + Object outputIntents; + catDict.dictLookup("OutputIntents", &outputIntents); + if (outputIntents.isArray() && outputIntents.arrayGetLength() == 1) { + Object firstElement; + outputIntents.arrayGet(0, &firstElement); + if (firstElement.isDict()) { + Object profile; + firstElement.dictLookup("DestOutputProfile", &profile); + if (profile.isStream()) { + Stream *iccStream = profile.getStream(); + int length = 0; + Guchar *profBuf = iccStream->toUnsignedChars(&length, 65536, 65536); + cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,length); + if (hp == 0) { + error(errSyntaxWarning, -1, "read ICCBased color space profile error"); + } else { + state->setDisplayProfile(hp); + } + gfree(profBuf); + } + profile.free(); + } + firstElement.free(); + } + outputIntents.free(); + } + catDict.free(); +#endif } Gfx::~Gfx() { @@ -1183,7 +1202,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { blendingColorSpace = NULL; isolated = knockout = gFalse; if (!obj4.dictLookup("CS", &obj5)->isNull()) { - blendingColorSpace = GfxColorSpace::parse(&obj5, out); + blendingColorSpace = GfxColorSpace::parse(&obj5, out, state); } obj5.free(); if (obj4.dictLookup("I", &obj5)->isBool()) { @@ -1371,6 +1390,7 @@ void Gfx::doSoftMask(Object *str, GBool alpha, } void Gfx::opSetRenderingIntent(Object args[], int numArgs) { + state->setRenderingIntent(args[0].getName()); } //------------------------------------------------------------------------ @@ -1385,7 +1405,7 @@ void Gfx::opSetFillGray(Object args[], int numArgs) { state->setFillPattern(NULL); res->lookupColorSpace("DefaultGray", &obj); if (!obj.isNull()) { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } if (colorSpace == NULL) { colorSpace = new GfxDeviceGrayColorSpace(); @@ -1406,7 +1426,7 @@ void Gfx::opSetStrokeGray(Object args[], int numArgs) { state->setStrokePattern(NULL); res->lookupColorSpace("DefaultGray", &obj); if (!obj.isNull()) { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } if (colorSpace == NULL) { colorSpace = new GfxDeviceGrayColorSpace(); @@ -1427,7 +1447,7 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) { res->lookupColorSpace("DefaultCMYK", &obj); if (!obj.isNull()) { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } if (colorSpace == NULL) { colorSpace = new GfxDeviceCMYKColorSpace(); @@ -1452,7 +1472,7 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) { state->setStrokePattern(NULL); res->lookupColorSpace("DefaultCMYK", &obj); if (!obj.isNull()) { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } if (colorSpace == NULL) { colorSpace = new GfxDeviceCMYKColorSpace(); @@ -1476,7 +1496,7 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) { state->setFillPattern(NULL); res->lookupColorSpace("DefaultRGB", &obj); if (!obj.isNull()) { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } if (colorSpace == NULL) { colorSpace = new GfxDeviceRGBColorSpace(); @@ -1500,7 +1520,7 @@ void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) { state->setStrokePattern(NULL); res->lookupColorSpace("DefaultRGB", &obj); if (!obj.isNull()) { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } if (colorSpace == NULL) { colorSpace = new GfxDeviceRGBColorSpace(); @@ -1522,9 +1542,9 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) { res->lookupColorSpace(args[0].getName(), &obj); if (obj.isNull()) { - colorSpace = GfxColorSpace::parse(&args[0], out); + colorSpace = GfxColorSpace::parse(&args[0], out, state); } else { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } obj.free(); if (colorSpace) { @@ -1547,9 +1567,9 @@ void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { state->setStrokePattern(NULL); res->lookupColorSpace(args[0].getName(), &obj); if (obj.isNull()) { - colorSpace = GfxColorSpace::parse(&args[0], out); + colorSpace = GfxColorSpace::parse(&args[0], out, state); } else { - colorSpace = GfxColorSpace::parse(&obj, out); + colorSpace = GfxColorSpace::parse(&obj, out, state); } obj.free(); if (colorSpace) { @@ -1620,7 +1640,7 @@ void Gfx::opSetFillColorN(Object args[], int numArgs) { } if (numArgs > 0) { if (args[numArgs-1].isName() && - (pattern = res->lookupPattern(args[numArgs-1].getName(), out))) { + (pattern = res->lookupPattern(args[numArgs-1].getName(), out, state))) { state->setFillPattern(pattern); } } @@ -1672,7 +1692,7 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) { return; } if (args[numArgs-1].isName() && - (pattern = res->lookupPattern(args[numArgs-1].getName(), out))) { + (pattern = res->lookupPattern(args[numArgs-1].getName(), out, state))) { state->setStrokePattern(pattern); } @@ -2382,7 +2402,7 @@ void Gfx::opShFill(Object args[], int numArgs) { return; } - if (!(shading = res->lookupShading(args[0].getName(), out))) { + if (!(shading = res->lookupShading(args[0].getName(), out, state))) { return; } @@ -4339,14 +4359,29 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } } if (!obj1.isNull()) { - colorSpace = GfxColorSpace::parse(&obj1, out); + Object objIntent; + char *tempIntent = NULL; + dict->lookup("Intent", &objIntent); + if (objIntent.isName()) { + tempIntent = state->getRenderingIntent(); + if (tempIntent != NULL) { + tempIntent = strdup(tempIntent); + } + state->setRenderingIntent(objIntent.getName()); + } + colorSpace = GfxColorSpace::parse(&obj1, out, state); + if (objIntent.isName()) { + state->setRenderingIntent(tempIntent); + free(tempIntent); + } + objIntent.free(); } else if (csMode == streamCSDeviceGray) { Object objCS; res->lookupColorSpace("DefaultGray", &objCS); if (objCS.isNull()) { colorSpace = new GfxDeviceGrayColorSpace(); } else { - colorSpace = GfxColorSpace::parse(&objCS, out); + colorSpace = GfxColorSpace::parse(&objCS, out, state); } objCS.free(); } else if (csMode == streamCSDeviceRGB) { @@ -4355,7 +4390,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { if (objCS.isNull()) { colorSpace = new GfxDeviceRGBColorSpace(); } else { - colorSpace = GfxColorSpace::parse(&objCS, out); + colorSpace = GfxColorSpace::parse(&objCS, out, state); } objCS.free(); } else if (csMode == streamCSDeviceCMYK) { @@ -4364,7 +4399,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { if (objCS.isNull()) { colorSpace = new GfxDeviceCMYKColorSpace(); } else { - colorSpace = GfxColorSpace::parse(&objCS, out); + colorSpace = GfxColorSpace::parse(&objCS, out, state); } objCS.free(); } else { @@ -4459,7 +4494,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj2.free(); } } - maskColorSpace = GfxColorSpace::parse(&obj1, out); + maskColorSpace = GfxColorSpace::parse(&obj1, out, state); obj1.free(); if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) { goto err1; @@ -4755,7 +4790,7 @@ void Gfx::doForm(Object *str) { if (dict->lookup("Group", &obj1)->isDict()) { if (obj1.dictLookup("S", &obj2)->isName("Transparency")) { if (!obj1.dictLookup("CS", &obj3)->isNull()) { - blendingColorSpace = GfxColorSpace::parse(&obj3, out); + blendingColorSpace = GfxColorSpace::parse(&obj3, out, state); } obj3.free(); if (obj1.dictLookup("I", &obj3)->isBool()) { diff --git a/poppler/Gfx.h b/poppler/Gfx.h index aba3b7e..941cd79 100644 --- a/poppler/Gfx.h +++ b/poppler/Gfx.h @@ -117,8 +117,8 @@ public: GBool lookupXObjectNF(char *name, Object *obj); GBool lookupMarkedContentNF(char *name, Object *obj); void lookupColorSpace(const char *name, Object *obj); - GfxPattern *lookupPattern(char *name, OutputDev *out); - GfxShading *lookupShading(char *name, OutputDev *out); + GfxPattern *lookupPattern(char *name, OutputDev *out, GfxState *state); + GfxShading *lookupShading(char *name, OutputDev *out, GfxState *state); GBool lookupGState(char *name, Object *obj); GBool lookupGStateNF(char *name, Object *obj); @@ -157,6 +157,10 @@ public: GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL, XRef *xrefA = NULL); + void init(double hDPI, double vDPI, int rotate, OutputDev *outA, + GBool upsideDown, PDFRectangle *box, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA); + ~Gfx(); XRef *getXRef() { return xref; } diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index d723833..be48df8 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -199,9 +199,11 @@ void GfxColorTransform::doTransform(void *in, void *out, unsigned int size) { } // transformA should be a cmsHTRANSFORM -GfxColorTransform::GfxColorTransform(void *transformA) { +GfxColorTransform::GfxColorTransform(void *transformA, int cmsIntentA, unsigned int transformPixelTypeA) { transform = transformA; refCount = 1; + cmsIntent = cmsIntentA; + transformPixelType = transformPixelTypeA; } GfxColorTransform::~GfxColorTransform() { @@ -229,6 +231,25 @@ static cmsHPROFILE loadColorProfile(const char *fileName); void GfxColorSpace::setDisplayProfile(void *displayProfileA) { displayProfile = displayProfileA; + if (displayProfile != NULL) { + cmsHTRANSFORM transform; + unsigned int nChannels; + + displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile)); + nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile)); + // create transform from XYZ + cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); + if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, + displayProfile, + COLORSPACE_SH(displayPixelType) | + CHANNELS_SH(nChannels) | BYTES_SH(1), + INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) { + error(errSyntaxWarning, -1, "Can't create Lab transform"); + } else { + XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, displayPixelType); + } + cmsCloseProfile(XYZProfile); + } } void GfxColorSpace::setDisplayProfileName(GooString *name) { @@ -257,7 +278,7 @@ GfxColorSpace::GfxColorSpace() { GfxColorSpace::~GfxColorSpace() { } -GfxColorSpace *GfxColorSpace::parse(Object *csObj, OutputDev *out, int recursion) { +GfxColorSpace *GfxColorSpace::parse(Object *csObj, OutputDev *out, GfxState *state, int recursion) { GfxColorSpace *cs; Object obj1; @@ -288,21 +309,21 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj, OutputDev *out, int recursion } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { cs = new GfxDeviceCMYKColorSpace(); } else if (obj1.isName("CalGray")) { - cs = GfxCalGrayColorSpace::parse(csObj->getArray()); + cs = GfxCalGrayColorSpace::parse(csObj->getArray(), state); } else if (obj1.isName("CalRGB")) { - cs = GfxCalRGBColorSpace::parse(csObj->getArray()); + cs = GfxCalRGBColorSpace::parse(csObj->getArray(), state); } else if (obj1.isName("Lab")) { - cs = GfxLabColorSpace::parse(csObj->getArray()); + cs = GfxLabColorSpace::parse(csObj->getArray(), state); } else if (obj1.isName("ICCBased")) { - cs = GfxICCBasedColorSpace::parse(csObj->getArray(), out, recursion); + cs = GfxICCBasedColorSpace::parse(csObj->getArray(), out, state, recursion); } else if (obj1.isName("Indexed") || obj1.isName("I")) { - cs = GfxIndexedColorSpace::parse(csObj->getArray(), out, recursion); + cs = GfxIndexedColorSpace::parse(csObj->getArray(), out, state, recursion); } else if (obj1.isName("Separation")) { - cs = GfxSeparationColorSpace::parse(csObj->getArray(), out, recursion); + cs = GfxSeparationColorSpace::parse(csObj->getArray(), out, state, recursion); } else if (obj1.isName("DeviceN")) { - cs = GfxDeviceNColorSpace::parse(csObj->getArray(), out, recursion); + cs = GfxDeviceNColorSpace::parse(csObj->getArray(), out, state, recursion); } else if (obj1.isName("Pattern")) { - cs = GfxPatternColorSpace::parse(csObj->getArray(), out, recursion); + cs = GfxPatternColorSpace::parse(csObj->getArray(), out, state, recursion); } else { error(errSyntaxWarning, -1, "Bad color space"); } @@ -421,13 +442,13 @@ int GfxColorSpace::setupColorProfiles() // create transform from XYZ cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - displayProfile, + displayProfile, COLORSPACE_SH(displayPixelType) | CHANNELS_SH(nChannels) | BYTES_SH(1), INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) { error(errSyntaxWarning, -1, "Can't create Lab transform"); } else { - XYZ2DisplayTransform = new GfxColorTransform(transform); + XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, displayPixelType); } cmsCloseProfile(XYZProfile); } @@ -649,6 +670,11 @@ GfxCalGrayColorSpace::GfxCalGrayColorSpace() { } GfxCalGrayColorSpace::~GfxCalGrayColorSpace() { +#ifdef USE_CMS + if (transform != NULL) { + if (transform->unref() == 0) delete transform; + } +#endif } GfxColorSpace *GfxCalGrayColorSpace::copy() { @@ -662,6 +688,10 @@ GfxColorSpace *GfxCalGrayColorSpace::copy() { cs->blackY = blackY; cs->blackZ = blackZ; cs->gamma = gamma; +#ifdef USE_CMS + cs->transform = transform; + if (transform != NULL) transform->ref(); +#endif return cs; } @@ -673,7 +703,7 @@ static const double xyzrgb[3][3] = { { 0.055643, -0.204026, 1.057229 } }; -GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { +GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, GfxState *state) { GfxCalGrayColorSpace *cs; Object obj1, obj2, obj3; @@ -731,7 +761,10 @@ GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + xyzrgb[2][1] * cs->whiteY + xyzrgb[2][2] * cs->whiteZ); - +#ifdef USE_CMS + cs->transform = (state != NULL) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform; + if (cs->transform != NULL) cs->transform->ref(); +#endif return cs; } @@ -750,7 +783,7 @@ void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxRGB rgb; #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) { + if (transform != NULL && transform->getTransformPixelType() == PT_GRAY) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; double X, Y, Z; @@ -759,7 +792,7 @@ void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); *gray = byteToCol(out[0]); return; } @@ -776,14 +809,14 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { getXYZ(color,&X,&Y,&Z); #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) { + if (transform != NULL && transform->getTransformPixelType() == PT_RGB) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); rgb->r = byteToCol(out[0]); rgb->g = byteToCol(out[1]); rgb->b = byteToCol(out[2]); @@ -807,7 +840,7 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxColorComp c, m, y, k; #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) { + if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) { double in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; double X, Y, Z; @@ -817,7 +850,7 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { in[1] = clip01(Y); in[2] = clip01(Z); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); cmyk->c = byteToCol(out[0]); cmyk->m = byteToCol(out[1]); cmyk->y = byteToCol(out[2]); @@ -1015,6 +1048,11 @@ GfxCalRGBColorSpace::GfxCalRGBColorSpace() { } GfxCalRGBColorSpace::~GfxCalRGBColorSpace() { +#ifdef USE_CMS + if (transform != NULL) { + if (transform->unref() == 0) delete transform; + } +#endif } GfxColorSpace *GfxCalRGBColorSpace::copy() { @@ -1034,10 +1072,14 @@ GfxColorSpace *GfxCalRGBColorSpace::copy() { for (i = 0; i < 9; ++i) { cs->mat[i] = mat[i]; } +#ifdef USE_CMS + cs->transform = transform; + if (transform != NULL) transform->ref(); +#endif return cs; } -GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { +GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, GfxState *state) { GfxCalRGBColorSpace *cs; Object obj1, obj2, obj3; int i; @@ -1119,6 +1161,10 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { xyzrgb[2][1] * cs->whiteY + xyzrgb[2][2] * cs->whiteZ); +#ifdef USE_CMS + cs->transform = (state != NULL) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform; + if (cs->transform != NULL) cs->transform->ref(); +#endif return cs; } @@ -1139,7 +1185,7 @@ void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxRGB rgb; #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) { + if (transform != NULL && transform->getTransformPixelType() == PT_GRAY) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; double X, Y, Z; @@ -1148,7 +1194,7 @@ void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); *gray = byteToCol(out[0]); return; } @@ -1165,14 +1211,14 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { getXYZ(color,&X,&Y,&Z); #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) { + if (transform != NULL && transform->getTransformPixelType() == PT_RGB) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; in[0] = clip01(X/whiteX); in[1] = clip01(Y/whiteY); in[2] = clip01(Z/whiteZ); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); rgb->r = byteToCol(out[0]); rgb->g = byteToCol(out[1]); rgb->b = byteToCol(out[2]); @@ -1193,7 +1239,7 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxColorComp c, m, y, k; #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) { + if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) { double in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; double X, Y, Z; @@ -1202,7 +1248,7 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); cmyk->c = byteToCol(out[0]); cmyk->m = byteToCol(out[1]); cmyk->y = byteToCol(out[2]); @@ -1389,6 +1435,11 @@ GfxLabColorSpace::GfxLabColorSpace() { } GfxLabColorSpace::~GfxLabColorSpace() { +#ifdef USE_CMS + if (transform != NULL) { + if (transform->unref() == 0) delete transform; + } +#endif } GfxColorSpace *GfxLabColorSpace::copy() { @@ -1408,10 +1459,14 @@ GfxColorSpace *GfxLabColorSpace::copy() { cs->kr = kr; cs->kg = kg; cs->kb = kb; +#ifdef USE_CMS + cs->transform = transform; + if (transform != NULL) transform->ref(); +#endif return cs; } -GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { +GfxColorSpace *GfxLabColorSpace::parse(Array *arr, GfxState *state) { GfxLabColorSpace *cs; Object obj1, obj2, obj3; @@ -1476,6 +1531,10 @@ GfxColorSpace *GfxLabColorSpace::parse(Array *arr) { xyzrgb[2][1] * cs->whiteY + xyzrgb[2][2] * cs->whiteZ); +#ifdef USE_CMS + cs->transform = (state != NULL) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform; + if (cs->transform != NULL) cs->transform->ref(); +#endif return cs; } @@ -1483,12 +1542,12 @@ void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxRGB rgb; #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) { + if (transform != NULL && transform->getTransformPixelType() == PT_GRAY) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; getXYZ(color, &in[0], &in[1], &in[2]); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); *gray = byteToCol(out[0]); return; } @@ -1535,18 +1594,40 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { getXYZ(color, &X, &Y, &Z); #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) { + if (transform != NULL && transform->getTransformPixelType() == PT_RGB) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); rgb->r = byteToCol(out[0]); rgb->g = byteToCol(out[1]); rgb->b = byteToCol(out[2]); return; + } else if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) { + Guchar out[gfxColorMaxComps]; + double in[gfxColorMaxComps]; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + in[0] = clip01(X); + in[1] = clip01(Y); + in[2] = clip01(Z); + transform->doTransform(in,out,1); + c = byteToDbl(out[0]); + m = byteToDbl(out[1]); + y = byteToDbl(out[2]); + k = byteToDbl(out[3]); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + rgb->r = clip01(dblToCol(r)); + rgb->g = clip01(dblToCol(g)); + rgb->b = clip01(dblToCol(b)); + return; } #endif X *= whiteX; @@ -1566,12 +1647,12 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxColorComp c, m, y, k; #ifdef USE_CMS - if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) { + if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) { double in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; getXYZ(color, &in[0], &in[1], &in[2]); - XYZ2DisplayTransform->doTransform(in,out,1); + transform->doTransform(in,out,1); cmyk->c = byteToCol(out[0]); cmyk->m = byteToCol(out[1]); cmyk->y = byteToCol(out[2]); @@ -1714,7 +1795,7 @@ GfxColorSpace *GfxICCBasedColorSpace::copy() { return cs; } -GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, int recursion) { +GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) { GfxICCBasedColorSpace *cs; Ref iccProfileStreamA; int nCompsA; @@ -1743,7 +1824,24 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, int recu if (item != NULL) { cs = static_cast(item->cs->copy()); - return cs; + int transformIntent = cs->getIntent(); + int cmsIntent = INTENT_RELATIVE_COLORIMETRIC; + if (state != NULL) { + const char *intent = state->getRenderingIntent(); + if (intent != NULL) { + if (strcmp(intent, "AbsoluteColorimetric") == 0) { + cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC; + } else if (strcmp(intent, "Saturation") == 0) { + cmsIntent = INTENT_SATURATION; + } else if (strcmp(intent, "Perceptual") == 0) { + cmsIntent = INTENT_PERCEPTUAL; + } + } + } + if (transformIntent == cmsIntent) { + return cs; + } + delete cs; } } #endif @@ -1769,7 +1867,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, int recu nCompsA = 4; } if (dict->lookup("Alternate", &obj2)->isNull() || - !(altA = GfxColorSpace::parse(&obj2, out, recursion + 1))) { + !(altA = GfxColorSpace::parse(&obj2, out, state, recursion + 1))) { switch (nCompsA) { case 1: altA = new GfxDeviceGrayColorSpace(); @@ -1819,32 +1917,46 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, int recu if (hp == 0) { error(errSyntaxWarning, -1, "read ICCBased color space profile error"); } else { - cmsHPROFILE dhp = displayProfile; + cmsHPROFILE dhp = (state != NULL && state->getDisplayProfile() != NULL) ? state->getDisplayProfile() : displayProfile; if (dhp == NULL) dhp = RGBProfile; unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp)); unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp)); unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(dhp)); cmsHTRANSFORM transform; + + int cmsIntent = INTENT_RELATIVE_COLORIMETRIC; + if (state != NULL) { + const char *intent = state->getRenderingIntent(); + if (intent != NULL) { + if (strcmp(intent, "AbsoluteColorimetric") == 0) { + cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC; + } else if (strcmp(intent, "Saturation") == 0) { + cmsIntent = INTENT_SATURATION; + } else if (strcmp(intent, "Perceptual") == 0) { + cmsIntent = INTENT_PERCEPTUAL; + } + } + } if ((transform = cmsCreateTransform(hp, COLORSPACE_SH(cst) |CHANNELS_SH(nCompsA) | BYTES_SH(1), dhp, COLORSPACE_SH(dcst) | CHANNELS_SH(dNChannels) | BYTES_SH(1), - INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) { + cmsIntent, LCMS_FLAGS)) == 0) { error(errSyntaxWarning, -1, "Can't create transform"); cs->transform = NULL; } else { - cs->transform = new GfxColorTransform(transform); + cs->transform = new GfxColorTransform(transform, cmsIntent, dcst); } - if (dcst == PT_RGB) { + if (dcst == PT_RGB || dcst == PT_CMYK) { // create line transform only when the display is RGB type color space if ((transform = cmsCreateTransform(hp, CHANNELS_SH(nCompsA) | BYTES_SH(1),dhp, - TYPE_RGB_8,INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) { + (dcst == PT_RGB) ? TYPE_RGB_8 : TYPE_CMYK_8, cmsIntent, LCMS_FLAGS)) == 0) { error(errSyntaxWarning, -1, "Can't create transform"); cs->lineTransform = NULL; } else { - cs->lineTransform = new GfxColorTransform(transform); + cs->lineTransform = new GfxColorTransform(transform, cmsIntent, dcst); } } cmsCloseProfile(hp); @@ -1862,7 +1974,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, int recu void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { #ifdef USE_CMS - if (transform != 0 && displayPixelType == PT_GRAY) { + if (transform != 0 && transform->getTransformPixelType() == PT_GRAY) { Guchar in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; @@ -1885,8 +1997,7 @@ void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { #ifdef USE_CMS - if (transform != 0 - && (displayProfile == NULL || displayPixelType == PT_RGB)) { + if (transform != 0 && transform->getTransformPixelType() == PT_RGB) { Guchar in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; @@ -1897,6 +2008,27 @@ void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = byteToCol(out[0]); rgb->g = byteToCol(out[1]); rgb->b = byteToCol(out[2]); + } else if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) { + Guchar in[gfxColorMaxComps]; + Guchar out[gfxColorMaxComps]; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + for (int i = 0;i < nComps;i++) { + in[i] = colToByte(color->c[i]); + } + transform->doTransform(in,out,1); + c = byteToDbl(out[0]); + m = byteToDbl(out[1]); + y = byteToDbl(out[2]); + k = byteToDbl(out[3]); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + rgb->r = clip01(dblToCol(r)); + rgb->g = clip01(dblToCol(g)); + rgb->b = clip01(dblToCol(b)); } else { alt->getRGB(color, rgb); } @@ -1908,7 +2040,7 @@ void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { void GfxICCBasedColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) { #ifdef USE_CMS - if (lineTransform != 0) { + if (lineTransform != 0 && lineTransform->getTransformPixelType() == PT_RGB) { Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); lineTransform->doTransform(in, tmp, length); for (int i = 0; i < length; ++i) { @@ -1926,7 +2058,7 @@ void GfxICCBasedColorSpace::getRGBLine(Guchar *in, unsigned int *out, void GfxICCBasedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) { #ifdef USE_CMS - if (lineTransform != 0) { + if (lineTransform != 0 && lineTransform->getTransformPixelType() == PT_RGB) { Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); lineTransform->doTransform(in, tmp, length); Guchar *current = tmp; @@ -1936,6 +2068,26 @@ void GfxICCBasedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) { *out++ = *current++; } gfree(tmp); + } else if (lineTransform != NULL && lineTransform->getTransformPixelType() == PT_CMYK) { + Guchar* tmp = (Guchar *)gmallocn(4 * length, sizeof(Guchar)); + lineTransform->doTransform(in, tmp, length); + Guchar *current = tmp; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + for (int i = 0; i < length; ++i) { + c = byteToDbl(*current++); + m = byteToDbl(*current++); + y = byteToDbl(*current++); + k = byteToDbl(*current++); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + *out++ = dblToByte(r); + *out++ = dblToByte(g); + *out++ = dblToByte(b); + } + gfree(tmp); } else { alt->getRGBLine(in, out, length); } @@ -1946,7 +2098,7 @@ void GfxICCBasedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) { void GfxICCBasedColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) { #ifdef USE_CMS - if (lineTransform != 0) { + if (lineTransform != 0 && lineTransform->getTransformPixelType() == PT_RGB) { Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); lineTransform->doTransform(in, tmp, length); Guchar *current = tmp; @@ -1967,7 +2119,7 @@ void GfxICCBasedColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) { void GfxICCBasedColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) { #ifdef USE_CMS - if (lineTransform != NULL && displayPixelType == PT_CMYK) { + if (lineTransform != NULL && lineTransform->getTransformPixelType() == PT_CMYK) { transform->doTransform(in,out,length); } else if (lineTransform != NULL) { GfxColorComp c, m, y, k; @@ -2001,7 +2153,7 @@ void GfxICCBasedColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) { void GfxICCBasedColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) { #ifdef USE_CMS - if (lineTransform != NULL && displayPixelType == PT_CMYK) { + if (lineTransform != NULL && lineTransform->getTransformPixelType() == PT_CMYK) { Guchar* tmp = (Guchar *)gmallocn(4 * length, sizeof(Guchar)); transform->doTransform(in,tmp,length); Guchar *p = tmp; @@ -2047,7 +2199,7 @@ void GfxICCBasedColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { #ifdef USE_CMS - if (transform != NULL && displayPixelType == PT_CMYK) { + if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) { Guchar in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; @@ -2177,7 +2329,7 @@ GfxColorSpace *GfxIndexedColorSpace::copy() { return cs; } -GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr, OutputDev *out, int recursion) { +GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) { GfxIndexedColorSpace *cs; GfxColorSpace *baseA; int indexHighA; @@ -2190,7 +2342,7 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr, OutputDev *out, int recur goto err1; } arr->get(1, &obj1); - if (!(baseA = GfxColorSpace::parse(&obj1, out, recursion + 1))) { + if (!(baseA = GfxColorSpace::parse(&obj1, out, state, recursion + 1))) { error(errSyntaxWarning, -1, "Bad Indexed color space (base color space)"); goto err2; } @@ -2442,7 +2594,7 @@ GfxColorSpace *GfxSeparationColorSpace::copy() { } //~ handle the 'All' and 'None' colorants -GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, OutputDev *out, int recursion) { +GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) { GfxSeparationColorSpace *cs; GooString *nameA; GfxColorSpace *altA; @@ -2460,7 +2612,7 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, OutputDev *out, int re nameA = new GooString(obj1.getName()); obj1.free(); arr->get(2, &obj1); - if (!(altA = GfxColorSpace::parse(&obj1, out, recursion + 1))) { + if (!(altA = GfxColorSpace::parse(&obj1, out, state, recursion + 1))) { error(errSyntaxWarning, -1, "Bad Separation color space (alternate color space)"); goto err3; } @@ -2691,7 +2843,7 @@ GfxColorSpace *GfxDeviceNColorSpace::copy() { } //~ handle the 'None' colorant -GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, OutputDev *out, int recursion) { +GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) { GfxDeviceNColorSpace *cs; int nCompsA; GooString *namesA[gfxColorMaxComps]; @@ -2726,7 +2878,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, OutputDev *out, int recur } obj1.free(); arr->get(2, &obj1); - if (!(altA = GfxColorSpace::parse(&obj1, out, recursion + 1))) { + if (!(altA = GfxColorSpace::parse(&obj1, out, state, recursion + 1))) { error(errSyntaxWarning, -1, "Bad DeviceN color space (alternate color space)"); goto err3; } @@ -2749,7 +2901,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, OutputDev *out, int recur Object obj3; colorants->getVal(i, &obj3); if (obj3.isArray()) { - separationList->append(GfxSeparationColorSpace::parse(obj3.getArray(), out, recursion)); + separationList->append(GfxSeparationColorSpace::parse(obj3.getArray(), out, state, recursion)); } else { obj3.free(); obj2.free(); @@ -2957,7 +3109,7 @@ GfxColorSpace *GfxPatternColorSpace::copy() { (GfxColorSpace *)NULL); } -GfxColorSpace *GfxPatternColorSpace::parse(Array *arr, OutputDev *out, int recursion) { +GfxColorSpace *GfxPatternColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) { GfxPatternColorSpace *cs; GfxColorSpace *underA; Object obj1; @@ -2969,7 +3121,7 @@ GfxColorSpace *GfxPatternColorSpace::parse(Array *arr, OutputDev *out, int recur underA = NULL; if (arr->getLength() == 2) { arr->get(1, &obj1); - if (!(underA = GfxColorSpace::parse(&obj1, out, recursion + 1))) { + if (!(underA = GfxColorSpace::parse(&obj1, out, state, recursion + 1))) { error(errSyntaxWarning, -1, "Bad Pattern color space (underlying color space)"); obj1.free(); return NULL; @@ -3014,7 +3166,7 @@ GfxPattern::GfxPattern(int typeA) { GfxPattern::~GfxPattern() { } -GfxPattern *GfxPattern::parse(Object *obj, OutputDev *out) { +GfxPattern *GfxPattern::parse(Object *obj, OutputDev *out, GfxState *state) { GfxPattern *pattern; Object obj1; @@ -3029,7 +3181,7 @@ GfxPattern *GfxPattern::parse(Object *obj, OutputDev *out) { if (obj1.isInt() && obj1.getInt() == 1) { pattern = GfxTilingPattern::parse(obj); } else if (obj1.isInt() && obj1.getInt() == 2) { - pattern = GfxShadingPattern::parse(obj, out); + pattern = GfxShadingPattern::parse(obj, out, state); } obj1.free(); return pattern; @@ -3157,7 +3309,7 @@ GfxPattern *GfxTilingPattern::copy() { // GfxShadingPattern //------------------------------------------------------------------------ -GfxShadingPattern *GfxShadingPattern::parse(Object *patObj, OutputDev *out) { +GfxShadingPattern *GfxShadingPattern::parse(Object *patObj, OutputDev *out, GfxState *state) { Dict *dict; GfxShading *shadingA; double matrixA[6]; @@ -3170,7 +3322,7 @@ GfxShadingPattern *GfxShadingPattern::parse(Object *patObj, OutputDev *out) { dict = patObj->getDict(); dict->lookup("Shading", &obj1); - shadingA = GfxShading::parse(&obj1, out); + shadingA = GfxShading::parse(&obj1, out, state); obj1.free(); if (!shadingA) { return NULL; @@ -3243,7 +3395,7 @@ GfxShading::~GfxShading() { } } -GfxShading *GfxShading::parse(Object *obj, OutputDev *out) { +GfxShading *GfxShading::parse(Object *obj, OutputDev *out, GfxState *state) { GfxShading *shading; Dict *dict; int typeA; @@ -3267,17 +3419,17 @@ GfxShading *GfxShading::parse(Object *obj, OutputDev *out) { switch (typeA) { case 1: - shading = GfxFunctionShading::parse(dict, out); + shading = GfxFunctionShading::parse(dict, out, state); break; case 2: - shading = GfxAxialShading::parse(dict, out); + shading = GfxAxialShading::parse(dict, out, state); break; case 3: - shading = GfxRadialShading::parse(dict, out); + shading = GfxRadialShading::parse(dict, out, state); break; case 4: if (obj->isStream()) { - shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream(), out); + shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream(), out, state); } else { error(errSyntaxWarning, -1, "Invalid Type 4 shading object"); goto err1; @@ -3285,7 +3437,7 @@ GfxShading *GfxShading::parse(Object *obj, OutputDev *out) { break; case 5: if (obj->isStream()) { - shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream(), out); + shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream(), out, state); } else { error(errSyntaxWarning, -1, "Invalid Type 5 shading object"); goto err1; @@ -3293,7 +3445,7 @@ GfxShading *GfxShading::parse(Object *obj, OutputDev *out) { break; case 6: if (obj->isStream()) { - shading = GfxPatchMeshShading::parse(6, dict, obj->getStream(), out); + shading = GfxPatchMeshShading::parse(6, dict, obj->getStream(), out, state); } else { error(errSyntaxWarning, -1, "Invalid Type 6 shading object"); goto err1; @@ -3301,7 +3453,7 @@ GfxShading *GfxShading::parse(Object *obj, OutputDev *out) { break; case 7: if (obj->isStream()) { - shading = GfxPatchMeshShading::parse(7, dict, obj->getStream(), out); + shading = GfxPatchMeshShading::parse(7, dict, obj->getStream(), out, state); } else { error(errSyntaxWarning, -1, "Invalid Type 7 shading object"); goto err1; @@ -3318,12 +3470,12 @@ GfxShading *GfxShading::parse(Object *obj, OutputDev *out) { return NULL; } -GBool GfxShading::init(Dict *dict, OutputDev *out) { +GBool GfxShading::init(Dict *dict, OutputDev *out, GfxState *state) { Object obj1, obj2; int i; dict->lookup("ColorSpace", &obj1); - if (!(colorSpace = GfxColorSpace::parse(&obj1, out))) { + if (!(colorSpace = GfxColorSpace::parse(&obj1, out, state))) { error(errSyntaxWarning, -1, "Bad color space in shading dictionary"); obj1.free(); return gFalse; @@ -3430,7 +3582,7 @@ GfxFunctionShading::~GfxFunctionShading() { } } -GfxFunctionShading *GfxFunctionShading::parse(Dict *dict, OutputDev *out) { +GfxFunctionShading *GfxFunctionShading::parse(Dict *dict, OutputDev *out, GfxState *state) { GfxFunctionShading *shading; double x0A, y0A, x1A, y1A; double matrixA[6]; @@ -3498,7 +3650,7 @@ GfxFunctionShading *GfxFunctionShading::parse(Dict *dict, OutputDev *out) { shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, funcsA, nFuncsA); - if (!shading->init(dict, out)) { + if (!shading->init(dict, out, state)) { delete shading; return NULL; } @@ -3749,7 +3901,7 @@ GfxAxialShading::GfxAxialShading(GfxAxialShading *shading): GfxAxialShading::~GfxAxialShading() { } -GfxAxialShading *GfxAxialShading::parse(Dict *dict, OutputDev *out) { +GfxAxialShading *GfxAxialShading::parse(Dict *dict, OutputDev *out, GfxState *state) { GfxAxialShading *shading; double x0A, y0A, x1A, y1A; double t0A, t1A; @@ -3846,7 +3998,7 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict, OutputDev *out) { shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A); - if (!shading->init(dict, out)) { + if (!shading->init(dict, out, state)) { delete shading; return NULL; } @@ -3957,7 +4109,7 @@ GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): GfxRadialShading::~GfxRadialShading() { } -GfxRadialShading *GfxRadialShading::parse(Dict *dict, OutputDev *out) { +GfxRadialShading *GfxRadialShading::parse(Dict *dict, OutputDev *out, GfxState *state) { GfxRadialShading *shading; double x0A, y0A, r0A, x1A, y1A, r1A; double t0A, t1A; @@ -4036,7 +4188,7 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict, OutputDev *out) { shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A); - if (!shading->init(dict, out)) { + if (!shading->init(dict, out, state)) { delete shading; return NULL; } @@ -4480,7 +4632,7 @@ GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, Dict *dict, Stream *str, - OutputDev *out) { + OutputDev *out, GfxState *gfxState) { GfxGouraudTriangleShading *shading; Function *funcsA[gfxColorMaxComps]; int nFuncsA; @@ -4676,7 +4828,7 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, trianglesA, nTrianglesA, funcsA, nFuncsA); - if (!shading->init(dict, out)) { + if (!shading->init(dict, out, gfxState)) { delete shading; return NULL; } @@ -4823,7 +4975,7 @@ GfxPatchMeshShading::~GfxPatchMeshShading() { } GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, - Stream *str, OutputDev *out) { + Stream *str, OutputDev *out, GfxState *state) { GfxPatchMeshShading *shading; Function *funcsA[gfxColorMaxComps]; int nFuncsA; @@ -5347,7 +5499,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, funcsA, nFuncsA); - if (!shading->init(dict, out)) { + if (!shading->init(dict, out, state)) { delete shading; return NULL; } @@ -6283,9 +6435,17 @@ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, clipXMax = pageWidth; clipYMax = pageHeight; + renderingIntent[0] = 0; + saved = NULL; #ifdef USE_CMS GfxColorSpace::setupColorProfiles(); + XYZ2DisplayTransformRelCol = NULL; + XYZ2DisplayTransformAbsCol = NULL; + XYZ2DisplayTransformSat = NULL; + XYZ2DisplayTransformPerc = NULL; + localDisplayProfile = NULL; + displayProfileRef = 0; #endif } @@ -6317,6 +6477,27 @@ GfxState::~GfxState() { if (font) { font->decRefCnt(); } +#ifdef USE_CMS + if (XYZ2DisplayTransformRelCol) { + if (XYZ2DisplayTransformRelCol->unref() == 0) + delete XYZ2DisplayTransformRelCol; + } + if (XYZ2DisplayTransformAbsCol) { + if (XYZ2DisplayTransformAbsCol->unref() == 0) + delete XYZ2DisplayTransformAbsCol; + } + if (XYZ2DisplayTransformSat) { + if (XYZ2DisplayTransformSat->unref() == 0) + delete XYZ2DisplayTransformSat; + } + if (XYZ2DisplayTransformPerc) { + if (XYZ2DisplayTransformPerc->unref() == 0) + delete XYZ2DisplayTransformPerc; + } + if (--displayProfileRef == 0 && localDisplayProfile != NULL) { + cmsCloseProfile(localDisplayProfile); + } +#endif } // Used for copy(); @@ -6352,8 +6533,102 @@ GfxState::GfxState(GfxState *state, GBool copyPath) { path = state->path->copy(); } saved = NULL; +#ifdef USE_CMS + if (XYZ2DisplayTransformRelCol) { + XYZ2DisplayTransformRelCol->ref(); + } + if (XYZ2DisplayTransformAbsCol) { + XYZ2DisplayTransformAbsCol->ref(); + } + if (XYZ2DisplayTransformSat) { + XYZ2DisplayTransformSat->ref(); + } + if (XYZ2DisplayTransformPerc) { + XYZ2DisplayTransformPerc->ref(); + } + if (localDisplayProfile) { + displayProfileRef++; + } +#endif +} + +#ifdef USE_CMS +void GfxState::setDisplayProfile(cmsHPROFILE localDisplayProfileA) { + if (localDisplayProfile != NULL) { + cmsCloseProfile(localDisplayProfile); + } + localDisplayProfile = localDisplayProfileA; + if (localDisplayProfileA != NULL) { + cmsHTRANSFORM transform; + unsigned int nChannels; + unsigned int localDisplayPixelType; + + localDisplayPixelType = getCMSColorSpaceType(cmsGetColorSpace(localDisplayProfile)); + nChannels = getCMSNChannels(cmsGetColorSpace(localDisplayProfile)); + displayProfileRef = 1; + // create transform from XYZ + cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); + if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, + localDisplayProfile, + COLORSPACE_SH(localDisplayPixelType) | + CHANNELS_SH(nChannels) | BYTES_SH(1), + INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) { + error(errSyntaxWarning, -1, "Can't create Lab transform"); + } else { + XYZ2DisplayTransformRelCol = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, localDisplayPixelType); + } + if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, + localDisplayProfile, + COLORSPACE_SH(localDisplayPixelType) | + CHANNELS_SH(nChannels) | BYTES_SH(1), + INTENT_ABSOLUTE_COLORIMETRIC,LCMS_FLAGS)) == 0) { + error(errSyntaxWarning, -1, "Can't create Lab transform"); + } else { + XYZ2DisplayTransformAbsCol = new GfxColorTransform(transform, INTENT_ABSOLUTE_COLORIMETRIC, localDisplayPixelType); + } + if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, + localDisplayProfile, + COLORSPACE_SH(localDisplayPixelType) | + CHANNELS_SH(nChannels) | BYTES_SH(1), + INTENT_SATURATION,LCMS_FLAGS)) == 0) { + error(errSyntaxWarning, -1, "Can't create Lab transform"); + } else { + XYZ2DisplayTransformSat = new GfxColorTransform(transform, INTENT_SATURATION, localDisplayPixelType); + } + if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, + localDisplayProfile, + COLORSPACE_SH(localDisplayPixelType) | + CHANNELS_SH(nChannels) | BYTES_SH(1), + INTENT_PERCEPTUAL,LCMS_FLAGS)) == 0) { + error(errSyntaxWarning, -1, "Can't create Lab transform"); + } else { + XYZ2DisplayTransformPerc = new GfxColorTransform(transform, INTENT_PERCEPTUAL, localDisplayPixelType); + } + cmsCloseProfile(XYZProfile); + } } +GfxColorTransform *GfxState::getXYZ2DisplayTransform() { + GfxColorTransform *transform; + + transform = XYZ2DisplayTransformRelCol; + if (renderingIntent != NULL) { + if (strcmp(renderingIntent, "AbsoluteColorimetric") == 0) { + transform = XYZ2DisplayTransformAbsCol; + } else if (strcmp(renderingIntent, "Saturation") == 0) { + transform = XYZ2DisplayTransformSat; + } else if (strcmp(renderingIntent, "Perceptual") == 0) { + transform = XYZ2DisplayTransformPerc; + } + } + if (transform == NULL) { + transform = XYZ2DisplayTransform; + } + return transform; +} + +#endif + void GfxState::setPath(GfxPath *pathA) { delete path; path = pathA; diff --git a/poppler/GfxState.h b/poppler/GfxState.h index 78fdbc0..70bc2ad 100644 --- a/poppler/GfxState.h +++ b/poppler/GfxState.h @@ -51,6 +51,7 @@ class GfxShading; class PopplerCache; class GooList; class OutputDev; +class GfxState; class Matrix { public: @@ -180,14 +181,18 @@ class GfxColorTransform { public: void doTransform(void *in, void *out, unsigned int size); // transformA should be a cmsHTRANSFORM - GfxColorTransform(void *transformA); + GfxColorTransform(void *transformA, int cmsIntent, unsigned int transformPixelType); ~GfxColorTransform(); + int getIntent() { return cmsIntent; } + int getTransformPixelType() { return transformPixelType; } void ref(); unsigned int unref(); private: GfxColorTransform() {} void *transform; unsigned int refCount; + int cmsIntent; + unsigned int transformPixelType; }; class GfxColorSpace { @@ -199,7 +204,7 @@ public: virtual GfxColorSpaceMode getMode() = 0; // Construct a color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Object *csObj, OutputDev *out, int recursion = 0); + static GfxColorSpace *parse(Object *csObj, OutputDev *out, GfxState *state, int recursion = 0); // Convert to gray, RGB, or CMYK. virtual void getGray(GfxColor *color, GfxGray *gray) = 0; @@ -312,7 +317,7 @@ public: virtual GfxColorSpaceMode getMode() { return csCalGray; } // Construct a CalGray color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); + static GfxColorSpace *parse(Array *arr, GfxState *state); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -338,6 +343,9 @@ private: double gamma; // gamma value double kr, kg, kb; // gamut mapping mulitpliers void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ); +#ifdef USE_CMS + GfxColorTransform *transform; +#endif }; //------------------------------------------------------------------------ @@ -387,7 +395,7 @@ public: virtual GfxColorSpaceMode getMode() { return csCalRGB; } // Construct a CalRGB color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); + static GfxColorSpace *parse(Array *arr, GfxState *state); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -417,6 +425,9 @@ private: double mat[9]; // ABC -> XYZ transform matrix double kr, kg, kb; // gamut mapping mulitpliers void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ); +#ifdef USE_CMS + GfxColorTransform *transform; +#endif }; //------------------------------------------------------------------------ @@ -463,7 +474,7 @@ public: virtual GfxColorSpaceMode getMode() { return csLab; } // Construct a Lab color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr); + static GfxColorSpace *parse(Array *arr, GfxState *state); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -495,6 +506,9 @@ private: double aMin, aMax, bMin, bMax; // range for the a and b components double kr, kg, kb; // gamut mapping mulitpliers void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ); +#ifdef USE_CMS + GfxColorTransform *transform; +#endif }; //------------------------------------------------------------------------ @@ -511,7 +525,7 @@ public: virtual GfxColorSpaceMode getMode() { return csICCBased; } // Construct an ICCBased color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr, OutputDev *out, int recursion); + static GfxColorSpace *parse(Array *arr, OutputDev *out, GfxState *state, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -544,6 +558,7 @@ private: double rangeMax[4]; // max values for each component Ref iccProfileStream; // the ICC profile #ifdef USE_CMS + int getIntent() { return (transform != NULL) ? transform->getIntent() : 0; } GfxColorTransform *transform; GfxColorTransform *lineTransform; // color transform for line #endif @@ -561,7 +576,7 @@ public: virtual GfxColorSpaceMode getMode() { return csIndexed; } // Construct an Indexed color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr, OutputDev *out, int recursion); + static GfxColorSpace *parse(Array *arr, OutputDev *out, GfxState *state, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -614,7 +629,7 @@ public: virtual GfxColorSpaceMode getMode() { return csSeparation; } // Construct a Separation color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr, OutputDev *out, int recursion); + static GfxColorSpace *parse(Array *arr, OutputDev *out, GfxState *state, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -659,7 +674,7 @@ public: virtual GfxColorSpaceMode getMode() { return csDeviceN; } // Construct a DeviceN color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr, OutputDev *out, int recursion); + static GfxColorSpace *parse(Array *arr, OutputDev *out, GfxState *state, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -706,7 +721,7 @@ public: virtual GfxColorSpaceMode getMode() { return csPattern; } // Construct a Pattern color space. Returns NULL if unsuccessful. - static GfxColorSpace *parse(Array *arr, OutputDev *out, int recursion); + static GfxColorSpace *parse(Array *arr, OutputDev *out, GfxState *state, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); @@ -735,7 +750,7 @@ public: GfxPattern(int typeA); virtual ~GfxPattern(); - static GfxPattern *parse(Object *obj, OutputDev *out); + static GfxPattern *parse(Object *obj, OutputDev *out, GfxState *state); virtual GfxPattern *copy() = 0; @@ -791,7 +806,7 @@ private: class GfxShadingPattern: public GfxPattern { public: - static GfxShadingPattern *parse(Object *patObj, OutputDev *out); + static GfxShadingPattern *parse(Object *patObj, OutputDev *out, GfxState *state); virtual ~GfxShadingPattern(); virtual GfxPattern *copy(); @@ -818,7 +833,7 @@ public: GfxShading(GfxShading *shading); virtual ~GfxShading(); - static GfxShading *parse(Object *obj, OutputDev *out); + static GfxShading *parse(Object *obj, OutputDev *out, GfxState *state); virtual GfxShading *copy() = 0; @@ -832,7 +847,7 @@ public: protected: - GBool init(Dict *dict, OutputDev *out); + GBool init(Dict *dict, OutputDev *out, GfxState *state); int type; GfxColorSpace *colorSpace; @@ -901,7 +916,7 @@ public: GfxFunctionShading(GfxFunctionShading *shading); virtual ~GfxFunctionShading(); - static GfxFunctionShading *parse(Dict *dict, OutputDev *out); + static GfxFunctionShading *parse(Dict *dict, OutputDev *out, GfxState *state); virtual GfxShading *copy(); @@ -935,7 +950,7 @@ public: GfxAxialShading(GfxAxialShading *shading); virtual ~GfxAxialShading(); - static GfxAxialShading *parse(Dict *dict, OutputDev *out); + static GfxAxialShading *parse(Dict *dict, OutputDev *out, GfxState *state); virtual GfxShading *copy(); @@ -968,7 +983,7 @@ public: GfxRadialShading(GfxRadialShading *shading); virtual ~GfxRadialShading(); - static GfxRadialShading *parse(Dict *dict, OutputDev *out); + static GfxRadialShading *parse(Dict *dict, OutputDev *out, GfxState *state); virtual GfxShading *copy(); @@ -1006,7 +1021,7 @@ public: GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); virtual ~GfxGouraudTriangleShading(); - static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str, OutputDev *out); + static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str, OutputDev *out, GfxState *state); virtual GfxShading *copy(); @@ -1092,7 +1107,7 @@ public: GfxPatchMeshShading(GfxPatchMeshShading *shading); virtual ~GfxPatchMeshShading(); - static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str, OutputDev *out); + static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str, OutputDev *out, GfxState *state); virtual GfxShading *copy(); @@ -1437,6 +1452,7 @@ public: double getLeading() { return leading; } double getRise() { return rise; } int getRender() { return render; } + char *getRenderingIntent() { return renderingIntent; } GfxPath *getPath() { return path; } void setPath(GfxPath *pathA); double getCurX() { return curX; } @@ -1515,6 +1531,14 @@ public: { rise = riseA; } void setRender(int renderA) { render = renderA; } + void setRenderingIntent(const char *intent) + { strncpy(renderingIntent, intent, 31); } + +#ifdef USE_CMS + void setDisplayProfile(void *localDisplayProfileA); + void *getDisplayProfile() { return localDisplayProfile; } + GfxColorTransform *getXYZ2DisplayTransform(); +#endif // Add to path. void moveTo(double x, double y) @@ -1603,10 +1627,20 @@ private: double clipXMin, clipYMin, // bounding box for clip region clipXMax, clipYMax; + char renderingIntent[32]; GfxState *saved; // next GfxState on stack GfxState(GfxState *state, GBool copyPath); + +#ifdef USE_CMS + void *localDisplayProfile; + int displayProfileRef; + GfxColorTransform *XYZ2DisplayTransformRelCol; + GfxColorTransform *XYZ2DisplayTransformAbsCol; + GfxColorTransform *XYZ2DisplayTransformSat; + GfxColorTransform *XYZ2DisplayTransformPerc; +#endif }; #endif diff --git a/poppler/Page.cc b/poppler/Page.cc index 0465c6b..ecdff32 100644 --- a/poppler/Page.cc +++ b/poppler/Page.cc @@ -672,7 +672,7 @@ GBool Page::loadThumb(unsigned char **data_out, obj1.free (); dict->lookup ("CS", &obj1); } - colorSpace = GfxColorSpace::parse(&obj1, NULL); + colorSpace = GfxColorSpace::parse(&obj1, NULL, NULL); obj1.free(); if (!colorSpace) { fprintf (stderr, "Error: Cannot parse color space\n");