CMakeLists.txt | 1 poppler/Gfx.cc | 135 ++++++++++++--- poppler/Gfx.h | 7 poppler/GfxState.cc | 63 ------- poppler/GfxState_helpers.h | 80 ++++++++ poppler/Makefile.am | 1 poppler/OutputDev.h | 14 + poppler/PSOutputDev.cc | 285 ++++++++++++++++++------------- poppler/PSOutputDev.h | 18 ++ poppler/SplashOutputDev.cc | 404 +++++++++++++++++++++++++++++++++++++-------- poppler/SplashOutputDev.h | 19 ++ splash/SplashState.cc | 17 + splash/SplashTypes.h | 10 + 13 files changed, 798 insertions(+), 256 deletions(-)
New commits: commit 104f9286ceb5fcb5f4795bca7633029142d5f6a4 Author: Thomas Freitag <[email protected]> Date: Tue Jun 2 22:59:42 2009 +0200 Support colorizing text in pattern colorspace This implements commits the final patches for bug 19670 and 19994 Also fixes bugs 15819 and 2807 Also implements blending for SPLASH_CMYK in Splash It's a quite big change but i've done regression testing over my whole pdf suite and did not fit anything that went worse, just improvements Missing the Cairo support diff --git a/CMakeLists.txt b/CMakeLists.txt index 03085a5..9e81b39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,6 +287,7 @@ if(ENABLE_XPDF_HEADERS) poppler/Gfx.h poppler/GfxFont.h poppler/GfxState.h + poppler/GfxState_helpers.h poppler/GlobalParams.h poppler/JArithmeticDecoder.h poppler/JBIG2Stream.h diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index 72b1068..e907850 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -28,6 +28,7 @@ // Copyright (C) 2008 Michael Vrable <[email protected]> // Copyright (C) 2008 Hib Eris <[email protected]> // Copyright (C) 2009 M Joonas Pihlaja <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -498,6 +499,9 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata subPage = gFalse; printCommands = globalParams->getPrintCommands(); profileCommands = globalParams->getProfileCommands(); + textHaveCSPattern = gFalse; + drawText = gFalse; + maskHaveCSPattern = gFalse; mcStack = NULL; // start the resource stack @@ -542,6 +546,9 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA, catalog = catalogA; subPage = gTrue; printCommands = globalParams->getPrintCommands(); + textHaveCSPattern = gFalse; + drawText = gFalse; + maskHaveCSPattern = gFalse; mcStack = NULL; // start the resource stack @@ -1230,12 +1237,32 @@ void Gfx::opSetRenderingIntent(Object args[], int numArgs) { void Gfx::opSetFillGray(Object args[], int numArgs) { GfxColor color; - state->setFillPattern(NULL); - state->setFillColorSpace(new GfxDeviceGrayColorSpace()); - out->updateFillColorSpace(state); - color.c[0] = dblToCol(args[0].getNum()); - state->setFillColor(&color); - out->updateFillColor(state); + if (textHaveCSPattern) { + GBool needFill = out->deviceHasTextClip(state); + out->endTextObject(state); + if (needFill) { + doPatternFill(gTrue); + } + out->restoreState(state); + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + out->updateFillColorSpace(state); + color.c[0] = dblToCol(args[0].getNum()); + state->setFillColor(&color); + out->updateFillColor(state); + out->beginTextObject(state); + out->updateRender(state); + out->updateTextMat(state); + out->updateTextPos(state); + textHaveCSPattern = gFalse; + } else { + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + out->updateFillColorSpace(state); + color.c[0] = dblToCol(args[0].getNum()); + state->setFillColor(&color); + out->updateFillColor(state); + } } void Gfx::opSetStrokeGray(Object args[], int numArgs) { @@ -1253,14 +1280,21 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) { GfxColor color; int i; - state->setFillPattern(NULL); - state->setFillColorSpace(new GfxDeviceCMYKColorSpace()); - out->updateFillColorSpace(state); - for (i = 0; i < 4; ++i) { - color.c[i] = dblToCol(args[i].getNum()); + if (textHaveCSPattern) { + colorSpaceText = new GfxDeviceCMYKColorSpace(); + for (i = 0; i < 4; ++i) { + colorText.c[i] = dblToCol(args[i].getNum()); + } + } else { + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceCMYKColorSpace()); + out->updateFillColorSpace(state); + for (i = 0; i < 4; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setFillColor(&color); + out->updateFillColor(state); } - state->setFillColor(&color); - out->updateFillColor(state); } void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) { @@ -1281,14 +1315,21 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) { GfxColor color; int i; - state->setFillPattern(NULL); - state->setFillColorSpace(new GfxDeviceRGBColorSpace()); - out->updateFillColorSpace(state); - for (i = 0; i < 3; ++i) { - color.c[i] = dblToCol(args[i].getNum()); + if (textHaveCSPattern) { + colorSpaceText = new GfxDeviceRGBColorSpace(); + for (i = 0; i < 3; ++i) { + colorText.c[i] = dblToCol(args[i].getNum()); + } + } else { + state->setFillPattern(NULL); + state->setFillColorSpace(new GfxDeviceRGBColorSpace()); + out->updateFillColorSpace(state); + for (i = 0; i < 3; ++i) { + color.c[i] = dblToCol(args[i].getNum()); + } + state->setFillColor(&color); + out->updateFillColor(state); } - state->setFillColor(&color); - out->updateFillColor(state); } void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) { @@ -1324,6 +1365,24 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) { colorSpace->getDefaultColor(&color); state->setFillColor(&color); out->updateFillColor(state); + if (drawText) { + if (colorSpace->getMode() == csPattern) { + colorSpaceText = NULL; + textHaveCSPattern = gTrue; + out->beginTextObject(state); + } else if (textHaveCSPattern) { + GBool needFill = out->deviceHasTextClip(state); + out->endTextObject(state); + if (needFill) { + doPatternFill(gTrue); + } + out->beginTextObject(state); + out->updateRender(state); + out->updateTextMat(state); + out->updateTextPos(state); + textHaveCSPattern = gFalse; + } + } } else { error(getPos(), "Bad color space (fill)"); } @@ -1847,7 +1906,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); - } else { + } else if (!textHaveCSPattern && !maskHaveCSPattern) { state->clip(); if (eoFill) { out->eoClip(state); @@ -1975,7 +2034,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); - } else { + } else if (!textHaveCSPattern && !maskHaveCSPattern) { state->clip(); if (eoFill) { out->eoClip(state); @@ -3121,15 +3180,38 @@ void Gfx::opEOClip(Object args[], int numArgs) { //------------------------------------------------------------------------ void Gfx::opBeginText(Object args[], int numArgs) { + out->beginTextObject(state); + drawText = gTrue; state->setTextMat(1, 0, 0, 1, 0, 0); state->textMoveTo(0, 0); out->updateTextMat(state); out->updateTextPos(state); fontChanged = gTrue; + if (out->supportTextCSPattern(state)) { + colorSpaceText = NULL; + textHaveCSPattern = gTrue; + } } void Gfx::opEndText(Object args[], int numArgs) { + GBool needFill = out->deviceHasTextClip(state); out->endTextObject(state); + drawText = gFalse; + if (out->supportTextCSPattern(state) && textHaveCSPattern) { + if (needFill) { + doPatternFill(gTrue); + } + out->restoreState(state); + if (colorSpaceText != NULL) { + state->setFillPattern(NULL); + state->setFillColorSpace(colorSpaceText); + out->updateFillColorSpace(state); + state->setFillColor(&colorText); + out->updateFillColor(state); + colorSpaceText = NULL; + } + } + textHaveCSPattern = gFalse; } //------------------------------------------------------------------------ @@ -3170,6 +3252,9 @@ void Gfx::opSetTextLeading(Object args[], int numArgs) { void Gfx::opSetTextRender(Object args[], int numArgs) { state->setRender(args[0].getInt()); + if (args[0].getInt() == 7) { + textHaveCSPattern = gFalse; + } out->updateRender(state); } @@ -3695,6 +3780,12 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { // draw it if (!contentIsHidden()) out->drawImageMask(state, ref, str, width, height, invert, inlineImg); + if (out->fillMaskCSPattern(state)) { + maskHaveCSPattern = gTrue; + doPatternFill(gTrue); + out->endMaskClip(state); + maskHaveCSPattern = gFalse; + } } else { diff --git a/poppler/Gfx.h b/poppler/Gfx.h index a75a92a..e03d025 100644 --- a/poppler/Gfx.h +++ b/poppler/Gfx.h @@ -18,6 +18,7 @@ // Copyright (C) 2008 Brad Hards <[email protected]> // Copyright (C) 2008 Carlos Garcia Campos <[email protected]> // Copyright (C) 2009 Albert Astals Cid <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -33,6 +34,7 @@ #include "goo/gtypes.h" #include "goo/GooList.h" +#include "GfxState.h" #include "Object.h" class GooString; @@ -175,6 +177,11 @@ private: GBool subPage; // is this a sub-page object? GBool printCommands; // print the drawing commands (for debugging) GBool profileCommands; // profile the drawing commands (for debugging) + GBool textHaveCSPattern; // in text drawing and text has pattern colorspace + GBool drawText; // in text drawing + GBool maskHaveCSPattern; // in mask drawing and mask has pattern colorspace + GfxColorSpace *colorSpaceText;// colorspace after text has filled with pattern + GfxColor colorText; // fill color after after text has filled with pattern GfxResources *res; // resource stack int updateLevel; diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index 14c0a3f..d75e015 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -40,19 +40,12 @@ #include "Array.h" #include "Page.h" #include "GfxState.h" +#include "GfxState_helpers.h" #include "GfxFont.h" #include "GlobalParams.h" //------------------------------------------------------------------------ -static inline GfxColorComp clip01(GfxColorComp x) { - return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; -} - -static inline double clip01(double x) { - return (x < 0) ? 0 : (x > 1) ? 1 : x; -} - GBool Matrix::invertTo(Matrix *other) { double det; @@ -1077,7 +1070,7 @@ void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) { } void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double c, m, y, k, c1, m1, y1, k1, r, g, b, x; + double c, m, y, k, c1, m1, y1, k1, r, g, b; c = colToDbl(color->c[0]); m = colToDbl(color->c[1]); @@ -1087,52 +1080,7 @@ void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { m1 = 1 - m; y1 = 1 - y; k1 = 1 - k; - // this is a matrix multiplication, unrolled for performance - // C M Y K - x = c1 * m1 * y1 * k1; // 0 0 0 0 - r = g = b = x; - x = c1 * m1 * y1 * k; // 0 0 0 1 - r += 0.1373 * x; - g += 0.1216 * x; - b += 0.1255 * x; - x = c1 * m1 * y * k1; // 0 0 1 0 - r += x; - g += 0.9490 * x; - x = c1 * m1 * y * k; // 0 0 1 1 - r += 0.1098 * x; - g += 0.1020 * x; - x = c1 * m * y1 * k1; // 0 1 0 0 - r += 0.9255 * x; - b += 0.5490 * x; - x = c1 * m * y1 * k; // 0 1 0 1 - r += 0.1412 * x; - x = c1 * m * y * k1; // 0 1 1 0 - r += 0.9294 * x; - g += 0.1098 * x; - b += 0.1412 * x; - x = c1 * m * y * k; // 0 1 1 1 - r += 0.1333 * x; - x = c * m1 * y1 * k1; // 1 0 0 0 - g += 0.6784 * x; - b += 0.9373 * x; - x = c * m1 * y1 * k; // 1 0 0 1 - g += 0.0588 * x; - b += 0.1412 * x; - x = c * m1 * y * k1; // 1 0 1 0 - g += 0.6510 * x; - b += 0.3137 * x; - x = c * m1 * y * k; // 1 0 1 1 - g += 0.0745 * x; - x = c * m * y1 * k1; // 1 1 0 0 - r += 0.1804 * x; - g += 0.1922 * x; - b += 0.5725 * x; - x = c * m * y1 * k; // 1 1 0 1 - b += 0.0078 * x; - x = c * m * y * k1; // 1 1 1 0 - r += 0.2118 * x; - g += 0.2119 * x; - b += 0.2235 * x; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); rgb->r = clip01(dblToCol(r)); rgb->g = clip01(dblToCol(g)); rgb->b = clip01(dblToCol(b)); diff --git a/poppler/GfxState_helpers.h b/poppler/GfxState_helpers.h new file mode 100644 index 0000000..77ac710 --- /dev/null +++ b/poppler/GfxState_helpers.h @@ -0,0 +1,80 @@ +//======================================================================== +// +// GfxState.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2009 Albert Astals Cid <[email protected]> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +static inline GfxColorComp clip01(GfxColorComp x) { + return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; +} + +static inline double clip01(double x) { + return (x < 0) ? 0 : (x > 1) ? 1 : x; +} + +static inline void cmykToRGBMatrixMultiplication(const double &c, const double &m, const double &y, const double &k, const double &c1, const double &m1, const double &y1, const double &k1, double &r, double &g, double &b) +{ + double x; + // this is a matrix multiplication, unrolled for performance + // C M Y K + x = c1 * m1 * y1 * k1; // 0 0 0 0 + r = g = b = x; + x = c1 * m1 * y1 * k; // 0 0 0 1 + r += 0.1373 * x; + g += 0.1216 * x; + b += 0.1255 * x; + x = c1 * m1 * y * k1; // 0 0 1 0 + r += x; + g += 0.9490 * x; + x = c1 * m1 * y * k; // 0 0 1 1 + r += 0.1098 * x; + g += 0.1020 * x; + x = c1 * m * y1 * k1; // 0 1 0 0 + r += 0.9255 * x; + b += 0.5490 * x; + x = c1 * m * y1 * k; // 0 1 0 1 + r += 0.1412 * x; + x = c1 * m * y * k1; // 0 1 1 0 + r += 0.9294 * x; + g += 0.1098 * x; + b += 0.1412 * x; + x = c1 * m * y * k; // 0 1 1 1 + r += 0.1333 * x; + x = c * m1 * y1 * k1; // 1 0 0 0 + g += 0.6784 * x; + b += 0.9373 * x; + x = c * m1 * y1 * k; // 1 0 0 1 + g += 0.0588 * x; + b += 0.1412 * x; + x = c * m1 * y * k1; // 1 0 1 0 + g += 0.6510 * x; + b += 0.3137 * x; + x = c * m1 * y * k; // 1 0 1 1 + g += 0.0745 * x; + x = c * m * y1 * k1; // 1 1 0 0 + r += 0.1804 * x; + g += 0.1922 * x; + b += 0.5725 * x; + x = c * m * y1 * k; // 1 1 0 1 + b += 0.0078 * x; + x = c * m * y * k1; // 1 1 1 0 + r += 0.2118 * x; + g += 0.2119 * x; + b += 0.2235 * x; +} diff --git a/poppler/Makefile.am b/poppler/Makefile.am index 1c63284..4f0f410 100644 --- a/poppler/Makefile.am +++ b/poppler/Makefile.am @@ -169,6 +169,7 @@ poppler_include_HEADERS = \ Gfx.h \ GfxFont.h \ GfxState.h \ + GfxState_helpers.h \ GlobalParams.h \ JArithmeticDecoder.h \ JBIG2Stream.h \ diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h index 66b5c38..4866631 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -17,6 +17,7 @@ // Copyright (C) 2006 Thorkild Stray <[email protected]> // Copyright (C) 2007 Jeff Muizelaar <[email protected]> // Copyright (C) 2007 Adrian Johnson <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -94,6 +95,17 @@ public: // Does this device need non-text content? virtual GBool needNonText() { return gTrue; } + // If current colorspace ist pattern, + // does this device support text in pattern colorspace? + // Default is false + virtual GBool supportTextCSPattern(GfxState * /*state*/) { return gFalse; } + + // If current colorspace ist pattern, + // need this device special handling for masks in pattern colorspace? + // Default is false + virtual GBool fillMaskCSPattern(GfxState * /*state*/) { return gFalse; } + virtual void endMaskClip(GfxState * /*state*/) {} + //----- initialization and control // Set default transform matrix. @@ -204,6 +216,8 @@ public: double /*dx*/, double /*dy*/, CharCode /*code*/, Unicode * /*u*/, int /*uLen*/); virtual void endType3Char(GfxState * /*state*/) {} + virtual void beginTextObject(GfxState * /*state*/) {} + virtual GBool deviceHasTextClip(GfxState * /*state*/) { return gFalse; } virtual void endTextObject(GfxState * /*state*/) {} //----- image drawing diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index f02bd98..d24e77e 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -20,6 +20,7 @@ // Copyright (C) 2007, 2008 Brad Hards <[email protected]> // Copyright (C) 2008 Koji Otani <[email protected]> // Copyright (C) 2008 Hib Eris <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -493,6 +494,8 @@ static char *prolog[] = { " pdfTextMat dtransform rmoveto } def", "/Tclip { pdfTextClipPath cvx exec clip newpath", " /pdfTextClipPath [] def } def", + "/Tclip* { pdfTextClipPath cvx exec eoclip newpath", + " /pdfTextClipPath [] def } def", "~1ns", "% Level 1 image operators", "~1n", @@ -990,6 +993,7 @@ PSOutputDev::PSOutputDev(const char *fileName, XRef *xrefA, Catalog *catalog, embFontList = NULL; customColors = NULL; haveTextClip = gFalse; + haveCSPattern = gFalse; t3String = NULL; forceRasterize = forceRasterizeA; @@ -1053,6 +1057,7 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, embFontList = NULL; customColors = NULL; haveTextClip = gFalse; + haveCSPattern = gFalse; t3String = NULL; forceRasterize = forceRasterizeA; @@ -2755,6 +2760,9 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { ++col; } } + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } // each line is: "dup nnnnn <~...data...~> put<eol>" // so max data length = 255 - 20 = 235 // chunks are 1 or 4 bytes each, so we have to stop at 232 @@ -3632,6 +3640,10 @@ void PSOutputDev::updateRender(GfxState *state) { int rm; rm = state->getRender(); + if (rm == 7 && haveCSPattern) { + haveCSPattern = gFalse; + restoreState(state); + } writePSFmt("{0:d} Tr\n", rm); rm &= 3; if (rm != 0 && rm != 3) { @@ -4283,34 +4295,71 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) { } } +void PSOutputDev::beginTextObject(GfxState *state) { + if (state->getFillColorSpace()->getMode() == csPattern) { + saveState(state); + haveCSPattern = gTrue; + savedRender = state->getRender(); + state->setRender(7); + writePSFmt("{0:d} Tr\n", 7); + } +} + void PSOutputDev::endTextObject(GfxState *state) { - if (haveTextClip) { + if (haveCSPattern) { + if (haveTextClip) { + writePS("Tclip*\n"); + haveTextClip = gFalse; + state->setRender(savedRender); + if (state->getFillColorSpace()->getMode() != csPattern) { + double cxMin, cyMin, cxMax, cyMax; + state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); + writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re\n", + cxMin, cyMin, + cxMax, cyMax); + writePS("f*\n"); + restoreState(state); + updateFillColor(state); + } + } else { + state->setRender(savedRender); + } + haveCSPattern = gFalse; + } else if (haveTextClip) { writePS("Tclip\n"); haveTextClip = gFalse; } } +void PSOutputDev::endMaskClip(GfxState * state) { + writePS("pdfImClipEnd\n"); +} + void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { int len; len = height * ((width + 7) / 8); - switch (level) { - case psLevel1: - case psLevel1Sep: - doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); - break; - case psLevel2: - case psLevel2Sep: - doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, - NULL, NULL, 0, 0, gFalse); - break; - case psLevel3: - case psLevel3Sep: - doImageL3(ref, NULL, invert, inlineImg, str, width, height, len, - NULL, NULL, 0, 0, gFalse); - break; + if (state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep)) { + maskToClippingPath(str, width, height, invert); + } else { + switch (level) { + case psLevel1: + case psLevel1Sep: + doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, + NULL, NULL, 0, 0, gFalse); + break; + case psLevel3: + case psLevel3Sep: + doImageL3(ref, NULL, invert, inlineImg, str, width, height, len, + NULL, NULL, 0, 0, gFalse); + break; + } } } @@ -4547,6 +4596,110 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, gfree(lineBuf); } +void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { + ImageStream *imgStr; + Guchar *line; + PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut; + int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize; + GBool emitRect, addRect, extendRect; + int i, x0, x1, y, maskXor; + + imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgStr->reset(); + rects0Len = rects1Len = rectsOutLen = 0; + rectsSize = rectsOutSize = 64; + rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); + rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); + rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect)); + maskXor = maskInvert ? 1 : 0; + for (y = 0; y < maskHeight; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + i = 0; + rects1Len = 0; + for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; + for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; + while (x0 < maskWidth || i < rects0Len) { + emitRect = addRect = extendRect = gFalse; + if (x0 >= maskWidth) { + emitRect = gTrue; + } else if (i >= rects0Len) { + addRect = gTrue; + } else if (rects0[i].x0 < x0) { + emitRect = gTrue; + } else if (x0 < rects0[i].x0) { + addRect = gTrue; + } else if (rects0[i].x1 == x1) { + extendRect = gTrue; + } else { + emitRect = addRect = gTrue; + } + if (emitRect) { + if (rectsOutLen == rectsOutSize) { + rectsOutSize *= 2; + rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect)); + } + rectsOut[rectsOutLen].x0 = rects0[i].x0; + rectsOut[rectsOutLen].x1 = rects0[i].x1; + rectsOut[rectsOutLen].y0 = maskHeight - y - 1; + rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; + ++rectsOutLen; + ++i; + } + if (addRect || extendRect) { + if (rects1Len == rectsSize) { + rectsSize *= 2; + rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect)); + rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect)); + } + rects1[rects1Len].x0 = x0; + rects1[rects1Len].x1 = x1; + if (addRect) { + rects1[rects1Len].y0 = y; + } + if (extendRect) { + rects1[rects1Len].y0 = rects0[i].y0; + ++i; + } + ++rects1Len; + for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; + for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; + } + } + rectsTmp = rects0; + rects0 = rects1; + rects1 = rectsTmp; + i = rects0Len; + rects0Len = rects1Len; + rects1Len = i; + } + for (i = 0; i < rects0Len; ++i) { + if (rectsOutLen == rectsOutSize) { + rectsOutSize *= 2; + rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect)); + } + rectsOut[rectsOutLen].x0 = rects0[i].x0; + rectsOut[rectsOutLen].x1 = rects0[i].x1; + rectsOut[rectsOutLen].y0 = maskHeight - y - 1; + rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; + ++rectsOutLen; + } + writePSFmt("{0:d} array 0\n", rectsOutLen * 4); + for (i = 0; i < rectsOutLen; ++i) { + writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n", + rectsOut[i].x0, rectsOut[i].y0, + rectsOut[i].x1 - rectsOut[i].x0, + rectsOut[i].y1 - rectsOut[i].y0); + } + writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight); + gfree(rectsOut); + gfree(rects0); + gfree(rects1); + delete imgStr; + maskStr->close(); +} + void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len, @@ -4713,105 +4866,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, // explicit masking } else if (maskStr) { - imgStr = new ImageStream(maskStr, maskWidth, 1, 1); - imgStr->reset(); - rects0Len = rects1Len = rectsOutLen = 0; - rectsSize = rectsOutSize = 64; - rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); - rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); - rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, - sizeof(PSOutImgClipRect)); - maskXor = maskInvert ? 1 : 0; - for (y = 0; y < maskHeight; ++y) { - if (!(line = imgStr->getLine())) { - break; - } - i = 0; - rects1Len = 0; - for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; - for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; - while (x0 < maskWidth || i < rects0Len) { - emitRect = addRect = extendRect = gFalse; - if (x0 >= maskWidth) { - emitRect = gTrue; - } else if (i >= rects0Len) { - addRect = gTrue; - } else if (rects0[i].x0 < x0) { - emitRect = gTrue; - } else if (x0 < rects0[i].x0) { - addRect = gTrue; - } else if (rects0[i].x1 == x1) { - extendRect = gTrue; - } else { - emitRect = addRect = gTrue; - } - if (emitRect) { - if (rectsOutLen == rectsOutSize) { - rectsOutSize *= 2; - rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, - sizeof(PSOutImgClipRect)); - } - rectsOut[rectsOutLen].x0 = rects0[i].x0; - rectsOut[rectsOutLen].x1 = rects0[i].x1; - rectsOut[rectsOutLen].y0 = maskHeight - y - 1; - rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; - ++rectsOutLen; - ++i; - } - if (addRect || extendRect) { - if (rects1Len == rectsSize) { - rectsSize *= 2; - rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, - sizeof(PSOutImgClipRect)); - rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, - sizeof(PSOutImgClipRect)); - } - rects1[rects1Len].x0 = x0; - rects1[rects1Len].x1 = x1; - if (addRect) { - rects1[rects1Len].y0 = y; - } - if (extendRect) { - rects1[rects1Len].y0 = rects0[i].y0; - ++i; - } - ++rects1Len; - for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; - for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; - } - } - rectsTmp = rects0; - rects0 = rects1; - rects1 = rectsTmp; - i = rects0Len; - rects0Len = rects1Len; - rects1Len = i; - } - for (i = 0; i < rects0Len; ++i) { - if (rectsOutLen == rectsOutSize) { - rectsOutSize *= 2; - rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, - sizeof(PSOutImgClipRect)); - } - rectsOut[rectsOutLen].x0 = rects0[i].x0; - rectsOut[rectsOutLen].x1 = rects0[i].x1; - rectsOut[rectsOutLen].y0 = maskHeight - y - 1; - rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; - ++rectsOutLen; - } - writePSFmt("{0:d} array 0\n", rectsOutLen * 4); - for (i = 0; i < rectsOutLen; ++i) { - writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n", - rectsOut[i].x0, rectsOut[i].y0, - rectsOut[i].x1 - rectsOut[i].x0, - rectsOut[i].y1 - rectsOut[i].y0); - } - writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight); - gfree(rectsOut); - gfree(rects0); - gfree(rects1); - delete imgStr; - maskStr->close(); + maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert); } // color space diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h index e490110..0aea502 100644 --- a/poppler/PSOutputDev.h +++ b/poppler/PSOutputDev.h @@ -17,6 +17,7 @@ // Copyright (C) 2005 Kristian Høgsberg <[email protected]> // Copyright (C) 2006-2008 Albert Astals Cid <[email protected]> // Copyright (C) 2007 Brad Hards <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -33,6 +34,7 @@ #include <poppler-config.h> #include <stddef.h> #include "Object.h" +#include "GfxState.h" #include "GlobalParams.h" #include "OutputDev.h" @@ -125,6 +127,10 @@ public: // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gFalse; } + // This device now supports text in pattern colorspace! + virtual GBool supportTextCSPattern(GfxState *state) + { return state->getFillColorSpace()->getMode() == csPattern; } + //----- header/trailer (used only if manualCtrl is true) // Write the document-level header. @@ -216,6 +222,8 @@ public: //----- text drawing virtual void drawString(GfxState *state, GooString *s); + virtual void beginTextObject(GfxState *state); + virtual GBool deviceHasTextClip(GfxState *state) { return haveTextClip && haveCSPattern; } virtual void endTextObject(GfxState *state); //----- image drawing @@ -230,6 +238,12 @@ public: GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); + // If current colorspace ist pattern, + // need this device special handling for masks in pattern colorspace? + // Default is false + virtual GBool fillMaskCSPattern(GfxState * state) + { return state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep); } + virtual void endMaskClip(GfxState * /*state*/); #if OPI_SUPPORT //----- OPI functions @@ -295,6 +309,7 @@ private: void addProcessColor(double c, double m, double y, double k); void addCustomColor(GfxSeparationColorSpace *sepCS); void doPath(GfxPath *path); + void maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); void doImageL1(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len); @@ -400,6 +415,9 @@ private: GBool haveTextClip; // set if text has been drawn with a // clipping render mode + GBool haveCSPattern; // set if text has been drawn with a + // clipping render mode because of pattern colorspace + int savedRender; // use if pattern colorspace GBool inType3Char; // inside a Type 3 CharProc GooString *t3String; // Type 3 content string diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index ca44682..9341c86 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -20,6 +20,7 @@ // Copyright (C) 2006 Scott Turner <[email protected]> // Copyright (C) 2007 Koji Otani <[email protected]> // Copyright (C) 2009 Petr Gajdos <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -70,6 +71,54 @@ static inline Guchar div255(int x) { return (Guchar)((x + (x >> 8) + 0x80) >> 8); } +#if SPLASH_CMYK + +#include "GfxState_helpers.h" + +//------------------------------------------------------------------------- +// helper for Blend functions (convert CMYK to RGB, do blend, convert back) +//------------------------------------------------------------------------- + +// based in GfxState.cc + +static void cmykToRGB(SplashColorPtr cmyk, SplashColor rgb) { + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + c = colToDbl(byteToCol(cmyk[0])); + m = colToDbl(byteToCol(cmyk[1])); + y = colToDbl(byteToCol(cmyk[2])); + k = colToDbl(byteToCol(cmyk[3])); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + rgb[0] = colToByte(clip01(dblToCol(r))); + rgb[1] = colToByte(clip01(dblToCol(g))); + rgb[2] = colToByte(clip01(dblToCol(b))); +} + +static void rgbToCMYK(SplashColor rgb, SplashColorPtr cmyk) { + GfxColorComp c, m, y, k; + + c = clip01(gfxColorComp1 - byteToCol(rgb[0])); + m = clip01(gfxColorComp1 - byteToCol(rgb[1])); + y = clip01(gfxColorComp1 - byteToCol(rgb[2])); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + cmyk[0] = colToByte(c - k); + cmyk[1] = colToByte(m - k); + cmyk[2] = colToByte(y - k); + cmyk[3] = colToByte(k); +} + +#endif + //------------------------------------------------------------------------ // Blend functions //------------------------------------------------------------------------ @@ -78,8 +127,23 @@ static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = (dest[i] * src[i]) / 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = (rgbDest[i] * rgbSrc[i]) / 255; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = (dest[i] * src[i]) / 255; + } } } @@ -87,8 +151,23 @@ static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = rgbDest[i] + rgbSrc[i] - (rgbDest[i] * rgbSrc[i]) / 255; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255; + } } } @@ -96,10 +175,27 @@ static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] < 0x80 - ? (src[i] * 2 * dest[i]) / 255 - : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = rgbDest[i] < 0x80 + ? (rgbSrc[i] * 2 * rgbDest[i]) / 255 + : 255 - 2 * ((255 - rgbSrc[i]) * (255 - rgbDest[i])) / 255; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < 0x80 + ? (src[i] * 2 * dest[i]) / 255 + : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255; + } } } @@ -107,8 +203,23 @@ static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] < src[i] ? dest[i] : src[i]; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = rgbDest[i] < rgbSrc[i] ? rgbDest[i] : rgbSrc[i]; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? dest[i] : src[i]; + } } } @@ -116,8 +227,23 @@ static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] > src[i] ? dest[i] : src[i]; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = rgbDest[i] > rgbSrc[i] ? rgbDest[i] : rgbSrc[i]; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] > src[i] ? dest[i] : src[i]; + } } } @@ -126,12 +252,32 @@ static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, SplashColorMode cm) { int i, x; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - if (src[i] == 255) { - blend[i] = 255; - } else { - x = (dest[i] * 255) / (255 - src[i]); - blend[i] = x <= 255 ? x : 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + if (rgbSrc[i] == 255) { + rgbBlend[i] = 255; + } else { + x = (rgbDest[i] * 255) / (255 - rgbSrc[i]); + rgbBlend[i] = x <= 255 ? x : 255; + } + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] == 255) { + blend[i] = 255; + } else { + x = (dest[i] * 255) / (255 - src[i]); + blend[i] = x <= 255 ? x : 255; + } } } } @@ -140,12 +286,32 @@ static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i, x; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - if (src[i] == 0) { - blend[i] = 0; - } else { - x = ((255 - dest[i]) * 255) / src[i]; - blend[i] = x <= 255 ? 255 - x : 0; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + if (rgbSrc[i] == 0) { + rgbBlend[i] = 0; + } else { + x = ((255 - rgbDest[i]) * 255) / rgbSrc[i]; + rgbBlend[i] = x <= 255 ? 255 - x : 0; + } + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] == 0) { + blend[i] = 0; + } else { + x = ((255 - dest[i]) * 255) / src[i]; + blend[i] = x <= 255 ? 255 - x : 0; + } } } } @@ -154,10 +320,27 @@ static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = src[i] < 0x80 - ? (dest[i] * 2 * src[i]) / 255 - : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = rgbSrc[i] < 0x80 + ? (rgbDest[i] * 2 * rgbSrc[i]) / 255 + : 255 - 2 * ((255 - rgbDest[i]) * (255 - rgbSrc[i])) / 255; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = src[i] < 0x80 + ? (dest[i] * 2 * src[i]) / 255 + : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255; + } } } @@ -165,18 +348,40 @@ static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i, x; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - if (src[i] < 0x80) { - blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) / - (255 * 255); - } else { - if (dest[i] < 0x40) { - x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255) - + 4 * 255) * dest[i]) / 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + if (rgbSrc[i] < 0x80) { + rgbBlend[i] = rgbDest[i] - (255 - 2 * rgbSrc[i]) * rgbDest[i] * (255 - rgbDest[i]) / (255 * 255); } else { - x = (int)sqrt(255.0 * dest[i]); + if (rgbDest[i] < 0x40) { + x = (((((16 * rgbDest[i] - 12 * 255) * rgbDest[i]) / 255) + 4 * 255) * rgbDest[i]) / 255; + } else { + x = (int)sqrt(255.0 * rgbDest[i]); + } + rgbBlend[i] = rgbDest[i] + (2 * rgbSrc[i] - 255) * (x - rgbDest[i]) / 255; + } + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] < 0x80) { + blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) / (255 * 255); + } else { + if (dest[i] < 0x40) { + x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255) + 4 * 255) * dest[i]) / 255; + } else { + x = (int)sqrt(255.0 * dest[i]); + } + blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255; } - blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255; } } } @@ -187,7 +392,12 @@ static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + blend[i] = dest[i] < src[i] ? 255 - (src[i] - dest[i]) : 255 - (dest[i] - src[i]); + } else { +#endif + blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; } } @@ -195,8 +405,23 @@ static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; - for (i = 0; i < splashColorModeNComps[cm]; ++i) { - blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255; +#ifdef SPLASH_CMYK + if (cm == splashModeCMYK8) { + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + for (i = 0; i < 3; ++i) { + rgbBlend[i] = rgbDest[i] + rgbSrc[i] - (2 * rgbDest[i] * rgbSrc[i]) / 255; + } + rgbToCMYK(rgbBlend, blend); + } else +#endif + { + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255; + } } } @@ -355,19 +580,15 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: - //~ (0xff - ...) should be clipped - cvtRGBToHSV(0xff - (src[0] + src[3]), - 0xff - (src[1] + src[3]), - 0xff - (src[2] + src[3]), &hs, &ss, &vs); - cvtRGBToHSV(0xff - (dest[0] + dest[3]), - 0xff - (dest[1] + dest[3]), - 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); - cvtHSVToRGB(hs, ss, vd, &r, &g, &b); - //~ should do black generation - blend[0] = 0xff - r; - blend[1] = 0xff - g; - blend[2] = 0xff - b; - blend[3] = 0; + SplashColor rgbSrc; + SplashColor rgbDest; + SplashColor rgbBlend; + cmykToRGB(src, rgbSrc); + cmykToRGB(dest, rgbDest); + cvtRGBToHSV(rgbSrc[0], rgbSrc[1], rgbSrc[2], &hs, &ss, &vs); + cvtRGBToHSV(rgbDest[0], rgbDest[1], rgbDest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &rgbBlend[0], &rgbBlend[1], &rgbBlend[2]); + rgbToCMYK(rgbBlend, blend); break; #endif } @@ -607,7 +828,12 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, colorMode != splashModeMono1; setupScreenParams(72.0, 72.0); reverseVideo = reverseVideoA; - splashColorCopy(paperColor, paperColorA); + if (paperColorA != NULL) { + splashColorCopy(paperColor, paperColorA); + } else { + splashClearColor(paperColor); + } + keepAlphaChannel = paperColorA == NULL; xref = NULL; @@ -624,7 +850,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, font = NULL; needFontUpdate = gFalse; textClipPath = NULL; - + haveCSPattern = gFalse; transpGroupStack = NULL; } @@ -791,7 +1017,7 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) { } void SplashOutputDev::endPage() { - if (colorMode != splashModeMono1) { + if (colorMode != splashModeMono1 && !keepAlphaChannel) { splash->compositeBackground(paperColor); } } @@ -982,6 +1208,15 @@ void SplashOutputDev::updateFont(GfxState * /*state*/) { needFontUpdate = gTrue; } +void SplashOutputDev::updateRender(GfxState *state) { + int rm; + rm = state->getRender(); + if (rm == 7 && haveCSPattern) { + haveCSPattern = gFalse; + restoreState(state); + } +} + void SplashOutputDev::doUpdateFont(GfxState *state) { GfxFont *gfxFont; GfxFontType fontType; @@ -1674,7 +1909,29 @@ void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font, splash->fillGlyph(0, 0, &glyph); } +void SplashOutputDev::beginTextObject(GfxState *state) { + if (state->getFillColorSpace()->getMode() == csPattern) { + haveCSPattern = gTrue; + saveState(state); + savedRender = state->getRender(); + state->setRender(7); + } +} + void SplashOutputDev::endTextObject(GfxState *state) { + if (haveCSPattern) { + state->setRender(savedRender); + haveCSPattern = gFalse; + if (state->getFillColorSpace()->getMode() != csPattern) { + if (textClipPath) { + splash->fill(textClipPath, gTrue); + delete textClipPath; + textClipPath = NULL; + } + restoreState(state); + updateFillColor(state); + } + } if (textClipPath) { splash->clipToPath(textClipPath, gFalse); delete textClipPath; @@ -1706,6 +1963,10 @@ GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) { return gTrue; } +void SplashOutputDev::endMaskClip(GfxState * state) { + splash->setSoftMask(NULL); +} + void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { @@ -1732,12 +1993,27 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, imgMaskData.height = height; imgMaskData.y = 0; - splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, - t3GlyphStack != NULL); - if (inlineImg) { - while (imgMaskData.y < height) { - imgMaskData.imgStr->getLine(); - ++imgMaskData.y; + if (state->getFillColorSpace()->getMode() == csPattern) { + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + + maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), 1, splashModeMono8, gFalse); + maskSplash = new Splash(maskBitmap, vectorAntialias); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskColor[0] = 0xff; + maskSplash->setFillPattern(new SplashSolidColor(maskColor)); + maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL); + delete maskSplash; + splash->setSoftMask(maskBitmap); + } else { + splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL); + if (inlineImg) { + while (imgMaskData.y < height) { + imgMaskData.imgStr->getLine(); + ++imgMaskData.y; + } } } @@ -2724,7 +3000,7 @@ void SplashOutputDev::setSoftMask(GfxState * /*state*/, double * /*bbox*/, break; #if SPLASH_CMYK case splashModeCMYK8: - lum = (1 - color[4] / 255.0) + lum = (1 - color[3] / 255.0) - (0.3 / 255.0) * color[0] - (0.59 / 255.0) * color[1] - (0.11 / 255.0) * color[2]; diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h index 02c7f9a..b9a7aad 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -14,6 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2005 Takashi Iwai <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -79,6 +80,10 @@ public: // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gTrue; } + // This device now supports text in pattern colorspace! + virtual GBool supportTextCSPattern(GfxState *state) + { return state->getFillColorSpace()->getMode() == csPattern; } + //----- initialization and control // Start a page. @@ -110,6 +115,7 @@ public: //----- update text state virtual void updateFont(GfxState *state); + virtual void updateRender(GfxState *state); //----- path painting virtual void stroke(GfxState *state); @@ -130,6 +136,8 @@ public: double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state); + virtual void beginTextObject(GfxState *state); + virtual GBool deviceHasTextClip(GfxState *state) { return textClipPath && haveCSPattern; } virtual void endTextObject(GfxState *state); //----- image drawing @@ -150,6 +158,12 @@ public: Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap); + // If current colorspace ist pattern, + // need this device special handling for masks in pattern colorspace? + // Default is false + virtual GBool fillMaskCSPattern(GfxState * state) + { return state->getFillColorSpace()->getMode() == csPattern; } + virtual void endMaskClip(GfxState * /*state*/); //----- Type 3 font operators virtual void type3D0(GfxState *state, double wx, double wy); @@ -225,6 +239,11 @@ private: static GBool maskedImageSrc(void *data, SplashColorPtr line, Guchar *alphaLine); + GBool haveCSPattern; // set if text has been drawn with a + // clipping render mode because of pattern colorspace + int savedRender; // use if pattern colorspace + GBool keepAlphaChannel; // don't fill with paper color, keep alpha channel + SplashColorMode colorMode; int bitmapRowPad; GBool bitmapTopDown; commit d3e4563146cbff4cb507522783e60462461c7524 Author: Thomas Freitag <[email protected]> Date: Sun May 31 23:23:07 2009 +0200 Set memory to 0 after allocation, fixes problems on Sun machines, should not hurt for others diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index 361060c..14c0a3f 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -18,6 +18,7 @@ // Copyright (C) 2006 Carlos Garcia Campos <[email protected]> // Copyright (C) 2006-2009 Albert Astals Cid <[email protected]> // Copyright (C) 2009 Koji Otani <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -3356,9 +3357,11 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, break; } if (nVerticesA == vertSize) { + int oldVertSize = vertSize; vertSize = (vertSize == 0) ? 16 : 2 * vertSize; verticesA = (GfxGouraudVertex *) greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); + memset(verticesA + oldVertSize, 0, (vertSize - oldVertSize) * sizeof(GfxGouraudVertex)); } verticesA[nVerticesA].x = xMin + xMul * (double)x; verticesA[nVerticesA].y = yMin + yMul * (double)y; @@ -3678,9 +3681,11 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, break; } if (nPatchesA == patchesSize) { + int oldPatchesSize = patchesSize; patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; patchesA = (GfxPatch *)greallocn(patchesA, patchesSize, sizeof(GfxPatch)); + memset(patchesA + oldPatchesSize, 0, (patchesSize - oldPatchesSize) * sizeof(GfxPatch)); } p = &patchesA[nPatchesA]; if (typeA == 6) { commit 78a58931b4347ecb505bad5a51104382ef5f91c7 Author: Thomas Freitag <[email protected]> Date: Sun May 31 22:52:23 2009 +0200 Add splashClearColor that assigns white to the given colorptr diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h index ba12a82..a868652 100644 --- a/splash/SplashTypes.h +++ b/splash/SplashTypes.h @@ -13,6 +13,7 @@ // // Copyright (C) 2006 Albert Astals Cid <[email protected]> // Copyright (C) 2008 Tomas Are Haavet <[email protected]> +// Copyright (C) 2009 Thomas Freitag <[email protected]> // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -90,6 +91,15 @@ static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } #endif +static inline void splashClearColor(SplashColorPtr dest) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; +#if SPLASH_CMYK + dest[3] = 0; +#endif +} + static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { dest[0] = src[0]; dest[1] = src[1]; commit 47c26747b32c242ec8ac60e7b93150a67eb22e31 Author: Thomas Freitag <[email protected]> Date: Sun May 31 22:51:22 2009 +0200 Fix splashColorModeNComps to correctly include all values for each SplashColorMode diff --git a/splash/SplashState.cc b/splash/SplashState.cc index 70a79ac..b1fa2f5 100644 --- a/splash/SplashState.cc +++ b/splash/SplashState.cc @@ -4,6 +4,20 @@ // //======================================================================== +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2009 Thomas Freitag <[email protected]> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + #include <config.h> #ifdef USE_GCC_PRAGMAS @@ -25,6 +39,9 @@ // number of components in each color mode int splashColorModeNComps[] = { 1, 1, 3, 3, 4 +#if SPLASH_CMYK + ,4 +#endif }; SplashState::SplashState(int width, int height, GBool vectorAntialias,
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
