summaryrefslogtreecommitdiff
path: root/splash
diff options
context:
space:
mode:
authorThomas Freitag <Thomas.Freitag@alfa.de>2012-09-11 23:33:25 +0200
committerAlbert Astals Cid <aacid@kde.org>2012-09-11 23:33:25 +0200
commit2e77799a1668f949612f551425d0665c59ff1d93 (patch)
tree9a7b935adf3de6016bda6e8e0d7835419e11b6db /splash
parentcb2ed646c4ef4161e443ee0a377d1111b3be28ff (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.cc255
-rw-r--r--splash/Splash.h7
-rw-r--r--splash/SplashBitmap.cc115
-rw-r--r--splash/SplashBitmap.h8
-rw-r--r--splash/SplashState.cc30
-rw-r--r--splash/SplashState.h3
-rw-r--r--splash/SplashTypes.h30
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
}