r23536 by jghali - #16073: Fix some clip handling issues in PDF import <Pontobart>
scribus-commit
scribus-commit at lists.scribus.net
Thu Mar 26 00:25:23 UTC 2020
Author: jghali
Date: Thu Mar 26 00:25:22 2020
New Revision: 23536
URL: http://scribus.net/websvn/listing.php?repname=Scribus&sc=1&rev=23536
Log:
#16073: Fix some clip handling issues in PDF import <Pontobart>
Modified:
trunk/Scribus/scribus/plugins/import/pdf/slaoutput.cpp
trunk/Scribus/scribus/plugins/import/pdf/slaoutput.h
Modified: trunk/Scribus/scribus/plugins/import/pdf/slaoutput.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=23536&path=/trunk/Scribus/scribus/plugins/import/pdf/slaoutput.cpp
==============================================================================
--- trunk/Scribus/scribus/plugins/import/pdf/slaoutput.cpp (original)
+++ trunk/Scribus/scribus/plugins/import/pdf/slaoutput.cpp Thu Mar 26 00:25:22 2020
@@ -1298,8 +1298,7 @@
m_actPage = pageNum;
m_groupStack.clear();
pushGroup();
- m_currentClipPath.resize(0);
- m_currentClipPath.svgInit();
+ m_currentClipPath = QPainterPath();
m_clipPaths.clear();
}
@@ -1358,10 +1357,10 @@
PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
if (ite)
{
- FPointArray out = m_currentClipPath.copy();
- out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
- out.translate(-ite->xPos(), -ite->yPos());
- ite->PoLine = out.copy();
+ QPainterPath clippath = m_currentClipPath;
+ clippath.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
+ clippath.translate(-ite->xPos(), -ite->yPos());
+ ite->PoLine.fromQPainterPath(clippath, true);
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setTextFlowMode(PageItem::TextFlowDisabled);
@@ -1486,10 +1485,10 @@
ite->FrameType = 3;
if (checkClip())
{
- FPointArray out = m_currentClipPath.copy();
- out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
- out.translate(-ite->xPos(), -ite->yPos());
- ite->PoLine = out.copy();
+ QPainterPath clippath = m_currentClipPath;
+ clippath.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
+ clippath.translate(-ite->xPos(), -ite->yPos());
+ ite->PoLine.fromQPainterPath(clippath, true);
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setTextFlowMode(PageItem::TextFlowDisabled);
@@ -1557,75 +1556,39 @@
void SlaOutputDev::clip(GfxState *state)
{
// qDebug() << "Clip";
- const double *ctm;
- ctm = state->getCTM();
+ adjustClip(state, Qt::WindingFill);
+}
+
+void SlaOutputDev::eoClip(GfxState *state)
+{
+// qDebug() << "EoClip";
+ adjustClip(state, Qt::OddEvenFill);
+}
+
+void SlaOutputDev::adjustClip(GfxState *state, Qt::FillRule fillRule)
+{
+ const double *ctm = state->getCTM();
m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
QString output = convertPath(state->getPath());
if (output.isEmpty())
return;
-
FPointArray out;
out.parseSVG(output);
out.svgClosePath();
out.map(m_ctm);
if (checkClip())
{
- QPainterPath pathN = out.toQPainterPath(true);
- QPainterPath pathA = m_currentClipPath.toQPainterPath(true);
- QPainterPath resultPath = pathA.intersected(pathN);
- if (!resultPath.isEmpty())
- {
- FPointArray polyline;
- polyline.resize(0);
- polyline.fromQPainterPath(resultPath, true);
- polyline.svgClosePath();
- m_currentClipPath = polyline.copy();
- }
- else
- {
- m_currentClipPath.resize(0);
- m_currentClipPath.svgInit();
- }
+ // "clip" (WindingFill) and "eoClip" (OddEvenFill) only the determine
+ // the fill rule of the new clipping path. The new clip should be the
+ // intersection of the old and new area. QPainterPath determines on
+ // its own which fill rule to use for the result. We should not loose
+ // this information.
+ QPainterPath pathN = out.toQPainterPath(false);
+ pathN.setFillRule(fillRule);
+ m_currentClipPath = pathN.intersected(m_currentClipPath);
}
else
- m_currentClipPath = out.copy();
-}
-
-void SlaOutputDev::eoClip(GfxState *state)
-{
-// qDebug() << "EoClip";
- const double *ctm;
- ctm = state->getCTM();
- m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
- QString output = convertPath(state->getPath());
- FPointArray out;
- if (!output.isEmpty())
- {
- out.parseSVG(output);
- out.svgClosePath();
- out.map(m_ctm);
- if (checkClip())
- {
- QPainterPath pathN = out.toQPainterPath(true);
- QPainterPath pathA = m_currentClipPath.toQPainterPath(true);
- QPainterPath resultPath = pathA.intersected(pathN);
- if (!resultPath.isEmpty())
- {
- FPointArray polyline;
- polyline.resize(0);
- polyline.fromQPainterPath(resultPath, true);
- polyline.svgClosePath();
- m_currentClipPath = polyline.copy();
- }
- else
- {
- m_currentClipPath.resize(0);
- m_currentClipPath.svgInit();
- }
- }
- else
- m_currentClipPath = out.copy();
- }
+ m_currentClipPath = out.toQPainterPath(false);
}
void SlaOutputDev::stroke(GfxState *state)
@@ -1723,6 +1686,17 @@
void SlaOutputDev::fill(GfxState *state)
{
// qDebug() << "Fill";
+ createFillItem(state, Qt::WindingFill);
+}
+
+void SlaOutputDev::eoFill(GfxState *state)
+{
+// qDebug() << "EoFill";
+ createFillItem(state, Qt::OddEvenFill);
+}
+
+void SlaOutputDev::createFillItem(GfxState *state, Qt::FillRule fillRule)
+{
const double *ctm;
ctm = state->getCTM();
double xCoor = m_doc->currentPage()->xOffset();
@@ -1732,9 +1706,15 @@
out.parseSVG(output);
m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
out.map(m_ctm);
+
+ // Clip the new path first and only add it if it is not empty.
+ QPainterPath path = out.toQPainterPath(false);
+ path.setFillRule(fillRule);
+ QPainterPath clippedPath = path.intersected(m_currentClipPath);
+
Coords = output;
- FPoint wh = out.widthHeight();
- if ((out.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)))
+ QRectF bbox = clippedPath.boundingRect();
+ if (!clippedPath.isEmpty() && !bbox.isNull())
{
CurrColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &CurrFillShade);
int z;
@@ -1743,17 +1723,20 @@
else
z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CurrColorFill, CommonStrings::None);
PageItem* ite = m_doc->Items->at(z);
- ite->PoLine = out.copy();
+ ite->PoLine.fromQPainterPath(clippedPath, true);
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setFillShade(CurrFillShade);
ite->setLineShade(100);
- ite->setFillEvenOdd(false);
+ // Only the new path has to be interpreted according to fillRule. QPainterPath
+ // could decide to create a final path according to the other rule. Thus
+ // we have to set this from the final path.
+ ite->setFillEvenOdd(clippedPath.fillRule() == Qt::OddEvenFill);
ite->setFillTransparency(1.0 - state->getFillOpacity());
ite->setFillBlendmode(getBlendMode(state));
ite->setLineEnd(PLineEnd);
ite->setLineJoin(PLineJoin);
- ite->setWidthHeight(wh.x(),wh.y());
+ ite->setWidthHeight(bbox.width(),bbox.height());
ite->setTextFlowMode(PageItem::TextFlowDisabled);
m_doc->adjustItemSize(ite);
m_Elements->append(ite);
@@ -1765,53 +1748,9 @@
}
}
-void SlaOutputDev::eoFill(GfxState *state)
-{
-// qDebug() << "EoFill";
- const double *ctm;
- ctm = state->getCTM();
- double xCoor = m_doc->currentPage()->xOffset();
- double yCoor = m_doc->currentPage()->yOffset();
- FPointArray out;
- QString output = convertPath(state->getPath());
- out.parseSVG(output);
- m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
- out.map(m_ctm);
- Coords = output;
- FPoint wh = out.widthHeight();
- if ((out.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)))
- {
- CurrColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &CurrFillShade);
- int z;
- if (pathIsClosed)
- z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CurrColorFill, CommonStrings::None);
- else
- z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CurrColorFill, CommonStrings::None);
- PageItem* ite = m_doc->Items->at(z);
- ite->PoLine = out.copy();
- ite->ClipEdited = true;
- ite->FrameType = 3;
- ite->setFillShade(CurrFillShade);
- ite->setLineShade(100);
- ite->setFillEvenOdd(true);
- ite->setFillTransparency(1.0 - state->getFillOpacity());
- ite->setFillBlendmode(getBlendMode(state));
- ite->setLineEnd(PLineEnd);
- ite->setLineJoin(PLineJoin);
- ite->setWidthHeight(wh.x(),wh.y());
- ite->setTextFlowMode(PageItem::TextFlowDisabled);
- m_doc->adjustItemSize(ite);
- m_Elements->append(ite);
- if (m_groupStack.count() != 0)
- {
- m_groupStack.top().Items.append(ite);
- applyMask(ite);
- }
- }
-}
-
GBool SlaOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax)
{
+// qDebug() << "SlaOutputDev::axialShadedFill";
double GrStartX;
double GrStartY;
double GrEndX;
@@ -1884,16 +1823,16 @@
PageItem* ite = m_doc->Items->at(z);
if (checkClip())
{
- FPointArray out = m_currentClipPath.copy();
+ QPainterPath out = m_currentClipPath;
out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
out.translate(-ite->xPos(), -ite->yPos());
- ite->PoLine = out.copy();
+ ite->PoLine.fromQPainterPath(out, true);
+ ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
}
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setFillShade(CurrFillShade);
ite->setLineShade(100);
- ite->setFillEvenOdd(false);
ite->setFillTransparency(1.0 - state->getFillOpacity());
ite->setFillBlendmode(getBlendMode(state));
ite->setLineEnd(PLineEnd);
@@ -1924,6 +1863,7 @@
GBool SlaOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax)
{
+// qDebug() << "SlaOutputDev::radialShadedFill";
double GrStartX;
double GrStartY;
double GrEndX;
@@ -2004,16 +1944,16 @@
PageItem* ite = m_doc->Items->at(z);
if (checkClip())
{
- FPointArray out = m_currentClipPath.copy();
+ QPainterPath out = m_currentClipPath;
out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
out.translate(-ite->xPos(), -ite->yPos());
- ite->PoLine = out.copy();
+ ite->PoLine.fromQPainterPath(out, true);
+ ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
}
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setFillShade(CurrFillShade);
ite->setLineShade(100);
- ite->setFillEvenOdd(false);
ite->setFillTransparency(1.0 - state->getFillOpacity());
ite->setFillBlendmode(getBlendMode(state));
ite->setLineEnd(PLineEnd);
@@ -2044,6 +1984,7 @@
GBool SlaOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
{
+// qDebug() << "SlaOutputDev::gouraudTriangleShadedFill";
double xCoor = m_doc->currentPage()->xOffset();
double yCoor = m_doc->currentPage()->yOffset();
double xmin, ymin, xmax, ymax;
@@ -2123,7 +2064,7 @@
GBool SlaOutputDev::patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
{
-// qDebug() << "mesh shaded fill";
+// qDebug() << "SlaOutputDev::patchMeshShadedFill";
double xCoor = m_doc->currentPage()->xOffset();
double yCoor = m_doc->currentPage()->yOffset();
double xmin, ymin, xmax, ymax;
@@ -2272,6 +2213,7 @@
GBool SlaOutputDev::tilingPatternFill(GfxState *state, Gfx * /*gfx*/, Catalog *cat, Object *str, POPPLER_CONST_070 double *pmat, int paintType, int tilingType, Dict *resDict, POPPLER_CONST_070 double *mat, POPPLER_CONST_070 double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep)
{
+// qDebug() << "SlaOutputDev::tilingPatternFill";
PDFRectangle box;
Gfx *gfx;
QString id;
@@ -2360,16 +2302,16 @@
ite = m_doc->Items->at(z);
if (checkClip())
{
- FPointArray out = m_currentClipPath.copy();
+ QPainterPath out = m_currentClipPath;
out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
out.translate(-ite->xPos(), -ite->yPos());
- ite->PoLine = out.copy();
+ ite->PoLine.fromQPainterPath(out, true);
+ ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
}
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setFillShade(CurrFillShade);
ite->setLineShade(100);
- ite->setFillEvenOdd(false);
ite->setFillTransparency(1.0 - state->getFillOpacity());
ite->setFillBlendmode(getBlendMode(state));
ite->setLineEnd(PLineEnd);
@@ -2700,6 +2642,17 @@
torigin = m_ctm.map(QPointF(0, 1));
}
+ // Determine the visible area of the picture after clipping it. If it is empty, no item
+ // needs to be created.
+ QPainterPath outline;
+ outline.addRect(0, 0, 1, 1);
+ outline = m_ctm.map(outline);
+ if (!m_currentClipPath.isEmpty())
+ outline = outline.intersected(m_currentClipPath);
+
+ if ((inPattern == 0) && (outline.isEmpty() || outline.boundingRect().isNull()))
+ return;
+
// Determine the width and height of the image by undoing the rotation part
// of the CTM and applying the result to the unit square.
QTransform without_rotation;
@@ -2798,20 +2751,15 @@
}
delete tempFile;
}
- if ((checkClip()) && (inPattern == 0))
- {
- FPointArray out = m_currentClipPath.copy();
+ if (inPattern == 0)
+ {
+ outline.translate(xCoor - ite->xPos(), yCoor - ite->yPos());
+ // Undo the rotation of the clipping path as it is rotated together with the iamge.
QTransform mm;
mm.rotate(-ite->rotation());
- out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
- out.translate(-ite->xPos(), -ite->yPos());
- // Undo the rotation of the clipping path as it is rotated together with the iamge.
- for (int i = 0; i != out.size(); ++i)
- {
- QPointF p = mm.map(out.pointQF(i));
- out.setPoint(i, p.x(), p.y());
- }
- ite->PoLine = out.copy();
+ outline = mm.map(outline);
+ ite->PoLine.fromQPainterPath(outline, true);
+ ite->setFillEvenOdd(outline.fillRule() == Qt::OddEvenFill);
ite->ClipEdited = true;
ite->FrameType = 3;
ite->setTextFlowMode(PageItem::TextFlowDisabled);
@@ -3536,6 +3484,7 @@
QString SlaOutputDev::convertPath(POPPLER_CONST_083 GfxPath *path)
{
+// qDebug() << "SlaOutputDev::convertPath";
if (! path)
return QString();
@@ -3798,10 +3747,10 @@
bool SlaOutputDev::checkClip()
{
bool ret = false;
- if (m_currentClipPath.count() != 0)
- {
- FPoint wh = m_currentClipPath.widthHeight();
- if ((wh.x() > 0) && (wh.y() > 0))
+ if (!m_currentClipPath.isEmpty())
+ {
+ QRectF bbox = m_currentClipPath.boundingRect();
+ if ((bbox.width() > 0) && (bbox.height() > 0))
ret = true;
}
return ret;
Modified: trunk/Scribus/scribus/plugins/import/pdf/slaoutput.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=23536&path=/trunk/Scribus/scribus/plugins/import/pdf/slaoutput.h
==============================================================================
--- trunk/Scribus/scribus/plugins/import/pdf/slaoutput.h (original)
+++ trunk/Scribus/scribus/plugins/import/pdf/slaoutput.h Thu Mar 26 00:25:22 2020
@@ -296,6 +296,14 @@
QString UnicodeParsedString(const std::string& s1);
bool checkClip();
+ // Intersect the current clip path with the new path in state where filled areas
+ // are interpreted according to fillRule.
+ void adjustClip(GfxState *state, Qt::FillRule fillRule);
+
+ // Take the current path of state and interpret it according to fillRule,
+ // intersect it with the clipping path and create a new pageitem for it.
+ void createFillItem(GfxState *state, Qt::FillRule fillRule);
+
void createImageFrame(QImage& image, GfxState *state, int numColorComponents);
bool pathIsClosed {false};
@@ -308,8 +316,15 @@
QVector<double> DashValues;
double DashOffset {0.0};
QString Coords;
- FPointArray m_currentClipPath;
- QStack<FPointArray> m_clipPaths;
+ // The currently visible area. If it is empty, everything is visible.
+ // QPainterPath has the drawback that it sometimes approximates Bezier curves
+ // by line segments for numerical stability. If available, a better class
+ // should be used. However, it is important that the used class knows which
+ // areas are covered and does not rely on external information about the fill
+ // rule to use.
+ QPainterPath m_currentClipPath;
+ QStack<QPainterPath> m_clipPaths;
+
struct groupEntry
{
QList<PageItem*> Items;
More information about the scribus-commit
mailing list