[poppler] Branch 'xpdf303merge' - 5 commits - poppler/CairoOutputDev.cc poppler/CairoOutputDev.h poppler/Gfx.cc poppler/Gfx.h poppler/GfxState.cc poppler/GfxState.h poppler/GlobalParams.cc poppler/GlobalParams.h poppler/OutputDev.h poppler/PreScanOutputDev.cc poppler/PreScanOutputDev.h poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/SplashOutputDev.cc poppler/SplashOutputDev.h splash/Splash.cc splash/SplashFontEngine.cc splash/SplashFontEngine.h splash/SplashFTFont.cc splash/SplashFTFontEngine.cc splash/SplashFTFontEngine.h splash/SplashFTFont.h splash/Splash.h splash/SplashXPath.cc utils/ImageOutputDev.cc utils/ImageOutputDev.h
Albert Astals Cid
aacid at kemper.freedesktop.org
Tue Jan 10 14:39:14 PST 2012
poppler/CairoOutputDev.cc | 2
poppler/CairoOutputDev.h | 4
poppler/Gfx.cc | 45
poppler/Gfx.h | 15
poppler/GfxState.cc | 5
poppler/GfxState.h | 7
poppler/GlobalParams.cc | 17
poppler/GlobalParams.h | 3
poppler/OutputDev.h | 3
poppler/PSOutputDev.cc | 2
poppler/PSOutputDev.h | 2
poppler/PreScanOutputDev.cc | 15
poppler/PreScanOutputDev.h | 2
poppler/SplashOutputDev.cc | 11
poppler/SplashOutputDev.h | 4
splash/Splash.cc | 2824 +++++++++++++++++++++++++++++--------------
splash/Splash.h | 60
splash/SplashFTFont.cc | 34
splash/SplashFTFont.h | 1
splash/SplashFTFontEngine.cc | 7
splash/SplashFTFontEngine.h | 5
splash/SplashFontEngine.cc | 3
splash/SplashFontEngine.h | 1
splash/SplashXPath.cc | 22
utils/ImageOutputDev.cc | 2
utils/ImageOutputDev.h | 2
26 files changed, 2116 insertions(+), 982 deletions(-)
New commits:
commit 52d190d8ff962a57a59218f6871c3a63a443ea53
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Jan 10 23:33:40 2012 +0100
[xpdf303] tiling "merges" from Thomas, using mostly our "old" code instead of xpdf's
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 2ab9a11..295eb94 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -751,7 +751,7 @@ void CairoOutputDev::eoFill(GfxState *state) {
}
-GBool CairoOutputDev::tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *cat, Object *str,
double *pmat, int paintType, int /*tilingType*/, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 2d67ae1..b00ab96 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -159,7 +159,7 @@ public:
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
virtual void clipToStrokePath(GfxState *state);
- virtual GBool tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
@@ -432,7 +432,7 @@ public:
virtual void stroke(GfxState *state) { }
virtual void fill(GfxState *state) { }
virtual void eoFill(GfxState *state) { }
- virtual GBool tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index cbdb1a3..9ac8fa9 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -1985,7 +1985,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
GfxPatternColorSpace *patCS;
GfxColorSpace *cs;
GfxColor color;
- GfxPath *savedPath;
+ GfxState *savedState;
double xMin, yMin, xMax, yMax, x, y, x1, y1;
double cxMin, cyMin, cxMax, cyMax;
int xi0, yi0, xi1, yi1, xi, yi;
@@ -2036,12 +2036,13 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
// save current graphics state
- savedPath = state->getPath()->copy();
- saveState();
+ savedState = saveStateStack();
// set underlying color space (for uncolored tiling patterns); set
// various other parameters (stroke color, line width) to match
// Adobe's behavior
+ state->setFillPattern(NULL);
+ state->setStrokePattern(NULL);
if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
state->setFillColorSpace(cs->copy());
out->updateFillColorSpace(state);
@@ -2052,6 +2053,8 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
} else {
state->setStrokeColor(state->getFillColor());
}
+ out->updateFillColor(state);
+ out->updateStrokeColor(state);
} else {
cs = new GfxDeviceGrayColorSpace();
state->setFillColorSpace(cs);
@@ -2062,10 +2065,10 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
state->setStrokeColor(&color);
out->updateStrokeColorSpace(state);
}
- state->setFillPattern(NULL);
- out->updateFillColor(state);
- state->setStrokePattern(NULL);
- out->updateStrokeColor(state);
+ if (!stroke) {
+ state->setLineWidth(0);
+ out->updateLineWidth(state);
+ }
// clip to current path
if (stroke) {
@@ -2080,8 +2083,6 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
}
}
state->clearPath();
- state->setLineWidth(0);
- out->updateLineWidth(state);
// get the clip region, check for empty
state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
@@ -2145,7 +2146,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
m1[4] = m[4];
m1[5] = m[5];
if (out->useTilingPatternFill() &&
- out->tilingPatternFill(state, catalog, tPat->getContentStream(),
+ out->tilingPatternFill(state, this, catalog, tPat->getContentStream(),
tPat->getMatrix(), tPat->getPaintType(), tPat->getTilingType(),
tPat->getResDict(), m1, tPat->getBBox(),
xi0, yi0, xi1, yi1, xstep, ystep)) {
@@ -2166,8 +2167,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
// restore graphics state
restore:
- restoreState();
- state->setPath(savedPath);
+ restoreStateStack(savedState);
}
void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
@@ -5100,6 +5100,27 @@ void Gfx::restoreState() {
stackHeight--;
}
+// Create a new state stack, and initialize it with a copy of the
+// current state.
+GfxState *Gfx::saveStateStack() {
+ GfxState *oldState;
+
+ out->saveState(state);
+ oldState = state;
+ state = state->copy(gTrue);
+ return oldState;
+}
+
+// Switch back to the previous state stack.
+void Gfx::restoreStateStack(GfxState *oldState) {
+ while (state->hasSaves()) {
+ restoreState();
+ }
+ delete state;
+ state = oldState;
+ out->restoreState(state);
+}
+
void Gfx::pushResources(Dict *resDict) {
res = new GfxResources(xref, resDict, res);
}
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 2db341b..32fe9cc 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -181,6 +181,13 @@ public:
// Get the current graphics state object.
GfxState *getState() { return state; }
+ void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
+ GBool transpGroup = gFalse, GBool softMask = gFalse,
+ GfxColorSpace *blendingColorSpace = NULL,
+ GBool isolated = gFalse, GBool knockout = gFalse,
+ GBool alpha = gFalse, Function *transferFunc = NULL,
+ GfxColor *backdropColor = NULL);
+
void pushResources(Dict *resDict);
void popResources();
@@ -347,12 +354,6 @@ private:
void opXObject(Object args[], int numArgs);
void doImage(Object *ref, Stream *str, GBool inlineImg);
void doForm(Object *str);
- void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
- GBool transpGroup = gFalse, GBool softMask = gFalse,
- GfxColorSpace *blendingColorSpace = NULL,
- GBool isolated = gFalse, GBool knockout = gFalse,
- GBool alpha = gFalse, Function *transferFunc = NULL,
- GfxColor *backdropColor = NULL);
// in-line image operators
void opBeginImage(Object args[], int numArgs);
@@ -372,6 +373,8 @@ private:
void opBeginMarkedContent(Object args[], int numArgs);
void opEndMarkedContent(Object args[], int numArgs);
void opMarkPoint(Object args[], int numArgs);
+ GfxState *saveStateStack();
+ void restoreStateStack(GfxState *oldState);
GBool contentIsHidden();
void pushMarkedContent();
void popMarkedContent();
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 224b9cf..7475ab4 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -5580,7 +5580,7 @@ GfxState::~GfxState() {
}
// Used for copy();
-GfxState::GfxState(GfxState *state) {
+GfxState::GfxState(GfxState *state, GBool copyPath) {
int i;
memcpy(this, state, sizeof(GfxState));
@@ -5608,6 +5608,9 @@ GfxState::GfxState(GfxState *state) {
if (font)
font->incRefCnt();
+ if (copyPath) {
+ path = state->path->copy();
+ }
saved = NULL;
}
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 632acc1..c8995e3 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -1312,8 +1312,9 @@ public:
// Destructor.
~GfxState();
- // Copy.
- GfxState *copy() { return new GfxState(this); }
+ // Copy.
+ GfxState *copy(GBool copyPath = gFalse)
+ { return new GfxState(this, copyPath); }
// Accessors.
double getHDPI() { return hDPI; }
@@ -1539,7 +1540,7 @@ private:
GfxState *saved; // next GfxState on stack
- GfxState(GfxState *state);
+ GfxState(GfxState *state, GBool copyPath);
};
#endif
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index 75f2bd0..03e1613 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -43,6 +43,7 @@ class Dict;
class GooHash;
class GooString;
class GfxState;
+class Gfx;
struct GfxColor;
class GfxColorSpace;
class GfxImageColorMap;
@@ -196,7 +197,7 @@ public:
virtual void stroke(GfxState * /*state*/) {}
virtual void fill(GfxState * /*state*/) {}
virtual void eoFill(GfxState * /*state*/) {}
- virtual GBool tilingPatternFill(GfxState * /*state*/, Catalog * /*cat*/, Object * /*str*/,
+ virtual GBool tilingPatternFill(GfxState * /*state*/, Gfx * /*gfx*/, Catalog * /*cat*/, Object * /*str*/,
double * /*pmat*/, int /*paintType*/, int /*tilingType*/, Dict * /*resDict*/,
double * /*mat*/, double * /*bbox*/,
int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/,
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 37e4bb6..5db5a31 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -4124,7 +4124,7 @@ GBool PSOutputDev::tilingPatternFillL2(GfxState *state, Catalog *cat, Object *st
return gTrue;
}
-GBool PSOutputDev::tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+GBool PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 57ede3f..11ebbb8 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -209,7 +209,7 @@ public:
virtual void stroke(GfxState *state);
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
- virtual GBool tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
diff --git a/poppler/PreScanOutputDev.cc b/poppler/PreScanOutputDev.cc
index b82828d..1c5d09a 100644
--- a/poppler/PreScanOutputDev.cc
+++ b/poppler/PreScanOutputDev.cc
@@ -81,18 +81,17 @@ void PreScanOutputDev::eoFill(GfxState *state) {
state->getFillOpacity(), state->getBlendMode());
}
-GBool PreScanOutputDev::tilingPatternFill(GfxState *state, Catalog *catalog, Object *str,
+GBool PreScanOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *catalog, Object *str,
double *pmat, int paintType, int /*tilingType*/, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
double xStep, double yStep) {
- PDFRectangle box;
- Gfx *gfx;
- box.x1 = bbox[0]; box.y1 = bbox[1];
- box.x2 = bbox[2]; box.y2 = bbox[3];
- gfx = new Gfx(doc, this, resDict, &box, NULL);
- gfx->display(str);
- delete gfx;
+ if (paintType == 1) {
+ gfx->doForm1(str, resDict, mat, bbox);
+ } else {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+ }
return gTrue;
}
diff --git a/poppler/PreScanOutputDev.h b/poppler/PreScanOutputDev.h
index d94afaa..ac147f3 100644
--- a/poppler/PreScanOutputDev.h
+++ b/poppler/PreScanOutputDev.h
@@ -80,7 +80,7 @@ public:
virtual void stroke(GfxState *state);
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
- virtual GBool tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 020808e..58382ca 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -1359,6 +1359,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
textClipPath = NULL;
haveCSPattern = gFalse;
transpGroupStack = NULL;
+ nestCount = 0;
}
void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
@@ -2384,6 +2385,7 @@ void SplashOutputDev::endType3Char(GfxState *state) {
double *ctm;
if (t3GlyphStack->cacheTag) {
+ --nestCount;
memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
t3GlyphStack->cache->glyphSize);
delete bitmap;
@@ -2525,6 +2527,7 @@ void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
-t3Font->glyphX, -t3Font->glyphY);
updateCTM(state, 0, 0, 0, 0, 0, 0);
+ ++nestCount;
}
void SplashOutputDev::drawType3Glyph(GfxState *state, T3FontCache *t3Font,
@@ -3681,10 +3684,12 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
transpGroup->tBitmap = bitmap;
state->shiftCTM(-tx, -ty);
updateCTM(state, 0, 0, 0, 0, 0, 0);
+ ++nestCount;
}
void SplashOutputDev::endTransparencyGroup(GfxState *state) {
// restore state
+ --nestCount;
delete splash;
bitmap = transpGroupStack->origBitmap;
splash = transpGroupStack->origSplash;
@@ -3896,7 +3901,7 @@ void SplashOutputDev::setFreeTypeHinting(GBool enable, GBool enableSlightHinting
enableSlightHinting = enableSlightHintingA;
}
-GBool SplashOutputDev::tilingPatternFill(GfxState *state, Catalog *catalog, Object *str,
+GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *catalog, Object *str,
double *ptm, int paintType, int /*tilingType*/, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
@@ -4056,7 +4061,6 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Catalog *catalog, Obje
matc[1] = ctm[1];
matc[2] = ctm[2];
matc[3] = ctm[3];
- splash->setOverprintMask(0xffffffff);
splash->drawImage(&tilingBitmapSrc, &imgData, colorMode, gTrue, result_width, result_height, matc);
delete tBitmap;
delete gfx;
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index c06359a..8975c65 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -273,7 +273,7 @@ public:
virtual void stroke(GfxState *state);
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
- virtual GBool tilingPatternFill(GfxState *state, Catalog *catalog, Object *str,
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *catalog, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
@@ -441,6 +441,7 @@ private:
SplashTransparencyGroup * // transparency group stack
transpGroupStack;
SplashBitmap *maskBitmap; // for image masks in pattern colorspace
+ int nestCount;
};
#endif
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 7c65f77..a188f34 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -2636,7 +2636,7 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
blitMask(scaledMask, x0, y0, clipRes);
delete scaledMask;
}
-
+
// scaling plus vertical flip
} else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
x0 = imgCoordMungeLowerC(mat[4], glyphMode);
@@ -3412,7 +3412,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
delete scaledImg;
}
-
+
// scaling plus vertical flip
} else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
x0 = imgCoordMungeLower(mat[4]);
@@ -3467,7 +3467,7 @@ SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData
SplashClipResult clipRes, clipRes2;
SplashPipe pipe;
SplashColor pixel;
- int scaledWidth, scaledHeight, t0, t1;
+ int scaledWidth, scaledHeight, t0, t1, th;
SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
SplashCoord vx[4], vy[4];
int xMin, yMin, xMax, yMax;
@@ -3524,13 +3524,29 @@ SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData
scaledWidth = t0 > t1 ? t0 : t1;
if (mat[2] >= 0) {
t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]);
+ if (splashAbs(mat[1]) >= 1) {
+ th = imgCoordMungeUpper(mat[2]) - imgCoordMungeLower(mat[0] * mat[3] / mat[1]);
+ if (th > t0) t0 = th;
+ }
} else {
t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]);
+ if (splashAbs(mat[1]) >= 1) {
+ th = imgCoordMungeUpper(mat[0] * mat[3] / mat[1]) - imgCoordMungeLower(mat[2]);
+ if (th > t0) t0 = th;
+ }
}
if (mat[3] >= 0) {
t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]);
+ if (splashAbs(mat[0]) >= 1) {
+ th = imgCoordMungeUpper(mat[3]) - imgCoordMungeLower(mat[1] * mat[2] / mat[0]);
+ if (th > t1) t1 = th;
+ }
} else {
t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]);
+ if (splashAbs(mat[0]) >= 1) {
+ th = imgCoordMungeUpper(mat[1] * mat[2] / mat[0]) - imgCoordMungeLower(mat[3]);
+ if (th > t1) t1 = th;
+ }
}
scaledHeight = t0 > t1 ? t0 : t1;
if (scaledWidth == 0) {
@@ -3901,7 +3917,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix2;
*destPtr++ = (Guchar)pix1;
*destPtr++ = (Guchar)pix0;
- *destPtr++ = (Guchar)255;
+ *destPtr++ = (Guchar)255;
break;
case splashModeBGR8:
@@ -4081,7 +4097,7 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix[2];
*destPtr++ = (Guchar)pix[1];
*destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)255;
+ *destPtr++ = (Guchar)255;
}
break;
case splashModeBGR8:
@@ -4222,7 +4238,7 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix[2];
*destPtr++ = (Guchar)pix[1];
*destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)255;
+ *destPtr++ = (Guchar)255;
}
break;
case splashModeBGR8:
@@ -4365,7 +4381,7 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
*destPtr++ = (Guchar)pix[2];
*destPtr++ = (Guchar)pix[1];
*destPtr++ = (Guchar)pix[0];
- *destPtr++ = (Guchar)255;
+ *destPtr++ = (Guchar)255;
}
}
break;
@@ -5243,7 +5259,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w,
GBool flatten) {
- SplashPath *pathIn, *dashPath, *pathOut;
+SplashPath *pathIn, *dashPath, *pathOut;
SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
SplashCoord crossprod, dotprod, miter, m;
GBool first, last, closed;
diff --git a/utils/ImageOutputDev.cc b/utils/ImageOutputDev.cc
index b35869f..dd855bb 100644
--- a/utils/ImageOutputDev.cc
+++ b/utils/ImageOutputDev.cc
@@ -70,7 +70,7 @@ void ImageOutputDev::setFilename(const char *fileExt) {
}
}
-GBool ImageOutputDev::tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+GBool ImageOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
diff --git a/utils/ImageOutputDev.h b/utils/ImageOutputDev.h
index 1e43308..fabe6b5 100644
--- a/utils/ImageOutputDev.h
+++ b/utils/ImageOutputDev.h
@@ -84,7 +84,7 @@ public:
virtual GBool useDrawChar() { return gFalse; }
//----- path painting
- virtual GBool tilingPatternFill(GfxState *state, Catalog *cat, Object *str,
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
double *pmat, int paintType, int tilingType, Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
commit bf75a957650dd5208ecf1f6db1555a3d00b7949c
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Jan 10 23:31:27 2012 +0100
[xpdf303] Splash::blitTransparent merges from Thomas
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 0ef97ed..7c65f77 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -5151,7 +5151,7 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h) {
SplashColorPtr p, sp;
Guchar *q;
- int x, y, mask;
+ int x, y, mask, srcMask;
if (src->mode != bitmap->mode) {
return splashErrModeMismatch;
@@ -5161,10 +5161,11 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
case splashModeMono1:
for (y = 0; y < h; ++y) {
p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
- sp = &src->data[(ySrc + y) * bitmap->rowSize + (xSrc >> 3)];
mask = 0x80 >> (xDest & 7);
+ sp = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)];
+ srcMask = 0x80 >> (xSrc & 7);
for (x = 0; x < w; ++x) {
- if (sp[0] & (0x80 >> (x & 7))) {
+ if (*sp & srcMask) {
*p |= mask;
} else {
*p &= ~mask;
@@ -5172,6 +5173,9 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
if (!(mask >>= 1)) {
mask = 0x80;
++p;
+ }
+ if (!(srcMask >>= 1)) {
+ srcMask = 0x80;
++sp;
}
}
commit 296244ab74e56b2781daae0a664617d1da30527c
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Jan 10 23:30:34 2012 +0100
[xpdf303] Merge xpath Splash stuff from Thomas
diff --git a/splash/SplashXPath.cc b/splash/SplashXPath.cc
index c3cb62c..1d6119c 100644
--- a/splash/SplashXPath.cc
+++ b/splash/SplashXPath.cc
@@ -71,8 +71,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
SplashXPathPoint *pts;
SplashXPathAdjust *adjusts, *adjust;
SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
- SplashCoord adj0, adj1, w;
- int ww;
+ SplashCoord adj0, adj1;
int curSubpath, i, j;
// transform the points
@@ -114,19 +113,24 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
adj0 = adj1;
adj1 = x0;
}
- w = adj1 - adj0;
- ww = splashRound(w);
- if (ww == 0) {
- ww = 1;
- }
adjusts[i].x0a = adj0 - 0.01;
adjusts[i].x0b = adj0 + 0.01;
adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
adjusts[i].x1a = adj1 - 0.01;
adjusts[i].x1b = adj1 + 0.01;
- adjusts[i].x0 = (SplashCoord)splashRound(adj0);
- adjusts[i].x1 = adjusts[i].x0 + ww - 0.01;
+ // rounding both edge coordinates can result in lines of
+ // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11;
+ // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the
+ // benefit of making adjacent strokes/fills line up without any
+ // gaps between them
+ x0 = splashRound(adj0);
+ x1 = splashRound(adj1);
+ if (x1 == x0) {
+ x1 = x1 + 1;
+ }
+ adjusts[i].x0 = (SplashCoord)x0;
+ adjusts[i].x1 = (SplashCoord)x1 - 0.01;
adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
adjusts[i].firstPt = hint->firstPt;
adjusts[i].lastPt = hint->lastPt;
commit e1ae7b900b01db7c7703da68ad94aa9bda1938f6
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Jan 10 23:29:38 2012 +0100
[xpdf303] Merge splash font stuff from Thomas
diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc
index 5757acc..a6c6ace 100644
--- a/poppler/GlobalParams.cc
+++ b/poppler/GlobalParams.cc
@@ -685,6 +685,7 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
textKeepTinyChars = gFalse;
fontDirs = new GooList();
enableFreeType = gTrue;
+ disableFreeTypeHinting = gFalse;
antialias = gTrue;
vectorAntialias = gTrue;
strokeAdjust = gTrue;
@@ -1509,6 +1510,14 @@ GBool GlobalParams::getEnableFreeType() {
return f;
}
+GBool GlobalParams::getDisableFreeTypeHinting() {
+ GBool f;
+
+ lockGlobalParams;
+ f = disableFreeTypeHinting;
+ unlockGlobalParams;
+ return f;
+}
GBool GlobalParams::getAntialias() {
GBool f;
@@ -1855,6 +1864,14 @@ GBool GlobalParams::setEnableFreeType(char *s) {
return ok;
}
+GBool GlobalParams::setDisableFreeTypeHinting(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &disableFreeTypeHinting);
+ unlockGlobalParams;
+ return ok;
+}
GBool GlobalParams::setAntialias(char *s) {
GBool ok;
diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h
index f4cb6c1..57b18f1 100644
--- a/poppler/GlobalParams.h
+++ b/poppler/GlobalParams.h
@@ -204,6 +204,7 @@ public:
GBool getTextKeepTinyChars();
GooString *findFontFile(GooString *fontName, const char **exts);
GBool getEnableFreeType();
+ GBool getDisableFreeTypeHinting();
GBool getAntialias();
GBool getVectorAntialias();
GBool getStrokeAdjust();
@@ -251,6 +252,7 @@ public:
void setTextPageBreaks(GBool pageBreaks);
void setTextKeepTinyChars(GBool keep);
GBool setEnableFreeType(char *s);
+ GBool setDisableFreeTypeHinting(char *s);
GBool setAntialias(char *s);
GBool setVectorAntialias(char *s);
void setStrokeAdjust(GBool strokeAdjust);
@@ -338,6 +340,7 @@ private:
GBool textKeepTinyChars; // keep all characters in text output
GooList *fontDirs; // list of font dirs [GooString]
GBool enableFreeType; // FreeType enable flag
+ GBool disableFreeTypeHinting; // FreeType disable hinting flag
GBool antialias; // anti-aliasing enable flag
GBool vectorAntialias; // vector anti-aliasing enable flag
GBool strokeAdjust; // stroke adjustment enable flag
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 52e2bef..020808e 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -1330,6 +1330,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
vectorAntialias = allowAntialias &&
globalParams->getVectorAntialias() &&
colorMode != splashModeMono1;
+ enableAutoHinting = !globalParams->getDisableFreeTypeHinting();
enableFreeTypeHinting = gFalse;
enableSlightHinting = gFalse;
setupScreenParams(72.0, 72.0);
@@ -1441,6 +1442,7 @@ void SplashOutputDev::startDoc(PDFDoc *docA) {
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
globalParams->getEnableFreeType(),
+ enableAutoHinting,
enableFreeTypeHinting,
enableSlightHinting,
#endif
@@ -3889,6 +3891,7 @@ void SplashOutputDev::setVectorAntialias(GBool vaa) {
void SplashOutputDev::setFreeTypeHinting(GBool enable, GBool enableSlightHintingA)
{
+ enableAutoHinting = gFalse;
enableFreeTypeHinting = enable;
enableSlightHinting = enableSlightHintingA;
}
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 8cfdbb1..c06359a 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -416,6 +416,7 @@ private:
GBool bitmapTopDown;
GBool allowAntialias;
GBool vectorAntialias;
+ GBool enableAutoHinting;
GBool enableFreeTypeHinting;
GBool enableSlightHinting;
GBool reverseVideo; // reverse video mode
diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc
index 9b5958c..b511c96 100644
--- a/splash/SplashFTFont.cc
+++ b/splash/SplashFTFont.cc
@@ -58,6 +58,7 @@ static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
SplashCoord *textMatA):
SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa),
+ enableAutoHinting(fontFileA->engine->enableAutoHinting),
enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting),
enableSlightHinting(fontFileA->engine->enableSlightHinting)
{
@@ -232,13 +233,28 @@ GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
}
-static FT_Int32 getFTLoadFlags(GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting)
+static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa,
+ GBool enableAutoHinting, GBool enableFreeTypeHinting, GBool enableSlightHinting)
{
int ret = FT_LOAD_DEFAULT;
if (aa)
ret |= FT_LOAD_NO_BITMAP;
- if (enableFreeTypeHinting) {
+ if (enableAutoHinting) {
+ if (trueType) {
+ // FT2's autohinting doesn't always work very well (especially with
+ // font subsets), so turn it off if anti-aliasing is enabled; if
+ // anti-aliasing is disabled, this seems to be a tossup - some fonts
+ // look better with hinting, some without, so leave hinting on
+ if (aa) {
+ ret |= FT_LOAD_NO_AUTOHINT;
+ }
+ } else if (type1) {
+ // Type 1 fonts seem to look better with 'light' hinting mode
+ ret |= FT_LOAD_TARGET_LIGHT;
+ }
+
+ } else if (enableFreeTypeHinting) {
if (enableSlightHinting)
ret |= FT_LOAD_TARGET_LIGHT;
} else {
@@ -271,7 +287,7 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
gid = (FT_UInt)c;
}
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(aa, enableFreeTypeHinting, enableSlightHinting))) {
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting))) {
return gFalse;
}
@@ -298,6 +314,12 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
return gFalse;
}
+ if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
+ // this can happen if (a) the glyph is really tiny or (b) the
+ // metrics in the TrueType file are broken
+ return gFalse;
+ }
+
bitmap->x = -slot->bitmap_left;
bitmap->y = slot->bitmap_top;
bitmap->w = slot->bitmap.width;
@@ -354,7 +376,7 @@ double SplashFTFont::getGlyphAdvance(int c)
return -1;
}
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(aa, enableFreeTypeHinting, enableSlightHinting))) {
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting))) {
return -1;
}
@@ -398,11 +420,11 @@ SplashPath *SplashFTFont::getGlyphPath(int c) {
} else {
gid = (FT_UInt)c;
}
- if (ff->trueType && gid == 0) {
+ if (ff->trueType && gid < 0) {
// skip the TrueType notdef glyph
return NULL;
}
- if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(aa, enableFreeTypeHinting, enableSlightHinting))) {
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting))) {
return NULL;
}
if (FT_Get_Glyph(slot, &glyph)) {
diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h
index f49d7b1..1745807 100644
--- a/splash/SplashFTFont.h
+++ b/splash/SplashFTFont.h
@@ -71,6 +71,7 @@ private:
FT_Matrix textMatrix;
SplashCoord textScale;
int size;
+ GBool enableAutoHinting;
GBool enableFreeTypeHinting;
GBool enableSlightHinting;
};
diff --git a/splash/SplashFTFontEngine.cc b/splash/SplashFTFontEngine.cc
index 7a4568d..dee5728 100644
--- a/splash/SplashFTFontEngine.cc
+++ b/splash/SplashFTFontEngine.cc
@@ -59,11 +59,12 @@ static void fileWrite(void *stream, const char *data, int len) {
// SplashFTFontEngine
//------------------------------------------------------------------------
-SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA,
+SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA,
GBool enableSlightHintingA, FT_Library libA) {
FT_Int major, minor, patch;
aa = aaA;
+ enableAutoHinting = enableAutoHintingA;
enableFreeTypeHinting = enableFreeTypeHintingA;
enableSlightHinting = enableSlightHintingA;
lib = libA;
@@ -74,14 +75,14 @@ SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA,
(major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
}
-SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, GBool enableFreeTypeHintingA,
+SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA,
GBool enableSlightHintingA) {
FT_Library libA;
if (FT_Init_FreeType(&libA)) {
return NULL;
}
- return new SplashFTFontEngine(aaA, enableFreeTypeHintingA, enableSlightHintingA, libA);
+ return new SplashFTFontEngine(aaA, enableAutoHintingA, enableFreeTypeHintingA, enableSlightHintingA, libA);
}
SplashFTFontEngine::~SplashFTFontEngine() {
diff --git a/splash/SplashFTFontEngine.h b/splash/SplashFTFontEngine.h
index aa1ad5f..d236e4f 100644
--- a/splash/SplashFTFontEngine.h
+++ b/splash/SplashFTFontEngine.h
@@ -45,7 +45,7 @@ class SplashFontSrc;
class SplashFTFontEngine {
public:
- static SplashFTFontEngine *init(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHinting);
+ static SplashFTFontEngine *init(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA, GBool enableSlightHinting);
~SplashFTFontEngine();
@@ -61,9 +61,10 @@ public:
private:
- SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHintingA, FT_Library libA);
+ SplashFTFontEngine(GBool aaA, GBool enableAutoHintingA, GBool enableFreeTypeHintingA, GBool enableSlightHintingA, FT_Library libA);
GBool aa;
+ GBool enableAutoHinting;
GBool enableFreeTypeHinting;
GBool enableSlightHinting;
FT_Library lib;
diff --git a/splash/SplashFontEngine.cc b/splash/SplashFontEngine.cc
index 2e74f5a..ab9beb9 100644
--- a/splash/SplashFontEngine.cc
+++ b/splash/SplashFontEngine.cc
@@ -69,6 +69,7 @@ SplashFontEngine::SplashFontEngine(
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
GBool enableFreeType,
+ GBool enableAutoHinting,
GBool enableFreeTypeHinting,
GBool enableSlightHinting,
#endif
@@ -88,7 +89,7 @@ SplashFontEngine::SplashFontEngine(
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
if (enableFreeType) {
- ftEngine = SplashFTFontEngine::init(aa, enableFreeTypeHinting, enableSlightHinting);
+ ftEngine = SplashFTFontEngine::init(aa, enableAutoHinting, enableFreeTypeHinting, enableSlightHinting);
} else {
ftEngine = NULL;
}
diff --git a/splash/SplashFontEngine.h b/splash/SplashFontEngine.h
index 54926b4..f0340a5 100644
--- a/splash/SplashFontEngine.h
+++ b/splash/SplashFontEngine.h
@@ -58,6 +58,7 @@ public:
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
GBool enableFreeType,
+ GBool enabbleAutoHinting,
GBool enableFreeTypeHinting,
GBool enableSlightHinting,
#endif
commit d46b673c46a72132fb3918b64733be552e35952f
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Jan 10 23:28:43 2012 +0100
[xpdf303] More merges from Thomas
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 5091edb..0ef97ed 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -71,6 +71,47 @@ static inline Guchar clip255(int x) {
template<typename T>
inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
+// The PDF spec says that all pixels whose *centers* lie within the
+// image target region get painted, so we want to round n+0.5 down to
+// n. But this causes problems, e.g., with PDF files that fill a
+// rectangle with black and then draw an image to the exact same
+// rectangle, so we instead use the fill scan conversion rule.
+// However, the correct rule works better for glyphs, so we also
+// provide that option in fillImageMask.
+#if 0
+static inline int imgCoordMungeLower(SplashCoord x) {
+ return splashCeil(x + 0.5) - 1;
+}
+static inline int imgCoordMungeUpper(SplashCoord x) {
+ return splashCeil(x + 0.5) - 1;
+}
+#else
+static inline int imgCoordMungeLower(SplashCoord x) {
+ return splashFloor(x);
+}
+static inline int imgCoordMungeUpper(SplashCoord x) {
+ return splashFloor(x) + 1;
+}
+static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) {
+ return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x);
+}
+static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) {
+ return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1);
+}
+#endif
+
+// Used by drawImage and fillImageMask to divide the target
+// quadrilateral into sections.
+struct ImageSection {
+ int y0, y1; // actual y range
+ int ia0, ia1; // vertex indices for edge A
+ int ib0, ib1; // vertex indices for edge A
+ SplashCoord xa0, ya0, xa1, ya1; // edge A
+ SplashCoord dxdya; // slope of edge A
+ SplashCoord xb0, yb0, xb1, yb1; // edge B
+ SplashCoord dxdyb; // slope of edge B
+};
+
//------------------------------------------------------------------------
// SplashPipe
//------------------------------------------------------------------------
@@ -2416,7 +2457,8 @@ void Splash::fillGlyph(SplashCoord x, SplashCoord y,
void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
SplashPipe pipe;
- int alpha0, alpha;
+ int alpha0;
+ Guchar alpha;
Guchar *p;
int x1, y1, xx, xx1, yy;
@@ -2547,22 +2589,11 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
int w, int h, SplashCoord *mat,
GBool glyphMode) {
- SplashPipe pipe;
- GBool rot;
- SplashCoord xScale, yScale, xShear, yShear, yShear1;
- int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
- int ulx, uly, llx, lly, urx, ury, lrx, lry;
- int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
- int xMin, xMax, yMin, yMax;
- SplashClipResult clipRes, clipRes2;
- int yp, yq, yt, yStep, lastYStep;
- int xp, xq, xt, xStep, xSrc;
- int k1, spanXMin, spanXMax, spanY;
- SplashColorPtr pixBuf, p;
- int pixAcc;
- int x, y, x1, x2, y2;
- SplashCoord y1;
- int n, m, i, j;
+ SplashBitmap *scaledMask;
+ SplashClipResult clipRes;
+ GBool minorAxisZero;
+ int x0, y0, x1, y1, scaledWidth, scaledHeight;
+ int yp;
if (debugMode) {
printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
@@ -2573,289 +2604,738 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
if (w == 0 && h == 0) return splashErrZeroImage;
// check for singular matrix
- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
return splashErrSingularMatrix;
}
- // compute scale, shear, rotation, translation parameters
- rot = splashAbs(mat[1]) > splashAbs(mat[0]);
- if (rot) {
- xScale = -mat[1];
- yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
- xShear = -mat[3] / yScale;
- yShear = -mat[0] / mat[1];
- } else {
- xScale = mat[0];
- yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
- xShear = mat[2] / yScale;
- yShear = mat[1] / mat[0];
- }
- // Note 1: The PDF spec says that all pixels whose *centers* lie
- // within the region get painted -- but that doesn't seem to match
- // up with what Acrobat actually does: it ends up leaving gaps
- // between image stripes. So we use the same rule here as for
- // fills: any pixel that overlaps the region gets painted.
- // Note 2: The "glyphMode" flag is a kludge: it switches back to
- // "correct" behavior (matching the spec), for use in rendering Type
- // 3 fonts.
- // Note 3: The +/-0.01 in these computations is to avoid floating
- // point precision problems which can lead to gaps between image
- // stripes (it can cause image stripes to overlap, but that's a much
- // less visible problem).
- if (glyphMode) {
- if (xScale >= 0) {
- tx = splashRound(mat[4]);
- tx2 = splashRound(mat[4] + xScale) - 1;
- } else {
- tx = splashRound(mat[4]) - 1;
- tx2 = splashRound(mat[4] + xScale);
+ minorAxisZero = mat[1] == 0 && mat[2] == 0;
+
+ // scaling only
+ if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ x0 = imgCoordMungeLowerC(mat[4], glyphMode);
+ y0 = imgCoordMungeLowerC(mat[5], glyphMode);
+ x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
+ y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode);
+ // make sure narrow images cover at least one pixel
+ if (x0 == x1) {
+ ++x1;
}
- } else {
- if (xScale >= 0) {
- tx = splashFloor(mat[4] - 0.01);
- tx2 = splashFloor(mat[4] + xScale + 0.01);
- } else {
- tx = splashFloor(mat[4] + 0.01);
- tx2 = splashFloor(mat[4] + xScale - 0.01);
+ if (y0 == y1) {
+ ++y1;
}
- }
- scaledWidth = abs(tx2 - tx) + 1;
- if (glyphMode) {
- if (yScale >= 0) {
- ty = splashRound(mat[5]);
- ty2 = splashRound(mat[5] + yScale) - 1;
- } else {
- ty = splashRound(mat[5]) - 1;
- ty2 = splashRound(mat[5] + yScale);
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+ blitMask(scaledMask, x0, y0, clipRes);
+ delete scaledMask;
}
- } else {
- if (yScale >= 0) {
- ty = splashFloor(mat[5] - 0.01);
- ty2 = splashFloor(mat[5] + yScale + 0.01);
- } else {
- ty = splashFloor(mat[5] + 0.01);
- ty2 = splashFloor(mat[5] + yScale - 0.01);
+
+ // scaling plus vertical flip
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+ x0 = imgCoordMungeLowerC(mat[4], glyphMode);
+ y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+ x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
+ y1 = imgCoordMungeUpperC(mat[5], glyphMode);
+ // make sure narrow images cover at least one pixel
+ if (x0 == x1) {
+ ++x1;
+ }
+ if (y0 == y1) {
+ ++y1;
}
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+ vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
+ blitMask(scaledMask, x0, y0, clipRes);
+ delete scaledMask;
+ }
+
+ // all other cases
+ } else {
+ arbitraryTransformMask(src, srcData, w, h, mat, glyphMode);
}
- scaledHeight = abs(ty2 - ty) + 1;
- xSign = (xScale < 0) ? -1 : 1;
- ySign = (yScale < 0) ? -1 : 1;
- yShear1 = (SplashCoord)xSign * yShear;
+
+ return splashOk;
+}
+
+void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool glyphMode) {
+ SplashBitmap *scaledMask;
+ SplashClipResult clipRes, clipRes2;
+ 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 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
- ulx1 = 0;
- uly1 = 0;
- urx1 = xSign * (scaledWidth - 1);
- ury1 = (int)(yShear * urx1);
- llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
- lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
- lrx1 = xSign * (scaledWidth - 1) +
- splashRound(xShear * ySign * (scaledHeight - 1));
- lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
- if (rot) {
- ulx = tx + uly1; uly = ty - ulx1;
- urx = tx + ury1; ury = ty - urx1;
- llx = tx + lly1; lly = ty - llx1;
- lrx = tx + lry1; lry = ty - lrx1;
- } else {
- ulx = tx + ulx1; uly = ty + uly1;
- urx = tx + urx1; ury = ty + ury1;
- llx = tx + llx1; lly = ty + lly1;
- lrx = tx + lrx1; lry = ty + lry1;
- }
- xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
- : (llx < lrx) ? llx : lrx
- : (urx < llx) ? (urx < lrx) ? urx : lrx
- : (llx < lrx) ? llx : lrx;
- xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
- : (llx > lrx) ? llx : lrx
- : (urx > llx) ? (urx > lrx) ? urx : lrx
- : (llx > lrx) ? llx : lrx;
- yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
- : (lly < lry) ? lly : lry
- : (ury < lly) ? (ury < lry) ? ury : lry
- : (lly < lry) ? lly : lry;
- yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
- : (lly > lry) ? lly : lry
- : (ury > lly) ? (ury > lry) ? ury : lry
- : (lly > lry) ? lly : lry;
- clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+ xMin = imgCoordMungeLowerC(vx[0], glyphMode);
+ xMax = imgCoordMungeUpperC(vx[0], glyphMode);
+ yMin = imgCoordMungeLowerC(vy[0], glyphMode);
+ yMax = imgCoordMungeUpperC(vy[0], glyphMode);
+ for (i = 1; i < 4; ++i) {
+ t0 = imgCoordMungeLowerC(vx[i], glyphMode);
+ if (t0 < xMin) {
+ xMin = t0;
+ }
+ t0 = imgCoordMungeUpperC(vx[i], glyphMode);
+ if (t0 > xMax) {
+ xMax = t0;
+ }
+ t1 = imgCoordMungeLowerC(vy[i], glyphMode);
+ if (t1 < yMin) {
+ yMin = t1;
+ }
+ t1 = imgCoordMungeUpperC(vy[i], glyphMode);
+ if (t1 > yMax) {
+ yMax = t1;
+ }
+ }
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
opClipRes = clipRes;
+ if (clipRes == splashClipAllOutside) {
+ return;
+ }
- // compute Bresenham parameters for x and y scaling
- yp = h / scaledHeight;
- yq = h % scaledHeight;
- xp = w / scaledWidth;
- xq = w % scaledWidth;
+ // compute the scale factors
+ if (mat[0] >= 0) {
+ t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[4], glyphMode);
+ } else {
+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[0] + mat[4], glyphMode);
+ }
+ if (mat[1] >= 0) {
+ t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[5], glyphMode);
+ } else {
+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[1] + mat[5], glyphMode);
+ }
+ scaledWidth = t0 > t1 ? t0 : t1;
+ if (mat[2] >= 0) {
+ t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[4], glyphMode);
+ } else {
+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
+ imgCoordMungeLowerC(mat[2] + mat[4], glyphMode);
+ }
+ if (mat[3] >= 0) {
+ t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[5], glyphMode);
+ } else {
+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
+ imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+ }
+ scaledHeight = t0 > t1 ? t0 : t1;
+ if (scaledWidth == 0) {
+ scaledWidth = 1;
+ }
+ if (scaledHeight == 0) {
+ scaledHeight = 1;
+ }
- // allocate pixel buffer
- if (yp < 0 || yp > INT_MAX - 1) {
- return splashErrBadArg;
+ // 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
+ return;
+ }
+ ir00 = r11 / det;
+ ir01 = -r01 / det;
+ ir10 = -r10 / det;
+ ir11 = r00 / det;
+
+ // scale the input image
+ scaledMask = scaleMask(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight);
+
+ // construct the three sections
+ i = (vy[2] <= vy[3]) ? 2 : 3;
+ if (vy[1] <= vy[i]) {
+ i = 1;
+ }
+ if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) {
+ i = 0;
+ }
+ if (vy[i] == vy[(i+1) & 3]) {
+ section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
+ section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 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 = imgCoordMungeLowerC(vy[i], glyphMode);
+ section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 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 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode);
+ section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode);
+ 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 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode);
+ section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode);
+ 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);
}
- pixBuf = (SplashColorPtr)gmallocn((yp + 1), w);
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, gFalse);
+ pipeInit(&pipe, 0, 0, state->fillPattern, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
if (vectorAntialias) {
drawAAPixelInit();
}
+ // 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
+ for (i = 0; i < nSections; ++i) {
+ for (y = section[i].y0; y <= section[i].y1; ++y) {
+ xa = imgCoordMungeLowerC(section[i].xa0 +
+ ((SplashCoord)y + 0.5 - section[i].ya0) *
+ section[i].dxdya,
+ glyphMode);
+ xb = imgCoordMungeUpperC(section[i].xb0 +
+ ((SplashCoord)y + 0.5 - section[i].yb0) *
+ section[i].dxdyb,
+ glyphMode);
+ // make sure narrow images cover at least one pixel
+ if (xa == xb) {
+ ++xb;
+ }
+ if (clipRes != splashClipAllInside) {
+ clipRes2 = state->clip->testSpan(xa, xb - 1, y);
+ } else {
+ clipRes2 = clipRes;
+ }
+ 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;
+ }
+ pipe.shape = scaledMask->data[yy * scaledWidth + xx];
+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
+ drawAAPixel(&pipe, x, y);
+ } else {
+ drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
+ }
+ }
+ }
+ }
+
+ delete scaledMask;
+}
+
+// Scale an image mask into a SplashBitmap.
+SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight) {
+ SplashBitmap *dest;
+
+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8,
+ gFalse);
+ if (scaledHeight < srcHeight) {
+ if (scaledWidth < srcWidth) {
+ scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ } else {
+ scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ }
+ } else {
+ if (scaledWidth < srcWidth) {
+ scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ } else {
+ scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
+ scaledWidth, scaledHeight, dest);
+ }
+ }
+ return dest;
+}
+
+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;
- lastYStep = 1;
+ destPtr = dest->data;
for (y = 0; y < scaledHeight; ++y) {
// y scale Bresenham
- yStep = yp;
- yt += yq;
- if (yt >= scaledHeight) {
+ if ((yt += yq) >= scaledHeight) {
yt -= scaledHeight;
- ++yStep;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
}
- // read row(s) from image
- n = (yp > 0) ? yStep : lastYStep;
- if (n > 0) {
- p = pixBuf;
- for (i = 0; i < n; ++i) {
- (*src)(srcData, p);
- p += w;
+ // 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];
}
}
- lastYStep = yStep;
- // loop-invariant constants
- k1 = splashRound(xShear * ySign * y);
+ // 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) {
- // clipping test
- if (clipRes != splashClipAllInside &&
- !rot &&
- (int)(yShear * k1) ==
- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
- if (xSign > 0) {
- spanXMin = tx + k1;
- spanXMax = spanXMin + (scaledWidth - 1);
+ // x scale Bresenham
+ if ((xt += xq) >= scaledWidth) {
+ xt -= scaledWidth;
+ xStep = xp + 1;
+ d = d1;
} else {
- spanXMax = tx + k1;
- spanXMin = spanXMax - (scaledWidth - 1);
+ xStep = xp;
+ d = d0;
}
- spanY = ty + ySign * y + (int)(yShear * k1);
- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
- if (clipRes2 == splashClipAllOutside) {
- continue;
+
+ // compute the final pixel
+ pix = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix += pixBuf[xx++];
}
+ // (255 * pix) / xStep * yStep
+ pix = (pix * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix;
+ }
+ }
+
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
+
+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));
+
+ // 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 {
- clipRes2 = clipRes;
+ 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;
- xSrc = 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;
+ }
- // x shear
- x1 = k1;
+ // compute the final pixel
+ pix = pixBuf[x];
+ // (255 * pix) / yStep
+ pix = (pix * d) >> 23;
- // y shear
- y1 = (SplashCoord)ySign * y + yShear * x1;
- // this is a kludge: if yShear1 is negative, then (int)y1 would
- // change immediately after the first pixel, which is not what we
- // want
- if (yShear1 < 0) {
- y1 += 0.999;
+ // store the pixel
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix;
+ }
}
+ }
- // loop-invariant constants
- n = yStep > 0 ? yStep : 1;
+ 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
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
+ if ((xt += xq) >= scaledWidth) {
xt -= scaledWidth;
- ++xStep;
+ xStep = xp + 1;
+ d = d1;
+ } else {
+ xStep = xp;
+ d = d0;
}
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the alpha value for (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = pixBuf + xSrc;
- pixAcc = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc += *p++;
- }
- p += w - m;
+ // compute the final pixel
+ pix = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix += lineBuf[xx++];
}
+ // (255 * pix) / xStep
+ pix = (pix * d) >> 23;
- // blend fill color with background
- if (pixAcc != 0) {
- pipe.shape = ((pixAcc == n * m)
- ? (SplashCoord)1
- : (SplashCoord)pixAcc / (SplashCoord)(n * m)) * 255;
- if (vectorAntialias && clipRes2 != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
- }
+ // store the pixel
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + i * scaledWidth + x;
+ *destPtr = (Guchar)pix;
}
+ }
+
+ destPtr0 += yStep * scaledWidth;
+ }
+
+ gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXu(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;
+ int i, j;
+
+ // 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;
+
+ 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;
+
+ xx = 0;
+ for (x = 0; x < srcWidth; ++x) {
// x scale Bresenham
- xSrc += xStep;
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
+ } else {
+ xStep = xp;
+ }
+
+ // compute the final pixel
+ pix = lineBuf[x] ? 255 : 0;
- // x shear
- x1 += xSign;
+ // store the pixel
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + i * scaledWidth + xx + j;
+ *destPtr++ = (Guchar)pix;
+ }
+ }
- // y shear
- y1 += yShear1;
+ xx += xStep;
}
+
+ destPtr0 += yStep * scaledWidth;
}
- // free memory
- gfree(pixBuf);
+ gfree(lineBuf);
+}
- return splashOk;
+void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
+ SplashClipResult clipRes) {
+ SplashPipe pipe;
+ Guchar *p;
+ int w, h, x, y;
+
+ w = src->getWidth();
+ h = src->getHeight();
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+ drawAAPixelInit();
+ p = src->getDataPtr();
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ pipe.shape = *p++;
+ drawAAPixel(&pipe, xDest + x, yDest + y);
+ }
+ }
+ } else {
+ pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+ p = src->getDataPtr();
+ if (clipRes == splashClipAllInside) {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (*p) {
+ pipe.shape = *p;
+ (this->*pipe.run)(&pipe);
+ } else {
+ pipeIncX(&pipe);
+ }
+ ++p;
+ }
+ }
+ updateModX(xDest);
+ updateModX(xDest + w - 1);
+ updateModY(yDest);
+ updateModY(yDest + h - 1);
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (*p && state->clip->test(xDest + x, yDest + y)) {
+ pipe.shape = *p;
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ ++p;
+ }
+ }
+ }
+ }
}
SplashError Splash::drawImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
int w, int h, SplashCoord *mat, SplashPattern *opImagePattern) {
- SplashPipe pipe;
- GBool ok, rot;
- SplashCoord xScale, yScale, xShear, yShear, yShear1;
- int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
- int ulx, uly, llx, lly, urx, ury, lrx, lry;
- int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
- int xMin, xMax, yMin, yMax;
- SplashClipResult clipRes, clipRes2;
- int yp, yq, yt, yStep, lastYStep;
- int xp, xq, xt, xStep, xSrc;
- int k1, spanXMin, spanXMax, spanY;
- SplashColorPtr colorBuf, p;
- SplashColor pix;
- Guchar *alphaBuf, *q;
-#if SPLASH_CMYK
- int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
-#else
- int pixAcc0, pixAcc1, pixAcc2;
-#endif
- int alphaAcc;
- SplashCoord pixMul, alphaMul, alpha;
- int x, y, x1, x2, y2;
- SplashCoord y1;
- int nComps, n, m, i, j;
+ GBool ok;
+ SplashBitmap *scaledImg;
+ SplashClipResult clipRes;
+ GBool minorAxisZero;
+ int x0, y0, x1, y1, scaledWidth, scaledHeight;
+ int nComps;
+ int yp;
if (debugMode) {
printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
@@ -2890,799 +3370,1242 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
nComps = 4;
break;
#endif
+ default:
+ ok = gFalse;
+ break;
}
if (!ok) {
return splashErrModeMismatch;
}
// check for singular matrix
- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
return splashErrSingularMatrix;
}
- // compute scale, shear, rotation, translation parameters
- rot = splashAbs(mat[1]) > splashAbs(mat[0]);
- if (rot) {
- xScale = -mat[1];
- yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
- xShear = -mat[3] / yScale;
- yShear = -mat[0] / mat[1];
- } else {
- xScale = mat[0];
- yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
- xShear = mat[2] / yScale;
- yShear = mat[1] / mat[0];
- }
- // Note 1: The PDF spec says that all pixels whose *centers* lie
- // within the region get painted -- but that doesn't seem to match
- // up with what Acrobat actually does: it ends up leaving gaps
- // between image stripes. So we use the same rule here as for
- // fills: any pixel that overlaps the region gets painted.
- // Note 2: The +/-0.01 in these computations is to avoid floating
- // point precision problems which can lead to gaps between image
- // stripes (it can cause image stripes to overlap, but that's a much
- // less visible problem).
- if (xScale >= 0) {
- tx = splashFloor(mat[4] - 0.01);
- tx2 = splashFloor(mat[4] + xScale + 0.01);
- } else {
- tx = splashFloor(mat[4] + 0.01);
- tx2 = splashFloor(mat[4] + xScale - 0.01);
- }
- scaledWidth = abs(tx2 - tx) + 1;
- if (yScale >= 0) {
- ty = splashFloor(mat[5] - 0.01);
- ty2 = splashFloor(mat[5] + yScale + 0.01);
+ minorAxisZero = mat[1] == 0 && mat[2] == 0;
+
+ // scaling only
+ if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+ x0 = imgCoordMungeLower(mat[4]);
+ y0 = imgCoordMungeLower(mat[5]);
+ x1 = imgCoordMungeUpper(mat[0] + mat[4]);
+ y1 = imgCoordMungeUpper(mat[3] + mat[5]);
+ // make sure narrow images cover at least one pixel
+ if (x0 == x1) {
+ ++x1;
+ }
+ if (y0 == y1) {
+ ++y1;
+ }
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+ scaledWidth, scaledHeight);
+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+ delete scaledImg;
+ }
+
+ // scaling plus vertical flip
+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+ x0 = imgCoordMungeLower(mat[4]);
+ y0 = imgCoordMungeLower(mat[3] + mat[5]);
+ x1 = imgCoordMungeUpper(mat[0] + mat[4]);
+ y1 = imgCoordMungeUpper(mat[5]);
+ if (x0 == x1) {
+ if (mat[4] + mat[0] * 0.5 < x0) {
+ --x0;
+ } else {
+ ++x1;
+ }
+ }
+ if (y0 == y1) {
+ if (mat[5] + mat[1] * 0.5 < y0) {
+ --y0;
+ } else {
+ ++y1;
+ }
+ }
+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+ opClipRes = clipRes;
+ if (clipRes != splashClipAllOutside) {
+ scaledWidth = x1 - x0;
+ scaledHeight = y1 - y0;
+ yp = h / scaledHeight;
+ if (yp < 0 || yp > INT_MAX - 1) {
+ return splashErrBadArg;
+ }
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+ scaledWidth, scaledHeight);
+ vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+ delete scaledImg;
+ }
+
+ // all other cases
} else {
- ty = splashFloor(mat[5] + 0.01);
- ty2 = splashFloor(mat[5] + yScale - 0.01);
+ return arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha,
+ w, h, mat);
}
- scaledHeight = abs(ty2 - ty) + 1;
- xSign = (xScale < 0) ? -1 : 1;
- ySign = (yScale < 0) ? -1 : 1;
- yShear1 = (SplashCoord)xSign * yShear;
+
+ return splashOk;
+}
+
+SplashError Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat) {
+ SplashBitmap *scaledImg;
+ SplashClipResult clipRes, clipRes2;
+ SplashPipe pipe;
+ SplashColor pixel;
+ 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, yp;
+
+ // 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
- ulx1 = 0;
- uly1 = 0;
- urx1 = xSign * (scaledWidth - 1);
- ury1 = (int)(yShear * urx1);
- llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
- lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
- lrx1 = xSign * (scaledWidth - 1) +
- splashRound(xShear * ySign * (scaledHeight - 1));
- lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
- if (rot) {
- ulx = tx + uly1; uly = ty - ulx1;
- urx = tx + ury1; ury = ty - urx1;
- llx = tx + lly1; lly = ty - llx1;
- lrx = tx + lry1; lry = ty - lrx1;
- } else {
- ulx = tx + ulx1; uly = ty + uly1;
- urx = tx + urx1; ury = ty + ury1;
- llx = tx + llx1; lly = ty + lly1;
- lrx = tx + lrx1; lry = ty + lry1;
- }
- xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
- : (llx < lrx) ? llx : lrx
- : (urx < llx) ? (urx < lrx) ? urx : lrx
- : (llx < lrx) ? llx : lrx;
- xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
- : (llx > lrx) ? llx : lrx
- : (urx > llx) ? (urx > lrx) ? urx : lrx
- : (llx > lrx) ? llx : lrx;
- yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
- : (lly < lry) ? lly : lry
- : (ury < lly) ? (ury < lry) ? ury : lry
- : (lly < lry) ? lly : lry;
- yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
- : (lly > lry) ? lly : lry
- : (ury > lly) ? (ury > lry) ? ury : lry
- : (lly > lry) ? lly : lry;
- clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+ xMin = imgCoordMungeLower(vx[0]);
+ xMax = imgCoordMungeUpper(vx[0]);
+ yMin = imgCoordMungeLower(vy[0]);
+ yMax = imgCoordMungeUpper(vy[0]);
+ for (i = 1; i < 4; ++i) {
+ t0 = imgCoordMungeLower(vx[i]);
+ if (t0 < xMin) {
+ xMin = t0;
+ }
+ t0 = imgCoordMungeUpper(vx[i]);
+ if (t0 > xMax) {
+ xMax = t0;
+ }
+ t1 = imgCoordMungeLower(vy[i]);
+ if (t1 < yMin) {
+ yMin = t1;
+ }
+ t1 = imgCoordMungeUpper(vy[i]);
+ if (t1 > yMax) {
+ yMax = t1;
+ }
+ }
+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
opClipRes = clipRes;
if (clipRes == splashClipAllOutside) {
return splashOk;
}
- // compute Bresenham parameters for x and y scaling
- yp = h / scaledHeight;
- yq = h % scaledHeight;
- xp = w / scaledWidth;
- xq = w % scaledWidth;
+ // compute the scale factors
+ if (mat[0] >= 0) {
+ t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]);
+ } else {
+ t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]);
+ }
+ if (mat[1] >= 0) {
+ t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]);
+ } else {
+ t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]);
+ }
+ scaledWidth = t0 > t1 ? t0 : t1;
+ if (mat[2] >= 0) {
+ t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]);
+ } else {
+ t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]);
+ }
+ if (mat[3] >= 0) {
+ t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]);
+ } else {
+ t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]);
+ }
+ scaledHeight = t0 > t1 ? t0 : t1;
+ if (scaledWidth == 0) {
+ scaledWidth = 1;
+ }
+ if (scaledHeight == 0) {
+ scaledHeight = 1;
+ }
- // allocate pixel buffers
+ // 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 splashErrBadArg;
+ }
+ ir00 = r11 / det;
+ ir01 = -r01 / det;
+ ir10 = -r10 / det;
+ ir11 = r00 / det;
+
+ // scale the input image
+ yp = srcHeight / scaledHeight;
if (yp < 0 || yp > INT_MAX - 1) {
return splashErrBadArg;
}
- colorBuf = (SplashColorPtr)gmallocn3((yp + 1), w, nComps);
- if (srcAlpha) {
- alphaBuf = (Guchar *)gmallocn((yp + 1), w);
+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight);
+
+ // 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 = imgCoordMungeLower(vy[i]);
+ section[0].y1 = imgCoordMungeUpper(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 {
- alphaBuf = NULL;
+ section[0].y0 = imgCoordMungeLower(vy[i]);
+ section[2].y1 = imgCoordMungeUpper(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 = imgCoordMungeLower(vy[(i+1) & 3]);
+ section[2].y0 = imgCoordMungeUpper(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 = imgCoordMungeLower(vy[(i+3) & 3]);
+ section[2].y0 = imgCoordMungeUpper(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);
}
- pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
-#if SPLASH_CMYK
- pixAcc3 = 0; // make gcc happy
-#endif
-
// initialize the pixel pipe
- pipeInit(&pipe, 0, 0, NULL, pix, (Guchar)splashRound(state->fillAlpha * 255),
+ pipeInit(&pipe, 0, 0, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255),
srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
gFalse);
if (vectorAntialias) {
drawAAPixelInit();
}
- if (srcAlpha) {
-
- // init y scale Bresenham
- yt = 0;
- lastYStep = 1;
-
- for (y = 0; y < scaledHeight; ++y) {
+ // 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;
+ }
+ }
- // y scale Bresenham
- yStep = yp;
- yt += yq;
- if (yt >= scaledHeight) {
- yt -= scaledHeight;
- ++yStep;
- }
-
- // read row(s) from image
- n = (yp > 0) ? yStep : lastYStep;
- if (n > 0) {
- p = colorBuf;
- q = alphaBuf;
- for (i = 0; i < n; ++i) {
- (*src)(srcData, p, q);
- p += w * nComps;
- q += w;
- }
+ // scan all pixels inside the target region
+ for (i = 0; i < nSections; ++i) {
+ for (y = section[i].y0; y <= section[i].y1; ++y) {
+ xa = imgCoordMungeLower(section[i].xa0 +
+ ((SplashCoord)y + 0.5 - section[i].ya0) *
+ section[i].dxdya);
+ xb = imgCoordMungeUpper(section[i].xb0 +
+ ((SplashCoord)y + 0.5 - section[i].yb0) *
+ section[i].dxdyb);
+ // make sure narrow images cover at least one pixel
+ if (xa == xb) {
+ ++xb;
}
- lastYStep = yStep;
-
- // loop-invariant constants
- k1 = splashRound(xShear * ySign * y);
-
- // clipping test
- if (clipRes != splashClipAllInside &&
- !rot &&
- (int)(yShear * k1) ==
- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
- if (xSign > 0) {
- spanXMin = tx + k1;
- spanXMax = spanXMin + (scaledWidth - 1);
+ if (clipRes != splashClipAllInside) {
+ clipRes2 = state->clip->testSpan(xa, xb - 1, y);
+ } else {
+ clipRes2 = clipRes;
+ }
+ 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;
+ }
+ scaledImg->getPixel(xx, yy, pixel);
+ if (srcAlpha) {
+ pipe.shape = scaledImg->alpha[yy * scaledWidth + xx];
} else {
- spanXMax = tx + k1;
- spanXMin = spanXMax - (scaledWidth - 1);
+ pipe.shape = 255;
}
- spanY = ty + ySign * y + (int)(yShear * k1);
- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
- if (clipRes2 == splashClipAllOutside) {
- continue;
+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
+ drawAAPixel(&pipe, x, y);
+ } else {
+ drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
}
- } else {
- clipRes2 = clipRes;
}
+ }
+ }
- // init x scale Bresenham
- xt = 0;
- xSrc = 0;
+ delete scaledImg;
+ return splashOk;
+}
- // x shear
- x1 = k1;
+// Scale an image into a SplashBitmap.
+SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight) {
+ SplashBitmap *dest;
+
+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha);
+ if (scaledHeight < srcHeight) {
+ if (scaledWidth < srcWidth) {
+ scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ } else {
+ scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ }
+ } else {
+ if (scaledWidth < srcWidth) {
+ scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ } else {
+ scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+ }
+ }
+ return dest;
+}
- // y shear
- y1 = (SplashCoord)ySign * y + yShear * x1;
- // this is a kludge: if yShear1 is negative, then (int)y1 would
- // change immediately after the first pixel, which is not what
- // we want
- if (yShear1 < 0) {
- y1 += 0.999;
- }
+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, nComps * sizeof(int));
+ if (srcAlpha) {
+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+ alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+ } else {
+ alphaLineBuf = NULL;
+ alphaPixBuf = NULL;
+ }
- // loop-invariant constants
- n = yStep > 0 ? yStep : 1;
+ // init y scale Bresenham
+ yt = 0;
- switch (srcMode) {
+ destPtr = dest->data;
+ destAlphaPtr = dest->alpha;
+ for (y = 0; y < scaledHeight; ++y) {
- case splashModeMono1:
- case splashModeMono8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ // y scale Bresenham
+ if ((yt += yq) >= scaledHeight) {
+ yt -= scaledHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
+ // 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];
+ }
+ }
+ }
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc;
- q = alphaBuf + xSrc;
- pixAcc0 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- alphaAcc += *q++;
- }
- p += w - m;
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * pixMul;
+ // init x scale Bresenham
+ xt = 0;
+ d0 = (1 << 23) / (yStep * xp);
+ d1 = (1 << 23) / (yStep * (xp + 1));
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ xx = xxa = 0;
+ for (x = 0; x < scaledWidth; ++x) {
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
+ // x scale Bresenham
+ if ((xt += xq) >= scaledWidth) {
+ xt -= scaledWidth;
+ xStep = xp + 1;
+ d = d1;
+ } else {
+ xStep = xp;
+ d = d0;
+ }
- // x scale Bresenham
- xSrc += xStep;
+ switch (srcMode) {
- // x shear
- x1 += xSign;
+ case splashModeMono8:
- // y shear
- y1 += yShear1;
+ // compute the final pixel
+ pix0 = 0;
+ for (i = 0; i < xStep; ++i) {
+ pix0 += pixBuf[xx++];
}
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix0;
break;
case splashModeRGB8:
- case splashModeBGR8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
-
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc * 3;
- q = alphaBuf + xSrc;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- alphaAcc += *q++;
- }
- p += 3 * (w - m);
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * pixMul;
-
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
-
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
-
- // x scale Bresenham
- xSrc += xStep;
- // x shear
- x1 += xSign;
-
- // y shear
- y1 += yShear1;
+ // 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) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix0;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix2;
break;
case splashModeXBGR8:
- for (x = 0; x < scaledWidth; ++x) {
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
-
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc * 4;
- q = alphaBuf + xSrc;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- p++;
- alphaAcc += *q++;
- }
- p += 4 * (w - m);
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * pixMul;
-
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = 255;
-
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
- // x scale Bresenham
- xSrc += xStep;
+ // 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 += 4;
+ }
+ // pix / xStep * yStep
+ pix0 = (pix0 * d) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix2;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix0;
+ *destPtr++ = (Guchar)255;
+ break;
- // x shear
- x1 += xSign;
+ case splashModeBGR8:
- // y shear
- y1 += yShear1;
+ // 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) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix2;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix0;
break;
-
#if SPLASH_CMYK
case splashModeCMYK8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- alphaAcc = 0;
- p = colorBuf + xSrc * 4;
- q = alphaBuf + xSrc;
- pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- pixAcc3 += *p++;
- alphaAcc += *q++;
- }
- p += 4 * (w - m);
- q += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
- alphaMul = pixMul * (1.0 / 255.0);
- alpha = (SplashCoord)alphaAcc * pixMul;
-
- if (alpha > 0) {
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
-
- // set pixel
- pipe.shape = alpha;
- if (vectorAntialias && clipRes != splashClipAllInside) {
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
- }
+ // 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) >> 23;
+ pix1 = (pix1 * d) >> 23;
+ pix2 = (pix2 * d) >> 23;
+ pix3 = (pix3 * d) >> 23;
+
+ // store the pixel
+ *destPtr++ = (Guchar)pix0;
+ *destPtr++ = (Guchar)pix1;
+ *destPtr++ = (Guchar)pix2;
+ *destPtr++ = (Guchar)pix3;
+ break;
+#endif
- // x scale Bresenham
- xSrc += xStep;
- // x shear
- x1 += xSign;
+ case splashModeMono1: // mono1 is not allowed
+ default:
+ break;
+ }
- // y shear
- y1 += yShear1;
+ // process alpha
+ if (srcAlpha) {
+ alpha = 0;
+ for (i = 0; i < xStep; ++i, ++xxa) {
+ alpha += alphaPixBuf[xxa];
}
- break;
-#endif // SPLASH_CMYK
+ // alpha / xStep * yStep
+ alpha = (alpha * d) >> 23;
+ *destAlphaPtr++ = (Guchar)alpha;
}
}
+ }
+ 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,
+ 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, nComps * sizeof(int));
+ if (srcAlpha) {
+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+ alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
} else {
+ alphaLineBuf = NULL;
+ alphaPixBuf = NULL;
+ }
- // init y scale Bresenham
- yt = 0;
- lastYStep = 1;
+ // init y scale Bresenham
+ yt = 0;
- for (y = 0; y < scaledHeight; ++y) {
+ destPtr = dest->data;
+ destAlphaPtr = dest->alpha;
+ for (y = 0; y < scaledHeight; ++y) {
- // y scale Bresenham
+ // y scale Bresenham
+ if ((yt += yq) >= scaledHeight) {
+ yt -= scaledHeight;
+ yStep = yp + 1;
+ } else {
yStep = yp;
- yt += yq;
- if (yt >= scaledHeight) {
- yt -= scaledHeight;
- ++yStep;
- }
-
- // read row(s) from image
- n = (yp > 0) ? yStep : lastYStep;
- if (n > 0) {
- p = colorBuf;
- for (i = 0; i < n; ++i) {
- (*src)(srcData, p, NULL);
- p += w * nComps;
+ }
+
+ // 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];
}
}
- lastYStep = yStep;
+ }
- // loop-invariant constants
- k1 = splashRound(xShear * ySign * y);
+ // init x scale Bresenham
+ xt = 0;
+ d = (1 << 23) / yStep;
- // clipping test
- if (clipRes != splashClipAllInside &&
- !rot &&
- (int)(yShear * k1) ==
- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
- if (xSign > 0) {
- spanXMin = tx + k1;
- spanXMax = spanXMin + (scaledWidth - 1);
- } else {
- spanXMax = tx + k1;
- spanXMin = spanXMax - (scaledWidth - 1);
- }
- spanY = ty + ySign * y + (int)(yShear * k1);
- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
- if (clipRes2 == splashClipAllOutside) {
- continue;
- }
+ for (x = 0; x < srcWidth; ++x) {
+
+ // x scale Bresenham
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
} else {
- clipRes2 = clipRes;
+ xStep = xp;
}
- // init x scale Bresenham
- xt = 0;
- xSrc = 0;
+ // compute the final pixel
+ for (i = 0; i < nComps; ++i) {
+ // pixBuf[] / yStep
+ pix[i] = (pixBuf[x * nComps + i] * d) >> 23;
+ }
- // x shear
- x1 = k1;
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono1: // mono1 is not allowed
+ break;
+ 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;
+ case splashModeXBGR8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)255;
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < xStep; ++i) {
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ }
+ 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
+ }
- // y shear
- y1 = (SplashCoord)ySign * y + yShear * x1;
- // this is a kludge: if yShear1 is negative, then (int)y1 would
- // change immediately after the first pixel, which is not what
- // we want
- if (yShear1 < 0) {
- y1 += 0.999;
+ // process alpha
+ if (srcAlpha) {
+ // alphaPixBuf[] / yStep
+ alpha = (alphaPixBuf[x] * d) >> 23;
+ for (i = 0; i < xStep; ++i) {
+ *destAlphaPtr++ = (Guchar)alpha;
+ }
}
+ }
+ }
- // loop-invariant constants
- n = yStep > 0 ? yStep : 1;
+ gfree(alphaPixBuf);
+ gfree(alphaLineBuf);
+ gfree(pixBuf);
+ gfree(lineBuf);
+}
- switch (srcMode) {
+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;
+ }
- case splashModeMono1:
- case splashModeMono8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ // init y scale Bresenham
+ yt = 0;
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
+ destPtr0 = dest->data;
+ destAlphaPtr0 = dest->alpha;
+ for (y = 0; y < srcHeight; ++y) {
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc;
- pixAcc0 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- }
- p += w - m;
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ // y scale Bresenham
+ if ((yt += yq) >= srcHeight) {
+ yt -= srcHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ // read row from image
+ (*src)(srcData, lineBuf, alphaLineBuf);
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)255;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ // init x scale Bresenham
+ xt = 0;
+ d0 = (1 << 23) / xp;
+ d1 = (1 << 23) / (xp + 1);
- // x scale Bresenham
- xSrc += xStep;
+ xx = xxa = 0;
+ for (x = 0; x < scaledWidth; ++x) {
- // x shear
- x1 += xSign;
+ // x scale Bresenham
+ if ((xt += xq) >= scaledWidth) {
+ xt -= scaledWidth;
+ xStep = xp + 1;
+ d = d1;
+ } else {
+ xStep = xp;
+ d = d0;
+ }
- // y shear
- y1 += yShear1;
+ // 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];
}
- break;
+ }
+ for (i = 0; i < nComps; ++i) {
+ // pix[] / xStep
+ pix[i] = (pix[i] * d) >> 23;
+ }
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono1: // mono1 is not allowed
+ break;
+ 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;
+ case splashModeXBGR8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)255;
+ }
+ break;
case splashModeBGR8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
-
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
-
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc * 3;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- }
- p += 3 * (w - m);
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ }
+ 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];
+ }
+ break;
+#endif
+ }
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+ // process alpha
+ if (srcAlpha) {
+ alpha = 0;
+ for (i = 0; i < xStep; ++i, ++xxa) {
+ alpha += alphaLineBuf[xxa];
+ }
+ // alpha / xStep
+ alpha = (alpha * d) >> 23;
+ for (i = 0; i < yStep; ++i) {
+ destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x;
+ *destAlphaPtr = (Guchar)alpha;
+ }
+ }
+ }
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)255;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ destPtr0 += yStep * scaledWidth * nComps;
+ if (srcAlpha) {
+ destAlphaPtr0 += yStep * scaledWidth;
+ }
+ }
- // x scale Bresenham
- xSrc += xStep;
+ gfree(alphaLineBuf);
+ gfree(lineBuf);
+}
- // x shear
- x1 += xSign;
+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;
+ Guint pix[splashMaxColorComps];
+ Guint alpha;
+ Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
+ int i, j;
+
+ // 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;
+ }
- // y shear
- y1 += yShear1;
- }
- break;
+ // init y scale Bresenham
+ yt = 0;
- case splashModeXBGR8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
- }
+ destPtr0 = dest->data;
+ destAlphaPtr0 = dest->alpha;
+ for (y = 0; y < srcHeight; ++y) {
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
- }
+ // y scale Bresenham
+ if ((yt += yq) >= srcHeight) {
+ yt -= srcHeight;
+ yStep = yp + 1;
+ } else {
+ yStep = yp;
+ }
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc * 4;
- pixAcc0 = pixAcc1 = pixAcc2 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- p++;
- }
- p += 4 * (w - m);
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ // read row from image
+ (*src)(srcData, lineBuf, alphaLineBuf);
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = 255;
+ // init x scale Bresenham
+ xt = 0;
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)255;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+ xx = 0;
+ for (x = 0; x < srcWidth; ++x) {
- // x scale Bresenham
- xSrc += xStep;
+ // x scale Bresenham
+ if ((xt += xq) >= srcWidth) {
+ xt -= srcWidth;
+ xStep = xp + 1;
+ } else {
+ xStep = xp;
+ }
- // x shear
- x1 += xSign;
+ // compute the final pixel
+ for (i = 0; i < nComps; ++i) {
+ pix[i] = lineBuf[x * nComps + i];
+ }
- // y shear
- y1 += yShear1;
+ // store the pixel
+ switch (srcMode) {
+ case splashModeMono1: // mono1 is not allowed
+ break;
+ case splashModeMono8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ }
+ }
+ break;
+ case splashModeRGB8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ }
+ }
+ break;
+ case splashModeXBGR8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)255;
+ }
+ }
+ break;
+ case splashModeBGR8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[0];
+ }
}
break;
-
#if SPLASH_CMYK
case splashModeCMYK8:
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
- xStep = xp;
- xt += xq;
- if (xt >= scaledWidth) {
- xt -= scaledWidth;
- ++xStep;
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ *destPtr++ = (Guchar)pix[0];
+ *destPtr++ = (Guchar)pix[1];
+ *destPtr++ = (Guchar)pix[2];
+ *destPtr++ = (Guchar)pix[3];
}
+ }
+ break;
+#endif
+ }
- // rotation
- if (rot) {
- x2 = (int)y1;
- y2 = -x1;
- } else {
- x2 = x1;
- y2 = (int)y1;
+ // process alpha
+ if (srcAlpha) {
+ alpha = alphaLineBuf[x];
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j;
+ *destAlphaPtr = (Guchar)alpha;
}
+ }
+ }
- // compute the filtered pixel at (x,y) after the x and y scaling
- // operations
- m = xStep > 0 ? xStep : 1;
- p = colorBuf + xSrc * 4;
- pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- pixAcc0 += *p++;
- pixAcc1 += *p++;
- pixAcc2 += *p++;
- pixAcc3 += *p++;
- }
- p += 4 * (w - m);
- }
- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ xx += xStep;
+ }
+
+ destPtr0 += yStep * scaledWidth * nComps;
+ if (srcAlpha) {
+ destAlphaPtr0 += yStep * scaledWidth;
+ }
+ }
- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
+ gfree(alphaLineBuf);
+ gfree(lineBuf);
+}
- // set pixel
- if (vectorAntialias && clipRes != splashClipAllInside) {
- pipe.shape = (SplashCoord)255;
- drawAAPixel(&pipe, tx + x2, ty + y2);
- } else {
- drawPixel(&pipe, tx + x2, ty + y2,
- clipRes2 == splashClipAllInside);
- }
+void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
+ int nComps) {
+ Guchar *lineBuf;
+ Guchar *p0, *p1;
+ int w;
+
+ w = width * nComps;
+ lineBuf = (Guchar *)gmalloc(w);
+ for (p0 = img->data, p1 = img->data + (height - 1) * w;
+ p0 < p1;
+ p0 += w, p1 -= w) {
+ memcpy(lineBuf, p0, w);
+ memcpy(p0, p1, w);
+ memcpy(p1, lineBuf, w);
+ }
+ if (img->alpha) {
+ for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width;
+ p0 < p1;
+ p0 += width, p1 -= width) {
+ memcpy(lineBuf, p0, width);
+ memcpy(p0, p1, width);
+ memcpy(p1, lineBuf, width);
+ }
+ }
+ gfree(lineBuf);
+}
- // x scale Bresenham
- xSrc += xStep;
+void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
+ SplashClipResult clipRes) {
+ SplashPipe pipe;
+ SplashColor pixel;
+ Guchar *ap;
+ int w, h, x0, y0, x1, y1, x, y;
- // x shear
- x1 += xSign;
+ // split the image into clipped and unclipped regions
+ w = src->getWidth();
+ h = src->getHeight();
+ 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;
+ }
+ }
+ }
- // y shear
- y1 += yShear1;
+ // draw the unclipped region
+ if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
+ pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+// pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel, state->fillAlpha,
+// srcAlpha,
+// gFalse, opImagePattern);
+ if (srcAlpha) {
+ for (y = y0; y < y1; ++y) {
+ pipeSetXY(&pipe, xDest + x0, yDest + y);
+ ap = src->getAlphaPtr() + y * w + x0;
+ for (x = x0; x < x1; ++x) {
+ src->getPixel(x, y, pixel);
+ pipe.shape = *ap++;
+ (this->*pipe.run)(&pipe);
+ }
+ }
+ } else {
+ for (y = y0; y < y1; ++y) {
+ pipeSetXY(&pipe, xDest + x0, yDest + y);
+ for (x = x0; x < x1; ++x) {
+ src->getPixel(x, y, pixel);
+ (this->*pipe.run)(&pipe);
}
- break;
-#endif // SPLASH_CMYK
}
}
+ updateModX(xDest + x0);
+ updateModX(xDest + x1 - 1);
+ updateModY(yDest + y0);
+ updateModY(yDest + y1 - 1);
+ }
+ // draw the clipped regions
+ if (y0 > 0) {
+ blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0);
}
+ if (y1 < h) {
+ blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1);
+ }
+ if (x0 > 0 && y0 < y1) {
+ blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0);
+ }
+ if (x1 < w && y0 < y1) {
+ blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0,
+ w - x1, y1 - y0);
+ }
+}
- gfree(colorBuf);
- gfree(alphaBuf);
+void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
+ int xSrc, int ySrc, int xDest, int yDest,
+ int w, int h) {
+ SplashPipe pipe;
+ SplashColor pixel;
+ Guchar *ap;
+ int x, y;
- return splashOk;
+ if (vectorAntialias) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+// pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
+// gTrue,
+// gFalse, opImagePattern);
+ drawAAPixelInit();
+ if (srcAlpha) {
+ for (y = 0; y < h; ++y) {
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ pipe.shape = *ap++;
+ drawAAPixel(&pipe, xDest + x, yDest + y);
+ }
+ }
+ } else {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ pipe.shape = 255;
+ drawAAPixel(&pipe, xDest + x, yDest + y);
+ }
+ }
+ }
+ } else {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+// pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
+// srcAlpha,
+// gFalse, opImagePattern);
+ if (srcAlpha) {
+ for (y = 0; y < h; ++y) {
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (state->clip->test(xDest + x, yDest + y)) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ pipe.shape = *ap++;
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ ++ap;
+ }
+ }
+ }
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ if (state->clip->test(xDest + x, yDest + y)) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
+ }
}
SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
@@ -3699,39 +4622,72 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
}
if (src->alpha) {
- pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255),
- gTrue, nonIsolated);
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
- for (x = 0; x < w; ++x) {
- alpha = *ap++;
- if (noClip || state->clip->test(xDest + x, yDest + y)) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated);
+ if (noClip) {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ alpha = *ap++;
// this uses shape instead of alpha, which isn't technically
// correct, but works out the same
- src->getPixel(xSrc + x, ySrc + y, pixel);
pipe.shape = alpha;
(this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
+ }
+ }
+ updateModX(xDest);
+ updateModX(xDest + w - 1);
+ updateModY(yDest);
+ updateModY(yDest + h - 1);
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ alpha = *ap++;
+ if (state->clip->test(xDest + x, yDest + y)) {
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ pipe.shape = alpha;
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
}
}
}
} else {
- pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255),
- gFalse, nonIsolated);
- for (y = 0; y < h; ++y) {
- pipeSetXY(&pipe, xDest, yDest + y);
- for (x = 0; x < w; ++x) {
- if (noClip || state->clip->test(xDest + x, yDest + y)) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
+ (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated);
+ if (noClip) {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
src->getPixel(xSrc + x, ySrc + y, pixel);
(this->*pipe.run)(&pipe);
- updateModX(xDest + x);
- updateModY(yDest + y);
- } else {
- pipeIncX(&pipe);
+ }
+ }
+ updateModX(xDest);
+ updateModX(xDest + w - 1);
+ updateModY(yDest);
+ updateModY(yDest + h - 1);
+ } else {
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ if (state->clip->test(xDest + x, yDest + y)) {
+ (this->*pipe.run)(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
}
}
}
@@ -3856,11 +4812,21 @@ void Splash::compositeBackground(SplashColorPtr color) {
q = &bitmap->alpha[y * bitmap->width];
for (x = 0; x < bitmap->width; ++x) {
alpha = *q++;
- alpha1 = 255 - alpha;
- p[0] = div255(alpha1 * color0 + alpha * p[0]);
- p[1] = div255(alpha1 * color1 + alpha * p[1]);
- p[2] = div255(alpha1 * color2 + alpha * p[2]);
- p[3] = div255(alpha1 * color3 + alpha * p[3]);
+ if (alpha == 0)
+ {
+ p[0] = color0;
+ p[1] = color1;
+ p[2] = color2;
+ p[3] = color3;
+ }
+ else if (alpha != 255)
+ {
+ alpha1 = 255 - alpha;
+ p[0] = div255(alpha1 * color0 + alpha * p[0]);
+ p[1] = div255(alpha1 * color1 + alpha * p[1]);
+ p[2] = div255(alpha1 * color2 + alpha * p[2]);
+ p[3] = div255(alpha1 * color3 + alpha * p[3]);
+ }
p += 4;
}
}
diff --git a/splash/Splash.h b/splash/Splash.h
index e538808..ce59497 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -318,6 +318,66 @@ private:
SplashPattern *pattern, SplashCoord alpha);
GBool pathAllOutside(SplashPath *path);
void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip);
+ void arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat, GBool glyphMode);
+ SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData,
+ int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight);
+ 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 blitMask(SplashBitmap *src, int xDest, int yDest,
+ SplashClipResult clipRes);
+ SplashError arbitraryTransformImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha,
+ int srcWidth, int srcHeight,
+ SplashCoord *mat);
+ SplashBitmap *scaleImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, int nComps,
+ GBool srcAlpha, int srcWidth, int srcHeight,
+ int scaledWidth, int scaledHeight);
+ 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,
+ int scaledWidth, int scaledHeight,
+ SplashBitmap *dest);
+ void vertFlipImage(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);
void dumpPath(SplashPath *path);
void dumpXPath(SplashXPath *path);
More information about the poppler
mailing list