summaryrefslogtreecommitdiff
path: root/Build/source/libs/xpdf/xpdf-src/splash
diff options
context:
space:
mode:
authorAkira Kakuto <kakuto@fuk.kindai.ac.jp>2021-02-01 06:11:18 +0000
committerAkira Kakuto <kakuto@fuk.kindai.ac.jp>2021-02-01 06:11:18 +0000
commit4f9de1dfebdc66d367d730252d6f224d37e96ee6 (patch)
tree3750421fabf3aa8a8e1f4f6d5558d489e9d4fe02 /Build/source/libs/xpdf/xpdf-src/splash
parent9d694205709f79666458dc2ee685767b28bcd9ac (diff)
xpdf 4.03
git-svn-id: svn://tug.org/texlive/trunk@57588 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/splash')
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/Splash.cc5663
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/Splash.h225
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc20
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h4
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc50
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc36
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h6
-rw-r--r--Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc3
8 files changed, 3266 insertions, 2741 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc b/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc
index 44f87a9dcd2..343db796fb2 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc
+++ b/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc
@@ -2,7 +2,7 @@
//
// Splash.cc
//
-// Copyright 2003-2013 Glyph & Cog, LLC
+// Copyright 2003-2020 Glyph & Cog, LLC
//
//========================================================================
@@ -80,6 +80,12 @@ struct SplashPipe {
Guchar aInput;
SplashColor cSrcVal;
+ // source overprint mask
+ //~ this is a kludge - this pointer should be passed as an arg to the
+ //~ pipeRun function, but that would require passing in a lot of
+ //~ null pointers, since it's rarely used
+ Guint *srcOverprintMaskPtr;
+
// special cases and result color
GBool noTransparency;
GBool shapeOnly;
@@ -163,7 +169,7 @@ inline void Splash::updateModY(int y) {
inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
Guchar aInput, GBool usesShape,
- GBool nonIsolatedGroup) {
+ GBool nonIsolatedGroup, GBool usesSrcOverprint) {
SplashColorMode mode;
mode = bitmap->mode;
@@ -181,6 +187,9 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
// source alpha
pipe->aInput = aInput;
+ // source overprint mask
+ pipe->srcOverprintMaskPtr = NULL;
+
// special cases
pipe->noTransparency = aInput == 255 &&
!state->softMask &&
@@ -212,7 +221,9 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
// select the 'run' function
pipe->run = &Splash::pipeRun;
- if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
+ if (overprintMaskBitmap || usesSrcOverprint) {
+ // use Splash::pipeRun
+ } else if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
if (mode == splashModeMono1 && !bitmap->alpha) {
pipe->run = &Splash::pipeRunSimpleMono1;
} else if (mode == splashModeMono8 && bitmap->alpha) {
@@ -239,6 +250,9 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
} else if (mode == splashModeCMYK8 && bitmap->alpha) {
pipe->run = &Splash::pipeRunShapeCMYK8;
#endif
+ } else if (mode == splashModeMono8 && !bitmap->alpha) {
+ // this is used when drawing soft-masked images
+ pipe->run = &Splash::pipeRunShapeNoAlphaMono8;
}
} else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
usesShape &&
@@ -258,6 +272,26 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
pipe->run = &Splash::pipeRunAACMYK8;
#endif
}
+ } else if (!pipe->pattern &&
+ aInput == 255 &&
+ state->softMask &&
+ usesShape &&
+ !state->inNonIsolatedGroup &&
+ !state->inKnockoutGroup &&
+ !nonIsolatedGroup &&
+ state->overprintMask == 0xffffffff &&
+ !state->blendFunc) {
+ if (mode == splashModeMono8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunSoftMaskMono8;
+ } else if (mode == splashModeRGB8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunSoftMaskRGB8;
+ } else if (mode == splashModeBGR8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunSoftMaskBGR8;
+#if SPLASH_CMYK
+ } else if (mode == splashModeCMYK8 && bitmap->alpha) {
+ pipe->run = &Splash::pipeRunSoftMaskCMYK8;
+#endif
+ }
} else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
usesShape &&
state->inNonIsolatedGroup && groupBackBitmap->alpha &&
@@ -292,6 +326,8 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
Guchar color0Mask;
Guchar *alpha0Ptr;
SplashColorPtr softMaskPtr;
+ Guint overprintMask;
+ Guint *overprintMaskPtr;
#if SPLASH_CMYK
Guchar aPrev;
SplashColor cSrc2, cDest2;
@@ -313,6 +349,9 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
}
cSrcPtr += cSrcStride;
++shapePtr2;
+ if (pipe->srcOverprintMaskPtr) {
+ ++pipe->srcOverprintMaskPtr;
+ }
}
} else {
shapeVal = 0xff;
@@ -326,6 +365,8 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
if (bitmap->mode == splashModeMono1) {
destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
destColorMask = (Guchar)(0x80 >> (x0 & 7));
@@ -367,6 +408,11 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
} else {
alpha0Ptr = NULL;
}
+ if (overprintMaskBitmap) {
+ overprintMaskPtr = overprintMaskBitmap + y * bitmap->width + x0;
+ } else {
+ overprintMaskPtr = NULL;
+ }
for (x = x0; x <= x1; ++x) {
@@ -399,6 +445,12 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
}
cSrcPtr += cSrcStride;
shapePtr2 += shapeStride;
+ if (pipe->srcOverprintMaskPtr) {
+ ++pipe->srcOverprintMaskPtr;
+ }
+ if (overprintMaskPtr) {
+ ++overprintMaskPtr;
+ }
continue;
}
lastX = x;
@@ -519,6 +571,15 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
//----- read source color; handle overprint
+ if (pipe->srcOverprintMaskPtr) {
+ overprintMask = *pipe->srcOverprintMaskPtr++;
+ } else {
+ overprintMask = state->overprintMask;
+ }
+ if (overprintMaskPtr) {
+ *overprintMaskPtr++ |= overprintMask;
+ }
+
switch (bitmap->mode) {
case splashModeMono1:
case splashModeMono8:
@@ -545,22 +606,22 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y,
aPrev = aDest;
}
}
- if (state->overprintMask & 0x01) {
+ if (overprintMask & 0x01) {
cSrc[0] = state->cmykTransferC[cSrcPtr[0]];
} else {
cSrc[0] = div255(aPrev * cDest[0]);
}
- if (state->overprintMask & 0x02) {
+ if (overprintMask & 0x02) {
cSrc[1] = state->cmykTransferM[cSrcPtr[1]];
} else {
cSrc[1] = div255(aPrev * cDest[1]);
}
- if (state->overprintMask & 0x04) {
+ if (overprintMask & 0x04) {
cSrc[2] = state->cmykTransferY[cSrcPtr[2]];
} else {
cSrc[2] = div255(aPrev * cDest[2]);
}
- if (state->overprintMask & 0x08) {
+ if (overprintMask & 0x08) {
cSrc[3] = state->cmykTransferK[cSrcPtr[3]];
} else {
cSrc[3] = div255(aPrev * cDest[3]);
@@ -862,6 +923,8 @@ void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y,
updateModX(x1);
updateModY(y);
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
destColorMask = (Guchar)(0x80 >> (x0 & 7));
@@ -905,6 +968,8 @@ void Splash::pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y,
updateModX(x1);
updateModY(y);
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -940,6 +1005,8 @@ void Splash::pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y,
updateModX(x1);
updateModY(y);
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -978,6 +1045,8 @@ void Splash::pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y,
updateModX(x1);
updateModY(y);
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1017,6 +1086,8 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y,
updateModX(x1);
updateModY(y);
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1067,6 +1138,8 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
destColorMask = (Guchar)(0x80 >> (x0 & 7));
@@ -1150,6 +1223,8 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1243,6 +1318,8 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1349,6 +1426,8 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1456,6 +1535,8 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1480,26 +1561,10 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
aDest = *destAlphaPtr;
//----- overprint
- if (state->overprintMask & 1) {
- cSrc0 = state->cmykTransferC[cSrcPtr[0]];
- } else {
- cSrc0 = div255(aDest * cDest0);
- }
- if (state->overprintMask & 2) {
- cSrc1 = state->cmykTransferM[cSrcPtr[1]];
- } else {
- cSrc1 = div255(aDest * cDest1);
- }
- if (state->overprintMask & 4) {
- cSrc2 = state->cmykTransferY[cSrcPtr[2]];
- } else {
- cSrc2 = div255(aDest * cDest2);
- }
- if (state->overprintMask & 8) {
- cSrc3 = state->cmykTransferK[cSrcPtr[3]];
- } else {
- cSrc3 = div255(aDest * cDest3);
- }
+ cSrc0 = state->cmykTransferC[cSrcPtr[0]];
+ cSrc1 = state->cmykTransferM[cSrcPtr[1]];
+ cSrc2 = state->cmykTransferY[cSrcPtr[2]];
+ cSrc3 = state->cmykTransferK[cSrcPtr[3]];
//----- source alpha
aSrc = shape;
@@ -1552,6 +1617,80 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
// special case:
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && !bitmap->alpha
+void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr,
+ SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, cSrc0, cDest0, cResult0;
+ SplashColorPtr destColorPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ useDestRow(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ ++destColorPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- source color
+ cSrc0 = state->grayTransfer[cSrcPtr[0]];
+
+ //----- source alpha
+ aSrc = shape;
+
+ //----- special case for aSrc = 255
+ if (aSrc == 255) {
+ cResult0 = cSrc0;
+ } else {
+
+ //----- read destination pixel
+ cDest0 = *destColorPtr;
+
+ //----- result color
+ cResult0 = div255((255 - aSrc) * cDest0 + aSrc * cSrc0);
+ }
+
+ //----- write destination pixel
+ *destColorPtr++ = cResult0;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
+}
+
+// special case:
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
// !pipe->nonIsolatedGroup &&
@@ -1584,6 +1723,8 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
destColorMask = (Guchar)(0x80 >> (x0 & 7));
@@ -1663,6 +1804,8 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1746,6 +1889,8 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1840,6 +1985,8 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -1935,6 +2082,8 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
@@ -2017,6 +2166,457 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
#endif
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && bitmap->alpha
+void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cSrc0, cDest0, cResult0;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ SplashColorPtr softMaskPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 1;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ useDestRow(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+ softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ ++destColorPtr;
+ ++destAlphaPtr;
+ ++softMaskPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read source color
+ cSrc0 = state->grayTransfer[cSrcPtr[0]];
+
+ //----- source alpha
+ aSrc = div255(*softMaskPtr++ * shape);
+
+ //----- special case for aSrc = 255
+ if (aSrc == 255) {
+ aResult = 255;
+ cResult0 = cSrc0;
+ } else {
+
+ //----- read destination alpha
+ aDest = *destAlphaPtr;
+
+ //----- special case for aDest = 0
+ if (aDest == 0) {
+ aResult = aSrc;
+ cResult0 = cSrc0;
+ } else {
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+
+ //----- result alpha and non-isolated group element correction
+ aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+ alphaI = aResult;
+
+ //----- result color
+ cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+ }
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ ++destColorPtr;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
+}
+
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeRGB8 && bitmap->alpha
+void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cSrc0, cSrc1, cSrc2;
+ Guchar cDest0, cDest1, cDest2;
+ Guchar cResult0, cResult1, cResult2;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ SplashColorPtr softMaskPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ useDestRow(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+ softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 3;
+ ++destAlphaPtr;
+ ++softMaskPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read source color
+ cSrc0 = state->rgbTransferR[cSrcPtr[0]];
+ cSrc1 = state->rgbTransferG[cSrcPtr[1]];
+ cSrc2 = state->rgbTransferB[cSrcPtr[2]];
+
+ //----- source alpha
+ aSrc = div255(*softMaskPtr++ * shape);
+
+ //----- special case for aSrc = 255
+ if (aSrc == 255) {
+ aResult = 255;
+ cResult0 = cSrc0;
+ cResult1 = cSrc1;
+ cResult2 = cSrc2;
+ } else {
+
+ //----- read destination alpha
+ aDest = *destAlphaPtr;
+
+ //----- special case for aDest = 0
+ if (aDest == 0) {
+ aResult = aSrc;
+ cResult0 = cSrc0;
+ cResult1 = cSrc1;
+ cResult2 = cSrc2;
+ } else {
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[2];
+
+ //----- result alpha and non-isolated group element correction
+ aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+ alphaI = aResult;
+
+ //----- result color
+ cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+ cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
+ cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
+ }
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr += 3;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
+}
+
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeBGR8 && bitmap->alpha
+void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cSrc0, cSrc1, cSrc2;
+ Guchar cDest0, cDest1, cDest2;
+ Guchar cResult0, cResult1, cResult2;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ SplashColorPtr softMaskPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 3;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ useDestRow(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+ softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 3;
+ ++destAlphaPtr;
+ ++softMaskPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read source color
+ cSrc0 = state->rgbTransferR[cSrcPtr[0]];
+ cSrc1 = state->rgbTransferG[cSrcPtr[1]];
+ cSrc2 = state->rgbTransferB[cSrcPtr[2]];
+
+ //----- source alpha
+ aSrc = div255(*softMaskPtr++ * shape);
+
+ //----- special case for aSrc = 255
+ if (aSrc == 255) {
+ aResult = 255;
+ cResult0 = cSrc0;
+ cResult1 = cSrc1;
+ cResult2 = cSrc2;
+ } else {
+
+ //----- read destination alpha
+ aDest = *destAlphaPtr;
+
+ //----- special case for aDest = 0
+ if (aDest == 0) {
+ aResult = aSrc;
+ cResult0 = cSrc0;
+ cResult1 = cSrc1;
+ cResult2 = cSrc2;
+ } else {
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[2];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[0];
+
+ //----- result alpha and non-isolated group element correction
+ aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+ alphaI = aResult;
+
+ //----- result color
+ cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+ cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
+ cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
+ }
+ }
+
+ //----- write destination pixel
+ destColorPtr[2] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[0] = cResult2;
+ destColorPtr += 3;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
+}
+
+#if SPLASH_CMYK
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeCMYK8 && bitmap->alpha
+void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+ Guchar shape, aSrc, aDest, alphaI, aResult;
+ Guchar cSrc0, cSrc1, cSrc2, cSrc3;
+ Guchar cDest0, cDest1, cDest2, cDest3;
+ Guchar cResult0, cResult1, cResult2, cResult3;
+ SplashColorPtr destColorPtr;
+ Guchar *destAlphaPtr;
+ SplashColorPtr softMaskPtr;
+ int cSrcStride, x, lastX;
+
+ if (cSrcPtr) {
+ cSrcStride = 4;
+ } else {
+ cSrcPtr = pipe->cSrcVal;
+ cSrcStride = 0;
+ }
+ for (; x0 <= x1; ++x0) {
+ if (*shapePtr) {
+ break;
+ }
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+ if (x0 > x1) {
+ return;
+ }
+ updateModX(x0);
+ updateModY(y);
+ lastX = x0;
+
+ useDestRow(y);
+
+ destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
+ destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+ softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+ for (x = x0; x <= x1; ++x) {
+
+ //----- shape
+ shape = *shapePtr;
+ if (!shape) {
+ destColorPtr += 4;
+ ++destAlphaPtr;
+ ++softMaskPtr;
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ continue;
+ }
+ lastX = x;
+
+ //----- read destination pixel
+ cDest0 = destColorPtr[0];
+ cDest1 = destColorPtr[1];
+ cDest2 = destColorPtr[2];
+ cDest3 = destColorPtr[3];
+
+ //----- read destination alpha
+ aDest = *destAlphaPtr;
+
+ //----- overprint
+ cSrc0 = state->cmykTransferC[cSrcPtr[0]];
+ cSrc1 = state->cmykTransferM[cSrcPtr[1]];
+ cSrc2 = state->cmykTransferY[cSrcPtr[2]];
+ cSrc3 = state->cmykTransferK[cSrcPtr[3]];
+
+ //----- source alpha
+ aSrc = div255(*softMaskPtr++ * shape);
+
+ //----- special case for aSrc = 255
+ if (aSrc == 255) {
+ aResult = 255;
+ cResult0 = cSrc0;
+ cResult1 = cSrc1;
+ cResult2 = cSrc2;
+ cResult3 = cSrc3;
+ } else {
+
+ //----- special case for aDest = 0
+ if (aDest == 0) {
+ aResult = aSrc;
+ cResult0 = cSrc0;
+ cResult1 = cSrc1;
+ cResult2 = cSrc2;
+ cResult3 = cSrc3;
+ } else {
+
+ //----- result alpha and non-isolated group element correction
+ aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+ alphaI = aResult;
+
+ //----- result color
+ cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+ cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
+ cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
+ cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
+ }
+ }
+
+ //----- write destination pixel
+ destColorPtr[0] = cResult0;
+ destColorPtr[1] = cResult1;
+ destColorPtr[2] = cResult2;
+ destColorPtr[3] = cResult3;
+ destColorPtr += 4;
+ *destAlphaPtr++ = aResult;
+
+ cSrcPtr += cSrcStride;
+ ++shapePtr;
+ }
+
+ updateModX(lastX);
+}
+#endif
+
+
void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr) {
Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
@@ -2046,6 +2646,8 @@ void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2130,6 +2732,8 @@ void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2225,6 +2829,8 @@ void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2321,6 +2927,8 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y,
updateModY(y);
lastX = x0;
+ useDestRow(y);
+
destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2409,6 +3017,84 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y,
#endif
+void Splash::useDestRow(int y) {
+ int y0, y1, yy;
+
+ if (groupDestInitMode == splashGroupDestPreInit) {
+ return;
+ }
+ if (groupDestInitYMin > groupDestInitYMax) {
+ y0 = y1 = y;
+ groupDestInitYMin = groupDestInitYMax = y;
+ } else if (y < groupDestInitYMin) {
+ y0 = y;
+ y1 = groupDestInitYMin - 1;
+ groupDestInitYMin = y;
+ } else if (y > groupDestInitYMax) {
+ y0 = groupDestInitYMax + 1;
+ y1 = y;
+ groupDestInitYMax = y;
+ } else {
+ return;
+ }
+ for (yy = y0; yy <= y1; ++yy) {
+ if (groupDestInitMode == splashGroupDestInitZero) {
+ // same as clear(color=0, alpha=0)
+ memset(bitmap->data + bitmap->rowSize * yy, 0,
+ bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize);
+ if (bitmap->alpha) {
+ memset(bitmap->alpha + bitmap->alphaRowSize * yy, 0,
+ bitmap->alphaRowSize);
+ }
+ } else { // (groupDestInitMode == splashGroupDestInitCopy)
+ // same as blitTransparent
+ copyGroupBackdropRow(yy);
+ }
+ }
+}
+
+void Splash::copyGroupBackdropRow(int y) {
+ SplashColorPtr p, q;
+ Guchar mask, srcMask;
+ int x;
+
+ if (groupBackBitmap->mode != bitmap->mode) {
+ return;
+ }
+
+ if (bitmap->mode == splashModeMono1) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ mask = (Guchar)0x80;
+ q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize
+ + (groupBackX >> 3)];
+ srcMask = (Guchar)(0x80 >> (groupBackX & 7));
+ for (x = 0; x < bitmap->width; ++x) {
+ if (*q & srcMask) {
+ *p |= mask;
+ } else {
+ *p &= (Guchar)~mask;
+ }
+ if (!(mask = (Guchar)(mask >> 1))) {
+ mask = 0x80;
+ ++p;
+ }
+ if (!(srcMask = (Guchar)(srcMask >> 1))) {
+ srcMask = 0x80;
+ ++q;
+ }
+ }
+ } else {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize
+ + bitmapComps * groupBackX];
+ memcpy(p, q, bitmapComps * bitmap->width);
+ }
+
+ if (bitmap->alpha) {
+ memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width);
+ }
+}
+
//------------------------------------------------------------------------
// Transform a point from user space to device space.
@@ -2428,7 +3114,13 @@ inline void Splash::transform(SplashCoord *matrix,
SplashImageCache::SplashImageCache() {
tag = NULL;
- image = NULL;
+ width = 0;
+ height = 0;
+ mode = splashModeRGB8;
+ alpha = gFalse;
+ interpolate = gFalse;
+ colorData = NULL;
+ alphaData = NULL;
refCount = 1;
}
@@ -2436,9 +3128,39 @@ SplashImageCache::~SplashImageCache() {
if (tag) {
delete tag;
}
- if (image) {
- delete image;
+ gfree(colorData);
+ gfree(alphaData);
+}
+
+GBool SplashImageCache::match(GString *aTag, int aWidth, int aHeight,
+ SplashColorMode aMode, GBool aAlpha,
+ GBool aInterpolate) {
+ return aTag && tag && !aTag->cmp(tag) &&
+ aWidth == width && aHeight == height &&
+ aMode == mode && aAlpha == alpha &&
+ aInterpolate == interpolate;
+}
+
+void SplashImageCache::reset(GString *aTag, int aWidth, int aHeight,
+ SplashColorMode aMode, GBool aAlpha,
+ GBool aInterpolate) {
+ if (tag) {
+ delete tag;
}
+ if (aTag) {
+ tag = aTag->copy();
+ } else {
+ tag = NULL;
+ }
+ width = aWidth;
+ height = aHeight;
+ mode = aMode;
+ alpha = aAlpha;
+ interpolate = aInterpolate;
+ gfree(colorData);
+ colorData = NULL;
+ gfree(alphaData);
+ alphaData = NULL;
}
void SplashImageCache::incRefCount() {
@@ -2453,6 +3175,1172 @@ void SplashImageCache::decRefCount() {
}
//------------------------------------------------------------------------
+// ImageScaler
+//------------------------------------------------------------------------
+
+// Abstract base class.
+class ImageScaler {
+public:
+
+ ImageScaler() {}
+ virtual ~ImageScaler() {}
+
+ // Compute the next line of the scaled image. This can be called up
+ // to [scaledHeight] times.
+ virtual void nextLine() = 0;
+
+ // Retrieve the color and alpha data generated by the most recent
+ // call to nextLine().
+ virtual Guchar *colorData() = 0;
+ virtual Guchar *alphaData() = 0;
+};
+
+//------------------------------------------------------------------------
+// BasicImageScaler
+//------------------------------------------------------------------------
+
+// The actual image scaler.
+class BasicImageScaler: public ImageScaler {
+public:
+
+ BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
+ int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
+ int aScaledWidth, int aScaledHeight, GBool aInterpolate);
+ virtual ~BasicImageScaler();
+ virtual void nextLine();
+ virtual Guchar *colorData() { return colorLine; }
+ virtual Guchar *alphaData() { return alphaLine; }
+
+protected:
+
+ void vertDownscaleHorizDownscale();
+ void vertDownscaleHorizUpscaleNoInterp();
+ void vertDownscaleHorizUpscaleInterp();
+ void vertUpscaleHorizDownscaleNoInterp();
+ void vertUpscaleHorizDownscaleInterp();
+ void vertUpscaleHorizUpscaleNoInterp();
+ void vertUpscaleHorizUpscaleInterp();
+
+ // source image data function
+ SplashImageSource src;
+ void *srcData;
+
+ // source image size
+ int srcWidth;
+ int srcHeight;
+
+ // scaled image size
+ int scaledWidth;
+ int scaledHeight;
+
+ // number of color and alpha components
+ int nComps;
+ GBool hasAlpha;
+
+ // params/state for vertical scaling
+ int yp, yq;
+ int yt, yn;
+ int ySrcCur, yScaledCur;
+ SplashCoord yInvScale;
+
+ // params for horizontal scaling
+ int xp, xq;
+ SplashCoord xInvScale;
+
+ // scaling function
+ void (BasicImageScaler::*scalingFunc)();
+
+ // temporary buffers for vertical scaling
+ Guchar *colorTmpBuf0;
+ Guchar *colorTmpBuf1;
+ Guchar *colorTmpBuf2;
+ Guchar *alphaTmpBuf0;
+ Guchar *alphaTmpBuf1;
+ Guchar *alphaTmpBuf2;
+ Guint *colorAccBuf;
+ Guint *alphaAccBuf;
+
+ // output of horizontal scaling
+ Guchar *colorLine;
+ Guchar *alphaLine;
+};
+
+BasicImageScaler::BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
+ int aSrcWidth, int aSrcHeight,
+ int aNComps, GBool aHasAlpha,
+ int aScaledWidth, int aScaledHeight,
+ GBool aInterpolate) {
+ colorTmpBuf0 = NULL;
+ colorTmpBuf1 = NULL;
+ colorTmpBuf2 = NULL;
+ alphaTmpBuf0 = NULL;
+ alphaTmpBuf1 = NULL;
+ alphaTmpBuf2 = NULL;
+ colorAccBuf = NULL;
+ alphaAccBuf = NULL;
+ colorLine = NULL;
+ alphaLine = NULL;
+
+ src = aSrc;
+ srcData = aSrcData;
+ srcWidth = aSrcWidth;
+ srcHeight = aSrcHeight;
+ scaledWidth = aScaledWidth;
+ scaledHeight = aScaledHeight;
+ nComps = aNComps;
+ hasAlpha = aHasAlpha;
+
+ // select scaling function; allocate buffers
+ if (scaledHeight <= srcHeight) {
+ // vertical downscaling
+ yp = srcHeight / scaledHeight;
+ yq = srcHeight % scaledHeight;
+ yt = 0;
+ colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
+ colorAccBuf = (Guint *)gmallocn(srcWidth, nComps * (int)sizeof(Guint));
+ if (hasAlpha) {
+ alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
+ alphaAccBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
+ }
+ if (scaledWidth <= srcWidth) {
+ scalingFunc = &BasicImageScaler::vertDownscaleHorizDownscale;
+ } else {
+ if (aInterpolate) {
+ scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleInterp;
+ } else {
+ scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleNoInterp;
+ }
+ }
+ } else {
+ // vertical upscaling
+ yp = scaledHeight / srcHeight;
+ yq = scaledHeight % srcHeight;
+ yt = 0;
+ yn = 0;
+ if (aInterpolate) {
+ yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
+ colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
+ colorTmpBuf1 = (Guchar *)gmallocn(srcWidth, nComps);
+ if (hasAlpha) {
+ alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
+ alphaTmpBuf1 = (Guchar *)gmalloc(srcWidth);
+ }
+ ySrcCur = 0;
+ yScaledCur = 0;
+ if (scaledWidth <= srcWidth) {
+ scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleInterp;
+ } else {
+ colorTmpBuf2 = (Guchar *)gmallocn(srcWidth, nComps);
+ if (hasAlpha) {
+ alphaTmpBuf2 = (Guchar *)gmalloc(srcWidth);
+ }
+ scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleInterp;
+ }
+ } else {
+ colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
+ if (hasAlpha) {
+ alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
+ }
+ if (scaledWidth <= srcWidth) {
+ scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleNoInterp;
+ } else {
+ scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleNoInterp;
+ }
+ }
+ }
+ if (scaledWidth <= srcWidth) {
+ xp = srcWidth / scaledWidth;
+ xq = srcWidth % scaledWidth;
+ } else {
+ xp = scaledWidth / srcWidth;
+ xq = scaledWidth % srcWidth;
+ if (aInterpolate) {
+ xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
+ }
+ }
+ colorLine = (Guchar *)gmallocn(scaledWidth, nComps);
+ if (hasAlpha) {
+ alphaLine = (Guchar *)gmalloc(scaledWidth);
+ }
+}
+
+BasicImageScaler::~BasicImageScaler() {
+ gfree(colorTmpBuf0);
+ gfree(colorTmpBuf1);
+ gfree(colorTmpBuf2);
+ gfree(alphaTmpBuf0);
+ gfree(alphaTmpBuf1);
+ gfree(alphaTmpBuf2);
+ gfree(colorAccBuf);
+ gfree(alphaAccBuf);
+ gfree(colorLine);
+ gfree(alphaLine);
+}
+
+void BasicImageScaler::nextLine() {
+ (this->*scalingFunc)();
+}
+
+void BasicImageScaler::vertDownscaleHorizDownscale() {
+ //--- vert downscale
+ int yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+ memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
+ if (hasAlpha) {
+ memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
+ }
+ int nRowComps = srcWidth * nComps;
+ for (int i = 0; i < yStep; ++i) {
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ for (int j = 0; j < nRowComps; ++j) {
+ colorAccBuf[j] += colorTmpBuf0[j];
+ }
+ if (hasAlpha) {
+ for (int j = 0; j < srcWidth; ++j) {
+ alphaAccBuf[j] += alphaTmpBuf0[j];
+ }
+ }
+ }
+
+ //--- horiz downscale
+ int colorAcc[splashMaxColorComps];
+ int xt = 0;
+ int unscaledColorIdx = 0;
+ int unscaledAlphaIdx = 0;
+ int scaledColorIdx = 0;
+
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ for (int j = 0; j < nComps; ++j) {
+ colorAcc[j] = 0;
+ }
+ for (int i = 0; i < xStep; ++i) {
+ for (int j = 0; j < nComps; ++j) {
+ colorAcc[j] += colorAccBuf[unscaledColorIdx + j];
+ }
+ unscaledColorIdx += nComps;
+ }
+ int nPixels = yStep * xStep;
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / nPixels);
+ }
+ scaledColorIdx += nComps;
+
+ if (hasAlpha) {
+ int alphaAcc = 0;
+ for (int i = 0; i < xStep; ++i) {
+ alphaAcc += alphaAccBuf[unscaledAlphaIdx];
+ ++unscaledAlphaIdx;
+ }
+ alphaLine[scaledIdx] = (Guchar)(alphaAcc / nPixels);
+ }
+ }
+}
+
+void BasicImageScaler::vertDownscaleHorizUpscaleNoInterp() {
+ //--- vert downscale
+ int yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+ memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
+ if (hasAlpha) {
+ memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
+ }
+ int nRowComps = srcWidth * nComps;
+ for (int i = 0; i < yStep; ++i) {
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ for (int j = 0; j < nRowComps; ++j) {
+ colorAccBuf[j] += colorTmpBuf0[j];
+ }
+ if (hasAlpha) {
+ for (int j = 0; j < srcWidth; ++j) {
+ alphaAccBuf[j] += alphaTmpBuf0[j];
+ }
+ }
+ }
+
+ //--- horiz upscale
+ Guchar colorBuf[splashMaxColorComps];
+ int xt = 0;
+ int scaledColorIdx = 0;
+ int srcColorIdx = 0;
+ int scaledAlphaIdx = 0;
+ for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= srcWidth) {
+ xt -= srcWidth;
+ ++xStep;
+ }
+ for (int j = 0; j < nComps; ++j) {
+ colorBuf[j] = (Guchar)(colorAccBuf[srcColorIdx + j] / yStep);
+ }
+ srcColorIdx += nComps;
+ for (int i = 0; i < xStep; ++i) {
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] = colorBuf[j];
+ }
+ scaledColorIdx += nComps;
+ }
+ if (hasAlpha) {
+ Guchar alphaBuf = (Guchar)(alphaAccBuf[srcIdx] / yStep);
+ for (int i = 0; i < xStep; ++i) {
+ alphaLine[scaledAlphaIdx] = alphaBuf;
+ ++scaledAlphaIdx;
+ }
+ }
+ }
+}
+
+void BasicImageScaler::vertDownscaleHorizUpscaleInterp() {
+ //--- vert downscale
+ int yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+ memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
+ if (hasAlpha) {
+ memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
+ }
+ int nRowComps = srcWidth * nComps;
+ for (int i = 0; i < yStep; ++i) {
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ for (int j = 0; j < nRowComps; ++j) {
+ colorAccBuf[j] += colorTmpBuf0[j];
+ }
+ if (hasAlpha) {
+ for (int j = 0; j < srcWidth; ++j) {
+ alphaAccBuf[j] += alphaTmpBuf0[j];
+ }
+ }
+ }
+ for (int j = 0; j < srcWidth * nComps; ++j) {
+ colorAccBuf[j] /= yStep;
+ }
+ if (hasAlpha) {
+ for (int j = 0; j < srcWidth; ++j) {
+ alphaAccBuf[j] /= yStep;
+ }
+ }
+
+ //--- horiz upscale
+ int scaledColorIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+ int x0 = splashFloor(xs - 0.5);
+ int x1 = x0 + 1;
+ SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
+ SplashCoord s1 = (SplashCoord)1 - s0;
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (x1 >= srcWidth) {
+ x1 = srcWidth - 1;
+ }
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] =
+ (Guchar)(int)(s0 * colorAccBuf[x0 * nComps + j] +
+ s1 * colorAccBuf[x1 * nComps + j]);
+ }
+ scaledColorIdx += nComps;
+ if (hasAlpha) {
+ alphaLine[scaledIdx] = (Guchar)(int)(s0 * alphaAccBuf[x0] +
+ s1 * alphaAccBuf[x1]);
+ }
+ }
+}
+
+void BasicImageScaler::vertUpscaleHorizDownscaleNoInterp() {
+ //--- vert upscale
+ if (yn == 0) {
+ yn = yp;
+ yt += yq;
+ if (yt >= srcHeight) {
+ yt -= srcHeight;
+ ++yn;
+ }
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ }
+ --yn;
+
+ //--- horiz downscale
+ int colorAcc[splashMaxColorComps];
+ int xt = 0;
+ int unscaledColorIdx = 0;
+ int unscaledAlphaIdx = 0;
+ int scaledColorIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ for (int j = 0; j < nComps; ++j) {
+ colorAcc[j] = 0;
+ }
+ for (int i = 0; i < xStep; ++i) {
+ for (int j = 0; j < nComps; ++j) {
+ colorAcc[j] += colorTmpBuf0[unscaledColorIdx + j];
+ }
+ unscaledColorIdx += nComps;
+ }
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
+ }
+ scaledColorIdx += nComps;
+
+ if (hasAlpha) {
+ int alphaAcc = 0;
+ for (int i = 0; i < xStep; ++i) {
+ alphaAcc += alphaTmpBuf0[unscaledAlphaIdx];
+ ++unscaledAlphaIdx;
+ }
+ alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
+ }
+ }
+}
+
+void BasicImageScaler::vertUpscaleHorizDownscaleInterp() {
+ //--- vert upscale
+ if (ySrcCur == 0) {
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+ ySrcCur = 1;
+ }
+ SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+ int y0 = splashFloor(ys - 0.5);
+ int y1 = y0 + 1;
+ SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
+ SplashCoord vs1 = (SplashCoord)1 - vs0;
+ if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+ Guchar *t = colorTmpBuf0;
+ colorTmpBuf0 = colorTmpBuf1;
+ colorTmpBuf1 = t;
+ if (hasAlpha) {
+ t = alphaTmpBuf0;
+ alphaTmpBuf0 = alphaTmpBuf1;
+ alphaTmpBuf1 = t;
+ }
+ (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+ ++ySrcCur;
+ }
+ Guchar *color0 = colorTmpBuf0;
+ Guchar *color1 = colorTmpBuf1;
+ Guchar *alpha0 = alphaTmpBuf0;
+ Guchar *alpha1 = alphaTmpBuf1;
+ if (y0 < 0) {
+ y0 = 0;
+ color1 = color0;
+ alpha1 = alpha0;
+ }
+ if (y1 >= srcHeight) {
+ y1 = srcHeight - 1;
+ color0 = color1;
+ alpha0 = alpha1;
+ }
+ ++yScaledCur;
+
+ //--- horiz downscale
+ int colorAcc[splashMaxColorComps];
+ int xt = 0;
+ int unscaledColorIdx = 0;
+ int unscaledAlphaIdx = 0;
+ int scaledColorIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ for (int j = 0; j < nComps; ++j) {
+ colorAcc[j] = 0;
+ }
+ for (int i = 0; i < xStep; ++i) {
+ for (int j = 0; j < nComps; ++j) {
+ colorAcc[j] += (int)(vs0 * (int)color0[unscaledColorIdx + j] +
+ vs1 * (int)color1[unscaledColorIdx + j]);
+ }
+ unscaledColorIdx += nComps;
+ }
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
+ }
+ scaledColorIdx += nComps;
+
+ if (hasAlpha) {
+ int alphaAcc = 0;
+ for (int i = 0; i < xStep; ++i) {
+ alphaAcc += (int)(vs0 * (int)alpha0[unscaledAlphaIdx] +
+ vs1 * (int)alpha1[unscaledAlphaIdx]);
+ ++unscaledAlphaIdx;
+ }
+ alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
+ }
+ }
+}
+
+void BasicImageScaler::vertUpscaleHorizUpscaleNoInterp() {
+ //--- vert upscale
+ if (yn == 0) {
+ yn = yp;
+ yt += yq;
+ if (yt >= srcHeight) {
+ yt -= srcHeight;
+ ++yn;
+ }
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ }
+ --yn;
+
+ //--- horiz upscale
+ int xt = 0;
+ int scaledColorIdx = 0;
+ int srcColorIdx = 0;
+ int scaledAlphaIdx = 0;
+ for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= srcWidth) {
+ xt -= srcWidth;
+ ++xStep;
+ }
+ for (int i = 0; i < xStep; ++i) {
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] = colorTmpBuf0[srcColorIdx + j];
+ }
+ scaledColorIdx += nComps;
+ }
+ srcColorIdx += nComps;
+ if (hasAlpha) {
+ Guchar alphaBuf = alphaTmpBuf0[srcIdx];
+ for (int i = 0; i < xStep; ++i) {
+ alphaLine[scaledAlphaIdx] = alphaBuf;
+ ++scaledAlphaIdx;
+ }
+ }
+ }
+}
+
+void BasicImageScaler::vertUpscaleHorizUpscaleInterp() {
+ //--- vert upscale
+ if (ySrcCur == 0) {
+ (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+ (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+ ySrcCur = 1;
+ }
+ SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+ int y0 = splashFloor(ys - 0.5);
+ int y1 = y0 + 1;
+ SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
+ SplashCoord vs1 = (SplashCoord)1 - vs0;
+ if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+ Guchar *t = colorTmpBuf0;
+ colorTmpBuf0 = colorTmpBuf1;
+ colorTmpBuf1 = t;
+ if (hasAlpha) {
+ t = alphaTmpBuf0;
+ alphaTmpBuf0 = alphaTmpBuf1;
+ alphaTmpBuf1 = t;
+ }
+ (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+ ++ySrcCur;
+ }
+ Guchar *color0 = colorTmpBuf0;
+ Guchar *color1 = colorTmpBuf1;
+ Guchar *alpha0 = alphaTmpBuf0;
+ Guchar *alpha1 = alphaTmpBuf1;
+ if (y0 < 0) {
+ y0 = 0;
+ color1 = color0;
+ alpha1 = alpha0;
+ }
+ if (y1 >= srcHeight) {
+ y1 = srcHeight - 1;
+ color0 = color1;
+ alpha0 = alpha1;
+ }
+ ++yScaledCur;
+ for (int srcIdx = 0; srcIdx < srcWidth * nComps; ++srcIdx) {
+ colorTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)color0[srcIdx] +
+ vs1 * (int)color1[srcIdx]);
+ }
+ if (hasAlpha) {
+ for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+ alphaTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)alpha0[srcIdx] +
+ vs1 * (int)alpha1[srcIdx]);
+ }
+ }
+
+ //--- horiz upscale
+ int scaledColorIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+ int x0 = splashFloor(xs - 0.5);
+ int x1 = x0 + 1;
+ SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
+ SplashCoord hs1 = (SplashCoord)1 - hs0;
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (x1 >= srcWidth) {
+ x1 = srcWidth - 1;
+ }
+ for (int j = 0; j < nComps; ++j) {
+ colorLine[scaledColorIdx + j] =
+ (Guchar)(int)(hs0 * (int)colorTmpBuf2[x0 * nComps + j] +
+ hs1 * (int)colorTmpBuf2[x1 * nComps + j]);
+ }
+ scaledColorIdx += nComps;
+ if (hasAlpha) {
+ alphaLine[scaledIdx] = (Guchar)(int)(hs0 * (int)alphaTmpBuf2[x0] +
+ hs1 * (int)alphaTmpBuf2[x1]);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// SavingImageScaler
+//------------------------------------------------------------------------
+
+// Wrapper around BasicImageScaler that saves the scaled image for use
+// by ReplayImageScaler.
+class SavingImageScaler: public BasicImageScaler {
+public:
+
+ SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
+ int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
+ int aScaledWidth, int aScaledHeight, GBool aInterpolate,
+ Guchar *aColorCache, Guchar *aAlphaCache);
+ virtual void nextLine();
+
+private:
+
+ Guchar *colorPtr;
+ Guchar *alphaPtr;
+};
+
+SavingImageScaler::SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
+ int aSrcWidth, int aSrcHeight,
+ int aNComps, GBool aHasAlpha,
+ int aScaledWidth, int aScaledHeight,
+ GBool aInterpolate,
+ Guchar *aColorCache, Guchar *aAlphaCache):
+ BasicImageScaler(aSrc, aSrcData, aSrcWidth, aSrcHeight, aNComps, aHasAlpha,
+ aScaledWidth, aScaledHeight, aInterpolate)
+{
+ colorPtr = aColorCache;
+ alphaPtr = aAlphaCache;
+}
+
+void SavingImageScaler::nextLine() {
+ BasicImageScaler::nextLine();
+ memcpy(colorPtr, colorData(), scaledWidth * nComps);
+ colorPtr += scaledWidth * nComps;
+ if (hasAlpha) {
+ memcpy(alphaPtr, alphaData(), scaledWidth);
+ alphaPtr += scaledWidth;
+ }
+}
+
+//------------------------------------------------------------------------
+// ReplayImageScaler
+//------------------------------------------------------------------------
+
+// "Replay" a scaled image saved by SavingImageScaler.
+class ReplayImageScaler: public ImageScaler {
+public:
+
+ ReplayImageScaler(int aNComps, GBool aHasAlpha,
+ int aScaledWidth,
+ Guchar *aColorCache, Guchar *aAlphaCache);
+ virtual void nextLine();
+ virtual Guchar *colorData() { return colorLine; }
+ virtual Guchar *alphaData() { return alphaLine; }
+
+private:
+
+ int nComps;
+ GBool hasAlpha;
+ int scaledWidth;
+ Guchar *colorPtr;
+ Guchar *alphaPtr;
+ Guchar *colorLine;
+ Guchar *alphaLine;
+};
+
+ReplayImageScaler::ReplayImageScaler(int aNComps, GBool aHasAlpha,
+ int aScaledWidth,
+ Guchar *aColorCache, Guchar *aAlphaCache) {
+ nComps = aNComps;
+ hasAlpha = aHasAlpha;
+ scaledWidth = aScaledWidth;
+ colorPtr = aColorCache;
+ alphaPtr = aAlphaCache;
+ colorLine = NULL;
+ alphaLine = NULL;
+}
+
+void ReplayImageScaler::nextLine() {
+ colorLine = colorPtr;
+ alphaLine = alphaPtr;
+ colorPtr += scaledWidth * nComps;
+ if (hasAlpha) {
+ alphaPtr += scaledWidth;
+ }
+}
+
+//------------------------------------------------------------------------
+// ImageMaskScaler
+//------------------------------------------------------------------------
+
+class ImageMaskScaler {
+public:
+
+ // Set up a MaskScaler to scale from [srcWidth]x[srcHeight] to
+ // [scaledWidth]x[scaledHeight].
+ ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
+ int aSrcWidth, int aSrcHeight,
+ int aScaledWidth, int aScaledHeight, GBool aInterpolate);
+
+ ~ImageMaskScaler();
+
+ // Compute the next line of the scaled image mask. This can be
+ // called up to [scaledHeight] times.
+ void nextLine();
+
+ // Retrieve the data generated by the most recent call to
+ // nextLine().
+ Guchar *data() { return line; }
+
+private:
+
+ void vertDownscaleHorizDownscale();
+ void vertDownscaleHorizUpscaleNoInterp();
+ void vertDownscaleHorizUpscaleInterp();
+ void vertUpscaleHorizDownscaleNoInterp();
+ void vertUpscaleHorizDownscaleInterp();
+ void vertUpscaleHorizUpscaleNoInterp();
+ void vertUpscaleHorizUpscaleInterp();
+
+ // source image data function
+ SplashImageMaskSource src;
+ void *srcData;
+
+ // source image size
+ int srcWidth;
+ int srcHeight;
+
+ // scaled image size
+ int scaledWidth;
+ int scaledHeight;
+
+ // params/state for vertical scaling
+ int yp, yq;
+ int yt, yn;
+ int ySrcCur, yScaledCur;
+ SplashCoord yInvScale;
+
+ // params for horizontal scaling
+ int xp, xq;
+ SplashCoord xInvScale;
+
+ // vertical and horizontal scaling functions
+ void (ImageMaskScaler::*scalingFunc)();
+
+ // temporary buffers for vertical scaling
+ Guchar *tmpBuf0;
+ Guchar *tmpBuf1;
+ Guchar *tmpBuf2;
+ Guint *accBuf;
+
+ // output of horizontal scaling
+ Guchar *line;
+};
+
+ImageMaskScaler::ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
+ int aSrcWidth, int aSrcHeight,
+ int aScaledWidth, int aScaledHeight,
+ GBool aInterpolate) {
+ tmpBuf0 = NULL;
+ tmpBuf1 = NULL;
+ tmpBuf2 = NULL;
+ accBuf = NULL;
+ line = NULL;
+
+ src = aSrc;
+ srcData = aSrcData;
+ srcWidth = aSrcWidth;
+ srcHeight = aSrcHeight;
+ scaledWidth = aScaledWidth;
+ scaledHeight = aScaledHeight;
+
+ // select scaling function; allocate buffers
+ if (scaledHeight <= srcHeight) {
+ // vertical downscaling
+ yp = srcHeight / scaledHeight;
+ yq = srcHeight % scaledHeight;
+ yt = 0;
+ tmpBuf0 = (Guchar *)gmalloc(srcWidth);
+ accBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
+ if (scaledWidth <= srcWidth) {
+ scalingFunc = &ImageMaskScaler::vertDownscaleHorizDownscale;
+ } else {
+ if (aInterpolate) {
+ scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleInterp;
+ } else {
+ scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp;
+ }
+ }
+ } else {
+ // vertical upscaling
+ yp = scaledHeight / srcHeight;
+ yq = scaledHeight % srcHeight;
+ yt = 0;
+ yn = 0;
+ if (aInterpolate) {
+ yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
+ tmpBuf0 = (Guchar *)gmalloc(srcWidth);
+ tmpBuf1 = (Guchar *)gmalloc(srcWidth);
+ ySrcCur = 0;
+ yScaledCur = 0;
+ if (scaledWidth <= srcWidth) {
+ scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleInterp;
+ } else {
+ tmpBuf2 = (Guchar *)gmalloc(srcWidth);
+ scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleInterp;
+ }
+ } else {
+ tmpBuf0 = (Guchar *)gmalloc(srcWidth);
+ if (scaledWidth <= srcWidth) {
+ scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp;
+ } else {
+ scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp;
+ }
+ }
+ }
+ if (scaledWidth <= srcWidth) {
+ xp = srcWidth / scaledWidth;
+ xq = srcWidth % scaledWidth;
+ } else {
+ xp = scaledWidth / srcWidth;
+ xq = scaledWidth % srcWidth;
+ if (aInterpolate) {
+ xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
+ }
+ }
+ line = (Guchar *)gmalloc(scaledWidth);
+}
+
+ImageMaskScaler::~ImageMaskScaler() {
+ gfree(tmpBuf0);
+ gfree(tmpBuf1);
+ gfree(tmpBuf2);
+ gfree(accBuf);
+ gfree(line);
+}
+
+void ImageMaskScaler::nextLine() {
+ (this->*scalingFunc)();
+}
+
+void ImageMaskScaler::vertDownscaleHorizDownscale() {
+ //--- vert downscale
+ int yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+ memset(accBuf, 0, srcWidth * sizeof(Guint));
+ for (int i = 0; i < yStep; ++i) {
+ (*src)(srcData, tmpBuf0);
+ for (int j = 0; j < srcWidth; ++j) {
+ accBuf[j] += tmpBuf0[j];
+ }
+ }
+
+ //--- horiz downscale
+ int acc;
+ int xt = 0;
+ int unscaledIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ acc = 0;
+ for (int i = 0; i < xStep; ++i) {
+ acc += accBuf[unscaledIdx];
+ ++unscaledIdx;
+ }
+ line[scaledIdx] = (Guchar)((255 * acc) / (xStep * yStep));
+ }
+}
+
+void ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp() {
+ //--- vert downscale
+ int yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+ memset(accBuf, 0, srcWidth * sizeof(Guint));
+ for (int i = 0; i < yStep; ++i) {
+ (*src)(srcData, tmpBuf0);
+ for (int j = 0; j < srcWidth; ++j) {
+ accBuf[j] += tmpBuf0[j];
+ }
+ }
+
+ //--- horiz upscale
+ int xt = 0;
+ int scaledIdx = 0;
+ for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= srcWidth) {
+ xt -= srcWidth;
+ ++xStep;
+ }
+ Guchar buf = (Guchar)((255 * accBuf[srcIdx]) / yStep);
+ for (int i = 0; i < xStep; ++i) {
+ line[scaledIdx] = buf;
+ ++scaledIdx;
+ }
+ }
+}
+
+void ImageMaskScaler::vertDownscaleHorizUpscaleInterp() {
+ //--- vert downscale
+ int yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+ memset(accBuf, 0, srcWidth * sizeof(Guint));
+ for (int i = 0; i < yStep; ++i) {
+ (*src)(srcData, tmpBuf0);
+ for (int j = 0; j < srcWidth; ++j) {
+ accBuf[j] += tmpBuf0[j];
+ }
+ }
+ for (int j = 0; j < srcWidth; ++j) {
+ accBuf[j] = (255 * accBuf[j]) / yStep;
+ }
+
+ //--- horiz upscale
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+ int x0 = splashFloor(xs - 0.5);
+ int x1 = x0 + 1;
+ SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
+ SplashCoord s1 = (SplashCoord)1 - s0;
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (x1 >= srcWidth) {
+ x1 = srcWidth - 1;
+ }
+ line[scaledIdx] = (Guchar)(int)(s0 * accBuf[x0] + s1 * accBuf[x1]);
+ }
+}
+
+void ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp() {
+ //--- vert upscale
+ if (yn == 0) {
+ yn = yp;
+ yt += yq;
+ if (yt >= srcHeight) {
+ yt -= srcHeight;
+ ++yn;
+ }
+ (*src)(srcData, tmpBuf0);
+ }
+ --yn;
+
+ //--- horiz downscale
+ int acc;
+ int xt = 0;
+ int unscaledIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ acc = 0;
+ for (int i = 0; i < xStep; ++i) {
+ acc += tmpBuf0[unscaledIdx];
+ ++unscaledIdx;
+ }
+ line[scaledIdx] = (Guchar)((255 * acc) / xStep);
+ }
+}
+
+void ImageMaskScaler::vertUpscaleHorizDownscaleInterp() {
+ //--- vert upscale
+ if (ySrcCur == 0) {
+ (*src)(srcData, tmpBuf0);
+ (*src)(srcData, tmpBuf1);
+ ySrcCur = 1;
+ }
+ SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+ int y0 = splashFloor(ys - 0.5);
+ int y1 = y0 + 1;
+ SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
+ SplashCoord vs1 = (SplashCoord)1 - vs0;
+ if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+ Guchar *t = tmpBuf0;
+ tmpBuf0 = tmpBuf1;
+ tmpBuf1 = t;
+ (*src)(srcData, tmpBuf1);
+ ++ySrcCur;
+ }
+ Guchar *mask0 = tmpBuf0;
+ Guchar *mask1 = tmpBuf1;
+ if (y0 < 0) {
+ y0 = 0;
+ mask1 = mask0;
+ }
+ if (y1 >= srcHeight) {
+ y1 = srcHeight - 1;
+ mask0 = mask1;
+ }
+ ++yScaledCur;
+
+ //--- horiz downscale
+ int acc;
+ int xt = 0;
+ int unscaledIdx = 0;
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ acc = 0;
+ for (int i = 0; i < xStep; ++i) {
+ acc += (int)(vs0 * (int)mask0[unscaledIdx] +
+ vs1 * (int)mask1[unscaledIdx]);
+ ++unscaledIdx;
+ }
+ line[scaledIdx] = (Guchar)((255 * acc) / xStep);
+ }
+}
+
+void ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp() {
+ //--- vert upscale
+ if (yn == 0) {
+ yn = yp;
+ yt += yq;
+ if (yt >= srcHeight) {
+ yt -= srcHeight;
+ ++yn;
+ }
+ (*src)(srcData, tmpBuf0);
+ }
+ --yn;
+
+ //--- horiz upscale
+ int xt = 0;
+ int scaledIdx = 0;
+ for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= srcWidth) {
+ xt -= srcWidth;
+ ++xStep;
+ }
+ Guchar buf = (Guchar)(255 * tmpBuf0[srcIdx]);
+ for (int i = 0; i < xStep; ++i) {
+ line[scaledIdx] = buf;
+ ++scaledIdx;
+ }
+ }
+}
+
+void ImageMaskScaler::vertUpscaleHorizUpscaleInterp() {
+ //--- vert upscale
+ if (ySrcCur == 0) {
+ (*src)(srcData, tmpBuf0);
+ (*src)(srcData, tmpBuf1);
+ ySrcCur = 1;
+ }
+ SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+ int y0 = splashFloor(ys - 0.5);
+ int y1 = y0 + 1;
+ SplashCoord vs0 = (SplashCoord)255 * ((SplashCoord)y1 + 0.5 - ys);
+ SplashCoord vs1 = (SplashCoord)255 - vs0;
+ if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+ Guchar *t = tmpBuf0;
+ tmpBuf0 = tmpBuf1;
+ tmpBuf1 = t;
+ (*src)(srcData, tmpBuf1);
+ ++ySrcCur;
+ }
+ Guchar *mask0 = tmpBuf0;
+ Guchar *mask1 = tmpBuf1;
+ if (y0 < 0) {
+ y0 = 0;
+ mask1 = mask0;
+ }
+ if (y1 >= srcHeight) {
+ y1 = srcHeight - 1;
+ mask0 = mask1;
+ }
+ ++yScaledCur;
+ for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+ tmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)mask0[srcIdx] +
+ vs1 * (int)mask1[srcIdx]);
+ }
+
+ //--- horiz upscale
+ for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+ SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+ int x0 = splashFloor(xs - 0.5);
+ int x1 = x0 + 1;
+ SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
+ SplashCoord hs1 = (SplashCoord)1 - hs0;
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (x1 >= srcWidth) {
+ x1 = srcWidth - 1;
+ }
+ line[scaledIdx] = (Guchar)(int)(hs0 * (int)tmpBuf2[x0] +
+ hs1 * (int)tmpBuf2[x1]);
+ }
+}
+
+//------------------------------------------------------------------------
// Splash
//------------------------------------------------------------------------
@@ -2472,6 +4360,8 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
scanBuf2 = NULL;
}
groupBackBitmap = NULL;
+ groupDestInitMode = splashGroupDestPreInit;
+ overprintMaskBitmap = NULL;
minLineWidth = 0;
clearModRegion();
debugMode = gFalse;
@@ -2499,6 +4389,8 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
scanBuf2 = NULL;
}
groupBackBitmap = NULL;
+ groupDestInitMode = splashGroupDestPreInit;
+ overprintMaskBitmap = NULL;
minLineWidth = 0;
clearModRegion();
debugMode = gFalse;
@@ -2699,14 +4591,23 @@ void Splash::setSoftMask(SplashBitmap *softMask) {
void Splash::setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
int groupBackXA, int groupBackYA,
+ SplashGroupDestInitMode groupDestInitModeA,
GBool nonIsolated, GBool knockout) {
groupBackBitmap = groupBackBitmapA;
groupBackX = groupBackXA;
groupBackY = groupBackYA;
+ groupDestInitMode = groupDestInitModeA;
+ groupDestInitYMin = 1;
+ groupDestInitYMax = 0;
state->inNonIsolatedGroup = nonIsolated;
state->inKnockoutGroup = knockout;
}
+void Splash::forceDeferredInit(int y, int h) {
+ useDestRow(y);
+ useDestRow(y + h - 1);
+}
+
void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
Guchar *gray) {
state->setTransfer(red, green, blue, gray);
@@ -3839,1140 +5740,493 @@ void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax,
}
}
+struct SplashDrawImageMaskRowData {
+ SplashPipe pipe;
+};
+
// The glyphMode flag is not currently used, but may be useful if the
// stroke adjustment behavior is changed.
SplashError Splash::fillImageMask(GString *imageTag,
SplashImageMaskSource src, void *srcData,
int w, int h, SplashCoord *mat,
GBool glyphMode, GBool interpolate) {
- SplashBitmap *scaledMask;
- SplashClipResult clipRes;
- GBool minorAxisZero;
- SplashCoord wSize, hSize, t0, t1;
- int x0, y0, x1, y1, scaledWidth, scaledHeight;
-
if (debugMode) {
printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
w, h, (double)mat[0], (double)mat[1], (double)mat[2],
(double)mat[3], (double)mat[4], (double)mat[5]);
}
- // check for singular matrix
+ //--- check for singular matrix
if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
return splashErrSingularMatrix;
}
- minorAxisZero = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
-
- // rough estimate of size of scaled mask
- t0 = splashAbs(mat[0]);
- t1 = splashAbs(mat[1]);
- wSize = t0 > t1 ? t0 : t1;
- t0 = splashAbs(mat[2]);
- t1 = splashAbs(mat[3]);
- hSize = t0 > t1 ? t0 : t1;
-
- // stream-mode upscaling -- this is slower, so we only use it if the
- // upscaled mask is large (in which case clipping should remove many
- // pixels)
-#if USE_FIXEDPOINT
- if ((wSize > 2 * w && hSize > 2 * h && (int)wSize > 1000000 / (int)hSize) ||
- (wSize > w && hSize > h && (int)wSize > 10000000 / (int)hSize) ||
- ((wSize > w || hSize > h) && (int)wSize > 25000000 / (int)hSize)) {
-#else
- if ((wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) ||
- (wSize > w && hSize > h && wSize * hSize > 10000000) ||
- ((wSize > w || hSize > h) && wSize * hSize > 25000000)) {
- upscaleMask(src, srcData, w, h, mat, glyphMode, interpolate);
-#endif
-
- // scaling only
- } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
- getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
- getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledMask = scaleMask(imageTag, src, srcData, w, h,
- scaledWidth, scaledHeight, interpolate);
- if (imageCache->vertFlip) {
- vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->vertFlip = gFalse;
- }
- if (imageCache->horizFlip) {
- horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->horizFlip = gFalse;
- }
- blitMask(scaledMask, x0, y0, clipRes);
- }
-
- // scaling plus vertical flip
- } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
- getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
- getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledMask = scaleMask(imageTag, src, srcData, w, h,
- scaledWidth, scaledHeight, interpolate);
- if (!imageCache->vertFlip) {
- vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->vertFlip = gTrue;
+ //--- compute image bbox, check clipping
+ GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
+ GBool horizFlip = gFalse;
+ GBool vertFlip = gFalse;
+ int xMin, yMin, xMax, yMax;
+ if (flipsOnly) {
+ horizFlip = mat[0] < 0;
+ vertFlip = mat[3] < 0;
+ if (vertFlip) {
+ if (horizFlip) { // bottom-up, mirrored
+ getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+ getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
+ } else { // bottom-up
+ getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+ getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
}
- if (imageCache->horizFlip) {
- horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->horizFlip = gFalse;
+ } else {
+ if (horizFlip) { // top-down, mirrored
+ getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+ getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
+ } else { // top-down
+ getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+ getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
}
- blitMask(scaledMask, x0, y0, clipRes);
}
+ } else {
+ int xx = splashRound(mat[4]); // (0,0)
+ int yy = splashRound(mat[5]);
+ xMin = xMax = xx;
+ yMin = yMax = yy;
+ xx = splashRound(mat[0] + mat[4]); // (1,0)
+ yy = splashRound(mat[1] + mat[5]);
+ if (xx < xMin) {
+ xMin = xx;
+ } else if (xx > xMax) {
+ xMax = xx;
+ }
+ if (yy < yMin) {
+ yMin = yy;
+ } else if (yy > yMax) {
+ yMax = yy;
+ }
+ xx = splashRound(mat[2] + mat[4]); // (0,1)
+ yy = splashRound(mat[3] + mat[5]);
+ if (xx < xMin) {
+ xMin = xx;
+ } else if (xx > xMax) {
+ xMax = xx;
+ }
+ if (yy < yMin) {
+ yMin = yy;
+ } else if (yy > yMax) {
+ yMax = yy;
+ }
+ xx = splashRound(mat[0] + mat[2] + mat[4]); // (1,1)
+ yy = splashRound(mat[1] + mat[3] + mat[5]);
+ if (xx < xMin) {
+ xMin = xx;
+ } else if (xx > xMax) {
+ xMax = xx;
+ }
+ if (yy < yMin) {
+ yMin = yy;
+ } else if (yy > yMax) {
+ yMax = yy;
+ }
+ if (xMax <= xMin) {
+ xMax = xMin + 1;
+ }
+ if (yMax <= yMin) {
+ yMax = yMin + 1;
+ }
+ }
+ SplashClipResult clipRes =
+ state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
+ state->strokeAdjust);
+ // If the scaled mask is much wider and/or taller than the clip
+ // region, we use the "arbitrary" scaling path, to avoid a
+ // potentially very slow loop in the flips-only path (which scans
+ // the full width and height of the scaled mask, regardless of the
+ // clip region).
+ int clipW = state->clip->getXMaxI(state->strokeAdjust)
+ - state->clip->getXMinI(state->strokeAdjust);
+ int clipH = state->clip->getYMaxI(state->strokeAdjust)
+ - state->clip->getYMinI(state->strokeAdjust);
+ GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) ||
+ ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000);
+
+ //--- set up the SplashDrawImageMaskRowData object and the pipes
+ SplashDrawImageMaskRowData dd;
+ pipeInit(&dd.pipe, state->fillPattern,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ gTrue, gFalse);
+
+ //--- choose the drawRow function
+ SplashDrawImageMaskRowFunc drawRowFunc;
+ if (clipRes == splashClipAllInside) {
+ drawRowFunc = &Splash::drawImageMaskRowNoClip;
+ } else {
+ if (vectorAntialias) {
+ drawRowFunc = &Splash::drawImageMaskRowClipAA;
+ } else {
+ drawRowFunc = &Splash::drawImageMaskRowClipNoAA;
+ }
+ }
- // scaling plus horizontal flip
- } else if (mat[0] < 0 && minorAxisZero && mat[3] > 0) {
- getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
- getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
+ //--- horizontal/vertical flips only
+ if (flipsOnly && !veryLarge) {
if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledMask = scaleMask(imageTag, src, srcData, w, h,
+ int scaledWidth = xMax - xMin;
+ int scaledHeight = yMax - yMin;
+ ImageMaskScaler scaler(src, srcData, w, h,
scaledWidth, scaledHeight, interpolate);
- if (imageCache->vertFlip) {
- vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->vertFlip = gFalse;
- }
- if (!imageCache->horizFlip) {
- horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->horizFlip = gTrue;
+ Guchar *tmpLine = NULL;
+ if (horizFlip) {
+ tmpLine = (Guchar *)gmalloc(scaledWidth);
+ }
+ if (vertFlip) {
+ if (horizFlip) { // bottom-up, mirrored
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth);
+ (this->*drawRowFunc)(&dd, tmpLine,
+ xMin, yMax - 1 - y, scaledWidth);
+ }
+ } else { // bottom-up
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ (this->*drawRowFunc)(&dd, scaler.data(),
+ xMin, yMax - 1 - y, scaledWidth);
+ }
+ }
+ } else {
+ if (horizFlip) { // top-down, mirrored
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth);
+ (this->*drawRowFunc)(&dd, tmpLine,
+ xMin, yMin + y, scaledWidth);
+ }
+ } else { // top-down
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ (this->*drawRowFunc)(&dd, scaler.data(),
+ xMin, yMin + y, scaledWidth);
+ }
+ }
}
- blitMask(scaledMask, x0, y0, clipRes);
+ gfree(tmpLine);
}
- // scaling plus horizontal and vertical flips
- } else if (mat[0] < 0 && minorAxisZero && mat[3] < 0) {
- getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
- getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledMask = scaleMask(imageTag, src, srcData, w, h,
+ //--- arbitrary transform
+ } else {
+ // estimate of size of scaled image
+ int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0]
+ + mat[1] * mat[1]));
+ int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2]
+ + mat[3] * mat[3]));
+ if (scaledWidth < 1) {
+ scaledWidth = 1;
+ }
+ if (scaledHeight < 1) {
+ scaledHeight = 1;
+ }
+ GBool downscaling = gTrue;
+ if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) {
+ downscaling = gFalse;
+ scaledWidth = w;
+ scaledHeight = h;
+ }
+
+ // compute mapping from device space to scaled image space
+ SplashCoord mat1[6];
+ mat1[0] = mat[0] / scaledWidth;
+ mat1[1] = mat[1] / scaledWidth;
+ mat1[2] = mat[2] / scaledHeight;
+ mat1[3] = mat[3] / scaledHeight;
+ mat1[4] = mat[4];
+ mat1[5] = mat[5];
+ SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2];
+ if (splashAbs(det) < 1e-6) {
+ // this should be caught by the singular matrix check in drawImage
+ return splashErrSingularMatrix;
+ }
+ SplashCoord invMat[6];
+ invMat[0] = mat1[3] / det;
+ invMat[1] = -mat1[1] / det;
+ invMat[2] = -mat1[2] / det;
+ invMat[3] = mat1[0] / det;
+ // the extra "+ 0.5 * (...)" terms are here because the
+ // drawImageArbitrary(No)Interp functions multiply by pixel
+ // centers, (x + 0.5, y + 0.5)
+ invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det
+ + (invMat[0] + invMat[2]) * 0.5;
+ invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det
+ + (invMat[1] + invMat[3]) * 0.5;
+
+ // if downscaling: store the downscaled image mask
+ // if upscaling: store the unscaled image mask
+ Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth);
+ if (downscaling) {
+ ImageMaskScaler scaler(src, srcData, w, h,
scaledWidth, scaledHeight, interpolate);
- if (!imageCache->vertFlip) {
- vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->vertFlip = gTrue;
+ Guchar *ptr = scaledMask;
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ memcpy(ptr, scaler.data(), scaledWidth);
+ ptr += scaledWidth;
}
- if (!imageCache->horizFlip) {
- horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->horizFlip = gTrue;
+ } else {
+ Guchar *ptr = scaledMask;
+ for (int y = 0; y < scaledHeight; ++y) {
+ (*src)(srcData, ptr);
+ for (int x = 0; x < scaledWidth; ++x) {
+ *ptr = (Guchar)(*ptr * 255);
+ ++ptr;
+ }
}
- blitMask(scaledMask, x0, y0, clipRes);
}
- // all other cases
- } else {
- arbitraryTransformMask(imageTag, src, srcData, w, h,
- mat, glyphMode, interpolate);
+ // draw it
+ if (interpolate) {
+ drawImageMaskArbitraryInterp(scaledMask,
+ &dd, drawRowFunc, invMat,
+ scaledWidth, scaledHeight,
+ xMin, yMin, xMax, yMax);
+ } else {
+ drawImageMaskArbitraryNoInterp(scaledMask,
+ &dd, drawRowFunc, invMat,
+ scaledWidth, scaledHeight,
+ xMin, yMin, xMax, yMax);
+ }
+
+ // free the downscaled/unscaled image
+ gfree(scaledMask);
}
return splashOk;
}
-// The glyphMode flag is not currently used, but may be useful if the
-// stroke adjustment behavior is changed.
-void Splash::upscaleMask(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- SplashCoord *mat, GBool glyphMode,
- GBool interpolate) {
- SplashClipResult clipRes;
- SplashPipe pipe;
- Guchar *unscaledImage, *p;
- SplashCoord xMin, yMin, xMax, yMax, t;
- SplashCoord mi0, mi1, mi2, mi3, mi4, mi5, det;
- SplashCoord ix, iy, sx, sy, pix0, pix1;
- int xMinI, yMinI, xMaxI, yMaxI, x, y, x0, y0, x1, y1, tt;
-
- // compute the bbox of the target quadrilateral
- xMin = xMax = mat[4];
- t = mat[2] + mat[4];
- if (t < xMin) {
- xMin = t;
- } else if (t > xMax) {
- xMax = t;
- }
- t = mat[0] + mat[2] + mat[4];
- if (t < xMin) {
- xMin = t;
- } else if (t > xMax) {
- xMax = t;
- }
- t = mat[0] + mat[4];
- if (t < xMin) {
- xMin = t;
- } else if (t > xMax) {
- xMax = t;
- }
- getImageBounds(xMin, xMax, &xMinI, &xMaxI);
- yMin = yMax = mat[5];
- t = mat[3] + mat[5];
- if (t < yMin) {
- yMin = t;
- } else if (t > yMax) {
- yMax = t;
- }
- t = mat[1] + mat[3] + mat[5];
- if (t < yMin) {
- yMin = t;
- } else if (t > yMax) {
- yMax = t;
- }
- t = mat[1] + mat[5];
- if (t < yMin) {
- yMin = t;
- } else if (t > yMax) {
- yMax = t;
- }
- getImageBounds(yMin, yMax, &yMinI, &yMaxI);
-
- // clipping
- clipRes = state->clip->testRect(xMinI, yMinI, xMaxI - 1, yMaxI - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes == splashClipAllOutside) {
- return;
- }
- if (clipRes != splashClipAllInside) {
- if ((tt = state->clip->getXMinI(state->strokeAdjust)) > xMinI) {
- xMinI = tt;
- }
- if ((tt = state->clip->getXMaxI(state->strokeAdjust) + 1) < xMaxI) {
- xMaxI = tt;
- }
- if ((tt = state->clip->getYMinI(state->strokeAdjust)) > yMinI) {
- yMinI = tt;
- }
- if ((tt = state->clip->getYMaxI(state->strokeAdjust) + 1) < yMaxI) {
- yMaxI = tt;
- }
- }
-
- // invert the matrix
- det = mat[0] * mat[3] - mat[1] * mat[2];
- if (splashAbs(det) < 1e-6) {
- // this should be caught by the singular matrix check in fillImageMask
+void Splash::drawImageMaskArbitraryNoInterp(
+ Guchar *scaledMask,
+ SplashDrawImageMaskRowData *dd,
+ SplashDrawImageMaskRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax) {
+ int tt = state->clip->getXMinI(state->strokeAdjust);
+ if (tt > xMin) {
+ xMin = tt;
+ }
+ tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+ if (tt < xMax) {
+ xMax = tt;
+ }
+ tt = state->clip->getYMinI(state->strokeAdjust);
+ if (tt > yMin) {
+ yMin = tt;
+ }
+ tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+ if (tt < yMax) {
+ yMax = tt;
+ }
+ if (xMax <= xMin || yMax <= yMin) {
return;
}
- det = (SplashCoord)1 / det;
- mi0 = det * mat[3] * srcWidth;
- mi1 = -det * mat[1] * srcHeight;
- mi2 = -det * mat[2] * srcWidth;
- mi3 = det * mat[0] * srcHeight;
- mi4 = det * (mat[2] * mat[5] - mat[3] * mat[4]) * srcWidth;
- mi5 = -det * (mat[0] * mat[5] - mat[1] * mat[4]) * srcHeight;
- // grab the image
- unscaledImage = (Guchar *)gmallocn(srcWidth, srcHeight);
- for (y = 0, p = unscaledImage; y < srcHeight; ++y, p += srcWidth) {
- (*src)(srcData, p);
- for (x = 0; x < srcWidth; ++x) {
- p[x] = (Guchar)(p[x] * 255);
- }
- }
-
- // draw it
- pipeInit(&pipe, state->fillPattern,
- (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
- for (y = yMinI; y < yMaxI; ++y) {
- for (x = xMinI; x < xMaxI; ++x) {
- ix = ((SplashCoord)x + 0.5) * mi0 + ((SplashCoord)y + 0.5) * mi2 + mi4;
- iy = ((SplashCoord)x + 0.5) * mi1 + ((SplashCoord)y + 0.5) * mi3 + mi5;
- if (interpolate) {
- if (ix >= 0 && ix < srcWidth && iy >= 0 && iy < srcHeight) {
- x0 = splashFloor(ix - 0.5);
- x1 = x0 + 1;
- sx = (ix - 0.5) - x0;
- y0 = splashFloor(iy - 0.5);
- y1 = y0 + 1;
- sy = (iy - 0.5) - y0;
- if (x0 < 0) {
- x0 = 0;
- }
- if (x1 >= srcWidth) {
- x1 = srcWidth - 1;
- }
- if (y0 < 0) {
- y0 = 0;
- }
- if (y1 >= srcHeight) {
- y1 = srcHeight - 1;
- }
- pix0 = ((SplashCoord)1 - sx)
- * (SplashCoord)unscaledImage[y0 * srcWidth + x0]
- + sx * (SplashCoord)unscaledImage[y0 * srcWidth + x1];
- pix1 = ((SplashCoord)1 - sx)
- * (SplashCoord)unscaledImage[y1 * srcWidth + x0]
- + sx * (SplashCoord)unscaledImage[y1 * srcWidth + x1];
- scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
- + sy * pix1);
- } else {
- scanBuf[x] = 0;
- }
- } else {
- x0 = splashFloor(ix);
- y0 = splashFloor(iy);
- if (x0 >= 0 && x0 < srcWidth && y0 >= 0 && y0 < srcHeight) {
- scanBuf[x] = unscaledImage[y0 * srcWidth + x0];
- } else {
- scanBuf[x] = 0;
+ Guchar *buf = (Guchar *)gmalloc(xMax - xMin);
+
+ for (int y = yMin; y < yMax; ++y) {
+ int rowMin = xMax;
+ int rowMax = 0;
+ for (int x = xMin; x < xMax; ++x) {
+ // note: invMat includes a "+0.5" factor so that this is really
+ // a multiply by (x+0.5, y+0.5)
+ int xx = splashFloor((SplashCoord)x * invMat[0]
+ + (SplashCoord)y * invMat[2] + invMat[4]);
+ int yy = splashFloor((SplashCoord)x * invMat[1]
+ + (SplashCoord)y * invMat[3] + invMat[5]);
+ if (xx >= 0 && xx < scaledWidth &&
+ yy >= 0 && yy < scaledHeight) {
+ Guchar *p = scaledMask + (yy * scaledWidth + xx);
+ Guchar *q = buf + (x - xMin);
+ *q = *p;
+ if (x < rowMin) {
+ rowMin = x;
}
+ rowMax = x + 1;
}
}
- if (clipRes != splashClipAllInside) {
- if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, y, xMinI, xMaxI - 1,
- state->strokeAdjust);
- } else {
- state->clip->clipSpanBinary(scanBuf, y, xMinI, xMaxI - 1,
- state->strokeAdjust);
- }
+ if (rowMin < rowMax) {
+ (this->*drawRowFunc)(dd, buf + (rowMin - xMin),
+ rowMin, y, rowMax - rowMin);
}
- (this->*pipe.run)(&pipe, xMinI, xMaxI - 1, y, scanBuf + xMinI, NULL);
}
- gfree(unscaledImage);
+ gfree(buf);
}
-// The glyphMode flag is not currently used, but may be useful if the
-// stroke adjustment behavior is changed.
-void Splash::arbitraryTransformMask(GString *imageTag,
- SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- SplashCoord *mat, GBool glyphMode,
- GBool interpolate) {
- SplashBitmap *scaledMask;
- SplashClipResult clipRes;
- SplashPipe pipe;
- int scaledWidth, scaledHeight, t0, t1;
- SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
- SplashCoord vx[4], vy[4];
- int xMin, yMin, xMax, yMax;
- ImageSection section[3];
- int nSections;
- int bw, y, xa, xb, x, i, xx, yy;
-
- // compute the four vertices of the target quadrilateral
- vx[0] = mat[4]; vy[0] = mat[5];
- vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5];
- vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5];
- vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5];
-
- // clipping
- xMin = splashRound(vx[0]);
- xMax = splashRound(vx[0]);
- yMin = splashRound(vy[0]);
- yMax = splashRound(vy[0]);
- for (i = 1; i < 4; ++i) {
- t0 = splashRound(vx[i]);
- if (t0 < xMin) {
- xMin = t0;
- } else if (t0 > xMax) {
- xMax = t0;
- }
- t1 = splashRound(vy[i]);
- if (t1 < yMin) {
- yMin = t1;
- } else if (t1 > yMax) {
- yMax = t1;
- }
- }
- clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes == splashClipAllOutside) {
- return;
- }
-
- // compute the scale factors
- if (mat[0] >= 0) {
- t0 = splashRound(mat[0] + mat[4]) - splashRound(mat[4]);
- } else {
- t0 = splashRound(mat[4]) - splashRound(mat[0] + mat[4]);
- }
- if (mat[1] >= 0) {
- t1 = splashRound(mat[1] + mat[5]) - splashRound(mat[5]);
- } else {
- t1 = splashRound(mat[5]) - splashRound(mat[1] + mat[5]);
- }
- scaledWidth = t0 > t1 ? t0 : t1;
- if (mat[2] >= 0) {
- t0 = splashRound(mat[2] + mat[4]) - splashRound(mat[4]);
- } else {
- t0 = splashRound(mat[4]) - splashRound(mat[2] + mat[4]);
- }
- if (mat[3] >= 0) {
- t1 = splashRound(mat[3] + mat[5]) - splashRound(mat[5]);
- } else {
- t1 = splashRound(mat[5]) - splashRound(mat[3] + mat[5]);
- }
- scaledHeight = t0 > t1 ? t0 : t1;
- if (scaledWidth == 0) {
- scaledWidth = 1;
- }
- if (scaledHeight == 0) {
- scaledHeight = 1;
- }
-
- // compute the inverse transform (after scaling) matrix
- r00 = mat[0] / scaledWidth;
- r01 = mat[1] / scaledWidth;
- r10 = mat[2] / scaledHeight;
- r11 = mat[3] / scaledHeight;
- det = r00 * r11 - r01 * r10;
- if (splashAbs(det) < 1e-6) {
- // this should be caught by the singular matrix check in fillImageMask
+void Splash::drawImageMaskArbitraryInterp(
+ Guchar *scaledMask,
+ SplashDrawImageMaskRowData *dd,
+ SplashDrawImageMaskRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax) {
+ int tt = state->clip->getXMinI(state->strokeAdjust);
+ if (tt > xMin) {
+ xMin = tt;
+ }
+ tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+ if (tt < xMax) {
+ xMax = tt;
+ }
+ tt = state->clip->getYMinI(state->strokeAdjust);
+ if (tt > yMin) {
+ yMin = tt;
+ }
+ tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+ if (tt < yMax) {
+ yMax = tt;
+ }
+ if (xMax <= xMin || yMax <= yMin) {
return;
}
- ir00 = r11 / det;
- ir01 = -r01 / det;
- ir10 = -r10 / det;
- ir11 = r00 / det;
-
- // scale the input image
- scaledMask = scaleMask(imageTag, src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, interpolate);
- if (imageCache->vertFlip) {
- vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->vertFlip = gFalse;
- }
- if (imageCache->horizFlip) {
- horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
- imageCache->horizFlip = gFalse;
- }
-
- // construct the three sections
- i = 0;
- if (vy[1] < vy[i]) {
- i = 1;
- }
- if (vy[2] < vy[i]) {
- i = 2;
- }
- if (vy[3] < vy[i]) {
- i = 3;
- }
- // NB: if using fixed point, 0.000001 will be truncated to zero,
- // so these two comparisons must be <=, not <
- if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 &&
- vy[(i-1) & 3] < vy[(i+1) & 3]) {
- i = (i-1) & 3;
- }
- if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) {
- section[0].y0 = splashRound(vy[i]);
- section[0].y1 = splashRound(vy[(i+2) & 3]) - 1;
- if (vx[i] < vx[(i+1) & 3]) {
- section[0].ia0 = i;
- section[0].ia1 = (i+3) & 3;
- section[0].ib0 = (i+1) & 3;
- section[0].ib1 = (i+2) & 3;
- } else {
- section[0].ia0 = (i+1) & 3;
- section[0].ia1 = (i+2) & 3;
- section[0].ib0 = i;
- section[0].ib1 = (i+3) & 3;
- }
- nSections = 1;
- } else {
- section[0].y0 = splashRound(vy[i]);
- section[2].y1 = splashRound(vy[(i+2) & 3]) - 1;
- section[0].ia0 = section[0].ib0 = i;
- section[2].ia1 = section[2].ib1 = (i+2) & 3;
- if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
- section[0].ia1 = section[2].ia0 = (i+1) & 3;
- section[0].ib1 = section[2].ib0 = (i+3) & 3;
- } else {
- section[0].ia1 = section[2].ia0 = (i+3) & 3;
- section[0].ib1 = section[2].ib0 = (i+1) & 3;
- }
- if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
- section[1].y0 = splashRound(vy[(i+1) & 3]);
- section[2].y0 = splashRound(vy[(i+3) & 3]);
- if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
- section[1].ia0 = (i+1) & 3;
- section[1].ia1 = (i+2) & 3;
- section[1].ib0 = i;
- section[1].ib1 = (i+3) & 3;
- } else {
- section[1].ia0 = i;
- section[1].ia1 = (i+3) & 3;
- section[1].ib0 = (i+1) & 3;
- section[1].ib1 = (i+2) & 3;
- }
- } else {
- section[1].y0 = splashRound(vy[(i+3) & 3]);
- section[2].y0 = splashRound(vy[(i+1) & 3]);
- if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
- section[1].ia0 = i;
- section[1].ia1 = (i+1) & 3;
- section[1].ib0 = (i+3) & 3;
- section[1].ib1 = (i+2) & 3;
- } else {
- section[1].ia0 = (i+3) & 3;
- section[1].ia1 = (i+2) & 3;
- section[1].ib0 = i;
- section[1].ib1 = (i+1) & 3;
- }
- }
- section[0].y1 = section[1].y0 - 1;
- section[1].y1 = section[2].y0 - 1;
- nSections = 3;
- }
- for (i = 0; i < nSections; ++i) {
- section[i].xa0 = vx[section[i].ia0];
- section[i].ya0 = vy[section[i].ia0];
- section[i].xa1 = vx[section[i].ia1];
- section[i].ya1 = vy[section[i].ia1];
- section[i].xb0 = vx[section[i].ib0];
- section[i].yb0 = vy[section[i].ib0];
- section[i].xb1 = vx[section[i].ib1];
- section[i].yb1 = vy[section[i].ib1];
- section[i].dxdya = (section[i].xa1 - section[i].xa0) /
- (section[i].ya1 - section[i].ya0);
- section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
- (section[i].yb1 - section[i].yb0);
- }
-
- // initialize the pixel pipe
- pipeInit(&pipe, state->fillPattern,
- (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
- // make sure narrow images cover at least one pixel
- if (nSections == 1) {
- if (section[0].y0 == section[0].y1) {
- ++section[0].y1;
- clipRes = opClipRes = splashClipPartial;
- }
- } else {
- if (section[0].y0 == section[2].y1) {
- ++section[1].y1;
- clipRes = opClipRes = splashClipPartial;
- }
- }
-
- // scan all pixels inside the target region
- bw = bitmap->width;
- for (i = 0; i < nSections; ++i) {
- for (y = section[i].y0; y <= section[i].y1; ++y) {
- xa = splashRound(section[i].xa0 +
- ((SplashCoord)y + 0.5 - section[i].ya0) *
- section[i].dxdya);
- xb = splashRound(section[i].xb0 +
- ((SplashCoord)y + 0.5 - section[i].yb0) *
- section[i].dxdyb);
- if (xa > xb) {
- continue;
- }
- // make sure narrow images cover at least one pixel
- if (xa == xb) {
- ++xb;
- }
- // check the scanBuf bounds
- if (xa >= bw || xb < 0) {
- continue;
- }
- if (xa < 0) {
- xa = 0;
- }
- if (xb > bw) {
- xb = bw;
- }
- // get the scan line
- for (x = xa; x < xb; ++x) {
- // map (x+0.5, y+0.5) back to the scaled image
- xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
- ((SplashCoord)y + 0.5 - mat[5]) * ir10);
- yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
- ((SplashCoord)y + 0.5 - mat[5]) * ir11);
- // xx should always be within bounds, but floating point
- // inaccuracy can cause problems
- if (xx < 0) {
- xx = 0;
- } else if (xx >= scaledWidth) {
- xx = scaledWidth - 1;
+ Guchar *buf = (Guchar *)gmalloc(xMax - xMin);
+
+ for (int y = yMin; y < yMax; ++y) {
+ int rowMin = xMax;
+ int rowMax = 0;
+ for (int x = xMin; x < xMax; ++x) {
+ // note: invMat includes a "+0.5" factor so that this is really
+ // a multiply by (x+0.5, y+0.5)
+ SplashCoord xs = (SplashCoord)x * invMat[0]
+ + (SplashCoord)y * invMat[2] + invMat[4];
+ SplashCoord ys = (SplashCoord)x * invMat[1]
+ + (SplashCoord)y * invMat[3] + invMat[5];
+ int x0 = splashFloor(xs - 0.5);
+ int x1 = x0 + 1;
+ int y0 = splashFloor(ys - 0.5);
+ int y1 = y0 + 1;
+ if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) {
+ SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs;
+ SplashCoord sx1 = (SplashCoord)1 - sx0;
+ SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys;
+ SplashCoord sy1 = (SplashCoord)1 - sy0;
+ if (x0 < 0) {
+ x0 = 0;
}
- if (yy < 0) {
- yy = 0;
- } else if (yy >= scaledHeight) {
- yy = scaledHeight - 1;
+ if (x1 >= scaledWidth) {
+ x1 = scaledWidth - 1;
}
- scanBuf[x] = scaledMask->data[yy * scaledWidth + xx];
- }
- // clip the scan line
- if (clipRes != splashClipAllInside) {
- if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, y, xa, xb - 1, state->strokeAdjust);
- } else {
- state->clip->clipSpanBinary(scanBuf, y, xa, xb - 1,
- state->strokeAdjust);
+ if (y0 < 0) {
+ y0 = 0;
}
- }
- // draw the scan line
- (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, NULL);
- }
- }
-}
-
-// Scale an image mask into a SplashBitmap.
-SplashBitmap *Splash::scaleMask(GString *imageTag,
- SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- GBool interpolate) {
- if (imageCache->tag && imageTag &&
- !imageCache->tag->cmp(imageTag) &&
- imageCache->isMask &&
- imageCache->width == scaledWidth &&
- imageCache->height == scaledHeight &&
- imageCache->interpolate == interpolate) {
- return imageCache->image;
- }
- if (imageCache->tag) {
- delete imageCache->tag;
- }
- if (imageCache->image) {
- delete imageCache->image;
- }
- imageCache->tag = imageTag ? imageTag->copy() : (GString *)NULL;
- imageCache->isMask = gTrue;
- imageCache->width = scaledWidth;
- imageCache->height = scaledHeight;
- imageCache->interpolate = interpolate;
- imageCache->vertFlip = gFalse;
- imageCache->horizFlip = gFalse;
- imageCache->image = new SplashBitmap(scaledWidth, scaledHeight,
- 1, splashModeMono8, gFalse,
- gTrue, NULL);
- if (scaledHeight < srcHeight) {
- if (scaledWidth < srcWidth) {
- scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, imageCache->image);
- } else {
- scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, imageCache->image);
- }
- } else {
- if (scaledWidth < srcWidth) {
- scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, imageCache->image);
- } else {
- if (interpolate) {
- scaleMaskYuXuI(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, imageCache->image);
- } else {
- scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
- scaledWidth, scaledHeight, imageCache->image);
- }
- }
- }
- return imageCache->image;
-}
-
-void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf;
- Guint *pixBuf;
- Guint pix;
- Guchar *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
- int i, j;
-
- // Bresenham parameters for y scale
- yp = srcHeight / scaledHeight;
- yq = srcHeight % scaledHeight;
-
- // Bresenham parameters for x scale
- xp = srcWidth / scaledWidth;
- xq = srcWidth % scaledWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmalloc(srcWidth);
- pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
-
- // init y scale Bresenham
- yt = 0;
-
- destPtr = dest->data;
- for (y = 0; y < scaledHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= scaledHeight) {
- yt -= scaledHeight;
- yStep = yp + 1;
- } else {
- yStep = yp;
- }
-
- // read rows from image
- memset(pixBuf, 0, srcWidth * sizeof(int));
- for (i = 0; i < yStep; ++i) {
- (*src)(srcData, lineBuf);
- for (j = 0; j < srcWidth; ++j) {
- pixBuf[j] += lineBuf[j];
+ if (y1 >= scaledHeight) {
+ y1 = scaledHeight - 1;
+ }
+ Guchar *p00 = scaledMask + (y0 * scaledWidth + x0);
+ Guchar *p10 = scaledMask + (y0 * scaledWidth + x1);
+ Guchar *p01 = scaledMask + (y1 * scaledWidth + x0);
+ Guchar *p11 = scaledMask + (y1 * scaledWidth + x1);
+ Guchar *q = buf + (x - xMin);
+ *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) +
+ sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11));
+ if (x < rowMin) {
+ rowMin = x;
+ }
+ rowMax = x + 1;
}
}
-
- // init x scale Bresenham
- xt = 0;
- d0 = (255 << 23) / (yStep * xp);
- d1 = (255 << 23) / (yStep * (xp + 1));
-
- xx = 0;
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= scaledWidth) {
- xt -= scaledWidth;
- xStep = xp + 1;
- d = d1;
- } else {
- xStep = xp;
- d = d0;
- }
-
- // compute the final pixel
- pix = 0;
- for (i = 0; i < xStep; ++i) {
- pix += pixBuf[xx++];
- }
- // (255 * pix) / xStep * yStep
- pix = (pix * d + (1 << 22)) >> 23;
-
- // store the pixel
- *destPtr++ = (Guchar)pix;
+ if (rowMin < rowMax) {
+ (this->*drawRowFunc)(dd, buf + (rowMin - xMin),
+ rowMin, y, rowMax - rowMin);
}
}
- gfree(pixBuf);
- gfree(lineBuf);
+ gfree(buf);
}
-void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf;
- Guint *pixBuf;
- Guint pix;
- Guchar *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
- int i, j;
-
- // Bresenham parameters for y scale
- yp = srcHeight / scaledHeight;
- yq = srcHeight % scaledHeight;
-
- // Bresenham parameters for x scale
- xp = scaledWidth / srcWidth;
- xq = scaledWidth % srcWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmalloc(srcWidth);
- pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+void Splash::mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width) {
+ Guchar *p, *q;
- // init y scale Bresenham
- yt = 0;
-
- destPtr = dest->data;
- for (y = 0; y < scaledHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= scaledHeight) {
- yt -= scaledHeight;
- yStep = yp + 1;
- } else {
- yStep = yp;
- }
-
- // read rows from image
- memset(pixBuf, 0, srcWidth * sizeof(int));
- for (i = 0; i < yStep; ++i) {
- (*src)(srcData, lineBuf);
- for (j = 0; j < srcWidth; ++j) {
- pixBuf[j] += lineBuf[j];
- }
- }
-
- // init x scale Bresenham
- xt = 0;
- d = (255 << 23) / yStep;
-
- for (x = 0; x < srcWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= srcWidth) {
- xt -= srcWidth;
- xStep = xp + 1;
- } else {
- xStep = xp;
- }
-
- // compute the final pixel
- pix = pixBuf[x];
- // (255 * pix) / yStep
- pix = (pix * d + (1 << 22)) >> 23;
-
- // store the pixel
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (Guchar)pix;
- }
- }
+ p = maskIn;
+ q = maskOut + (width - 1);
+ for (int i = 0; i < width; ++i) {
+ *q = *p;
+ ++p;
+ --q;
}
-
- gfree(pixBuf);
- gfree(lineBuf);
}
-void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf;
- Guint pix;
- Guchar *destPtr0, *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
- int i;
-
- // Bresenham parameters for y scale
- yp = scaledHeight / srcHeight;
- yq = scaledHeight % srcHeight;
-
- // Bresenham parameters for x scale
- xp = srcWidth / scaledWidth;
- xq = srcWidth % scaledWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmalloc(srcWidth);
-
- // init y scale Bresenham
- yt = 0;
-
- destPtr0 = dest->data;
- for (y = 0; y < srcHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= srcHeight) {
- yt -= srcHeight;
- yStep = yp + 1;
- } else {
- yStep = yp;
- }
-
- // read row from image
- (*src)(srcData, lineBuf);
-
- // init x scale Bresenham
- xt = 0;
- d0 = (255 << 23) / xp;
- d1 = (255 << 23) / (xp + 1);
-
- xx = 0;
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= scaledWidth) {
- xt -= scaledWidth;
- xStep = xp + 1;
- d = d1;
- } else {
- xStep = xp;
- d = d0;
- }
-
- // compute the final pixel
- pix = 0;
- for (i = 0; i < xStep; ++i) {
- pix += lineBuf[xx++];
- }
- // (255 * pix) / xStep
- pix = (pix * d + (1 << 22)) >> 23;
-
- // store the pixel
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + i * scaledWidth + x;
- *destPtr = (Guchar)pix;
- }
- }
-
- destPtr0 += yStep * scaledWidth;
- }
-
- gfree(lineBuf);
+void Splash::drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width) {
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, maskData, NULL);
}
-void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf;
- Guchar pix;
- Guchar *srcPtr, *destPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep;
- int i;
-
- // Bresenham parameters for y scale
- yp = scaledHeight / srcHeight;
- yq = scaledHeight % srcHeight;
-
- // Bresenham parameters for x scale
- xp = scaledWidth / srcWidth;
- xq = scaledWidth % srcWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmalloc(srcWidth);
-
- // init y scale Bresenham
- yt = 0;
-
- destPtr = dest->data;
- for (y = 0; y < srcHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= srcHeight) {
- yt -= srcHeight;
- yStep = yp + 1;
- } else {
- yStep = yp;
- }
-
- // read row from image
- (*src)(srcData, lineBuf);
-
- // init x scale Bresenham
- xt = 0;
-
- // generate one row
- srcPtr = lineBuf;
- for (x = 0; x < srcWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= srcWidth) {
- xt -= srcWidth;
- xStep = xp + 1;
- } else {
- xStep = xp;
- }
-
- // compute the final pixel
- pix = *srcPtr ? 255 : 0;
- ++srcPtr;
-
- // duplicate the pixel horizontally
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = pix;
- }
- }
-
- // duplicate the row vertically
- for (i = 1 ; i < yStep; ++i) {
- memcpy(destPtr, destPtr - scaledWidth, scaledWidth);
- destPtr += scaledWidth;
- }
+void Splash::drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width) {
+ if (y < 0 || y >= bitmap->height) {
+ return;
}
-
- gfree(lineBuf);
+ if (x < 0) {
+ maskData -= x;
+ width += x;
+ x = 0;
+ }
+ if (x + width > bitmap->width) {
+ width = bitmap->width - x;
+ }
+ if (width <= 0) {
+ return;
+ }
+ memcpy(scanBuf + x, maskData, width);
+ state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
+ state->strokeAdjust);
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ scanBuf + x, NULL);
}
-void Splash::scaleMaskYuXuI(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf0, *lineBuf1, *tBuf;
- Guchar pix;
- SplashCoord yr, xr, ys, xs, ySrc, xSrc;
- int ySrc0, ySrc1, yBuf, xSrc0, xSrc1, y, x;
- Guchar *destPtr;
-
- // ratios
- yr = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
- xr = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
-
- // allocate buffers
- lineBuf0 = (Guchar *)gmalloc(scaledWidth);
- lineBuf1 = (Guchar *)gmalloc(scaledWidth);
-
- // read first two rows
- (*src)(srcData, lineBuf0);
- if (srcHeight > 1) {
- (*src)(srcData, lineBuf1);
- yBuf = 1;
- } else {
- memcpy(lineBuf1, lineBuf0, srcWidth);
- yBuf = 0;
- }
-
- // interpolate first two rows
- for (x = scaledWidth - 1; x >= 0; --x) {
- xSrc = xr * x;
- xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
- xSrc1 = xSrc0 + 1;
- xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
- if (xSrc0 < 0) {
- xSrc0 = 0;
- }
- if (xSrc1 >= srcWidth) {
- xSrc1 = srcWidth - 1;
- }
- lineBuf0[x] = (Guchar)(int)
- ((xs * (int)lineBuf0[xSrc0] +
- ((SplashCoord)1 - xs) * (int)lineBuf0[xSrc1]) * 255);
- lineBuf1[x] = (Guchar)(int)
- ((xs * (int)lineBuf1[xSrc0] +
- ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1]) * 255);
- }
-
- destPtr = dest->data;
- for (y = 0; y < scaledHeight; ++y) {
-
- // compute vertical interpolation parameters
- ySrc = yr * y;
- ySrc0 = splashFloor(ySrc + yr * 0.5 - 0.5);
- ySrc1 = ySrc0 + 1;
- ys = ((SplashCoord)ySrc1 + 0.5) - (ySrc + yr * 0.5);
- if (ySrc0 < 0) {
- ySrc0 = 0;
- ys = 1;
- }
- if (ySrc1 >= srcHeight) {
- ySrc1 = srcHeight - 1;
- ys = 0;
- }
-
- // read another row (if necessary)
- if (ySrc1 > yBuf) {
- tBuf = lineBuf0;
- lineBuf0 = lineBuf1;
- lineBuf1 = tBuf;
- (*src)(srcData, lineBuf1);
-
- // interpolate the row
- for (x = scaledWidth - 1; x >= 0; --x) {
- xSrc = xr * x;
- xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
- xSrc1 = xSrc0 + 1;
- xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
- if (xSrc0 < 0) {
- xSrc0 = 0;
- }
- if (xSrc1 >= srcWidth) {
- xSrc1 = srcWidth - 1;
- }
- lineBuf1[x] = (Guchar)(int)
- ((xs * (int)lineBuf1[xSrc0] +
- ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1]) * 255);
- }
-
- ++yBuf;
- }
-
- // do the vertical interpolation
- for (x = 0; x < scaledWidth; ++x) {
-
- pix = (Guchar)(int)(ys * (int)lineBuf0[x] +
- ((SplashCoord)1 - ys) * (int)lineBuf1[x]);
-
- // store the pixel
- *destPtr++ = pix;
- }
+void Splash::drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width) {
+ if (y < 0 || y >= bitmap->height) {
+ return;
}
-
- gfree(lineBuf1);
- gfree(lineBuf0);
+ if (x < 0) {
+ maskData -= x;
+ width += x;
+ x = 0;
+ }
+ if (x + width > bitmap->width) {
+ width = bitmap->width - x;
+ }
+ if (width <= 0) {
+ return;
+ }
+ memcpy(scanBuf + x, maskData, width);
+ state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ scanBuf + x, NULL);
}
-void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
- SplashClipResult clipRes) {
+struct SplashDrawImageRowData {
+ int nComps;
+ GBool srcAlpha;
SplashPipe pipe;
- int w, h, x0, x1, y0, y1, y, t;
-
- w = src->width;
- h = src->height;
- pipeInit(&pipe, state->fillPattern,
- (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
- if (clipRes == splashClipAllInside) {
- for (y = 0; y < h; ++y) {
- (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
- src->data + y * (size_t)w, NULL);
- }
- } else {
- x0 = xDest;
- if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
- x0 = t;
- }
- x1 = xDest + w;
- if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
- x1 = t;
- }
- y0 = yDest;
- if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
- y0 = t;
- }
- y1 = yDest + h;
- if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
- y1 = t;
- }
- if (x0 < x1 && y0 < y1) {
- for (y = y0; y < y1; ++y) {
- memcpy(scanBuf + x0,
- src->data + (y - yDest) * (size_t)w + (x0 - xDest),
- x1 - x0);
- if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, y, x0, x1 - 1,
- state->strokeAdjust);
- } else {
- state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1,
- state->strokeAdjust);
- }
- (this->*pipe.run)(&pipe, x0, x1 - 1, y, scanBuf + x0, NULL);
- }
- }
- }
-}
+};
SplashError Splash::drawImage(GString *imageTag,
SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
int w, int h, SplashCoord *mat,
GBool interpolate) {
- GBool ok;
- SplashBitmap *scaledImg;
- SplashClipResult clipRes;
- GBool minorAxisZero;
- SplashCoord wSize, hSize, t0, t1;
- int x0, y0, x1, y1, scaledWidth, scaledHeight;
- int nComps;
-
if (debugMode) {
printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
(double)mat[3], (double)mat[4], (double)mat[5]);
}
- // check color modes
- ok = gFalse; // make gcc happy
- nComps = 0; // make gcc happy
+ //--- check color modes
+ GBool ok = gFalse;
+ int nComps = 0;
switch (bitmap->mode) {
case splashModeMono1:
case splashModeMono8:
@@ -4998,1665 +6252,727 @@ SplashError Splash::drawImage(GString *imageTag,
return splashErrModeMismatch;
}
- // check for singular matrix
+ //--- check for singular matrix
if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
return splashErrSingularMatrix;
}
- minorAxisZero = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
-
- // rough estimate of size of scaled image
- t0 = splashAbs(mat[0]);
- t1 = splashAbs(mat[1]);
- wSize = t0 > t1 ? t0 : t1;
- t0 = splashAbs(mat[2]);
- t1 = splashAbs(mat[3]);
- hSize = t0 > t1 ? t0 : t1;
-
- // stream-mode upscaling -- this is slower, so we only use it if the
- // upscaled image is large (in which case clipping should remove
- // many pixels)
-#if USE_FIXEDPOINT
- if ((wSize > 2 * w && hSize > 2 * h && (int)wSize > 1000000 / (int)hSize) ||
- (wSize > w && hSize > h && (int)wSize > 10000000 / (int)hSize) ||
- ((wSize > w || hSize > h) && (int)wSize > 25000000 / (int)hSize)) {
-#else
- if ((wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) ||
- (wSize > w && hSize > h && wSize * hSize > 10000000) ||
- ((wSize > w || hSize > h) && wSize * hSize > 25000000)) {
-#endif
- upscaleImage(src, srcData, srcMode, nComps, srcAlpha,
- w, h, mat, interpolate);
-
- // scaling only
- } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
- getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
- getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledImg = scaleImage(imageTag,
- src, srcData, srcMode, nComps, srcAlpha, w, h,
- scaledWidth, scaledHeight, interpolate);
- if (imageCache->vertFlip) {
- vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->vertFlip = gFalse;
- }
- if (imageCache->horizFlip) {
- horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->horizFlip = gFalse;
- }
- blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
- }
-
- // scaling plus vertical flip
- } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
- getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
- getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledImg = scaleImage(imageTag,
- src, srcData, srcMode, nComps, srcAlpha, w, h,
- scaledWidth, scaledHeight, interpolate);
- if (!imageCache->vertFlip) {
- vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->vertFlip = gTrue;
- }
- if (imageCache->horizFlip) {
- horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->horizFlip = gFalse;
- }
- blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
- }
-
- // scaling plus horizontal flip
- } else if (mat[0] < 0 && minorAxisZero && mat[3] > 0) {
- getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
- getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledImg = scaleImage(imageTag,
- src, srcData, srcMode, nComps, srcAlpha, w, h,
- scaledWidth, scaledHeight, interpolate);
- if (imageCache->vertFlip) {
- vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->vertFlip = gFalse;
- }
- if (!imageCache->horizFlip) {
- horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->horizFlip = gTrue;
- }
- blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
- }
-
- // scaling plus horizontal and vertical flips
- } else if (mat[0] < 0 && minorAxisZero && mat[3] < 0) {
- getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
- getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
- clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes != splashClipAllOutside) {
- scaledWidth = x1 - x0;
- scaledHeight = y1 - y0;
- scaledImg = scaleImage(imageTag,
- src, srcData, srcMode, nComps, srcAlpha, w, h,
- scaledWidth, scaledHeight, interpolate);
- if (!imageCache->vertFlip) {
- vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->vertFlip = gTrue;
+ //--- compute image bbox, check clipping
+ GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
+ GBool horizFlip = gFalse;
+ GBool vertFlip = gFalse;
+ int xMin, yMin, xMax, yMax;
+ if (flipsOnly) {
+ horizFlip = mat[0] < 0;
+ vertFlip = mat[3] < 0;
+ if (vertFlip) {
+ if (horizFlip) { // bottom-up, mirrored
+ getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+ getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
+ } else { // bottom-up
+ getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+ getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
}
- if (!imageCache->horizFlip) {
- horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->horizFlip = gTrue;
+ } else {
+ if (horizFlip) { // top-down, mirrored
+ getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+ getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
+ } else { // top-down
+ getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+ getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
}
- blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
}
-
- // all other cases
} else {
- arbitraryTransformImage(imageTag, src, srcData, srcMode, nComps, srcAlpha,
- w, h, mat, interpolate);
- }
-
- return splashOk;
-}
-
-void Splash::upscaleImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- SplashCoord *mat, GBool interpolate) {
- SplashClipResult clipRes;
- SplashPipe pipe;
- SplashColorPtr unscaledImage, pixelBuf, p, q, q00, q01, q10, q11;
- Guchar *unscaledAlpha, *alphaPtr;
- SplashCoord xMin, yMin, xMax, yMax, t;
- SplashCoord mi0, mi1, mi2, mi3, mi4, mi5, det;
- SplashCoord ix, iy, sx, sy, pix0, pix1;
- SplashBitmapRowSize rowSize;
- int xMinI, yMinI, xMaxI, yMaxI, x, y, x0, y0, x1, y1, tt, i;
-
- // compute the bbox of the target quadrilateral
- xMin = xMax = mat[4];
- t = mat[2] + mat[4];
- if (t < xMin) {
- xMin = t;
- } else if (t > xMax) {
- xMax = t;
- }
- t = mat[0] + mat[2] + mat[4];
- if (t < xMin) {
- xMin = t;
- } else if (t > xMax) {
- xMax = t;
- }
- t = mat[0] + mat[4];
- if (t < xMin) {
- xMin = t;
- } else if (t > xMax) {
- xMax = t;
- }
- getImageBounds(xMin, xMax, &xMinI, &xMaxI);
- yMin = yMax = mat[5];
- t = mat[3] + mat[5];
- if (t < yMin) {
- yMin = t;
- } else if (t > yMax) {
- yMax = t;
- }
- t = mat[1] + mat[3] + mat[5];
- if (t < yMin) {
- yMin = t;
- } else if (t > yMax) {
- yMax = t;
- }
- t = mat[1] + mat[5];
- if (t < yMin) {
- yMin = t;
- } else if (t > yMax) {
- yMax = t;
- }
- getImageBounds(yMin, yMax, &yMinI, &yMaxI);
-
- // clipping
- clipRes = state->clip->testRect(xMinI, yMinI, xMaxI - 1, yMaxI - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes == splashClipAllOutside) {
- return;
- }
- if (clipRes != splashClipAllInside) {
- if ((tt = state->clip->getXMinI(state->strokeAdjust)) > xMinI) {
- xMinI = tt;
- }
- if ((tt = state->clip->getXMaxI(state->strokeAdjust) + 1) < xMaxI) {
- xMaxI = tt;
- }
- if ((tt = state->clip->getYMinI(state->strokeAdjust)) > yMinI) {
- yMinI = tt;
- }
- if ((tt = state->clip->getYMaxI(state->strokeAdjust) + 1) < yMaxI) {
- yMaxI = tt;
- }
- }
+ int xx = splashRound(mat[4]); // (0,0)
+ int yy = splashRound(mat[5]);
+ xMin = xMax = xx;
+ yMin = yMax = yy;
+ xx = splashRound(mat[0] + mat[4]); // (1,0)
+ yy = splashRound(mat[1] + mat[5]);
+ if (xx < xMin) {
+ xMin = xx;
+ } else if (xx > xMax) {
+ xMax = xx;
+ }
+ if (yy < yMin) {
+ yMin = yy;
+ } else if (yy > yMax) {
+ yMax = yy;
+ }
+ xx = splashRound(mat[2] + mat[4]); // (0,1)
+ yy = splashRound(mat[3] + mat[5]);
+ if (xx < xMin) {
+ xMin = xx;
+ } else if (xx > xMax) {
+ xMax = xx;
+ }
+ if (yy < yMin) {
+ yMin = yy;
+ } else if (yy > yMax) {
+ yMax = yy;
+ }
+ xx = splashRound(mat[0] + mat[2] + mat[4]); // (1,1)
+ yy = splashRound(mat[1] + mat[3] + mat[5]);
+ if (xx < xMin) {
+ xMin = xx;
+ } else if (xx > xMax) {
+ xMax = xx;
+ }
+ if (yy < yMin) {
+ yMin = yy;
+ } else if (yy > yMax) {
+ yMax = yy;
+ }
+ if (xMax <= xMin) {
+ xMax = xMin + 1;
+ }
+ if (yMax <= yMin) {
+ yMax = yMin + 1;
+ }
+ }
+ SplashClipResult clipRes =
+ state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
+ state->strokeAdjust);
+ // If the scaled image is much wider and/or taller than the clip
+ // region, we use the arbitrary transform path, to avoid a
+ // potentially very slow loop in the flips-only path (which scans
+ // the full width and height of the scaled image, regardless of the
+ // clip region).
+ int clipW = state->clip->getXMaxI(state->strokeAdjust)
+ - state->clip->getXMinI(state->strokeAdjust);
+ int clipH = state->clip->getYMaxI(state->strokeAdjust)
+ - state->clip->getYMinI(state->strokeAdjust);
+ GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) ||
+ ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000);
+
+ //--- set up the SplashDrawImageRowData object and the pipes
+ SplashDrawImageRowData dd;
+ dd.nComps = nComps;
+ dd.srcAlpha = srcAlpha;
+ pipeInit(&dd.pipe, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ clipRes != splashClipAllInside || srcAlpha,
+ gFalse);
- // invert the matrix
- det = mat[0] * mat[3] - mat[1] * mat[2];
- if (splashAbs(det) < 1e-6) {
- // this should be caught by the singular matrix check in fillImageMask
- return;
- }
- det = (SplashCoord)1 / det;
- mi0 = det * mat[3] * srcWidth;
- mi1 = -det * mat[1] * srcHeight;
- mi2 = -det * mat[2] * srcWidth;
- mi3 = det * mat[0] * srcHeight;
- mi4 = det * (mat[2] * mat[5] - mat[3] * mat[4]) * srcWidth;
- mi5 = -det * (mat[0] * mat[5] - mat[1] * mat[4]) * srcHeight;
-
- // grab the image
- if (srcWidth > INT_MAX / nComps) {
- rowSize = -1;
- } else {
- rowSize = srcWidth * nComps;
- }
- unscaledImage = (SplashColorPtr)gmallocn64(srcHeight, rowSize);
- if (srcAlpha) {
- unscaledAlpha = (Guchar *)gmallocn(srcHeight, srcWidth);
- for (y = 0, p = unscaledImage, alphaPtr = unscaledAlpha;
- y < srcHeight;
- ++y, p += rowSize, alphaPtr += srcWidth) {
- (*src)(srcData, p, alphaPtr);
+ //--- choose the drawRow function
+ SplashDrawImageRowFunc drawRowFunc;
+ if (clipRes == splashClipAllInside) {
+ if (srcAlpha) {
+ drawRowFunc = &Splash::drawImageRowNoClipAlpha;
+ } else {
+ drawRowFunc = &Splash::drawImageRowNoClipNoAlpha;
}
} else {
- unscaledAlpha = NULL;
- for (y = 0, p = unscaledImage; y < srcHeight; ++y, p += rowSize) {
- (*src)(srcData, p, NULL);
- }
- }
-
- // draw it
- pixelBuf = (SplashColorPtr)gmallocn(xMaxI - xMinI, nComps);
- pipeInit(&pipe, NULL,
- (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
- for (y = yMinI; y < yMaxI; ++y) {
- p = pixelBuf;
- for (x = xMinI; x < xMaxI; ++x) {
- ix = ((SplashCoord)x + 0.5) * mi0 + ((SplashCoord)y + 0.5) * mi2 + mi4;
- iy = ((SplashCoord)x + 0.5) * mi1 + ((SplashCoord)y + 0.5) * mi3 + mi5;
- if (interpolate) {
- if (ix >= 0 && ix < srcWidth && iy >= 0 && iy < srcHeight) {
- x0 = splashFloor(ix - 0.5);
- x1 = x0 + 1;
- sx = (ix - 0.5) - x0;
- y0 = splashFloor(iy - 0.5);
- y1 = y0 + 1;
- sy = (iy - 0.5) - y0;
- if (x0 < 0) {
- x0 = 0;
- }
- if (x1 >= srcWidth) {
- x1 = srcWidth - 1;
- }
- if (y0 < 0) {
- y0 = 0;
- }
- if (y1 >= srcHeight) {
- y1 = srcHeight - 1;
- }
- q00 = &unscaledImage[y0 * rowSize + (SplashBitmapRowSize)x0 * nComps];
- q01 = &unscaledImage[y0 * rowSize + (SplashBitmapRowSize)x1 * nComps];
- q10 = &unscaledImage[y1 * rowSize + (SplashBitmapRowSize)x0 * nComps];
- q11 = &unscaledImage[y1 * rowSize + (SplashBitmapRowSize)x1 * nComps];
- for (i = 0; i < nComps; ++i) {
- pix0 = ((SplashCoord)1 - sx) * (int)*q00++ + sx * (int)*q01++;
- pix1 = ((SplashCoord)1 - sx) * (int)*q10++ + sx * (int)*q11++;
- *p++ = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
- + sy * pix1);
- }
- if (srcAlpha) {
- pix0 = ((SplashCoord)1 - sx)
- * (SplashCoord)unscaledAlpha[y0 * srcWidth + x0]
- + sx * (SplashCoord)unscaledAlpha[y0 * srcWidth + x1];
- pix1 = ((SplashCoord)1 - sx)
- * (SplashCoord)unscaledAlpha[y1 * srcWidth + x0]
- + sx * (SplashCoord)unscaledAlpha[y1 * srcWidth + x1];
- scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
- + sy * pix1);
- } else {
- scanBuf[x] = 0xff;
- }
- } else {
- for (i = 0; i < nComps; ++i) {
- *p++ = 0;
- }
- scanBuf[x] = 0;
- }
+ if (srcAlpha) {
+ if (vectorAntialias) {
+ drawRowFunc = &Splash::drawImageRowClipAlphaAA;
} else {
- x0 = splashFloor(ix);
- y0 = splashFloor(iy);
- if (x0 >= 0 && x0 < srcWidth && y0 >= 0 && y0 < srcHeight) {
- q = &unscaledImage[y0 * rowSize + (SplashBitmapRowSize)x0 * nComps];
- for (i = 0; i < nComps; ++i) {
- *p++ = *q++;
- }
- if (srcAlpha) {
- scanBuf[x] = unscaledAlpha[y0 * srcWidth + x0];
- } else {
- scanBuf[x] = 0xff;
- }
- } else {
- for (i = 0; i < nComps; ++i) {
- *p++ = 0;
- }
- scanBuf[x] = 0;
- }
+ drawRowFunc = &Splash::drawImageRowClipAlphaNoAA;
}
- }
- if (clipRes != splashClipAllInside) {
+ } else {
if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, y, xMinI, xMaxI - 1,
- state->strokeAdjust);
+ drawRowFunc = &Splash::drawImageRowClipNoAlphaAA;
} else {
- state->clip->clipSpanBinary(scanBuf, y, xMinI, xMaxI - 1,
- state->strokeAdjust);
+ drawRowFunc = &Splash::drawImageRowClipNoAlphaNoAA;
}
}
- (this->*pipe.run)(&pipe, xMinI, xMaxI - 1, y, scanBuf + xMinI, pixelBuf);
- }
-
- gfree(pixelBuf);
- gfree(unscaledImage);
- gfree(unscaledAlpha);
-}
-
-void Splash::arbitraryTransformImage(GString *imageTag,
- SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha,
- int srcWidth, int srcHeight,
- SplashCoord *mat, GBool interpolate) {
- SplashBitmap *scaledImg;
- SplashClipResult clipRes;
- SplashPipe pipe;
- SplashColorPtr pixelBuf;
- int scaledWidth, scaledHeight, t0, t1;
- SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
- SplashCoord vx[4], vy[4];
- int xMin, yMin, xMax, yMax;
- ImageSection section[3];
- int nSections;
- int y, xa, xb, x, i, xx, yy;
-
- // compute the four vertices of the target quadrilateral
- vx[0] = mat[4]; vy[0] = mat[5];
- vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5];
- vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5];
- vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5];
-
- // clipping
- xMin = splashRound(vx[0]);
- xMax = splashRound(vx[0]);
- yMin = splashRound(vy[0]);
- yMax = splashRound(vy[0]);
- for (i = 1; i < 4; ++i) {
- t0 = splashRound(vx[i]);
- if (t0 < xMin) {
- xMin = t0;
- } else if (t0 > xMax) {
- xMax = t0;
- }
- t1 = splashRound(vy[i]);
- if (t1 < yMin) {
- yMin = t1;
- } else if (t1 > yMax) {
- yMax = t1;
- }
- }
- clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
- state->strokeAdjust);
- opClipRes = clipRes;
- if (clipRes == splashClipAllOutside) {
- return;
- }
-
- // compute the scale factors
- if (mat[0] >= 0) {
- t0 = splashRound(mat[0] + mat[4]) - splashRound(mat[4]);
- } else {
- t0 = splashRound(mat[4]) - splashRound(mat[0] + mat[4]);
- }
- if (mat[1] >= 0) {
- t1 = splashRound(mat[1] + mat[5]) - splashRound(mat[5]);
- } else {
- t1 = splashRound(mat[5]) - splashRound(mat[1] + mat[5]);
- }
- scaledWidth = t0 > t1 ? t0 : t1;
- if (mat[2] >= 0) {
- t0 = splashRound(mat[2] + mat[4]) - splashRound(mat[4]);
- } else {
- t0 = splashRound(mat[4]) - splashRound(mat[2] + mat[4]);
- }
- if (mat[3] >= 0) {
- t1 = splashRound(mat[3] + mat[5]) - splashRound(mat[5]);
- } else {
- t1 = splashRound(mat[5]) - splashRound(mat[3] + mat[5]);
}
- scaledHeight = t0 > t1 ? t0 : t1;
- if (scaledWidth == 0) {
- scaledWidth = 1;
- }
- if (scaledHeight == 0) {
- scaledHeight = 1;
- }
-
- // compute the inverse transform (after scaling) matrix
- r00 = mat[0] / scaledWidth;
- r01 = mat[1] / scaledWidth;
- r10 = mat[2] / scaledHeight;
- r11 = mat[3] / scaledHeight;
- det = r00 * r11 - r01 * r10;
- if (splashAbs(det) < 1e-6) {
- // this should be caught by the singular matrix check in drawImage
- return;
- }
- ir00 = r11 / det;
- ir01 = -r01 / det;
- ir10 = -r10 / det;
- ir11 = r00 / det;
-
- // scale the input image
- scaledImg = scaleImage(imageTag, src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight,
- interpolate);
- if (imageCache->vertFlip) {
- vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->vertFlip = gFalse;
- }
- if (imageCache->horizFlip) {
- horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
- imageCache->horizFlip = gFalse;
- }
-
- // construct the three sections
- i = 0;
- if (vy[1] < vy[i]) {
- i = 1;
- }
- if (vy[2] < vy[i]) {
- i = 2;
- }
- if (vy[3] < vy[i]) {
- i = 3;
- }
- // NB: if using fixed point, 0.000001 will be truncated to zero,
- // so these two comparisons must be <=, not <
- if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 &&
- vy[(i-1) & 3] < vy[(i+1) & 3]) {
- i = (i-1) & 3;
- }
- if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) {
- section[0].y0 = splashRound(vy[i]);
- section[0].y1 = splashRound(vy[(i+2) & 3]) - 1;
- if (vx[i] < vx[(i+1) & 3]) {
- section[0].ia0 = i;
- section[0].ia1 = (i+3) & 3;
- section[0].ib0 = (i+1) & 3;
- section[0].ib1 = (i+2) & 3;
- } else {
- section[0].ia0 = (i+1) & 3;
- section[0].ia1 = (i+2) & 3;
- section[0].ib0 = i;
- section[0].ib1 = (i+3) & 3;
- }
- nSections = 1;
- } else {
- section[0].y0 = splashRound(vy[i]);
- section[2].y1 = splashRound(vy[(i+2) & 3]) - 1;
- section[0].ia0 = section[0].ib0 = i;
- section[2].ia1 = section[2].ib1 = (i+2) & 3;
- if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
- section[0].ia1 = section[2].ia0 = (i+1) & 3;
- section[0].ib1 = section[2].ib0 = (i+3) & 3;
- } else {
- section[0].ia1 = section[2].ia0 = (i+3) & 3;
- section[0].ib1 = section[2].ib0 = (i+1) & 3;
- }
- if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
- section[1].y0 = splashRound(vy[(i+1) & 3]);
- section[2].y0 = splashRound(vy[(i+3) & 3]);
- if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
- section[1].ia0 = (i+1) & 3;
- section[1].ia1 = (i+2) & 3;
- section[1].ib0 = i;
- section[1].ib1 = (i+3) & 3;
- } else {
- section[1].ia0 = i;
- section[1].ia1 = (i+3) & 3;
- section[1].ib0 = (i+1) & 3;
- section[1].ib1 = (i+2) & 3;
- }
- } else {
- section[1].y0 = splashRound(vy[(i+3) & 3]);
- section[2].y0 = splashRound(vy[(i+1) & 3]);
- if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
- section[1].ia0 = i;
- section[1].ia1 = (i+1) & 3;
- section[1].ib0 = (i+3) & 3;
- section[1].ib1 = (i+2) & 3;
- } else {
- section[1].ia0 = (i+3) & 3;
- section[1].ia1 = (i+2) & 3;
- section[1].ib0 = i;
- section[1].ib1 = (i+1) & 3;
- }
- }
- section[0].y1 = section[1].y0 - 1;
- section[1].y1 = section[2].y0 - 1;
- nSections = 3;
- }
- for (i = 0; i < nSections; ++i) {
- section[i].xa0 = vx[section[i].ia0];
- section[i].ya0 = vy[section[i].ia0];
- section[i].xa1 = vx[section[i].ia1];
- section[i].ya1 = vy[section[i].ia1];
- section[i].xb0 = vx[section[i].ib0];
- section[i].yb0 = vy[section[i].ib0];
- section[i].xb1 = vx[section[i].ib1];
- section[i].yb1 = vy[section[i].ib1];
- section[i].dxdya = (section[i].xa1 - section[i].xa0) /
- (section[i].ya1 - section[i].ya0);
- section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
- (section[i].yb1 - section[i].yb0);
- }
-
- // initialize the pixel pipe
- pipeInit(&pipe, NULL,
- (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
- // make sure narrow images cover at least one pixel
- if (nSections == 1) {
- if (section[0].y0 == section[0].y1) {
- ++section[0].y1;
- clipRes = opClipRes = splashClipPartial;
- }
- } else {
- if (section[0].y0 == section[2].y1) {
- ++section[1].y1;
- clipRes = opClipRes = splashClipPartial;
- }
- }
-
- pixelBuf = (SplashColorPtr)gmallocn(xMax - xMin + 1, bitmapComps);
-
- // scan all pixels inside the target region
- for (i = 0; i < nSections; ++i) {
- for (y = section[i].y0; y <= section[i].y1; ++y) {
- xa = splashRound(section[i].xa0 +
- ((SplashCoord)y + 0.5 - section[i].ya0) *
- section[i].dxdya);
- xb = splashRound(section[i].xb0 +
- ((SplashCoord)y + 0.5 - section[i].yb0) *
- section[i].dxdyb);
- if (xa > xb) {
- continue;
- }
- // make sure narrow images cover at least one pixel
- if (xa == xb) {
- ++xb;
- }
- // check the scanBuf bounds
- if (xa >= bitmap->width || xb < 0) {
- continue;
- }
- if (xa < 0) {
- xa = 0;
- }
- if (xb > bitmap->width) {
- xb = bitmap->width;
- }
- // clip the scan line
- memset(scanBuf + xa, 0xff, xb - xa);
- if (clipRes != splashClipAllInside) {
- if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, y, xa, xb - 1,
- state->strokeAdjust);
- } else {
- state->clip->clipSpanBinary(scanBuf, y, xa, xb - 1,
- state->strokeAdjust);
- }
- }
- // draw the scan line
- for (x = xa; x < xb; ++x) {
- // map (x+0.5, y+0.5) back to the scaled image
- xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
- ((SplashCoord)y + 0.5 - mat[5]) * ir10);
- yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
- ((SplashCoord)y + 0.5 - mat[5]) * ir11);
- // xx should always be within bounds, but floating point
- // inaccuracy can cause problems
- if (xx < 0) {
- xx = 0;
- } else if (xx >= scaledWidth) {
- xx = scaledWidth - 1;
- }
- if (yy < 0) {
- yy = 0;
- } else if (yy >= scaledHeight) {
- yy = scaledHeight - 1;
- }
- // get the color
- scaledImg->getPixel(xx, yy, pixelBuf + (x - xa) * bitmapComps);
- // apply alpha
+ //--- horizontal/vertical flips only
+ if (flipsOnly && !veryLarge) {
+ if (clipRes != splashClipAllOutside) {
+ int scaledWidth = xMax - xMin;
+ int scaledHeight = yMax - yMin;
+ ImageScaler *scaler = getImageScaler(imageTag, src, srcData,
+ w, h, nComps,
+ scaledWidth, scaledHeight,
+ srcMode, srcAlpha, interpolate);
+ Guchar *tmpLine = NULL;
+ Guchar *tmpAlphaLine = NULL;
+ if (horizFlip) {
+ tmpLine = (Guchar *)gmallocn(scaledWidth, nComps);
if (srcAlpha) {
- scanBuf[x] = div255(scanBuf[x] *
- scaledImg->alpha[yy * scaledWidth + xx]);
+ tmpAlphaLine = (Guchar *)gmalloc(scaledWidth);
}
}
- (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, pixelBuf);
- }
- }
-
- gfree(pixelBuf);
-}
-
-// Scale an image into a SplashBitmap.
-SplashBitmap *Splash::scaleImage(GString *imageTag,
- SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- GBool interpolate) {
- if (imageCache->tag && imageTag &&
- !imageCache->tag->cmp(imageTag) &&
- !imageCache->isMask &&
- imageCache->width == scaledWidth &&
- imageCache->height == scaledHeight &&
- imageCache->mode == srcMode &&
- imageCache->alpha == srcAlpha &&
- imageCache->interpolate == interpolate) {
- return imageCache->image;
- }
- if (imageCache->tag) {
- delete imageCache->tag;
- }
- if (imageCache->image) {
- delete imageCache->image;
- }
- imageCache->tag = imageTag ? imageTag->copy() : (GString *)NULL;
- imageCache->isMask = gFalse;
- imageCache->width = scaledWidth;
- imageCache->height = scaledHeight;
- imageCache->mode = srcMode;
- imageCache->alpha = srcAlpha;
- imageCache->interpolate = interpolate;
- imageCache->vertFlip = gFalse;
- imageCache->horizFlip = gFalse;
- imageCache->image = new SplashBitmap(scaledWidth, scaledHeight, 1,
- srcMode, srcAlpha, gTrue, NULL);
- if (scaledHeight < srcHeight) {
- if (scaledWidth < srcWidth) {
- scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight,
- imageCache->image);
- } else {
- scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight,
- imageCache->image);
- }
- } else {
- if (scaledWidth < srcWidth) {
- scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight,
- imageCache->image);
- } else {
- if (interpolate) {
- scaleImageYuXuI(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight,
- imageCache->image);
+ if (vertFlip) {
+ if (horizFlip) { // bottom-up, mirrored
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler->nextLine();
+ mirrorImageRow(scaler->colorData(), scaler->alphaData(),
+ tmpLine, tmpAlphaLine,
+ scaledWidth, nComps, srcAlpha);
+ (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
+ xMin, yMax - 1 - y, scaledWidth);
+ }
+ } else { // bottom-up
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler->nextLine();
+ (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(),
+ xMin, yMax - 1 - y, scaledWidth);
+ }
+ }
} else {
- scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
- srcWidth, srcHeight, scaledWidth, scaledHeight,
- imageCache->image);
+ if (horizFlip) { // top-down, mirrored
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler->nextLine();
+ mirrorImageRow(scaler->colorData(), scaler->alphaData(),
+ tmpLine, tmpAlphaLine,
+ scaledWidth, nComps, srcAlpha);
+ (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
+ xMin, yMin + y, scaledWidth);
+ }
+ } else { // top-down
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler->nextLine();
+ (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(),
+ xMin, yMin + y, scaledWidth);
+ }
+ }
}
+ gfree(tmpLine);
+ gfree(tmpAlphaLine);
+ delete scaler;
}
- }
- return imageCache->image;
-}
-void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf, *alphaLineBuf;
- Guint *pixBuf, *alphaPixBuf;
- Guint pix0, pix1, pix2;
-#if SPLASH_CMYK
- Guint pix3;
-#endif
- Guint alpha;
- Guchar *destPtr, *destAlphaPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
- int i, j;
-
- // Bresenham parameters for y scale
- yp = srcHeight / scaledHeight;
- yq = srcHeight % scaledHeight;
-
- // Bresenham parameters for x scale
- xp = srcWidth / scaledWidth;
- xq = srcWidth % scaledWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
- pixBuf = (Guint *)gmallocn(srcWidth, (int)(nComps * sizeof(int)));
- if (srcAlpha) {
- alphaLineBuf = (Guchar *)gmalloc(srcWidth);
- alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+ //--- arbitrary transform
} else {
- alphaLineBuf = NULL;
- alphaPixBuf = NULL;
- }
-
- // init y scale Bresenham
- yt = 0;
-
- destPtr = dest->data;
- destAlphaPtr = dest->alpha;
- for (y = 0; y < scaledHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= scaledHeight) {
- yt -= scaledHeight;
- yStep = yp + 1;
+ // estimate of size of scaled image
+ int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0]
+ + mat[1] * mat[1]));
+ int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2]
+ + mat[3] * mat[3]));
+ if (scaledWidth < 1) {
+ scaledWidth = 1;
+ }
+ if (scaledHeight < 1) {
+ scaledHeight = 1;
+ }
+ if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) {
+ scaledWidth = w;
+ scaledHeight = h;
+ }
+
+ // compute mapping from device space to scaled image space
+ SplashCoord mat1[6];
+ mat1[0] = mat[0] / scaledWidth;
+ mat1[1] = mat[1] / scaledWidth;
+ mat1[2] = mat[2] / scaledHeight;
+ mat1[3] = mat[3] / scaledHeight;
+ mat1[4] = mat[4];
+ mat1[5] = mat[5];
+ SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2];
+ if (splashAbs(det) < 1e-6) {
+ // this should be caught by the singular matrix check in drawImage
+ return splashErrSingularMatrix;
+ }
+ SplashCoord invMat[6];
+ invMat[0] = mat1[3] / det;
+ invMat[1] = -mat1[1] / det;
+ invMat[2] = -mat1[2] / det;
+ invMat[3] = mat1[0] / det;
+ // the extra "+ 0.5 * (...)" terms are here because the
+ // drawImageArbitrary(No)Interp functions multiply by pixel
+ // centers, (x + 0.5, y + 0.5)
+ invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det
+ + (invMat[0] + invMat[2]) * 0.5;
+ invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det
+ + (invMat[1] + invMat[3]) * 0.5;
+
+ Guchar *scaledColor, *scaledAlpha;
+ GBool freeScaledImage;
+ getScaledImage(imageTag, src, srcData, w, h, nComps,
+ scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate,
+ &scaledColor, &scaledAlpha, &freeScaledImage);
+
+ // draw it
+ if (interpolate) {
+ drawImageArbitraryInterp(scaledColor, scaledAlpha,
+ &dd, drawRowFunc, invMat,
+ scaledWidth, scaledHeight,
+ xMin, yMin, xMax, yMax,
+ nComps, srcAlpha);
} else {
- yStep = yp;
+ drawImageArbitraryNoInterp(scaledColor, scaledAlpha,
+ &dd, drawRowFunc, invMat,
+ scaledWidth, scaledHeight,
+ xMin, yMin, xMax, yMax,
+ nComps, srcAlpha);
}
- // read rows from image
- memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
- if (srcAlpha) {
- memset(alphaPixBuf, 0, srcWidth * sizeof(int));
- }
- for (i = 0; i < yStep; ++i) {
- (*src)(srcData, lineBuf, alphaLineBuf);
- for (j = 0; j < srcWidth * nComps; ++j) {
- pixBuf[j] += lineBuf[j];
- }
- if (srcAlpha) {
- for (j = 0; j < srcWidth; ++j) {
- alphaPixBuf[j] += alphaLineBuf[j];
- }
- }
+ // free the downscaled/unscaled image
+ if (freeScaledImage) {
+ gfree(scaledColor);
+ gfree(scaledAlpha);
}
+ }
- // init x scale Bresenham
- xt = 0;
- d0 = (1 << 23) / (yStep * xp);
- d1 = (1 << 23) / (yStep * (xp + 1));
-
- xx = xxa = 0;
- for (x = 0; x < scaledWidth; ++x) {
+ return splashOk;
+}
- // x scale Bresenham
- if ((xt += xq) >= scaledWidth) {
- xt -= scaledWidth;
- xStep = xp + 1;
- d = d1;
+ImageScaler *Splash::getImageScaler(GString *imageTag,
+ SplashImageSource src, void *srcData,
+ int w, int h, int nComps,
+ int scaledWidth, int scaledHeight,
+ SplashColorMode srcMode,
+ GBool srcAlpha, GBool interpolate) {
+ // Notes:
+ //
+ // * If the scaled image width or height is greater than 2000, we
+ // don't cache it.
+ //
+ // * Caching is done on the third consecutive use (second
+ // consecutive reuse) of an image; this avoids overhead on the
+ // common case of single-use images.
+
+ if (scaledWidth < 2000 && scaledHeight < 2000 &&
+ imageCache->match(imageTag, scaledWidth, scaledHeight,
+ srcMode, srcAlpha, interpolate)) {
+ if (imageCache->colorData) {
+ return new ReplayImageScaler(nComps, srcAlpha, scaledWidth,
+ imageCache->colorData,
+ imageCache->alphaData);
+ } else {
+ int lineSize;
+ if (scaledWidth < INT_MAX / nComps) {
+ lineSize = scaledWidth * nComps;
} else {
- xStep = xp;
- d = d0;
+ lineSize = -1;
}
-
- switch (srcMode) {
-
- case splashModeMono8:
-
- // compute the final pixel
- pix0 = 0;
- for (i = 0; i < xStep; ++i) {
- pix0 += pixBuf[xx++];
- }
- // pix / xStep * yStep
- pix0 = (pix0 * d + (1 << 22)) >> 23;
-
- // store the pixel
- *destPtr++ = (Guchar)pix0;
- break;
-
- case splashModeRGB8:
-
- // compute the final pixel
- pix0 = pix1 = pix2 = 0;
- for (i = 0; i < xStep; ++i) {
- pix0 += pixBuf[xx];
- pix1 += pixBuf[xx+1];
- pix2 += pixBuf[xx+2];
- xx += 3;
- }
- // pix / xStep * yStep
- pix0 = (pix0 * d + (1 << 22)) >> 23;
- pix1 = (pix1 * d + (1 << 22)) >> 23;
- pix2 = (pix2 * d + (1 << 22)) >> 23;
-
- // store the pixel
- *destPtr++ = (Guchar)pix0;
- *destPtr++ = (Guchar)pix1;
- *destPtr++ = (Guchar)pix2;
- break;
-
-#if SPLASH_CMYK
- case splashModeCMYK8:
-
- // compute the final pixel
- pix0 = pix1 = pix2 = pix3 = 0;
- for (i = 0; i < xStep; ++i) {
- pix0 += pixBuf[xx];
- pix1 += pixBuf[xx+1];
- pix2 += pixBuf[xx+2];
- pix3 += pixBuf[xx+3];
- xx += 4;
- }
- // pix / xStep * yStep
- pix0 = (pix0 * d + (1 << 22)) >> 23;
- pix1 = (pix1 * d + (1 << 22)) >> 23;
- pix2 = (pix2 * d + (1 << 22)) >> 23;
- pix3 = (pix3 * d + (1 << 22)) >> 23;
-
- // store the pixel
- *destPtr++ = (Guchar)pix0;
- *destPtr++ = (Guchar)pix1;
- *destPtr++ = (Guchar)pix2;
- *destPtr++ = (Guchar)pix3;
- break;
-#endif
-
-
- case splashModeMono1: // mono1 is not allowed
- case splashModeBGR8: // bgr8 is not allowed
- default:
- break;
- }
-
- // process alpha
+ imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize);
if (srcAlpha) {
- alpha = 0;
- for (i = 0; i < xStep; ++i, ++xxa) {
- alpha += alphaPixBuf[xxa];
- }
- // alpha / xStep * yStep
- alpha = (alpha * d + (1 << 22)) >> 23;
- *destAlphaPtr++ = (Guchar)alpha;
+ imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth);
}
+ return new SavingImageScaler(src, srcData,
+ w, h, nComps, srcAlpha,
+ scaledWidth, scaledHeight,
+ interpolate,
+ imageCache->colorData,
+ imageCache->alphaData);
}
+ } else {
+ imageCache->reset(imageTag, scaledWidth, scaledHeight,
+ srcMode, srcAlpha, interpolate);
+ return new BasicImageScaler(src, srcData,
+ w, h, nComps, srcAlpha,
+ scaledWidth, scaledHeight,
+ interpolate);
}
-
- gfree(alphaPixBuf);
- gfree(alphaLineBuf);
- gfree(pixBuf);
- gfree(lineBuf);
}
-void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
+void Splash::getScaledImage(GString *imageTag,
+ SplashImageSource src, void *srcData,
+ int w, int h, int nComps,
int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf, *alphaLineBuf;
- Guint *pixBuf, *alphaPixBuf;
- Guint pix[splashMaxColorComps];
- Guint alpha;
- Guchar *destPtr, *destAlphaPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
- int i, j;
-
- // Bresenham parameters for y scale
- yp = srcHeight / scaledHeight;
- yq = srcHeight % scaledHeight;
-
- // Bresenham parameters for x scale
- xp = scaledWidth / srcWidth;
- xq = scaledWidth % srcWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
- pixBuf = (Guint *)gmallocn(srcWidth, (int)(nComps * sizeof(int)));
- if (srcAlpha) {
- alphaLineBuf = (Guchar *)gmalloc(srcWidth);
- alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
- } else {
- alphaLineBuf = NULL;
- alphaPixBuf = NULL;
- }
-
- // make gcc happy
- pix[0] = pix[1] = pix[2] = 0;
-#if SPLASH_CMYK
- pix[3] = 0;
-#endif
-
- // init y scale Bresenham
- yt = 0;
-
- destPtr = dest->data;
- destAlphaPtr = dest->alpha;
- for (y = 0; y < scaledHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= scaledHeight) {
- yt -= scaledHeight;
- yStep = yp + 1;
+ SplashColorMode srcMode,
+ GBool srcAlpha, GBool interpolate,
+ Guchar **scaledColor, Guchar **scaledAlpha,
+ GBool *freeScaledImage) {
+ // Notes:
+ //
+ // * If the scaled image width or height is greater than 2000, we
+ // don't cache it.
+ //
+ // * This buffers the whole image anyway, so there's no reason to
+ // skip caching on the first reuse.
+
+ if (scaledWidth >= 2000 || scaledHeight >= 2000) {
+ int lineSize;
+ if (scaledWidth < INT_MAX / nComps) {
+ lineSize = scaledWidth * nComps;
} else {
- yStep = yp;
+ lineSize = -1;
}
-
- // read rows from image
- memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+ *scaledColor = (Guchar *)gmallocn(scaledHeight, lineSize);
if (srcAlpha) {
- memset(alphaPixBuf, 0, srcWidth * sizeof(int));
- }
- for (i = 0; i < yStep; ++i) {
- (*src)(srcData, lineBuf, alphaLineBuf);
- for (j = 0; j < srcWidth * nComps; ++j) {
- pixBuf[j] += lineBuf[j];
+ *scaledAlpha = (Guchar *)gmallocn(scaledHeight, scaledWidth);
+ } else {
+ *scaledAlpha = NULL;
+ }
+ *freeScaledImage = gTrue;
+ if (scaledWidth == w && scaledHeight == h) {
+ Guchar *colorPtr = *scaledColor;
+ Guchar *alphaPtr = *scaledAlpha;
+ for (int y = 0; y < scaledHeight; ++y) {
+ (*src)(srcData, colorPtr, alphaPtr);
+ colorPtr += scaledWidth * nComps;
+ if (srcAlpha) {
+ alphaPtr += scaledWidth;
+ }
}
- if (srcAlpha) {
- for (j = 0; j < srcWidth; ++j) {
- alphaPixBuf[j] += alphaLineBuf[j];
+ } else {
+ BasicImageScaler scaler(src, srcData, w, h, nComps, srcAlpha,
+ scaledWidth, scaledHeight, interpolate);
+ Guchar *colorPtr = *scaledColor;
+ Guchar *alphaPtr = *scaledAlpha;
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps);
+ colorPtr += scaledWidth * nComps;
+ if (srcAlpha) {
+ memcpy(alphaPtr, scaler.alphaData(), scaledWidth);
+ alphaPtr += scaledWidth;
}
}
}
-
- // init x scale Bresenham
- xt = 0;
- d = (1 << 23) / yStep;
-
- for (x = 0; x < srcWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= srcWidth) {
- xt -= srcWidth;
- xStep = xp + 1;
+ } else {
+ if (!imageCache->match(imageTag, scaledWidth, scaledHeight,
+ srcMode, srcAlpha, interpolate) ||
+ !imageCache->colorData) {
+ imageCache->reset(imageTag, scaledWidth, scaledHeight,
+ srcMode, srcAlpha, interpolate);
+ int lineSize;
+ if (scaledWidth < INT_MAX / nComps) {
+ lineSize = scaledWidth * nComps;
} else {
- xStep = xp;
+ lineSize = -1;
}
-
- // compute the final pixel
- for (i = 0; i < nComps; ++i) {
- // pixBuf[] / yStep
- pix[i] = (pixBuf[x * nComps + i] * d + (1 << 22)) >> 23;
- }
-
- // store the pixel
- switch (srcMode) {
- case splashModeMono8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (Guchar)pix[0];
- }
- break;
- case splashModeRGB8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[2];
- }
- break;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[2];
- *destPtr++ = (Guchar)pix[3];
- }
- break;
-#endif
- case splashModeMono1: // mono1 is not allowed
- case splashModeBGR8: // BGR8 is not allowed
- default:
- break;
- }
-
- // process alpha
+ imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize);
if (srcAlpha) {
- // alphaPixBuf[] / yStep
- alpha = (alphaPixBuf[x] * d + (1 << 22)) >> 23;
- for (i = 0; i < xStep; ++i) {
- *destAlphaPtr++ = (Guchar)alpha;
+ imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth);
+ }
+ if (scaledWidth == w && scaledHeight == h) {
+ Guchar *colorPtr = imageCache->colorData;
+ Guchar *alphaPtr = imageCache->alphaData;
+ for (int y = 0; y < scaledHeight; ++y) {
+ (*src)(srcData, colorPtr, alphaPtr);
+ colorPtr += scaledWidth * nComps;
+ if (srcAlpha) {
+ alphaPtr += scaledWidth;
+ }
+ }
+ } else {
+ SavingImageScaler scaler(src, srcData, w, h, nComps, srcAlpha,
+ scaledWidth, scaledHeight, interpolate,
+ imageCache->colorData, imageCache->alphaData);
+ Guchar *colorPtr = imageCache->colorData;
+ Guchar *alphaPtr = imageCache->alphaData;
+ for (int y = 0; y < scaledHeight; ++y) {
+ scaler.nextLine();
+ memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps);
+ colorPtr += scaledWidth * nComps;
+ if (srcAlpha) {
+ memcpy(alphaPtr, scaler.alphaData(), scaledWidth);
+ alphaPtr += scaledWidth;
+ }
}
}
}
+ *scaledColor = imageCache->colorData;
+ *scaledAlpha = imageCache->alphaData;
+ *freeScaledImage = gFalse;
}
-
- gfree(alphaPixBuf);
- gfree(alphaLineBuf);
- gfree(pixBuf);
- gfree(lineBuf);
}
-void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf, *alphaLineBuf;
- Guint pix[splashMaxColorComps];
- Guint alpha;
- Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
- int i, j;
-
- // Bresenham parameters for y scale
- yp = scaledHeight / srcHeight;
- yq = scaledHeight % srcHeight;
-
- // Bresenham parameters for x scale
- xp = srcWidth / scaledWidth;
- xq = srcWidth % scaledWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
- if (srcAlpha) {
- alphaLineBuf = (Guchar *)gmalloc(srcWidth);
- } else {
- alphaLineBuf = NULL;
+void Splash::drawImageArbitraryNoInterp(Guchar *scaledColor,
+ Guchar *scaledAlpha,
+ SplashDrawImageRowData *dd,
+ SplashDrawImageRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax,
+ int nComps, GBool srcAlpha) {
+ int tt = state->clip->getXMinI(state->strokeAdjust);
+ if (tt > xMin) {
+ xMin = tt;
+ }
+ tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+ if (tt < xMax) {
+ xMax = tt;
+ }
+ tt = state->clip->getYMinI(state->strokeAdjust);
+ if (tt > yMin) {
+ yMin = tt;
+ }
+ tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+ if (tt < yMax) {
+ yMax = tt;
+ }
+ if (xMax <= xMin || yMax <= yMin) {
+ return;
}
- // make gcc happy
- pix[0] = pix[1] = pix[2] = 0;
-#if SPLASH_CMYK
- pix[3] = 0;
-#endif
-
- // init y scale Bresenham
- yt = 0;
-
- destPtr0 = dest->data;
- destAlphaPtr0 = dest->alpha;
- for (y = 0; y < srcHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= srcHeight) {
- yt -= srcHeight;
- yStep = yp + 1;
- } else {
- yStep = yp;
- }
-
- // read row from image
- (*src)(srcData, lineBuf, alphaLineBuf);
-
- // init x scale Bresenham
- xt = 0;
- d0 = (1 << 23) / xp;
- d1 = (1 << 23) / (xp + 1);
-
- xx = xxa = 0;
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= scaledWidth) {
- xt -= scaledWidth;
- xStep = xp + 1;
- d = d1;
- } else {
- xStep = xp;
- d = d0;
- }
-
- // compute the final pixel
- for (i = 0; i < nComps; ++i) {
- pix[i] = 0;
- }
- for (i = 0; i < xStep; ++i) {
- for (j = 0; j < nComps; ++j, ++xx) {
- pix[j] += lineBuf[xx];
- }
- }
- for (i = 0; i < nComps; ++i) {
- // pix[] / xStep
- pix[i] = (pix[i] * d + (1 << 22)) >> 23;
- }
-
- // store the pixel
- switch (srcMode) {
- case splashModeMono8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (Guchar)pix[0];
- }
- break;
- case splashModeRGB8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[2];
- }
- break;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- for (i = 0; i < yStep; ++i) {
- destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
- *destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)pix[1];
- *destPtr++ = (Guchar)pix[2];
- *destPtr++ = (Guchar)pix[3];
+ Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps);
+ Guchar *alphaBuf = NULL;
+ if (srcAlpha) {
+ alphaBuf = (Guchar *)gmalloc(xMax - xMin);
+ }
+
+ for (int y = yMin; y < yMax; ++y) {
+ int rowMin = xMax;
+ int rowMax = 0;
+ for (int x = xMin; x < xMax; ++x) {
+ // note: invMat includes a "+0.5" factor so that this is really
+ // a multiply by (x+0.5, y+0.5)
+ int xx = splashFloor((SplashCoord)x * invMat[0]
+ + (SplashCoord)y * invMat[2] + invMat[4]);
+ int yy = splashFloor((SplashCoord)x * invMat[1]
+ + (SplashCoord)y * invMat[3] + invMat[5]);
+ if (xx >= 0 && xx < scaledWidth &&
+ yy >= 0 && yy < scaledHeight) {
+ Guchar *p = scaledColor + (yy * scaledWidth + xx) * nComps;
+ Guchar *q = colorBuf + (x - xMin) * nComps;
+ for (int i = 0; i < nComps; ++i) {
+ *q++ = *p++;
}
- break;
-#endif
- case splashModeMono1: // mono1 is not allowed
- case splashModeBGR8: // BGR8 is not allowed
- default:
- break;
- }
-
- // process alpha
- if (srcAlpha) {
- alpha = 0;
- for (i = 0; i < xStep; ++i, ++xxa) {
- alpha += alphaLineBuf[xxa];
+ if (srcAlpha) {
+ alphaBuf[x - xMin] = scaledAlpha[yy * scaledWidth + xx];
}
- // alpha / xStep
- alpha = (alpha * d + (1 << 22)) >> 23;
- for (i = 0; i < yStep; ++i) {
- destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x;
- *destAlphaPtr = (Guchar)alpha;
+ if (x < rowMin) {
+ rowMin = x;
}
+ rowMax = x + 1;
}
}
-
- destPtr0 += yStep * scaledWidth * nComps;
- if (srcAlpha) {
- destAlphaPtr0 += yStep * scaledWidth;
+ if (rowMin < rowMax) {
+ (this->*drawRowFunc)(dd,
+ colorBuf + (rowMin - xMin) * nComps,
+ alphaBuf + (rowMin - xMin),
+ rowMin, y, rowMax - rowMin);
}
}
- gfree(alphaLineBuf);
- gfree(lineBuf);
+ gfree(colorBuf);
+ gfree(alphaBuf);
}
-void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf, *alphaLineBuf;
- Guchar pix0, pix1, pix2;
-#if SPLASH_CMYK
- Guchar pix3;
-#endif
- Guchar alpha;
- Guchar *srcPtr, *srcAlphaPtr;
- Guchar *destPtr, *destAlphaPtr;
- int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep;
- int i;
-
- // Bresenham parameters for y scale
- yp = scaledHeight / srcHeight;
- yq = scaledHeight % srcHeight;
-
- // Bresenham parameters for x scale
- xp = scaledWidth / srcWidth;
- xq = scaledWidth % srcWidth;
-
- // allocate buffers
- lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
- if (srcAlpha) {
- alphaLineBuf = (Guchar *)gmalloc(srcWidth);
- } else {
- alphaLineBuf = NULL;
+void Splash::drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha,
+ SplashDrawImageRowData *dd,
+ SplashDrawImageRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax,
+ int nComps, GBool srcAlpha) {
+ int tt = state->clip->getXMinI(state->strokeAdjust);
+ if (tt > xMin) {
+ xMin = tt;
+ }
+ tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+ if (tt < xMax) {
+ xMax = tt;
+ }
+ tt = state->clip->getYMinI(state->strokeAdjust);
+ if (tt > yMin) {
+ yMin = tt;
+ }
+ tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+ if (tt < yMax) {
+ yMax = tt;
+ }
+ if (xMax <= xMin || yMax <= yMin) {
+ return;
}
- // init y scale Bresenham
- yt = 0;
-
- destPtr = dest->data;
- destAlphaPtr = dest->alpha;
- for (y = 0; y < srcHeight; ++y) {
-
- // y scale Bresenham
- if ((yt += yq) >= srcHeight) {
- yt -= srcHeight;
- yStep = yp + 1;
- } else {
- yStep = yp;
- }
-
- // read row from image
- (*src)(srcData, lineBuf, alphaLineBuf);
-
- // init x scale Bresenham
- xt = 0;
-
- // generate one row
- srcPtr = lineBuf;
- srcAlphaPtr = alphaLineBuf;
- for (x = 0; x < srcWidth; ++x) {
-
- // x scale Bresenham
- if ((xt += xq) >= srcWidth) {
- xt -= srcWidth;
- xStep = xp + 1;
- } else {
- xStep = xp;
- }
-
- // duplicate the pixel horizontally
- switch (srcMode) {
- case splashModeMono8:
- pix0 = *srcPtr++;
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = pix0;
+ Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps);
+ Guchar *alphaBuf = NULL;
+ if (srcAlpha) {
+ alphaBuf = (Guchar *)gmalloc(xMax - xMin);
+ }
+
+ for (int y = yMin; y < yMax; ++y) {
+ int rowMin = xMax;
+ int rowMax = 0;
+ for (int x = xMin; x < xMax; ++x) {
+ // note: invMat includes a "+0.5" factor so that this is really
+ // a multiply by (x+0.5, y+0.5)
+ SplashCoord xs = (SplashCoord)x * invMat[0]
+ + (SplashCoord)y * invMat[2] + invMat[4];
+ SplashCoord ys = (SplashCoord)x * invMat[1]
+ + (SplashCoord)y * invMat[3] + invMat[5];
+ int x0 = splashFloor(xs - 0.5);
+ int x1 = x0 + 1;
+ int y0 = splashFloor(ys - 0.5);
+ int y1 = y0 + 1;
+ if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) {
+ SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs;
+ SplashCoord sx1 = (SplashCoord)1 - sx0;
+ SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys;
+ SplashCoord sy1 = (SplashCoord)1 - sy0;
+ if (x0 < 0) {
+ x0 = 0;
}
- break;
- case splashModeRGB8:
- pix0 = *srcPtr++;
- pix1 = *srcPtr++;
- pix2 = *srcPtr++;
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = pix0;
- *destPtr++ = pix1;
- *destPtr++ = pix2;
+ if (x1 >= scaledWidth) {
+ x1 = scaledWidth - 1;
}
- break;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- pix0 = *srcPtr++;
- pix1 = *srcPtr++;
- pix2 = *srcPtr++;
- pix3 = *srcPtr++;
- for (i = 0; i < xStep; ++i) {
- *destPtr++ = pix0;
- *destPtr++ = pix1;
- *destPtr++ = pix2;
- *destPtr++ = pix3;
+ if (y0 < 0) {
+ y0 = 0;
}
- break;
-#endif
- case splashModeMono1: // mono1 is not allowed
- case splashModeBGR8: // BGR8 is not allowed
- default:
- break;
- }
-
- // duplicate the alpha value horizontally
- if (srcAlpha) {
- alpha = *srcAlphaPtr++;
- for (i = 0; i < xStep; ++i) {
- *destAlphaPtr++ = alpha;
+ if (y1 >= scaledHeight) {
+ y1 = scaledHeight - 1;
}
+ Guchar *p00 = scaledColor + (y0 * scaledWidth + x0) * nComps;
+ Guchar *p10 = scaledColor + (y0 * scaledWidth + x1) * nComps;
+ Guchar *p01 = scaledColor + (y1 * scaledWidth + x0) * nComps;
+ Guchar *p11 = scaledColor + (y1 * scaledWidth + x1) * nComps;
+ Guchar *q = colorBuf + (x - xMin) * nComps;
+ for (int i = 0; i < nComps; ++i) {
+ *q++ = (Guchar)(int)(sx0 * (sy0 * (int)*p00++ + sy1 * (int)*p01++) +
+ sx1 * (sy0 * (int)*p10++ + sy1 * (int)*p11++));
+ }
+ if (srcAlpha) {
+ p00 = scaledAlpha + (y0 * scaledWidth + x0);
+ p10 = scaledAlpha + (y0 * scaledWidth + x1);
+ p01 = scaledAlpha + (y1 * scaledWidth + x0);
+ p11 = scaledAlpha + (y1 * scaledWidth + x1);
+ q = alphaBuf + (x - xMin);
+ *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) +
+ sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11));
+ }
+ if (x < rowMin) {
+ rowMin = x;
+ }
+ rowMax = x + 1;
}
}
-
- // duplicate the row vertically
- for (i = 1; i < yStep; ++i) {
- memcpy(destPtr, destPtr - scaledWidth * nComps,
- scaledWidth * nComps);
- destPtr += scaledWidth * nComps;
- }
- if (srcAlpha) {
- for (i = 1; i < yStep; ++i) {
- memcpy(destAlphaPtr, destAlphaPtr - scaledWidth, scaledWidth);
- destAlphaPtr += scaledWidth;
- }
+ if (rowMin < rowMax) {
+ (this->*drawRowFunc)(dd,
+ colorBuf + (rowMin - xMin) * nComps,
+ alphaBuf + (rowMin - xMin),
+ rowMin, y, rowMax - rowMin);
}
}
- gfree(alphaLineBuf);
- gfree(lineBuf);
+ gfree(colorBuf);
+ gfree(alphaBuf);
}
-void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest) {
- Guchar *lineBuf0, *lineBuf1, *alphaLineBuf0, *alphaLineBuf1, *tBuf;
- Guchar pix[splashMaxColorComps];
- SplashCoord yr, xr, ys, xs, ySrc, xSrc;
- int ySrc0, ySrc1, yBuf, xSrc0, xSrc1, y, x, i;
- Guchar *destPtr, *destAlphaPtr;
-
- // ratios
- yr = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
- xr = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
-
- // allocate buffers
- lineBuf0 = (Guchar *)gmallocn(scaledWidth, nComps);
- lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps);
- if (srcAlpha) {
- alphaLineBuf0 = (Guchar *)gmalloc(scaledWidth);
- alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth);
- } else {
- alphaLineBuf0 = NULL;
- alphaLineBuf1 = NULL;
- }
-
- // read first two rows
- (*src)(srcData, lineBuf0, alphaLineBuf0);
- if (srcHeight > 1) {
- (*src)(srcData, lineBuf1, alphaLineBuf1);
- yBuf = 1;
- } else {
- memcpy(lineBuf1, lineBuf0, srcWidth * nComps);
- if (srcAlpha) {
- memcpy(alphaLineBuf1, alphaLineBuf0, srcWidth);
- }
- yBuf = 0;
- }
+void Splash::mirrorImageRow(Guchar *colorIn, Guchar *alphaIn,
+ Guchar *colorOut, Guchar *alphaOut,
+ int width, int nComps, GBool srcAlpha) {
+ Guchar *p, *q;
- // interpolate first two rows
- for (x = scaledWidth - 1; x >= 0; --x) {
- xSrc = xr * x;
- xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
- xSrc1 = xSrc0 + 1;
- xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
- if (xSrc0 < 0) {
- xSrc0 = 0;
- }
- if (xSrc1 >= srcWidth) {
- xSrc1 = srcWidth - 1;
- }
- for (i = 0; i < nComps; ++i) {
- lineBuf0[x*nComps+i] = (Guchar)(int)
- (xs * (int)lineBuf0[xSrc0*nComps+i] +
- ((SplashCoord)1 - xs) * (int)lineBuf0[xSrc1*nComps+i]);
- lineBuf1[x*nComps+i] = (Guchar)(int)
- (xs * (int)lineBuf1[xSrc0*nComps+i] +
- ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1*nComps+i]);
- }
- if (srcAlpha) {
- alphaLineBuf0[x] = (Guchar)(int)
- (xs * (int)alphaLineBuf0[xSrc0] +
- ((SplashCoord)1 - xs) * (int)alphaLineBuf0[xSrc1]);
- alphaLineBuf1[x] = (Guchar)(int)
- (xs * (int)alphaLineBuf1[xSrc0] +
- ((SplashCoord)1 - xs) * (int)alphaLineBuf1[xSrc1]);
+ p = colorIn;
+ q = colorOut + (width - 1) * nComps;
+ for (int i = 0; i < width; ++i) {
+ for (int j = 0; j < nComps; ++j) {
+ q[j] = p[j];
}
+ p += nComps;
+ q -= nComps;
}
- // make gcc happy
- pix[0] = pix[1] = pix[2] = 0;
-#if SPLASH_CMYK
- pix[3] = 0;
-#endif
-
- destPtr = dest->data;
- destAlphaPtr = dest->alpha;
- for (y = 0; y < scaledHeight; ++y) {
-
- // compute vertical interpolation parameters
- ySrc = yr * y;
- ySrc0 = splashFloor(ySrc + yr * 0.5 - 0.5);
- ySrc1 = ySrc0 + 1;
- ys = ((SplashCoord)ySrc1 + 0.5) - (ySrc + yr * 0.5);
- if (ySrc0 < 0) {
- ySrc0 = 0;
- ys = 1;
- }
- if (ySrc1 >= srcHeight) {
- ySrc1 = srcHeight - 1;
- ys = 0;
- }
-
- // read another row (if necessary)
- if (ySrc1 > yBuf) {
- tBuf = lineBuf0;
- lineBuf0 = lineBuf1;
- lineBuf1 = tBuf;
- tBuf = alphaLineBuf0;
- alphaLineBuf0 = alphaLineBuf1;
- alphaLineBuf1 = tBuf;
- (*src)(srcData, lineBuf1, alphaLineBuf1);
-
- // interpolate the row
- for (x = scaledWidth - 1; x >= 0; --x) {
- xSrc = xr * x;
- xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
- xSrc1 = xSrc0 + 1;
- xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
- if (xSrc0 < 0) {
- xSrc0 = 0;
- }
- if (xSrc1 >= srcWidth) {
- xSrc1 = srcWidth - 1;
- }
- for (i = 0; i < nComps; ++i) {
- lineBuf1[x*nComps+i] = (Guchar)(int)
- (xs * (int)lineBuf1[xSrc0*nComps+i] +
- ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1*nComps+i]);
- }
- if (srcAlpha) {
- alphaLineBuf1[x] = (Guchar)(int)
- (xs * (int)alphaLineBuf1[xSrc0] +
- ((SplashCoord)1 - xs) * (int)alphaLineBuf1[xSrc1]);
- }
- }
-
- ++yBuf;
- }
-
- // do the vertical interpolation
- for (x = 0; x < scaledWidth; ++x) {
-
- for (i = 0; i < nComps; ++i) {
- pix[i] = (Guchar)(int)
- (ys * (int)lineBuf0[x*nComps+i] +
- ((SplashCoord)1 - ys) * (int)lineBuf1[x*nComps+i]);
- }
-
- // store the pixel
- switch (srcMode) {
- case splashModeMono8:
- *destPtr++ = pix[0];
- break;
- case splashModeRGB8:
- *destPtr++ = pix[0];
- *destPtr++ = pix[1];
- *destPtr++ = pix[2];
- break;
-#if SPLASH_CMYK
- case splashModeCMYK8:
- *destPtr++ = pix[0];
- *destPtr++ = pix[1];
- *destPtr++ = pix[2];
- *destPtr++ = pix[3];
- break;
-#endif
- case splashModeMono1: // mono1 is not allowed
- case splashModeBGR8: // BGR8 is not allowed
- default:
- break;
- }
-
- // process alpha
- if (srcAlpha) {
- *destAlphaPtr++ = (Guchar)(int)
- (ys * (int)alphaLineBuf0[x] +
- ((SplashCoord)1 - ys) * (int)alphaLineBuf1[x]);
- }
+ if (srcAlpha) {
+ p = alphaIn;
+ q = alphaOut + (width - 1);
+ for (int i = 0; i < width; ++i) {
+ *q = *p;
+ ++p;
+ --q;
}
}
+}
- gfree(alphaLineBuf1);
- gfree(alphaLineBuf0);
- gfree(lineBuf1);
- gfree(lineBuf0);
+void Splash::drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data,
+ Guchar *colorData, Guchar *alphaData,
+ int x, int y, int width) {
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, NULL, colorData);
}
-void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
- int nComps) {
- Guchar *lineBuf;
- Guchar *p0, *p1;
- int w;
+void Splash::drawImageRowNoClipAlpha(SplashDrawImageRowData *data,
+ Guchar *colorData, Guchar *alphaData,
+ int x, int y, int width) {
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ alphaData, colorData);
+}
- w = width * nComps;
- lineBuf = (Guchar *)gmalloc(w);
- for (p0 = img->data, p1 = img->data + (height - 1) * (size_t)w;
- p0 < p1;
- p0 += w, p1 -= w) {
- memcpy(lineBuf, p0, w);
- memcpy(p0, p1, w);
- memcpy(p1, lineBuf, w);
+void Splash::drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width) {
+ if (y < 0 || y >= bitmap->height) {
+ return;
}
- if (img->alpha) {
- for (p0 = img->alpha, p1 = img->alpha + (height - 1) * (size_t)width;
- p0 < p1;
- p0 += width, p1 -= width) {
- memcpy(lineBuf, p0, width);
- memcpy(p0, p1, width);
- memcpy(p1, lineBuf, width);
- }
+ if (x < 0) {
+ colorData -= x * data->nComps;
+ width += x;
+ x = 0;
}
- gfree(lineBuf);
-}
-
-void Splash::horizFlipImage(SplashBitmap *img, int width, int height,
- int nComps) {
- Guchar *lineBuf;
- SplashColorPtr p0, p1, p2;
- int w, x, y, i;
-
- w = width * nComps;
- lineBuf = (Guchar *)gmalloc(w);
- for (y = 0, p0 = img->data; y < height; ++y, p0 += img->rowSize) {
- memcpy(lineBuf, p0, w);
- p1 = p0;
- p2 = lineBuf + (w - nComps);
- for (x = 0; x < width; ++x) {
- for (i = 0; i < nComps; ++i) {
- p1[i] = p2[i];
- }
- p1 += nComps;
- p2 -= nComps;
- }
+ if (x + width > bitmap->width) {
+ width = bitmap->width - x;
}
- if (img->alpha) {
- for (y = 0, p0 = img->alpha; y < height; ++y, p0 += width) {
- memcpy(lineBuf, p0, width);
- p1 = p0;
- p2 = lineBuf + (width - 1);
- for (x = 0; x < width; ++x) {
- *p1++ = *p2--;
- }
- }
+ if (width <= 0) {
+ return;
}
- gfree(lineBuf);
+ memset(scanBuf + x, 0xff, width);
+ state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
+ state->strokeAdjust);
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ scanBuf + x, colorData);
}
-void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
- SplashClipResult clipRes) {
- SplashPipe pipe;
- int w, h, x0, y0, x1, y1, y;
-
- // split the image into clipped and unclipped regions
- w = src->width;
- h = src->height;
- if (clipRes == splashClipAllInside) {
- x0 = 0;
- y0 = 0;
- x1 = w;
- y1 = h;
- } else {
- if (state->clip->getNumPaths()) {
- x0 = x1 = w;
- y0 = y1 = h;
- } else {
- if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) {
- x0 = 0;
- }
- if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) {
- y0 = 0;
- }
- if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) {
- x1 = w;
- }
- if (x1 < x0) {
- x1 = x0;
- }
- if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) {
- y1 = h;
- }
- if (y1 < y0) {
- y1 = y0;
- }
- }
+void Splash::drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width) {
+ if (y < 0 || y >= bitmap->height) {
+ return;
}
-
- // draw the unclipped region
- if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
- pipeInit(&pipe, NULL,
- (Guchar)splashRound(state->fillAlpha * 255),
- srcAlpha, gFalse);
- if (srcAlpha) {
- for (y = y0; y < y1; ++y) {
- (this->*pipe.run)(&pipe, xDest + x0, xDest + x1 - 1, yDest + y,
- src->alpha + y * src->alphaRowSize + x0,
- src->data + y * src->rowSize + x0 * bitmapComps);
- }
- } else {
- for (y = y0; y < y1; ++y) {
- (this->*pipe.run)(&pipe, xDest + x0, xDest + x1 - 1, yDest + y,
- NULL,
- src->data + y * src->getRowSize() +
- x0 * bitmapComps);
- }
- }
+ if (x < 0) {
+ colorData -= x * data->nComps;
+ width += x;
+ x = 0;
+ }
+ if (x + width > bitmap->width) {
+ width = bitmap->width - x;
+ }
+ if (width <= 0) {
+ return;
}
+ memset(scanBuf + x, 0xff, width);
+ state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ scanBuf + x, colorData);
+}
- // draw the clipped regions
- if (y0 > 0) {
- blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0);
+void Splash::drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width) {
+ if (y < 0 || y >= bitmap->height) {
+ return;
}
- if (y1 < h) {
- blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1);
+ if (x < 0) {
+ colorData -= x * data->nComps;
+ alphaData -= x;
+ width += x;
+ x = 0;
}
- if (x0 > 0 && y0 < y1) {
- blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0);
+ if (x + width > bitmap->width) {
+ width = bitmap->width - x;
}
- if (x1 < w && y0 < y1) {
- blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0,
- w - x1, y1 - y0);
+ if (width <= 0) {
+ return;
}
+ memcpy(scanBuf + x, alphaData, width);
+ state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
+ state->strokeAdjust);
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ scanBuf + x, colorData);
}
-void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
- int xSrc, int ySrc, int xDest, int yDest,
- int w, int h) {
- SplashPipe pipe;
- int y;
-
- if (xDest < 0) {
- xSrc -= xDest;
- w += xDest;
- xDest = 0;
- }
- if (xDest + w > bitmap->width) {
- w = bitmap->width - xDest;
+void Splash::drawImageRowClipAlphaAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width) {
+ if (y < 0 || y >= bitmap->height) {
+ return;
}
- if (yDest < 0) {
- ySrc -= yDest;
- h += yDest;
- yDest = 0;
+ if (x < 0) {
+ colorData -= x * data->nComps;
+ alphaData -= x;
+ width += x;
+ x = 0;
}
- if (yDest + h > bitmap->height) {
- h = bitmap->height - yDest;
+ if (x + width > bitmap->width) {
+ width = bitmap->width - x;
}
- if (w <= 0 || h <= 0) {
+ if (width <= 0) {
return;
}
-
- pipeInit(&pipe, NULL,
- (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
- if (srcAlpha) {
- for (y = 0; y < h; ++y) {
- memcpy(scanBuf + xDest,
- src->alpha + (ySrc + y) * src->alphaRowSize + xSrc,
- w);
- if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, yDest + y, xDest, xDest + w - 1,
- state->strokeAdjust);
- } else {
- state->clip->clipSpanBinary(scanBuf, yDest + y, xDest, xDest + w - 1,
- state->strokeAdjust);
- }
- (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
- scanBuf + xDest,
- src->data + (ySrc + y) * src->rowSize +
- xSrc * bitmapComps);
- }
- } else {
- for (y = 0; y < h; ++y) {
- memset(scanBuf + xDest, 0xff, w);
- if (vectorAntialias) {
- state->clip->clipSpan(scanBuf, yDest + y, xDest, xDest + w - 1,
- state->strokeAdjust);
- } else {
- state->clip->clipSpanBinary(scanBuf, yDest + y, xDest, xDest + w - 1,
- state->strokeAdjust);
- }
- (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
- scanBuf + xDest,
- src->data + (ySrc + y) * src->rowSize +
- xSrc * bitmapComps);
- }
- }
+ memcpy(scanBuf + x, alphaData, width);
+ state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
+ (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+ scanBuf + x, colorData);
}
SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
@@ -6950,6 +7266,101 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
return splashOk;
}
+SplashError Splash::compositeWithOverprint(SplashBitmap *src,
+ Guint *srcOverprintMaskBitmap,
+ int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h,
+ GBool noClip, GBool nonIsolated) {
+ SplashPipe pipe;
+ int x0, x1, y0, y1, y, t;
+
+ if (!(src->mode == bitmap->mode ||
+ (src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) ||
+ (src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) {
+ return splashErrModeMismatch;
+ }
+
+ pipeInit(&pipe, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255),
+ !noClip || src->alpha != NULL, nonIsolated, gTrue);
+
+ if (noClip) {
+ if (src->alpha) {
+ for (y = 0; y < h; ++y) {
+ pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc;
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ src->alpha +
+ (ySrc + y) * src->alphaRowSize + xSrc,
+ src->data + (ySrc + y) * src->rowSize +
+ xSrc * bitmapComps);
+ }
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc;
+ (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+ NULL,
+ src->data + (ySrc + y) * src->rowSize +
+ xSrc * bitmapComps);
+ }
+ }
+ } else {
+ x0 = xDest;
+ if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
+ x0 = t;
+ }
+ x1 = xDest + w;
+ if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
+ x1 = t;
+ }
+ y0 = yDest;
+ if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
+ y0 = t;
+ }
+ y1 = yDest + h;
+ if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
+ y1 = t;
+ }
+ if (x0 < x1 && y0 < y1) {
+ if (src->alpha) {
+ for (y = y0; y < y1; ++y) {
+ memcpy(scanBuf + x0,
+ src->alpha + (ySrc + y - yDest) * src->alphaRowSize +
+ (xSrc + x0 - xDest),
+ x1 - x0);
+ state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
+ pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap
+ + (ySrc + y - yDest) * w
+ + (xSrc + x0 - xDest);
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ (this->*pipe.run)(&pipe, x0, x1 - 1, y,
+ scanBuf + x0,
+ src->data +
+ (ySrc + y - yDest) * src->rowSize +
+ (xSrc + x0 - xDest) * bitmapComps);
+ }
+ } else {
+ for (y = y0; y < y1; ++y) {
+ memset(scanBuf + x0, 0xff, x1 - x0);
+ state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
+ pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap
+ + (ySrc + y - yDest) * w
+ + (xSrc + x0 - xDest);
+ (this->*pipe.run)(&pipe, x0, x1 - 1, y,
+ scanBuf + x0,
+ src->data +
+ (ySrc + y - yDest) * src->rowSize +
+ (xSrc + x0 - xDest) * bitmapComps);
+ }
+ }
+ }
+ }
+
+ return splashOk;
+}
+
void Splash::compositeBackground(SplashColorPtr color) {
SplashColorPtr p;
Guchar *q;
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Splash.h b/Build/source/libs/xpdf/xpdf-src/splash/Splash.h
index f35aa7eafd9..d6cc33a5fad 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/Splash.h
+++ b/Build/source/libs/xpdf/xpdf-src/splash/Splash.h
@@ -29,6 +29,17 @@ class SplashPath;
class SplashXPath;
class SplashFont;
struct SplashPipe;
+struct SplashDrawImageMaskRowData;
+class ImageScaler;
+typedef void (Splash::*SplashDrawImageMaskRowFunc)(
+ SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width);
+struct SplashDrawImageRowData;
+typedef void (Splash::*SplashDrawImageRowFunc)(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width);
//------------------------------------------------------------------------
@@ -66,6 +77,15 @@ enum SplashPipeResultColorCtrl {
};
//------------------------------------------------------------------------
+
+// Transparency group destination bitmap initialization control.
+enum SplashGroupDestInitMode {
+ splashGroupDestPreInit, // dest is already initialized
+ splashGroupDestInitZero, // initialize to zero (isolated group)
+ splashGroupDestInitCopy // copy backdrop (non-isolated group)
+};
+
+//------------------------------------------------------------------------
// SplashImageCache
//------------------------------------------------------------------------
@@ -76,19 +96,23 @@ public:
SplashImageCache();
~SplashImageCache();
+ GBool match(GString *aTag, int aWidth, int aHeight,
+ SplashColorMode aMode, GBool aAlpha,
+ GBool aInterpolate);
+ void reset(GString *aTag, int aWidth, int aHeight,
+ SplashColorMode aMode, GBool aAlpha,
+ GBool aInterpolate);
void incRefCount();
void decRefCount();
GString *tag;
- GBool isMask;
int width;
int height;
SplashColorMode mode;
GBool alpha;
GBool interpolate;
- GBool vertFlip;
- GBool horizFlip;
- SplashBitmap *image;
+ Guchar *colorData;
+ Guchar *alphaData;
int refCount;
};
@@ -161,7 +185,9 @@ public:
void setSoftMask(SplashBitmap *softMask);
void setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
int groupBackXA, int groupBackYA,
+ SplashGroupDestInitMode groupDestInitModeA,
GBool nonIsolated, GBool knockout);
+ void forceDeferredInit(int y, int h);
void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
void setOverprintMask(Guint overprintMask);
void setEnablePathSimplification(GBool en);
@@ -234,6 +260,15 @@ public:
int xDest, int yDest, int w, int h,
GBool noClip, GBool nonIsolated);
+ // Composite a rectangular region from <src> onto this Splash
+ // object, using <srcOverprintMaskBitmap> as the overprint mask per
+ // pixel. This is only supported for CMYK and DeviceN bitmaps.
+ SplashError compositeWithOverprint(SplashBitmap *src,
+ Guint *srcOverprintMaskBitmap,
+ int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h,
+ GBool noClip, GBool nonIsolated);
+
// Composite this Splash object onto a background color. The
// background alpha is assumed to be 1.
void compositeBackground(SplashColorPtr color);
@@ -269,6 +304,10 @@ public:
// Return the associated bitmap.
SplashBitmap *getBitmap() { return bitmap; }
+ // Enable writing the per-pixel overprint mask to a separate bitmap.
+ void setOverprintMaskBitmap(Guint *overprintMaskBitmapA)
+ { overprintMaskBitmap = overprintMaskBitmapA; }
+
// Set the minimum line width.
void setMinLineWidth(SplashCoord w) { minLineWidth = w; }
@@ -298,7 +337,7 @@ private:
void pipeInit(SplashPipe *pipe, SplashPattern *pattern,
Guchar aInput, GBool usesShape,
- GBool nonIsolatedGroup);
+ GBool nonIsolatedGroup, GBool usesSrcOverprint = gFalse);
void pipeRun(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr);
void pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y,
@@ -325,6 +364,8 @@ private:
void pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr);
#endif
+ void pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
void pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr);
void pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y,
@@ -337,6 +378,16 @@ private:
void pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr);
#endif
+ void pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+ void pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+#if SPLASH_CMYK
+ void pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+ Guchar *shapePtr, SplashColorPtr cSrcPtr);
+#endif
void pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr);
void pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y,
@@ -347,6 +398,8 @@ private:
void pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y,
Guchar *shapePtr, SplashColorPtr cSrcPtr);
#endif
+ void useDestRow(int y);
+ void copyGroupBackdropRow(int y);
void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
SplashCoord *xo, SplashCoord *yo);
void updateModX(int x);
@@ -371,92 +424,81 @@ private:
SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph);
void getImageBounds(SplashCoord xyMin, SplashCoord xyMax,
int *xyMinI, int *xyMaxI);
- void upscaleMask(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- SplashCoord *mat, GBool glyphMode,
- GBool interpolate);
- void arbitraryTransformMask(GString *imageTag,
- SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- SplashCoord *mat, GBool glyphMode,
- GBool interpolate);
- SplashBitmap *scaleMask(GString *imageTag,
- SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- GBool interpolate);
- void scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleMaskYuXuI(SplashImageMaskSource src, void *srcData,
- int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void blitMask(SplashBitmap *src, int xDest, int yDest,
- SplashClipResult clipRes);
- void upscaleImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- SplashCoord *mat, GBool interpolate);
- void arbitraryTransformImage(GString *imageTag,
- SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha,
- int srcWidth, int srcHeight,
- SplashCoord *mat, GBool interpolate);
- SplashBitmap *scaleImage(GString *imageTag,
- SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- GBool interpolate);
- void scaleImageYdXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYdXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYuXd(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYuXu(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
+ void drawImageMaskArbitraryNoInterp(Guchar *scaledMask,
+ SplashDrawImageMaskRowData *dd,
+ SplashDrawImageMaskRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax);
+ void drawImageMaskArbitraryInterp(Guchar *scaledMask,
+ SplashDrawImageMaskRowData *dd,
+ SplashDrawImageMaskRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax);
+ void mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width);
+ void drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width);
+ void drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width);
+ void drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data,
+ Guchar *maskData,
+ int x, int y, int width);
+ ImageScaler *getImageScaler(GString *imageTag,
+ SplashImageSource src, void *srcData,
+ int w, int h, int nComps,
+ int scaledWidth, int scaledHeight,
+ SplashColorMode srcMode,
+ GBool srcAlpha, GBool interpolate);
+ void getScaledImage(GString *imageTag,
+ SplashImageSource src, void *srcData,
+ int w, int h, int nComps,
int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void scaleImageYuXuI(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, int nComps,
- GBool srcAlpha, int srcWidth, int srcHeight,
- int scaledWidth, int scaledHeight,
- SplashBitmap *dest);
- void vertFlipImage(SplashBitmap *img, int width, int height,
- int nComps);
- void horizFlipImage(SplashBitmap *img, int width, int height,
- int nComps);
- void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
- SplashClipResult clipRes);
- void blitImageClipped(SplashBitmap *src, GBool srcAlpha,
- int xSrc, int ySrc, int xDest, int yDest,
- int w, int h);
+ SplashColorMode srcMode,
+ GBool srcAlpha, GBool interpolate,
+ Guchar **scaledColor, Guchar **scaledAlpha,
+ GBool *freeScaledImage);
+ void drawImageArbitraryNoInterp(Guchar *scaledColor, Guchar *scaledAlpha,
+ SplashDrawImageRowData *dd,
+ SplashDrawImageRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax,
+ int nComps, GBool srcAlpha);
+ void drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha,
+ SplashDrawImageRowData *dd,
+ SplashDrawImageRowFunc drawRowFunc,
+ SplashCoord *invMat,
+ int scaledWidth, int scaledHeight,
+ int xMin, int yMin, int xMax, int yMax,
+ int nComps, GBool srcAlpha);
+ void mirrorImageRow(Guchar *colorIn, Guchar *alphaIn,
+ Guchar *colorOut, Guchar *alphaOut,
+ int width, int nComps, GBool srcAlpha);
+ void drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data,
+ Guchar *colorData, Guchar *alphaData,
+ int x, int y, int width);
+ void drawImageRowNoClipAlpha(SplashDrawImageRowData *data,
+ Guchar *colorData, Guchar *alphaData,
+ int x, int y, int width);
+ void drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width);
+ void drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width);
+ void drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width);
+ void drawImageRowClipAlphaAA(SplashDrawImageRowData *data,
+ Guchar *colorData,
+ Guchar *alphaData,
+ int x, int y, int width);
void dumpPath(SplashPath *path);
void dumpXPath(SplashXPath *path);
@@ -474,6 +516,9 @@ private:
SplashBitmap // for transparency groups, this is the bitmap
*groupBackBitmap; // containing the alpha0/color0 values
int groupBackX, groupBackY; // offset within groupBackBitmap
+ SplashGroupDestInitMode groupDestInitMode;
+ int groupDestInitYMin, groupDestInitYMax;
+ Guint *overprintMaskBitmap;
SplashCoord minLineWidth;
int modXMin, modYMin, modXMax, modYMax;
SplashClipResult opClipRes;
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc
index 88ce49ca3b4..db341d7c733 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc
+++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc
@@ -16,6 +16,8 @@
#include <limits.h>
#include "gmem.h"
#include "gmempp.h"
+#include "gfile.h"
+#include "Trace.h"
#include "SplashErrorCodes.h"
#include "SplashBitmap.h"
@@ -64,6 +66,11 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
rowSize += rowPad - 1;
rowSize -= rowSize % rowPad;
+ traceAlloc(this, "alloc bitmap: %d x %d x %d %s -> %lld bytes",
+ width, height, splashColorModeNComps[mode],
+ alphaA ? "with alpha" : "without alpha",
+ height * rowSize + (alphaA ? height * width : 0));
+
parent = parentA;
oldData = NULL;
oldAlpha = NULL;
@@ -75,8 +82,14 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
parent->oldHeight == height) {
data = parent->oldData;
parent->oldData = NULL;
+ traceMessage("reusing bitmap memory");
} else {
data = (SplashColorPtr)gmallocn64(height, rowSize);
+ traceMessage("not reusing bitmap memory"
+ " (parent=%p parent->oldData=%p same-size=%d)",
+ parent, parent ? parent->oldData : NULL,
+ parent ? (parent->oldRowSize == rowSize &&
+ parent->oldHeight == height) : 0);
}
if (!topDown) {
data += (height - 1) * rowSize;
@@ -99,11 +112,12 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
}
SplashBitmap::~SplashBitmap() {
+ traceFree(this, "free bitmap");
if (data && rowSize < 0) {
rowSize = -rowSize;
data -= (height - 1) * rowSize;
}
- if (parent && rowSize > 10000000 / height) {
+ if (parent && rowSize > 4000000 / height) {
gfree(parent->oldData);
gfree(parent->oldAlpha);
parent->oldData = data;
@@ -123,7 +137,7 @@ SplashError SplashBitmap::writePNMFile(char *fileName) {
FILE *f;
SplashError err;
- if (!(f = fopen(fileName, "wb"))) {
+ if (!(f = openFile(fileName, "wb"))) {
return splashErrOpenFile;
}
err = writePNMFile(f);
@@ -211,7 +225,7 @@ SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
if (!alpha) {
return splashErrModeMismatch;
}
- if (!(f = fopen(fileName, "wb"))) {
+ if (!(f = openFile(fileName, "wb"))) {
return splashErrOpenFile;
}
fprintf(f, "P5\n%d %d\n255\n", width, height);
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h
index 44980833668..54975a377a2 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h
+++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h
@@ -17,6 +17,10 @@
#include <stdio.h>
#include <limits.h>
+// older compilers won't define SIZE_MAX in stdint.h without this
+#ifndef __STDC_LIMIT_MACROS
+# define __STDC_LIMIT_MACROS 1
+#endif
#include <stdint.h>
#include "SplashTypes.h"
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc
index add34311756..2fcd83d1266 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc
+++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFont.cc
@@ -71,7 +71,11 @@ void SplashFont::initCache() {
// if the glyphs are too large, don't cache them -- setting the
// cache bitmap size to something tiny will cause getGlyph() to
// fall back to the uncached case
- glyphW = glyphH = 1;
+ glyphW = glyphH = 0;
+ glyphSize = 0;
+ cacheSets = 0;
+ cacheAssoc = 0;
+ return;
}
if (aa) {
glyphSize = glyphW * glyphH;
@@ -117,29 +121,33 @@ GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
}
// check the cache
- i = (c & (cacheSets - 1)) * cacheAssoc;
- for (j = 0; j < cacheAssoc; ++j) {
- if ((cacheTags[i+j].mru & 0x80000000) &&
- cacheTags[i+j].c == c &&
- (int)cacheTags[i+j].xFrac == xFrac &&
- (int)cacheTags[i+j].yFrac == yFrac) {
- bitmap->x = cacheTags[i+j].x;
- bitmap->y = cacheTags[i+j].y;
- bitmap->w = cacheTags[i+j].w;
- bitmap->h = cacheTags[i+j].h;
- for (k = 0; k < cacheAssoc; ++k) {
- if (k != j &&
- (cacheTags[i+k].mru & 0x7fffffff) <
+ if (cache) {
+ i = (c & (cacheSets - 1)) * cacheAssoc;
+ for (j = 0; j < cacheAssoc; ++j) {
+ if ((cacheTags[i+j].mru & 0x80000000) &&
+ cacheTags[i+j].c == c &&
+ (int)cacheTags[i+j].xFrac == xFrac &&
+ (int)cacheTags[i+j].yFrac == yFrac) {
+ bitmap->x = cacheTags[i+j].x;
+ bitmap->y = cacheTags[i+j].y;
+ bitmap->w = cacheTags[i+j].w;
+ bitmap->h = cacheTags[i+j].h;
+ for (k = 0; k < cacheAssoc; ++k) {
+ if (k != j &&
+ (cacheTags[i+k].mru & 0x7fffffff) <
(cacheTags[i+j].mru & 0x7fffffff)) {
- ++cacheTags[i+k].mru;
+ ++cacheTags[i+k].mru;
+ }
}
+ cacheTags[i+j].mru = 0x80000000;
+ bitmap->aa = aa;
+ bitmap->data = cache + (i+j) * glyphSize;
+ bitmap->freeData = gFalse;
+ return gTrue;
}
- cacheTags[i+j].mru = 0x80000000;
- bitmap->aa = aa;
- bitmap->data = cache + (i+j) * glyphSize;
- bitmap->freeData = gFalse;
- return gTrue;
}
+ } else {
+ i = 0; // make gcc happy
}
// generate the glyph bitmap
@@ -149,7 +157,7 @@ GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
// if the glyph doesn't fit in the bounding box, return a temporary
// uncached bitmap
- if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
+ if (!cache || bitmap2.w > glyphW || bitmap2.h > glyphH) {
*bitmap = bitmap2;
return gTrue;
}
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc
index fe377fe25f4..81afe0cd914 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc
+++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc
@@ -20,6 +20,7 @@
#include "gmem.h"
#include "gmempp.h"
#include "GString.h"
+#include "GList.h"
#include "SplashMath.h"
#include "SplashFTFontEngine.h"
#include "SplashFontFile.h"
@@ -48,6 +49,7 @@ SplashFontEngine::SplashFontEngine(
for (i = 0; i < splashFontCacheSize; ++i) {
fontCache[i] = NULL;
}
+ badFontFiles = new GList();
#if HAVE_FREETYPE_H
if (enableFreeType) {
@@ -66,6 +68,7 @@ SplashFontEngine::~SplashFontEngine() {
delete fontCache[i];
}
}
+ deleteGList(badFontFiles, SplashFontFileID);
#if HAVE_FREETYPE_H
if (ftEngine) {
@@ -89,6 +92,15 @@ SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
return NULL;
}
+GBool SplashFontEngine::checkForBadFontFile(SplashFontFileID *id) {
+ for (int i = 0; i < badFontFiles->getLength(); ++i) {
+ if (((SplashFontFileID *)badFontFiles->get(i))->matches(id)) {
+ return gTrue;
+ }
+ }
+ return gFalse;
+}
+
SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
#if LOAD_FONTS_FROM_MEM
GString *fontBuf,
@@ -122,6 +134,10 @@ SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
}
#endif
+ if (!fontFile) {
+ badFontFiles->append(idA);
+ }
+
return fontFile;
}
@@ -162,6 +178,10 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
}
#endif
+ if (!fontFile) {
+ badFontFiles->append(idA);
+ }
+
return fontFile;
}
@@ -202,6 +222,10 @@ SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
}
#endif
+ if (!fontFile) {
+ badFontFiles->append(idA);
+ }
+
return fontFile;
}
@@ -243,6 +267,10 @@ SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
}
#endif
+ if (!fontFile) {
+ badFontFiles->append(idA);
+ }
+
return fontFile;
}
@@ -284,6 +312,10 @@ SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
}
#endif
+ if (!fontFile) {
+ badFontFiles->append(idA);
+ }
+
return fontFile;
}
@@ -327,6 +359,10 @@ SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
}
#endif
+ if (!fontFile) {
+ badFontFiles->append(idA);
+ }
+
return fontFile;
}
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h
index f9eab4d00f4..59adb95858a 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h
+++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h
@@ -17,6 +17,7 @@
#include "gtypes.h"
class GString;
+class GList;
class SplashFTFontEngine;
class SplashDTFontEngine;
@@ -54,6 +55,10 @@ public:
// matching entry in the cache.
SplashFontFile *getFontFile(SplashFontFileID *id);
+ // Returns true if [id] refers to a bad font file, i.e., if one of
+ // the loadXXXFont functions has returned NULL for that ID.
+ GBool checkForBadFontFile(SplashFontFileID *id);
+
// Load fonts - these create new SplashFontFile objects.
SplashFontFile *loadType1Font(SplashFontFileID *idA,
#if LOAD_FONTS_FROM_MEM
@@ -114,6 +119,7 @@ public:
private:
SplashFont *fontCache[splashFontCacheSize];
+ GList *badFontFiles; // [SplashFontFileID]
#if HAVE_FREETYPE_H
SplashFTFontEngine *ftEngine;
diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc
index 01a94987637..4c77765723e 100644
--- a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc
+++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc
@@ -593,7 +593,8 @@ void SplashXPath::finishSegments() {
seg->dydx = 0;
}
#else
- if (seg->y0 == seg->y1 || seg->x0 == seg->x1) {
+ if (splashAbs(seg->y1 - seg->y0) < 1e-200 ||
+ splashAbs(seg->x1 - seg->x0) < 1e-200) {
seg->dxdy = 0;
seg->dydx = 0;
} else {