diff options
author | Thomas Freitag <Thomas.Freitag@alfa.de> | 2012-09-11 23:33:25 +0200 |
---|---|---|
committer | Albert Astals Cid <aacid@kde.org> | 2012-09-11 23:33:25 +0200 |
commit | 2e77799a1668f949612f551425d0665c59ff1d93 (patch) | |
tree | 9a7b935adf3de6016bda6e8e0d7835419e11b6db /splash | |
parent | cb2ed646c4ef4161e443ee0a377d1111b3be28ff (diff) |
Splash: Implement DeviceN support
Bug #53140
Some copying from the bug tracker
To explain
it a little bit more I copy a few lines from "Patch 8.01 — DeviceN Support (6
colors)" of the Ghent PDF workgroup:
"This patch tests the DeviceN capabilities of a workflow. If DeviceN is not
handled correctly the colors are converted to CMYK. Instead of the check marks
an X will appear in the lower left corner of each image and in the gradient.
In addition you could inspect the color separations. The objects should appear
only in the Black, Pantone 265C and GWG Green separations as indicated in the
captions."
Without the patch all DeviceN colors are immediately converted to CMYK (with
SPLASH_CMYK). This leads especially to problems, if overprint is used: in
overprint mode a CMYK color will knockout the underlying CMYK components, BUT
neither any spot colors. But if underlying spot colors are immediately
converted to CMYK colors, they will be kocked out then, too!
The patch now spends up to four (or up to SPOT_NCOMPS) additional spot colors
in the splash bitmap, so the order in the bitmap will be
CMYKSTUVCMYKSTUVCMYKSTUV... where S, T, U, V are spot colors (I would use
S1,S2, S3, S4 if it's possible to use indexes), and all painting operations are
done now in this new device. Only at the end, when we want to store the bitmap
in a CMYK or RGB color, the spot colors are converted and their alternate CMYK
components are added to the normal CMYK components.
According to the PDF spec are PDF writer should use different spot color names
if they have a different appearance in their alternate CMYK colorspace.
"hasDifferntResultSet" (sorry for the typo) proofs that: if the same spot color
name is reused BUT has a different appearance in the alternate colorspace, it
will be converted immediately to its alternate colorspace.
"createMapping" is used so that getDeviceN (color) returns the components in
the correct order according their appearance in the splash bitmap, i.e. the
fourth detected spot color must be placed in index 7 of the color array.
updateFill- and updateStrokeColorspace are needed to create this mapping at the
appropriate place. And they are not called once but everytime the colorspace
changed in the PDF (but of course only once in Gfx).
The GooList *getSeparationList() is used to store the functions for converting
the spot colors to their alternate colorspace in order of their appearance in
the splash bitmap. The functions are needed to compare if a spot color with the
same name has really the same appearance and at the end when the splash bitmap
has to be converted to a CMYK or RGB bitmap (s. ahead).
deviceNTransfer is needed simular to rgbTransferX or cmykTransferX if a
transfer function is specified in the ExtGState and splash uses the DeviceN8.
"Do we really need splashModeDeviceN8?": Do we really need splashModeXBGR8? But
kidding aside: splashModeDeviceN8 needs four more components than
splashModeCMYK8, so the bitmap size in memory doubles the size of a pure CMYK
bitmap, and it is only needed if the PDF uses spot colors. So I think it's a
good idea to spend an additional mode and let it up to the calling application
and the cirumstances if it wants to use this new mode or not.
Diffstat (limited to 'splash')
-rw-r--r-- | splash/Splash.cc | 255 | ||||
-rw-r--r-- | splash/Splash.h | 7 | ||||
-rw-r--r-- | splash/SplashBitmap.cc | 115 | ||||
-rw-r--r-- | splash/SplashBitmap.h | 8 | ||||
-rw-r--r-- | splash/SplashState.cc | 30 | ||||
-rw-r--r-- | splash/SplashState.h | 3 | ||||
-rw-r--r-- | splash/SplashTypes.h | 30 |
7 files changed, 426 insertions, 22 deletions
diff --git a/splash/Splash.cc b/splash/Splash.cc index e6559f48..e46a4965 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -36,6 +36,7 @@ #include <math.h> #include "goo/gmem.h" #include "goo/GooLikely.h" +#include "goo/GooList.h" #include "poppler/Error.h" #include "SplashErrorCodes.h" #include "SplashMath.h" @@ -170,7 +171,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { splashPipeResultColorNoAlphaBlendRGB #if SPLASH_CMYK , - splashPipeResultColorNoAlphaBlendCMYK + splashPipeResultColorNoAlphaBlendCMYK, + splashPipeResultColorNoAlphaBlendDeviceN #endif }; @@ -182,7 +184,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { splashPipeResultColorAlphaNoBlendRGB #if SPLASH_CMYK , - splashPipeResultColorAlphaNoBlendCMYK + splashPipeResultColorAlphaNoBlendCMYK, + splashPipeResultColorAlphaNoBlendDeviceN #endif }; @@ -194,7 +197,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { splashPipeResultColorAlphaBlendRGB #if SPLASH_CMYK , - splashPipeResultColorAlphaBlendCMYK + splashPipeResultColorAlphaBlendCMYK, + splashPipeResultColorAlphaBlendDeviceN #endif }; @@ -307,6 +311,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, #if SPLASH_CMYK } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleCMYK8; + } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunSimpleDeviceN8; #endif } } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && @@ -326,6 +332,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, #if SPLASH_CMYK } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAACMYK8; + } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { + pipe->run = &Splash::pipeRunAADeviceN8; #endif } } @@ -338,6 +346,10 @@ void Splash::pipeRun(SplashPipe *pipe) { SplashColorPtr cSrc; Guchar cResult0, cResult1, cResult2, cResult3; int t; +#if SPLASH_CMYK + int cp, mask; + Guchar cResult[SPOT_NCOMPS+4]; +#endif //----- source color @@ -412,6 +424,16 @@ void Splash::pipeRun(SplashPipe *pipe) { } pipe->destColorPtr += 4; break; + case splashModeDeviceN8: + mask = 1; + for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; + } + mask <<= 1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; #endif } if (pipe->destAlphaPtr) { @@ -452,6 +474,10 @@ void Splash::pipeRun(SplashPipe *pipe) { cDest[2] = pipe->destColorPtr[2]; cDest[3] = pipe->destColorPtr[3]; break; + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS + 4; cp++) + cDest[cp] = pipe->destColorPtr[cp]; + break; #endif } if (pipe->destAlphaPtr) { @@ -489,6 +515,10 @@ void Splash::pipeRun(SplashPipe *pipe) { t = (aDest * 255) / pipe->shape - aDest; switch (bitmap->mode) { #if SPLASH_CMYK + case splashModeDeviceN8: + for (cp = 4; cp < SPOT_NCOMPS + 4; cp++) + cSrcNonIso[cp] = clip255(pipe->cSrc[cp] + + ((pipe->cSrc[cp] - cDest[cp]) * t) / 255); case splashModeCMYK8: cSrcNonIso[3] = clip255(pipe->cSrc[3] + ((pipe->cSrc[3] - cDest[3]) * t) / 255); @@ -570,6 +600,11 @@ void Splash::pipeRun(SplashPipe *pipe) { cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] + aDest * cBlend[3])]; break; + case splashPipeResultColorNoAlphaBlendDeviceN: + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] + + aDest * cBlend[cp])]; + break; #endif case splashPipeResultColorAlphaNoBlendMono: @@ -612,6 +647,16 @@ void Splash::pipeRun(SplashPipe *pipe) { aSrc * cSrc[3]) / alphaI]; } break; + case splashPipeResultColorAlphaNoBlendDeviceN: + if (alphaI == 0) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + + aSrc * cSrc[cp]) / alphaI]; + } + break; #endif case splashPipeResultColorAlphaBlendMono: @@ -670,6 +715,18 @@ void Splash::pipeRun(SplashPipe *pipe) { alphaI]; } break; + case splashPipeResultColorAlphaBlendDeviceN: + if (alphaI == 0) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] + + aSrc * ((255 - alphaIm1) * cSrc[cp] + + alphaIm1 * cBlend[cp]) / 255) / + alphaI]; + } + break; #endif } @@ -730,6 +787,16 @@ void Splash::pipeRun(SplashPipe *pipe) { } pipe->destColorPtr += 4; break; + case splashModeDeviceN8: + mask = 1; + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = cResult[cp]; + } + mask <<=1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; #endif } if (pipe->destAlphaPtr) { @@ -844,8 +911,25 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) { ++pipe->x; } -#endif +// special case: +// !pipe->pattern && pipe->noTransparency && !state->blendFunc && +// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) { +void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) { + //----- write destination pixel + int mask = 1; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]]; + } + mask <<=1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + *pipe->destAlphaPtr++ = 255; + + ++pipe->x; +} +#endif // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && @@ -1125,6 +1209,53 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe) { ++pipe->x; } + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr +void Splash::pipeRunAADeviceN8(SplashPipe *pipe) { + Guchar aSrc, aDest, alpha2, aResult; + SplashColor cDest; + Guchar cResult[SPOT_NCOMPS+4]; + int cp, mask; + + //----- read destination pixel + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cDest[cp] = pipe->destColorPtr[cp]; + aDest = *pipe->destAlphaPtr; + + //----- source alpha + aSrc = div255(pipe->aInput * pipe->shape); + + //----- result alpha and non-isolated group element correction + aResult = aSrc + aDest - div255(aSrc * aDest); + alpha2 = aResult; + + //----- result color + if (alpha2 == 0) { + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = 0; + } else { + for (cp=0; cp < SPOT_NCOMPS+4; cp++) + cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] + + aSrc * pipe->cSrc[cp]) / alpha2)]; + } + + //----- write destination pixel + mask = 1; + for (cp=0; cp < SPOT_NCOMPS+4; cp++) { + if (state->overprintMask & mask) { + pipe->destColorPtr[cp] = cResult[cp]; + } + mask <<= 1; + } + pipe->destColorPtr += (SPOT_NCOMPS+4); + *pipe->destAlphaPtr++ = aResult; + + ++pipe->x; +} #endif inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { @@ -1153,6 +1284,9 @@ inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { case splashModeCMYK8: pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; break; + case splashModeDeviceN8: + pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x]; + break; #endif } if (bitmap->alpha) { @@ -1195,6 +1329,9 @@ inline void Splash::pipeIncX(SplashPipe *pipe) { case splashModeCMYK8: pipe->destColorPtr += 4; break; + case splashModeDeviceN8: + pipe->destColorPtr += (SPOT_NCOMPS+4); + break; #endif } if (pipe->destAlphaPtr) { @@ -1774,6 +1911,17 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) { } } break; + case splashModeDeviceN8: + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *p++ = color[cp]; + } + row += bitmap->rowSize; + } + break; #endif } @@ -3355,7 +3503,7 @@ void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, SplashError Splash::drawImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, GBool srcAlpha, int w, int h, SplashCoord *mat, - GBool tilingPattern) { + GBool tilingPattern) { GBool ok; SplashBitmap *scaledImg; SplashClipResult clipRes; @@ -3396,6 +3544,10 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, ok = srcMode == splashModeCMYK8; nComps = 4; break; + case splashModeDeviceN8: + ok = srcMode == splashModeDeviceN8; + nComps = SPOT_NCOMPS+4; + break; #endif default: ok = gFalse; @@ -3496,7 +3648,7 @@ SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData GBool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat, - GBool tilingPattern) { + GBool tilingPattern) { SplashBitmap *scaledImg; SplashClipResult clipRes, clipRes2; SplashPipe pipe; @@ -3621,7 +3773,7 @@ SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData } scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight); - + if (scaledImg == NULL) { return splashErrBadArg; } @@ -3802,7 +3954,7 @@ SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, int scaledWidth, int scaledHeight) { SplashBitmap *dest; - dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha); + dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList()); if (dest->getDataPtr() != NULL) { if (scaledHeight < srcHeight) { if (scaledWidth < srcWidth) { @@ -3838,6 +3990,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, Guint pix0, pix1, pix2; #if SPLASH_CMYK Guint pix3; + Guint pix[SPOT_NCOMPS+4], cp; #endif Guint alpha; Guchar *destPtr, *destAlphaPtr; @@ -4017,6 +4170,25 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, *destPtr++ = (Guchar)pix2; *destPtr++ = (Guchar)pix3; break; + case splashModeDeviceN8: + + // compute the final pixel + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + pix[cp] = 0; + for (i = 0; i < xStep; ++i) { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) { + pix[cp] += pixBuf[xx + cp]; + } + xx += (SPOT_NCOMPS+4); + } + // pix / xStep * yStep + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + pix[cp] = (pix[cp] * d) >> 23; + + // store the pixel + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + break; #endif @@ -4168,6 +4340,12 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, *destPtr++ = (Guchar)pix[3]; } break; + case splashModeDeviceN8: + for (i = 0; i < xStep; ++i) { + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + break; #endif } @@ -4311,6 +4489,13 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, *destPtr++ = (Guchar)pix[3]; } break; + case splashModeDeviceN8: + for (i = 0; i < yStep; ++i) { + destPtr = destPtr0 + (i * scaledWidth + x) * nComps; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + break; #endif } @@ -4459,6 +4644,15 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, } } break; + case splashModeDeviceN8: + for (i = 0; i < yStep; ++i) { + for (j = 0; j < xStep; ++j) { + destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + } + } + break; #endif } @@ -4681,6 +4875,10 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, return splashErrModeMismatch; } + if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) { + for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++) + bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy()); + } if (src->alpha) { pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated, @@ -4694,7 +4892,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, alpha = *ap++; // this uses shape instead of alpha, which isn't technically // correct, but works out the same - pipe.shape = alpha; + pipe.shape = alpha; (this->*pipe.run)(&pipe); } } @@ -4712,7 +4910,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, if (state->clip->test(xDest + x, yDest + y)) { // this uses shape instead of alpha, which isn't technically // correct, but works out the same - pipe.shape = alpha; + pipe.shape = alpha; (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); @@ -4763,6 +4961,7 @@ void Splash::compositeBackground(SplashColorPtr color) { Guchar alpha, alpha1, c, color0, color1, color2; #if SPLASH_CMYK Guchar color3; + Guchar colorsp[SPOT_NCOMPS+4], cp; #endif int x, y, mask; @@ -4892,6 +5091,29 @@ void Splash::compositeBackground(SplashColorPtr color) { } } break; + case splashModeDeviceN8: + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + colorsp[cp] = color[cp]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->width]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) + { + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + p[cp] = colorsp[cp]; + } + else if (alpha != 255) + { + alpha1 = 255 - alpha; + for (cp = 0; cp < SPOT_NCOMPS+4; cp++) + p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]); + } + p += (SPOT_NCOMPS+4); + } + } + break; #endif } memset(bitmap->alpha, 255, bitmap->width * bitmap->height); @@ -4951,6 +5173,9 @@ GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading) case splashModeCMYK8: colorComps=4; break; + case splashModeDeviceN8: + colorComps=SPOT_NCOMPS+4; + break; #endif } @@ -5289,6 +5514,16 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, } } break; + case splashModeDeviceN8: + for (y = 0; y < h; ++y) { + p = &bitmap->data[(yDest + y) * bitmap->rowSize + (SPOT_NCOMPS+4) * xDest]; + sp = &src->data[(ySrc + y) * src->rowSize + (SPOT_NCOMPS+4) * xSrc]; + for (x = 0; x < w; ++x) { + for (int cp=0; cp < SPOT_NCOMPS+4; cp++) + *p++ = *sp++; + } + } + break; #endif } diff --git a/splash/Splash.h b/splash/Splash.h index f4fb5429..223afdd0 100644 --- a/splash/Splash.h +++ b/splash/Splash.h @@ -60,6 +60,7 @@ typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine, enum SplashPipeResultColorCtrl { #if SPLASH_CMYK splashPipeResultColorNoAlphaBlendCMYK, + splashPipeResultColorNoAlphaBlendDeviceN, #endif splashPipeResultColorNoAlphaBlendRGB, splashPipeResultColorNoAlphaBlendMono, @@ -67,12 +68,14 @@ enum SplashPipeResultColorCtrl { splashPipeResultColorAlphaNoBlendRGB, #if SPLASH_CMYK splashPipeResultColorAlphaNoBlendCMYK, + splashPipeResultColorAlphaNoBlendDeviceN, #endif splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendRGB #if SPLASH_CMYK , - splashPipeResultColorAlphaBlendCMYK + splashPipeResultColorAlphaBlendCMYK, + splashPipeResultColorAlphaBlendDeviceN #endif }; @@ -285,6 +288,7 @@ private: void pipeRunSimpleBGR8(SplashPipe *pipe); #if SPLASH_CMYK void pipeRunSimpleCMYK8(SplashPipe *pipe); + void pipeRunSimpleDeviceN8(SplashPipe *pipe); #endif void pipeRunAAMono1(SplashPipe *pipe); void pipeRunAAMono8(SplashPipe *pipe); @@ -293,6 +297,7 @@ private: void pipeRunAABGR8(SplashPipe *pipe); #if SPLASH_CMYK void pipeRunAACMYK8(SplashPipe *pipe); + void pipeRunAADeviceN8(SplashPipe *pipe); #endif void pipeSetXY(SplashPipe *pipe, int x, int y); void pipeIncX(SplashPipe *pipe); diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc index cd85543c..5fe61a2e 100644 --- a/splash/SplashBitmap.cc +++ b/splash/SplashBitmap.cc @@ -45,6 +45,7 @@ #include "goo/PNGWriter.h" #include "goo/TiffWriter.h" #include "goo/ImgWriter.h" +#include "goo/GooList.h" //------------------------------------------------------------------------ // SplashBitmap @@ -52,7 +53,7 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, SplashColorMode modeA, GBool alphaA, - GBool topDown) { + GBool topDown, GooList *separationListA) { width = widthA; height = heightA; mode = modeA; @@ -95,6 +96,13 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, rowSize = -1; } break; + case splashModeDeviceN8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * (SPOT_NCOMPS + 4); + } else { + rowSize = -1; + } + break; #endif } if (rowSize > 0) { @@ -115,11 +123,15 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, } else { alpha = NULL; } + separationList = new GooList(); + if (separationListA != NULL) + for (int i = 0; i < separationListA->getLength(); i++) + separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy()); } SplashBitmap *SplashBitmap::copy(SplashBitmap *src) { SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), - src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0); + src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0, src->getSeparationList()); Guchar *dataSource = src->getDataPtr(); Guchar *dataDest = result->getDataPtr(); int amount = src->getRowSize(); @@ -146,6 +158,7 @@ SplashBitmap::~SplashBitmap() { } } gfree(alpha); + deleteGooList(separationList, GfxSeparationColorSpace); } @@ -234,6 +247,7 @@ SplashError SplashBitmap::writePNMFile(FILE *f) { #if SPLASH_CMYK case splashModeCMYK8: + case splashModeDeviceN8: // PNM doesn't support CMYK error(errInternal, -1, "unsupported SplashBitmap mode"); return splashErrGeneric; @@ -300,6 +314,11 @@ void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { pixel[2] = p[2]; pixel[3] = p[3]; break; + case splashModeDeviceN8: + p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x]; + for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++) + pixel[cp] = p[cp]; + break; #endif } } @@ -386,6 +405,31 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) { m = byteToDbl(col[1]); y = byteToDbl(col[2]); k = byteToDbl(col[3]); +#if SPLASH_CMYK + if (separationList->getLength() > 0) { + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + if (c > 1) c = 1; + if (m > 1) m = 1; + if (y > 1) y = 1; + if (k > 1) k = 1; + } +#endif c1 = 1 - c; m1 = 1 - m; y1 = 1 - y; @@ -397,10 +441,52 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) { } } +#if SPLASH_CMYK +void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) { + SplashColor col; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + if (separationList->getLength() > 0) { + double c, m, y, k; + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + col[0] = dblToByte(clip01(c)); + col[1] = dblToByte(clip01(m)); + col[2] = dblToByte(clip01(y)); + col[3] = dblToByte(clip01(k)); + } + *line++ = col[0]; + *line++ = col[1]; + *line++ = col[2]; + *line++ = col[3]; + } +} +#endif + SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) { if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 #if SPLASH_CMYK - && mode != splashModeCMYK8 + && mode != splashModeCMYK8 && mode != splashModeDeviceN8 #endif ) { error(errInternal, -1, "unsupported SplashBitmap mode"); @@ -440,6 +526,29 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int delete[] row; } break; + case splashModeDeviceN8: + if (writer->supportCMYK()) { + unsigned char *row = new unsigned char[4 * width]; + for (int y = 0; y < height; y++) { + getCMYKLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } else { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + getRGBLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; #endif case splashModeRGB8: { diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h index 5ef5573a..0bff2050 100644 --- a/splash/SplashBitmap.h +++ b/splash/SplashBitmap.h @@ -34,6 +34,7 @@ #endif #include "SplashTypes.h" +#include "poppler/GfxState.h" #include <stdio.h> class ImgWriter; @@ -51,7 +52,7 @@ public: // upside-down, i.e., with the last row first in memory. SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, - GBool topDown = gTrue); + GBool topDown = gTrue, GooList *separationList = NULL); static SplashBitmap *copy(SplashBitmap *src); ~SplashBitmap(); @@ -64,6 +65,7 @@ public: SplashColorMode getMode() { return mode; } SplashColorPtr getDataPtr() { return data; } Guchar *getAlphaPtr() { return alpha; } + GooList *getSeparationList() { return separationList; } SplashError writePNMFile(char *fileName); SplashError writePNMFile(FILE *f); @@ -75,6 +77,9 @@ public: void getPixel(int x, int y, SplashColorPtr pixel); void getRGBLine(int y, SplashColorPtr line); +#if SPLASH_CMYK + void getCMYKLine(int y, SplashColorPtr line); +#endif Guchar getAlpha(int x, int y); // Caller takes ownership of the bitmap data. The SplashBitmap @@ -92,6 +97,7 @@ private: SplashColorPtr data; // pointer to row zero of the color data Guchar *alpha; // pointer to row zero of the alpha data // (always top-down) + GooList *separationList; // list of spot colorants and their mapping functions friend class Splash; }; diff --git a/splash/SplashState.cc b/splash/SplashState.cc index e258f668..fd2789d0 100644 --- a/splash/SplashState.cc +++ b/splash/SplashState.cc @@ -40,7 +40,7 @@ int splashColorModeNComps[] = { 1, 1, 3, 3, 4 #if SPLASH_CMYK - ,4 + , 4, 4 + SPOT_NCOMPS #endif }; @@ -80,10 +80,14 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + deviceNTransfer[cp][i] = (Guchar)i; +#endif } overprintMask = 0xffffffff; overprintAdditive = gFalse; @@ -126,10 +130,14 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + deviceNTransfer[cp][i] = (Guchar)i; +#endif } overprintMask = 0xffffffff; overprintAdditive = gFalse; @@ -170,10 +178,14 @@ SplashState::SplashState(SplashState *state) { memcpy(rgbTransferG, state->rgbTransferG, 256); memcpy(rgbTransferB, state->rgbTransferB, 256); memcpy(grayTransfer, state->grayTransfer, 256); +#if SPLASH_CMYK memcpy(cmykTransferC, state->cmykTransferC, 256); memcpy(cmykTransferM, state->cmykTransferM, 256); memcpy(cmykTransferY, state->cmykTransferY, 256); memcpy(cmykTransferK, state->cmykTransferK, 256); + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + memcpy(deviceNTransfer[cp], state->deviceNTransfer[cp], 256); +#endif overprintMask = state->overprintMask; overprintAdditive = state->overprintAdditive; next = NULL; @@ -228,16 +240,24 @@ void SplashState::setSoftMask(SplashBitmap *softMaskA) { void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray) { +#if SPLASH_CMYK int i; - memcpy(rgbTransferR, red, 256); - memcpy(rgbTransferG, green, 256); - memcpy(rgbTransferB, blue, 256); - memcpy(grayTransfer, gray, 256); for (i = 0; i < 256; ++i) { cmykTransferC[i] = 255 - rgbTransferR[255 - i]; cmykTransferM[i] = 255 - rgbTransferG[255 - i]; cmykTransferY[i] = 255 - rgbTransferB[255 - i]; cmykTransferK[i] = 255 - grayTransfer[255 - i]; } + for (i = 0; i < 256; ++i) { + deviceNTransfer[0][i] = 255 - rgbTransferR[255 - i]; + deviceNTransfer[1][i] = 255 - rgbTransferG[255 - i]; + deviceNTransfer[2][i] = 255 - rgbTransferB[255 - i]; + deviceNTransfer[3][i] = 255 - grayTransfer[255 - i]; + } +#endif + memcpy(rgbTransferR, red, 256); + memcpy(rgbTransferG, green, 256); + memcpy(rgbTransferB, blue, 256); + memcpy(grayTransfer, gray, 256); } diff --git a/splash/SplashState.h b/splash/SplashState.h index 01e77720..13d54788 100644 --- a/splash/SplashState.h +++ b/splash/SplashState.h @@ -121,10 +121,13 @@ private: rgbTransferG[256],
rgbTransferB[256];
Guchar grayTransfer[256];
+#if SPLASH_CMYK
Guchar cmykTransferC[256],
cmykTransferM[256],
cmykTransferY[256],
cmykTransferK[256];
+ Guchar deviceNTransfer[SPOT_NCOMPS+4][256];
+#endif
Guint overprintMask;
GBool overprintAdditive;
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h index 65525b13..531b945b 100644 --- a/splash/SplashTypes.h +++ b/splash/SplashTypes.h @@ -13,7 +13,7 @@ // // Copyright (C) 2006, 2010 Albert Astals Cid <aacid@kde.org> // Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com> -// Copyright (C) 2009, 2011 Thomas Freitag <Thomas.Freitag@alfa.de> +// Copyright (C) 2009, 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de> // Copyright (C) 2009 Stefan Thomas <thomas@eload24.com> // Copyright (C) 2010 William Bader <williambader@hotmail.com> // @@ -46,6 +46,12 @@ typedef double SplashCoord; #define splashAASize 4 +#ifdef SPLASH_CMYK +#ifndef SPOT_NCOMPS +#define SPOT_NCOMPS 4 +#endif +#endif + //------------------------------------------------------------------------ // colors //------------------------------------------------------------------------ @@ -62,8 +68,11 @@ enum SplashColorMode { // XBGRXBGR... #if SPLASH_CMYK , - splashModeCMYK8 // 1 byte per component, 4 bytes per pixel: + splashModeCMYK8, // 1 byte per component, 4 bytes per pixel: // CMYKCMYK... + splashModeDeviceN8 // 1 byte per component, + // 4 bytes + n bytes spot colors per pixel: + // CMYKSSSSCMYKSSSS... #endif }; @@ -72,7 +81,11 @@ enum SplashColorMode { extern int splashColorModeNComps[]; // max number of components in any SplashColor +#if SPLASH_CMYK +#define splashMaxColorComps SPOT_NCOMPS+4 +#else #define splashMaxColorComps 4 +#endif typedef Guchar SplashColor[splashMaxColorComps]; typedef Guchar *SplashColorPtr; @@ -93,6 +106,13 @@ static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } + +// DEVICEN8 +static inline Guchar splashDeviceN8C(SplashColorPtr deviceN8) { return deviceN8[0]; } +static inline Guchar splashDeviceN8M(SplashColorPtr deviceN8) { return deviceN8[1]; } +static inline Guchar splashDeviceN8Y(SplashColorPtr deviceN8) { return deviceN8[2]; } +static inline Guchar splashDeviceN8K(SplashColorPtr deviceN8) { return deviceN8[3]; } +static inline Guchar splashDeviceN8S(SplashColorPtr deviceN8, int nSpot) { return deviceN8[4 + nSpot]; } #endif static inline void splashClearColor(SplashColorPtr dest) { @@ -101,6 +121,8 @@ static inline void splashClearColor(SplashColorPtr dest) { dest[2] = 0; #if SPLASH_CMYK dest[3] = 0; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] = 0; #endif } @@ -110,6 +132,8 @@ static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { dest[2] = src[2]; #if SPLASH_CMYK dest[3] = src[3]; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] = src[i]; #endif } @@ -119,6 +143,8 @@ static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { dest[2] ^= src[2]; #if SPLASH_CMYK dest[3] ^= src[3]; + for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++) + dest[i] ^= src[i]; #endif } |