poppler/Gfx.cc | 214 +++++++++++++++++++++++++++++++++++++++++----------- poppler/Gfx.h | 9 +- poppler/GfxState.cc | 96 ++++++++++++++++++++++- poppler/GfxState.h | 127 ++++++++++++++++++++++++++++++ poppler/Page.cc | 19 ++-- 5 files changed, 409 insertions(+), 56 deletions(-)
New commits: commit b604a008a2a379a21e5fdfa0799886f80d893a08 Author: Christian Feuersänger <[email protected]> Date: Thu Oct 14 23:56:36 2010 +0100 Improve rendering of Shading Type 6 and 7 diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index 4f4510a..12c0bd2 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 @@ -3098,22 +3107,52 @@ 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 (speed improvements) + state->moveTo(0., 0.); + state->lineTo(1., 0.); + state->lineTo(0., 1.); + state->closePath(); + + GfxState::ReusablePathIterator *reusablePath = state->getReusablePath(); + + 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; @@ -3127,13 +3166,15 @@ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0, 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(); + + 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()); + if (!contentIsHidden()) out->fill(state); - state->clearPath(); } else { x01 = 0.5 * (x0 + x1); y01 = 0.5 * (y0 + y1); @@ -3141,21 +3182,74 @@ 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; } 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()); + + if (!contentIsHidden()) + out->fill(state); + } else { + const double x01 = 0.5 * (x0 + x1); + const double y01 = 0.5 * (y0 + y1); + const double x12 = 0.5 * (x1 + x2); + const double y12 = 0.5 * (y1 + y2); + const double x20 = 0.5 * (x2 + x0); + const double y20 = 0.5 * (y2 + y0); + const double color01 = (color0 + color1) / 2.; + const double color12 = (color1 + color2) / 2.; + const double 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); } } @@ -3171,32 +3265,68 @@ 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. + */ + const 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) { + +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 < 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) { + 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], @@ -3274,9 +3404,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; @@ -3299,10 +3427,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); } } diff --git a/poppler/Gfx.h b/poppler/Gfx.h index cb42b5c..adabe7d 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); + 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 nComps, int depth); + 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..c750d2d 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 @@ -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,39 @@ 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 +3487,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 +3609,12 @@ 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]); + 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 +3991,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); } @@ -4506,6 +4558,46 @@ 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() const { + 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) { diff --git a/poppler/GfxState.h b/poppler/GfxState.h index 900214d..b425b4a 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; } + + 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 //------------------------------------------------------------------------ +/** + * 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]; - GfxColor color[2][2]; + 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,61 @@ 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 { + 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() const; + + /** + * 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(); + private: + GfxPath *path; + int subPathOff; + + int coordOff; + int numCoords; + + GfxSubpath *curSubPath; + }; // Construct a default GfxState, for a device with resolution <hDPI> // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and @@ -1276,6 +1400,7 @@ public: // Misc GBool parseBlendMode(Object *obj, GfxBlendMode *mode); + ReusablePathIterator *getReusablePath() { return new ReusablePathIterator(path); } private: double hDPI, vDPI; // resolution commit c6bb63b31c268e4e842532e6839b15edb31cf25c Author: Albert Astals Cid <[email protected]> Date: Thu Oct 14 23:33:13 2010 +0100 Only clip boxes to mediabox if we are at the page level Fixes bug 30784 diff --git a/poppler/Page.cc b/poppler/Page.cc index 3c2d880..caf233f 100644 --- a/poppler/Page.cc +++ b/poppler/Page.cc @@ -15,7 +15,7 @@ // // Copyright (C) 2005 Kristian Høgsberg <[email protected]> // Copyright (C) 2005 Jeff Muizelaar <[email protected]> -// Copyright (C) 2005-2009 Albert Astals Cid <[email protected]> +// Copyright (C) 2005-2010 Albert Astals Cid <[email protected]> // Copyright (C) 2006-2008 Pino Toscano <[email protected]> // Copyright (C) 2006 Nickolay V. Shmyrev <[email protected]> // Copyright (C) 2006 Scott Turner <[email protected]> @@ -91,6 +91,7 @@ void PDFRectangle::clipTo(PDFRectangle *rect) { PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { Object obj1; PDFRectangle mBox; + const GBool isPage = dict->is("Page"); // get old/default values if (attrs) { @@ -124,8 +125,8 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { if (!haveCropBox) { cropBox = mediaBox; } - else - { + + if (isPage) { // cropBox can not be bigger than mediaBox if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1) { @@ -147,11 +148,13 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { artBox = cropBox; readBox(dict, "ArtBox", &artBox); - // clip all other boxes to the media box - cropBox.clipTo(&mediaBox); - bleedBox.clipTo(&mediaBox); - trimBox.clipTo(&mediaBox); - artBox.clipTo(&mediaBox); + if (isPage) { + // clip all other boxes to the media box + cropBox.clipTo(&mediaBox); + bleedBox.clipTo(&mediaBox); + trimBox.clipTo(&mediaBox); + artBox.clipTo(&mediaBox); + } // rotate dict->lookup("Rotate", &obj1);
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
