From ed634e86fef25b49e7e2695ef1035007468848ce Mon Sep 17 00:00:00 2001 From: Eliot Jones Date: Sun, 26 Nov 2017 22:19:42 +0000 Subject: [PATCH] arrange operations into folders in line with grouping from the specification and start creating a context to mutate through operations. --- .../Operations/General/SetMiterLimitTests.cs | 27 +++ .../SpecialGraphicsState/PopTests.cs | 52 ++++++ .../SpecialGraphicsState/PushTests.cs | 26 +++ .../Graphics/TestOperationContext.cs | 42 +++++ .../Parser/PageContentParserTests.cs | 73 +++++++- src/UglyToad.Pdf/Content/ResourceContainer.cs | 7 +- src/UglyToad.Pdf/Core/IDeepCloneable.cs | 7 + src/UglyToad.Pdf/Graphics/CurrentFontState.cs | 84 +++++++++ .../Graphics/CurrentGraphicsState.cs | 176 ++++++++++++++++++ src/UglyToad.Pdf/Graphics/LineCapStyle.cs | 9 + src/UglyToad.Pdf/Graphics/LineDashPattern.cs | 20 ++ src/UglyToad.Pdf/Graphics/LineJoinStyle.cs | 9 + .../Graphics/Operations/BeginText.cs | 19 -- .../ModifyClippingByEvenOddIntersect.cs | 0 ...ModifyClippingByNonZeroWindingIntersect.cs | 2 +- .../Graphics/Operations/EndText.cs | 19 -- .../{ => General}/SetColorRenderingIntent.cs | 2 +- .../{ => General}/SetFlatnessTolerance.cs | 2 +- .../Operations/{ => General}/SetLineCap.cs | 15 +- .../Operations/General/SetLineDashPattern.cs | 22 +++ .../Operations/{ => General}/SetLineJoin.cs | 15 +- .../Operations/{ => General}/SetLineWidth.cs | 10 +- .../Operations/{ => General}/SetMiterLimit.cs | 11 +- .../AppendDualControlPointBezierCurve.cs | 2 +- .../AppendEndControlPointBezierCurve.cs | 2 +- .../{ => PathConstruction}/AppendRectangle.cs | 2 +- .../AppendStartControlPointBezierCurve.cs | 2 +- .../AppendStraightLineSegment.cs | 2 +- .../{ => PathConstruction}/BeginNewSubpath.cs | 2 +- .../{ => PathConstruction}/CloseSubpath.cs | 2 +- src/UglyToad.Pdf/Graphics/Operations/Pop.cs | 19 -- .../Graphics/Operations/SetLineDashPattern.cs | 24 --- .../ModifyTransformationMatrix.cs | 2 +- .../Operations/SpecialGraphicsState/Pop.cs | 35 ++++ .../{ => SpecialGraphicsState}/Push.cs | 9 +- .../Operations/TextObjects/BeginText.cs | 28 +++ .../Operations/TextObjects/EndText.cs | 28 +++ .../{ => TextPositioning}/MoveToNextLine.cs | 2 +- .../MoveToNextLineWithOffset.cs | 2 +- .../MoveToNextLineWithOffsetSetLeading.cs | 2 +- .../{ => TextPositioning}/SetTextMatrix.cs | 2 +- .../MoveToNextLineShowText.cs} | 6 +- .../MoveToNextLineShowTextWithSpacing.cs} | 6 +- .../ShowText.cs} | 6 +- .../ShowTextsWithPositioning.cs} | 6 +- .../{ => TextState}/SetCharacterSpacing.cs | 2 +- .../Operations/{ => TextState}/SetFontSize.cs | 2 +- .../{ => TextState}/SetHorizontalScaling.cs | 2 +- .../{ => TextState}/SetTextLeading.cs | 2 +- .../{ => TextState}/SetTextRenderingMode.cs | 6 +- .../Operations/{ => TextState}/SetTextRise.cs | 2 +- .../{ => TextState}/SetWordSpacing.cs | 2 +- src/UglyToad.Pdf/Graphics/RenderingIntent.cs | 44 +++++ src/UglyToad.Pdf/Graphics/RenderingMode.cs | 44 +++++ .../Graphics/RenderingModeExtensions.cs | 29 +++ 55 files changed, 831 insertions(+), 144 deletions(-) create mode 100644 src/UglyToad.Pdf.Tests/Graphics/Operations/General/SetMiterLimitTests.cs create mode 100644 src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PopTests.cs create mode 100644 src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PushTests.cs create mode 100644 src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs create mode 100644 src/UglyToad.Pdf/Core/IDeepCloneable.cs create mode 100644 src/UglyToad.Pdf/Graphics/CurrentFontState.cs create mode 100644 src/UglyToad.Pdf/Graphics/CurrentGraphicsState.cs create mode 100644 src/UglyToad.Pdf/Graphics/LineCapStyle.cs create mode 100644 src/UglyToad.Pdf/Graphics/LineDashPattern.cs create mode 100644 src/UglyToad.Pdf/Graphics/LineJoinStyle.cs delete mode 100644 src/UglyToad.Pdf/Graphics/Operations/BeginText.cs rename src/UglyToad.Pdf/Graphics/Operations/{ => ClippingPaths}/ModifyClippingByEvenOddIntersect.cs (100%) rename src/UglyToad.Pdf/Graphics/Operations/{ => ClippingPaths}/ModifyClippingByNonZeroWindingIntersect.cs (88%) delete mode 100644 src/UglyToad.Pdf/Graphics/Operations/EndText.cs rename src/UglyToad.Pdf/Graphics/Operations/{ => General}/SetColorRenderingIntent.cs (75%) rename src/UglyToad.Pdf/Graphics/Operations/{ => General}/SetFlatnessTolerance.cs (88%) rename src/UglyToad.Pdf/Graphics/Operations/{ => General}/SetLineCap.cs (63%) create mode 100644 src/UglyToad.Pdf/Graphics/Operations/General/SetLineDashPattern.cs rename src/UglyToad.Pdf/Graphics/Operations/{ => General}/SetLineJoin.cs (64%) rename src/UglyToad.Pdf/Graphics/Operations/{ => General}/SetLineWidth.cs (56%) rename src/UglyToad.Pdf/Graphics/Operations/{ => General}/SetMiterLimit.cs (56%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/AppendDualControlPointBezierCurve.cs (92%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/AppendEndControlPointBezierCurve.cs (91%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/AppendRectangle.cs (91%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/AppendStartControlPointBezierCurve.cs (91%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/AppendStraightLineSegment.cs (88%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/BeginNewSubpath.cs (87%) rename src/UglyToad.Pdf/Graphics/Operations/{ => PathConstruction}/CloseSubpath.cs (85%) delete mode 100644 src/UglyToad.Pdf/Graphics/Operations/Pop.cs delete mode 100644 src/UglyToad.Pdf/Graphics/Operations/SetLineDashPattern.cs rename src/UglyToad.Pdf/Graphics/Operations/{ => SpecialGraphicsState}/ModifyTransformationMatrix.cs (92%) create mode 100644 src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Pop.cs rename src/UglyToad.Pdf/Graphics/Operations/{ => SpecialGraphicsState}/Push.cs (60%) create mode 100644 src/UglyToad.Pdf/Graphics/Operations/TextObjects/BeginText.cs create mode 100644 src/UglyToad.Pdf/Graphics/Operations/TextObjects/EndText.cs rename src/UglyToad.Pdf/Graphics/Operations/{ => TextPositioning}/MoveToNextLine.cs (86%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextPositioning}/MoveToNextLineWithOffset.cs (88%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextPositioning}/MoveToNextLineWithOffsetSetLeading.cs (88%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextPositioning}/SetTextMatrix.cs (91%) rename src/UglyToad.Pdf/Graphics/Operations/{MoveToNextLineShowString.cs => TextShowing/MoveToNextLineShowText.cs} (61%) rename src/UglyToad.Pdf/Graphics/Operations/{MoveToNextLineShowStringWithSpacing.cs => TextShowing/MoveToNextLineShowTextWithSpacing.cs} (67%) rename src/UglyToad.Pdf/Graphics/Operations/{ShowString.cs => TextShowing/ShowText.cs} (65%) rename src/UglyToad.Pdf/Graphics/Operations/{ShowStringsWithPositioning.cs => TextShowing/ShowTextsWithPositioning.cs} (50%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetCharacterSpacing.cs (88%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetFontSize.cs (89%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetHorizontalScaling.cs (87%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetTextLeading.cs (87%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetTextRenderingMode.cs (70%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetTextRise.cs (87%) rename src/UglyToad.Pdf/Graphics/Operations/{ => TextState}/SetWordSpacing.cs (87%) create mode 100644 src/UglyToad.Pdf/Graphics/RenderingIntent.cs create mode 100644 src/UglyToad.Pdf/Graphics/RenderingMode.cs create mode 100644 src/UglyToad.Pdf/Graphics/RenderingModeExtensions.cs diff --git a/src/UglyToad.Pdf.Tests/Graphics/Operations/General/SetMiterLimitTests.cs b/src/UglyToad.Pdf.Tests/Graphics/Operations/General/SetMiterLimitTests.cs new file mode 100644 index 00000000..6fb5b26e --- /dev/null +++ b/src/UglyToad.Pdf.Tests/Graphics/Operations/General/SetMiterLimitTests.cs @@ -0,0 +1,27 @@ +namespace UglyToad.Pdf.Tests.Graphics.Operations.General +{ + using Pdf.Graphics.Operations.General; + using Xunit; + + public class SetMiterLimitTests + { + private readonly TestResourceStore resourceStore = new TestResourceStore(); + private readonly TestOperationContext context = new TestOperationContext(); + + [Fact] + public void RunSetsMiterLimitOfCurrentState() + { + var limit = new SetMiterLimit(25); + + limit.Run(context, resourceStore); + + Assert.Equal(25, context.GetCurrentState().MiterLimit); + } + + [Fact] + public void MiterLimitSymbolCorrect() + { + Assert.Equal("M", SetMiterLimit.Symbol); + } + } +} diff --git a/src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PopTests.cs b/src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PopTests.cs new file mode 100644 index 00000000..6ed02f8c --- /dev/null +++ b/src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PopTests.cs @@ -0,0 +1,52 @@ +namespace UglyToad.Pdf.Tests.Graphics.Operations.SpecialGraphicsState +{ + using System; + using Pdf.Graphics; + using Pdf.Graphics.Operations.SpecialGraphicsState; + using Xunit; + + public class PopTests + { + private readonly TestResourceStore resourceStore = new TestResourceStore(); + private readonly TestOperationContext context = new TestOperationContext(); + + [Fact] + public void PopSymbolCorrect() + { + Assert.Equal("Q", Pop.Symbol); + Assert.Equal("Q", Pop.Value.Operator); + } + + [Fact] + public void CannotPopWithSingleFrame() + { + Action action = () => Pop.Value.Run(context, resourceStore); + + Assert.Throws(action); + } + + [Fact] + public void CannotPopWithNoFrames() + { + context.StateStack.Pop(); + + Action action = () => Pop.Value.Run(context, resourceStore); + + Assert.Throws(action); + } + + [Fact] + public void PopsTopFrame() + { + context.StateStack.Push(new CurrentGraphicsState + { + LineWidth = 23 + }); + + Pop.Value.Run(context, resourceStore); + + Assert.Equal(1, context.StackSize); + Assert.Equal(1, context.GetCurrentState().LineWidth); + } + } +} diff --git a/src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PushTests.cs b/src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PushTests.cs new file mode 100644 index 00000000..d125db11 --- /dev/null +++ b/src/UglyToad.Pdf.Tests/Graphics/Operations/SpecialGraphicsState/PushTests.cs @@ -0,0 +1,26 @@ +namespace UglyToad.Pdf.Tests.Graphics.Operations.SpecialGraphicsState +{ + using Pdf.Graphics.Operations.SpecialGraphicsState; + using Xunit; + + public class PushTests + { + private readonly TestResourceStore resourceStore = new TestResourceStore(); + private readonly TestOperationContext context = new TestOperationContext(); + + [Fact] + public void PushSymbolCorrect() + { + Assert.Equal("q", Push.Symbol); + Assert.Equal("q", Push.Value.Operator); + } + + [Fact] + public void PushAddsToStack() + { + Push.Value.Run(context, resourceStore); + + Assert.Equal(2, context.StackSize); + } + } +} diff --git a/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs b/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs new file mode 100644 index 00000000..81383000 --- /dev/null +++ b/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs @@ -0,0 +1,42 @@ +namespace UglyToad.Pdf.Tests.Graphics +{ + using System.Collections.Generic; + using Content; + using Pdf.Graphics; + + internal class TestOperationContext : IOperationContext + { + public Stack StateStack { get; } + = new Stack(); + + public int StackSize => StateStack.Count; + + public TextMatrices TextMatrices { get; set; } + = new TextMatrices(); + + public TestOperationContext() + { + StateStack.Push(new CurrentGraphicsState()); + } + + public CurrentGraphicsState GetCurrentState() + { + return StateStack.Peek(); + } + + public void PopState() + { + StateStack.Pop(); + } + + public void PushState() + { + StateStack.Push(StateStack.Peek().DeepClone()); + } + } + + internal class TestResourceStore : IResourceStore + { + + } +} diff --git a/src/UglyToad.Pdf.Tests/Parser/PageContentParserTests.cs b/src/UglyToad.Pdf.Tests/Parser/PageContentParserTests.cs index c23ed086..d22c5271 100644 --- a/src/UglyToad.Pdf.Tests/Parser/PageContentParserTests.cs +++ b/src/UglyToad.Pdf.Tests/Parser/PageContentParserTests.cs @@ -1,12 +1,19 @@ namespace UglyToad.Pdf.Tests.Parser { - using Graphics; + using Pdf.Cos; + using Pdf.Graphics; + using Pdf.Graphics.Operations.General; + using Pdf.Graphics.Operations.TextObjects; + using Pdf.Graphics.Operations.TextPositioning; + using Pdf.Graphics.Operations.TextShowing; + using Pdf.Graphics.Operations.TextState; using Pdf.Parser; using Xunit; public class PageContentParserTests { private readonly PageContentParser parser = new PageContentParser(); + private readonly IGraphicsStateOperationFactory operationFactory = new ReflectionGraphicsStateOperationFactory(); [Fact] public void CorrectlyExtractsOperations() @@ -16,6 +23,70 @@ var result = parser.Parse(new ReflectionGraphicsStateOperationFactory(), input.Bytes); } + [Fact] + public void CorrectlyExtractsOptionsInTextContext() + { + const string s = @"BT +/F13 48 Tf +20 38 Td +1 Tr +2 w +(ABC) Tj +ET"; + var input = StringBytesTestConverter.Convert(s, false); + + var result = parser.Parse(operationFactory, input.Bytes); + + Assert.Equal(7, result.GraphicsStateOperations.Count); + + Assert.Equal(BeginText.Value, result.GraphicsStateOperations[0]); + + var font = Assert.IsType(result.GraphicsStateOperations[1]); + Assert.Equal(CosName.Create("F13"), font.Font); + Assert.Equal(48, font.Size); + + var nextLine = Assert.IsType(result.GraphicsStateOperations[2]); + Assert.Equal(20, nextLine.Tx); + Assert.Equal(38, nextLine.Ty); + + var renderingMode = Assert.IsType(result.GraphicsStateOperations[3]); + Assert.Equal(RenderingMode.Stroke, renderingMode.Mode); + + var lineWidth = Assert.IsType(result.GraphicsStateOperations[4]); + Assert.Equal(2, lineWidth.Width); + + var text = Assert.IsType(result.GraphicsStateOperations[5]); + Assert.Equal("ABC", text.Text); + + Assert.Equal(EndText.Value, result.GraphicsStateOperations[6]); + } + + [Fact] + public void SkipsComments() + { + const string s = @"BT +21 32 Td %A comment here +0 Tr +ET"; + + var input = StringBytesTestConverter.Convert(s, false); + + var result = parser.Parse(operationFactory, input.Bytes); + + Assert.Equal(4, result.GraphicsStateOperations.Count); + + Assert.Equal(BeginText.Value, result.GraphicsStateOperations[0]); + + var moveLine = Assert.IsType(result.GraphicsStateOperations[1]); + Assert.Equal(21, moveLine.Tx); + Assert.Equal(32, moveLine.Ty); + + var renderingMode = Assert.IsType(result.GraphicsStateOperations[2]); + Assert.Equal(RenderingMode.Fill, renderingMode.Mode); + + Assert.Equal(EndText.Value, result.GraphicsStateOperations[3]); + } + private const string SimpleGoogleDocPageContent = @" 1 0 0 -1 0 792 cm q diff --git a/src/UglyToad.Pdf/Content/ResourceContainer.cs b/src/UglyToad.Pdf/Content/ResourceContainer.cs index 33f8db36..60513273 100644 --- a/src/UglyToad.Pdf/Content/ResourceContainer.cs +++ b/src/UglyToad.Pdf/Content/ResourceContainer.cs @@ -7,7 +7,12 @@ using Fonts; using Parser; - public class ResourceContainer + public interface IResourceStore + { + + } + + public class ResourceContainer : IResourceStore { private readonly Dictionary loadedFonts = new Dictionary(); diff --git a/src/UglyToad.Pdf/Core/IDeepCloneable.cs b/src/UglyToad.Pdf/Core/IDeepCloneable.cs new file mode 100644 index 00000000..55161221 --- /dev/null +++ b/src/UglyToad.Pdf/Core/IDeepCloneable.cs @@ -0,0 +1,7 @@ +namespace UglyToad.Pdf.Core +{ + public interface IDeepCloneable + { + T DeepClone(); + } +} diff --git a/src/UglyToad.Pdf/Graphics/CurrentFontState.cs b/src/UglyToad.Pdf/Graphics/CurrentFontState.cs new file mode 100644 index 00000000..0d454dcc --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/CurrentFontState.cs @@ -0,0 +1,84 @@ +// ReSharper disable RedundantDefaultMemberInitializer +namespace UglyToad.Pdf.Graphics +{ + using Core; + using Cos; + + /// + /// The current state of text related parameters for a content stream. + /// + internal class CurrentFontState : IDeepCloneable + { + /// + /// A value in unscaled text space units which is added to the horizontal (or vertical if in vertical writing mode) + /// glyph displacement. + /// + /// + /// In horizontal writing mode a positive value will expand the distance between letters/glyphs. + /// Default value 0. + /// + public decimal CharacterSpacing { get; set; } = 0; + + /// + /// As for but applies only for the space character (32). + /// + /// + /// Default value 0. + /// + public decimal WordSpacing { get; set; } = 0; + + /// + /// Adjusts the width of glyphs/letters by stretching (or compressing) them horizontally. + /// Value is a percentage of the normal width. + /// + public decimal HorizontalScaling { get; set; } = 100; + + /// + /// The vertical distance in unscaled text space units between the baselines of lines of text. + /// + public decimal Leading { get; set; } + + public CosName FontName { get; set; } + + public decimal FontSize { get; set; } + + /// + /// The for glyph outlines. + /// + /// + /// When the rendering mode requires filling the current non-stroking color in the state is used.
+ /// When the rendering mode requires stroking the current stroking color in the state is used.
+ /// The rendering mode has no impact on Type 3 fonts. + ///
+ public RenderingMode RenderingMode { get; set; } = RenderingMode.Fill; + + /// + /// The distance in unscaled text space units to move the default baseline either up or down. + /// + /// + /// Always applies to the vertical coordinate irrespective or writing mode. + /// + public decimal Rise { get; set; } + + /// + /// Are all glpyhs in a text object treated as a single elementary object for the purpose of the transparent imaging model? + /// + public bool Knockout { get; set; } + + public CurrentFontState DeepClone() + { + return new CurrentFontState + { + CharacterSpacing = CharacterSpacing, + RenderingMode = RenderingMode, + Rise = Rise, + Leading = Leading, + WordSpacing = WordSpacing, + FontName = FontName, + FontSize = FontSize, + HorizontalScaling = HorizontalScaling, + Knockout = Knockout + }; + } + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/CurrentGraphicsState.cs b/src/UglyToad.Pdf/Graphics/CurrentGraphicsState.cs new file mode 100644 index 00000000..414b550f --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/CurrentGraphicsState.cs @@ -0,0 +1,176 @@ +namespace UglyToad.Pdf.Graphics +{ + using System; + using System.Collections.Generic; + using Core; + using Geometry; + using Operations; + + internal class CurrentGraphicsState : IDeepCloneable + { + /// + /// The for this graphics state. + /// + public CurrentFontState FontState { get; set; } + + /// + /// Thickness in user space units of path to be stroked. + /// + public decimal LineWidth { get; set; } = 1; + + /// + /// Specifies the shape of line ends for open stroked paths. + /// + public LineCapStyle CapStyle { get; set; } = LineCapStyle.Butt; + + /// + /// Specifies the shape of joins between connected stroked path segments. + /// + public LineJoinStyle JoinStyle { get; set; } = LineJoinStyle.Miter; + + /// + /// Maximum length of mitered line joins for paths before becoming a bevel. + /// + public decimal MiterLimit { get; set; } = 10; + + /// + /// The pattern to be used for stroked lines. + /// + public LineDashPattern LineDashPattern { get; set; } = LineDashPattern.Solid; + + /// + /// The rendering intent to use when converting CIE-based colors to device colors. + /// + public RenderingIntent RenderingIntent { get; set; } = RenderingIntent.RelativeColorimetric; + + /// + /// Should a correction for rasterization effects be applied? + /// + public bool StrokeAdjustment { get; set; } = false; + + /// + /// Opacity value to be used for transparent imaging. + /// + public decimal AlphaConstant { get; set; } = 1; + + /// + /// Should soft mask and alpha constant values be interpreted as shape () or opacity () values? + /// + public bool AlphaSource { get; set; } = false; + + /// + /// Maps positions from user coordinates to device coordinates. + /// + public TransformationMatrix CurrentTransformationMatrix { get; set; } = TransformationMatrix.Default; + + #region Device Dependent + + /// + /// Should painting in a colorant set erase () + /// or leave unchanged () areas of other colorant sets? + /// + public bool Overprint { get; set; } = false; + + /// + /// As for but with non-stroking operations. + /// + public bool NonStrokingOverprint { get; set; } = false; + + /// + /// In DeviceCMYK color space a value of 0 for a component will erase a component (0) + /// or leave it unchanged (1) for overprinting. + /// + public decimal OverprintMode { get; set; } + + /// + /// The precision for rendering curves, smaller numbers give smoother curves. + /// + public decimal Flatness { get; set; } = 1; + + /// + /// The precision for rendering color gradients on the output device. + /// + public decimal Smoothness { get; set; } = 0; + + #endregion + + public CurrentGraphicsState DeepClone() + { + return new CurrentGraphicsState + { + FontState = FontState.DeepClone(), + RenderingIntent = RenderingIntent + }; + } + } + + internal interface IOperationContext + { + CurrentGraphicsState GetCurrentState(); + + TextMatrices TextMatrices { get; } + + int StackSize { get; } + + void PopState(); + + void PushState(); + } + + internal class TextMatrices + { + public TransformationMatrix TextMatrix { get; set; } + + public TransformationMatrix TextLineMatrix { get; set; } + } + + internal class ContentStreamProcessor : IOperationContext + { + private readonly Stack graphicsStack = new Stack(); + + public TextMatrices TextMatrices { get; private set; } = new TextMatrices(); + + public int StackSize => graphicsStack.Count; + + + public ContentStreamProcessor(PdfRectangle cropBox) + { + + } + + public void Process(IReadOnlyList operations) + { + var currentState = CloneAllStates(); + + + } + + private void ProcessOperations(IReadOnlyList operations) + { + foreach (var stateOperation in operations) + { + // stateOperation.Run(); + } + } + + private Stack CloneAllStates() + { + throw new NotImplementedException(); + } + + public CurrentGraphicsState GetCurrentState() + { + return graphicsStack.Peek(); + } + + public void PopState() + { + graphicsStack.Pop(); + } + + public void PushState() + { + graphicsStack.Push(graphicsStack.Peek().DeepClone()); + } + } +} diff --git a/src/UglyToad.Pdf/Graphics/LineCapStyle.cs b/src/UglyToad.Pdf/Graphics/LineCapStyle.cs new file mode 100644 index 00000000..817660ff --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/LineCapStyle.cs @@ -0,0 +1,9 @@ +namespace UglyToad.Pdf.Graphics +{ + internal enum LineCapStyle + { + Butt = 0, + Round = 1, + ProjectingSquare = 2 + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/LineDashPattern.cs b/src/UglyToad.Pdf/Graphics/LineDashPattern.cs new file mode 100644 index 00000000..af18fe7a --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/LineDashPattern.cs @@ -0,0 +1,20 @@ +namespace UglyToad.Pdf.Graphics +{ + using System; + + public struct LineDashPattern + { + public int Phase { get; } + + public decimal[] Array { get; } + + public LineDashPattern(int phase, decimal[] array) + { + Phase = phase; + Array = array ?? throw new ArgumentNullException(nameof(array)); + } + + public static LineDashPattern Solid { get; } + = new LineDashPattern(0, new decimal[0]); + } +} diff --git a/src/UglyToad.Pdf/Graphics/LineJoinStyle.cs b/src/UglyToad.Pdf/Graphics/LineJoinStyle.cs new file mode 100644 index 00000000..8cb13033 --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/LineJoinStyle.cs @@ -0,0 +1,9 @@ +namespace UglyToad.Pdf.Graphics +{ + internal enum LineJoinStyle + { + Miter = 0, + Round = 1, + Bevel = 2 + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/BeginText.cs b/src/UglyToad.Pdf/Graphics/Operations/BeginText.cs deleted file mode 100644 index 204b385c..00000000 --- a/src/UglyToad.Pdf/Graphics/Operations/BeginText.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace UglyToad.Pdf.Graphics.Operations -{ - internal class BeginText : IGraphicsStateOperation - { - public const string Symbol = "BT"; - public static readonly BeginText Value = new BeginText(); - - public string Operator => Symbol; - - private BeginText() - { - } - - public override string ToString() - { - return Symbol; - } - } -} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/ModifyClippingByEvenOddIntersect.cs b/src/UglyToad.Pdf/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs similarity index 100% rename from src/UglyToad.Pdf/Graphics/Operations/ModifyClippingByEvenOddIntersect.cs rename to src/UglyToad.Pdf/Graphics/Operations/ClippingPaths/ModifyClippingByEvenOddIntersect.cs diff --git a/src/UglyToad.Pdf/Graphics/Operations/ModifyClippingByNonZeroWindingIntersect.cs b/src/UglyToad.Pdf/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs similarity index 88% rename from src/UglyToad.Pdf/Graphics/Operations/ModifyClippingByNonZeroWindingIntersect.cs rename to src/UglyToad.Pdf/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs index 3a20a2aa..b77af299 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/ModifyClippingByNonZeroWindingIntersect.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/ClippingPaths/ModifyClippingByNonZeroWindingIntersect.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.ClippingPaths { internal class ModifyClippingByNonZeroWindingIntersect : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/EndText.cs b/src/UglyToad.Pdf/Graphics/Operations/EndText.cs deleted file mode 100644 index 1b06c83a..00000000 --- a/src/UglyToad.Pdf/Graphics/Operations/EndText.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace UglyToad.Pdf.Graphics.Operations -{ - internal class EndText : IGraphicsStateOperation - { - public const string Symbol = "q"; - public static readonly EndText Value = new EndText(); - - public string Operator => Symbol; - - private EndText() - { - } - - public override string ToString() - { - return Symbol; - } - } -} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetColorRenderingIntent.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetColorRenderingIntent.cs similarity index 75% rename from src/UglyToad.Pdf/Graphics/Operations/SetColorRenderingIntent.cs rename to src/UglyToad.Pdf/Graphics/Operations/General/SetColorRenderingIntent.cs index 03df4e44..917380b7 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetColorRenderingIntent.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetColorRenderingIntent.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.General { internal class SetColorRenderingIntent : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetFlatnessTolerance.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetFlatnessTolerance.cs similarity index 88% rename from src/UglyToad.Pdf/Graphics/Operations/SetFlatnessTolerance.cs rename to src/UglyToad.Pdf/Graphics/Operations/General/SetFlatnessTolerance.cs index bec4a575..9b035dfc 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetFlatnessTolerance.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetFlatnessTolerance.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.General { internal class SetFlatnessTolerance : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetLineCap.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineCap.cs similarity index 63% rename from src/UglyToad.Pdf/Graphics/Operations/SetLineCap.cs rename to src/UglyToad.Pdf/Graphics/Operations/General/SetLineCap.cs index d9cb2bd8..92554c39 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetLineCap.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineCap.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.General { using System; @@ -8,10 +8,10 @@ public string Operator => Symbol; - public Style Cap { get; set; } + public LineCapStyle Cap { get; set; } - public SetLineCap(int cap) : this((Style)cap) { } - public SetLineCap(Style cap) + public SetLineCap(int cap) : this((LineCapStyle)cap) { } + public SetLineCap(LineCapStyle cap) { if (cap < 0 || (int)cap > 2) { @@ -25,12 +25,5 @@ { return $"{(int) Cap} {Symbol}"; } - - public enum Style - { - Butt = 0, - Round = 1, - ProjectingSquare = 2 - } } } \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/General/SetLineDashPattern.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineDashPattern.cs new file mode 100644 index 00000000..c1c04ecb --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineDashPattern.cs @@ -0,0 +1,22 @@ +namespace UglyToad.Pdf.Graphics.Operations.General +{ + internal class SetLineDashPattern : IGraphicsStateOperation + { + public const string Symbol = "d"; + + public string Operator => Symbol; + + public LineDashPattern Pattern { get; } + + + public SetLineDashPattern(decimal[] array, int phase) + { + Pattern = new LineDashPattern(phase, array); + } + + public override string ToString() + { + return $"{Pattern.Array} {Pattern.Phase} {Symbol}"; + } + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetLineJoin.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineJoin.cs similarity index 64% rename from src/UglyToad.Pdf/Graphics/Operations/SetLineJoin.cs rename to src/UglyToad.Pdf/Graphics/Operations/General/SetLineJoin.cs index 26087341..da7a5dc9 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetLineJoin.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineJoin.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.General { using System; @@ -8,10 +8,10 @@ public string Operator => Symbol; - public Style Join { get; set; } + public LineJoinStyle Join { get; set; } - public SetLineJoin(int join) : this((Style)join) { } - public SetLineJoin(Style join) + public SetLineJoin(int join) : this((LineJoinStyle)join) { } + public SetLineJoin(LineJoinStyle join) { if (join < 0 || (int)join > 2) { @@ -25,12 +25,5 @@ { return $"{(int)Join} {Symbol}"; } - - public enum Style - { - Miter = 0, - Round = 1, - Bevel = 2 - } } } \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetLineWidth.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineWidth.cs similarity index 56% rename from src/UglyToad.Pdf/Graphics/Operations/SetLineWidth.cs rename to src/UglyToad.Pdf/Graphics/Operations/General/SetLineWidth.cs index 8a366892..049438af 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetLineWidth.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetLineWidth.cs @@ -1,5 +1,7 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.General { + using Content; + internal class SetLineWidth : IGraphicsStateOperation { public const string Symbol = "w"; @@ -13,6 +15,12 @@ Width = width; } + public void Run(IOperationContext operationContext, IResourceStore resourceStore) + { + var currentState = operationContext.GetCurrentState(); + currentState.LineWidth = Width; + } + public override string ToString() { return $"{Width} {Symbol}"; diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetMiterLimit.cs b/src/UglyToad.Pdf/Graphics/Operations/General/SetMiterLimit.cs similarity index 56% rename from src/UglyToad.Pdf/Graphics/Operations/SetMiterLimit.cs rename to src/UglyToad.Pdf/Graphics/Operations/General/SetMiterLimit.cs index 605d53ca..497af492 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetMiterLimit.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/General/SetMiterLimit.cs @@ -1,5 +1,7 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.General { + using Content; + internal class SetMiterLimit : IGraphicsStateOperation { public const string Symbol = "M"; @@ -12,6 +14,13 @@ { Limit = limit; } + + public void Run(IOperationContext operationContext, IResourceStore resourceStore) + { + var currentState = operationContext.GetCurrentState(); + + currentState.MiterLimit = Limit; + } public override string ToString() { diff --git a/src/UglyToad.Pdf/Graphics/Operations/AppendDualControlPointBezierCurve.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs similarity index 92% rename from src/UglyToad.Pdf/Graphics/Operations/AppendDualControlPointBezierCurve.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs index 1b082fc0..a0cdcd67 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/AppendDualControlPointBezierCurve.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendDualControlPointBezierCurve.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { using Geometry; diff --git a/src/UglyToad.Pdf/Graphics/Operations/AppendEndControlPointBezierCurve.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs similarity index 91% rename from src/UglyToad.Pdf/Graphics/Operations/AppendEndControlPointBezierCurve.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs index 17493b64..1075be76 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/AppendEndControlPointBezierCurve.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendEndControlPointBezierCurve.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { using Geometry; diff --git a/src/UglyToad.Pdf/Graphics/Operations/AppendRectangle.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendRectangle.cs similarity index 91% rename from src/UglyToad.Pdf/Graphics/Operations/AppendRectangle.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendRectangle.cs index 7c5a4e26..749dbeed 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/AppendRectangle.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendRectangle.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { using Geometry; diff --git a/src/UglyToad.Pdf/Graphics/Operations/AppendStartControlPointBezierCurve.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs similarity index 91% rename from src/UglyToad.Pdf/Graphics/Operations/AppendStartControlPointBezierCurve.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs index e720eb32..a80a8866 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/AppendStartControlPointBezierCurve.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendStartControlPointBezierCurve.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { using Geometry; diff --git a/src/UglyToad.Pdf/Graphics/Operations/AppendStraightLineSegment.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs similarity index 88% rename from src/UglyToad.Pdf/Graphics/Operations/AppendStraightLineSegment.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs index bb7ea489..e7a6f5e6 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/AppendStraightLineSegment.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/AppendStraightLineSegment.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { using Geometry; diff --git a/src/UglyToad.Pdf/Graphics/Operations/BeginNewSubpath.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/BeginNewSubpath.cs similarity index 87% rename from src/UglyToad.Pdf/Graphics/Operations/BeginNewSubpath.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/BeginNewSubpath.cs index c52b5d00..3e000eca 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/BeginNewSubpath.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/BeginNewSubpath.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { using Geometry; diff --git a/src/UglyToad.Pdf/Graphics/Operations/CloseSubpath.cs b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/CloseSubpath.cs similarity index 85% rename from src/UglyToad.Pdf/Graphics/Operations/CloseSubpath.cs rename to src/UglyToad.Pdf/Graphics/Operations/PathConstruction/CloseSubpath.cs index 9a4a1ab5..782e392e 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/CloseSubpath.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/PathConstruction/CloseSubpath.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.PathConstruction { internal class CloseSubpath : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/Pop.cs b/src/UglyToad.Pdf/Graphics/Operations/Pop.cs deleted file mode 100644 index 2d4163a6..00000000 --- a/src/UglyToad.Pdf/Graphics/Operations/Pop.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace UglyToad.Pdf.Graphics.Operations -{ - internal class Pop : IGraphicsStateOperation - { - public const string Symbol = "Q"; - public static readonly Pop Value = new Pop(); - - public string Operator => Symbol; - - private Pop() - { - } - - public override string ToString() - { - return Symbol; - } - } -} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetLineDashPattern.cs b/src/UglyToad.Pdf/Graphics/Operations/SetLineDashPattern.cs deleted file mode 100644 index 1acf00a6..00000000 --- a/src/UglyToad.Pdf/Graphics/Operations/SetLineDashPattern.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace UglyToad.Pdf.Graphics.Operations -{ - internal class SetLineDashPattern : IGraphicsStateOperation - { - public const string Symbol = "d"; - - public string Operator => Symbol; - - public decimal[] Array { get; } - - public decimal Phase { get; } - - public SetLineDashPattern(decimal[] array, decimal phase) - { - Array = array; - Phase = phase; - } - - public override string ToString() - { - return $"{Array} {Phase} {Symbol}"; - } - } -} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/ModifyTransformationMatrix.cs b/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/ModifyTransformationMatrix.cs similarity index 92% rename from src/UglyToad.Pdf/Graphics/Operations/ModifyTransformationMatrix.cs rename to src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/ModifyTransformationMatrix.cs index 6e34c261..726da53c 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/ModifyTransformationMatrix.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/ModifyTransformationMatrix.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.SpecialGraphicsState { using System; diff --git a/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Pop.cs b/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Pop.cs new file mode 100644 index 00000000..c6eeba4b --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Pop.cs @@ -0,0 +1,35 @@ +namespace UglyToad.Pdf.Graphics.Operations.SpecialGraphicsState +{ + using System; + using Content; + + internal class Pop : IGraphicsStateOperation + { + public const string Symbol = "Q"; + public static readonly Pop Value = new Pop(); + + public string Operator => Symbol; + + private Pop() + { + } + + public void Run(IOperationContext operationContext, IResourceStore resourceStore) + { + var currentStackSize = operationContext.StackSize; + if (currentStackSize > 1) + { + operationContext.PopState(); + } + else + { + throw new InvalidOperationException("Cannot execute a pop of the graphics state stack, it would leave the stack empty."); + } + } + + public override string ToString() + { + return Symbol; + } + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/Push.cs b/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Push.cs similarity index 60% rename from src/UglyToad.Pdf/Graphics/Operations/Push.cs rename to src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Push.cs index fec25854..ede8dae8 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/Push.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/SpecialGraphicsState/Push.cs @@ -1,5 +1,7 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.SpecialGraphicsState { + using Content; + internal class Push : IGraphicsStateOperation { public const string Symbol = "q"; @@ -15,5 +17,10 @@ { return Symbol; } + + public void Run(IOperationContext context, IResourceStore resourceStore) + { + context.PushState(); + } } } diff --git a/src/UglyToad.Pdf/Graphics/Operations/TextObjects/BeginText.cs b/src/UglyToad.Pdf/Graphics/Operations/TextObjects/BeginText.cs new file mode 100644 index 00000000..1b8013b5 --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/Operations/TextObjects/BeginText.cs @@ -0,0 +1,28 @@ +namespace UglyToad.Pdf.Graphics.Operations.TextObjects +{ + using Content; + using Core; + + internal class BeginText : IGraphicsStateOperation + { + public const string Symbol = "BT"; + public static readonly BeginText Value = new BeginText(); + + public string Operator => Symbol; + + private BeginText() + { + } + + public void Run(IOperationContext operationContext, IResourceStore resourceStore) + { + operationContext.TextMatrices.TextMatrix = TransformationMatrix.Default; + operationContext.TextMatrices.TextLineMatrix = TransformationMatrix.Default; + } + + public override string ToString() + { + return Symbol; + } + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/TextObjects/EndText.cs b/src/UglyToad.Pdf/Graphics/Operations/TextObjects/EndText.cs new file mode 100644 index 00000000..81e259b8 --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/Operations/TextObjects/EndText.cs @@ -0,0 +1,28 @@ +namespace UglyToad.Pdf.Graphics.Operations.TextObjects +{ + using Content; + using Core; + + internal class EndText : IGraphicsStateOperation + { + public const string Symbol = "ET"; + public static readonly EndText Value = new EndText(); + + public string Operator => Symbol; + + private EndText() + { + } + + public void Run(IOperationContext operationContext, IResourceStore resourceStore) + { + operationContext.TextMatrices.TextMatrix = TransformationMatrix.Default; + operationContext.TextMatrices.TextLineMatrix = TransformationMatrix.Default; + } + + public override string ToString() + { + return Symbol; + } + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLine.cs b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLine.cs similarity index 86% rename from src/UglyToad.Pdf/Graphics/Operations/MoveToNextLine.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLine.cs index a704814a..14ec97a6 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLine.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLine.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextPositioning { internal class MoveToNextLine : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineWithOffset.cs b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs similarity index 88% rename from src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineWithOffset.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs index d867ec97..125f20ab 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineWithOffset.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLineWithOffset.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextPositioning { internal class MoveToNextLineWithOffset : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineWithOffsetSetLeading.cs b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs similarity index 88% rename from src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineWithOffsetSetLeading.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs index 9c501e7e..7691252b 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineWithOffsetSetLeading.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/MoveToNextLineWithOffsetSetLeading.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextPositioning { internal class MoveToNextLineWithOffsetSetLeading : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetTextMatrix.cs b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/SetTextMatrix.cs similarity index 91% rename from src/UglyToad.Pdf/Graphics/Operations/SetTextMatrix.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextPositioning/SetTextMatrix.cs index bd88333d..32d5b364 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetTextMatrix.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextPositioning/SetTextMatrix.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextPositioning { using System; diff --git a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineShowString.cs b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs similarity index 61% rename from src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineShowString.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs index d3958d28..fbac75bc 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineShowString.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/MoveToNextLineShowText.cs @@ -1,6 +1,6 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextShowing { - internal class MoveToNextLineShowString : IGraphicsStateOperation + internal class MoveToNextLineShowText : IGraphicsStateOperation { public const string Symbol = "'"; @@ -8,7 +8,7 @@ public string Text { get; } - public MoveToNextLineShowString(string text) + public MoveToNextLineShowText(string text) { Text = text; } diff --git a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineShowStringWithSpacing.cs b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs similarity index 67% rename from src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineShowStringWithSpacing.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs index a40c03ea..d4a26f7a 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/MoveToNextLineShowStringWithSpacing.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/MoveToNextLineShowTextWithSpacing.cs @@ -1,6 +1,6 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextShowing { - internal class MoveToNextLineShowStringWithSpacing : IGraphicsStateOperation + internal class MoveToNextLineShowTextWithSpacing : IGraphicsStateOperation { public const string Symbol = "\""; @@ -12,7 +12,7 @@ public string Text { get; } - public MoveToNextLineShowStringWithSpacing(decimal wordSpacing, decimal characterSpacing, string text) + public MoveToNextLineShowTextWithSpacing(decimal wordSpacing, decimal characterSpacing, string text) { WordSpacing = wordSpacing; CharacterSpacing = characterSpacing; diff --git a/src/UglyToad.Pdf/Graphics/Operations/ShowString.cs b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/ShowText.cs similarity index 65% rename from src/UglyToad.Pdf/Graphics/Operations/ShowString.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextShowing/ShowText.cs index 152ff1bb..4cf71ddc 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/ShowString.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/ShowText.cs @@ -1,6 +1,6 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextShowing { - internal class ShowString : IGraphicsStateOperation + internal class ShowText : IGraphicsStateOperation { public const string Symbol = "Tj"; @@ -8,7 +8,7 @@ public string Text { get; } - public ShowString(string text) + public ShowText(string text) { Text = text; } diff --git a/src/UglyToad.Pdf/Graphics/Operations/ShowStringsWithPositioning.cs b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs similarity index 50% rename from src/UglyToad.Pdf/Graphics/Operations/ShowStringsWithPositioning.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs index ea84bc52..61e4d034 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/ShowStringsWithPositioning.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextShowing/ShowTextsWithPositioning.cs @@ -1,6 +1,6 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextShowing { - internal class ShowStringsWithPositioning : IGraphicsStateOperation + internal class ShowTextsWithPositioning : IGraphicsStateOperation { public const string Symbol = "TJ"; @@ -8,7 +8,7 @@ public object[] Array { get; } - public ShowStringsWithPositioning(object[] array) + public ShowTextsWithPositioning(object[] array) { Array = array; } diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetCharacterSpacing.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetCharacterSpacing.cs similarity index 88% rename from src/UglyToad.Pdf/Graphics/Operations/SetCharacterSpacing.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetCharacterSpacing.cs index a853acfa..99105b16 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetCharacterSpacing.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetCharacterSpacing.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { internal class SetCharacterSpacing : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetFontSize.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetFontSize.cs similarity index 89% rename from src/UglyToad.Pdf/Graphics/Operations/SetFontSize.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetFontSize.cs index 437d587b..d1289ff2 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetFontSize.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetFontSize.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { using Cos; diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetHorizontalScaling.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetHorizontalScaling.cs similarity index 87% rename from src/UglyToad.Pdf/Graphics/Operations/SetHorizontalScaling.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetHorizontalScaling.cs index 3886a5e5..9d5c7caf 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetHorizontalScaling.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetHorizontalScaling.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { internal class SetHorizontalScaling : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetTextLeading.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextLeading.cs similarity index 87% rename from src/UglyToad.Pdf/Graphics/Operations/SetTextLeading.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextLeading.cs index 4e125154..4fde77e4 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetTextLeading.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextLeading.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { internal class SetTextLeading : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetTextRenderingMode.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextRenderingMode.cs similarity index 70% rename from src/UglyToad.Pdf/Graphics/Operations/SetTextRenderingMode.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextRenderingMode.cs index cf14ca31..65e6d3e4 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetTextRenderingMode.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextRenderingMode.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { internal class SetTextRenderingMode : IGraphicsStateOperation { @@ -6,11 +6,11 @@ public string Operator => Symbol; - public int Mode { get; } + public RenderingMode Mode { get; } public SetTextRenderingMode(int mode) { - Mode = mode; + Mode = (RenderingMode)mode; } public override string ToString() diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetTextRise.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextRise.cs similarity index 87% rename from src/UglyToad.Pdf/Graphics/Operations/SetTextRise.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextRise.cs index c0ff24d0..99ce4e21 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetTextRise.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetTextRise.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { internal class SetTextRise : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/Operations/SetWordSpacing.cs b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetWordSpacing.cs similarity index 87% rename from src/UglyToad.Pdf/Graphics/Operations/SetWordSpacing.cs rename to src/UglyToad.Pdf/Graphics/Operations/TextState/SetWordSpacing.cs index 08482c77..ba74e3f8 100644 --- a/src/UglyToad.Pdf/Graphics/Operations/SetWordSpacing.cs +++ b/src/UglyToad.Pdf/Graphics/Operations/TextState/SetWordSpacing.cs @@ -1,4 +1,4 @@ -namespace UglyToad.Pdf.Graphics.Operations +namespace UglyToad.Pdf.Graphics.Operations.TextState { internal class SetWordSpacing : IGraphicsStateOperation { diff --git a/src/UglyToad.Pdf/Graphics/RenderingIntent.cs b/src/UglyToad.Pdf/Graphics/RenderingIntent.cs new file mode 100644 index 00000000..7b625d79 --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/RenderingIntent.cs @@ -0,0 +1,44 @@ +namespace UglyToad.Pdf.Graphics +{ + internal enum RenderingIntent + { + /// + /// No correction for the output medium's white point. Colors + /// only represented relative to the light source. + /// + AbsoluteColorimetric = 0, + /// + /// Combines light source and output medium's white point. + /// + RelativeColorimetric = 1, + /// + /// Emphasises saturation rather than colorimetric accuracy. + /// + Saturation = 2, + /// + /// Modifies from colorimetric values to provide a "pleasing perceptual appearance". + /// + Perceptual = 3 + } + + internal static class RenderingIntentExtensions + { + public static RenderingIntent ToRenderingIntent(this string s) + { + switch (s) + { + case "AbsoluteColorimetric": + return RenderingIntent.AbsoluteColorimetric; + case "RelativeColorimetric": + return RenderingIntent.RelativeColorimetric; + case "Saturation": + return RenderingIntent.Saturation; + case "Perceptual": + return RenderingIntent.Perceptual; + default: + // If the application does not recognise the name it uses RelativeColorimetric by default. + return RenderingIntent.RelativeColorimetric; + } + } + } +} diff --git a/src/UglyToad.Pdf/Graphics/RenderingMode.cs b/src/UglyToad.Pdf/Graphics/RenderingMode.cs new file mode 100644 index 00000000..c33e4239 --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/RenderingMode.cs @@ -0,0 +1,44 @@ +namespace UglyToad.Pdf.Graphics +{ + internal enum RenderingMode + { + /// + /// Fill text. + /// + /// + /// Corresponds to filling the entire letter region. + /// + Fill = 0, + /// + /// Stroke text. + /// + /// + /// Corresponds to drawing the border/outline of the letter. + /// + Stroke = 1, + /// + /// Fill then stroke text. + /// + FillThenStroke = 2, + /// + /// Neither fill nor stroke text thereby causing text to become invisible. + /// + Neither = 3, + /// + /// Fill the text and add to the clipping path. + /// + FillClip = 4, + /// + /// Stroke the text and add to the clipping path. + /// + StrokeClip = 5, + /// + /// Fill then stroke the text and then add to the clipping path. + /// + FillThenStrokeClip = 6, + /// + /// Neither fill nor stroke but add to the clipping path. + /// + NeitherClip = 7 + } +} \ No newline at end of file diff --git a/src/UglyToad.Pdf/Graphics/RenderingModeExtensions.cs b/src/UglyToad.Pdf/Graphics/RenderingModeExtensions.cs new file mode 100644 index 00000000..605e5a08 --- /dev/null +++ b/src/UglyToad.Pdf/Graphics/RenderingModeExtensions.cs @@ -0,0 +1,29 @@ +namespace UglyToad.Pdf.Graphics +{ + internal static class RenderingModeExtensions + { + public static bool IsFill(this RenderingMode mode) + { + return mode == RenderingMode.Fill + || mode == RenderingMode.FillThenStroke + || mode == RenderingMode.FillClip + || mode == RenderingMode.FillThenStrokeClip; + } + + public static bool IsStroke(this RenderingMode mode) + { + return mode == RenderingMode.Stroke + || mode == RenderingMode.FillThenStroke + || mode == RenderingMode.StrokeClip + || mode == RenderingMode.FillThenStrokeClip; + } + + public static bool IsClip(this RenderingMode mode) + { + return mode == RenderingMode.FillClip + || mode == RenderingMode.StrokeClip + || mode == RenderingMode.FillThenStrokeClip + || mode == RenderingMode.NeitherClip; + } + } +} \ No newline at end of file