Added "Paths" collection to Page object.

Added matrix transformation to path operators.
This commit is contained in:
vadimy
2019-07-16 00:35:29 -04:00
parent 453faf50af
commit b9d0cca2a6
14 changed files with 73 additions and 34 deletions

View File

@@ -9,6 +9,7 @@
using Util;
using Util.JetBrains.Annotations;
using XObjects;
using UglyToad.PdfPig.Geometry;
/// <summary>
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
@@ -41,6 +42,11 @@
/// </summary>
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>
/// The full text of all characters on the page in the order they are presented in the PDF content.
/// </summary>

View File

@@ -5,6 +5,7 @@
using Graphics.Operations;
using Tokenization.Scanner;
using XObjects;
using UglyToad.PdfPig.Geometry;
/// <summary>
///
@@ -23,8 +24,9 @@
internal IReadOnlyList<IGraphicsStateOperation> GraphicsStateOperations { 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,
IPdfTokenScanner pdfScanner,
XObjectFactory xObjectFactory,
@@ -32,6 +34,7 @@
{
GraphicsStateOperations = graphicsStateOperations;
Letters = letters;
Paths = paths;
this.xObjects = xObjects;
this.pdfScanner = pdfScanner;
this.xObjectFactory = xObjectFactory;

View File

@@ -5,27 +5,29 @@ namespace UglyToad.PdfPig.Geometry
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UglyToad.PdfPig.Core;
/// <summary>
/// A path in a PDF document, used by glyphs and page content.
/// </summary>
public class PdfPath
{
private readonly List<IPathCommand> commands = new List<IPathCommand>();
public readonly List<IPathCommand> Commands = new List<IPathCommand>();
private PdfPoint? currentPosition;
internal TransformationMatrix CurrentTransformationMatrix;
internal void MoveTo(decimal x, decimal y)
{
currentPosition = new PdfPoint(x, y);
commands.Add(new Move(currentPosition.Value));
currentPosition = CurrentTransformationMatrix.Transform(new PdfPoint(x, y));
Commands.Add(new Move(currentPosition.Value));
}
internal void LineTo(decimal x, decimal y)
{
if (currentPosition.HasValue)
{
var to = new PdfPoint(x, y);
commands.Add(new Line(currentPosition.Value, to));
var to = CurrentTransformationMatrix.Transform(new PdfPoint(x, y));
Commands.Add(new Line(currentPosition.Value, to));
currentPosition = to;
}
else
@@ -40,9 +42,9 @@ namespace UglyToad.PdfPig.Geometry
{
if (currentPosition.HasValue)
{
var to = new PdfPoint(x3, y3);
commands.Add(new BezierCurve(currentPosition.Value,
new PdfPoint(x1, y1), new PdfPoint(x2, y2), to));
var to = CurrentTransformationMatrix.Transform(new PdfPoint(x3, y3));
Commands.Add(new BezierCurve(currentPosition.Value,
CurrentTransformationMatrix.Transform(new PdfPoint(x1, y1)), CurrentTransformationMatrix.Transform(new PdfPoint(x2, y2)), to));
currentPosition = to;
}
else
@@ -55,12 +57,12 @@ namespace UglyToad.PdfPig.Geometry
internal void ClosePath()
{
commands.Add(new Close());
Commands.Add(new Close());
}
internal PdfRectangle? GetBoundingRectangle()
{
if (commands.Count == 0)
if (Commands.Count == 0)
{
return null;
}
@@ -71,7 +73,7 @@ namespace UglyToad.PdfPig.Geometry
var minY = decimal.MaxValue;
var maxY = decimal.MinValue;
foreach (var command in commands)
foreach (var command in Commands)
{
var rect = command.GetBoundingRectangle();
if (rect == null)
@@ -106,7 +108,7 @@ namespace UglyToad.PdfPig.Geometry
internal string ToSvg()
{
var builder = new StringBuilder();
foreach (var pathCommand in commands)
foreach (var pathCommand in Commands)
{
pathCommand.WriteSvg(builder);
}
@@ -136,7 +138,7 @@ namespace UglyToad.PdfPig.Geometry
var bbox = GetBoundingRectangle();
var bboxes = new List<PdfRectangle>();
foreach (var command in commands)
foreach (var command in Commands)
{
var segBbox = command.GetBoundingRectangle();
if (segBbox.HasValue)
@@ -153,7 +155,7 @@ namespace UglyToad.PdfPig.Geometry
return result;
}
internal interface IPathCommand
public interface IPathCommand
{
PdfRectangle? GetBoundingRectangle();
@@ -173,7 +175,7 @@ namespace UglyToad.PdfPig.Geometry
}
}
private class Move : IPathCommand
public class Move : IPathCommand
{
public PdfPoint Location { get; }
@@ -193,7 +195,7 @@ namespace UglyToad.PdfPig.Geometry
}
}
private class Line : IPathCommand
public class Line : IPathCommand
{
public PdfPoint From { get; }
@@ -216,7 +218,7 @@ namespace UglyToad.PdfPig.Geometry
}
}
internal class BezierCurve : IPathCommand
public class BezierCurve : IPathCommand
{
public PdfPoint StartPoint { get; }
@@ -379,6 +381,11 @@ namespace UglyToad.PdfPig.Geometry
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);
}
}
}

View File

@@ -48,7 +48,6 @@
};
public List<Letter> Letters = new List<Letter>();
public ContentStreamProcessor(PdfRectangle cropBox, IResourceStore resourceStore, UserSpaceUnit userSpaceUnit, PageRotationDegrees rotation, bool isLenientParsing,
IPdfTokenScanner pdfScanner,
XObjectFactory xObjectFactory,
@@ -70,7 +69,7 @@
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)
@@ -192,7 +191,7 @@
var textState = currentState.FontState;
var fontSize = textState.FontSize;
var horizontalScaling = textState.HorizontalScaling/100m;
var horizontalScaling = textState.HorizontalScaling / 100m;
var font = resourceStore.GetFont(textState.FontName);
var isVertical = font.IsVertical;
@@ -226,7 +225,7 @@
}
else
{
bytes = OtherEncodings.StringAsLatin1Bytes(((StringToken) token).Data);
bytes = OtherEncodings.StringAsLatin1Bytes(((StringToken)token).Data);
}
ShowText(new ByteArrayInputBytes(bytes));
@@ -267,6 +266,7 @@
public void BeginSubpath()
{
CurrentPath = new PdfPath();
CurrentPath.CurrentTransformationMatrix = GetCurrentState().CurrentTransformationMatrix;
}
public void StrokePath(bool close)
@@ -275,12 +275,21 @@
{
ClosePath();
}
paths.Add(CurrentPath);
}
public void FillPath(bool close)
{
if (close)
{
ClosePath();
}
paths.Add(CurrentPath);
}
public void ClosePath()
{
CurrentPath.ClosePath();
paths.Add(CurrentPath);
CurrentPath = null;
}
@@ -297,12 +306,12 @@
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))
{
currentGraphicsState.JoinStyle = (LineJoinStyle) ljToken.Int;
currentGraphicsState.JoinStyle = (LineJoinStyle)ljToken.Int;
}
if (state.TryGet(NameToken.Font, pdfScanner, out ArrayToken fontArray) && fontArray.Length == 2

View File

@@ -82,6 +82,12 @@
/// <param name="close">Whether to also close the path.</param>
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>
/// Close the current path.
/// </summary>

View File

@@ -28,6 +28,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(true);
}
/// <inheritdoc />

View File

@@ -28,6 +28,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(true);
}
/// <inheritdoc />

View File

@@ -28,6 +28,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(false);
}
/// <inheritdoc />

View File

@@ -28,6 +28,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(false);
}
/// <inheritdoc />

View File

@@ -29,6 +29,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(false);
}
/// <inheritdoc />

View File

@@ -28,6 +28,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(false);
}
/// <inheritdoc />

View File

@@ -29,6 +29,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.FillPath(false);
}
/// <inheritdoc />

View File

@@ -52,7 +52,7 @@
{
operationContext.BeginSubpath();
operationContext.CurrentPath.Rectangle(LowerLeft.X, LowerLeft.Y, Width, Height);
operationContext.CurrentPath.ClosePath();
//operationContext.CurrentPath.ClosePath();
}
/// <inheritdoc />

View File

@@ -37,6 +37,7 @@
{
operationContext.BeginSubpath();
operationContext.CurrentPosition = Point;
operationContext.CurrentPath.LineTo(Point.X, Point.Y);
}
/// <inheritdoc />