From d6a896dcb041b12396df85298cbde3653c33be7a Mon Sep 17 00:00:00 2001 From: Eliot Jones Date: Sun, 2 Dec 2018 16:14:55 +0000 Subject: [PATCH] #21 enable document creation using standard 14 font to test output --- .../Writer/PdfDocumentBuilderTests.cs | 23 ++++ src/UglyToad.PdfPig/Fonts/Standard14.cs | 62 +++++++--- .../ModifyClippingByEvenOddIntersect.cs | 6 + ...ModifyClippingByNonZeroWindingIntersect.cs | 6 + .../Graphics/Operations/CloseAndStrokePath.cs | 6 + .../CloseFillPathEvenOddRuleAndStroke.cs | 6 + .../CloseFillPathNonZeroWindingAndStroke.cs | 6 + .../Graphics/Operations/EndPath.cs | 6 + .../Operations/FillPathEvenOddRule.cs | 6 + .../FillPathEvenOddRuleAndStroke.cs | 6 + .../Operations/FillPathNonZeroWinding.cs | 6 + .../FillPathNonZeroWindingAndStroke.cs | 6 + .../FillPathNonZeroWindingCompatibility.cs | 6 + .../General/SetColorRenderingIntent.cs | 6 + .../General/SetFlatnessTolerance.cs | 6 + .../Graphics/Operations/General/SetLineCap.cs | 6 + .../Operations/General/SetLineDashPattern.cs | 6 + .../Operations/General/SetLineJoin.cs | 6 + .../Operations/General/SetLineWidth.cs | 6 + .../Operations/General/SetMiterLimit.cs | 6 + .../Operations/IGraphicsStateOperation.cs | 3 + .../Graphics/Operations/InvokeNamedXObject.cs | 6 + .../Operations/OperationWriteHelper.cs | 32 +++++ .../AppendDualControlPointBezierCurve.cs | 6 + .../AppendEndControlPointBezierCurve.cs | 6 + .../PathConstruction/AppendRectangle.cs | 6 + .../AppendStartControlPointBezierCurve.cs | 6 + .../AppendStraightLineSegment.cs | 6 + .../PathConstruction/BeginNewSubpath.cs | 6 + .../PathConstruction/CloseSubpath.cs | 6 + .../Operations/SetNonStrokeColorDeviceCmyk.cs | 6 + .../Operations/SetNonStrokeColorDeviceGray.cs | 6 + .../Operations/SetNonStrokeColorDeviceRgb.cs | 6 + .../Operations/SetStrokeColorDeviceCmyk.cs | 6 + .../Operations/SetStrokeColorDeviceGray.cs | 6 + .../Operations/SetStrokeColorDeviceRgb.cs | 6 + .../ModifyCurrentTransformationMatrix.cs | 19 +++ .../Operations/SpecialGraphicsState/Pop.cs | 6 + .../Operations/SpecialGraphicsState/Push.cs | 6 + .../Graphics/Operations/StrokePath.cs | 6 + .../Operations/TextObjects/BeginText.cs | 7 ++ .../Operations/TextObjects/EndText.cs | 7 ++ .../TextPositioning/MoveToNextLine.cs | 6 + .../MoveToNextLineWithOffset.cs | 11 ++ .../MoveToNextLineWithOffsetSetLeading.cs | 6 + .../TextPositioning/SetTextMatrix.cs | 6 + .../TextShowing/MoveToNextLineShowText.cs | 6 + .../MoveToNextLineShowTextWithSpacing.cs | 6 + .../Operations/TextShowing/ShowText.cs | 15 +++ .../TextShowing/ShowTextsWithPositioning.cs | 6 + .../TextState/SetCharacterSpacing.cs | 6 + .../Operations/TextState/SetFontAndSize.cs | 11 ++ .../TextState/SetHorizontalScaling.cs | 6 + .../Operations/TextState/SetTextLeading.cs | 6 + .../TextState/SetTextRenderingMode.cs | 6 + .../Operations/TextState/SetTextRise.cs | 6 + .../Operations/TextState/SetWordSpacing.cs | 6 + src/UglyToad.PdfPig/Writer/IWritingFont.cs | 15 +++ .../Writer/PdfDocumentBuilder.cs | 109 ++++++++++++------ src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs | 13 +-- .../Writer/Standard14WritingFont.cs | 47 ++++++++ src/UglyToad.PdfPig/Writer/TokenWriter.cs | 19 ++- .../Writer/TrueTypeWritingFont.cs | 33 ++++++ 63 files changed, 646 insertions(+), 62 deletions(-) create mode 100644 src/UglyToad.PdfPig/Graphics/Operations/OperationWriteHelper.cs create mode 100644 src/UglyToad.PdfPig/Writer/IWritingFont.cs create mode 100644 src/UglyToad.PdfPig/Writer/Standard14WritingFont.cs create mode 100644 src/UglyToad.PdfPig/Writer/TrueTypeWritingFont.cs diff --git a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs index 6a51545e..36f9fb23 100644 --- a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs +++ b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs @@ -2,7 +2,9 @@ { using System; using System.IO; + using System.Linq; using Content; + using PdfPig.Fonts; using PdfPig.Geometry; using PdfPig.Util; using PdfPig.Writer; @@ -59,6 +61,27 @@ return result; } + [Fact] + public void CanWriteSinglePageStandard14FontHelloWorld() + { + var builder = new PdfDocumentBuilder(); + + var page = builder.AddPage(PageSize.A4); + + var font = builder.AddStandard14Font(Standard14Font.Helvetica); + + page.AddText("Hello World!", 12, new PdfPoint(25, 520), font); + + var b = builder.Build(); + + using (var document = PdfDocument.Open(b)) + { + var page1 = document.GetPage(1); + + Assert.Equal(new[] {"Hello", "World!"}, page1.GetWords().Select(x => x.Text)); + } + } + [Fact] public void CanWriteSinglePageHelloWorld() { diff --git a/src/UglyToad.PdfPig/Fonts/Standard14.cs b/src/UglyToad.PdfPig/Fonts/Standard14.cs index 7af0946e..b9a6febb 100644 --- a/src/UglyToad.PdfPig/Fonts/Standard14.cs +++ b/src/UglyToad.PdfPig/Fonts/Standard14.cs @@ -36,23 +36,24 @@ private static readonly HashSet Standard14Names = new HashSet(); private static readonly Dictionary Standard14Mapping = new Dictionary(34); private static readonly Dictionary Standard14AfmMap = new Dictionary(34); + private static readonly Dictionary Standard14AfmTypeMap = new Dictionary(14); static Standard14() { - AddAdobeFontMetrics("Courier-Bold"); - AddAdobeFontMetrics("Courier-BoldOblique"); - AddAdobeFontMetrics("Courier"); - AddAdobeFontMetrics("Courier-Oblique"); - AddAdobeFontMetrics("Helvetica"); - AddAdobeFontMetrics("Helvetica-Bold"); - AddAdobeFontMetrics("Helvetica-BoldOblique"); - AddAdobeFontMetrics("Helvetica-Oblique"); - AddAdobeFontMetrics("Symbol"); - AddAdobeFontMetrics("Times-Bold"); - AddAdobeFontMetrics("Times-BoldItalic"); - AddAdobeFontMetrics("Times-Italic"); - AddAdobeFontMetrics("Times-Roman"); - AddAdobeFontMetrics("ZapfDingbats"); + AddAdobeFontMetrics("Courier-Bold", Standard14Font.CourierBold); + AddAdobeFontMetrics("Courier-BoldOblique", Standard14Font.CourierBoldOblique); + AddAdobeFontMetrics("Courier", Standard14Font.Courier); + AddAdobeFontMetrics("Courier-Oblique", Standard14Font.CourierOblique); + AddAdobeFontMetrics("Helvetica", Standard14Font.Helvetica); + AddAdobeFontMetrics("Helvetica-Bold", Standard14Font.HelveticaBold); + AddAdobeFontMetrics("Helvetica-BoldOblique", Standard14Font.HelveticaBoldOblique); + AddAdobeFontMetrics("Helvetica-Oblique", Standard14Font.HelveticaOblique); + AddAdobeFontMetrics("Symbol", Standard14Font.Symbol); + AddAdobeFontMetrics("Times-Bold", Standard14Font.TimesBold); + AddAdobeFontMetrics("Times-BoldItalic", Standard14Font.TimesBoldItalic); + AddAdobeFontMetrics("Times-Italic", Standard14Font.TimesItalic); + AddAdobeFontMetrics("Times-Roman", Standard14Font.TimesRoman); + AddAdobeFontMetrics("ZapfDingbats", Standard14Font.ZapfDingbats); // alternative names from Adobe Supplement to the ISO 32000 AddAdobeFontMetrics("CourierCourierNew", "Courier"); @@ -79,12 +80,12 @@ AddAdobeFontMetrics("Times,BoldItalic", "Times-BoldItalic"); } - private static void AddAdobeFontMetrics(string fontName) + private static void AddAdobeFontMetrics(string fontName, Standard14Font? type = null) { - AddAdobeFontMetrics(fontName, fontName); + AddAdobeFontMetrics(fontName, fontName, type); } - private static void AddAdobeFontMetrics(string fontName, string afmName) + private static void AddAdobeFontMetrics(string fontName, string afmName, Standard14Font? type = null) { Standard14Names.Add(fontName); Standard14Mapping.Add(fontName, afmName); @@ -109,6 +110,10 @@ } Standard14AfmMap[fontName] = Parser.Parse(bytes, true); + if (type.HasValue) + { + Standard14AfmTypeMap[type.Value] = Standard14AfmMap[fontName]; + } } catch (Exception ex) { @@ -127,6 +132,11 @@ return metrics; } + + public static FontMetrics GetAdobeFontMetrics(Standard14Font fontType) + { + return Standard14AfmTypeMap[fontType]; + } /// /// Determines if a font with this name is a standard 14 font. @@ -157,4 +167,22 @@ return mappedName; } } + + internal enum Standard14Font + { + TimesRoman = 0, + TimesBold = 1, + TimesItalic=2, + TimesBoldItalic = 3, + Helvetica = 4, + HelveticaBold = 5, + HelveticaOblique = 6, + HelveticaBoldOblique = 7, + Courier = 8, + CourierBold = 9, + CourierOblique = 10, + CourierBoldOblique = 11, + Symbol = 12, + ZapfDingbats = 13 + } } diff --git a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs index 513f0ed5..47dacf88 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.ClippingPaths { + using System.IO; using Content; internal class ModifyClippingByEvenOddIntersect : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs index 57afc6f6..734d7312 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.ClippingPaths { + using System.IO; using Content; internal class ModifyClippingByNonZeroWindingIntersect : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs b/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs index 8571254d..ef46da5a 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/CloseAndStrokePath.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class CloseAndStrokePath : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathEvenOddRuleAndStroke.cs b/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathEvenOddRuleAndStroke.cs index 7c2f4bf0..db2c8d8b 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathEvenOddRuleAndStroke.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathEvenOddRuleAndStroke.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class CloseFillPathEvenOddRuleAndStroke : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathNonZeroWindingAndStroke.cs b/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathNonZeroWindingAndStroke.cs index e07f1367..f6dfbdc6 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathNonZeroWindingAndStroke.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/CloseFillPathNonZeroWindingAndStroke.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class CloseFillPathNonZeroWindingAndStroke : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/EndPath.cs b/src/UglyToad.PdfPig/Graphics/Operations/EndPath.cs index 3d916e7c..178bb53c 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/EndPath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/EndPath.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class EndPath : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRule.cs b/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRule.cs index b5c9c04d..c4e33de3 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRule.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRule.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class FillPathEvenOddRule : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRuleAndStroke.cs b/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRuleAndStroke.cs index 60b8b999..c86fb06b 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRuleAndStroke.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/FillPathEvenOddRuleAndStroke.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class FillPathEvenOddRuleAndStroke : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWinding.cs b/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWinding.cs index fdd01db6..aa6731f0 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWinding.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWinding.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class FillPathNonZeroWinding : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingAndStroke.cs b/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingAndStroke.cs index 3ae85f27..1ce7d630 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingAndStroke.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingAndStroke.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class FillPathNonZeroWindingAndStroke : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingCompatibility.cs b/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingCompatibility.cs index 00016866..ee9bcffb 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingCompatibility.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/FillPathNonZeroWindingCompatibility.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class FillPathNonZeroWindingCompatibility : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetColorRenderingIntent.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetColorRenderingIntent.cs index 3dddbfc0..68322bb9 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetColorRenderingIntent.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetColorRenderingIntent.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { + using System.IO; using Content; internal class SetColorRenderingIntent : IGraphicsStateOperation @@ -12,5 +13,10 @@ { } + + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetFlatnessTolerance.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetFlatnessTolerance.cs index 1e0fa395..a115d176 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetFlatnessTolerance.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetFlatnessTolerance.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { + using System.IO; using Content; internal class SetFlatnessTolerance : IGraphicsStateOperation @@ -20,6 +21,11 @@ operationContext.GetCurrentState().Flatness = Tolerance; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Tolerance} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineCap.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineCap.cs index c5646f4b..a06676ba 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineCap.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineCap.cs @@ -1,6 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { using System; + using System.IO; using Content; using Core; @@ -28,6 +29,11 @@ operationContext.GetCurrentState().CapStyle = Cap; } + public void Write(Stream stream) + { + throw new NotImplementedException(); + } + public override string ToString() { return $"{(int) Cap} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineDashPattern.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineDashPattern.cs index a2bb4203..e421ae25 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineDashPattern.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineDashPattern.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { + using System.IO; using Content; using Core; @@ -21,6 +22,11 @@ operationContext.GetCurrentState().LineDashPattern = Pattern; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Pattern.Array} {Pattern.Phase} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineJoin.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineJoin.cs index 4df284b9..f9a56738 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineJoin.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineJoin.cs @@ -1,6 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { using System; + using System.IO; using Content; using Core; @@ -28,6 +29,11 @@ operationContext.GetCurrentState().JoinStyle = Join; } + public void Write(Stream stream) + { + throw new NotImplementedException(); + } + public override string ToString() { return $"{(int)Join} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs index ebf214d3..d57534ef 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetLineWidth.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { + using System.IO; using Content; internal class SetLineWidth : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.LineWidth = Width; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Width} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/General/SetMiterLimit.cs b/src/UglyToad.PdfPig/Graphics/Operations/General/SetMiterLimit.cs index aea4cb9d..16ab2e10 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/General/SetMiterLimit.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/General/SetMiterLimit.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.General { + using System.IO; using Content; internal class SetMiterLimit : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.MiterLimit = Limit; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Limit} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/IGraphicsStateOperation.cs b/src/UglyToad.PdfPig/Graphics/Operations/IGraphicsStateOperation.cs index 3c11e5d6..eb64f639 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/IGraphicsStateOperation.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/IGraphicsStateOperation.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal interface IGraphicsStateOperation @@ -7,5 +8,7 @@ string Operator { get; } void Run(IOperationContext operationContext, IResourceStore resourceStore); + + void Write(Stream stream); } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Graphics/Operations/InvokeNamedXObject.cs b/src/UglyToad.PdfPig/Graphics/Operations/InvokeNamedXObject.cs index a9772135..6f63ed90 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/InvokeNamedXObject.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/InvokeNamedXObject.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; using Tokens; @@ -23,6 +24,11 @@ operationContext.ApplyXObject(xobject); } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Name} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/OperationWriteHelper.cs b/src/UglyToad.PdfPig/Graphics/Operations/OperationWriteHelper.cs new file mode 100644 index 00000000..6734dbe1 --- /dev/null +++ b/src/UglyToad.PdfPig/Graphics/Operations/OperationWriteHelper.cs @@ -0,0 +1,32 @@ +namespace UglyToad.PdfPig.Graphics.Operations +{ + using System.IO; + using Util; + + internal static class OperationWriteHelper + { + private static readonly byte WhiteSpace = OtherEncodings.StringAsLatin1Bytes(" ")[0]; + private static readonly byte NewLine = OtherEncodings.StringAsLatin1Bytes("\n")[0]; + + public static void WriteText(this Stream stream, string text) + { + var bytes = OtherEncodings.StringAsLatin1Bytes(text); + stream.Write(bytes, 0, bytes.Length); + } + + public static void WriteWhiteSpace(this Stream stream) + { + stream.WriteByte(WhiteSpace); + } + + public static void WriteNewLine(this Stream stream) + { + stream.WriteByte(NewLine); + } + + public static void WriteDecimal(this Stream stream, decimal value) + { + stream.WriteText(value.ToString("G")); + } + } +} diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs index 7fa29d61..c81fa97f 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; using Geometry; @@ -26,6 +27,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{ControlPoint1.X} {ControlPoint1.Y} {ControlPoint2.X} {ControlPoint2.Y} {End.X} {End.Y} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs index e8773b26..59c23f80 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; using Geometry; @@ -23,6 +24,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{ControlPoint1.X} {ControlPoint1.Y} {End.X} {End.Y} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs index 0b311c9f..fb8fbcc0 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendRectangle.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; using Geometry; @@ -27,6 +28,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{LowerLeft.X} {LowerLeft.Y} {Width} {Height} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs index 8f683ea4..5bcdc54f 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; using Geometry; @@ -23,6 +24,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{ControlPoint2.X} {ControlPoint2.Y} {End.X} {End.Y} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs index a1028a17..99d94a0c 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; using Geometry; @@ -20,6 +21,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{End.X} {End.Y} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs index db51e375..3cc10131 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/BeginNewSubpath.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; using Geometry; @@ -20,6 +21,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Point.X} {Point.Y} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs index 3c7e261f..3fee623b 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction { + using System.IO; using Content; internal class CloseSubpath : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceCmyk.cs b/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceCmyk.cs index e862a1c5..9d6fde55 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceCmyk.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceCmyk.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class SetNonStrokeColorDeviceCmyk : IGraphicsStateOperation @@ -28,6 +29,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{C} {M} {Y} {K} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceGray.cs b/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceGray.cs index 71bac4ce..e0b3332b 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceGray.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceGray.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class SetNonStrokeColorDeviceGray : IGraphicsStateOperation @@ -19,6 +20,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Gray} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceRgb.cs b/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceRgb.cs index 9509807b..dd2cf2c8 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceRgb.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SetNonStrokeColorDeviceRgb.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class SetNonStrokeColorDeviceRgb : IGraphicsStateOperation @@ -25,6 +26,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{R} {G} {B} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceCmyk.cs b/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceCmyk.cs index 932a2da8..de8db880 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceCmyk.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceCmyk.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class SetStrokeColorDeviceCmyk : IGraphicsStateOperation @@ -28,6 +29,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{C} {M} {Y} {K} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceGray.cs b/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceGray.cs index e6e2ff78..1d0335c4 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceGray.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceGray.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class SetStrokeColorDeviceGray : IGraphicsStateOperation @@ -19,6 +20,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Gray} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceRgb.cs b/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceRgb.cs index 852943a8..7cd02c2e 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceRgb.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SetStrokeColorDeviceRgb.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class SetStrokeColorDeviceRgb : IGraphicsStateOperation @@ -25,6 +26,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{R} {G} {B} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/ModifyCurrentTransformationMatrix.cs b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/ModifyCurrentTransformationMatrix.cs index b3c0563c..3ab91225 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/ModifyCurrentTransformationMatrix.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/ModifyCurrentTransformationMatrix.cs @@ -1,6 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState { using System; + using System.IO; using Content; using PdfPig.Core; @@ -37,6 +38,24 @@ operationContext.GetCurrentState().CurrentTransformationMatrix = newCtm; } + public void Write(Stream stream) + { + stream.WriteDecimal(Value[0]); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Value[1]); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Value[2]); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Value[3]); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Value[4]); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Value[5]); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); + } + public override string ToString() { return $"{Value[0]} {Value[1]} {Value[2]} {Value[3]} {Value[4]} {Value[5]} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Pop.cs b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Pop.cs index c69309d0..1a5eb3bf 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Pop.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Pop.cs @@ -1,6 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState { using System; + using System.IO; using Content; internal class Pop : IGraphicsStateOperation @@ -27,6 +28,11 @@ } } + public void Write(Stream stream) + { + throw new NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Push.cs b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Push.cs index c0c3a8b7..52f44f9c 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Push.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/Push.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState { + using System.IO; using Content; internal class Push : IGraphicsStateOperation @@ -22,5 +23,10 @@ { context.PushState(); } + + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } } } diff --git a/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs b/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs index fa448f32..68ec1bc1 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/StrokePath.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations { + using System.IO; using Content; internal class StrokePath : IGraphicsStateOperation @@ -18,6 +19,11 @@ { } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/BeginText.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/BeginText.cs index f1925709..48b5e428 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/BeginText.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/BeginText.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextObjects { + using System.IO; using Content; using PdfPig.Core; @@ -20,6 +21,12 @@ operationContext.TextMatrices.TextLineMatrix = TransformationMatrix.Identity; } + public void Write(Stream stream) + { + stream.WriteText(Symbol); + stream.WriteNewLine(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/EndText.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/EndText.cs index 4a6171ca..c8d2c88f 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/EndText.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextObjects/EndText.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextObjects { + using System.IO; using Content; using PdfPig.Core; @@ -20,6 +21,12 @@ operationContext.TextMatrices.TextLineMatrix = TransformationMatrix.Identity; } + public void Write(Stream stream) + { + stream.WriteText(Symbol); + stream.WriteNewLine(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLine.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLine.cs index 9efe8a96..06162fd6 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLine.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLine.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning { + using System.IO; using Content; /// @@ -27,6 +28,11 @@ tdOperation.Run(operationContext, resourceStore); } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return Symbol; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs index 4be2a7f6..985ad13f 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning { + using System.IO; using Content; using PdfPig.Core; @@ -40,6 +41,16 @@ operationContext.TextMatrices.TextMatrix = transformed; } + public void Write(Stream stream) + { + stream.WriteDecimal(Tx); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Ty); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); + } + public override string ToString() { return $"{Tx} {Ty} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs index 81de01b0..c7d53f4a 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning { + using System.IO; using Content; using TextState; @@ -30,6 +31,11 @@ tdOperation.Run(operationContext, resourceStore); } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Tx} {Ty} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/SetTextMatrix.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/SetTextMatrix.cs index 2dfc9d6b..0f102ef3 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/SetTextMatrix.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextPositioning/SetTextMatrix.cs @@ -1,6 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning { using System; + using System.IO; using Content; using PdfPig.Core; @@ -30,6 +31,11 @@ operationContext.TextMatrices.TextLineMatrix = newMatrix; } + public void Write(Stream stream) + { + throw new NotImplementedException(); + } + public override string ToString() { return $"{Value[0]} {Value[1]} {Value[2]} {Value[3]} {Value[4]} {Value[5]} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs index a0363398..979a00c8 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextShowing { + using System.IO; using Content; using TextPositioning; using Util.JetBrains.Annotations; @@ -36,6 +37,11 @@ showText.Run(operationContext, resourceStore); } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Text} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs index d72aff33..be141740 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextShowing { + using System.IO; using Content; using TextPositioning; using TextState; @@ -48,6 +49,11 @@ showText.Run(operationContext, resourceStore); } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{WordSpacing} {CharacterSpacing} {Text} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowText.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowText.cs index 8a06f804..a249d839 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowText.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowText.cs @@ -1,5 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextShowing { + using System; + using System.IO; using Content; using IO; using Util; @@ -50,6 +52,19 @@ operationContext.ShowText(input); } + public void Write(Stream stream) + { + if (Text == null && Bytes != null) + { + throw new NotImplementedException("Support for writing hex not done yet."); + } + + stream.WriteText($"({Text})"); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); + } + public override string ToString() { return $"{Text} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs index 173649dd..9e135e63 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs @@ -2,6 +2,7 @@ { using System; using System.Collections.Generic; + using System.IO; using Content; using Tokens; @@ -36,5 +37,10 @@ { operationContext.ShowPositionedText(Array); } + + public void Write(Stream stream) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetCharacterSpacing.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetCharacterSpacing.cs index 913af09d..72f8dd80 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetCharacterSpacing.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetCharacterSpacing.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { + using System.IO; using Content; internal class SetCharacterSpacing : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.FontState.CharacterSpacing = Spacing; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Spacing} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetFontAndSize.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetFontAndSize.cs index eb905b1f..5be81a85 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetFontAndSize.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetFontAndSize.cs @@ -1,6 +1,7 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { using System; + using System.IO; using Content; using Tokens; using Util.JetBrains.Annotations; @@ -37,6 +38,16 @@ currentState.FontState.FontName = Font; } + public void Write(Stream stream) + { + stream.WriteText(Font.ToString()); + stream.WriteWhiteSpace(); + stream.WriteDecimal(Size); + stream.WriteWhiteSpace(); + stream.WriteText(Symbol); + stream.WriteNewLine(); + } + public override string ToString() { return $"{Font} {Size} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetHorizontalScaling.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetHorizontalScaling.cs index 374e9fde..9734158f 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetHorizontalScaling.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetHorizontalScaling.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { + using System.IO; using Content; internal class SetHorizontalScaling : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.FontState.HorizontalScaling = Scale; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Scale} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextLeading.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextLeading.cs index 658b21e1..cfb6eed0 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextLeading.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextLeading.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { + using System.IO; using Content; internal class SetTextLeading : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.FontState.Leading = Leading; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Leading} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRenderingMode.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRenderingMode.cs index 19d9ca51..a07c8107 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRenderingMode.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRenderingMode.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { + using System.IO; using Content; using Core; @@ -23,6 +24,11 @@ currentState.FontState.RenderingMode = Mode; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Mode} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRise.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRise.cs index 228eda68..1d5cd506 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRise.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetTextRise.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { + using System.IO; using Content; internal class SetTextRise : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.FontState.Rise = Rise; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Rise} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetWordSpacing.cs b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetWordSpacing.cs index ea3d7521..91f2f02d 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetWordSpacing.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/TextState/SetWordSpacing.cs @@ -1,5 +1,6 @@ namespace UglyToad.PdfPig.Graphics.Operations.TextState { + using System.IO; using Content; internal class SetWordSpacing : IGraphicsStateOperation @@ -22,6 +23,11 @@ currentState.FontState.WordSpacing = Spacing; } + public void Write(Stream stream) + { + throw new System.NotImplementedException(); + } + public override string ToString() { return $"{Spacing} {Symbol}"; diff --git a/src/UglyToad.PdfPig/Writer/IWritingFont.cs b/src/UglyToad.PdfPig/Writer/IWritingFont.cs new file mode 100644 index 00000000..9b0ad8fb --- /dev/null +++ b/src/UglyToad.PdfPig/Writer/IWritingFont.cs @@ -0,0 +1,15 @@ +namespace UglyToad.PdfPig.Writer +{ + using System.Collections.Generic; + using Geometry; + using Tokens; + + internal interface IWritingFont + { + bool HasWidths { get; } + + bool TryGetBoundingBox(char character, out PdfRectangle boundingBox); + + IReadOnlyDictionary GetDictionary(NameToken fontKeyName); + } +} \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs index cc283c58..efddcbac 100644 --- a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs @@ -5,12 +5,15 @@ using System.IO; using System.Linq; using Content; + using Fonts; using Fonts.TrueType; using Fonts.TrueType.Parser; using Geometry; + using Graphics.Operations; using IO; using Tokens; using Util; + using Util.JetBrains.Annotations; internal class PdfDocumentBuilder { @@ -21,7 +24,7 @@ private readonly Dictionary fonts = new Dictionary(); public IReadOnlyDictionary Pages => pages; - public IReadOnlyDictionary Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram); + public IReadOnlyDictionary Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram); public AddedFont AddTrueTypeFont(IReadOnlyList fontFileBytes) { @@ -31,7 +34,7 @@ var id = Guid.NewGuid(); var i = fonts.Count; var added = new AddedFont(id, NameToken.Create($"F{i}")); - fonts[id] = new FontStored(added, font); + fonts[id] = new FontStored(added, new TrueTypeWritingFont(font)); return added; } @@ -41,6 +44,16 @@ } } + public AddedFont AddStandard14Font(Standard14Font type) + { + var id = Guid.NewGuid(); + var name = NameToken.Create($"F{fonts.Count}"); + var added = new AddedFont(id, name); + fonts[id] = new FontStored(added, new Standard14WritingFont(Standard14.GetAdobeFontMetrics(type))); + + return added; + } + public PdfPageBuilder AddPage(PageSize size, bool isPortrait = true) { if (!size.TryGetPdfRectangle(out var rectangle)) @@ -97,27 +110,17 @@ // Body foreach (var font in fonts) { - var widths = new ArrayToken(new[] { new NumericToken(0), new NumericToken(255) }); - var widthsObj = WriteObject(widths, memory, objectLocations, ref number); + var fontDictionary = font.Value.FontProgram.GetDictionary(font.Value.FontKey.Name); // TODO // var descriptorRef = new IndirectReference(number++, 0); - var dictionary = new DictionaryToken(new Dictionary - { - { NameToken.Type, NameToken.Font }, - { NameToken.Subtype, NameToken.TrueType }, - { NameToken.FirstChar, new NumericToken(0) }, - { NameToken.LastChar, new NumericToken(255) }, - { NameToken.Encoding, NameToken.WinAnsiEncoding }, - { NameToken.Widths, widthsObj }, - //{ NameToken.FontDesc, new IndirectReferenceToken(descriptorRef) } - }); + var dictionary = new DictionaryToken(fontDictionary); var fontObj = WriteObject(dictionary, memory, objectLocations, ref number); fontsWritten.Add(font.Key, fontObj); } - + var resources = new Dictionary { { NameToken.ProcSet, new ArrayToken(new []{ NameToken.Create("PDF"), NameToken.Create("Text") }) } @@ -133,22 +136,37 @@ resources.Add(NameToken.Font, new IndirectReferenceToken(fontsDictionaryRef.Number)); } - var page = new DictionaryToken(new Dictionary + var pageReferences = new List(); + foreach (var page in pages) { - { NameToken.Type, NameToken.Page }, + var pageDictionary = new Dictionary { - NameToken.Resources, - new DictionaryToken(resources) - }, - { NameToken.MediaBox, RectangleToArray(pages[1].PageSize) } - }); + {NameToken.Type, NameToken.Page}, + { + NameToken.Resources, + new DictionaryToken(resources) + }, + {NameToken.MediaBox, RectangleToArray(page.Value.PageSize)} + }; - var pageRef = WriteObject(page, memory, objectLocations, ref number); + if (page.Value.Operations.Count > 0) + { + var contentStream = WriteContentStream(page.Value.Operations); + + var contentStreamObj = WriteObject(contentStream, memory, objectLocations, ref number); + + pageDictionary[NameToken.Contents] = new IndirectReferenceToken(contentStreamObj.Number); + } + + var pageRef = WriteObject(new DictionaryToken(pageDictionary), memory, objectLocations, ref number); + + pageReferences.Add(new IndirectReferenceToken(pageRef.Number)); + } var pagesDictionary = new DictionaryToken(new Dictionary { { NameToken.Type, NameToken.Pages }, - { NameToken.Kids, new ArrayToken(new [] { new IndirectReferenceToken(pageRef.Number) }) }, + { NameToken.Kids, new ArrayToken(pageReferences) }, { NameToken.Count, new NumericToken(1) } }); @@ -168,14 +186,36 @@ } } + private static StreamToken WriteContentStream(IReadOnlyList content) + { + using (var memoryStream = new MemoryStream()) + { + foreach (var operation in content) + { + operation.Write(memoryStream); + } + + var bytes = memoryStream.ToArray(); + + var streamDictionary = new Dictionary + { + { NameToken.Length, new NumericToken(bytes.Length) } + }; + + var stream = new StreamToken(new DictionaryToken(streamDictionary), bytes); + + return stream; + } + } + private static ArrayToken RectangleToArray(PdfRectangle rectangle) { return new ArrayToken(new[] { - new NumericToken(rectangle.BottomLeft.X), - new NumericToken(rectangle.BottomLeft.Y), - new NumericToken(rectangle.TopRight.X), - new NumericToken(rectangle.TopRight.Y) + new NumericToken(rectangle.BottomLeft.X), + new NumericToken(rectangle.BottomLeft.Y), + new NumericToken(rectangle.TopRight.X), + new NumericToken(rectangle.TopRight.Y) }); } @@ -198,17 +238,19 @@ stream.WriteByte(Break); } } - + internal class FontStored { + [NotNull] public AddedFont FontKey { get; } - public TrueTypeFontProgram FontProgram { get; } + [NotNull] + public IWritingFont FontProgram { get; } - public FontStored(AddedFont fontKey, TrueTypeFontProgram fontProgram) + public FontStored(AddedFont fontKey, IWritingFont fontProgram) { - FontKey = fontKey; - FontProgram = fontProgram; + FontKey = fontKey ?? throw new ArgumentNullException(nameof(fontKey)); + FontProgram = fontProgram ?? throw new ArgumentNullException(nameof(fontProgram)); } } @@ -225,5 +267,4 @@ } } } - } diff --git a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs index 466e9973..8cbf880a 100644 --- a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs @@ -8,6 +8,7 @@ using Graphics.Operations; using Graphics.Operations.SpecialGraphicsState; using Graphics.Operations.TextObjects; + using Graphics.Operations.TextPositioning; using Graphics.Operations.TextShowing; using Graphics.Operations.TextState; @@ -59,24 +60,18 @@ try { - var ctm = TransformationMatrix.FromValues(position.X, 0, position.Y, 0, 0, 0); - - var realWidth = ctm.Transform(widthRect).Width; + var realWidth = widthRect.Width; if (realWidth + position.X > PageSize.Width) { throw new InvalidOperationException("Text would exceed the bounds."); } - operations.Add(new ModifyCurrentTransformationMatrix(new[] - { - position.X, 0, position.Y, 0, 0, 0 - })); - var beginText = BeginText.Value; operations.Add(beginText); operations.Add(new SetFontAndSize(font.Name, fontSize)); + operations.Add(new MoveToNextLineWithOffset(position.X, position.Y)); operations.Add(new ShowText(text)); operations.Add(EndText.Value); @@ -90,7 +85,7 @@ return this; } - private static decimal CalculateGlyphSpaceTextWidth(string text, TrueTypeFontProgram font) + private static decimal CalculateGlyphSpaceTextWidth(string text, IWritingFont font) { var width = 0m; for (var i = 0; i < text.Length; i++) diff --git a/src/UglyToad.PdfPig/Writer/Standard14WritingFont.cs b/src/UglyToad.PdfPig/Writer/Standard14WritingFont.cs new file mode 100644 index 00000000..23b623ea --- /dev/null +++ b/src/UglyToad.PdfPig/Writer/Standard14WritingFont.cs @@ -0,0 +1,47 @@ +namespace UglyToad.PdfPig.Writer +{ + using System.Collections.Generic; + using Fonts; + using Fonts.Encodings; + using Geometry; + using Tokens; + + internal class Standard14WritingFont : IWritingFont + { + private readonly FontMetrics metrics; + + public bool HasWidths { get; } = false; + + public Standard14WritingFont(FontMetrics metrics) + { + this.metrics = metrics; + } + + public bool TryGetBoundingBox(char character, out PdfRectangle boundingBox) + { + var encoding = StandardEncoding.Instance; + boundingBox = default(PdfRectangle); + if (!metrics.CharacterMetrics.TryGetValue(encoding.GetName(character), out var characterMetric)) + { + return false; + } + + boundingBox = new PdfRectangle(characterMetric.BoundingBox.Left, characterMetric.BoundingBox.Bottom, + characterMetric.BoundingBox.Left + characterMetric.WidthX, characterMetric.BoundingBox.Top); + + return true; + } + + public IReadOnlyDictionary GetDictionary(NameToken fontKeyName) + { + return new Dictionary + { + { NameToken.Type, NameToken.Font }, + { NameToken.Subtype, NameToken.Type1 }, + { NameToken.BaseFont, NameToken.Create(metrics.FontName) }, + { NameToken.Encoding, NameToken.MacRomanEncoding }, + { NameToken.Name, fontKeyName } + }; + } + } +} \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Writer/TokenWriter.cs b/src/UglyToad.PdfPig/Writer/TokenWriter.cs index 0202cf99..79d81f6b 100644 --- a/src/UglyToad.PdfPig/Writer/TokenWriter.cs +++ b/src/UglyToad.PdfPig/Writer/TokenWriter.cs @@ -36,6 +36,9 @@ private static readonly byte[] StartXref = OtherEncodings.StringAsLatin1Bytes("startxref"); + private static readonly byte[] StreamStart = OtherEncodings.StringAsLatin1Bytes("stream"); + private static readonly byte[] StreamEnd = OtherEncodings.StringAsLatin1Bytes("endstream"); + private static readonly byte StringStart = GetByte("("); private static readonly byte StringEnd = GetByte(")"); @@ -81,8 +84,9 @@ case ObjectToken objectToken: WriteObject(objectToken, outputStream); break; - case StreamToken _: - throw new NotImplementedException(); + case StreamToken streamToken: + WriteStream(streamToken, outputStream); + break; case StringToken stringToken: WriteString(stringToken, outputStream); break; @@ -268,6 +272,17 @@ WriteLineBreak(outputStream); } + private static void WriteStream(StreamToken streamToken, Stream outputStream) + { + WriteDictionary(streamToken.StreamDictionary, outputStream); + WriteLineBreak(outputStream); + outputStream.Write(StreamStart, 0, StreamStart.Length); + WriteLineBreak(outputStream); + outputStream.Write(streamToken.Data.ToArray(), 0, streamToken.Data.Count); + WriteLineBreak(outputStream); + outputStream.Write(StreamEnd, 0, StreamEnd.Length); + } + private static void WriteString(StringToken stringToken, Stream outputStream) { outputStream.WriteByte(StringStart); diff --git a/src/UglyToad.PdfPig/Writer/TrueTypeWritingFont.cs b/src/UglyToad.PdfPig/Writer/TrueTypeWritingFont.cs new file mode 100644 index 00000000..4b70429d --- /dev/null +++ b/src/UglyToad.PdfPig/Writer/TrueTypeWritingFont.cs @@ -0,0 +1,33 @@ +namespace UglyToad.PdfPig.Writer +{ + using System.Collections.Generic; + using Fonts.TrueType; + using Geometry; + using Tokens; + + internal class TrueTypeWritingFont : IWritingFont + { + private readonly TrueTypeFontProgram font; + + public TrueTypeWritingFont(TrueTypeFontProgram font) + { + this.font = font; + } + + public bool HasWidths { get; } = true; + + public bool TryGetBoundingBox(char character, out PdfRectangle boundingBox) + { + return font.TryGetBoundingBox(character, out boundingBox); + } + + public IReadOnlyDictionary GetDictionary(NameToken fontKeyName) + { + return new Dictionary + { + { NameToken.Type, NameToken.Font }, + { NameToken.Subtype, NameToken.TrueType } + }; + } + } +} \ No newline at end of file