diff --git a/src/UglyToad.PdfPig.Core/ClippingRule.cs b/src/UglyToad.PdfPig.Core/ClippingRule.cs new file mode 100644 index 00000000..72f21f14 --- /dev/null +++ b/src/UglyToad.PdfPig.Core/ClippingRule.cs @@ -0,0 +1,32 @@ +namespace UglyToad.PdfPig.Core +{ + /// + /// Rules for determining which points lie inside/outside a path. + /// + public enum ClippingRule + { + /// + /// No rule. + /// + None, + + /// + /// This even-odd rule determines whether a point is inside a path by drawing a ray from that point in + /// any direction and simply counting the number of path segments that cross the ray, regardless of + /// direction. If this number is odd, the point is inside; if even, the point is outside. This yields + /// the same results as the nonzero winding number rule for paths with simple shapes, but produces + /// different results for more complex shapes. + /// + EvenOdd, + + /// + /// The nonzero winding number rule determines whether a given point is inside a path by conceptually + /// drawing a ray from that point to infinity in any direction and then examining the places where a + /// segment of the path crosses the ray. Starting with a count of 0, the rule adds 1 each time a path + /// segment crosses the ray from left to right and subtracts 1 each time a segment crosses from right + /// to left. After counting all the crossings, if the result is 0, the point is outside the path; + /// otherwise, it is inside. + /// + NonZeroWinding + } +} diff --git a/src/UglyToad.PdfPig.Core/PdfPath.cs b/src/UglyToad.PdfPig.Core/PdfPath.cs index 339a371f..f99abdde 100644 --- a/src/UglyToad.PdfPig.Core/PdfPath.cs +++ b/src/UglyToad.PdfPig.Core/PdfPath.cs @@ -22,6 +22,16 @@ /// public bool IsDrawnAsRectangle { get; internal set; } + /// + /// Rules for determining which points lie inside/outside the path. + /// + public ClippingRule ClippingRule { get; private set; } + + /// + /// Returns true if this is a clipping path. + /// + public bool IsClipping { get; private set; } + private PdfPoint? currentPosition; private double shoeLaceSum; @@ -78,6 +88,16 @@ return new PdfPoint(points.Average(p => p.X), points.Average(p => p.Y)); } + /// + /// + /// + /// + public void SetClipping(ClippingRule clippingRule) + { + IsClipping = true; + ClippingRule = clippingRule; + } + internal static PdfPoint GetStartPoint(IPathCommand command) { if (command is Line line) diff --git a/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs b/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs index 2e6dce19..9dec83ec 100644 --- a/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs +++ b/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs @@ -93,12 +93,14 @@ public void BeginMarkedContent(NameToken name, NameToken propertyDictionaryName, DictionaryToken properties) { - } public void EndMarkedContent() { + } + public void ModifyClippingIntersect(ClippingRule clippingRule) + { } private class TestFontFactory : IFontFactory diff --git a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs index a3dc979a..af326ecd 100644 --- a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs +++ b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs @@ -565,5 +565,10 @@ TextMatrices.TextMatrix = newMatrix; } + + public void ModifyClippingIntersect(ClippingRule clippingRule) + { + CurrentPath.SetClipping(clippingRule); + } } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Graphics/IOperationContext.cs b/src/UglyToad.PdfPig/Graphics/IOperationContext.cs index c81e8af8..740c3a0f 100644 --- a/src/UglyToad.PdfPig/Graphics/IOperationContext.cs +++ b/src/UglyToad.PdfPig/Graphics/IOperationContext.cs @@ -127,5 +127,10 @@ /// Indicates that the current inline image is complete. /// void EndInlineImage(IReadOnlyList bytes); + + /// + /// Modify the clipping rule of the current path. + /// + void ModifyClippingIntersect(ClippingRule clippingRule); } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs index ac88494d..284614d5 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs @@ -29,6 +29,7 @@ /// public void Run(IOperationContext operationContext) { + operationContext.ModifyClippingIntersect(PdfPig.Core.ClippingRule.EvenOdd); } /// diff --git a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs index fa39bac0..6c5d0459 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs @@ -29,6 +29,7 @@ /// public void Run(IOperationContext operationContext) { + operationContext.ModifyClippingIntersect(PdfPig.Core.ClippingRule.NonZeroWinding); } ///