Merge pull request #220 from BobLd/fix-clip-line-fill

fix clipping error when trying to fill a single line
This commit is contained in:
Eliot Jones
2020-09-22 20:36:24 +01:00
committed by GitHub
4 changed files with 53 additions and 11 deletions

View File

@@ -0,0 +1,19 @@
using UglyToad.PdfPig.Tests.Integration;
using Xunit;
namespace UglyToad.PdfPig.Tests.Geometry
{
public class ClippingTests
{
[Fact]
public void ContainsRectangleEvenOdd()
{
using (var document = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("SPARC - v9 Architecture Manual"),
new ParsingOptions() { ClipPaths = true }))
{
var page = document.GetPage(45);
Assert.Equal(28, page.ExperimentalAccess.Paths.Count);
}
}
}
}

View File

@@ -6,6 +6,7 @@
using ClipperLibrary; using ClipperLibrary;
using Core; using Core;
using Graphics; using Graphics;
using UglyToad.PdfPig.Logging;
using static Core.PdfSubpath; using static Core.PdfSubpath;
/// <summary> /// <summary>
@@ -23,7 +24,7 @@
/// <summary> /// <summary>
/// Generates the result of applying a clipping path to another path. /// Generates the result of applying a clipping path to another path.
/// </summary> /// </summary>
public static PdfPath Clip(this PdfPath clipping, PdfPath subject) public static PdfPath Clip(this PdfPath clipping, PdfPath subject, ILog log = null)
{ {
if (clipping == null) if (clipping == null)
{ {
@@ -61,7 +62,10 @@
subPathClipping.CloseSubpath(); subPathClipping.CloseSubpath();
} }
clipper.AddPath(subPathClipping.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true); if (!clipper.AddPath(subPathClipping.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true))
{
log?.Error("ClippingExtensions.Clip(): failed to add clipping subpath.");
}
} }
// Subject path // Subject path
@@ -74,13 +78,27 @@
continue; continue;
} }
if (subjectClose && !subPathSubject.IsClosed()
&& subPathSubject.Commands.Count(sp => sp is Line) < 2
&& subPathSubject.Commands.Count(sp => sp is BezierCurve) == 0)
{
// strange here:
// the subpath contains maximum 1 line and no curves
// it cannot be filled or a be clipping path
// cancel closing the path/subpath
subjectClose = false;
}
// Force close subject if need be // Force close subject if need be
if (subjectClose && !subPathSubject.IsClosed()) if (subjectClose && !subPathSubject.IsClosed())
{ {
subPathSubject.CloseSubpath(); subPathSubject.CloseSubpath();
} }
clipper.AddPath(subPathSubject.ToClipperPolygon().ToList(), ClipperPolyType.Subject, subjectClose); if (!clipper.AddPath(subPathSubject.ToClipperPolygon().ToList(), ClipperPolyType.Subject, subjectClose))
{
log?.Error("ClippingExtensions.Clip(): failed to add subject subpath for clipping.");
}
} }
var clippingFillType = clipping.FillingRule == FillingRule.NonZeroWinding ? ClipperPolyFillType.NonZero : ClipperPolyFillType.EvenOdd; var clippingFillType = clipping.FillingRule == FillingRule.NonZeroWinding ? ClipperPolyFillType.NonZero : ClipperPolyFillType.EvenOdd;
@@ -164,11 +182,12 @@
yield break; yield break;
} }
if (pdfPath.Commands[0] is Move currentMove) ClipperIntPoint movePoint;
if (pdfPath.Commands[0] is Move move)
{ {
var previous = currentMove.Location.ToClipperIntPoint(); movePoint = move.Location.ToClipperIntPoint();
yield return previous; yield return movePoint;
if (pdfPath.Commands.Count == 1) if (pdfPath.Commands.Count == 1)
{ {
@@ -185,7 +204,7 @@
var command = pdfPath.Commands[i]; var command = pdfPath.Commands[i];
if (command is Move) if (command is Move)
{ {
throw new ArgumentException("ToClipperPolygon():only one move allowed per subpath.", nameof(pdfPath)); throw new ArgumentException("ToClipperPolygon(): only one move allowed per subpath.", nameof(pdfPath));
} }
if (command is Line line) if (command is Line line)
@@ -203,7 +222,11 @@
} }
else if (command is Close) else if (command is Close)
{ {
yield return currentMove.Location.ToClipperIntPoint(); if (movePoint == null)
{
throw new ArgumentException("ToClipperPolygon(): Move command was null, cannot close the subpath.");
}
yield return movePoint;
} }
} }
} }

View File

@@ -106,7 +106,7 @@
var clippingSubpath = new PdfSubpath(); var clippingSubpath = new PdfSubpath();
clippingSubpath.Rectangle(cropBox.BottomLeft.X, cropBox.BottomLeft.Y, cropBox.Width, cropBox.Height); clippingSubpath.Rectangle(cropBox.BottomLeft.X, cropBox.BottomLeft.Y, cropBox.Width, cropBox.Height);
var clippingPath = new PdfPath() { clippingSubpath }; var clippingPath = new PdfPath() { clippingSubpath };
clippingPath.SetClipping(FillingRule.NonZeroWinding); clippingPath.SetClipping(FillingRule.EvenOdd);
graphicsStack.Push(new CurrentGraphicsState() graphicsStack.Push(new CurrentGraphicsState()
{ {
@@ -627,7 +627,7 @@
if (clipPaths) if (clipPaths)
{ {
var clippedPath = currentState.CurrentClippingPath.Clip(CurrentPath); var clippedPath = currentState.CurrentClippingPath.Clip(CurrentPath, log);
if (clippedPath != null) if (clippedPath != null)
{ {
paths.Add(clippedPath); paths.Add(clippedPath);
@@ -658,7 +658,7 @@
var currentClipping = GetCurrentState().CurrentClippingPath; var currentClipping = GetCurrentState().CurrentClippingPath;
currentClipping.SetClipping(clippingRule); currentClipping.SetClipping(clippingRule);
var newClippings = CurrentPath.Clip(currentClipping); var newClippings = CurrentPath.Clip(currentClipping, log);
if (newClippings == null) if (newClippings == null)
{ {
log.Warn("Empty clipping path found. Clipping path not updated."); log.Warn("Empty clipping path found. Clipping path not updated.");