Am 27.12.2010 19:40, schrieb Albert Astals Cid:
A Dilluns, 27 de desembre de 2010, Thomas Freitag va escriure:
Thanks for immediately starting regtesting.
Thought You're in xmas vacation or have enough to do releasing 0.16.0.
Here the correction for the artefacts by pdftoppm, I made a small
mistake when optimizing my code.
Found some more problems, i found a pdf in which it seems that a circle is not
totally filled, sending you the files.
Albert
Playing once again patch ping pong with You. Hope, we can finish the
game until end of this week :-)
This PDF was a real headscratcher: Okay, I had some rounding problems
calculating the size of the bitmap needed for the pattern. But that
wasn't the main reason. The main reason was that only the half of the
circles are painted with radial pattern, and the clipping path was
exactly on the diameter and the outer line of the circle. Therefore the
use antialiasing has the effect, that is seems that the circles are not
totally filled. You can see that in the middle line of the circles with
the former patch.
Because there is no way to decide on the values of the shading
parameters wether to use antialiasing or not, I changed my mind with
heavy heart not using antialiasing on radial shading pattern. At least
the wine glass is still looking better.
Please try the new attached patch,
Thomas
Thomas
Am 27.12.2010 02:07, schrieb Albert Astals Cid:
A Dilluns, 27 de desembre de 2010, Albert Astals Cid va escriure:
A Diumenge, 26 de desembre de 2010, Thomas Freitag va escriure:
Am 04.11.2010 22:26, schrieb Albert Astals Cid:
Hi, i just commited the patch to splash with antialias and shadings,
really good work!
Now, it seems you are both magicians so i'm asking another wish :D
Of course only do this if you feel like it's fun ;-)
Have a look at the ducks and roses at
http://www.acquerra.com.au/poppler/img_0.pdf
Do you guys feel like trying to fix it?
Albert
Hi Albert!
As I already mentioned, I had a deeper look at the ducks& roses, and
espially at the wine glass.
I encountered, that there is no way to solve that in Gfx.cc, and
therefore I implemented radial shading in SplashOutputDev now. It took
me "some" days, more effort then I thought before beginning, but the
result is really beautiful, therefore I attach not only the patch but
the rendering result too, so that You can immediately what I mean with
beautiful :-)
Take it a belated xmas gift for the poppler community :-)
Good work :-)
I've found a regression though, if you run pdftotext with and without
the pdf file i'll send you in private, you'll see that the lower left
square has some "random" white pixels that are not there without the
patch.
s/pdftotext/pdftoppm :D
Albert
Albert
Best regards,
Thomas
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
.
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
.
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 0b3722a..e8b658b 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -153,6 +153,261 @@ void SplashGouraudPattern::getParameterizedColor(double
colorinterp, SplashColor
}
//------------------------------------------------------------------------
+// SplashRadialPattern
+//------------------------------------------------------------------------
+// Max number of splits along the t axis for a radial shading fill.
+#define radialMaxSplits 256
+
+// Max delta allowed in any color component for a radial shading fill.
+#define radialColorDelta (dblToCol(1.0 / 256.0))
+
+// Max size of pattern bitmap of min (width, height)
+#define radialMaxSize 256
+
+SplashRadialPattern::SplashRadialPattern(GfxState *stateA, GfxRadialShading
*shadingA,
+
double sMinA, double sMaxA, SplashColorMode colorModeA) {
+ double width, height;
+ Matrix ctm;
+
+ state = stateA;
+ shading = shadingA;
+ sMin = sMinA;
+ sMax = sMaxA;
+ colorMode = colorModeA;
+ state->getCTM(&ctm);
+ ctm.invertTo(&ictm);
+ ia = 0;
+ splash = NULL;
+ bitmap = NULL;
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ if (shading->getHasBBox())
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ else
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ xMin = splashRound(xMin);
+ xMax = splashRound(xMax);
+ yMin = splashRound(yMin);
+ yMax = splashRound(yMax);
+ width = xMax - xMin;
+ height = yMax - yMin;
+ if (radialMaxSize > 0) {
+ if ( width > height)
+ scale = radialMaxSize / height;
+ else
+ scale = radialMaxSize / width;
+ } else
+ scale = 1;
+ xMin *= scale;
+ xMax *= scale;
+ yMin *= scale;
+ yMax *= scale;
+ width *= scale;
+ height *= scale;
+ bitmap = new SplashBitmap(splashRound(width) + 1, splashRound(height) + 1,
colorMode != splashModeMono1, colorMode, gTrue);
+ splash = new Splash(bitmap, gFalse /* AntiAlias in shading Dict! */);
+
+ // show only what is painted, delete alpha channel
+ Guchar *bitmapAlpha = bitmap->getAlphaPtr();
+ int size = bitmap->getWidth() * bitmap->getHeight();
+ for (int i = 0; i < size; ++i)
+ bitmapAlpha[i] = 0;
+
+ // change transfer matrix to fit to scaled bitmap
+ ictm.m[0] *= scale;
+ ictm.m[1] *= scale;
+ ictm.m[2] *= scale;
+ ictm.m[3] *= scale;
+ ictm.m[4] *= scale;
+ ictm.m[5] *= scale;
+ ictm.m[4] -= xMin;
+ ictm.m[5] -= yMin;
+}
+
+SplashRadialPattern::~SplashRadialPattern() {
+ if (splash) {
+ delete splash;
+ }
+ if (bitmap) {
+ delete bitmap;
+ }
+}
+
+GBool SplashRadialPattern::getColor(int x, int y, SplashColorPtr c) {
+ double xc, yc;
+ int xs, ys;
+ Guchar *bitmapAlpha;
+
+ bitmapAlpha = bitmap->getAlphaPtr();
+ ictm.transform(x, y, &xc, &yc);
+ xs = splashRound(xc);
+ ys = splashRound(yc);
+ if (xs < 0 || xs >= bitmap->getWidth())
+ return gFalse;
+ if (ys < 0 || ys >= bitmap->getHeight())
+ return gFalse;
+ if (bitmapAlpha[ys * bitmap->getWidth() + xs])
+ bitmap->getPixel(xs, ys, c);
+ else
+ return gFalse;
+ return gTrue;
+}
+
+static inline void getShadingColorRadialHelper(double t0, double t1, double t,
GfxRadialShading *shading, GfxColor *color)
+{
+ if (t0 < t1) {
+ if (t < t0) {
+ shading->getColor(t0, color);
+ } else if (t > t1) {
+ shading->getColor(t1, color);
+ } else {
+ shading->getColor(t, color);
+ }
+ } else {
+ if (t > t0) {
+ shading->getColor(t0, color);
+ } else if (t < t1) {
+ shading->getColor(t1, color);
+ } else {
+ shading->getColor(t, color);
+ }
+ }
+}
+
+void SplashRadialPattern::getStartCircle(SplashCoord *xsc, SplashCoord *ysc,
+
SplashCoord *radius,
+
SplashColorPtr c) {
+ GfxColor colorA;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ sa = (r0 > r1) ? sMin : sMax;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ getShadingColorRadialHelper(t0, t1, ta, shading, &colorA);
+ *radius = splashRound(ra * scale);
+ *xsc = splashRound(xa * scale - xMin); *ysc = splashRound(ya * scale -
yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorA);
+}
+
+static inline GBool isSameGfxColor(const GfxColor &colorA, const GfxColor
&colorB, Guint nComps, double delta) {
+ for (Guint k = 0; k < nComps; ++k) {
+ if (abs(colorA.c[k] - colorB.c[k]) > delta) {
+ return false;
+ }
+ }
+ return true;
+}
+
+GBool SplashRadialPattern::getNextCircle(SplashCoord *xsc, SplashCoord *ysc,
+
SplashCoord *radius,
+
SplashColorPtr c) {
+ GfxColor colorA, colorB;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ double sb, tb, factor;
+ int ib, nComps;
+ nComps = shading->getColorSpace()->getNComps();
+ if (ia >= radialMaxSplits)
+ return gFalse;
+ getShadingColorRadialHelper(t0, t1, ta, shading, &colorA);
+ ib = radialMaxSplits;
+ sb = (r0 > r1) ? sMax : sMin;
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ while (ib - ia > 1) {
+ if (isSameGfxColor(colorB, colorA, nComps, radialColorDelta)) {
+ // The shading is not necessarily lineal so having two points with the
+ // same color does not mean all the areas in between have the same
color too
+ int ic = ia + 1;
+ for (; ic <= ib; ic++) {
+ GfxColor colorC;
+ factor = (r0 > r1) ? (double)ic /
(double)radialMaxSplits : 1 - (double)ic / (double)radialMaxSplits;
+ double sc = sMin + factor * (sMax - sMin);
+ double tc = t0 + sc * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tc, shading,
&colorC);
+ if (!isSameGfxColor(colorC, colorA, nComps,
radialColorDelta)) {
+ break;
+ }
+ }
+ ib = (ic > ia + 1)? ic - 1 : ia + 1;
+ factor = (r0 > r1) ? (double)ib / (double)radialMaxSplits : 1
- (double)ib / (double)radialMaxSplits;
+ sb = sMin + factor * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ break;
+ }
+ ib = (ia + ib) / 2;
+ factor = (r0 > r1) ? (double)ib / (double)radialMaxSplits : 1 -
(double)ib / (double)radialMaxSplits;
+ sb = sMin + factor * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ }
+ // compute center and radius of the circle
+ xa = x0 + sb * (x1 - x0);
+ ya = y0 + sb * (y1 - y0);
+ ra = r0 + sb * (r1 - r0);
+ *radius = splashRound(ra * scale);
+ *xsc = splashRound(xa * scale - xMin); *ysc = splashRound(ya * scale -
yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorB);
+ ia = ib;
+ ta = tb;
+ return gTrue;
+}
+
+GBool SplashRadialPattern::getLargerExtendCircle(SplashCoord *xsc, SplashCoord
*ysc,
+
SplashCoord *radius, SplashColorPtr c) {
+ GfxColor colorA;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ if (r0 > r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ *radius = splashRound(ra * scale);
+ *xsc = splashRound(xa * scale - xMin); *ysc = splashRound(ya
* scale - yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorA);
+ return gTrue;
+ }
+ return gFalse;
+}
+
+GBool SplashRadialPattern::getSmallerExtendCircle(SplashCoord *xsc,
SplashCoord *ysc,
+
SplashCoord *radius, SplashColorPtr c) {
+ GfxColor colorA;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ if ((shading->getExtend0() && r0 <= r1) ||
+ (shading->getExtend1() && r1 < r0)) {
+ if (r0 <= r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ *radius = splashRound(ra * scale);
+ *xsc = splashRound(xa * scale - xMin); *ysc = splashRound(ya
* scale - yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorA);
+ return gTrue;
+ }
+ return gFalse;
+}
+//------------------------------------------------------------------------
// SplashAxialPattern
//------------------------------------------------------------------------
@@ -3379,3 +3634,35 @@ GBool SplashOutputDev::axialShadedFill(GfxState *state,
GfxAxialShading *shading
return retVal;
}
+
+GBool SplashOutputDev::radialShadedFill(GfxState *state, GfxRadialShading
*shading, double sMin, double sMax) {
+ double xMin, yMin, xMax, yMax;
+ SplashPath *path;
+
+ GBool retVal = gFalse;
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // fill the region
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ path = convertPath(state, state->getPath());
+
+ SplashRadialColor *pattern = new SplashRadialPattern(state, shading, sMin,
sMax, colorMode);
+ if (pattern->isOk()) {
+ // first draw the radial shading in its own bitmap
+ retVal = (pattern->getSplash()->radialShadedFill(pattern) ==
splashOk);
+ // now use this bitmap as dynamic pattern:
+ if (retVal) {
+ retVal = (splash->shadedFill(path, shading->getHasBBox(),
pattern) == splashOk);
+ }
+ }
+ state->clearPath();
+ delete pattern;
+ delete path;
+
+ return retVal;
+}
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 570d036..1e243c2 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -105,6 +105,45 @@ private:
GBool bDirectColorTranslation;
};
+// see GfxState.h, GfxRadialShading
+class SplashRadialPattern: public SplashRadialColor {
+public:
+
+ SplashRadialPattern(GfxState *state, GfxRadialShading *shading, double sMin,
double sMax, SplashColorMode colorMode);
+
+ GBool isOk() { return (bitmap != NULL); }
+
+ Splash *getSplash() { return splash; }
+
+ SplashBitmap *getBitmap() { return bitmap; }
+
+ virtual SplashPattern *copy() { return new SplashRadialPattern(state,
shading, sMin, sMax, colorMode); }
+
+ virtual ~SplashRadialPattern();
+
+ virtual GBool getColor(int x, int y, SplashColorPtr c);
+
+ virtual GBool isStatic() { return gFalse; }
+
+ virtual void getStartCircle(SplashCoord *x0, SplashCoord *y0, SplashCoord
*radius, SplashColorPtr c);
+ virtual GBool getNextCircle(SplashCoord *x0, SplashCoord *y0, SplashCoord
*radius, SplashColorPtr c);
+ virtual GBool getLargerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c);
+ virtual GBool getSmallerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c);
+private:
+ GfxRadialShading *shading;
+ GfxState *state;
+ Matrix ictm;
+ double sMin, sMax;
+ double xMin, xMax, yMin, yMax;
+ double scale;
+ double xa, ya, ra, ta, sa;
+ int ia;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ Splash *splash;
+ SplashBitmap *bitmap;
+ SplashColorMode colorMode;
+};
+
//------------------------------------------------------------------------
// number of Type 3 fonts to cache
@@ -132,7 +171,7 @@ public:
// radialShadedFill()? If this returns false, these shaded fills
// will be reduced to a series of other drawing operations.
virtual GBool useShadedFills(int type)
- { return (type == 2 || type == 4 || type == 5 ) ? gTrue : gFalse; }
+ { return (type >= 2 && type <= 5) ? gTrue : gFalse; }
// Does this device use upside-down coordinates?
// (Upside-down means (0,0) is the top left corner of the page.)
@@ -186,6 +225,7 @@ public:
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading,
double tMin, double tMax);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading,
double sMin, double sMax);
virtual GBool gouraudTriangleShadedFill(GfxState *state,
GfxGouraudTriangleShading *shading);
//----- path clipping
diff --git a/splash/Splash.cc b/splash/Splash.cc
index bc317a6..ef48921 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -3531,6 +3531,257 @@ GBool
Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
return gTrue;
}
+SplashPath *Splash::getBresenhamPoints(SplashCoord xc, SplashCoord yc,
SplashCoord rc) {
+ int radius = splashRound(rc);
+ int x0 = splashRound(xc);
+ int y0 = splashRound(yc);
+ int f = 1 - radius;
+ int ddF_x = 1;
+ int ddF_y = -2 * radius;
+ int x = 0, lastX = x;
+ int y = radius, lastY = y;
+ Guchar dummy;
+ SplashPath *splashPath = new SplashPath();
+
+ if (radius == 0) {
+ splashPath->moveTo(lastX, lastY);
+ return splashPath;
+ }
+
+ while(x < y)
+ {
+ // ddF_x == 2 * x + 1;
+ // ddF_y == -2 * y;
+ // f == x*x + y*y - radius*radius + 2*x - y + 1;
+ if(f >= 0)
+ {
+ y--;
+ ddF_y += 2;
+ f += ddF_y;
+ }
+ x++;
+ ddF_x += 2;
+ f += ddF_x;
+ if (lastY != y) {
+ if (splashPath->getLength())
+ splashPath->lineTo(lastX, lastY);
+ else
+ splashPath->moveTo(lastX, lastY);
+ lastY = y;
+ }
+ lastX = x;
+ }
+ for (int i = splashPath->getLength() -1; i >= 0; i--) {
+ SplashCoord curX, curY;
+ splashPath->getPoint(i, &curY, &curX, &dummy);
+ for (SplashCoord j = lastY; j >= curY; j--)
+ splashPath->lineTo(curX, j);
+ lastY = splashRound(curY - 1);
+ }
+ while (lastY >= 0)
+ splashPath->lineTo(rc, lastY--);
+ return splashPath;
+}
+
+static inline void getBEllipseLine(SplashPath *bresPoints, SplashCoord y,
SplashCoord y0, SplashCoord r, SplashCoord *x) {
+ GBool found = gFalse;
+ if (y == y0)
+ *x = r;
+ else if (y > y0) {
+ SplashCoord curX, curY;
+ Guchar dummy;
+ for (int i = 0; i < bresPoints->getLength(); i++) {
+ bresPoints->getPoint(i, &curX, &curY, &dummy);
+ if (curY + y0 == y) {
+ *x = curX;
+ return;
+ }
+ }
+ } else {
+ SplashCoord curX, curY;
+ Guchar dummy;
+ for (int i = bresPoints->getLength() - 1; i >= 0; i--) {
+ bresPoints->getPoint(i, &curX, &curY, &dummy);
+ if (y0 - curY == y) {
+ *x = curX;
+ return;
+ }
+ }
+ }
+}
+
+void Splash::drawPartEllipseLine(SplashPipe *pipe,
+ SplashCoord
y,
+ SplashCoord
xMin, SplashCoord xMax) {
+ int yI, xmaxI, xminI;
+ int height = bitmap->getHeight();
+ int width = bitmap->getWidth();
+ Guchar *bitmapAlpha = bitmap->getAlphaPtr();
+ yI = splashRound(y);
+ xmaxI = splashRound(xMax);
+ xminI = splashRound(xMin);
+ if (yI >= 0 && yI < height) {
+ if (xminI < 0)
+ xminI = 0;
+ if (xminI < width) {
+ if (xmaxI > width - 1)
+ xmaxI = width - 1;
+ drawSpan(pipe, xminI, xmaxI, yI, gTrue);
+ }
+ }
+}
+
+void Splash::drawBEllipseLine(SplashPipe *pipe, SplashPath *bresInnerPoints,
+ SplashCoord
y, SplashCoord yiMin, SplashCoord yiMax,
+ SplashCoord
yi, SplashCoord xi, SplashCoord iradius,
+ SplashCoord
xMin, SplashCoord xMax) {
+ if (y > yiMax || y < yiMin)
+ drawPartEllipseLine(pipe, y, xMin, xMax);
+ else {
+ SplashCoord xiMin, xiMax;
+ getBEllipseLine(bresInnerPoints, y, yi, iradius, &xiMin);
+ xiMax = xi + xiMin;
+ xiMin = xi - xiMin;
+ if (xiMin >= xMin || xiMax <= xMax) {
+ if (xiMax < xMin || xiMin > xMax)
+ drawPartEllipseLine(pipe, y, xMin - 1, xMax +
1);
+ else if (xiMin < xMin && xiMax < xMax)
+ drawPartEllipseLine(pipe, y, xiMax - 1, xMax +
1);
+ else if (xiMin > xMin && xiMax < xMax) {
+ drawPartEllipseLine(pipe, y, xMin - 1, xiMin +
1);
+ drawPartEllipseLine(pipe, y, xiMax - 1, xMax +
1);
+ } else
+ drawPartEllipseLine(pipe, y, xMin - 1, xiMin +
1);
+ }
+ }
+}
+
+SplashError Splash::radialShadedFill(SplashRadialColor *shading) {
+ SplashPipe pipe;
+ SplashColor cSrcVal, cNextVal;
+ SplashColorPtr cur = cSrcVal, curNext = cNextVal;
+
+ pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse,
gFalse);
+
+ SplashCoord xo, yo, oradius;
+ SplashCoord xi, yi, iradius;
+ shading->getStartCircle(&xo, &yo, &oradius, cur);
+ SplashPath *bresOuterPoints = getBresenhamPoints(xo, yo, oradius);
+ if (bresOuterPoints == NULL)
+ return splashErrEmptyPath;
+ pipe.cSrc = cur;
+ while (shading->getNextCircle(&xi, &yi, &iradius, curNext)) {
+ if (xi == xo && yi == yo && iradius == oradius) {
+ splashColorCopy(cur, curNext);
+ continue;
+ }
+ SplashPath *bresInnerPoints = getBresenhamPoints(xi, yi,
iradius);
+ if (bresInnerPoints == NULL)
+ break;
+ SplashCoord yiMax = yi + iradius, yiMin = yi - iradius;
+ Guchar dummy;
+
+ for (int i = 0; i < bresOuterPoints->getLength(); i++) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ bresOuterPoints->getPoint(i, &curX, &curY, &dummy);
+ xMax = xo + curX;
+ xMin = xo - curX;
+ curY += yo;
+ if (curY >= 0 && curY < bitmap->getHeight())
+ drawBEllipseLine(&pipe, bresInnerPoints,
+ curY, yiMin, yiMax, yi, xi, iradius,
xMin, xMax);
+ curY = 2 * yo - curY;
+ if (curY >= 0 && curY < bitmap->getHeight())
+ drawBEllipseLine(&pipe, bresInnerPoints,
+ curY, yiMin, yiMax, yi, xi, iradius,
xMin, xMax);
+ }
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ yo = yi; xo = xi; oradius = iradius;
+ splashColorCopy(cur, curNext);
+ }
+ delete bresOuterPoints;
+ if (shading->getSmallerExtendCircle(&xo, &yo, &oradius, cur)) {
+ SplashPath *bresPoints = getBresenhamPoints(xo, yo, oradius);
+ if (bresPoints == NULL)
+ goto DrawLarge;
+ SplashCoord xMin, xMax;
+ Guchar dummy;
+ for (int i = 0; i < bresPoints->getLength(); i++) {
+ SplashCoord curX, curY;
+ bresPoints->getPoint(i, &curX, &curY, &dummy);
+ curY += yo;
+ xMax = xo + curX;
+ xMin = xo - curX;
+ if (curY >= 0 && curY < bitmap->getHeight())
+ drawPartEllipseLine(&pipe, curY, xMin, xMax);
+ curY = 2 * yo - curY;
+ if (curY >= 0 && curY < bitmap->getHeight())
+ drawPartEllipseLine(&pipe, 2* yo - curY, xMin,
xMax);
+ }
+ delete bresPoints;
+ }
+DrawLarge:
+ if (shading->getLargerExtendCircle(&xo, &yo, &oradius, cur)) {
+ SplashPath *bresPoints = getBresenhamPoints(xo, yo, oradius);
+ if (bresPoints == NULL)
+ goto RadialEnd;
+ SplashCoord xMin, xMax, y;
+ SplashCoord yMin, yMax;
+ yMax = yo + oradius;
+ yMin = yo - oradius;
+ Guchar dummy;
+ int i = 0;
+ if (yMax >= bitmap->getHeight()) {
+ i = splashRound(yMax - bitmap->getHeight() + 1);
+ }
+ if (yo >= bitmap->getHeight()) {
+ i = bresPoints->getLength() - 1 - splashRound(yo -
bitmap->getHeight() + 1);
+ }
+ for (y = bitmap->getHeight() - 1; y >= 0; y--) {
+ if (y > yMax || y < yMin)
+ drawPartEllipseLine(&pipe, y, 0,
bitmap->getWidth() - 1);
+ else if (y > yo) {
+ SplashCoord curX, curY;
+ bresPoints->getPoint(i++, &curX, &curY, &dummy);
+ xMin = xo - curX;
+ xMax = xo + curX;
+ if (xMin - 1 > 0)
+ drawPartEllipseLine(&pipe, y, 0, xMin +
1);
+ if (xMax + 1 < 0)
+ drawPartEllipseLine(&pipe, y, 0,
bitmap->getWidth() - 1);
+ else if (xMax + 1 < bitmap->getWidth())
+ drawPartEllipseLine(&pipe, y, xMax - 1,
bitmap->getWidth() - 1);
+ } else if (y == yo) {
+ i = bresPoints->getLength() - 1;
+ xMin = xo - oradius;
+ xMax = xo + oradius;
+ if (xMin - 1 > 0)
+ drawPartEllipseLine(&pipe, y, 0, xMin +
1);
+ if (xMax + 1 < 0)
+ drawPartEllipseLine(&pipe, y, 0,
bitmap->getWidth() - 1);
+ else if (xMax + 1 < bitmap->getWidth())
+ drawPartEllipseLine(&pipe, y, xMax - 1,
bitmap->getWidth() - 1);
+ } else {
+ SplashCoord curX, curY;
+ bresPoints->getPoint(--i, &curX, &curY, &dummy);
+ xMin = xo - curX;
+ xMax = xo + curX;
+ if (xMin - 1 > 0)
+ drawPartEllipseLine(&pipe, y, 0, xMin +
1);
+ if (xMax + 1 < 0)
+ drawPartEllipseLine(&pipe, y, 0,
bitmap->getWidth() - 1);
+ else if (xMax + 1 < bitmap->getWidth())
+ drawPartEllipseLine(&pipe, y, xMax - 1,
bitmap->getWidth() - 1);
+ }
+ }
+ delete bresPoints;
+ }
+RadialEnd:
+ return splashOk;
+}
+
SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h) {
SplashColor pixel;
@@ -3950,19 +4201,25 @@ SplashError Splash::shadedFill(SplashPath *path, GBool
hasBBox,
int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
SplashClipResult clipRes;
- if (aaBuf == NULL) { // should not happen, but to be secure
+ if (vectorAntialias && aaBuf == NULL) { // should not happen, but to be
secure
return splashErrGeneric;
}
if (path->length == 0) {
return splashErrEmptyPath;
}
xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
- xPath->aaScale();
+ if (vectorAntialias) {
+ xPath->aaScale();
+ }
xPath->sort();
scanner = new SplashXPathScanner(xPath, gFalse);
- // get the min and max x and y values
- scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ // get the min and max x and y values
+ if (vectorAntialias) {
+ scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ } else {
+ scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ }
// check clipping
if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) !=
splashClipAllOutside) {
@@ -3977,13 +4234,34 @@ SplashError Splash::shadedFill(SplashPath *path, GBool
hasBBox,
pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias
&& !hasBBox, gFalse);
// draw the spans
- for (y = yMinI; y <= yMaxI; ++y) {
- scanner->renderAALine(aaBuf, &x0, &x1, y);
- if (clipRes != splashClipAllInside) {
- state->clip->clipAALine(aaBuf, &x0, &x1, y);
- }
- drawAALine(&pipe, x0, x1, y);
- }
+ if (vectorAntialias) {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ scanner->renderAALine(aaBuf, &x0, &x1, y);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ }
+ drawAALine(&pipe, x0, x1, y);
+ }
+ } else {
+ SplashClipResult clipRes2;
+ for (y = yMinI; y <= yMaxI; ++y) {
+ while (scanner->getNextSpan(y, &x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, gTrue);
+ } else {
+ // limit the x range
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
+ }
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
+ }
+ clipRes2 = state->clip->testSpan(x0,
x1, y);
+ drawSpan(&pipe, x0, x1, y, clipRes2 ==
splashClipAllInside);
+ }
+ }
+ }
+ }
}
opClipRes = clipRes;
diff --git a/splash/Splash.h b/splash/Splash.h
index a52dc13..37e63f9 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -255,6 +255,14 @@ public:
SplashPattern *pattern);
// Draw a gouraud triangle shading.
GBool gouraudTriangleShadedFill(SplashGouraudColor *shading);
+ // Draw a radial shading.
+ void drawPartEllipseLine(SplashPipe *pipe, SplashCoord y, SplashCoord xMin,
SplashCoord xMax);
+ void drawBEllipseLine(SplashPipe *pipe, SplashPath *bresInnerPoints,
+ SplashCoord
y, SplashCoord yiMin, SplashCoord yiMax,
+ SplashCoord
yi, SplashCoord xi, SplashCoord iradius,
+ SplashCoord
xMin, SplashCoord xMax);
+ SplashPath *getBresenhamPoints(SplashCoord x0, SplashCoord y0, SplashCoord
radius);
+ SplashError radialShadedFill(SplashRadialColor *shading);
private:
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index 09e9b1a..fb82df2 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -28,6 +28,8 @@
#include "SplashTypes.h"
class SplashScreen;
+class Splash;
+class SplashBitmap;
//------------------------------------------------------------------------
// SplashPattern
@@ -92,4 +94,19 @@ public:
virtual void getParameterizedColor(double t, SplashColorMode mode,
SplashColorPtr c) = 0;
};
+//------------------------------------------------------------------------
+// SplashRadialColor (needed for radialShadedFill)
+//------------------------------------------------------------------------
+
+class SplashRadialColor: public SplashPattern {
+public:
+ virtual void getStartCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool getNextCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool getSmallerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool getLargerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool isOk() = 0;
+ virtual Splash *getSplash() = 0;
+ virtual SplashBitmap *getBitmap() = 0;
+};
+
#endif
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler