fix clipping error when trying to fill a single line; add log; set EvenOdd as default in initiate CurrentClippingPath; add tests

This commit is contained in:
BobLd 2020-09-22 10:47:34 +01:00
parent e41ae7d3a2
commit 8f0f7769a6
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 Core;
using Graphics;
using UglyToad.PdfPig.Logging;
using static Core.PdfSubpath;
/// <summary>
@ -23,7 +24,7 @@
/// <summary>
/// Generates the result of applying a clipping path to another path.
/// </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)
{
@ -61,7 +62,10 @@
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
@ -74,13 +78,27 @@
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
if (subjectClose && !subPathSubject.IsClosed())
{
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;
@ -164,11 +182,12 @@
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)
{
@ -185,7 +204,7 @@
var command = pdfPath.Commands[i];
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)
@ -203,7 +222,11 @@
}
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();
clippingSubpath.Rectangle(cropBox.BottomLeft.X, cropBox.BottomLeft.Y, cropBox.Width, cropBox.Height);
var clippingPath = new PdfPath() { clippingSubpath };
clippingPath.SetClipping(FillingRule.NonZeroWinding);
clippingPath.SetClipping(FillingRule.EvenOdd);
graphicsStack.Push(new CurrentGraphicsState()
{
@ -627,7 +627,7 @@
if (clipPaths)
{
var clippedPath = currentState.CurrentClippingPath.Clip(CurrentPath);
var clippedPath = currentState.CurrentClippingPath.Clip(CurrentPath, log);
if (clippedPath != null)
{
paths.Add(clippedPath);
@ -658,7 +658,7 @@
var currentClipping = GetCurrentState().CurrentClippingPath;
currentClipping.SetClipping(clippingRule);
var newClippings = CurrentPath.Clip(currentClipping);
var newClippings = CurrentPath.Clip(currentClipping, log);
if (newClippings == null)
{
log.Warn("Empty clipping path found. Clipping path not updated.");