Hi Albert!
I discussed this issue with Christian, and I have the following
suggestion now:
1. You should commit the bugfix part of Christian's patch in 0.15.0, so
that it will be part of 0.15.1. To clearify what I mean with the bugfix
part, I attach the bugfix diff I made against 0.15.0 once again. This
should already run over Your regtest, as far as I understand the several
mails here.
2. I take over the improvement part of the patch, where Christian
implements the gouraud shading in Splash. I made several suggestions to
Christian, i.e. that in the Splash library should be nor references to
the Gfx stuff from the poppler library. I will walk over the code and
redesign it a little bit next weekend. The base should be the same.
3. After You create the 0.15.1, I will make a new diff including my
improvements of bug 30436 and the improvements of Cjhristian and upload
that patch to bug 30436.
Is this okay for You (and for Christian, too), or does anyone have other
suggestions?
Best regards,
Thomas
Am 13.10.2010 20:56, schrieb Christian Feuersaenger:
Am 13.10.2010 20:34, schrieb Albert Astals Cid:
A Divendres, 8 d'octubre de 2010, Christian Feuersaenger va escriure:
Am 07.10.2010 23:17, schrieb Albert Astals Cid:
A Divendres, 1 d'octubre de 2010, Christian Feuersaenger va escriure:
Am 13.08.2010 23:43, schrieb Albert Astals Cid:
A Divendres, 30 de juliol de 2010, Albert Astals Cid va escriure:
A Dimarts, 27 de juliol de 2010, Christian Feuersaenger va
escriure:
Dear Albert,
thank you for your time to perform the regression tests!
I have fixed the bug; it was a data type problem.
Attached you find the fixed version.
The file
bugfix_shadingtype4567_incremental.patch
is relative to the version you used for the regression tests.
The file
bugfix_shadingtype4567_poppler0.14.patch
is relative to poppler-0.14.0-3-gb2427d0 .
Thank you for considering my contributions.
I've ran the regression test with the Splash outputdev and all
looks
ok, will have to run it over the cairo and ps outputdevs before
committing, though it'll take a while since next week i'm going
to be
away on holidays.
Bad news, this patch produces a regression in pdftops when
running over
the attached file, that is, the unpatched version creates a ps file
that is valid (gs will open it) and the patched version creates a ps
file that "crashes" gs.
Do you think you can have a look?
Albert
Dear Albert,
I am having difficulties to reproduce the problem. Here is what I
did:
1. try to view bug157704.pdf with the standard gs
--> crash (see below)
2. call pdftops (using system's version of libpoppler) and open gs on
the result
--> works without errors (see below)
3. call pdftops using the patched libpoppler and open gs on the
result
--> works without errors
4. call pdftops of poppler git version of 0.14 without my patch (I
have
not yet pulled the new version) and open gs on the result
--> works without errors
Do you have more detailed information about the crash? I fear I am
unable to do anything here...
Wops, works for me now too, i must have done something weird, sorry
:-/
I'll start the regression test again.
Albert
Ok, thanks for the notice!
Dear Albert,
thanks for the thorough testing.
The regression test was successful, though i have some questions i'd
like to
get answered before commiting the patch.
In Gfx::gouraudFillTriangle you removed the check for
contentIsHidden, why?
Hm. It seems as if the test should be there - I must have forgotten to
include it. Thank you for pointing it out! Could you add it right
before the fill statement?
Why do this if everything else in the line is intengers, what's the
point of
having a 2. there?
- color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
+ color01.c[i] = (color0->c[i] + color1->c[i]) / 2.;
You are right, that's certainly a waste of time. I should have
investigated the compiler warnings; sorry about that. Please feel free
to remove the double suffixes.
Best regards
Christian
Here are the detailed outputs for your reference:
for (1):
[ludewich] tmp>>gs bug157704.pdf
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for
details.
Processing pages 1 through 1.
Page 1
Error: /unknownerror in --run--
Operand stack:
--dict:6/15(L)--
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval--
--nostringval-- 2 %stopped_push --nostringval--
--nostringval-- --nostringval-- false 1 %stopped_push 1878
1 3 %oparray_pop 1877 1 3 %oparray_pop 1861 1 3
%oparray_pop --nostringval-- --nostringval-- 2 1 1
--nostringval-- %for_pos_int_continue --nostringval--
--nostringval-- false 1 %stopped_push --nostringval--
--nostringval-- --nostringval-- %array_continue --nostringval--
false 1 %stopped_push --nostringval-- %loop_continue
--nostringval--
Dictionary stack:
--dict:1153/1684(ro)(G)-- --dict:1/20(G)--
--dict:75/200(L)--
--dict:75/200(L)-- --dict:108/127(ro)(G)--
--dict:288/300(ro)(G)--
--dict:22/25(L)-- --dict:6/8(L)-- --dict:21/40(L)--
--dict:3/5(L)-- Current allocation mode is local
Last OS error: 11
GPL Ghostscript 8.71: Unrecoverable error, exit code 1
for (2):
[ludewich] tmp>>pdftops -?
pdftops version 0.12.4
[ludewich] tmp>>time pdftops bug157704.pdf
real 0m14.925s
user 0m13.900s
sys 0m0.140s
[ludewich] tmp>>gs bug157704.ps
GPL Ghostscript 8.71 (2010-02-10)
[ ALL OK ]
for (3):
[ludewich] poppler>>git describe # (with my patch)
poppler-0.14.0-18-g821bc2a
[ludewich] tmp>>time ~/code/xpdf/poppler/utils/pdftops bug157704.pdf
real 0m2.785s
user 0m2.540s
sys 0m0.130s
[ludewich] tmp>>gs bug157704.ps
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for
details.
[ ALL OK ]
for (4):
[ludewich] poppler>>git describe # (without my patch using
poppler-0.14
) poppler-0.14.0-3-gb2427d0
[ludewich] tmp>>time ~/code/xpdf/poppler/utils/pdftops bug157704.pdf
real 0m15.844s
user 0m13.820s
sys 0m0.140s
[ludewich] tmp>>gs bug157704.ps
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for
details.
[ ALL OK ]
Albert
Best regards
Christian
Am 25.07.2010 16:56, schrieb Albert Astals Cid:
A Dissabte, 3 de juliol de 2010, Christian Feuersaenger va
escriure:
Hello Albert,
Hi
I've managed to fix a bug in the Shading Type 6/7 (Coons&
cubic
tensor patches) implementation.
The bugfix is small and stable (in my eyes); the poppler-0.14
branch doesn't implement support for parameterized patch
shadings.
I modified the existing implementation accordingly with
relatively
few changes.
Attached you find the patch file and the updated test.pdf to see
the improvement.
The file type4567patch.... also includes the patch of my
previous
mail (they only share the same refinement threshold).
The patch should work relative to poppler-0.14.0-3-gb2427d0 .
This patch causes a regression in the attached pdf (the blue area
disappears)
Albert
Best regards
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
_______________________________________________
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/Gfx.cc b/poppler/Gfx.cc
index 7552fed..079706e 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -32,6 +32,7 @@
// Copyright (C) 2009 William Bader <[email protected]>
// Copyright (C) 2009, 2010 David Benjamin <[email protected]>
// Copyright (C) 2010 Nils Höglund <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -99,18 +100,26 @@
#define radialColorDelta (dblToCol(1 / 256.0))
// Max recursive depth for a Gouraud triangle shading fill.
+//
+// Triangles will be split at most gouraudMaxDepth times (each time into 4
+// smaller ones). That makes pow(4,gouraudMaxDepth) many triangles for
+// every triangle.
#define gouraudMaxDepth 6
// Max delta allowed in any color component for a Gouraud triangle
// shading fill.
-#define gouraudColorDelta (dblToCol(1 / 256.0))
+#define gouraudColorDelta (dblToCol(3. / 256.0))
+
+// Gouraud triangle: if the three color parameters differ by at more than this
percend of
+// the total color parameter range, the triangle will be refined
+#define gouraudParameterizedColorDelta 5e-3
// Max recursive depth for a patch mesh shading fill.
#define patchMaxDepth 6
// Max delta allowed in any color component for a patch mesh shading
// fill.
-#define patchColorDelta (dblToCol(1 / 256.0))
+#define patchColorDelta (dblToCol((3. / 256.0)))
//------------------------------------------------------------------------
// Operator table
@@ -487,7 +496,7 @@ GBool GfxResources::lookupGState(char *name, Object *obj) {
if (!obj->isRef())
return gTrue;
-
+
const Ref ref = obj->getRef();
if (!gStateCache.lookup(ref, obj)->isNull())
return gTrue;
@@ -716,7 +725,7 @@ void Gfx::go(GBool topLevel) {
data_p = new ProfileData();
hash->add (cmd_g, data_p);
}
-
+
data_p->addElement(timer.getElapsed ());
}
}
@@ -2389,14 +2398,14 @@ void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
colors2[2] = colorM0;
colors2[3] = colorMM;
doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
-
+
// lower-left sub-rectangle
colors2[0] = color0M;
colors2[1] = colors[1];
colors2[2] = colorMM;
colors2[3] = colorM1;
doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
-
+
// upper-right sub-rectangle
colors2[0] = colorM0;
colors2[1] = colorMM;
@@ -2594,10 +2603,10 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
}
shading->getColor(tt, &color1);
if (isSameGfxColor(color1, color0, nComps, axialColorDelta)) {
- // in these two if what we guarantee is that if we are skipping lots
of
+ // in these two if what we guarantee is that if we are skipping lots
of
// positions because the colors are the same, we still create a region
// with vertexs passing by bboxIntersections[1] and
bboxIntersections[2]
- // otherwise we can have empty regions that should really be painted
+ // otherwise we can have empty regions that should really be painted
// like happened in bug 19896
// What we do to ensure that we pass a line through this points
// is making sure use the exact bboxIntersections[] value as one of
the used ta[] values
@@ -3097,22 +3106,62 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
double x0, y0, x1, y1, x2, y2;
- GfxColor color0, color1, color2;
int i;
- for (i = 0; i < shading->getNTriangles(); ++i) {
- shading->getTriangle(i, &x0, &y0, &color0,
- &x1, &y1, &color1,
- &x2, &y2, &color2);
- gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
- shading->getColorSpace()->getNComps(), 0);
- }
+ // preallocate a path.
+ // Overwriting the coordinates saves about 10% at runtime for larger
+ // shadings.
+ state->moveTo(0., 0.);
+ state->lineTo(1., 0.);
+ state->lineTo(0., 1.);
+ state->closePath();
+
+ GfxState::ReusablePathIterator *reusablePath = state->getReusablePath();
+
+// Idea:
+// - state->getReferenceToReusablePath()
+// the return value has the setX/setY methods, the standard GfxState doesn't
+// - state should not delete the current path until
+// - state->freeReusablePath()
+// but that's overhead and I am not highly motivated.
+//
+
+ if (shading->isParameterized()) {
+ // work with parameterized values:
+ double color0, color1, color2;
+ // a relative threshold:
+ const double refineColorThreshold = gouraudParameterizedColorDelta *
+ (shading->getParameterDomainMax() -
shading->getParameterDomainMin());
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ gouraudFillTriangle(x0, y0, color0, x1, y1, color1, x2, y2, color2,
refineColorThreshold, 0, shading, reusablePath);
+ }
+
+ } else {
+ // this always produces output -- even for parameterized ranges.
+ // But it ignores the parameterized color map (the function).
+ //
+ // Note that using this code in for parameterized shadings might be
+ // correct in circumstances (namely if the function is linear in the
actual
+ // triangle), but in general, it will simply be wrong.
+ GfxColor color0, color1, color2;
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
shading->getColorSpace()->getNComps(), 0, reusablePath);
+ }
+ }
+
+ delete reusablePath;
}
void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
double x1, double y1, GfxColor *color1,
double x2, double y2, GfxColor *color2,
- int nComps, int depth) {
+ int nComps, int depth,
GfxState::ReusablePathIterator* path) {
double x01, y01, x12, y12, x20, y20;
GfxColor color01, color12, color20;
int i;
@@ -3123,16 +3172,18 @@ void Gfx::gouraudFillTriangle(double x0, double y0,
GfxColor *color0,
break;
}
}
- if (i == nComps || depth == gouraudMaxDepth) {
+ if (i == nComps || depth == gouraudMaxDepth) {
+
state->setFillColor(color0);
out->updateFillColor(state);
- state->moveTo(x0, y0);
- state->lineTo(x1, y1);
- state->lineTo(x2, y2);
- state->closePath();
- if (!contentIsHidden())
- out->fill(state);
- state->clearPath();
+
+ path->reset(); assert(!path->isEnd());
+ path->setCoord(x0,y0); path->next(); assert(!path->isEnd());
+ path->setCoord(x1,y1); path->next(); assert(!path->isEnd());
+ path->setCoord(x2,y2); path->next(); assert(!path->isEnd());
+ path->setCoord(x0,y0); path->next(); assert( path->isEnd());
+
+ out->fill(state);
} else {
x01 = 0.5 * (x0 + x1);
y01 = 0.5 * (y0 + y1);
@@ -3140,21 +3191,76 @@ void Gfx::gouraudFillTriangle(double x0, double y0,
GfxColor *color0,
y12 = 0.5 * (y1 + y2);
x20 = 0.5 * (x2 + x0);
y20 = 0.5 * (y2 + y0);
- //~ if the shading has a Function, this should interpolate on the
- //~ function parameter, not on the color components
for (i = 0; i < nComps; ++i) {
- color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
- color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
- color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
+ color01.c[i] = (color0->c[i] + color1->c[i]) / 2.;
+ color12.c[i] = (color1->c[i] + color2->c[i]) / 2.;
+ color20.c[i] = (color2->c[i] + color0->c[i]) / 2.;
}
gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
- x20, y20, &color20, nComps, depth + 1);
+ x20, y20, &color20, nComps, depth + 1, path);
gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
- x12, y12, &color12, nComps, depth + 1);
+ x12, y12, &color12, nComps, depth + 1, path);
gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
- x20, y20, &color20, nComps, depth + 1);
+ x20, y20, &color20, nComps, depth + 1, path);
gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
- x2, y2, color2, nComps, depth + 1);
+ x2, y2, color2, nComps, depth + 1, path);
+ }
+}
+
+void Gfx::gouraudFillTriangle(double x0, double y0, double color0,
+ double x1, double y1, double color1,
+ double x2, double y2, double color2,
+ double refineColorThreshold, int depth,
GfxGouraudTriangleShading* shading, GfxState::ReusablePathIterator* path ) {
+ const double meanColor = (color0 + color1 + color2) / 3;
+
+ const bool isFineEnough =
+ fabs(color0 - meanColor) < refineColorThreshold &&
+ fabs(color1 - meanColor) < refineColorThreshold &&
+ fabs(color2 - meanColor) < refineColorThreshold;
+
+ if (isFineEnough || depth == gouraudMaxDepth) {
+ GfxColor color;
+
+ shading->getParameterizedColor(meanColor, &color);
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+
+ path->reset(); assert(!path->isEnd());
+ path->setCoord(x0,y0); path->next(); assert(!path->isEnd());
+ path->setCoord(x1,y1); path->next(); assert(!path->isEnd());
+ path->setCoord(x2,y2); path->next(); assert(!path->isEnd());
+ path->setCoord(x0,y0); path->next(); assert( path->isEnd());
+
+ out->fill(state);
+ } else {
+ double x01, y01, x12, y12, x20, y20;
+ double color01, color12, color20;
+ x01 = 0.5 * (x0 + x1);
+ y01 = 0.5 * (y0 + y1);
+ x12 = 0.5 * (x1 + x2);
+ y12 = 0.5 * (y1 + y2);
+ x20 = 0.5 * (x2 + x0);
+ y20 = 0.5 * (y2 + y0);
+ color01 = (color0 + color1) / 2.;
+ color12 = (color1 + color2) / 2.;
+ color20 = (color2 + color0) / 2.;
+ ++depth;
+ gouraudFillTriangle(x0, y0, color0,
+ x01, y01, color01,
+ x20, y20, color20,
+ refineColorThreshold, depth, shading, path);
+ gouraudFillTriangle(x01, y01, color01,
+ x1, y1, color1,
+ x12, y12, color12,
+ refineColorThreshold, depth, shading, path);
+ gouraudFillTriangle(x01, y01, color01,
+ x12, y12, color12,
+ x20, y20, color20,
+ refineColorThreshold, depth, shading, path);
+ gouraudFillTriangle(x20, y20, color20,
+ x12, y12, color12,
+ x2, y2, color2,
+ refineColorThreshold, depth, shading, path);
}
}
@@ -3170,32 +3276,72 @@ void Gfx::doPatchMeshShFill(GfxPatchMeshShading
*shading) {
} else {
start = 0;
}
+ /*
+ * Parameterized shadings take one parameter [t_0,t_e]
+ * and map it into the color space.
+ *
+ * Consequently, all color values are stored as doubles.
+ *
+ * These color values are interpreted as parameters for parameterized
+ * shadings and as colorspace entities otherwise.
+ *
+ * The only difference is that color space entities are stored into
+ * DOUBLE arrays, not into arrays of type GfxColorComp.
+ */
+ int colorComps = shading->getColorSpace()->getNComps();
+ double refineColorThreshold;
+ if( shading->isParameterized() ) {
+ refineColorThreshold = gouraudParameterizedColorDelta *
+ (shading->getParameterDomainMax() -
shading->getParameterDomainMin());
+
+ } else {
+ refineColorThreshold = patchColorDelta;
+ }
+
for (i = 0; i < shading->getNPatches(); ++i) {
- fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
- start);
+ fillPatch(shading->getPatch(i),
+ colorComps,
+ shading->isParameterized() ? 1 : colorComps,
+ refineColorThreshold,
+ start,
+ shading);
}
}
-void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
- GfxPatch patch00, patch01, patch10, patch11;
- double xx[4][8], yy[4][8];
- double xxm, yym;
- int i;
-
- for (i = 0; i < nComps; ++i) {
- if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
- > patchColorDelta ||
- abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
- > patchColorDelta ||
- abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
- > patchColorDelta ||
- abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
- > patchColorDelta) {
+void Gfx::fillPatch(GfxPatch *patch, int colorComps, int patchColorComps,
double refineColorThreshold, int depth, GfxPatchMeshShading *shading ) {
+ GfxPatch patch00, patch01, patch10, patch11;
+ double xx[4][8], yy[4][8];
+ double xxm, yym;
+ int i;
+
+ for (i = 0; i < patchColorComps; ++i) {
+ // these comparisons are done in double arithmetics.
+ //
+ // For non-parameterized shadings, they are done in color space
+ // components.
+ if (fabs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
+ > refineColorThreshold ||
+ fabs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
+ > refineColorThreshold ||
+ fabs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
+ > refineColorThreshold ||
+ fabs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
+ > refineColorThreshold) {
break;
}
}
- if (i == nComps || depth == patchMaxDepth) {
- state->setFillColor(&patch->color[0][0]);
+ if (i == patchColorComps || depth == patchMaxDepth) {
+ GfxColor flatColor;
+ if( shading->isParameterized() ) {
+ shading->getParameterizedColor( patch->color[0][0].c[0],
&flatColor );
+
+ } else {
+ for( i = 0; i<colorComps; ++i ) {
+ // simply cast to the desired type; that's all what is
needed.
+ flatColor.c[i] = GfxColorComp(patch->color[0][0].c[i]);
+ }
+ }
+ state->setFillColor(&flatColor);
out->updateFillColor(state);
state->moveTo(patch->x[0][0], patch->y[0][0]);
state->curveTo(patch->x[0][1], patch->y[0][1],
@@ -3273,9 +3419,7 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int
depth) {
patch11.x[3][i-4] = xx[3][i];
patch11.y[3][i-4] = yy[3][i];
}
- //~ if the shading has a Function, this should interpolate on the
- //~ function parameter, not on the color components
- for (i = 0; i < nComps; ++i) {
+ for (i = 0; i < patchColorComps; ++i) {
patch00.color[0][0].c[i] = patch->color[0][0].c[i];
patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
patch->color[0][1].c[i]) / 2;
@@ -3298,10 +3442,10 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int
depth) {
patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
}
- fillPatch(&patch00, nComps, depth + 1);
- fillPatch(&patch10, nComps, depth + 1);
- fillPatch(&patch01, nComps, depth + 1);
- fillPatch(&patch11, nComps, depth + 1);
+ fillPatch(&patch00, colorComps, patchColorComps, refineColorThreshold,
depth + 1, shading);
+ fillPatch(&patch10, colorComps, patchColorComps, refineColorThreshold,
depth + 1, shading);
+ fillPatch(&patch01, colorComps, patchColorComps, refineColorThreshold,
depth + 1, shading);
+ fillPatch(&patch11, colorComps, patchColorComps, refineColorThreshold,
depth + 1, shading);
}
}
@@ -3399,21 +3543,21 @@ void Gfx::opSetTextLeading(Object args[], int numArgs) {
void Gfx::opSetTextRender(Object args[], int numArgs) {
int rm = state->getRender();
state->setRender(args[0].getInt());
- if ((args[0].getInt() & 4) && textHaveCSPattern && drawText) {
- GBool needFill = out->deviceHasTextClip(state);
- out->endTextObject(state);
- if (needFill) {
- doPatternFill(gTrue);
- }
- out->restoreState(state);
- out->beginTextObject(state);
- out->updateTextMat(state);
- out->updateTextPos(state);
- textHaveCSPattern = gFalse;
- } else if ((rm & 4) && !(args[0].getInt() & 4) &&
out->supportTextCSPattern(state) && drawText) {
- out->beginTextObject(state);
- textHaveCSPattern = gTrue;
- }
+ if ((args[0].getInt() & 4) && textHaveCSPattern && drawText) {
+ GBool needFill = out->deviceHasTextClip(state);
+ out->endTextObject(state);
+ if (needFill) {
+ doPatternFill(gTrue);
+ }
+ out->restoreState(state);
+ out->beginTextObject(state);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ textHaveCSPattern = gFalse;
+ } else if ((rm & 4) && !(args[0].getInt() & 4) &&
out->supportTextCSPattern(state) && drawText) {
+ out->beginTextObject(state);
+ textHaveCSPattern = gTrue;
+ }
out->updateRender(state);
}
@@ -4379,7 +4523,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double
*matrix, double *bbox,
// draw the form
display(str, gFalse);
-
+
if (stateBefore != state) {
if (state->isParentState(stateBefore)) {
error(-1, "There's a form with more q than Q, trying to fix");
@@ -4432,7 +4576,7 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
// display the image
if (str) {
doImage(NULL, str, gTrue);
-
+
// skip 'EI' tag
c1 = str->getUndecodedStream()->getChar();
c2 = str->getUndecodedStream()->getChar();
@@ -4559,7 +4703,7 @@ GBool Gfx::contentIsHidden() {
void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
// push a new stack entry
pushMarkedContent();
-
+
OCGs *contentConfig = catalog->getOptContentConfig();
char* name0 = args[0].getName();
if ( strncmp( name0, "OC", 2) == 0 && contentConfig) {
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index cb42b5c..86dc03c 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -20,6 +20,7 @@
// Copyright (C) 2009 Albert Astals Cid <[email protected]>
// Copyright (C) 2009, 2010 Thomas Freitag <[email protected]>
// Copyright (C) 2010 David Benjamin <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -299,9 +300,13 @@ private:
void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
double x1, double y1, GfxColor *color1,
double x2, double y2, GfxColor *color2,
- int nComps, int depth);
- void doPatchMeshShFill(GfxPatchMeshShading *shading);
- void fillPatch(GfxPatch *patch, int nComps, int depth);
+ int nComps, int depth,
GfxState::ReusablePathIterator* path);
+ void gouraudFillTriangle(double x0, double y0, double color0,
+ double x1, double y1, double color1,
+ double x2, double y2, double color2,
+ double refineColorThreshold, int depth,
GfxGouraudTriangleShading* shading, GfxState::ReusablePathIterator* path);
+ void doPatchMeshShFill(GfxPatchMeshShading *shading);
+ void fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double
refineColorThreshold, int depth, GfxPatchMeshShading *shading );
void doEndPath();
// path clipping operators
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 59a8863..381a09e 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -21,6 +21,7 @@
// Copyright (C) 2009 Thomas Freitag <[email protected]>
// Copyright (C) 2009 Christian Persch <[email protected]>
// Copyright (C) 2010 PaweÅ Wiejacha <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -672,9 +673,9 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB
*rgb) {
r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
- rgb->r = dblToCol(sqrt(clip01(r * kr)));
- rgb->g = dblToCol(sqrt(clip01(g * kg)));
- rgb->b = dblToCol(sqrt(clip01(b * kb)));
+ rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+ rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+ rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
}
void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -908,12 +909,12 @@ void GfxCalRGBColorSpace::getXYZ(GfxColor *color,
double *pX, double *pY, double *pZ) {
double A, B, C;
- A = pow(colToDbl(color->c[0]), gammaR);
- B = pow(colToDbl(color->c[1]), gammaG);
- C = pow(colToDbl(color->c[2]), gammaB);
- *pX = mat[0] * A + mat[3] * B + mat[6] * C;
- *pY = mat[1] * A + mat[4] * B + mat[7] * C;
- *pZ = mat[2] * A + mat[5] * B + mat[8] * C;
+ A = colToDbl(color->c[0]);
+ B = colToDbl(color->c[1]);
+ C = colToDbl(color->c[2]);
+ *pX = mat[0]*pow(A,gammaR)+mat[3]*pow(B,gammaG)+mat[6]*pow(C,gammaB);
+ *pY = mat[1]*pow(A,gammaR)+mat[4]*pow(B,gammaG)+mat[7]*pow(C,gammaB);
+ *pZ = mat[2]*pow(A,gammaR)+mat[5]*pow(B,gammaG)+mat[8]*pow(C,gammaB);
}
void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
@@ -964,9 +965,9 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB
*rgb) {
r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
- rgb->r = dblToCol(sqrt(clip01(r)));
- rgb->g = dblToCol(sqrt(clip01(g)));
- rgb->b = dblToCol(sqrt(clip01(b)));
+ rgb->r = dblToCol(pow(clip01(r), 0.5));
+ rgb->g = dblToCol(pow(clip01(g), 0.5));
+ rgb->b = dblToCol(pow(clip01(b), 0.5));
}
void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -1245,9 +1246,9 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB
*rgb) {
r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
- rgb->r = dblToCol(sqrt(clip01(r * kr)));
- rgb->g = dblToCol(sqrt(clip01(g * kg)));
- rgb->b = dblToCol(sqrt(clip01(b * kb)));
+ rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+ rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+ rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
}
void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -3350,6 +3351,8 @@ void GfxGouraudTriangleShading::getTriangle(
double out[gfxColorMaxComps];
int v, j;
+ assert(!isParameterized());
+
v = triangles[i][0];
*x0 = vertices[v].x;
*y0 = vertices[v].y;
@@ -3394,6 +3397,40 @@ void GfxGouraudTriangleShading::getTriangle(
}
}
+void GfxGouraudTriangleShading::getParameterizedColor(double t, GfxColor
*color) {
+ double out[gfxColorMaxComps];
+
+ for (int j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&t, &out[j]);
+ }
+ for (int 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;
+
+ assert(isParameterized());
+
+ 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
//------------------------------------------------------------------------
@@ -3451,7 +3488,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int
typeA, Dict *dict,
Guint flag;
double x[16], y[16];
Guint xi, yi;
- GfxColorComp c[4][gfxColorMaxComps];
+ double c[4][gfxColorMaxComps];
Guint ci[4];
GfxShadingBitBuf *bitBuf;
Object obj1, obj2;
@@ -3573,7 +3610,14 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int
typeA, Dict *dict,
if (!bitBuf->getBits(compBits, &ci[j])) {
break;
}
- c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
+ // store it into a double array.
+ // That's necessary for parameterized shadings....
+ c[i][j] = cMin[j] + cMul[j] * (double)ci[j];
+ if( nFuncsA == 0 ) {
+ // ... and colorspace values can also be stored into doubles.
+ // They will be casted later.
+ c[i][j] = dblToCol(c[i][j]);
+ }
}
if (j < nComps) {
break;
@@ -3950,6 +3994,17 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int
typeA, Dict *dict,
return NULL;
}
+void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+
+ for (int j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&t, &out[j]);
+ }
+ for (int j = 0; j < gfxColorMaxComps; ++j) {
+ color->c[j] = dblToCol(out[j]);
+ }
+}
+
GfxShading *GfxPatchMeshShading::copy() {
return new GfxPatchMeshShading(this);
}
@@ -4507,6 +4562,52 @@ void GfxPath::offset(double dx, double dy) {
// GfxState
//------------------------------------------------------------------------
+GfxState::ReusablePathIterator::ReusablePathIterator( GfxPath *path )
+ :
+ path(path),
+ subPathOff(0),
+ coordOff(0),
+ numCoords(0),
+ curSubPath(NULL)
+{
+ if( path->getNumSubpaths() ) {
+ curSubPath = path->getSubpath(subPathOff);
+ numCoords = curSubPath->getNumPoints();
+ }
+}
+
+bool
+GfxState::ReusablePathIterator::isEnd() {
+ return coordOff >= numCoords;
+}
+
+void
+GfxState::ReusablePathIterator::next() {
+ ++coordOff;
+ if( coordOff == numCoords ) {
+ ++subPathOff;
+ if( subPathOff < path->getNumSubpaths() ) {
+ coordOff=0;
+ curSubPath = path->getSubpath(subPathOff);
+ numCoords = curSubPath->getNumPoints();
+ }
+ }
+}
+
+void
+GfxState::ReusablePathIterator::setCoord( double x, double y ) {
+ curSubPath->setX( coordOff, x );
+ curSubPath->setY( coordOff, y );
+}
+
+void
+GfxState::ReusablePathIterator::reset() {
+ coordOff = 0;
+ subPathOff = 0;
+ curSubPath = path->getSubpath(0);
+ numCoords = curSubPath->getNumPoints();
+}
+
GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
int rotateA, GBool upsideDown) {
double kx, ky;
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 900214d..0d259da 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -18,6 +18,7 @@
// Copyright (C) 2006 Carlos Garcia Campos <[email protected]>
// Copyright (C) 2009 Koji Otani <[email protected]>
// Copyright (C) 2009, 2010 Albert Astals Cid <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -35,6 +36,8 @@
#include "Object.h"
#include "Function.h"
+#include <assert.h>
+
class Array;
class Gfx;
class GfxFont;
@@ -876,10 +879,37 @@ public:
virtual GfxShading *copy();
int getNTriangles() { return nTriangles; }
- void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
- double *x1, double *y1, GfxColor *color1,
- double *x2, double *y2, GfxColor *color2);
-
+
+ bool isParameterized() const { return nFuncs > 0; }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMin() const { assert(isParameterized()); return
funcs[0]->getDomainMin(0); }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMax() const { assert(isParameterized()); 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;
@@ -894,10 +924,32 @@ private:
// GfxPatchMeshShading
//------------------------------------------------------------------------
-struct GfxPatch {
- double x[4][4];
- double y[4][4];
- GfxColor color[2][2];
+/**
+ * A tensor product cubic bezier patch consisting of 4x4 points and 4 color
+ * values.
+ *
+ * See the Shading Type 7 specifications. Note that Shading Type 6 is also
+ * represented using GfxPatch.
+ */
+ struct GfxPatch {
+ /**
+ * Represents a single color value for the patch.
+ */
+ struct ColorValue {
+ /**
+ * For parameterized patches, only element 0 is valid; it contains
+ * the single parameter.
+ *
+ * For non-parameterized patches, c contains all color components
+ * as decoded from the input stream. In this case, you will need to
+ * use dblToCol() before assigning them to GfxColor.
+ */
+ double c[gfxColorMaxComps];
+ };
+
+ double x[4][4];
+ double y[4][4];
+ ColorValue color[2][2];
};
class GfxPatchMeshShading: public GfxShading {
@@ -915,6 +967,20 @@ public:
int getNPatches() { return nPatches; }
GfxPatch *getPatch(int i) { return &patches[i]; }
+ bool isParameterized() const { return nFuncs > 0; }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMin() const { assert(isParameterized()); return
funcs[0]->getDomainMin(0); }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMax() const { assert(isParameterized()); return
funcs[0]->getDomainMax(0); }
+
+ void getParameterizedColor(double t, GfxColor *color);
+
private:
GfxPatch *patches;
@@ -1004,6 +1070,9 @@ public:
double getY(int i) { return y[i]; }
GBool getCurve(int i) { return curve[i]; }
+ void setX(int i, double a) { x[i] = a; }
+ void setY(int i, double a) { y[i] = a; }
+
// Get last point.
double getLastX() { return x[n-1]; }
double getLastY() { return y[n-1]; }
@@ -1098,6 +1167,60 @@ private:
class GfxState {
public:
+ /**
+ * When GfxState::getReusablePath() is invoked, the currently active
+ * path is taken per reference and its coordinates can be re-edited.
+ *
+ * A ReusablePathIterator is intented to reduce overhead when the same
+ * path type is used a lot of times, only with different coordinates. It
+ * allows just to update the coordinates (occuring in the same order as
+ * in the original path).
+ */
+ class ReusablePathIterator {
+ GfxPath *path;
+ int subPathOff;
+
+ int coordOff;
+ int numCoords;
+
+ GfxSubpath *curSubPath;
+ public:
+ /**
+ * Creates the ReusablePathIterator. This should only be done from
+ * GfxState::getReusablePath().
+ *
+ * @param path the path as it is used so far. Changing this path,
+ * deleting it or starting a new path from scratch will most likely
+ * invalidate the iterator (and may cause serious problems). Make
+ * sure the path's memory structure is not changed during the
+ * lifetime of the ReusablePathIterator.
+ */
+ ReusablePathIterator( GfxPath* path );
+
+ /**
+ * Returns true if and only if the current iterator position is
+ * beyond the last valid point.
+ *
+ * A call to setCoord() will be undefined.
+ */
+ bool isEnd();
+
+ /**
+ * Advances the iterator.
+ */
+ void next();
+
+ /**
+ * Updates the coordinates associated to the current iterator
+ * position.
+ */
+ void setCoord( double x, double y );
+
+ /**
+ * Resets the iterator.
+ */
+ void reset();
+ };
// Construct a default GfxState, for a device with resolution <hDPI>
// x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
@@ -1276,6 +1399,7 @@ public:
// Misc
GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
+ ReusablePathIterator *getReusablePath() { return new
ReusablePathIterator(path); }
private:
double hDPI, vDPI; // resolution
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler