diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index db06453..01d8b39 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -27,6 +27,7 @@ // Copyright (C) 2008 Pino Toscano // Copyright (C) 2008 Michael Vrable // Copyright (C) 2008 Hib Eris +// Copyright (C) 2009 Thomas Freitag // // 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 @@ -497,6 +498,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata subPage = gFalse; printCommands = globalParams->getPrintCommands(); profileCommands = globalParams->getProfileCommands(); + textHaveCSPattern = gFalse; mcStack = NULL; // start the resource stack @@ -541,6 +543,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA, catalog = catalogA; subPage = gTrue; printCommands = globalParams->getPrintCommands(); + textHaveCSPattern = gFalse; mcStack = NULL; // start the resource stack @@ -657,7 +660,7 @@ void Gfx::go(GBool topLevel) { data_p = new ProfileData(); hash->add (cmd_g, data_p); } - + data_p->addElement(timer.getElapsed ()); } } @@ -1229,12 +1232,17 @@ 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) { + colorSpaceText = new GfxDeviceGrayColorSpace(); + colorText.c[0] = dblToCol(args[0].getNum()); + } 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) { @@ -1252,14 +1260,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) { @@ -1280,14 +1295,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) { @@ -1846,7 +1868,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); - } else { + } else if (!textHaveCSPattern) { state->clip(); if (eoFill) { out->eoClip(state); @@ -1974,7 +1996,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); - } else { + } else if (!textHaveCSPattern) { state->clip(); if (eoFill) { out->eoClip(state); @@ -2239,14 +2261,14 @@ void Gfx::doFunctionShFill1(GfxFunctionShading *shading, colors2[2] = colorM0; colors2[3] = colorMM; doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1); - + // lower-left sub-rectangle colors2[0] = color0M; colors2[1] = colors[1]; colors2[2] = colorMM; colors2[3] = colorM1; doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1); - + // upper-right sub-rectangle colors2[0] = colorM0; colors2[1] = colorMM; @@ -3090,15 +3112,34 @@ void Gfx::opEOClip(Object args[], int numArgs) { //------------------------------------------------------------------------ void Gfx::opBeginText(Object args[], int numArgs) { + out->beginTextObject(state); state->setTextMat(1, 0, 0, 1, 0, 0); + state->clearTextCorners(); 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) { out->endTextObject(state); + if (out->supportTextCSPattern(state)) { + 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; } //------------------------------------------------------------------------ @@ -4084,7 +4125,7 @@ void Gfx::opBeginImage(Object args[], int numArgs) { // display the image if (str) { doImage(NULL, str, gTrue); - + // skip 'EI' tag c1 = str->getUndecodedStream()->getChar(); c2 = str->getUndecodedStream()->getChar(); @@ -4200,7 +4241,7 @@ GBool Gfx::contentIsHidden() { void Gfx::opBeginMarkedContent(Object args[], int numArgs) { // push a new stack entry pushMarkedContent(); - + OCGs *contentConfig = catalog->getOptContentConfig(); char* name0 = args[0].getName(); if ( strncmp( name0, "OC", 2) == 0 && contentConfig) { diff --git a/poppler/Gfx.h b/poppler/Gfx.h index a75a92a..521115e 100644 --- a/poppler/Gfx.h +++ b/poppler/Gfx.h @@ -18,6 +18,7 @@ // Copyright (C) 2008 Brad Hards // Copyright (C) 2008 Carlos Garcia Campos // Copyright (C) 2009 Albert Astals Cid +// Copyright (C) 2009 Thomas Freitag // // 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; @@ -170,11 +172,14 @@ public: private: XRef *xref; // the xref table for this PDF file - Catalog *catalog; // the Catalog for this PDF file + Catalog *catalog; // the Catalog for this PDF file OutputDev *out; // output device 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 + 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/OutputDev.h b/poppler/OutputDev.h index 66b5c38..07d3a5b 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -17,6 +17,7 @@ // Copyright (C) 2006 Thorkild Stray // Copyright (C) 2007 Jeff Muizelaar // Copyright (C) 2007 Adrian Johnson +// Copyright (C) 2009 Thomas Freitag // // 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,11 @@ 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; } + //----- initialization and control // Set default transform matrix. @@ -204,6 +210,7 @@ public: double /*dx*/, double /*dy*/, CharCode /*code*/, Unicode * /*u*/, int /*uLen*/); virtual void endType3Char(GfxState * /*state*/) {} + virtual void beginTextObject(GfxState * /*state*/) {} virtual void endTextObject(GfxState * /*state*/) {} //----- image drawing @@ -232,8 +239,8 @@ public: virtual void beginMarkedContent(char *name, Dict *properties); virtual void markPoint(char *name); virtual void markPoint(char *name, Dict *properties); - - + + #if OPI_SUPPORT //----- OPI functions diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 8d4758a..32c5335 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -19,6 +19,7 @@ // Copyright (C) 2006 Krzysztof Kowalczyk // Copyright (C) 2006 Scott Turner // Copyright (C) 2007 Koji Otani +// Copyright (C) 2009 Thomas Freitag // // 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 @@ -69,6 +70,107 @@ static inline Guchar div255(int x) { return (Guchar)((x + (x >> 8) + 0x80) >> 8); } +#if SPLASH_CMYK + +//------------------------------------------------------------------------- +// helper for Blend functions (convert CMYK to RGB, do blend, convert back) +//------------------------------------------------------------------------- + +// based in GfxState.cc + + +static GfxColorComp clip01(GfxColorComp x) { + return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; +} + +static double clip01(double x) { + return (x < 0) ? 0 : (x > 1) ? 1 : x; +} + +static void cmykToRGB(SplashColorPtr cmyk, SplashColor rgb) { + double c, m, y, k, c1, m1, y1, k1, r, g, b, x; + + 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; + // 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; + 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 //------------------------------------------------------------------------ @@ -77,8 +179,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; + } } } @@ -86,8 +203,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; + } } } @@ -95,10 +227,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; + } } } @@ -106,8 +255,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]; + } } } @@ -115,8 +279,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]; + } } } @@ -125,13 +304,33 @@ 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; + } + } } } @@ -139,13 +338,33 @@ 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; + } + } } } @@ -153,10 +372,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; + } } } @@ -164,19 +400,45 @@ 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; - } else { - x = (int)sqrt(255.0 * dest[i]); - } - blend[i] = dest[i] + (2 * src[i] - 255) * (x - 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 { + 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; + } + } } } @@ -194,8 +456,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; + } } } @@ -606,7 +883,11 @@ 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; @@ -623,7 +904,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, font = NULL; needFontUpdate = gFalse; textClipPath = NULL; - + haveCSPattern = gFalse; transpGroupStack = NULL; } @@ -789,7 +1070,7 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) { } void SplashOutputDev::endPage() { - if (colorMode != splashModeMono1) { + if (colorMode != splashModeMono1 && !keepAlphaChannel) { splash->compositeBackground(paperColor); } } @@ -1672,7 +1953,24 @@ 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) { + restoreState(state); + updateFillColor(state); + } + } if (textClipPath) { splash->clipToPath(textClipPath, gFalse); delete textClipPath; @@ -2560,7 +2858,7 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, // create the temporary bitmap bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue, - bitmapTopDown); + bitmapTopDown); splash = new Splash(bitmap, vectorAntialias, transpGroup->origSplash->getScreen()); if (isolated) { @@ -2598,6 +2896,11 @@ void SplashOutputDev::endTransparencyGroup(GfxState *state) { double *ctm; // restore state +#ifdef _DEBUG + GBool endPaint = gFalse; + if (endPaint) + throw new EndPaintException(); +#endif delete splash; bitmap = transpGroupStack->origBitmap; splash = transpGroupStack->origSplash; @@ -2617,12 +2920,28 @@ void SplashOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bb tBitmap = transpGroupStack->tBitmap; isolated = transpGroupStack->isolated; +#ifdef _DEBUG + GBool showOrigBitmap = gFalse; + if (showOrigBitmap) + throw new EndPaintException(); + GBool showTBitmap = gFalse; + if (showTBitmap) { + bitmap = tBitmap; + throw new EndPaintException(); + } +#endif + // paint the transparency group onto the parent bitmap // - the clip path was set in the parent's state) splash->composite(tBitmap, 0, 0, tx, ty, tBitmap->getWidth(), tBitmap->getHeight(), gFalse, !isolated); +#ifdef _DEBUG + GBool endPaint = gFalse; + if (endPaint) + throw new EndPaintException(); +#endif // pop the stack transpGroup = transpGroupStack; transpGroupStack = transpGroup->next; @@ -2722,7 +3041,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..941e35e 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -14,6 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2005 Takashi Iwai +// Copyright (C) 2009 Thomas Freitag // // 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 @@ -30,8 +31,8 @@ #include "goo/gtypes.h" #include "splash/SplashTypes.h" #include "poppler-config.h" -#include "OutputDev.h" -#include "GfxState.h" +#include "poppler/OutputDev.h" +#include "poppler/GfxState.h" class Gfx8BitFont; class SplashBitmap; @@ -45,6 +46,14 @@ struct T3FontCacheTag; struct T3GlyphStack; struct SplashTransparencyGroup; +#ifdef _DEBUG +class EndPaintException +{ +public: + EndPaintException() {} +}; +#endif + //------------------------------------------------------------------------ // number of Type 3 fonts to cache @@ -79,6 +88,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. @@ -130,6 +143,7 @@ public: double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state); + virtual void beginTextObject(GfxState *state); virtual void endTextObject(GfxState *state); //----- image drawing @@ -171,7 +185,7 @@ public: // Called to indicate that a new PDF document has been loaded. void startDoc(XRef *xrefA); - + void setPaperColor(SplashColorPtr paperColorA); GBool isReverseVideo() { return reverseVideo; } @@ -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; 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 // Copyright (C) 2008 Tomas Are Haavet +// Copyright (C) 2009 Thomas Freitag // // 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];