diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index db06453..1f5bbc2 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,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 @@ -541,6 +545,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 @@ -657,7 +664,7 @@ void Gfx::go(GBool topLevel) { data_p = new ProfileData(); hash->add (cmd_g, data_p); } - + data_p->addElement(timer.getElapsed ()); } } @@ -1229,12 +1236,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 +1264,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 +1299,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) { @@ -1323,6 +1349,11 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) { colorSpace->getDefaultColor(&color); state->setFillColor(&color); out->updateFillColor(state); + if (drawText && colorSpace->getMode() == csPattern) { + colorSpaceText = NULL; + textHaveCSPattern = gTrue; + out->beginTextObject(state); + } } else { error(getPos(), "Bad color space (fill)"); } @@ -1846,7 +1877,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); @@ -1974,7 +2005,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); @@ -2239,14 +2270,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 +3121,35 @@ 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) { out->endTextObject(state); + drawText = gFalse; + if (out->supportTextCSPattern(state) && textHaveCSPattern) { + 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; } //------------------------------------------------------------------------ @@ -3664,6 +3715,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 { @@ -4084,7 +4141,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 +4257,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..e425cc0 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,17 @@ 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 + GBool drawText; // in text drawing + GfxColorSpace *colorSpaceText; // colorspace after text has filled with pattern + GfxColor colorText; // fill color after after text has filled with pattern + GBool maskHaveCSPattern; // in mask drawing and mask has pattern colorspace + GfxResources *res; // resource stack int updateLevel; diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index 0de4840..64b125f 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -18,6 +18,7 @@ // Copyright (C) 2006 Carlos Garcia Campos // Copyright (C) 2006-2008 Albert Astals Cid // Copyright (C) 2009 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 @@ -107,9 +108,9 @@ static const GfxBlendModeInfo gfxBlendModeNames[] = { #define nGfxBlendModeNames \ ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo)))) - + //------------------------------------------------------------------------ -// +// // NB: This must match the GfxColorSpaceMode enum defined in // GfxState.h static char *gfxColorSpaceModeNames[] = { @@ -214,7 +215,7 @@ void GfxColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) { n = getNComps(); for (i = 0; i < length; i++) { - + for (j = 0; j < n; j++) color.c[j] = in[i * n + j] * 256; @@ -311,7 +312,7 @@ int GfxColorSpace::setupColorProfiles() // create transform from XYZ cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - displayProfile, + displayProfile, COLORSPACE_SH(displayPixelType) | CHANNELS_SH(nChannels) | BYTES_SH(1), INTENT_RELATIVE_COLORIMETRIC,0)) == 0) { @@ -452,7 +453,7 @@ void GfxColorSpace::getGrayLine(Guchar *in, unsigned char *out, int length) { n = getNComps(); for (i = 0; i < length; i++) { - + for (j = 0; j < n; j++) color.c[j] = in[i * n + j] * 256; @@ -598,7 +599,7 @@ GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) { // convert CalGray to media XYZ color space // (not multiply by the white point) -void GfxCalGrayColorSpace::getXYZ(GfxColor *color, +void GfxCalGrayColorSpace::getXYZ(GfxColor *color, double *pX, double *pY, double *pZ) { double A; @@ -616,7 +617,7 @@ void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; double X, Y, Z; - + getXYZ(color,&X,&Y,&Z); in[0] = clip01(X); in[1] = clip01(Y); @@ -641,7 +642,7 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; - + in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); @@ -674,12 +675,12 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { double in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; double X, Y, Z; - + getXYZ(color,&X,&Y,&Z); in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); - + XYZ2DisplayTransform->doTransform(in,out,1); cmyk->c = byteToCol(out[0]); cmyk->m = byteToCol(out[1]); @@ -733,9 +734,9 @@ void GfxDeviceRGBColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) { int i; for (i = 0; i < length; i++) { - out[i] = - (in[i * 3 + 0] * 19595 + - in[i * 3 + 1] * 38469 + + out[i] = + (in[i * 3 + 0] * 19595 + + in[i * 3 + 1] * 38469 + in[i * 3 + 2] * 7472) / 65536; } } @@ -892,7 +893,7 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) { } // convert CalRGB to XYZ color space -void GfxCalRGBColorSpace::getXYZ(GfxColor *color, +void GfxCalRGBColorSpace::getXYZ(GfxColor *color, double *pX, double *pY, double *pZ) { double A, B, C; @@ -912,7 +913,7 @@ void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; double X, Y, Z; - + getXYZ(color,&X,&Y,&Z); in[0] = clip01(X); in[1] = clip01(Y); @@ -937,7 +938,7 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; - + in[0] = clip01(X/whiteX); in[1] = clip01(Y/whiteY); in[2] = clip01(Z/whiteZ); @@ -966,7 +967,7 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { double in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; double X, Y, Z; - + getXYZ(color,&X,&Y,&Z); in[0] = clip01(X); in[1] = clip01(Y); @@ -1025,7 +1026,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; - + c = colToDbl(color->c[0]); m = colToDbl(color->c[1]); y = colToDbl(color->c[2]); @@ -1208,7 +1209,7 @@ void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; - + getXYZ(color, &in[0], &in[1], &in[2]); XYZ2DisplayTransform->doTransform(in,out,1); *gray = byteToCol(out[0]); @@ -1223,7 +1224,7 @@ void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { // convert L*a*b* to media XYZ color space // (not multiply by the white point) -void GfxLabColorSpace::getXYZ(GfxColor *color, +void GfxLabColorSpace::getXYZ(GfxColor *color, double *pX, double *pY, double *pZ) { double X, Y, Z; double t1, t2; @@ -1260,7 +1261,7 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) { Guchar out[gfxColorMaxComps]; double in[gfxColorMaxComps]; - + in[0] = clip01(X); in[1] = clip01(Y); in[2] = clip01(Z); @@ -1291,7 +1292,7 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) { double in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; - + getXYZ(color, &in[0], &in[1], &in[2]); XYZ2DisplayTransform->doTransform(in,out,1); cmyk->c = byteToCol(out[0]); @@ -1511,7 +1512,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) { } cs->transform = new GfxColorTransform(transform); if (dcst == PT_RGB) { - // create line transform only when the display is RGB type color space + // create line transform only when the display is RGB type color space if ((transform = cmsCreateTransform(hp, CHANNELS_SH(nCompsA) | BYTES_SH(1),dhp, TYPE_RGB_8,INTENT_RELATIVE_COLORIMETRIC,0)) == 0) { @@ -1535,7 +1536,7 @@ void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { if (transform != 0 && displayPixelType == PT_GRAY) { Guchar in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; - + for (int i = 0;i < nComps;i++) { in[i] = colToByte(color->c[i]); } @@ -1559,7 +1560,7 @@ void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { && (displayProfile == NULL || displayPixelType == PT_RGB)) { Guchar in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; - + for (int i = 0;i < nComps;i++) { in[i] = colToByte(color->c[i]); } @@ -1599,7 +1600,7 @@ void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { if (transform != NULL && displayPixelType == PT_CMYK) { Guchar in[gfxColorMaxComps]; Guchar out[gfxColorMaxComps]; - + for (int i = 0;i < nComps;i++) { in[i] = colToByte(color->c[i]); } @@ -3300,9 +3301,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; @@ -3622,9 +3625,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) { @@ -4114,11 +4119,11 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, mapped = decodeLow[k] + (i * decodeRange[k]) / maxPixel; lookup[k][i] = dblToCol(mapped); byte = (int) (mapped * 255.0 + 0.5); - if (byte < 0) - byte = 0; - else if (byte > 255) - byte = 255; - byte_lookup[i * nComps + k] = byte; + if (byte < 0) + byte = 0; + else if (byte > 255) + byte = 255; + byte_lookup[i * nComps + k] = byte; } } } @@ -4438,7 +4443,7 @@ void GfxPath::curveTo(double x1, double y1, double x2, double y2, if (justMoved) { if (n >= size) { size += 16; - subpaths = (GfxSubpath **) + subpaths = (GfxSubpath **) greallocn(subpaths, size, sizeof(GfxSubpath *)); } subpaths[n] = new GfxSubpath(firstX, firstY); diff --git a/poppler/GfxState.h b/poppler/GfxState.h index ad5fae6..4656ad8 100644 --- a/poppler/GfxState.h +++ b/poppler/GfxState.h @@ -17,6 +17,7 @@ // Copyright (C) 2006, 2007 Jeff Muizelaar // Copyright (C) 2006 Carlos Garcia Campos // Copyright (C) 2009 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 @@ -53,7 +54,7 @@ public: //------------------------------------------------------------------------ // GfxBlendMode //------------------------------------------------------------------------ - + enum GfxBlendMode { gfxBlendNormal, gfxBlendMultiply, @@ -233,7 +234,7 @@ protected: static cmsHPROFILE displayProfile; // display profile static unsigned int displayPixelType; static GfxColorTransform *XYZ2DisplayTransform; - // convert color space signature to cmsColor type + // convert color space signature to cmsColor type static unsigned int getCMSColorSpaceType(icColorSpaceSignature cs); static unsigned int getCMSNChannels(icColorSpaceSignature cs); static cmsHPROFILE loadColorProfile(const char *fileName); diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h index 66b5c38..79a29b8 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,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,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 +245,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/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 diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index 8d4758a..4f4d04d 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; + } + } } } @@ -186,7 +448,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]; } } @@ -194,8 +461,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; + } } } @@ -354,6 +636,16 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: + 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); +/* //~ (0xff - ...) should be clipped cvtRGBToHSV(0xff - (src[0] + src[3]), 0xff - (src[1] + src[3]), @@ -367,6 +659,7 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, blend[1] = 0xff - g; blend[2] = 0xff - b; blend[3] = 0; +*/ break; #endif } @@ -606,7 +899,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 +920,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, font = NULL; needFontUpdate = gFalse; textClipPath = NULL; - + haveCSPattern = gFalse; transpGroupStack = NULL; } @@ -789,7 +1086,7 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) { } void SplashOutputDev::endPage() { - if (colorMode != splashModeMono1) { + if (colorMode != splashModeMono1 && !keepAlphaChannel) { splash->compositeBackground(paperColor); } } @@ -1672,7 +1969,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; @@ -1704,6 +2023,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) { @@ -1714,7 +2037,6 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, if (state->getFillColorSpace()->isNonMarking()) { return; } - ctm = state->getCTM(); mat[0] = ctm[0]; mat[1] = ctm[1]; @@ -1730,13 +2052,31 @@ 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; + } + } } delete imgMaskData.imgStr; @@ -2560,7 +2900,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) { @@ -2722,7 +3062,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..9994361 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; @@ -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. @@ -130,6 +135,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 @@ -150,6 +156,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); @@ -171,7 +183,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 +237,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/Splash.cc b/splash/Splash.cc index c93ef40..c2c74dd 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -347,10 +347,10 @@ inline void Splash::pipeRun(SplashPipe *pipe) { if (state->softMask) { if (pipe->usesShape) { - aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++ - * pipe->shape); + aSrc = (Guchar)splashRound((double) pipe->aInput * (double) *pipe->softMaskPtr++ + * (double)pipe->shape); } else { - aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++); + aSrc = (Guchar)splashRound((double) pipe->aInput * (double) *pipe->softMaskPtr++); } } else if (pipe->usesShape) { // pipe->aInput is premultiplied by 255 in pipeInit @@ -2352,7 +2352,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, // loop-invariant constants k1 = splashRound(xShear * ySign * y); - + // clipping test if (clipRes != splashClipAllInside && !rot && diff --git a/splash/SplashState.cc b/splash/SplashState.cc index 70a79ac..948b076 100644 --- a/splash/SplashState.cc +++ b/splash/SplashState.cc @@ -25,6 +25,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, 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];