mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-21 04:17:57 +08:00
Added "Paths" collection to Page object.
Added matrix transformation to path operators.
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
using Util;
|
using Util;
|
||||||
using Util.JetBrains.Annotations;
|
using Util.JetBrains.Annotations;
|
||||||
using XObjects;
|
using XObjects;
|
||||||
|
using UglyToad.PdfPig.Geometry;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
|
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
|
||||||
@@ -41,6 +42,11 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<Letter> Letters => Content?.Letters ?? new Letter[0];
|
public IReadOnlyList<Letter> Letters => Content?.Letters ?? new Letter[0];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The set of <see cref="PdfPath"/>s drawn by the PDF content.
|
||||||
|
/// </summary>
|
||||||
|
public List<PdfPath> Paths => Content?.Paths ?? new List<PdfPath>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The full text of all characters on the page in the order they are presented in the PDF content.
|
/// The full text of all characters on the page in the order they are presented in the PDF content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
using Graphics.Operations;
|
using Graphics.Operations;
|
||||||
using Tokenization.Scanner;
|
using Tokenization.Scanner;
|
||||||
using XObjects;
|
using XObjects;
|
||||||
|
using UglyToad.PdfPig.Geometry;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -23,8 +24,9 @@
|
|||||||
internal IReadOnlyList<IGraphicsStateOperation> GraphicsStateOperations { get; }
|
internal IReadOnlyList<IGraphicsStateOperation> GraphicsStateOperations { get; }
|
||||||
|
|
||||||
public IReadOnlyList<Letter> Letters { get; }
|
public IReadOnlyList<Letter> Letters { get; }
|
||||||
|
public List<PdfPath> Paths { get; }
|
||||||
|
|
||||||
internal PageContent(IReadOnlyList<IGraphicsStateOperation> graphicsStateOperations, IReadOnlyList<Letter> letters,
|
internal PageContent(IReadOnlyList<IGraphicsStateOperation> graphicsStateOperations, IReadOnlyList<Letter> letters, List<PdfPath> paths,
|
||||||
IReadOnlyDictionary<XObjectType, List<XObjectContentRecord>> xObjects,
|
IReadOnlyDictionary<XObjectType, List<XObjectContentRecord>> xObjects,
|
||||||
IPdfTokenScanner pdfScanner,
|
IPdfTokenScanner pdfScanner,
|
||||||
XObjectFactory xObjectFactory,
|
XObjectFactory xObjectFactory,
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
{
|
{
|
||||||
GraphicsStateOperations = graphicsStateOperations;
|
GraphicsStateOperations = graphicsStateOperations;
|
||||||
Letters = letters;
|
Letters = letters;
|
||||||
|
Paths = paths;
|
||||||
this.xObjects = xObjects;
|
this.xObjects = xObjects;
|
||||||
this.pdfScanner = pdfScanner;
|
this.pdfScanner = pdfScanner;
|
||||||
this.xObjectFactory = xObjectFactory;
|
this.xObjectFactory = xObjectFactory;
|
||||||
|
@@ -5,27 +5,29 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using UglyToad.PdfPig.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A path in a PDF document, used by glyphs and page content.
|
/// A path in a PDF document, used by glyphs and page content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PdfPath
|
public class PdfPath
|
||||||
{
|
{
|
||||||
private readonly List<IPathCommand> commands = new List<IPathCommand>();
|
public readonly List<IPathCommand> Commands = new List<IPathCommand>();
|
||||||
private PdfPoint? currentPosition;
|
private PdfPoint? currentPosition;
|
||||||
|
internal TransformationMatrix CurrentTransformationMatrix;
|
||||||
|
|
||||||
internal void MoveTo(decimal x, decimal y)
|
internal void MoveTo(decimal x, decimal y)
|
||||||
{
|
{
|
||||||
currentPosition = new PdfPoint(x, y);
|
currentPosition = CurrentTransformationMatrix.Transform(new PdfPoint(x, y));
|
||||||
commands.Add(new Move(currentPosition.Value));
|
Commands.Add(new Move(currentPosition.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LineTo(decimal x, decimal y)
|
internal void LineTo(decimal x, decimal y)
|
||||||
{
|
{
|
||||||
if (currentPosition.HasValue)
|
if (currentPosition.HasValue)
|
||||||
{
|
{
|
||||||
var to = new PdfPoint(x, y);
|
var to = CurrentTransformationMatrix.Transform(new PdfPoint(x, y));
|
||||||
commands.Add(new Line(currentPosition.Value, to));
|
Commands.Add(new Line(currentPosition.Value, to));
|
||||||
currentPosition = to;
|
currentPosition = to;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -40,9 +42,9 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
{
|
{
|
||||||
if (currentPosition.HasValue)
|
if (currentPosition.HasValue)
|
||||||
{
|
{
|
||||||
var to = new PdfPoint(x3, y3);
|
var to = CurrentTransformationMatrix.Transform(new PdfPoint(x3, y3));
|
||||||
commands.Add(new BezierCurve(currentPosition.Value,
|
Commands.Add(new BezierCurve(currentPosition.Value,
|
||||||
new PdfPoint(x1, y1), new PdfPoint(x2, y2), to));
|
CurrentTransformationMatrix.Transform(new PdfPoint(x1, y1)), CurrentTransformationMatrix.Transform(new PdfPoint(x2, y2)), to));
|
||||||
currentPosition = to;
|
currentPosition = to;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -55,12 +57,12 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
|
|
||||||
internal void ClosePath()
|
internal void ClosePath()
|
||||||
{
|
{
|
||||||
commands.Add(new Close());
|
Commands.Add(new Close());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal PdfRectangle? GetBoundingRectangle()
|
internal PdfRectangle? GetBoundingRectangle()
|
||||||
{
|
{
|
||||||
if (commands.Count == 0)
|
if (Commands.Count == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -71,7 +73,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
var minY = decimal.MaxValue;
|
var minY = decimal.MaxValue;
|
||||||
var maxY = decimal.MinValue;
|
var maxY = decimal.MinValue;
|
||||||
|
|
||||||
foreach (var command in commands)
|
foreach (var command in Commands)
|
||||||
{
|
{
|
||||||
var rect = command.GetBoundingRectangle();
|
var rect = command.GetBoundingRectangle();
|
||||||
if (rect == null)
|
if (rect == null)
|
||||||
@@ -106,7 +108,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
internal string ToSvg()
|
internal string ToSvg()
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
foreach (var pathCommand in commands)
|
foreach (var pathCommand in Commands)
|
||||||
{
|
{
|
||||||
pathCommand.WriteSvg(builder);
|
pathCommand.WriteSvg(builder);
|
||||||
}
|
}
|
||||||
@@ -136,7 +138,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
var bbox = GetBoundingRectangle();
|
var bbox = GetBoundingRectangle();
|
||||||
var bboxes = new List<PdfRectangle>();
|
var bboxes = new List<PdfRectangle>();
|
||||||
|
|
||||||
foreach (var command in commands)
|
foreach (var command in Commands)
|
||||||
{
|
{
|
||||||
var segBbox = command.GetBoundingRectangle();
|
var segBbox = command.GetBoundingRectangle();
|
||||||
if (segBbox.HasValue)
|
if (segBbox.HasValue)
|
||||||
@@ -153,7 +155,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface IPathCommand
|
public interface IPathCommand
|
||||||
{
|
{
|
||||||
PdfRectangle? GetBoundingRectangle();
|
PdfRectangle? GetBoundingRectangle();
|
||||||
|
|
||||||
@@ -173,7 +175,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Move : IPathCommand
|
public class Move : IPathCommand
|
||||||
{
|
{
|
||||||
public PdfPoint Location { get; }
|
public PdfPoint Location { get; }
|
||||||
|
|
||||||
@@ -193,7 +195,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Line : IPathCommand
|
public class Line : IPathCommand
|
||||||
{
|
{
|
||||||
public PdfPoint From { get; }
|
public PdfPoint From { get; }
|
||||||
|
|
||||||
@@ -216,7 +218,7 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class BezierCurve : IPathCommand
|
public class BezierCurve : IPathCommand
|
||||||
{
|
{
|
||||||
public PdfPoint StartPoint { get; }
|
public PdfPoint StartPoint { get; }
|
||||||
|
|
||||||
@@ -379,6 +381,11 @@ namespace UglyToad.PdfPig.Geometry
|
|||||||
|
|
||||||
internal void Rectangle(decimal x, decimal y, decimal width, decimal height)
|
internal void Rectangle(decimal x, decimal y, decimal width, decimal height)
|
||||||
{
|
{
|
||||||
|
currentPosition = CurrentTransformationMatrix.Transform(new PdfPoint(x, y));
|
||||||
|
LineTo(x + width, y);
|
||||||
|
LineTo(x + width, y + height);
|
||||||
|
LineTo(x, y + height);
|
||||||
|
LineTo(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
public List<Letter> Letters = new List<Letter>();
|
public List<Letter> Letters = new List<Letter>();
|
||||||
|
|
||||||
public ContentStreamProcessor(PdfRectangle cropBox, IResourceStore resourceStore, UserSpaceUnit userSpaceUnit, PageRotationDegrees rotation, bool isLenientParsing,
|
public ContentStreamProcessor(PdfRectangle cropBox, IResourceStore resourceStore, UserSpaceUnit userSpaceUnit, PageRotationDegrees rotation, bool isLenientParsing,
|
||||||
IPdfTokenScanner pdfScanner,
|
IPdfTokenScanner pdfScanner,
|
||||||
XObjectFactory xObjectFactory,
|
XObjectFactory xObjectFactory,
|
||||||
@@ -70,7 +69,7 @@
|
|||||||
|
|
||||||
ProcessOperations(operations);
|
ProcessOperations(operations);
|
||||||
|
|
||||||
return new PageContent(operations, Letters, xObjects, pdfScanner, xObjectFactory, isLenientParsing);
|
return new PageContent(operations, Letters, paths, xObjects, pdfScanner, xObjectFactory, isLenientParsing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessOperations(IReadOnlyList<IGraphicsStateOperation> operations)
|
private void ProcessOperations(IReadOnlyList<IGraphicsStateOperation> operations)
|
||||||
@@ -192,7 +191,7 @@
|
|||||||
var textState = currentState.FontState;
|
var textState = currentState.FontState;
|
||||||
|
|
||||||
var fontSize = textState.FontSize;
|
var fontSize = textState.FontSize;
|
||||||
var horizontalScaling = textState.HorizontalScaling/100m;
|
var horizontalScaling = textState.HorizontalScaling / 100m;
|
||||||
var font = resourceStore.GetFont(textState.FontName);
|
var font = resourceStore.GetFont(textState.FontName);
|
||||||
|
|
||||||
var isVertical = font.IsVertical;
|
var isVertical = font.IsVertical;
|
||||||
@@ -226,7 +225,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bytes = OtherEncodings.StringAsLatin1Bytes(((StringToken) token).Data);
|
bytes = OtherEncodings.StringAsLatin1Bytes(((StringToken)token).Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowText(new ByteArrayInputBytes(bytes));
|
ShowText(new ByteArrayInputBytes(bytes));
|
||||||
@@ -267,6 +266,7 @@
|
|||||||
public void BeginSubpath()
|
public void BeginSubpath()
|
||||||
{
|
{
|
||||||
CurrentPath = new PdfPath();
|
CurrentPath = new PdfPath();
|
||||||
|
CurrentPath.CurrentTransformationMatrix = GetCurrentState().CurrentTransformationMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StrokePath(bool close)
|
public void StrokePath(bool close)
|
||||||
@@ -275,12 +275,21 @@
|
|||||||
{
|
{
|
||||||
ClosePath();
|
ClosePath();
|
||||||
}
|
}
|
||||||
|
paths.Add(CurrentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FillPath(bool close)
|
||||||
|
{
|
||||||
|
if (close)
|
||||||
|
{
|
||||||
|
ClosePath();
|
||||||
|
}
|
||||||
|
paths.Add(CurrentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClosePath()
|
public void ClosePath()
|
||||||
{
|
{
|
||||||
CurrentPath.ClosePath();
|
CurrentPath.ClosePath();
|
||||||
paths.Add(CurrentPath);
|
|
||||||
CurrentPath = null;
|
CurrentPath = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,12 +306,12 @@
|
|||||||
|
|
||||||
if (state.TryGet(NameToken.Lc, pdfScanner, out NumericToken lcToken))
|
if (state.TryGet(NameToken.Lc, pdfScanner, out NumericToken lcToken))
|
||||||
{
|
{
|
||||||
currentGraphicsState.CapStyle = (LineCapStyle) lcToken.Int;
|
currentGraphicsState.CapStyle = (LineCapStyle)lcToken.Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.TryGet(NameToken.Lj, pdfScanner, out NumericToken ljToken))
|
if (state.TryGet(NameToken.Lj, pdfScanner, out NumericToken ljToken))
|
||||||
{
|
{
|
||||||
currentGraphicsState.JoinStyle = (LineJoinStyle) ljToken.Int;
|
currentGraphicsState.JoinStyle = (LineJoinStyle)ljToken.Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.TryGet(NameToken.Font, pdfScanner, out ArrayToken fontArray) && fontArray.Length == 2
|
if (state.TryGet(NameToken.Font, pdfScanner, out ArrayToken fontArray) && fontArray.Length == 2
|
||||||
|
@@ -82,6 +82,12 @@
|
|||||||
/// <param name="close">Whether to also close the path.</param>
|
/// <param name="close">Whether to also close the path.</param>
|
||||||
void StrokePath(bool close);
|
void StrokePath(bool close);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fill the current path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="close">Whether to also close the path.</param>
|
||||||
|
void FillPath(bool close);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close the current path.
|
/// Close the current path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Run(IOperationContext operationContext)
|
public void Run(IOperationContext operationContext)
|
||||||
{
|
{
|
||||||
|
operationContext.FillPath(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -52,7 +52,7 @@
|
|||||||
{
|
{
|
||||||
operationContext.BeginSubpath();
|
operationContext.BeginSubpath();
|
||||||
operationContext.CurrentPath.Rectangle(LowerLeft.X, LowerLeft.Y, Width, Height);
|
operationContext.CurrentPath.Rectangle(LowerLeft.X, LowerLeft.Y, Width, Height);
|
||||||
operationContext.CurrentPath.ClosePath();
|
//operationContext.CurrentPath.ClosePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
{
|
{
|
||||||
operationContext.BeginSubpath();
|
operationContext.BeginSubpath();
|
||||||
operationContext.CurrentPosition = Point;
|
operationContext.CurrentPosition = Point;
|
||||||
|
operationContext.CurrentPath.LineTo(Point.X, Point.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
Reference in New Issue
Block a user