diff --git a/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs b/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs index 7f504d7c..033a2b95 100644 --- a/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs +++ b/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs @@ -10,7 +10,7 @@ [Fact] public void BezierCurveGeneratesCorrectBoundingBox() { - var curve = new CharacterPath.BezierCurve(new PdfPoint(60, 105), + var curve = new PdfPath.BezierCurve(new PdfPoint(60, 105), new PdfPoint(75, 30), new PdfPoint(215, 115), new PdfPoint(140, 160)); @@ -28,7 +28,7 @@ [Fact] public void LoopBezierCurveGeneratesCorrectBoundingBox() { - var curve = new CharacterPath.BezierCurve(new PdfPoint(166, 142), + var curve = new PdfPath.BezierCurve(new PdfPoint(166, 142), new PdfPoint(75, 30), new PdfPoint(215, 115), new PdfPoint(140, 160)); @@ -47,7 +47,7 @@ [Fact] public void BezierCurveAddsCorrectSvgCommand() { - var curve = new CharacterPath.BezierCurve(new PdfPoint(60, 105), + var curve = new PdfPath.BezierCurve(new PdfPoint(60, 105), new PdfPoint(75, 30), new PdfPoint(215, 115), new PdfPoint(140, 160)); diff --git a/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs b/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs index 7cc9d35e..3008f97f 100644 --- a/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs +++ b/src/UglyToad.PdfPig.Tests/Graphics/TestOperationContext.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Content; using PdfPig.Fonts; + using PdfPig.Geometry; using PdfPig.Graphics; using PdfPig.IO; using PdfPig.Tokens; @@ -17,9 +18,14 @@ public TextMatrices TextMatrices { get; set; } = new TextMatrices(); + public PdfPath CurrentPath { get; set; } + + public PdfPoint CurrentPosition { get; set; } + public TestOperationContext() { StateStack.Push(new CurrentGraphicsState()); + CurrentPath = new PdfPath(); } public CurrentGraphicsState GetCurrentState() @@ -48,6 +54,18 @@ public void ApplyXObject(StreamToken xObjectStream) { } + + public void BeginSubpath() + { + } + + public void StrokePath(bool close) + { + } + + public void ClosePath() + { + } } internal class TestResourceStore : IResourceStore diff --git a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs index 0a0cf329..3e3471f8 100644 --- a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs +++ b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs @@ -93,6 +93,14 @@ var page = builder.AddPage(PageSize.A4); + page.DrawLine(new PdfPoint(30, 520), new PdfPoint(360, 520)); + page.DrawLine(new PdfPoint(360, 520), new PdfPoint(360, 250)); + + page.DrawLine(new PdfPoint(25, 70), new PdfPoint(100, 70), 3); + + page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m); + page.DrawRectangle(new PdfPoint(30, 200), 250, 100, 0.5m); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts", "TrueType"); var file = Path.Combine(path, "Andada-Regular.ttf"); @@ -139,6 +147,8 @@ { var builder = new PdfDocumentBuilder(); + builder.DocumentInformation.Title = "Hello Windows!"; + var page = builder.AddPage(PageSize.A4); var file = @"C:\Windows\Fonts\BASKVILL.TTF"; diff --git a/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2BuildCharContext.cs b/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2BuildCharContext.cs index 864d82cd..c62e4553 100644 --- a/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2BuildCharContext.cs +++ b/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2BuildCharContext.cs @@ -18,7 +18,7 @@ /// /// The current path. /// - public CharacterPath Path { get; } = new CharacterPath(); + public PdfPath Path { get; } = new PdfPath(); /// /// The current location of the active point. diff --git a/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2CharStrings.cs b/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2CharStrings.cs index 2adba0bd..87a0c3dd 100644 --- a/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2CharStrings.cs +++ b/src/UglyToad.PdfPig/Fonts/CompactFontFormat/CharStrings/Type2CharStrings.cs @@ -46,7 +46,7 @@ /// Evaluate the CharString for the character with a given name returning the path constructed for the glyph. /// /// The name of the character to retrieve the CharString for. - /// A for the glyph. + /// A for the glyph. public Type2Glyph Generate(string name) { Type2Glyph glyph; @@ -171,7 +171,7 @@ /// The path of the glyph. /// [NotNull] - public CharacterPath Path { get; } + public PdfPath Path { get; } /// /// The width of the glyph as a difference from the nominal width X for the font. Optional. @@ -181,7 +181,7 @@ /// /// Create a new . /// - public Type2Glyph(CharacterPath path, decimal? widthDifferenceFromNominal) + public Type2Glyph(PdfPath path, decimal? widthDifferenceFromNominal) { Path = path ?? throw new ArgumentNullException(nameof(path)); WidthDifferenceFromNominal = widthDifferenceFromNominal; diff --git a/src/UglyToad.PdfPig/Fonts/CharacterPath.cs b/src/UglyToad.PdfPig/Fonts/PdfPath.cs similarity index 96% rename from src/UglyToad.PdfPig/Fonts/CharacterPath.cs rename to src/UglyToad.PdfPig/Fonts/PdfPath.cs index 17a501c1..81652ebd 100644 --- a/src/UglyToad.PdfPig/Fonts/CharacterPath.cs +++ b/src/UglyToad.PdfPig/Fonts/PdfPath.cs @@ -7,7 +7,7 @@ namespace UglyToad.PdfPig.Fonts using System.Text; using Geometry; - internal class CharacterPath + internal class PdfPath { private readonly List commands = new List(); private PdfPoint? currentPosition; @@ -239,8 +239,8 @@ namespace UglyToad.PdfPig.Fonts double maxX; if (StartPoint.X <= EndPoint.X) { - minX = (double) StartPoint.X; - maxX = (double) EndPoint.X; + minX = (double)StartPoint.X; + maxX = (double)EndPoint.X; } else { @@ -254,9 +254,9 @@ namespace UglyToad.PdfPig.Fonts { minY = (double)StartPoint.Y; maxY = (double)EndPoint.Y; - } - else - { + } + else + { minY = (double)EndPoint.Y; maxY = (double)StartPoint.Y; } @@ -294,7 +294,7 @@ namespace UglyToad.PdfPig.Fonts // P' = 3da(1-t)^2 + 6db(1-t)t + 3dct^2 // P' = 3da - 3dat - 3dat + 3dat^2 + 6dbt - 6dbt^2 + 3dct^2 // P' = (3da - 6db + 3dc)t^2 + (6db - 3da - 3da)t + 3da - var p1 = (double)( isX ? StartPoint.X : StartPoint.Y); + var p1 = (double)(isX ? StartPoint.X : StartPoint.Y); var p2 = (double)(isX ? FirstControlPoint.X : FirstControlPoint.Y); var p3 = (double)(isX ? SecondControlPoint.X : SecondControlPoint.Y); var p4 = (double)(isX ? EndPoint.X : EndPoint.Y); @@ -361,8 +361,8 @@ namespace UglyToad.PdfPig.Fonts // P = (1−t)^3*P_1 + 3(1−t)^2*t*P_2 + 3(1−t)*t^2*P_3 + t^3*P_4 var oneMinusT = 1 - t; var p = ((oneMinusT * oneMinusT * oneMinusT) * p1) - + (3 * (oneMinusT * oneMinusT) * t * p2) - + (3 * oneMinusT * (t * t) * p3) + + (3 * (oneMinusT * oneMinusT) * t * p2) + + (3 * oneMinusT * (t * t) * p3) + ((t * t * t) * p4); return p; @@ -374,5 +374,9 @@ namespace UglyToad.PdfPig.Fonts EndPoint.X, EndPoint.Y); } } + + public void Rectangle(decimal x, decimal y, decimal width, decimal height) + { + } } } diff --git a/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Commands/Type1BuildCharContext.cs b/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Commands/Type1BuildCharContext.cs index 2a0af378..29939308 100644 --- a/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Commands/Type1BuildCharContext.cs +++ b/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Commands/Type1BuildCharContext.cs @@ -7,7 +7,7 @@ internal class Type1BuildCharContext { - private readonly Func characterByIndexFactory; + private readonly Func characterByIndexFactory; public IReadOnlyDictionary Subroutines { get; } public decimal WidthX { get; set; } @@ -21,7 +21,7 @@ public bool IsFlexing { get; set; } [NotNull] - public CharacterPath Path { get; private set; } = new CharacterPath(); + public PdfPath Path { get; private set; } = new PdfPath(); public PdfPoint CurrentPosition { get; set; } @@ -32,7 +32,7 @@ public IReadOnlyList FlexPoints { get; } public Type1BuildCharContext(IReadOnlyDictionary subroutines, - Func characterByIndexFactory) + Func characterByIndexFactory) { this.characterByIndexFactory = characterByIndexFactory ?? throw new ArgumentNullException(nameof(characterByIndexFactory)); Subroutines = subroutines ?? throw new ArgumentNullException(nameof(subroutines)); @@ -43,12 +43,12 @@ } - public CharacterPath GetCharacter(int characterCode) + public PdfPath GetCharacter(int characterCode) { return characterByIndexFactory(characterCode); } - public void SetPath(CharacterPath path) + public void SetPath(PdfPath path) { Path = path ?? throw new ArgumentNullException(nameof(path)); } diff --git a/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Type1CharStrings.cs b/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Type1CharStrings.cs index 886393bb..ee8e641c 100644 --- a/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Type1CharStrings.cs +++ b/src/UglyToad.PdfPig/Fonts/Type1/CharStrings/Type1CharStrings.cs @@ -10,7 +10,7 @@ { private readonly IReadOnlyDictionary charStringIndexToName; private readonly object locker = new object(); - private readonly Dictionary glyphs = new Dictionary(); + private readonly Dictionary glyphs = new Dictionary(); public IReadOnlyDictionary CharStrings { get; } @@ -24,9 +24,9 @@ Subroutines = subroutines ?? throw new ArgumentNullException(nameof(subroutines)); } - public CharacterPath Generate(string name) + public PdfPath Generate(string name) { - CharacterPath glyph; + PdfPath glyph; lock (locker) { if (glyphs.TryGetValue(name, out var result)) @@ -47,7 +47,7 @@ return glyph; } - private CharacterPath Run(CommandSequence sequence) + private PdfPath Run(CommandSequence sequence) { var context = new Type1BuildCharContext(Subroutines, i => { diff --git a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs index 98e63c1f..4db29d77 100644 --- a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs +++ b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs @@ -16,6 +16,7 @@ internal class ContentStreamProcessor : IOperationContext { + private readonly List paths = new List(); private readonly IResourceStore resourceStore; private readonly UserSpaceUnit userSpaceUnit; private readonly bool isLenientParsing; @@ -26,6 +27,9 @@ public TextMatrices TextMatrices { get; } = new TextMatrices(); + public PdfPath CurrentPath { get; private set; } + public PdfPoint CurrentPosition { get; set; } + public int StackSize => graphicsStack.Count; private readonly Dictionary> xObjects = new Dictionary> @@ -73,7 +77,7 @@ graphicsStack.Push(saved.Peek().DeepClone()); return saved; } - + [DebuggerStepThrough] public CurrentGraphicsState GetCurrentState() { @@ -245,6 +249,26 @@ } } + public void BeginSubpath() + { + CurrentPath = new PdfPath(); + } + + public void StrokePath(bool close) + { + if (close) + { + ClosePath(); + } + } + + public void ClosePath() + { + CurrentPath.ClosePath(); + paths.Add(CurrentPath); + CurrentPath = null; + } + private void AdjustTextMatrix(decimal tx, decimal ty) { var matrix = TransformationMatrix.GetTranslationMatrix(tx, ty); diff --git a/src/UglyToad.PdfPig/Graphics/IOperationContext.cs b/src/UglyToad.PdfPig/Graphics/IOperationContext.cs index fd10f469..1f15aef9 100644 --- a/src/UglyToad.PdfPig/Graphics/IOperationContext.cs +++ b/src/UglyToad.PdfPig/Graphics/IOperationContext.cs @@ -1,11 +1,19 @@ namespace UglyToad.PdfPig.Graphics { using System.Collections.Generic; + using Fonts; + using Geometry; using IO; using Tokens; + using Util.JetBrains.Annotations; internal interface IOperationContext { + [CanBeNull] + PdfPath CurrentPath { get; } + + PdfPoint CurrentPosition { get; set; } + CurrentGraphicsState GetCurrentState(); TextMatrices TextMatrices { get; } @@ -21,5 +29,11 @@ void ShowPositionedText(IReadOnlyList tokens); void ApplyXObject(StreamToken xObjectStream); + + void BeginSubpath(); + + void StrokePath(bool close); + + void ClosePath(); } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs b/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs index ef46da5a..6c440852 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs @@ -17,11 +17,13 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.StrokePath(true); } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs index d57534ef..64b43465 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs @@ -25,7 +25,10 @@ public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(Width); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs index c81fa97f..e25d8e84 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs @@ -25,11 +25,28 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.CurrentPath.BezierCurveTo(ControlPoint1.X, ControlPoint1.Y, + ControlPoint2.X, ControlPoint2.Y, + End.X, End.Y); + operationContext.CurrentPosition = End; } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(ControlPoint1.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(ControlPoint1.Y); + stream.WriteWhiteSpace(); + stream.WriteDecimal(ControlPoint2.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(ControlPoint2.Y); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.Y); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs index 59c23f80..2972118b 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs @@ -22,11 +22,26 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.CurrentPath.BezierCurveTo(ControlPoint1.X, ControlPoint1.Y, + End.X, + End.Y, + End.X, + End.Y); + operationContext.CurrentPosition = End; } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(ControlPoint1.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(ControlPoint1.Y); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.Y); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs index fb8fbcc0..94e159dc 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs @@ -26,11 +26,23 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.BeginSubpath(); + operationContext.CurrentPath.Rectangle(LowerLeft.X, LowerLeft.Y, Width, Height); + operationContext.CurrentPath.ClosePath(); } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(LowerLeft.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(LowerLeft.Y); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Width); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Height); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs index 5bcdc54f..bc85f3cf 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs @@ -22,11 +22,27 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.CurrentPath.BezierCurveTo(operationContext.CurrentPosition.X, + operationContext.CurrentPosition.Y, + ControlPoint2.X, + ControlPoint2.Y, + End.X, + End.Y); + operationContext.CurrentPosition = End; } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(ControlPoint2.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(ControlPoint2.Y); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.Y); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs index 99d94a0c..33d485a8 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs @@ -19,11 +19,18 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.CurrentPath.LineTo(End.X, End.Y); + operationContext.CurrentPosition = End; } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(End.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(End.Y); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteWhiteSpace(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs index 3cc10131..ea0d3067 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs @@ -19,11 +19,18 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.BeginSubpath(); + operationContext.CurrentPosition = Point; } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteDecimal(Point.X); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Point.Y); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs index 3fee623b..2185c7f8 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs @@ -17,11 +17,13 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.CurrentPath.ClosePath(); } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs b/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs index 68ec1bc1..cfe54048 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs @@ -17,11 +17,13 @@ public void Run(IOperationContext operationContext, IResourceStore resourceStore) { + operationContext.StrokePath(false); } public void Write(Stream stream) { - throw new System.NotImplementedException(); + stream.WriteText(Symbol); + stream.WriteNewLine(); } public override string ToString() diff --git a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs index 24c0c65c..41c1a185 100644 --- a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs @@ -17,12 +17,15 @@ internal class PdfDocumentBuilder { - private const byte Break = (byte) '\n'; + private const byte Break = (byte)'\n'; private static readonly TrueTypeFontParser Parser = new TrueTypeFontParser(); private readonly Dictionary pages = new Dictionary(); private readonly Dictionary fonts = new Dictionary(); + public bool IncludeDocumentInformation { get; set; } = true; + public DocumentInformationBuilder DocumentInformation { get; } = new DocumentInformationBuilder(); + public IReadOnlyDictionary Pages => pages; public IReadOnlyDictionary Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram); @@ -219,7 +222,18 @@ var catalogRef = context.WriteObject(memory, catalog); - TokenWriter.WriteCrossReferenceTable(context.ObjectOffsets, catalogRef, memory); + var informationReference = default(IndirectReference?); + if (IncludeDocumentInformation) + { + var informationDictionary = DocumentInformation.ToDictionary(); + if (informationDictionary.Count > 0) + { + var dictionary = new DictionaryToken(informationDictionary); + informationReference = context.WriteObject(memory, dictionary).Number; + } + } + + TokenWriter.WriteCrossReferenceTable(context.ObjectOffsets, catalogRef, memory, informationReference); return memory.ToArray(); } @@ -257,7 +271,7 @@ new NumericToken(rectangle.TopRight.Y) }); } - + private static void WriteString(string text, MemoryStream stream, bool appendBreak = true) { var bytes = OtherEncodings.StringAsLatin1Bytes(text); @@ -295,5 +309,52 @@ Name = name ?? throw new ArgumentNullException(nameof(name)); } } + + internal class DocumentInformationBuilder + { + public string Title { get; set; } + public string Author { get; set; } + public string Subject { get; set; } + public string Keywords { get; set; } + public string Creator { get; set; } + public string Producer { get; set; } = "PdfPig"; + + internal Dictionary ToDictionary() + { + var result = new Dictionary(); + + if (Title != null) + { + result[NameToken.Title] = new StringToken(Title); + } + + if (Author != null) + { + result[NameToken.Author] = new StringToken(Author); + } + + if (Subject != null) + { + result[NameToken.Subject] = new StringToken(Subject); + } + + if (Keywords != null) + { + result[NameToken.Keywords] = new StringToken(Keywords); + } + + if (Creator != null) + { + result[NameToken.Creator] = new StringToken(Creator); + } + + if (Producer != null) + { + result[NameToken.Producer] = new StringToken(Producer); + } + + return result; + } + } } } diff --git a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs index f25adbc0..584ea3e9 100644 --- a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs @@ -6,6 +6,8 @@ using Core; using Geometry; using Graphics.Operations; + using Graphics.Operations.General; + using Graphics.Operations.PathConstruction; using Graphics.Operations.TextObjects; using Graphics.Operations.TextPositioning; using Graphics.Operations.TextShowing; @@ -28,6 +30,39 @@ PageNumber = number; } + public void DrawLine(PdfPoint from, PdfPoint to, decimal lineWidth = 1) + { + if (lineWidth != 1) + { + operations.Add(new SetLineWidth(lineWidth)); + } + + operations.Add(new BeginNewSubpath(from.X, from.Y)); + operations.Add(new AppendStraightLineSegment(to.X, to.Y)); + operations.Add(StrokePath.Value); + + if (lineWidth != 1) + { + operations.Add(new SetLineWidth(1)); + } + } + + public void DrawRectangle(PdfPoint position, decimal width, decimal height, decimal lineWidth = 1) + { + if (lineWidth != 1) + { + operations.Add(new SetLineWidth(lineWidth)); + } + + operations.Add(new AppendRectangle(position.X, position.Y, width, height)); + operations.Add(StrokePath.Value); + + if (lineWidth != 1) + { + operations.Add(new SetLineWidth(lineWidth)); + } + } + public List AddText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font) { if (font == null) diff --git a/src/UglyToad.PdfPig/Writer/TokenWriter.cs b/src/UglyToad.PdfPig/Writer/TokenWriter.cs index 82c5eb75..9b623080 100644 --- a/src/UglyToad.PdfPig/Writer/TokenWriter.cs +++ b/src/UglyToad.PdfPig/Writer/TokenWriter.cs @@ -2,6 +2,7 @@ { using System; using System.Collections.Generic; + using System.Collections.ObjectModel; using System.IO; using System.Linq; using Tokens; @@ -95,7 +96,8 @@ public static void WriteCrossReferenceTable(IReadOnlyDictionary objectOffsets, ObjectToken catalogToken, - Stream outputStream) + Stream outputStream, + IndirectReference? documentInformationReference) { if (objectOffsets.Count == 0) { @@ -150,11 +152,18 @@ outputStream.Write(Trailer, 0, Trailer.Length); WriteLineBreak(outputStream); - var trailerDictionary = new DictionaryToken(new Dictionary + var trailerDictionaryData = new Dictionary { - {NameToken.Size, new NumericToken(objectOffsets.Count) }, - {NameToken.Root, new IndirectReferenceToken(catalogToken.Number) } - }); + {NameToken.Size, new NumericToken(objectOffsets.Count)}, + {NameToken.Root, new IndirectReferenceToken(catalogToken.Number)} + }; + + if (documentInformationReference.HasValue) + { + trailerDictionaryData[NameToken.Info] = new IndirectReferenceToken(documentInformationReference.Value); + } + + var trailerDictionary = new DictionaryToken(trailerDictionaryData); WriteDictionary(trailerDictionary, outputStream); WriteLineBreak(outputStream);