summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Knechtges <philipp-dev@knechtges.com>2020-09-13 19:59:41 +0200
committerAlbert Astals Cid <tsdgeos@yahoo.es>2020-11-01 22:10:25 +0000
commit75abc683868d8933f10128074a4234afaf76e77f (patch)
tree284313faf16360184824a0eea90d8dbee0abb864
parent0c772071baa74b11c66981f768dccf123f431ce1 (diff)
PSOutputDev: use the DeviceN8 bitmap for rasterization with CMYK-output + overprint
This mostly mimics the pdftoppm behaviour.
-rw-r--r--poppler/PSOutputDev.cc24
-rw-r--r--poppler/Stream.cc82
-rw-r--r--poppler/Stream.h52
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