diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index 9477762..3c761c2 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -20,6 +20,7 @@ // Copyright (C) 2007, 2008 Brad Hards // Copyright (C) 2008 Koji Otani // 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 @@ -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; @@ -4283,34 +4288,68 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) { } } +void PSOutputDev::beginTextObject(GfxState *state) { + if (state->getFillColorSpace()->getMode() == csPattern) { + saveState(state); + haveTextClip = gTrue; + haveCSPattern = gTrue; + savedRender = state->getRender(); + state->setRender(7); + updateRender(state); + } +} + void PSOutputDev::endTextObject(GfxState *state) { - if (haveTextClip) { + if (haveCSPattern) { + writePS("Tclip*\n"); + haveTextClip = gFalse; + state->setRender(savedRender); + haveCSPattern = gFalse; + 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 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 +4586,115 @@ 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 +4861,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 @@ -4899,7 +4949,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, colorMap ? colorMap->getBits() : 1); } - // decode + // decode if (colorMap) { writePS(" /Decode ["); if ((level == psLevel2Sep || level == psLevel3Sep) && @@ -5192,7 +5242,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap, colorMap ? colorMap->getBits() : 1); } - // decode + // decode if (colorMap) { writePS(" /Decode ["); if ((level == psLevel2Sep || level == psLevel3Sep) && diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h index e490110..ea9ce05 100644 --- a/poppler/PSOutputDev.h +++ b/poppler/PSOutputDev.h @@ -17,6 +17,7 @@ // Copyright (C) 2005 Kristian Høgsberg // Copyright (C) 2006-2008 Albert Astals Cid // Copyright (C) 2007 Brad Hards +// 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 @@ -125,6 +126,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 +221,7 @@ public: //----- text drawing virtual void drawString(GfxState *state, GooString *s); + virtual void beginTextObject(GfxState *state); virtual void endTextObject(GfxState *state); //----- image drawing @@ -230,6 +236,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 +307,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 +413,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