A Dimecres, 6 d'octubre de 2010, Christian Feuersaenger va escriure:
> Am 05.10.2010 22:59, schrieb Albert Astals Cid:
> > A Dijous, 30 de setembre de 2010, Christian Feuersaenger va escriure:
> >> Hello Albert,
> >>
> >> Am 30.09.2010 00:00, schrieb Albert Astals Cid:
> >>> A Dijous, 19 d'agost de 2010, vàreu escriure:
> >>>> Dear Albert,
> >>>>
> >>>> attached you find a test.pdf in which the improvements can be seen.
> >>>>
> >>>> The rendering quality of my patch is much better; it eliminates the
> >>>> moire effects of the flat shading approximation (top left image).
> >>>>
> >>>> Compare also the image with opacity on page 2 of test.pdf.
> >>>>
> >>>> Besides the improved rendering quality, the most obvious change is the
> >>>> required runtime: on my system, the default xpdf requires 15 seconds
> >>>> until it stops rendering the first page whereas xpdf with poppler
> >>>> support and my new patch requires about one second. The pdftoppm
> >>>> utility is also considerably faster.
> >>>>
> >>>> Let me stress that the patch is unrelated to my previous bugfixes, so
> >>>> rendering problems are only fixed together with the other bugfix.
> >>>
> >>> I'm not sure i understand this last sentence, you say that the patches
> >>> are
> >>> unrelated but then you say the bugs are only fixed together with the
> >>> other
> >>> patch?
> >>>
> >>> Should i run a regression test over this patch or does it need to be in
> >>> conjunction with the other patch?
> >>
> >> The "Implementation for real gouraud shaded triangles" is more a new
> >> feature than simply a bugfix: it re-implements the shaders for the
> >> splash device. Its purpose is mainly a vastly improved rendering speed.
> >> I'd suggest to run regression tests on this implementation separately
> >> from my other patch proposals.
> >>
> >> The other patch proposals (you have processed them already; I still
> >> have to investigate your problem report) are bug fixes which should be
> >> tested separately.
> >>
> >> My last remark is to be understood as follows:
> >> 1. if you view test.pdf with both patches, you have best quality and
> >> highest speed.
> >> 2. if you view test.pdf only with the given patch, you have high speed
> >> and good quality for the triangle patches, but the coons patch things
> >> will be buggy.
> >> 3. if you only process the other patch proposal (the bugfixes which are
> >> not part of mail), the coons patches are rendered correctly; but the
> >> triangle patches are slow and only approximately correct due to the
> >> piecewise flat triangle approximation as it is currently done in
> >> libpoppler.
> >>
> >> I think the most reliable quality verification can be gained by testing
> >> both patches separately.
> >
> > Ok, i've ran the test regression over this aptch and everything seems to
> > be ok, could you please fix the FIXME and TODO you have in the code?
>
> Hello Albert,
>
> I'm glad the regression tests passed. Concerning the FIXME and TODO
> list: They constitute (without exception) additional features which do
> not limit the application of the patch (falling back to the old
> implementations automatically). I am willing to work on the FIXMEs, but
> a realization might not be finished before the beginning of the new year
> due to my personal time schedule for the next months.
>
> I suggest to incorporate the patch into libpoppler as-is, and I will
> work on the remaining feature requests eventually.
Not really, i want at least splashModeXBGR8 fixed (can can just try it with
qt4/test/test-poppler-qt4) before commiting since is what the Qt frontend uses
that is the major user of the Splash backend.
I attach the patch as i tried.
Albert
>
> Best regards
>
> Christian
>
> > Thanks,
> >
> > Albert
> >>
> >> Best regards
> >>
> >> Christian
> >>
> >> PS
> >> Sorry if you get notifications because of 'Post by non-member to a
> >> members-only list'... I keep clicking onto the wrong email address :(
> >> (have now registered both of them)
> >>
> >>> Albert
> >>>
> >>>> Best regards
> >>>>
> >>>> Christian
> >>>>
> >>>> Am 18.08.2010 23:15, schrieb Albert Astals Cid:
> >>>>> A Dijous, 15 de juliol de 2010, Christian Feuersaenger va escriure:
> >>>>>> Dear poppler developers,
> >>>>>>
> >>>>>> hereby I propose a new patch for a high quality, fast gouraud
> >>>>>> shader for
> >>>>>> triangle shadings.
> >>>>>>
> >>>>>> The patch provides
> >>>>>> - scalable triangle shadings (in contrast to the old approach),
> >>>>>> - correct shading, no approximation using flat triangles,
> >>>>>> - greatly (!) improved rendering speed,
> >>>>>> - support for opacity (in contrast to the previous approach).
> >>>>>>
> >>>>>> This patch is relative to the master branch,
> >>>>>> git show poppler-0.14.0-91-g31ac578 .
> >>>>>>
> >>>>>> It is unrelated to my previous patch proposals concerning shadings;
> >>>>>> the
> >>>>>> other patch proposal (my mail several weeks ago) is still important
> >>>>>> and
> >>>>>> relevant. The patch in this mail is independent and does not
> >>>>>> include my
> >>>>>> previous patch proposals.
> >>>>>>
> >>>>>> I tested the new patch with pdftoppm and with the xpdf-poppler fork
> >>>>>> of Rogerio Brito; it appears to work reliable. I tested
> >>>>>> - matrix shadings and triangle patch shadings (Types 4 and 5),
> >>>>>> - degenerated triangles,
> >>>>>> - clipping,
> >>>>>> - opacity,
> >>>>>> - RGB color spaces.
> >>>>>>
> >>>>>> The implementation now supports these shadings on a display driver
> >>>>>> level
> >>>>>> and is implemented directly in the splash device (using scanline
> >>>>>> sweeps).
> >>>>>>
> >>>>>> I've been defensive: I have no test cases for other color spaces and
> >>>>>> I have no test data for non-parametric shadings. Consequently, I
> >>>>>> disabled
> >>>>>> the shader for these cases; it will fall back to the existing
> >>>>>> solutions
> >>>>>> (approximate shading by means of many flat triangles).
> >>>>>>
> >>>>>> I hope you find my patch proposal useful. I believe it is worthy of
> >>>>>> being part of libpoppler.
> >>>>>
> >>>>> Do you have a pdf where we can see the improvement this patch gives?
> >>>>>
> >>>>> Albert
> >>>>>
> >>>>>> Thanks,
> >>>>>>
> >>>>>> Christian
> >>>>>
> >>>>> _______________________________________________
> >>>>> 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
> >
> > _______________________________________________
> > 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/Function.cc b/poppler/Function.cc
index e7383fd..d32948c 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -523,6 +523,7 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
e = obj1.getNum();
obj1.free();
+ isLinear = fabs(e-1.) < 1e-10;
ok = gTrue;
return;
@@ -553,7 +554,7 @@ void ExponentialFunction::transform(double *in, double *out) {
x = in[0];
}
for (i = 0; i < n; ++i) {
- out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
+ out[i] = c0[i] + ( isLinear ? x : pow(x, e) ) * (c1[i] - c0[i]);
if (hasRange) {
if (out[i] < range[i][0]) {
out[i] = range[i][0];
diff --git a/poppler/Function.h b/poppler/Function.h
index 2dcccb0..de9a88c 100644
--- a/poppler/Function.h
+++ b/poppler/Function.h
@@ -174,6 +174,7 @@ private:
double c0[funcMaxOutputs];
double c1[funcMaxOutputs];
double e;
+ bool isLinear;
GBool ok;
};
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 7552fed..8edb0b6 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -3096,6 +3096,11 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
}
void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
+ if( out->useShadingType( shading->getType() ) ) {
+ if( out->gouraudTriangleShadedFill( state, shading ) )
+ return;
+ }
+
double x0, y0, x1, y1, x2, y2;
GfxColor color0, color1, color2;
int i;
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 59a8863..7a9e68e 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -3394,6 +3394,41 @@ void GfxGouraudTriangleShading::getTriangle(
}
}
+void GfxGouraudTriangleShading::getParameterizedColor(
+ double t, GfxColor* color ) {
+
+ double out[gfxColorMaxComps];
+ int j;
+
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&t, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color->c[j] = dblToCol(out[j]);
+ }
+}
+
+void GfxGouraudTriangleShading::getTriangle(
+ int i,
+ double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2) {
+ int v;
+
+ v = triangles[i][0];
+ *x0 = vertices[v].x;
+ *y0 = vertices[v].y;
+ *color0 = colToDbl(vertices[v].color.c[0]);
+ v = triangles[i][1];
+ *x1 = vertices[v].x;
+ *y1 = vertices[v].y;
+ *color1 = colToDbl(vertices[v].color.c[0]);
+ v = triangles[i][2];
+ *x2 = vertices[v].x;
+ *y2 = vertices[v].y;
+ *color2 = colToDbl(vertices[v].color.c[0]);
+}
+
//------------------------------------------------------------------------
// GfxPatchMeshShading
//------------------------------------------------------------------------
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 900214d..dbcbcee 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -876,10 +876,35 @@ public:
virtual GfxShading *copy();
int getNTriangles() { return nTriangles; }
+
+ bool isParameterized() const { return nFuncs > 0; }
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMin() const { return funcs[0]->getDomainMin(0); }
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMax() const { return funcs[0]->getDomainMax(0); }
+
+ /**
+ * @precondition isParameterized() == false
+ */
void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
double *x1, double *y1, GfxColor *color1,
double *x2, double *y2, GfxColor *color2);
+ /**
+ * Variant for functions.
+ *
+ * @precondition isParameterized() == true
+ */
+ void getTriangle(int i, double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2);
+
+ void getParameterizedColor( double t, GfxColor* color );
+
private:
GfxGouraudVertex *vertices;
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index cdc74cf..b6bc5ca 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -47,6 +47,8 @@ class GfxColorSpace;
class GfxImageColorMap;
class GfxFunctionShading;
class GfxAxialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
class GfxRadialShading;
class Stream;
class Links;
@@ -87,6 +89,9 @@ public:
// will be reduced to a series of other drawing operations.
virtual GBool useShadedFills() { return gFalse; }
+ // Does this device support specific shading types?
+ // see gouraudTriangleShadedFill() and patchMeshShadedFill()
+ virtual GBool useShadingType( int type ) { if( type < 4 ) return useShadedFills(); return gFalse; }
// Does this device use FillColorStop()?
virtual GBool useFillColorStop() { return gFalse; }
@@ -208,6 +213,10 @@ public:
{ return gFalse; }
virtual GBool radialShadedSupportExtend(GfxState * /*state*/, GfxRadialShading * /*shading*/)
{ return gFalse; }
+ virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+ { return gFalse; }
+ virtual GBool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
+ { return gFalse; }
//----- path clipping
virtual void clip(GfxState * /*state*/) {}
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 0ae5bc5..129f07a 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -963,6 +963,13 @@ void SplashOutputDev::startDoc(XRef *xrefA) {
nT3Fonts = 0;
}
+GBool SplashOutputDev::useShadingType( int type )
+{
+ if( type < 4 )
+ return useShadedFills();
+ return type == 4 || type == 5;
+}
+
void SplashOutputDev::startPage(int pageNum, GfxState *state) {
int w, h;
double *ctm;
@@ -3186,3 +3193,8 @@ void SplashOutputDev::setFreeTypeHinting(GBool enable)
{
enableFreeTypeHinting = enable;
}
+
+GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+{
+ return splash->gouraudTriangleShadedFill(state,shading);
+}
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index adbd196..2b7a9e3 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -81,6 +81,8 @@ public:
// text in Type 3 fonts will be drawn with drawChar/drawString.
virtual GBool interpretType3Chars() { return gTrue; }
+ virtual GBool useShadingType( int type );
+
// This device now supports text in pattern colorspace!
virtual GBool supportTextCSPattern(GfxState *state)
{ return state->getFillColorSpace()->getMode() == csPattern; }
@@ -217,6 +219,8 @@ public:
SplashFont *getCurrentFont() { return font; }
+ GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
+
#if 1 //~tmp: turn off anti-aliasing temporarily
virtual GBool getVectorAntialias();
virtual void setVectorAntialias(GBool vaa);
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 5e27d42..c0278bb 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -55,6 +55,10 @@ static inline Guchar div255(int x) {
return (Guchar)((x + (x >> 8) + 0x80) >> 8);
}
+template<typename T>
+inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
+
+
//------------------------------------------------------------------------
// SplashPipe
//------------------------------------------------------------------------
@@ -3182,6 +3186,332 @@ void Splash::compositeBackground(SplashColorPtr color) {
memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
}
+//#include <iostream> // FIXME
+GBool Splash::gouraudTriangleShadedFill(GfxState *gfxState, GfxGouraudTriangleShading *shading)
+{
+ // TODO :
+ // - sanity checking between Function and colorspace is not done
+ // - did not test anything but RGB colors
+ double xdbl[3] = {0., 0., 0.};
+ double ydbl[3] = {0., 0., 0.};
+ int x[3] = {0, 0, 0};
+ int y[3] = {0, 0, 0};
+ double xt=0.,xa=0.,yt=0.;
+ double ca=0.,ct=0.;
+
+ // triangle interpolation:
+ //
+ double scanLimitMapL[2] = {0., 0.};
+ double scanLimitMapR[2] = {0., 0.};
+ double scanColorMapL[2] = {0., 0.};
+ double scanColorMapR[2] = {0., 0.};
+ double scanColorMap[2] = {0., 0.};
+ int scanEdgeL[2] = { 0, 0 };
+ int scanEdgeR[2] = { 0, 0 };
+ bool hasFurtherSegment = false;
+
+ int X=0,Y=0;
+ int scanLineOff=0;
+ int bitmapOff=0;
+ int scanLimitR=0,scanLimitL=0,Yt=0;
+ int i=0,m=0;
+
+ int bitmapWidth = bitmap->getWidth();
+ SplashClip* clip = getClip();
+ SplashBitmap *blitTarget = bitmap;
+ SplashColorPtr bitmapData = bitmap->getDataPtr();
+ SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
+ SplashColorPtr cur=NULL;
+ SplashCoord* userToCanvasMatrix = getMatrix();
+ SplashColorMode bitmapMode = bitmap->getMode();
+ bool hasAlpha=(bitmapAlpha != NULL);
+ int rowSize = bitmap->getRowSize();
+ int colorComps=0;
+ switch (bitmapMode) {
+ case splashModeMono1:
+ return gFalse; // FIXME. This can't work yet.
+ break;
+ case splashModeMono8:
+ return gFalse; // FIXME I disable it just because it is not tested.
+ colorComps=1;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ colorComps=3;
+ break;
+ case splashModeXBGR8:
+ return gFalse; // FIXME I disable it just because it is not tested.
+ colorComps=3;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ return gFalse; // FIXME I disable it just because it is not tested.
+ colorComps=4;
+ break;
+#endif
+ }
+
+ SplashPipe pipe;
+ SplashColor cSrcVal;
+ pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha,
+ gFalse, gFalse);
+
+ // idea:
+ // 1. If pipe->noTransparency && !state->blendFunc
+ // -> blit directly into the drawing surface!
+ // -> disable alpha manually.
+ // 2. Otherwise:
+ // - blit also directly, but into an intermediate surface.
+ // Afterwards, blit the intermediate surface using the drawing pipeline.
+ // This is necessary because triangle elements can be on top of each
+ // other, so the complete shading needs to be drawn before opacity is
+ // applied.
+ // - the final step, is performed using a SplashPipe:
+ // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
+ // - invoke drawPixel(&pipe,X,Y,bNoClip);
+ bool bDirectBlit = pipe.noTransparency && !state->blendFunc;
+ if( !bDirectBlit ) {
+ blitTarget = new SplashBitmap(
+ bitmap->getWidth(),
+ bitmap->getHeight(),
+ bitmap->getRowPad(),
+ bitmap->getMode(),
+ true,
+ bitmap->getRowSize() >= 0 );
+ bitmapData = blitTarget->getDataPtr();
+ bitmapAlpha = blitTarget->getAlphaPtr();
+
+ // initialisation seems to be necessary:
+ int S = bitmap->getWidth() * bitmap->getHeight();
+ for( i = 0; i<S; ++i )
+ bitmapAlpha[i] = 0;
+ hasAlpha = true;
+ }
+
+ if( shading->isParameterized() ) {
+ double color[3];
+ double colorinterp;
+ GfxColor mappedColor;
+
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i,
+ xdbl+0, ydbl+0, color+0,
+ xdbl+1, ydbl+1, color+1,
+ xdbl+2, ydbl+2, color+2);
+ for( m =0; m<3; ++m ) {
+ xt= xdbl[m] * userToCanvasMatrix[0] + ydbl[m] * userToCanvasMatrix[2] + userToCanvasMatrix[4];
+ yt= xdbl[m] * userToCanvasMatrix[1] + ydbl[m] * userToCanvasMatrix[3] + userToCanvasMatrix[5];
+ xdbl[m] = xt;
+ ydbl[m] = yt;
+ // we operate on scanlines which are integer offsets into the
+ // raster image. The double offsets are of no use here.
+ x[m] = splashRound(xt);
+ y[m] = splashRound(yt);
+ }
+ // sort according to y coordinate to simplify sweep through scanlines:
+ // INSERTION SORT.
+ if( y[0] > y[1] ) {
+ Guswap( x[0], x[1] ); Guswap( y[0], y[1] ); Guswap( color[0], color[1] );
+ }
+ // first two are sorted .
+ assert( y[0] <= y[1] );
+ if( y[1] > y[2] ) {
+ int tmpX = x[2];
+ int tmpY = y[2];
+ double tmpC = color[2];
+ x[2] = x[1]; y[2] = y[1]; color[2] = color[1];
+
+ if( y[0] > tmpY ) {
+ x[1] = x[0]; y[1] = y[0]; color[1] = color[0];
+ x[0] = tmpX; y[0] = tmpY; color[0] = tmpC;
+ } else {
+ x[1] = tmpX; y[1] = tmpY; color[1] = tmpC;
+ }
+ }
+ // first three are sorted
+ assert( y[0] <= y[1] );
+ assert( y[1] <= y[2] );
+ /////
+
+ // this here is det( T ) == 0
+ // where T is the matrix to map to barycentric coordinates.
+ if( (x[0]-x[2]) * (y[1]-y[2])
+ - (x[1]-x[2]) * (y[0]-y[2]) == 0 )
+ continue; // degenerate triangle.
+
+ // this here initialises the scanline generation.
+ // We start with low Y coordinates and sweep up to the large Y
+ // coordinates.
+ //
+ // scanEdgeL[m] in {0,1,2} m=0,1
+ // scanEdgeR[m] in {0,1,2} m=0,1
+ //
+ // are the two edges between which scanlines are (currently)
+ // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
+ // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
+ //
+ scanEdgeL[0] = 0;
+ scanEdgeR[0] = 0;
+ if( y[0] == y[1] ) {
+ scanEdgeL[0] = 1;
+ scanEdgeL[1] = scanEdgeR[1] =2;
+
+ } else {
+ scanEdgeL[1] = 1; scanEdgeR[1] = 2;
+ }
+ assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
+ assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
+
+ // Ok. Now prepare the linear maps which map the y coordinate of
+ // the current scanline to the corresponding LEFT and RIGHT x
+ // coordinate (which define the scanline).
+ scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]] );
+ scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
+ scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+ xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];
+ xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];
+ if( xa > xt ) {
+ // I have "left" is to the right of "right".
+ // Exchange sides!
+ Guswap(scanEdgeL[0], scanEdgeR[0]);
+ Guswap(scanEdgeL[1], scanEdgeR[1]);
+ Guswap(scanLimitMapL[0], scanLimitMapR[0]);
+ Guswap(scanLimitMapL[1], scanLimitMapR[1]);
+ // FIXME I'm sure there is a more efficient way to check this.
+ }
+
+ //std::cout << "triangle " << i << "\t (" <<xdbl[0]<<", "<<ydbl[0] <<"); (" << xdbl[1] <<", "<<ydbl[1] <<"); (" << xdbl[2]<<", "<<ydbl[2]<<")\n" << " \t (" <<x[0]<<", "<<y[0] <<" [" << color[0] <<"]); (" << x[1] <<", "<<y[1] <<" [" << color[1] <<"]); (" << x[2]<<", "<<y[2]<<" [" << color[2] <<"])" << std::endl;
+ //std::cout << "scanEdgeL = " << scanEdgeL[0] << " " << scanEdgeL[1] << std::endl;
+ //std::cout << "scanEdgeR = " << scanEdgeR[0] << " " << scanEdgeR[1] << std::endl;
+
+ // Same game: we can linearly interpolate the color based on the
+ // current y coordinate (that's correct for triangle
+ // interpolation due to linearity. We could also have done it in
+ // barycentric coordinates, but that's slightly more involved)
+ scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]] );
+ scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
+ scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+
+
+ Y = y[0];
+ Yt= y[2];
+ hasFurtherSegment = (y[1] < y[2]);
+ scanLineOff = Y * rowSize;
+
+ for( Y = y[0]; Y <= y[2]; ++Y, scanLineOff+=rowSize ) {
+ if( hasFurtherSegment && Y == y[1] ) {
+ // SWEEP EVENT: we encountered the next segment.
+ //
+ // switch to next segment, either at left end or at right
+ // end:
+ if( scanEdgeL[1] == 1 ) {
+ scanEdgeL[0] = 1;
+ scanEdgeL[1] = 2;
+ scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]] );
+ scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
+
+ scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]] );
+ scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
+ //std::cout << "scanEdgeL = " << scanEdgeL[0] << " " << scanEdgeL[1] << std::endl;
+ } else if( scanEdgeR[1] == 1 ) {
+ scanEdgeR[0] = 1;
+ scanEdgeR[1] = 2;
+ scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+ scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+ scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+ //std::cout << "scanEdgeR = " << scanEdgeR[0] << " " << scanEdgeR[1] << std::endl;
+ }
+ assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
+ assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
+ hasFurtherSegment = false;
+ }
+
+ yt = Y;
+
+ xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
+ xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
+
+ ca = yt * scanColorMapL[0] + scanColorMapL[1];
+ ct = yt * scanColorMapR[0] + scanColorMapR[1];
+
+ scanLimitL=splashRound(xa);
+ scanLimitR=splashRound(xt);
+
+ // Ok. Now: init the color interpolation depending on the X
+ // coordinate inside of the current scanline:
+ scanColorMap[0] = (scanLimitR==scanLimitL) ? 0. : ( (ct - ca) / (scanLimitR - scanLimitL) );
+ scanColorMap[1] = ca - scanLimitL * scanColorMap[0];
+
+ //std::cout << "scanline y= "<< Y << " for x = " << scanLimitL << " (color " <<ca <<") to " << scanLimitR << "(color " << ct << ") [ " << xa << " = " << scanLimitMapL[0] << "*y + " << scanLimitMapL[1] <<" to " << xt << " = " << scanLimitMapR[0] << "*y + " << scanLimitMapR[1] << "] hasFurtherSegment = " << hasFurtherSegment << std::endl;
+
+ // handled by clipping:
+ // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
+ assert(scanLimitL <= scanLimitR || abs( scanLimitL-scanLimitR)<=2); // allow rounding inaccuracies
+ assert( scanLineOff == Y*rowSize );
+
+ colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];
+
+ bitmapOff = scanLineOff + scanLimitL * colorComps;
+ for( X = scanLimitL; X<=scanLimitR; ++X, colorinterp+=scanColorMap[0], bitmapOff += colorComps ) {
+ // FIXME : standard rectangular clipping can be done for a
+ // complete scanline which is faster
+ // --> see SplashClip and its methods
+ if( !clip->test(X,Y) )
+ continue;
+
+ assert( fabs( colorinterp - (scanColorMap[0] * X + scanColorMap[1]) ) < 1e-10 );
+
+ shading->getParameterizedColor(colorinterp, &mappedColor);
+
+ // FIXME : I am pretty sure this works only for RGB color
+ // spaces.
+ assert( bitmapOff == Y*rowSize + colorComps*X && scanLineOff == Y*rowSize);
+ cur = &bitmapData[bitmapOff];
+ for( m = 0; m<colorComps; ++m )
+ cur[m] = colToByte(mappedColor.c[m]);
+ // make the shading visible.
+ // Note that opacity is handled by the bDirectBlit stuff, see
+ // above for comments and below for implementation.
+ if(hasAlpha)
+ bitmapAlpha[ Y*bitmapWidth + X ] = 255;
+ }
+
+ }
+ }
+
+ } else {
+ return false;
+ }
+ if( !bDirectBlit ) {
+ // ok. Finalize the stuff by blitting the shading into the final
+ // geometry, this time respecting the rendering pipe.
+ int W = blitTarget->getWidth();
+ int H = blitTarget->getHeight();
+ cur = cSrcVal;
+
+ for( X = 0; X<W; ++X ) {
+ for( Y = 0; Y<H; ++Y ) {
+ if( !bitmapAlpha[ Y*bitmapWidth + X ] )
+ continue; // draw only parts of the shading!
+ bitmapOff = Y*rowSize + colorComps*X;
+
+ for( m = 0; m<colorComps; ++m )
+ cur[m] = bitmapData[bitmapOff+m];
+ drawPixel(&pipe, X,Y, true ); // no clipping - has already been done.
+ }
+ }
+
+ delete blitTarget; blitTarget=NULL;
+ }
+
+ return true;
+}
+
SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h) {
SplashColor pixel;
diff --git a/splash/Splash.h b/splash/Splash.h
index c9d57cc..bc3589b 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -28,6 +28,7 @@
#include "SplashTypes.h"
#include "SplashClip.h"
+#include "GfxState.h"
class Splash;
class SplashBitmap;
@@ -209,6 +210,10 @@ public:
int xDest, int yDest, int w, int h,
GBool noClip, GBool nonIsolated);
+ // Draw a triangle shading.
+ // Return true on success and false if the operation is not supported.
+ GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
+
// Composite this Splash object onto a background color. The
// background alpha is assumed to be 1.
void compositeBackground(SplashColorPtr color);
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index f983439..4094db9 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -50,6 +50,7 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
width = widthA;
height = heightA;
mode = modeA;
+ this->rowPad = rowPad;// just remember it.
switch (mode) {
case splashModeMono1:
if (width > 0) {
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index e741a91..e42a49d 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -56,6 +56,7 @@ public:
int getHeight() { return height; }
int getRowSize() { return rowSize; }
int getAlphaRowSize() { return width; }
+ int getRowPad() { return rowPad; }
SplashColorMode getMode() { return mode; }
SplashColorPtr getDataPtr() { return data; }
Guchar *getAlphaPtr() { return alpha; }
@@ -73,6 +74,7 @@ public:
private:
int width, height; // size of bitmap
+ int rowPad;
int rowSize; // size of one row of data, in bytes
// - negative for bottom-up bitmaps
SplashColorMode mode; // color mode
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler