diff options
author | Philipp Knechtges <philipp-dev@knechtges.com> | 2020-09-13 19:59:41 +0200 |
---|---|---|
committer | Albert Astals Cid <tsdgeos@yahoo.es> | 2020-11-01 22:10:25 +0000 |
commit | 75abc683868d8933f10128074a4234afaf76e77f (patch) | |
tree | 284313faf16360184824a0eea90d8dbee0abb864 | |
parent | 0c772071baa74b11c66981f768dccf123f431ce1 (diff) |
PSOutputDev: use the DeviceN8 bitmap for rasterization with CMYK-output + overprint
This mostly mimics the pdftoppm behaviour.
-rw-r--r-- | poppler/PSOutputDev.cc | 24 | ||||
-rw-r--r-- | poppler/Stream.cc | 82 | ||||
-rw-r--r-- | poppler/Stream.h | 52 |
3 files changed, 153 insertions, 5 deletions
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index 67ae28fe..e77d0ed6 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -3141,6 +3141,7 @@ bool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, i unsigned char digit; bool isOptimizedGray; bool overprint; + SplashColorMode internalColorFormat; #endif if (!postInitDone) { @@ -3176,13 +3177,25 @@ bool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, i startPage(page->getNum(), state, xref); delete state; + // If we would not rasterize this page, we would emit the overprint code anyway for language level 2 and upwards. + // As such it is safe to assume for a CMYK printer that it would respect the overprint operands. + overprint = globalParams->getOverprintPreview() || (processColorFormat == splashModeCMYK8 && level >= psLevel2); + // set up the SplashOutputDev + internalColorFormat = processColorFormat; if (processColorFormat == splashModeMono8) { numComps = 1; paperColor[0] = 0xff; } else if (processColorFormat == splashModeCMYK8) { numComps = 4; paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; + + // If overprinting is emulated, it is not sufficient to just store the CMYK values in a bitmap. + // All separation channels need to be stored and collapsed at the end. + // Cf. PDF32000_2008 Section 11.7.4.5 and Tables 148, 149 + if (overprint) { + internalColorFormat = splashModeDeviceN8; + } } else if (processColorFormat == splashModeRGB8) { numComps = 3; paperColor[0] = paperColor[1] = paperColor[2] = 0xff; @@ -3192,10 +3205,7 @@ bool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, i numComps = 3; paperColor[0] = paperColor[1] = paperColor[2] = 0xff; } - // If we would not rasterize this page, we would emit the overprint code anyway for language level 2 and upwards. - // As such it is safe to assume for a CMYK printer that it would respect the overprint operands. - overprint = globalParams->getOverprintPreview() || (processColorFormat == splashModeCMYK8 && level >= psLevel2); - splashOut = new SplashOutputDev(processColorFormat, 1, false, paperColor, false, splashThinLineDefault, overprint); + splashOut = new SplashOutputDev(internalColorFormat, 1, false, paperColor, false, splashThinLineDefault, overprint); splashOut->setFontAntialias(rasterAntialias); splashOut->setVectorAntialias(rasterAntialias); # ifdef USE_CMS @@ -3440,7 +3450,11 @@ bool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, i case psLevel3: case psLevel3Sep: p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); - str0 = new MemStream((char *)p, 0, w * h * numComps, Object(objNull)); + if (processColorFormat == splashModeCMYK8 && internalColorFormat != splashModeCMYK8) { + str0 = new SplashBitmapCMYKEncoder(bitmap); + } else { + str0 = new MemStream((char *)p, 0, w * h * numComps, Object(objNull)); + } // Check for a color image that uses only gray if (!getOptimizeColorSpace()) { isOptimizedGray = false; diff --git a/poppler/Stream.cc b/poppler/Stream.cc index 4971e2ed..ab850a91 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -68,6 +68,10 @@ #include "Stream-CCITT.h" #include "CachedFile.h" +#ifdef HAVE_SPLASH +# include "splash/SplashBitmap.h" +#endif + #ifdef ENABLE_LIBJPEG # include "DCTStream.h" #endif @@ -5137,3 +5141,81 @@ bool RGBGrayEncoder::fillBuf() *bufEnd++ = (char)i; return true; } + +//------------------------------------------------------------------------ +// SplashBitmapCMYKEncoder +//------------------------------------------------------------------------ + +#ifdef HAVE_SPLASH +SplashBitmapCMYKEncoder::SplashBitmapCMYKEncoder(SplashBitmap *bitmapA) : bitmap(bitmapA) +{ + width = (size_t)4 * bitmap->getWidth(); + height = bitmap->getHeight(); + buf.resize(width); + bufPtr = width; + curLine = height - 1; +} + +SplashBitmapCMYKEncoder::~SplashBitmapCMYKEncoder() { } + +void SplashBitmapCMYKEncoder::reset() +{ + bufPtr = width; + curLine = height - 1; +} + +int SplashBitmapCMYKEncoder::lookChar() +{ + if (bufPtr >= width && !fillBuf()) { + return EOF; + } + return buf[bufPtr]; +} + +int SplashBitmapCMYKEncoder::getChar() +{ + int ret = lookChar(); + bufPtr++; + return ret; +} + +bool SplashBitmapCMYKEncoder::fillBuf() +{ + if (curLine < 0) { + return false; + } + + if (bufPtr < width) { + return true; + } + + bitmap->getCMYKLine(curLine, &buf[0]); + bufPtr = 0; + curLine--; + return true; +} + +Goffset SplashBitmapCMYKEncoder::getPos() +{ + return (height - 1 - curLine) * width + bufPtr; +} + +void SplashBitmapCMYKEncoder::setPos(Goffset pos, int dir) +{ + // This code is mostly untested! + if (dir < 0) { + curLine = pos / width; + } else { + curLine = height - 1 - pos / width; + } + + bufPtr = width; + fillBuf(); + + if (dir < 0) { + bufPtr = width - 1 - pos % width; + } else { + bufPtr = pos % width; + } +} +#endif diff --git a/poppler/Stream.h b/poppler/Stream.h index c6b363f6..720811ba 100644 --- a/poppler/Stream.h +++ b/poppler/Stream.h @@ -47,6 +47,9 @@ class GooFile; class BaseStream; class CachedFile; +#ifdef HAVE_SPLASH +class SplashBitmap; +#endif //------------------------------------------------------------------------ @@ -1428,4 +1431,53 @@ private: bool fillBuf(); }; +//------------------------------------------------------------------------ +// SplashBitmapCMYKEncoder +// +// This stream helps to condense SplashBitmaps (mostly of DeviceN8 type) into +// pure CMYK colors. In particular for a DeviceN8 bitmap it redacts the spot colorants. +//------------------------------------------------------------------------ + +#ifdef HAVE_SPLASH +class SplashBitmapCMYKEncoder : public Stream +{ +public: + SplashBitmapCMYKEncoder(SplashBitmap *bitmapA); + ~SplashBitmapCMYKEncoder() override; + StreamKind getKind() const override { return strWeird; } + void reset() override; + int getChar() override; + int lookChar() override; + GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } + bool isBinary(bool /*last = true*/) override { return true; } + + // Although we are an encoder, we return false here, since we do not want do be auto-deleted by + // successive streams. + bool isEncoder() override { return false; } + + int getUnfilteredChar() override { return getChar(); } + void unfilteredReset() override { reset(); } + + BaseStream *getBaseStream() override { return nullptr; } + Stream *getUndecodedStream() override { return this; } + + Dict *getDict() override { return nullptr; } + Object *getDictObject() override { return nullptr; } + + Goffset getPos() override; + void setPos(Goffset pos, int dir = 0) override; + +private: + SplashBitmap *bitmap; + size_t width; + int height; + + std::vector<unsigned char> buf; + size_t bufPtr; + int curLine; + + bool fillBuf(); +}; +#endif + #endif |