Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using PdfPig.Graphics;
using PdfPig.IO;
using PdfPig.Tokens;
using UglyToad.PdfPig.Core;

internal class TestOperationContext : IOperationContext
{
Expand All @@ -16,6 +17,11 @@ internal class TestOperationContext : IOperationContext
public TextMatrices TextMatrices { get; set; }
= new TextMatrices();

public TransformationMatrix CurrentTransformationMatrix
{
get { return GetCurrentState().CurrentTransformationMatrix; }
}

public PdfPath CurrentPath { get; set; }

public IColorspaceContext ColorspaceContext { get; } = new ColorspaceContext();
Expand All @@ -25,7 +31,7 @@ internal class TestOperationContext : IOperationContext
public TestOperationContext()
{
StateStack.Push(new CurrentGraphicsState());
CurrentPath = new PdfPath();
CurrentPath = new PdfPath(CurrentTransformationMatrix);
}

public CurrentGraphicsState GetCurrentState()
Expand Down Expand Up @@ -62,6 +68,9 @@ public void BeginSubpath()
public void StrokePath(bool close)
{
}
public void FillPath(bool close)
{
}

public void ClosePath()
{
Expand Down
8 changes: 7 additions & 1 deletion src/UglyToad.PdfPig/Content/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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"/>.
Expand Down Expand Up @@ -41,6 +42,11 @@ public class Page
/// </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 IReadOnlyList<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>
Expand Down Expand Up @@ -165,4 +171,4 @@ public decimal GetPointSize(Letter letter)
}
}
}
}
}
5 changes: 4 additions & 1 deletion src/UglyToad.PdfPig/Content/PageContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Graphics.Operations;
using Tokenization.Scanner;
using XObjects;
using UglyToad.PdfPig.Geometry;

/// <summary>
///
Expand All @@ -23,15 +24,17 @@ internal class PageContent
internal IReadOnlyList<IGraphicsStateOperation> GraphicsStateOperations { get; }

public IReadOnlyList<Letter> Letters { get; }
public IReadOnlyList<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,
bool isLenientParsing)
{
GraphicsStateOperations = graphicsStateOperations;
Letters = letters;
Paths = paths;
this.xObjects = xObjects;
this.pdfScanner = pdfScanner;
this.xObjectFactory = xObjectFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
internal class Type2BuildCharContext
{
private readonly Dictionary<int, decimal> transientArray = new Dictionary<int, decimal>();

/// <summary>
/// The numbers currently on the Type 2 Build Char stack.
/// </summary>
Expand All @@ -18,7 +18,7 @@ internal class Type2BuildCharContext
/// <summary>
/// The current path.
/// </summary>
public PdfPath Path { get; } = new PdfPath();
public PdfPath Path { get; } = new PdfPath(Core.TransformationMatrix.Identity);

/// <summary>
/// The current location of the active point.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal class Type1BuildCharContext
public bool IsFlexing { get; set; }

[NotNull]
public PdfPath Path { get; private set; } = new PdfPath();
public PdfPath Path { get; private set; } = new PdfPath(Core.TransformationMatrix.Identity);

public PdfPoint CurrentPosition { get; set; }

Expand Down Expand Up @@ -63,7 +63,7 @@ public void SetPath(PdfPath path)

public void ClearFlexPoints()
{

}
}
}
30 changes: 22 additions & 8 deletions src/UglyToad.PdfPig/Geometry/PdfPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,35 @@ 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 IReadOnlyList<IPathCommand> Commands => commands;

private PdfPoint? currentPosition;
private TransformationMatrix currentTransformationMatrix = TransformationMatrix.Identity;

public PdfPath(TransformationMatrix transformationMatrix)
{
currentTransformationMatrix = transformationMatrix;
}

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));
}

internal void LineTo(decimal x, decimal y)
{
if (currentPosition.HasValue)
{
var to = new PdfPoint(x, y);
var to = currentTransformationMatrix.Transform(new PdfPoint(x, y));
commands.Add(new Line(currentPosition.Value, to));
currentPosition = to;
}
Expand All @@ -40,9 +49,9 @@ internal void BezierCurveTo(decimal x1, decimal y1, decimal x2, decimal y2, deci
{
if (currentPosition.HasValue)
{
var to = new PdfPoint(x3, y3);
var to = currentTransformationMatrix.Transform(new PdfPoint(x3, y3));
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;
}
else
Expand Down Expand Up @@ -153,7 +162,7 @@ string BboxToRect(PdfRectangle box, string stroke)
return result;
}

internal interface IPathCommand
public interface IPathCommand
{
PdfRectangle? GetBoundingRectangle();

Expand All @@ -173,7 +182,7 @@ public void WriteSvg(StringBuilder builder)
}
}

private class Move : IPathCommand
public class Move : IPathCommand
{
public PdfPoint Location { get; }

Expand All @@ -193,7 +202,7 @@ public void WriteSvg(StringBuilder builder)
}
}

private class Line : IPathCommand
public class Line : IPathCommand
{
public PdfPoint From { get; }

Expand All @@ -216,7 +225,7 @@ public void WriteSvg(StringBuilder builder)
}
}

internal class BezierCurve : IPathCommand
public class BezierCurve : IPathCommand
{
public PdfPoint StartPoint { get; }

Expand Down Expand Up @@ -379,6 +388,11 @@ public void WriteSvg(StringBuilder builder)

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);
}
}
}
43 changes: 28 additions & 15 deletions src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ internal class ContentStreamProcessor : IOperationContext

public TextMatrices TextMatrices { get; } = new TextMatrices();

public TransformationMatrix CurrentTransformationMatrix
{
get { return GetCurrentState().CurrentTransformationMatrix; }
}

public PdfPath CurrentPath { get; private set; }

public IColorspaceContext ColorspaceContext { get; } = new ColorspaceContext();
Expand All @@ -48,8 +53,7 @@ internal class ContentStreamProcessor : IOperationContext
};

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,
XObjectFactory xObjectFactory,
ILog log)
Expand All @@ -69,8 +73,8 @@ public PageContent Process(IReadOnlyList<IGraphicsStateOperation> operations)
var currentState = CloneAllStates();

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)
Expand All @@ -88,7 +92,7 @@ private Stack<CurrentGraphicsState> CloneAllStates()
graphicsStack.Push(saved.Peek().DeepClone());
return saved;
}

[DebuggerStepThrough]
public CurrentGraphicsState GetCurrentState()
{
Expand Down Expand Up @@ -116,7 +120,7 @@ public void ShowText(IInputBytes bytes)
{
throw new InvalidOperationException($"Could not find the font with name {currentState.FontState.FontName} in the resource store. It has not been loaded yet.");
}

var fontSize = currentState.FontState.FontSize;
var horizontalScaling = currentState.FontState.HorizontalScaling / 100m;
var characterSpacing = currentState.FontState.CharacterSpacing;
Expand All @@ -130,7 +134,7 @@ public void ShowText(IInputBytes bytes)
// TODO: this does not seem correct, produces the correct result for now but we need to revisit.
// see: https://stackoverflow.com/questions/48010235/pdf-specification-get-font-size-in-points
var pointSize = decimal.Round(rotation.Rotate(transformationMatrix).Multiply(TextMatrices.TextMatrix).Multiply(fontSize).A, 2);

while (bytes.MoveNext())
{
var code = font.ReadCharacterCode(bytes, out int codeLength);
Expand All @@ -149,7 +153,7 @@ public void ShowText(IInputBytes bytes)
{
wordSpacing += GetCurrentState().FontState.WordSpacing;
}

if (font.IsVertical)
{
throw new NotImplementedException("Vertical fonts are currently unsupported, please submit a pull request or issue with an example file.");
Expand Down Expand Up @@ -192,7 +196,7 @@ public void ShowPositionedText(IReadOnlyList<IToken> tokens)
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;
Expand Down Expand Up @@ -226,7 +230,7 @@ public void ShowPositionedText(IReadOnlyList<IToken> tokens)
}
else
{
bytes = OtherEncodings.StringAsLatin1Bytes(((StringToken) token).Data);
bytes = OtherEncodings.StringAsLatin1Bytes(((StringToken)token).Data);
}

ShowText(new ByteArrayInputBytes(bytes));
Expand All @@ -248,7 +252,7 @@ public void ApplyXObject(NameToken xObjectName)

if (subType.Equals(NameToken.Ps))
{
xObjects[XObjectType.PostScript].Add(new XObjectContentRecord(XObjectType.PostScript, xObjectStream, matrix));
xObjects[XObjectType.PostScript].Add(new XObjectContentRecord(XObjectType.PostScript, xObjectStream, matrix));
}
else if (subType.Equals(NameToken.Image))
{
Expand All @@ -266,7 +270,7 @@ public void ApplyXObject(NameToken xObjectName)

public void BeginSubpath()
{
CurrentPath = new PdfPath();
CurrentPath = new PdfPath(CurrentTransformationMatrix);
}

public void StrokePath(bool close)
Expand All @@ -275,12 +279,21 @@ public void StrokePath(bool close)
{
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;
}

Expand All @@ -297,12 +310,12 @@ public void SetNamedGraphicsState(NameToken stateName)

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
Expand Down
Loading