Skip to content

Commit 0754e7f

Browse files
committed
Implement clipping in ProcessFormXObject()
1 parent 306642a commit 0754e7f

File tree

5 files changed

+60
-12
lines changed

5 files changed

+60
-12
lines changed

src/UglyToad.PdfPig.Tests/Integration/StreamProcessorTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ public override void ModifyClippingIntersect(FillingRule clippingRule)
231231
// No op
232232
}
233233

234+
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
235+
{
236+
// No op
237+
}
238+
234239
public override void PaintShading(NameToken shadingName)
235240
{
236241
// No op

src/UglyToad.PdfPig.Tests/Integration/VisualVerification/SkiaHelpers/SkiaGlyphStreamProcessor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ public override void ModifyClippingIntersect(FillingRule clippingRule)
206206
// No op
207207
}
208208

209+
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
210+
{
211+
// No op
212+
}
213+
209214
public override void PaintShading(NameToken shadingName)
210215
{
211216
// No op

src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,19 @@ static double polarAngle(in PdfPoint point1, in PdfPoint point2)
381381
#endregion
382382

383383
#region PdfRectangle
384+
/// <summary>
385+
/// Converts a <see cref="PdfRectangle"/> into its <see cref="PdfPath"/> representation.
386+
/// </summary>
387+
public static PdfPath ToPdfPath(this PdfRectangle rectangle)
388+
{
389+
var clippingSubpath = new PdfSubpath();
390+
clippingSubpath.Rectangle(rectangle.BottomLeft.X,
391+
rectangle.BottomLeft.Y,
392+
rectangle.Width,
393+
rectangle.Height);
394+
return new PdfPath() { clippingSubpath };
395+
}
396+
384397
/// <summary>
385398
/// Whether the point is located inside the rectangle.
386399
/// </summary>

src/UglyToad.PdfPig/Graphics/BaseStreamProcessor.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,8 @@ protected BaseStreamProcessor(
145145
/// </summary>
146146
protected static PdfPath GetInitialClipping(CropBox cropBox)
147147
{
148-
var cropBoxBounds = cropBox.Bounds;
149-
150-
// initiate CurrentClippingPath to cropBox
151-
var clippingSubpath = new PdfSubpath();
152-
clippingSubpath.Rectangle(cropBoxBounds.BottomLeft.X,
153-
cropBoxBounds.BottomLeft.Y,
154-
cropBoxBounds.Width,
155-
cropBoxBounds.Height);
156-
var clippingPath = new PdfPath() { clippingSubpath };
148+
// Initiate CurrentClippingPath to cropBox
149+
var clippingPath = cropBox.Bounds.ToPdfPath();
157150
clippingPath.SetClipping(FillingRule.EvenOdd);
158151
return clippingPath;
159152
}
@@ -581,7 +574,14 @@ protected virtual void ProcessFormXObject(StreamToken formStream, NameToken xObj
581574
new MemoryInputBytes(contentStream),
582575
ParsingOptions.Logger);
583576

584-
// 3. We don't respect clipping currently.
577+
// 3. Clip according to the form dictionary's BBox entry.
578+
if (formStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Bbox, PdfScanner, out var bboxToken))
579+
{
580+
var points = bboxToken.Data.OfType<NumericToken>().Select(x => x.Double).ToArray();
581+
PdfRectangle bbox = new PdfRectangle(points[0], points[1], points[2], points[3]);
582+
PdfRectangle transformedBox = startState.CurrentTransformationMatrix.Transform(bbox);
583+
ClipToRectangle(transformedBox, FillingRule.EvenOdd); // TODO - Check that Even Odd is valid
584+
}
585585

586586
// 4. Paint the objects.
587587
bool hasCircularReference = HasFormXObjectCircularReference(formStream, xObjectName, operations);
@@ -668,6 +668,9 @@ protected virtual bool HasFormXObjectCircularReference(StreamToken formStream,
668668
/// <inheritdoc/>
669669
public abstract void ModifyClippingIntersect(FillingRule clippingRule);
670670

671+
/// <inheritdoc/>
672+
protected abstract void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule);
673+
671674
/// <inheritdoc/>
672675
public virtual void SetNamedGraphicsState(NameToken stateName)
673676
{

src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ public override void ModifyClippingIntersect(FillingRule clippingRule)
422422

423423
if (ParsingOptions.ClipPaths)
424424
{
425-
var currentClipping = GetCurrentState().CurrentClippingPath!;
425+
var graphicsState = GetCurrentState();
426+
var currentClipping = graphicsState.CurrentClippingPath!;
426427
currentClipping.SetClipping(clippingRule);
427428

428429
var newClippings = CurrentPath.Clip(currentClipping, ParsingOptions.Logger);
@@ -432,11 +433,32 @@ public override void ModifyClippingIntersect(FillingRule clippingRule)
432433
}
433434
else
434435
{
435-
GetCurrentState().CurrentClippingPath = newClippings;
436+
graphicsState.CurrentClippingPath = newClippings;
436437
}
437438
}
438439
}
439440

441+
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
442+
{
443+
// https://github.com/apache/pdfbox/blob/f4bfe47de37f6fe69e8f98b164c3546facfd5e91/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java#L611
444+
var graphicsState = GetCurrentState();
445+
var clip = rectangle.ToPdfPath();
446+
clip.SetClipping(clippingRule);
447+
448+
var currentClipping = graphicsState.CurrentClippingPath!;
449+
currentClipping.SetClipping(clippingRule);
450+
var newClippings = clip.Clip(currentClipping, ParsingOptions.Logger);
451+
452+
if (newClippings is null)
453+
{
454+
ParsingOptions.Logger.Warn("Empty clipping path found. Clipping path not updated.");
455+
}
456+
else
457+
{
458+
graphicsState.CurrentClippingPath = newClippings;
459+
}
460+
}
461+
440462
protected override void RenderInlineImage(InlineImage inlineImage)
441463
{
442464
images.Add(Union<XObjectContentRecord, InlineImage>.Two(inlineImage));

0 commit comments

Comments
 (0)