Implement clipping in ProcessFormXObject()
Some checks failed
Build and test / build (push) Has been cancelled
Run Integration Tests / build (push) Has been cancelled
Nightly Release / tests (push) Has been cancelled
Nightly Release / Check latest commit (push) Has been cancelled
Nightly Release / build_and_publish_nightly (push) Has been cancelled

This commit is contained in:
BobLd 2025-03-23 20:39:22 +00:00
parent 306642a234
commit 0754e7f003
5 changed files with 60 additions and 12 deletions

View File

@ -231,6 +231,11 @@
// No op
}
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
{
// No op
}
public override void PaintShading(NameToken shadingName)
{
// No op

View File

@ -206,6 +206,11 @@
// No op
}
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
{
// No op
}
public override void PaintShading(NameToken shadingName)
{
// No op

View File

@ -381,6 +381,19 @@
#endregion
#region PdfRectangle
/// <summary>
/// Converts a <see cref="PdfRectangle"/> into its <see cref="PdfPath"/> representation.
/// </summary>
public static PdfPath ToPdfPath(this PdfRectangle rectangle)
{
var clippingSubpath = new PdfSubpath();
clippingSubpath.Rectangle(rectangle.BottomLeft.X,
rectangle.BottomLeft.Y,
rectangle.Width,
rectangle.Height);
return new PdfPath() { clippingSubpath };
}
/// <summary>
/// Whether the point is located inside the rectangle.
/// </summary>

View File

@ -145,15 +145,8 @@
/// </summary>
protected static PdfPath GetInitialClipping(CropBox cropBox)
{
var cropBoxBounds = cropBox.Bounds;
// initiate CurrentClippingPath to cropBox
var clippingSubpath = new PdfSubpath();
clippingSubpath.Rectangle(cropBoxBounds.BottomLeft.X,
cropBoxBounds.BottomLeft.Y,
cropBoxBounds.Width,
cropBoxBounds.Height);
var clippingPath = new PdfPath() { clippingSubpath };
// Initiate CurrentClippingPath to cropBox
var clippingPath = cropBox.Bounds.ToPdfPath();
clippingPath.SetClipping(FillingRule.EvenOdd);
return clippingPath;
}
@ -581,7 +574,14 @@
new MemoryInputBytes(contentStream),
ParsingOptions.Logger);
// 3. We don't respect clipping currently.
// 3. Clip according to the form dictionary's BBox entry.
if (formStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Bbox, PdfScanner, out var bboxToken))
{
var points = bboxToken.Data.OfType<NumericToken>().Select(x => x.Double).ToArray();
PdfRectangle bbox = new PdfRectangle(points[0], points[1], points[2], points[3]);
PdfRectangle transformedBox = startState.CurrentTransformationMatrix.Transform(bbox);
ClipToRectangle(transformedBox, FillingRule.EvenOdd); // TODO - Check that Even Odd is valid
}
// 4. Paint the objects.
bool hasCircularReference = HasFormXObjectCircularReference(formStream, xObjectName, operations);
@ -668,6 +668,9 @@
/// <inheritdoc/>
public abstract void ModifyClippingIntersect(FillingRule clippingRule);
/// <inheritdoc/>
protected abstract void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule);
/// <inheritdoc/>
public virtual void SetNamedGraphicsState(NameToken stateName)
{

View File

@ -422,7 +422,8 @@ namespace UglyToad.PdfPig.Graphics
if (ParsingOptions.ClipPaths)
{
var currentClipping = GetCurrentState().CurrentClippingPath!;
var graphicsState = GetCurrentState();
var currentClipping = graphicsState.CurrentClippingPath!;
currentClipping.SetClipping(clippingRule);
var newClippings = CurrentPath.Clip(currentClipping, ParsingOptions.Logger);
@ -432,11 +433,32 @@ namespace UglyToad.PdfPig.Graphics
}
else
{
GetCurrentState().CurrentClippingPath = newClippings;
graphicsState.CurrentClippingPath = newClippings;
}
}
}
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
{
// https://github.com/apache/pdfbox/blob/f4bfe47de37f6fe69e8f98b164c3546facfd5e91/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java#L611
var graphicsState = GetCurrentState();
var clip = rectangle.ToPdfPath();
clip.SetClipping(clippingRule);
var currentClipping = graphicsState.CurrentClippingPath!;
currentClipping.SetClipping(clippingRule);
var newClippings = clip.Clip(currentClipping, ParsingOptions.Logger);
if (newClippings is null)
{
ParsingOptions.Logger.Warn("Empty clipping path found. Clipping path not updated.");
}
else
{
graphicsState.CurrentClippingPath = newClippings;
}
}
protected override void RenderInlineImage(InlineImage inlineImage)
{
images.Add(Union<XObjectContentRecord, InlineImage>.Two(inlineImage));