diff --git a/poppler/Function.cc b/poppler/Function.cc index 25e8f74..f4ef2b0 100644 --- a/poppler/Function.cc +++ b/poppler/Function.cc @@ -509,6 +509,20 @@ void SampledFunction::transform(double *in, double *out) { } } +GBool SampledFunction::hasDifferntResultSet(Function *func) { + if (func->getType() == 0) { + SampledFunction *compTo = (SampledFunction *) func; + if (compTo->getSampleNumber() != nSamples) + return gTrue; + double *compSamples = compTo->getSamples(); + for (int i = 0; i < nSamples; i++) { + if (samples[i] != compSamples[i]) + return gTrue; + } + } + return gFalse; +} + //------------------------------------------------------------------------ // ExponentialFunction //------------------------------------------------------------------------ diff --git a/poppler/Function.h b/poppler/Function.h index a456dfe..797397b 100644 --- a/poppler/Function.h +++ b/poppler/Function.h @@ -79,6 +79,7 @@ public: double getRangeMin(int i) { return range[i][0]; } double getRangeMax(int i) { return range[i][1]; } GBool getHasRange() { return hasRange; } + virtual GBool hasDifferntResultSet(Function *func) { return gFalse; } // Transform an input tuple into an output tuple. virtual void transform(double *in, double *out) = 0; @@ -126,6 +127,7 @@ public: virtual int getType() { return 0; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + virtual GBool hasDifferntResultSet(Function *func); int getSampleSize(int i) { return sampleSize[i]; } double getEncodeMin(int i) { return encode[i][0]; } @@ -133,6 +135,7 @@ public: double getDecodeMin(int i) { return decode[i][0]; } double getDecodeMax(int i) { return decode[i][1]; } double *getSamples() { return samples; } + int getSampleNumber() { return nSamples; } private: diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index e3413e5..a195835 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -248,6 +248,7 @@ cmsHPROFILE GfxColorSpace::getDisplayProfile() { GfxColorSpace::GfxColorSpace() { overprintMask = 0x0f; + mapping = NULL; } GfxColorSpace::~GfxColorSpace() { @@ -321,6 +322,10 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj, Gfx *gfx, int recursion) { return cs; } +void GfxColorSpace::createMapping(GooList *separationList, int maxSepComps) { + return; +} + void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { int i; @@ -602,6 +607,12 @@ void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = clip01(gfxColorComp1 - color->c[0]); } +void GfxDeviceGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + deviceN->c[3] = clip01(gfxColorComp1 - color->c[0]); +} + void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; } @@ -810,6 +821,17 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = k; } +void GfxCalGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + GfxCMYK cmyk; + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; +} + void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; } @@ -895,6 +917,17 @@ void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = k; } +void GfxDeviceRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + GfxCMYK cmyk; + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; +} + void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; color->c[1] = 0; @@ -1127,6 +1160,17 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = k; } +void GfxCalRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + GfxCMYK cmyk; + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; +} + void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; color->c[1] = 0; @@ -1227,6 +1271,15 @@ void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = clip01(color->c[3]); } +void GfxDeviceCMYKColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + deviceN->c[0] = clip01(color->c[0]); + deviceN->c[1] = clip01(color->c[1]); + deviceN->c[2] = clip01(color->c[2]); + deviceN->c[3] = clip01(color->c[3]); +} + void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; color->c[1] = 0; @@ -1453,6 +1506,17 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = k; } +void GfxLabColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + GfxCMYK cmyk; + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; +} + void GfxLabColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; if (aMin > 0) { @@ -1858,6 +1922,17 @@ GBool GfxICCBasedColorSpace::useGetRGBLine() { #endif } +void GfxICCBasedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + GfxCMYK cmyk; + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; +} + void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) { int i; @@ -2077,6 +2152,12 @@ void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { base->getCMYK(mapColorToBase(color, &color2), cmyk); } +void GfxIndexedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + GfxColor color2; + + base->getDeviceN(mapColorToBase(color, &color2), deviceN); +} + void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; } @@ -2107,6 +2188,8 @@ GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA, overprintMask = 0x04; } else if (!name->cmp("Black")) { overprintMask = 0x08; + } else if (!name->cmp("All")) { + overprintMask = 0xffffffff; } } @@ -2114,23 +2197,32 @@ GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA, Function *funcA, GBool nonMarkingA, - Guint overprintMaskA) { + Guint overprintMaskA, + int *mappingA) { name = nameA; alt = altA; func = funcA; nonMarking = nonMarkingA; overprintMask = overprintMaskA; + mapping = mappingA; } GfxSeparationColorSpace::~GfxSeparationColorSpace() { delete name; delete alt; delete func; + if (mapping != NULL) + gfree(mapping); } GfxColorSpace *GfxSeparationColorSpace::copy() { + int *mappingA = NULL; + if (mapping != NULL) { + mappingA = (int *) gmalloc(sizeof(int)); + *mappingA = *mapping; + } return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(), - nonMarking, overprintMask); + nonMarking, overprintMask, mappingA); } //~ handle the 'All' and 'None' colorants @@ -2217,10 +2309,75 @@ void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { alt->getCMYK(&color2, cmyk); } +void GfxSeparationColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + if (mapping == NULL || mapping[0] == -1) { + GfxCMYK cmyk; + + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; + } else { + deviceN->c[mapping[0]] = color->c[0]; + } +} + void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = gfxColorComp1; } +void GfxSeparationColorSpace::createMapping(GooList *separationList, int maxSepComps) { + if (nonMarking) + return; + mapping = (int *)gmalloc(sizeof(int)); + switch (overprintMask) { + case 0x01: + *mapping = 0; + break; + case 0x02: + *mapping = 1; + break; + case 0x04: + *mapping = 2; + break; + case 0x08: + *mapping = 3; + break; + default: + Guint newOverprintMask = 0x10; + for (int i = 0; i < separationList->getLength(); i++) { + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + if (!sepCS->getName()->cmp(name)) { + if (sepCS->getFunc()->hasDifferntResultSet(func)) { + error(errSyntaxWarning, -1, + "Different functions found for '{0:s}', convert immediately", name); + gfree(mapping); + mapping = NULL; + return; + } + *mapping = i+4; + overprintMask = newOverprintMask; + return; + } + newOverprintMask <<=1; + } + if (separationList->getLength() == maxSepComps) { + error(errSyntaxWarning, -1, + "Too many ({0:d}) spots, convert '{1:s}' immediately", maxSepComps, name); + gfree(mapping); + mapping = NULL; + return; + } + *mapping = separationList->getLength() + 4; + separationList->append(this->copy()); + overprintMask = newOverprintMask; + break; + } +} + //------------------------------------------------------------------------ // GfxDeviceNColorSpace //------------------------------------------------------------------------ @@ -2228,14 +2385,17 @@ void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) { GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, GooString **namesA, GfxColorSpace *altA, - Function *funcA) { + Function *funcA, + GooList *sepsCSA) { int i; nComps = nCompsA; alt = altA; func = funcA; + sepsCS = sepsCSA; nonMarking = gTrue; overprintMask = 0; + mapping = NULL; for (i = 0; i < nComps; ++i) { names[i] = namesA[i]; if (names[i]->cmp("None")) { @@ -2249,6 +2409,8 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, overprintMask |= 0x04; } else if (!names[i]->cmp("Black")) { overprintMask |= 0x08; + } else if (!names[i]->cmp("All")) { + overprintMask = 0xffffffff; } else { overprintMask = 0x0f; } @@ -2259,6 +2421,8 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, GooString **namesA, GfxColorSpace *altA, Function *funcA, + GooList *sepsCSA, + int *mappingA, GBool nonMarkingA, Guint overprintMaskA) { int i; @@ -2266,6 +2430,8 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, nComps = nCompsA; alt = altA; func = funcA; + sepsCS = sepsCSA; + mapping = mappingA; nonMarking = nonMarkingA; overprintMask = overprintMaskA; for (i = 0; i < nComps; ++i) { @@ -2281,11 +2447,25 @@ GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { } delete alt; delete func; + deleteGooList(sepsCS, GfxSeparationColorSpace); + if (mapping != NULL) + gfree(mapping); } GfxColorSpace *GfxDeviceNColorSpace::copy() { + int i; + int *mappingA = NULL; + + GooList *sepsCSA = new GooList(sepsCS->getLength()); + for (i = 0; i < sepsCS->getLength(); i++) + sepsCSA->append(((GfxSeparationColorSpace *) sepsCS->get(i))->copy()); + if (mapping != NULL) { + mappingA = (int *)gmalloc(sizeof(int) * nComps); + for (i = 0; i < nComps; i++) + mappingA[i] = mapping[i]; + } return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(), - nonMarking, overprintMask); + sepsCSA, mappingA, nonMarking, overprintMask); } //~ handle the 'None' colorant @@ -2297,6 +2477,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion) Function *funcA; Object obj1, obj2; int i; + GooList *separationList = new GooList(); if (arr->getLength() != 4 && arr->getLength() != 5) { error(errSyntaxWarning, -1, "Bad DeviceN color space"); @@ -2333,7 +2514,26 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion) goto err4; } obj1.free(); - cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA); + if (arr->getLength() == 5) { + if (!arr->get(4, &obj1)->isDict()) { + error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)"); + goto err4; + } + Dict *attribs = obj1.getDict(); + attribs->lookup("Colorants", &obj2); + if (obj2.isDict()) { + Dict *colorants = obj2.getDict(); + for (i = 0; i < colorants->getLength(); i++) { + Object obj3; + colorants->getVal(i, &obj3); + separationList->append(GfxSeparationColorSpace::parse(obj3.getArray(), gfx, recursion)); + obj3.free(); + } + } + obj2.free(); + obj1.free(); + } + cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList); return cs; err4: @@ -2345,6 +2545,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion) err2: obj1.free(); err1: + delete separationList; return NULL; } @@ -2393,6 +2594,24 @@ void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { alt->getCMYK(&color2, cmyk); } +void GfxDeviceNColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + if (mapping == NULL) { + GfxCMYK cmyk; + + getCMYK(color, &cmyk); + deviceN->c[0] = cmyk.c; + deviceN->c[1] = cmyk.m; + deviceN->c[2] = cmyk.y; + deviceN->c[3] = cmyk.k; + } else { + for (int j = 0; j < nComps; j++) + if (mapping[j] != -1) + deviceN->c[mapping[j]] = color->c[j]; + } +} + void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) { int i; @@ -2401,6 +2620,95 @@ void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) { } } +void GfxDeviceNColorSpace::createMapping(GooList *separationList, int maxSepComps) { + if (nonMarking) // None + return; + mapping = (int *)gmalloc(sizeof(int) * nComps); + Guint newOverprintMask = 0; + for (int i = 0; i < nComps; i++) { + if (!names[i]->cmp("None")) { + mapping[i] = -1; + } else if (!names[i]->cmp("Cyan")) { + newOverprintMask |= 0x01; + mapping[i] = 0; + } else if (!names[i]->cmp("Magenta")) { + newOverprintMask |= 0x02; + mapping[i] = 1; + } else if (!names[i]->cmp("Yellow")) { + newOverprintMask |= 0x04; + mapping[i] = 2; + } else if (!names[i]->cmp("Black")) { + newOverprintMask |= 0x08; + mapping[i] = 3; + } else { + Guint startOverprintMask = 0x10; + GBool found = gFalse; + Function *sepFunc = NULL; + if (nComps == 1) + sepFunc = func; + else { + for (int k = 0; k < sepsCS->getLength(); k++) { + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k); + if (!sepCS->getName()->cmp(names[i])) { + sepFunc = sepCS->getFunc(); + break; + } + } + } + for (int j = 0; j < separationList->getLength(); j++) { + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(j); + if (!sepCS->getName()->cmp(names[i])) { + if (sepFunc != NULL && sepCS->getFunc()->hasDifferntResultSet(sepFunc)) { + error(errSyntaxWarning, -1, + "Different functions found for '{0:s}', convert immediately", names[i]); + gfree(mapping); + mapping = NULL; + overprintMask = 0xffffffff; + return; + } + mapping[i] = j+4; + newOverprintMask |= startOverprintMask; + found = gTrue; + break; + } + startOverprintMask <<=1; + } + if (!found) { + if (separationList->getLength() == maxSepComps) { + error(errSyntaxWarning, -1, + "Too many ({0:d}) spots, convert '{1:s}' immediately", maxSepComps, names[i]); + gfree(mapping); + mapping = NULL; + overprintMask = 0xffffffff; + return; + } + mapping[i] = separationList->getLength() + 4; + newOverprintMask |= startOverprintMask; + if (nComps == 1) + separationList->append(new GfxSeparationColorSpace(names[i]->copy(),alt->copy(), func->copy())); + else { + for (int k = 0; k < sepsCS->getLength(); k++) { + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k); + if (!sepCS->getName()->cmp(names[i])) { + found = gTrue; + separationList->append(sepCS->copy()); + break; + } + } + if(!found) { + error(errSyntaxWarning, -1, "DeviceN has no suitable colorant"); + gfree(mapping); + mapping = NULL; + overprintMask = 0xffffffff; + return; + } + } + } + } + } + overprintMask = newOverprintMask; +} + //------------------------------------------------------------------------ // GfxPatternColorSpace //------------------------------------------------------------------------ @@ -2456,6 +2764,12 @@ void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = 1; } +void GfxPatternColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { + for (int i = 0; i < gfxColorMaxComps; i++) + deviceN->c[i] = 0; + deviceN->c[3] = 1; +} + void GfxPatternColorSpace::getDefaultColor(GfxColor *color) { color->c[0]=0; } @@ -5273,6 +5587,23 @@ void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { } } +void GfxImageColorMap::getDeviceN(Guchar *x, GfxColor *deviceN) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup2[i][x[0]]; + } + colorSpace2->getDeviceN(&color, deviceN); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getDeviceN(&color, deviceN); + } +} + void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { int maxPixel, i; diff --git a/poppler/GfxState.h b/poppler/GfxState.h index 856ec3f..2fbb286 100644 --- a/poppler/GfxState.h +++ b/poppler/GfxState.h @@ -48,6 +48,7 @@ class GfxFont; class PDFRectangle; class GfxShading; class PopplerCache; +class GooList; class Matrix { public: @@ -202,11 +203,15 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray) = 0; virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN) = 0; virtual void getGrayLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getGrayLine this should not happen"); } virtual void getRGBLine(Guchar * /*in*/, unsigned int * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (first variant) this should not happen"); } virtual void getRGBLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (second variant) this should not happen"); } virtual void getRGBXLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBXLine this should not happen"); } + // create mapping for spot colorants + virtual void createMapping(GooList *separationList, int maxSepComps); + // Does this ColorSpace support getRGBLine? virtual GBool useGetRGBLine() { return gFalse; } // Does this ColorSpace support getGrayLine? @@ -249,6 +254,7 @@ public: protected: Guint overprintMask; + int *mapping; }; //------------------------------------------------------------------------ @@ -266,6 +272,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual void getGrayLine(Guchar *in, Guchar *out, int length); virtual void getRGBLine(Guchar *in, unsigned int *out, int length); virtual void getRGBLine(Guchar *in, Guchar *out, int length); @@ -298,6 +305,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual int getNComps() { return 1; } virtual void getDefaultColor(GfxColor *color); @@ -335,6 +343,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual void getGrayLine(Guchar *in, Guchar *out, int length); virtual void getRGBLine(Guchar *in, unsigned int *out, int length); virtual void getRGBLine(Guchar *in, Guchar *out, int length); @@ -367,6 +376,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual int getNComps() { return 3; } virtual void getDefaultColor(GfxColor *color); @@ -408,6 +418,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual void getRGBLine(Guchar *in, unsigned int *out, int length); virtual void getRGBLine(Guchar *, Guchar *out, int length); virtual void getRGBXLine(Guchar *in, Guchar *out, int length); @@ -437,6 +448,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual int getNComps() { return 3; } virtual void getDefaultColor(GfxColor *color); @@ -484,6 +496,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual void getRGBLine(Guchar *in, unsigned int *out, int length); virtual void getRGBLine(Guchar *in, Guchar *out, int length); virtual void getRGBXLine(Guchar *in, Guchar *out, int length); @@ -529,6 +542,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual void getRGBLine(Guchar *in, unsigned int *out, int length); virtual void getRGBLine(Guchar *in, Guchar *out, int length); virtual void getRGBXLine(Guchar *in, Guchar *out, int length); @@ -546,6 +560,10 @@ public: int getIndexHigh() { return indexHigh; } Guchar *getLookup() { return lookup; } GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor); + Guint getOverprintMask() { return base->getOverprintMask(); } + virtual void createMapping(GooList *separationList, int maxSepComps) + { base->createMapping(separationList, maxSepComps); } + private: @@ -573,6 +591,9 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); + + virtual void createMapping(GooList *separationList, int maxSepComps); virtual int getNComps() { return 1; } virtual void getDefaultColor(GfxColor *color); @@ -588,7 +609,7 @@ private: GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA, Function *funcA, GBool nonMarkingA, - Guint overprintMaskA); + Guint overprintMaskA, int *mappingA); GooString *name; // colorant name GfxColorSpace *alt; // alternate color space @@ -604,7 +625,7 @@ class GfxDeviceNColorSpace: public GfxColorSpace { public: GfxDeviceNColorSpace(int nCompsA, GooString **namesA, - GfxColorSpace *alt, Function *func); + GfxColorSpace *alt, Function *func, GooList *sepsCS); virtual ~GfxDeviceNColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceN; } @@ -615,6 +636,9 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); + + virtual void createMapping(GooList *separationList, int maxSepComps); virtual int getNComps() { return nComps; } virtual void getDefaultColor(GfxColor *color); @@ -629,8 +653,8 @@ public: private: GfxDeviceNColorSpace(int nCompsA, GooString **namesA, - GfxColorSpace *alt, Function *func, - GBool nonMarkingA, Guint overprintMaskA); + GfxColorSpace *alt, Function *func, GooList *sepsCSA, + int *mappingA, GBool nonMarkingA, Guint overprintMaskA); int nComps; // number of components GooString // colorant names @@ -638,6 +662,7 @@ private: GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) GBool nonMarking; + GooList *sepsCS; // list of separation cs for spot colorants; }; //------------------------------------------------------------------------ @@ -658,6 +683,7 @@ public: virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + virtual void getDeviceN(GfxColor *color, GfxColor *deviceN); virtual int getNComps() { return 0; } virtual void getDefaultColor(GfxColor *color); @@ -1107,6 +1133,7 @@ public: void getRGBXLine(Guchar *in, Guchar *out, int length); void getGrayLine(Guchar *in, Guchar *out, int length); void getCMYK(Guchar *x, GfxCMYK *cmyk); + void getDeviceN(Guchar *x, GfxColor *deviceN); void getColor(Guchar *x, GfxColor *color); private: @@ -1342,8 +1369,12 @@ public: { strokeColorSpace->getRGB(&strokeColor, rgb); } void getFillCMYK(GfxCMYK *cmyk) { fillColorSpace->getCMYK(&fillColor, cmyk); } + void getFillDeviceN(GfxColor *deviceN) + { fillColorSpace->getDeviceN(&fillColor, deviceN); } void getStrokeCMYK(GfxCMYK *cmyk) { strokeColorSpace->getCMYK(&strokeColor, cmyk); } + void getStrokeDeviceN(GfxColor *deviceN) + { strokeColorSpace->getDeviceN(&strokeColor, deviceN); } GfxColorSpace *getFillColorSpace() { return fillColorSpace; } GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } GfxPattern *getFillPattern() { return fillPattern; } diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 9e07060..05e9dea 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -94,6 +94,7 @@ static inline void convertGfxColor(SplashColorPtr dest, GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif // make gcc happy @@ -124,6 +125,11 @@ static inline void convertGfxColor(SplashColorPtr dest, color[2] = colToByte(cmyk.y); color[3] = colToByte(cmyk.k); break; + case splashModeDeviceN8: + colorSpace->getDeviceN(src, &deviceN); + for (int i = 0; i < SPOT_NCOMPS + 4; i++) + color[i] = colToByte(deviceN.c[i]); + break; #endif } splashColorCopy(dest, color); @@ -154,6 +160,8 @@ void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColor #if SPLASH_CMYK if (mode == splashModeCMYK8) colorComps=4; + else if (mode == splashModeDeviceN8) + colorComps=4 + SPOT_NCOMPS; #endif shading->getParameterizedColor(colorinterp, &src); @@ -436,7 +444,7 @@ static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -460,7 +468,7 @@ static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -484,7 +492,7 @@ static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -512,7 +520,7 @@ static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -536,7 +544,7 @@ static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -561,7 +569,7 @@ static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, int i, x; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -595,7 +603,7 @@ static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, int i, x; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -629,7 +637,7 @@ static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -657,7 +665,7 @@ static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, int i, x; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -700,7 +708,7 @@ static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -724,7 +732,7 @@ static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, int i; #if SPLASH_CMYK - if (cm == splashModeCMYK8) { + if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) { SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; @@ -859,6 +867,7 @@ static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: for (i = 0; i < 4; i++) { // convert to additive src2[i] = 0xff - src[i]; @@ -908,6 +917,7 @@ static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: for (i = 0; i < 4; i++) { // convert to additive src2[i] = 0xff - src[i]; @@ -952,6 +962,7 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: for (i = 0; i < 4; i++) { // convert to additive src2[i] = 0xff - src[i]; @@ -995,6 +1006,7 @@ static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: for (i = 0; i < 4; i++) { // convert to additive src2[i] = 0xff - src[i]; @@ -1391,6 +1403,10 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) { case splashModeCMYK8: color[0] = color[1] = color[2] = color[3] = 0; break; + case splashModeDeviceN8: + for (int i = 0; i < 4 + SPOT_NCOMPS; i++) + color[i] = 0; + break; #endif } splash->setStrokePattern(new SplashSolidColor(color)); @@ -1429,7 +1445,9 @@ void SplashOutputDev::updateAll(GfxState *state) { updateFlatness(state); updateMiterLimit(state); updateStrokeAdjust(state); + updateFillColorSpace(state); updateFillColor(state); + updateStrokeColorSpace(state); updateStrokeColor(state); needFontUpdate = gTrue; } @@ -1500,11 +1518,26 @@ void SplashOutputDev::updateStrokeAdjust(GfxState * /*state*/) { #endif } +void SplashOutputDev::updateFillColorSpace(GfxState *state) { +#if SPLASH_CMYK + if (colorMode == splashModeDeviceN8) + state->getFillColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS); +#endif +} + +void SplashOutputDev::updateStrokeColorSpace(GfxState *state) { +#if SPLASH_CMYK + if (colorMode == splashModeDeviceN8) + state->getStrokeColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS); +#endif +} + void SplashOutputDev::updateFillColor(GfxState *state) { GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif switch (colorMode) { @@ -1524,6 +1557,10 @@ void SplashOutputDev::updateFillColor(GfxState *state) { state->getFillCMYK(&cmyk); splash->setFillPattern(getColor(&cmyk)); break; + case splashModeDeviceN8: + state->getFillDeviceN(&deviceN); + splash->setFillPattern(getColor(&deviceN)); + break; #endif } } @@ -1533,6 +1570,7 @@ void SplashOutputDev::updateStrokeColor(GfxState *state) { GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif switch (colorMode) { @@ -1552,6 +1590,10 @@ void SplashOutputDev::updateStrokeColor(GfxState *state) { state->getStrokeCMYK(&cmyk); splash->setStrokePattern(getColor(&cmyk)); break; + case splashModeDeviceN8: + state->getStrokeDeviceN(&deviceN); + splash->setStrokePattern(getColor(&deviceN)); + break; #endif } } @@ -1596,6 +1638,14 @@ SplashPattern *SplashOutputDev::getColor(GfxCMYK *cmyk) { color[3] = colToByte(cmyk->k); return new SplashSolidColor(color); } + +SplashPattern *SplashOutputDev::getColor(GfxColor *deviceN) { + SplashColor color; + + for (int i = 0; i < 4 + SPOT_NCOMPS; i++) + color[i] = colToByte(deviceN->c[i]); + return new SplashSolidColor(color); +} #endif void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace, @@ -2717,6 +2767,7 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif int nComps, x; @@ -2765,6 +2816,13 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, *q++ = col[3]; } break; + case splashModeDeviceN8: + for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) { + col = &imgData->lookup[(SPOT_NCOMPS+4) * *p]; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *q++ = col[cp]; + } + break; #endif } } else { @@ -2804,6 +2862,13 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, *q++ = colToByte(cmyk.k); } break; + case splashModeDeviceN8: + for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) { + imgData->colorMap->getDeviceN(p, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *q++ = colToByte(deviceN.c[cp]); + } + break; #endif } } @@ -2821,6 +2886,7 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif Guchar alpha; int nComps, x, i; @@ -2873,6 +2939,11 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, *q++ = col[2]; *q++ = col[3]; break; + case splashModeDeviceN8: + col = &imgData->lookup[(SPOT_NCOMPS+4) * *p]; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *q++ = col[cp]; + break; #endif } *aq++ = alpha; @@ -2900,6 +2971,11 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, *q++ = colToByte(cmyk.y); *q++ = colToByte(cmyk.k); break; + case splashModeDeviceN8: + imgData->colorMap->getDeviceN(p, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *q++ = colToByte(deviceN.c[cp]); + break; #endif } *aq++ = alpha; @@ -2976,7 +3052,7 @@ GBool SplashOutputDev::tilingBitmapSrc(void *data, SplashColorPtr colorLine, imgData->pattern->getColor(x, imgData->y, pat); for (int i = 0; i < splashColorModeNComps[imgData->colorMode]; ++i) { #if SPLASH_CMYK - if (imgData->colorMode == splashModeCMYK8) + if (imgData->colorMode == splashModeCMYK8 || imgData->colorMode == splashModeDeviceN8) dest[i] = div255(pat[i] * (255 - col[0])); else #endif @@ -3017,6 +3093,7 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, #if SPLASH_CMYK GfxCMYK cmyk; GBool grayIndexed = gFalse; + GfxColor deviceN; #endif Guchar pix; int n, i; @@ -3096,6 +3173,21 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, imgData.lookup[4*i+3] = colToByte(cmyk.k); } break; + case splashModeDeviceN8: + colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS); + grayIndexed = colorMap->getColorSpace()->getMode() != csDeviceGray; + imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + if (cmyk.c != 0 || cmyk.m != 0 || cmyk.y != 0) { + grayIndexed = gFalse; + } + colorMap->getDeviceN(&pix, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + imgData.lookup[(SPOT_NCOMPS+4)*i +cp] = colToByte(deviceN.c[cp]); + } + break; #endif } } @@ -3146,6 +3238,7 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif Guchar alpha; Guchar *maskPtr; @@ -3200,6 +3293,11 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, *q++ = col[2]; *q++ = col[3]; break; + case splashModeDeviceN8: + col = &imgData->lookup[(SPOT_NCOMPS+4) * *p]; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *q++ = col[cp]; + break; #endif } *aq++ = alpha; @@ -3227,6 +3325,11 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, *q++ = colToByte(cmyk.y); *q++ = colToByte(cmyk.k); break; + case splashModeDeviceN8: + imgData->colorMap->getDeviceN(p, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *q++ = colToByte(deviceN.c[cp]); + break; #endif } *aq++ = alpha; @@ -3258,10 +3361,14 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif Guchar pix; int n, i; +#if SPLASH_CMYK + colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS); +#endif setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(), state->getOverprintMode(), NULL); @@ -3383,6 +3490,15 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, imgData.lookup[4*i+3] = colToByte(cmyk.k); } break; + case splashModeDeviceN8: + imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getDeviceN(&pix, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]); + } + break; #endif } } @@ -3421,10 +3537,14 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif Guchar pix; int n, i; +#if SPLASH_CMYK + colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS); +#endif setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(), state->getOverprintMode(), NULL); @@ -3533,6 +3653,15 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, imgData.lookup[4*i+3] = colToByte(cmyk.k); } break; + case splashModeDeviceN8: + imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getDeviceN(&pix, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]); + } + break; #endif } } @@ -3676,7 +3805,7 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, // create the temporary bitmap bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue, - bitmapTopDown); + bitmapTopDown, bitmap->getSeparationList()); splash = new Splash(bitmap, vectorAntialias, transpGroup->origSplash->getScreen()); splash->setMinLineWidth(globalParams->getMinLineWidth()); @@ -3765,6 +3894,7 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox, GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; + GfxColor deviceN; #endif double lum, lum2; int tx, ty, x, y; @@ -3808,6 +3938,12 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox, color[3] = colToByte(cmyk.k); tSplash->compositeBackground(color); break; + case splashModeDeviceN8: + transpGroupStack->blendingColorSpace->getDeviceN(backdropColor, &deviceN); + for (int cp=0; cp < SPOT_NCOMPS+4; cp++) + color[cp] = colToByte(deviceN.c[cp]); + tSplash->compositeBackground(color); + break; #endif } delete tSplash; @@ -3849,6 +3985,7 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox, break; #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: lum = (1 - color[3] / 255.0) - (0.3 / 255.0) * color[0] - (0.59 / 255.0) * color[1] @@ -4047,7 +4184,9 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *ca memset(bitmap->getAlphaPtr(), 0, bitmap->getWidth() * bitmap->getHeight()); if (paintType == 2) { #if SPLASH_CMYK - memset(bitmap->getDataPtr(), (colorMode == splashModeCMYK8) ? 0x00 : 0xFF, bitmap->getRowSize() * bitmap->getHeight()); + memset(bitmap->getDataPtr(), + (colorMode == splashModeCMYK8 || colorMode == splashModeDeviceN8) ? 0x00 : 0xFF, + bitmap->getRowSize() * bitmap->getHeight()); #else memset(bitmap->getDataPtr(), 0xFF, bitmap->getRowSize() * bitmap->getHeight()); #endif @@ -4107,7 +4246,8 @@ GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTria break; #if SPLASH_CMYK case splashModeCMYK8: - bDirectColorTranslation = (shadingMode == csDeviceCMYK); + case splashModeDeviceN8: + bDirectColorTranslation = (shadingMode == csDeviceCMYK || shadingMode == csDeviceN); break; #endif default: @@ -4177,6 +4317,9 @@ GBool SplashOutputDev::univariateShadedFill(GfxState *state, SplashUnivariatePat state->closePath(); path = convertPath(state, state->getPath(), gTrue); +#if SPLASH_CMYK + pattern->getShading()->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS); +#endif setOverprintMask(pattern->getShading()->getColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); retVal = (splash->shadedFill(path, pattern->getShading()->getHasBBox(), pattern) == splashOk); diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h index f1c87ec..de7934d 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -215,6 +215,8 @@ public: virtual void updateMiterLimit(GfxState *state); virtual void updateLineWidth(GfxState *state); virtual void updateStrokeAdjust(GfxState *state); + virtual void updateFillColorSpace(GfxState *state); + virtual void updateStrokeColorSpace(GfxState *state); virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); virtual void updateBlendMode(GfxState *state); @@ -362,6 +364,7 @@ private: SplashPattern *getColor(GfxRGB *rgb); #if SPLASH_CMYK SplashPattern *getColor(GfxCMYK *cmyk); + SplashPattern *getColor(GfxColor *deviceN); #endif void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag, int overprintMode, GfxColor *singleColor, GBool grayIndexed = gFalse); diff --git a/splash/Splash.cc b/splash/Splash.cc index e6559f4..e46a496 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -36,6 +36,7 @@ #include #include "goo/gmem.h" #include "goo/GooLikely.h" +#include "goo/GooList.h" #include "poppler/Error.h" #include "SplashErrorCodes.h" #include "SplashMath.h" @@ -170,7 +171,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { splashPipeResultColorNoAlphaBlendRGB #if SPLASH_CMYK , - splashPipeResultColorNoAlphaBlendCMYK + splashPipeResultColorNoAlphaBlendCMYK, + splashPipeResultColorNoAlphaBlendDeviceN #endif }; @@ -182,7 +184,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { splashPipeResultColorAlphaNoBlendRGB #if SPLASH_CMYK , - splashPipeResultColorAlphaNoBlendCMYK + splashPipeResultColorAlphaNoBlendCMYK, + splashPipeResultColorAlphaNoBlendDeviceN #endif }; @@ -194,7 +197,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { splashPipeResultColorAlphaBlendRGB #if SPLASH_CMYK , - splashPipeResultColorAlphaBlendCMYK + splashPipeResultColorAlphaBlendCMYK, + splashPipeResultColorAlphaBlendDeviceN #endif }; @@ -307,6 +311,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, #if SPLASH_CMYK } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleCMYK8; + } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleDeviceN8; #endif } } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && @@ -326,6 +332,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, #if SPLASH_CMYK } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAACMYK8; + } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAADeviceN8; #endif } } @@ -338,6 +346,10 @@ void Splash::pipeRun(SplashPipe *pipe) { SplashColorPtr cSrc; Guchar cResult0, cResult1, cResult2, cResult3; int t; +#if SPLASH_CMYK + int cp, mask; + Guchar cResult[SPOT_NCOMPS+4]; +#endif //----- source color @@ -412,6 +424,16 @@ void Splash::pipeRun(SplashPipe *pipe) { } pipe->destColorPtr += 4; break; + case splashModeDeviceN8: + mask = 1; + for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; + } + mask <<= 1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; #endif } if (pipe->destAlphaPtr) { @@ -452,6 +474,10 @@ void Splash::pipeRun(SplashPipe *pipe) { cDest[2] = pipe->destColorPtr[2]; cDest[3] = pipe->destColorPtr[3]; break; + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS + 4; cp++) + cDest[cp] = pipe->destColorPtr[cp]; + break; #endif } if (pipe->destAlphaPtr) { @@ -489,6 +515,10 @@ void Splash::pipeRun(SplashPipe *pipe) { t = (aDest * 255) / pipe->shape - aDest; switch (bitmap->mode) { #if SPLASH_CMYK + case splashModeDeviceN8: + for (cp = 4; cp < SPOT_NCOMPS + 4; cp++) + cSrcNonIso[cp] = clip255(pipe->cSrc[cp] + + ((pipe->cSrc[cp] - cDest[cp]) * t) / 255); case splashModeCMYK8: cSrcNonIso[3] = clip255(pipe->cSrc[3] + ((pipe->cSrc[3] - cDest[3]) * t) / 255); @@ -570,6 +600,11 @@ void Splash::pipeRun(SplashPipe *pipe) { cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] + aDest * cBlend[3])]; break; + case splashPipeResultColorNoAlphaBlendDeviceN: + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] + + aDest * cBlend[cp])]; + break; #endif case splashPipeResultColorAlphaNoBlendMono: @@ -612,6 +647,16 @@ void Splash::pipeRun(SplashPipe *pipe) { aSrc * cSrc[3]) / alphaI]; } break; + case splashPipeResultColorAlphaNoBlendDeviceN: + if (alphaI == 0) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + + aSrc * cSrc[cp]) / alphaI]; + } + break; #endif case splashPipeResultColorAlphaBlendMono: @@ -670,6 +715,18 @@ void Splash::pipeRun(SplashPipe *pipe) { alphaI]; } break; + case splashPipeResultColorAlphaBlendDeviceN: + if (alphaI == 0) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + + aSrc * ((255 - alphaIm1) * cSrc[cp] + + alphaIm1 * cBlend[cp]) / 255) / + alphaI]; + } + break; #endif } @@ -730,6 +787,16 @@ void Splash::pipeRun(SplashPipe *pipe) { } pipe->destColorPtr += 4; break; + case splashModeDeviceN8: + mask = 1; + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = cResult[cp]; + } + mask <<=1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; #endif } if (pipe->destAlphaPtr) { @@ -844,8 +911,25 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) { ++pipe->x; } -#endif +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) { + //----- write destination pixel + int mask = 1; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; + } + mask <<=1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} +#endif // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && @@ -1125,6 +1209,53 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe) { ++pipe->x; } + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr +void Splash::pipeRunAADeviceN8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult[SPOT_NCOMPS+4]; + int cp, mask; + + //----- read destination pixel + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cDest[cp] = pipe->destColorPtr[cp]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] + + aSrc * pipe->cSrc[cp]) / alpha2)]; + } + + //----- write destination pixel + mask = 1; + for (cp=0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = cResult[cp]; + } + mask <<= 1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} #endif inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { @@ -1153,6 +1284,9 @@ inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { case splashModeCMYK8: pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; break; + case splashModeDeviceN8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x]; + break; #endif } if (bitmap->alpha) { @@ -1195,6 +1329,9 @@ inline void Splash::pipeIncX(SplashPipe *pipe) { case splashModeCMYK8: pipe->destColorPtr += 4; break; + case splashModeDeviceN8: + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; #endif } if (pipe->destAlphaPtr) { @@ -1774,6 +1911,17 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) { } } break; + case splashModeDeviceN8: + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *p++ = color[cp]; + } + row += bitmap->rowSize; + } + break; #endif } @@ -3355,7 +3503,7 @@ void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, SplashError Splash::drawImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, GBool srcAlpha, int w, int h, SplashCoord *mat, - GBool tilingPattern) { + GBool tilingPattern) { GBool ok; SplashBitmap *scaledImg; SplashClipResult clipRes; @@ -3396,6 +3544,10 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, ok = srcMode == splashModeCMYK8; nComps = 4; break; + case splashModeDeviceN8: + ok = srcMode == splashModeDeviceN8; + nComps = SPOT_NCOMPS+4; + break; #endif default: ok = gFalse; @@ -3496,7 +3648,7 @@ SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData GBool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat, - GBool tilingPattern) { + GBool tilingPattern) { SplashBitmap *scaledImg; SplashClipResult clipRes, clipRes2; SplashPipe pipe; @@ -3621,7 +3773,7 @@ SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData } scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight); - + if (scaledImg == NULL) { return splashErrBadArg; } @@ -3802,7 +3954,7 @@ SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, int scaledWidth, int scaledHeight) { SplashBitmap *dest; - dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha); + dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList()); if (dest->getDataPtr() != NULL) { if (scaledHeight < srcHeight) { if (scaledWidth < srcWidth) { @@ -3838,6 +3990,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, Guint pix0, pix1, pix2; #if SPLASH_CMYK Guint pix3; + Guint pix[SPOT_NCOMPS+4], cp; #endif Guint alpha; Guchar *destPtr, *destAlphaPtr; @@ -4017,6 +4170,25 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, *destPtr++ = (Guchar)pix2; *destPtr++ = (Guchar)pix3; break; + case splashModeDeviceN8: + + // compute the final pixel + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + pix[cp] = 0; + for (i = 0; i < xStep; ++i) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { + pix[cp] += pixBuf[xx + cp]; + } + xx += (SPOT_NCOMPS+4); + } + // pix / xStep * yStep + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + pix[cp] = (pix[cp] * d) >> 23; + + // store the pixel + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + break; #endif @@ -4168,6 +4340,12 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, *destPtr++ = (Guchar)pix[3]; } break; + case splashModeDeviceN8: + for (i = 0; i < xStep; ++i) { + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + break; #endif } @@ -4311,6 +4489,13 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, *destPtr++ = (Guchar)pix[3]; } break; + case splashModeDeviceN8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + break; #endif } @@ -4459,6 +4644,15 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, } } break; + case splashModeDeviceN8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + } + break; #endif } @@ -4681,6 +4875,10 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, return splashErrModeMismatch; } + if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) { + for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++) + bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy()); + } if (src->alpha) { pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated, @@ -4694,7 +4892,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, alpha = *ap++; // this uses shape instead of alpha, which isn't technically // correct, but works out the same - pipe.shape = alpha; + pipe.shape = alpha; (this->*pipe.run)(&pipe); } } @@ -4712,7 +4910,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, if (state->clip->test(xDest + x, yDest + y)) { // this uses shape instead of alpha, which isn't technically // correct, but works out the same - pipe.shape = alpha; + pipe.shape = alpha; (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); @@ -4763,6 +4961,7 @@ void Splash::compositeBackground(SplashColorPtr color) { Guchar alpha, alpha1, c, color0, color1, color2; #if SPLASH_CMYK Guchar color3; + Guchar colorsp[SPOT_NCOMPS+4], cp; #endif int x, y, mask; @@ -4892,6 +5091,29 @@ void Splash::compositeBackground(SplashColorPtr color) { } } break; + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + colorsp[cp] = color[cp]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) + { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + p[cp] = colorsp[cp]; + } + else if (alpha != 255) + { + alpha1 = 255 - alpha; + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]); + } + p += (SPOT_NCOMPS+4); + } + } + break; #endif } memset(bitmap->alpha, 255, bitmap->width * bitmap->height); @@ -4951,6 +5173,9 @@ GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading) case splashModeCMYK8: colorComps=4; break; + case splashModeDeviceN8: + colorComps=SPOT_NCOMPS+4; + break; #endif } @@ -5289,6 +5514,16 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, } } break; + case splashModeDeviceN8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + (SPOT_NCOMPS+4) * xDest]; + sp = &src->data[(ySrc + y) * src->rowSize + (SPOT_NCOMPS+4) * xSrc]; + for (x = 0; x < w; ++x) { + for (int cp=0; cp < SPOT_NCOMPS+4; cp++) + *p++ = *sp++; + } + } + break; #endif } diff --git a/splash/Splash.h b/splash/Splash.h index f4fb542..223afdd 100644 --- a/splash/Splash.h +++ b/splash/Splash.h @@ -60,6 +60,7 @@ typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine, enum SplashPipeResultColorCtrl { #if SPLASH_CMYK splashPipeResultColorNoAlphaBlendCMYK, + splashPipeResultColorNoAlphaBlendDeviceN, #endif splashPipeResultColorNoAlphaBlendRGB, splashPipeResultColorNoAlphaBlendMono, @@ -67,12 +68,14 @@ enum SplashPipeResultColorCtrl { splashPipeResultColorAlphaNoBlendRGB, #if SPLASH_CMYK splashPipeResultColorAlphaNoBlendCMYK, + splashPipeResultColorAlphaNoBlendDeviceN, #endif splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendRGB #if SPLASH_CMYK , - splashPipeResultColorAlphaBlendCMYK + splashPipeResultColorAlphaBlendCMYK, + splashPipeResultColorAlphaBlendDeviceN #endif }; @@ -285,6 +288,7 @@ private: void pipeRunSimpleBGR8(SplashPipe *pipe); #if SPLASH_CMYK void pipeRunSimpleCMYK8(SplashPipe *pipe); + void pipeRunSimpleDeviceN8(SplashPipe *pipe); #endif void pipeRunAAMono1(SplashPipe *pipe); void pipeRunAAMono8(SplashPipe *pipe); @@ -293,6 +297,7 @@ private: void pipeRunAABGR8(SplashPipe *pipe); #if SPLASH_CMYK void pipeRunAACMYK8(SplashPipe *pipe); + void pipeRunAADeviceN8(SplashPipe *pipe); #endif void pipeSetXY(SplashPipe *pipe, int x, int y); void pipeIncX(SplashPipe *pipe); diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc index cd85543..5fe61a2 100644 --- a/splash/SplashBitmap.cc +++ b/splash/SplashBitmap.cc @@ -45,6 +45,7 @@ #include "goo/PNGWriter.h" #include "goo/TiffWriter.h" #include "goo/ImgWriter.h" +#include "goo/GooList.h" //------------------------------------------------------------------------ // SplashBitmap @@ -52,7 +53,7 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, SplashColorMode modeA, GBool alphaA, - GBool topDown) { + GBool topDown, GooList *separationListA) { width = widthA; height = heightA; mode = modeA; @@ -95,6 +96,13 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, rowSize = -1; } break; + case splashModeDeviceN8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * (SPOT_NCOMPS + 4); + } else { + rowSize = -1; + } + break; #endif } if (rowSize > 0) { @@ -115,11 +123,15 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, } else { alpha = NULL; } + separationList = new GooList(); + if (separationListA != NULL) + for (int i = 0; i < separationListA->getLength(); i++) + separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy()); } SplashBitmap *SplashBitmap::copy(SplashBitmap *src) { SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), - src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0); + src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0, src->getSeparationList()); Guchar *dataSource = src->getDataPtr(); Guchar *dataDest = result->getDataPtr(); int amount = src->getRowSize(); @@ -146,6 +158,7 @@ SplashBitmap::~SplashBitmap() { } } gfree(alpha); + deleteGooList(separationList, GfxSeparationColorSpace); } @@ -234,6 +247,7 @@ SplashError SplashBitmap::writePNMFile(FILE *f) { #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: // PNM doesn't support CMYK error(errInternal, -1, "unsupported SplashBitmap mode"); return splashErrGeneric; @@ -300,6 +314,11 @@ void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { pixel[2] = p[2]; pixel[3] = p[3]; break; + case splashModeDeviceN8: + p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x]; + for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++) + pixel[cp] = p[cp]; + break; #endif } } @@ -386,6 +405,31 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) { m = byteToDbl(col[1]); y = byteToDbl(col[2]); k = byteToDbl(col[3]); +#if SPLASH_CMYK + if (separationList->getLength() > 0) { + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + if (c > 1) c = 1; + if (m > 1) m = 1; + if (y > 1) y = 1; + if (k > 1) k = 1; + } +#endif c1 = 1 - c; m1 = 1 - m; y1 = 1 - y; @@ -397,10 +441,52 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) { } } +#if SPLASH_CMYK +void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) { + SplashColor col; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + if (separationList->getLength() > 0) { + double c, m, y, k; + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + col[0] = dblToByte(clip01(c)); + col[1] = dblToByte(clip01(m)); + col[2] = dblToByte(clip01(y)); + col[3] = dblToByte(clip01(k)); + } + *line++ = col[0]; + *line++ = col[1]; + *line++ = col[2]; + *line++ = col[3]; + } +} +#endif + SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) { if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 #if SPLASH_CMYK - && mode != splashModeCMYK8 + && mode != splashModeCMYK8 && mode != splashModeDeviceN8 #endif ) { error(errInternal, -1, "unsupported SplashBitmap mode"); @@ -440,6 +526,29 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int delete[] row; } break; + case splashModeDeviceN8: + if (writer->supportCMYK()) { + unsigned char *row = new unsigned char[4 * width]; + for (int y = 0; y < height; y++) { + getCMYKLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } else { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + getRGBLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; #endif case splashModeRGB8: { diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h index 5ef5573..0bff205 100644 --- a/splash/SplashBitmap.h +++ b/splash/SplashBitmap.h @@ -34,6 +34,7 @@ #endif #include "SplashTypes.h" +#include "poppler/GfxState.h" #include class ImgWriter; @@ -51,7 +52,7 @@ public: // upside-down, i.e., with the last row first in memory. SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, - GBool topDown = gTrue); + GBool topDown = gTrue, GooList *separationList = NULL); static SplashBitmap *copy(SplashBitmap *src); ~SplashBitmap(); @@ -64,6 +65,7 @@ public: SplashColorMode getMode() { return mode; } SplashColorPtr getDataPtr() { return data; } Guchar *getAlphaPtr() { return alpha; } + GooList *getSeparationList() { return separationList; } SplashError writePNMFile(char *fileName); SplashError writePNMFile(FILE *f); @@ -75,6 +77,9 @@ public: void getPixel(int x, int y, SplashColorPtr pixel); void getRGBLine(int y, SplashColorPtr line); +#if SPLASH_CMYK + void getCMYKLine(int y, SplashColorPtr line); +#endif Guchar getAlpha(int x, int y); // Caller takes ownership of the bitmap data. The SplashBitmap @@ -92,6 +97,7 @@ private: SplashColorPtr data; // pointer to row zero of the color data Guchar *alpha; // pointer to row zero of the alpha data // (always top-down) + GooList *separationList; // list of spot colorants and their mapping functions friend class Splash; }; diff --git a/splash/SplashState.cc b/splash/SplashState.cc index e258f66..fd2789d 100644 --- a/splash/SplashState.cc +++ b/splash/SplashState.cc @@ -40,7 +40,7 @@ int splashColorModeNComps[] = { 1, 1, 3, 3, 4 #if SPLASH_CMYK - ,4 + , 4, 4 + SPOT_NCOMPS #endif }; @@ -80,10 +80,14 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + deviceNTransfer[cp][i] = (Guchar)i; +#endif } overprintMask = 0xffffffff; overprintAdditive = gFalse; @@ -126,10 +130,14 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + deviceNTransfer[cp][i] = (Guchar)i; +#endif } overprintMask = 0xffffffff; overprintAdditive = gFalse; @@ -170,10 +178,14 @@ SplashState::SplashState(SplashState *state) { memcpy(rgbTransferG, state->rgbTransferG, 256); memcpy(rgbTransferB, state->rgbTransferB, 256); memcpy(grayTransfer, state->grayTransfer, 256); +#if SPLASH_CMYK memcpy(cmykTransferC, state->cmykTransferC, 256); memcpy(cmykTransferM, state->cmykTransferM, 256); memcpy(cmykTransferY, state->cmykTransferY, 256); memcpy(cmykTransferK, state->cmykTransferK, 256); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + memcpy(deviceNTransfer[cp], state->deviceNTransfer[cp], 256); +#endif overprintMask = state->overprintMask; overprintAdditive = state->overprintAdditive; next = NULL; @@ -228,16 +240,24 @@ void SplashState::setSoftMask(SplashBitmap *softMaskA) { void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray) { +#if SPLASH_CMYK int i; - memcpy(rgbTransferR, red, 256); - memcpy(rgbTransferG, green, 256); - memcpy(rgbTransferB, blue, 256); - memcpy(grayTransfer, gray, 256); for (i = 0; i < 256; ++i) { cmykTransferC[i] = 255 - rgbTransferR[255 - i]; cmykTransferM[i] = 255 - rgbTransferG[255 - i]; cmykTransferY[i] = 255 - rgbTransferB[255 - i]; cmykTransferK[i] = 255 - grayTransfer[255 - i]; } + for (i = 0; i < 256; ++i) { + deviceNTransfer[0][i] = 255 - rgbTransferR[255 - i]; + deviceNTransfer[1][i] = 255 - rgbTransferG[255 - i]; + deviceNTransfer[2][i] = 255 - rgbTransferB[255 - i]; + deviceNTransfer[3][i] = 255 - grayTransfer[255 - i]; + } +#endif + memcpy(rgbTransferR, red, 256); + memcpy(rgbTransferG, green, 256); + memcpy(rgbTransferB, blue, 256); + memcpy(grayTransfer, gray, 256); } diff --git a/splash/SplashState.h b/splash/SplashState.h index 01e7772..13d5478 100644 --- a/splash/SplashState.h +++ b/splash/SplashState.h @@ -121,10 +121,13 @@ private: rgbTransferG[256], rgbTransferB[256]; Guchar grayTransfer[256]; +#if SPLASH_CMYK Guchar cmykTransferC[256], cmykTransferM[256], cmykTransferY[256], cmykTransferK[256]; + Guchar deviceNTransfer[SPOT_NCOMPS+4][256]; +#endif Guint overprintMask; GBool overprintAdditive; diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h index 65525b1..5a41e4f 100644 --- a/splash/SplashTypes.h +++ b/splash/SplashTypes.h @@ -46,6 +46,12 @@ typedef double SplashCoord; #define splashAASize 4 +#ifdef SPLASH_CMYK +#ifndef SPOT_NCOMPS +#define SPOT_NCOMPS 4 +#endif +#endif + //------------------------------------------------------------------------ // colors //------------------------------------------------------------------------ @@ -62,8 +68,11 @@ enum SplashColorMode { // XBGRXBGR... #if SPLASH_CMYK , - splashModeCMYK8 // 1 byte per component, 4 bytes per pixel: + splashModeCMYK8, // 1 byte per component, 4 bytes per pixel: // CMYKCMYK... + splashModeDeviceN8 // 1 byte per component, + // 4 bytes + n bytes spot colors per pixel: + // CMYKSSSSCMYKSSSS... #endif }; @@ -72,7 +81,11 @@ enum SplashColorMode { extern int splashColorModeNComps[]; // max number of components in any SplashColor +#if SPLASH_CMYK +#define splashMaxColorComps SPOT_NCOMPS+4 +#else #define splashMaxColorComps 4 +#endif typedef Guchar SplashColor[splashMaxColorComps]; typedef Guchar *SplashColorPtr; @@ -93,6 +106,13 @@ static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } + +// DEVICEN8 +static inline Guchar splashDeviceN8C(SplashColorPtr deviceN8) { return deviceN8[0]; } +static inline Guchar splashDeviceN8M(SplashColorPtr deviceN8) { return deviceN8[1]; } +static inline Guchar splashDeviceN8Y(SplashColorPtr deviceN8) { return deviceN8[2]; } +static inline Guchar splashDeviceN8K(SplashColorPtr deviceN8) { return deviceN8[3]; } +static inline Guchar splashDeviceN8S(SplashColorPtr deviceN8, int nSpot) { return deviceN8[4 + nSpot]; } #endif static inline void splashClearColor(SplashColorPtr dest) { @@ -101,6 +121,8 @@ static inline void splashClearColor(SplashColorPtr dest) { dest[2] = 0; #if SPLASH_CMYK dest[3] = 0; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] = 0; #endif } @@ -110,6 +132,8 @@ static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { dest[2] = src[2]; #if SPLASH_CMYK dest[3] = src[3]; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] = src[i]; #endif } @@ -119,6 +143,8 @@ static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { dest[2] ^= src[2]; #if SPLASH_CMYK dest[3] ^= src[3]; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] ^= src[i]; #endif } diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc index 04a0dfb..6495cfd 100644 --- a/utils/pdftoppm.cc +++ b/utils/pdftoppm.cc @@ -353,10 +353,8 @@ int main(int argc, char *argv[]) { #if SPLASH_CMYK if (jpegcmyk || overprint) { globalParams->setOverprintPreview(gTrue); - paperColor[0] = 0; - paperColor[1] = 0; - paperColor[2] = 0; - paperColor[3] = 0; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + paperColor[cp] = 0; } else #endif { @@ -367,7 +365,7 @@ int main(int argc, char *argv[]) { splashOut = new SplashOutputDev(mono ? splashModeMono1 : gray ? splashModeMono8 : #if SPLASH_CMYK - (jpegcmyk || overprint) ? splashModeCMYK8 : + (jpegcmyk || overprint) ? splashModeDeviceN8 : #endif splashModeRGB8, 4, gFalse, paperColor);