diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index 577c482..d2b0c99 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -4553,7 +4553,33 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { delete maskColorMap; goto err1; } - //~ handle the Matte entry + // handle the Matte entry + maskDict->lookup("Matte", &obj1); + if (obj1.isArray() && maskStr->getKind() != strDCT) { + if (obj1.getArray()->getLength() != colorSpace->getNComps()) { + error(errSyntaxError, -1, "Matte entry should have {0:d} components but has {1:d}", + colorSpace->getNComps(), obj1.getArray()->getLength()); + } else if (maskWidth != width || maskHeight != height) { + error(errSyntaxError, -1, "Softmask with matte entry {0:d} x {1:d} must have same geometry as the image {2:d} x {3:d}", + maskWidth, maskHeight, width, height); + } else { + GfxColor matteColor; + for (i = 0; i < colorSpace->getNComps(); i++) { + obj1.getArray()->get(i, &obj2); + if (!obj2.isNum()) { + obj2.free(); + error(errSyntaxError, -1, "Matte entry {0:d} should be a number but it's of type {1:d}", i, obj2.getType()); + + break; + } + matteColor.c[i] = dblToCol(maskColorMap->getDecodeLow(0) + obj2.getNum() * (maskColorMap->getDecodeHigh(0) - maskColorMap->getDecodeLow(0))); + obj2.free(); + } + if (i == colorSpace->getNComps()) { + maskColorMap->setMatteColor(&matteColor); + } + } + } haveSoftMask = gTrue; } else if (maskObj.isArray()) { // color key mask diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index bd3b42d..26bf820 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -5821,6 +5821,7 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, GBool useByteLookup; ok = gTrue; + useMatte = gFalse; // bits per component and color space bits = bitsA; @@ -5983,6 +5984,8 @@ GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { bits = colorMap->bits; nComps = colorMap->nComps; nComps2 = colorMap->nComps2; + useMatte = colorMap->useMatte; + matteColor = colorMap->matteColor; colorSpace2 = NULL; for (k = 0; k < gfxColorMaxComps; ++k) { lookup[k] = NULL; @@ -6570,7 +6573,7 @@ void GfxPath::offset(double dx, double dy) { } //------------------------------------------------------------------------ -// GfxState +// //------------------------------------------------------------------------ GfxState::ReusablePathIterator::ReusablePathIterator(GfxPath *path) : path(path), diff --git a/poppler/GfxState.h b/poppler/GfxState.h index c20438b..eb28486 100644 --- a/poppler/GfxState.h +++ b/poppler/GfxState.h @@ -1194,6 +1194,9 @@ public: void getDeviceN(Guchar *x, GfxColor *deviceN); void getColor(Guchar *x, GfxColor *color); + // Matte color ops + void setMatteColor(GfxColor *color) { useMatte = gTrue; matteColor = *color; } + GfxColor *getMatteColor() { return (useMatte) ? &matteColor : NULL; } private: GfxImageColorMap(GfxImageColorMap *colorMap); @@ -1212,6 +1215,8 @@ private: decodeLow[gfxColorMaxComps]; double // max - min value for each component decodeRange[gfxColorMaxComps]; + GBool useMatte; + GfxColor matteColor; GBool ok; }; diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 7b11279..050c449 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -1760,6 +1760,51 @@ SplashPattern *SplashOutputDev::getColor(GfxColor *deviceN) { } #endif +void SplashOutputDev::getMatteColor(SplashColorMode colorMode, GfxImageColorMap *colorMap, GfxColor *matteColorIn, SplashColor matteColor) { + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; + GfxColor deviceN; +#endif + + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + colorMap->getColorSpace()->getGray(matteColorIn, &gray); + matteColor[0] = colToByte(gray); + break; + case splashModeRGB8: + case splashModeBGR8: + colorMap->getColorSpace()->getRGB(matteColorIn, &rgb); + matteColor[0] = colToByte(rgb.r); + matteColor[1] = colToByte(rgb.g); + matteColor[2] = colToByte(rgb.b); + break; + case splashModeXBGR8: + colorMap->getColorSpace()->getRGB(matteColorIn, &rgb); + matteColor[0] = colToByte(rgb.r); + matteColor[1] = colToByte(rgb.g); + matteColor[2] = colToByte(rgb.b); + matteColor[3] = 255; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + colorMap->getColorSpace()->getCMYK(matteColorIn, &cmyk); + matteColor[0] = colToByte(cmyk.c); + matteColor[1] = colToByte(cmyk.m); + matteColor[2] = colToByte(cmyk.y); + matteColor[3] = colToByte(cmyk.k); + break; + case splashModeDeviceN8: + colorMap->getColorSpace()->getDeviceN(matteColorIn, &deviceN); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + matteColor[cp] = colToByte(deviceN.c[cp]); + break; +#endif + } +} + void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag, int overprintMode, @@ -2899,6 +2944,8 @@ struct SplashOutImageData { int *maskColors; SplashColorMode colorMode; int width, height, y; + ImageStream *maskStr; + SplashColor matteColor; }; #ifdef USE_CMS @@ -2932,6 +2979,11 @@ GBool SplashOutputDev::useIccImageSrc(void *data) { } #endif +// Clip x to lie in [0, 255]. +static inline Guchar clip255(int x) { + return x < 0 ? 0 : x > 255 ? 255 : x; +} + GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, Guchar * /*alphaLine*/) { SplashOutImageData *imgData = (SplashOutImageData *)data; @@ -3075,6 +3127,15 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, } } + if (imgData->maskStr != NULL && (p = imgData->maskStr->getLine()) != NULL) { + int destComps = splashColorModeNComps[imgData->colorMode]; + int convComps = (imgData->colorMode == splashModeXBGR8) ? 3 : destComps; + for (x = 0, q = colorLine; x < imgData->width; ++x, p++, q += destComps) { + for (int cp = 0; cp < convComps; cp++) { + q[cp] = (*p) ? clip255(imgData->matteColor[cp] + (int) (q[cp] - imgData->matteColor[cp]) * 255 / *p) : q[cp]; + } + } + } ++imgData->y; return gTrue; } @@ -3415,6 +3476,7 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, imgData.colorMode = colorMode; imgData.width = width; imgData.height = height; + imgData.maskStr = NULL; imgData.y = 0; // special case for one-channel (monochrome/gray/separation) images: @@ -3879,6 +3941,7 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, imgMaskData.width = maskWidth; imgMaskData.height = maskHeight; imgMaskData.y = 0; + imgMaskData.maskStr = NULL; n = 1 << maskColorMap->getBits(); imgMaskData.lookup = (SplashColorPtr)gmalloc(n); for (i = 0; i < n; ++i) { @@ -3894,7 +3957,6 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, maskSplash->drawImage(&imageSrc, NULL, &imgMaskData, splashModeMono8, gFalse, maskWidth, maskHeight, mat, maskInterpolate); delete imgMaskData.imgStr; - maskStr->close(); gfree(imgMaskData.lookup); delete maskSplash; splash->setSoftMask(maskBitmap); @@ -3910,6 +3972,14 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, imgData.colorMode = colorMode; imgData.width = width; imgData.height = height; + imgData.maskStr = NULL; + if (maskColorMap->getMatteColor() != NULL) { + getMatteColor(colorMode, colorMap, maskColorMap->getMatteColor(), imgData.matteColor); + imgData.maskStr = new ImageStream(maskStr, maskWidth, + maskColorMap->getNumPixelComps(), + maskColorMap->getBits()); + imgData.maskStr->reset(); + } imgData.y = 0; // special case for one-channel (monochrome/gray/separation) images: @@ -3982,7 +4052,9 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, splash->drawImage(&imageSrc, NULL, &imgData, srcMode, gFalse, width, height, mat, interpolate); splash->setSoftMask(NULL); gfree(imgData.lookup); + delete imgData.maskStr; delete imgData.imgStr; + maskStr->close(); str->close(); } diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h index ce4082f..586a4d1 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -379,6 +379,7 @@ private: SplashPattern *getColor(GfxCMYK *cmyk); SplashPattern *getColor(GfxColor *deviceN); #endif + void getMatteColor( SplashColorMode colorMode, GfxImageColorMap *colorMap, GfxColor * matteColor, SplashColor splashMatteColor); void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag, int overprintMode, GfxColor *singleColor, GBool grayIndexed = gFalse); SplashPath *convertPath(GfxState *state, GfxPath *path,