diff --git a/src/UglyToad.PdfPig.Tests/Geometry/ClippingTests.cs b/src/UglyToad.PdfPig.Tests/Geometry/ClippingTests.cs new file mode 100644 index 00000000..17fd56eb --- /dev/null +++ b/src/UglyToad.PdfPig.Tests/Geometry/ClippingTests.cs @@ -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); + } + } + } +} diff --git a/src/UglyToad.PdfPig.Tests/Integration/Documents/SPARC - v9 Architecture Manual.pdf b/src/UglyToad.PdfPig.Tests/Integration/Documents/SPARC - v9 Architecture Manual.pdf new file mode 100644 index 00000000..77dc6426 Binary files /dev/null and b/src/UglyToad.PdfPig.Tests/Integration/Documents/SPARC - v9 Architecture Manual.pdf differ diff --git a/src/UglyToad.PdfPig/Geometry/ClippingExtensions.cs b/src/UglyToad.PdfPig/Geometry/ClippingExtensions.cs index 12d839ad..17b6d74a 100644 --- a/src/UglyToad.PdfPig/Geometry/ClippingExtensions.cs +++ b/src/UglyToad.PdfPig/Geometry/ClippingExtensions.cs @@ -6,6 +6,7 @@ using ClipperLibrary; using Core; using Graphics; + using UglyToad.PdfPig.Logging; using static Core.PdfSubpath; /// @@ -23,7 +24,7 @@ /// /// Generates the result of applying a clipping path to another path. /// - 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; } } } diff --git a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs index 362cade9..040f7c8b 100644 --- a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs +++ b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs @@ -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.");