arrange operations into folders in line with grouping from the specification and start creating a context to mutate through operations.

This commit is contained in:
Eliot Jones
2017-11-26 22:19:42 +00:00
parent b0e53efbfe
commit ed634e86fe
55 changed files with 831 additions and 144 deletions

View File

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

View File

@@ -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<InvalidOperationException>(action);
}
[Fact]
public void CannotPopWithNoFrames()
{
context.StateStack.Pop();
Action action = () => Pop.Value.Run(context, resourceStore);
Assert.Throws<InvalidOperationException>(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);
}
}
}

View File

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

View File

@@ -0,0 +1,42 @@
namespace UglyToad.Pdf.Tests.Graphics
{
using System.Collections.Generic;
using Content;
using Pdf.Graphics;
internal class TestOperationContext : IOperationContext
{
public Stack<CurrentGraphicsState> StateStack { get; }
= new Stack<CurrentGraphicsState>();
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
{
}
}

View File

@@ -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<SetFontSize>(result.GraphicsStateOperations[1]);
Assert.Equal(CosName.Create("F13"), font.Font);
Assert.Equal(48, font.Size);
var nextLine = Assert.IsType<MoveToNextLineWithOffset>(result.GraphicsStateOperations[2]);
Assert.Equal(20, nextLine.Tx);
Assert.Equal(38, nextLine.Ty);
var renderingMode = Assert.IsType<SetTextRenderingMode>(result.GraphicsStateOperations[3]);
Assert.Equal(RenderingMode.Stroke, renderingMode.Mode);
var lineWidth = Assert.IsType<SetLineWidth>(result.GraphicsStateOperations[4]);
Assert.Equal(2, lineWidth.Width);
var text = Assert.IsType<ShowText>(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<MoveToNextLineWithOffset>(result.GraphicsStateOperations[1]);
Assert.Equal(21, moveLine.Tx);
Assert.Equal(32, moveLine.Ty);
var renderingMode = Assert.IsType<SetTextRenderingMode>(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

View File

@@ -7,7 +7,12 @@
using Fonts;
using Parser;
public class ResourceContainer
public interface IResourceStore
{
}
public class ResourceContainer : IResourceStore
{
private readonly Dictionary<CosName, IFont> loadedFonts = new Dictionary<CosName, IFont>();

View File

@@ -0,0 +1,7 @@
namespace UglyToad.Pdf.Core
{
public interface IDeepCloneable<out T>
{
T DeepClone();
}
}

View File

@@ -0,0 +1,84 @@
// ReSharper disable RedundantDefaultMemberInitializer
namespace UglyToad.Pdf.Graphics
{
using Core;
using Cos;
/// <summary>
/// The current state of text related parameters for a content stream.
/// </summary>
internal class CurrentFontState : IDeepCloneable<CurrentFontState>
{
/// <summary>
/// A value in unscaled text space units which is added to the horizontal (or vertical if in vertical writing mode)
/// glyph displacement.
/// </summary>
/// <remarks>
/// In horizontal writing mode a positive value will expand the distance between letters/glyphs.
/// Default value 0.
/// </remarks>
public decimal CharacterSpacing { get; set; } = 0;
/// <summary>
/// As for <see cref="CharacterSpacing"/> but applies only for the space character (32).
/// </summary>
/// <remarks>
/// Default value 0.
/// </remarks>
public decimal WordSpacing { get; set; } = 0;
/// <summary>
/// Adjusts the width of glyphs/letters by stretching (or compressing) them horizontally.
/// Value is a percentage of the normal width.
/// </summary>
public decimal HorizontalScaling { get; set; } = 100;
/// <summary>
/// The vertical distance in unscaled text space units between the baselines of lines of text.
/// </summary>
public decimal Leading { get; set; }
public CosName FontName { get; set; }
public decimal FontSize { get; set; }
/// <summary>
/// The <see cref="RenderingMode"/> for glyph outlines.
/// </summary>
/// <remarks>
/// When the rendering mode requires filling the current non-stroking color in the state is used.<br/>
/// When the rendering mode requires stroking the current stroking color in the state is used.<br/>
/// The rendering mode has no impact on Type 3 fonts.
/// </remarks>
public RenderingMode RenderingMode { get; set; } = RenderingMode.Fill;
/// <summary>
/// The distance in unscaled text space units to move the default baseline either up or down.
/// </summary>
/// <remarks>
/// Always applies to the vertical coordinate irrespective or writing mode.
/// </remarks>
public decimal Rise { get; set; }
/// <summary>
/// Are all glpyhs in a text object treated as a single elementary object for the purpose of the transparent imaging model?
/// </summary>
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
};
}
}
}

View File

@@ -0,0 +1,176 @@
namespace UglyToad.Pdf.Graphics
{
using System;
using System.Collections.Generic;
using Core;
using Geometry;
using Operations;
internal class CurrentGraphicsState : IDeepCloneable<CurrentGraphicsState>
{
/// <summary>
/// The <see cref="CurrentFontState"/> for this graphics state.
/// </summary>
public CurrentFontState FontState { get; set; }
/// <summary>
/// Thickness in user space units of path to be stroked.
/// </summary>
public decimal LineWidth { get; set; } = 1;
/// <summary>
/// Specifies the shape of line ends for open stroked paths.
/// </summary>
public LineCapStyle CapStyle { get; set; } = LineCapStyle.Butt;
/// <summary>
/// Specifies the shape of joins between connected stroked path segments.
/// </summary>
public LineJoinStyle JoinStyle { get; set; } = LineJoinStyle.Miter;
/// <summary>
/// Maximum length of mitered line joins for paths before becoming a bevel.
/// </summary>
public decimal MiterLimit { get; set; } = 10;
/// <summary>
/// The pattern to be used for stroked lines.
/// </summary>
public LineDashPattern LineDashPattern { get; set; } = LineDashPattern.Solid;
/// <summary>
/// The rendering intent to use when converting CIE-based colors to device colors.
/// </summary>
public RenderingIntent RenderingIntent { get; set; } = RenderingIntent.RelativeColorimetric;
/// <summary>
/// Should a correction for rasterization effects be applied?
/// </summary>
public bool StrokeAdjustment { get; set; } = false;
/// <summary>
/// Opacity value to be used for transparent imaging.
/// </summary>
public decimal AlphaConstant { get; set; } = 1;
/// <summary>
/// Should soft mask and alpha constant values be interpreted as shape (<see langword="true"/>) or opacity (<see langword="false"/>) values?
/// </summary>
public bool AlphaSource { get; set; } = false;
/// <summary>
/// Maps positions from user coordinates to device coordinates.
/// </summary>
public TransformationMatrix CurrentTransformationMatrix { get; set; } = TransformationMatrix.Default;
#region Device Dependent
/// <summary>
/// Should painting in a colorant set erase (<see langword="false"/>)
/// or leave unchanged (<see langword="true"/>) areas of other colorant sets?
/// </summary>
public bool Overprint { get; set; } = false;
/// <summary>
/// As for <see cref="Overprint"/> but with non-stroking operations.
/// </summary>
public bool NonStrokingOverprint { get; set; } = false;
/// <summary>
/// In DeviceCMYK color space a value of 0 for a component will erase a component (0)
/// or leave it unchanged (1) for overprinting.
/// </summary>
public decimal OverprintMode { get; set; }
/// <summary>
/// The precision for rendering curves, smaller numbers give smoother curves.
/// </summary>
public decimal Flatness { get; set; } = 1;
/// <summary>
/// The precision for rendering color gradients on the output device.
/// </summary>
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<CurrentGraphicsState> graphicsStack = new Stack<CurrentGraphicsState>();
public TextMatrices TextMatrices { get; private set; } = new TextMatrices();
public int StackSize => graphicsStack.Count;
public ContentStreamProcessor(PdfRectangle cropBox)
{
}
public void Process(IReadOnlyList<IGraphicsStateOperation> operations)
{
var currentState = CloneAllStates();
}
private void ProcessOperations(IReadOnlyList<IGraphicsStateOperation> operations)
{
foreach (var stateOperation in operations)
{
// stateOperation.Run();
}
}
private Stack<CurrentGraphicsState> CloneAllStates()
{
throw new NotImplementedException();
}
public CurrentGraphicsState GetCurrentState()
{
return graphicsStack.Peek();
}
public void PopState()
{
graphicsStack.Pop();
}
public void PushState()
{
graphicsStack.Push(graphicsStack.Peek().DeepClone());
}
}
}

View File

@@ -0,0 +1,9 @@
namespace UglyToad.Pdf.Graphics
{
internal enum LineCapStyle
{
Butt = 0,
Round = 1,
ProjectingSquare = 2
}
}

View File

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

View File

@@ -0,0 +1,9 @@
namespace UglyToad.Pdf.Graphics
{
internal enum LineJoinStyle
{
Miter = 0,
Round = 1,
Bevel = 2
}
}

View File

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

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.ClippingPaths
{
internal class ModifyClippingByNonZeroWindingIntersect : IGraphicsStateOperation
{

View File

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

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.General
{
internal class SetColorRenderingIntent : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.General
{
internal class SetFlatnessTolerance : IGraphicsStateOperation
{

View File

@@ -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
}
}
}

View File

@@ -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}";
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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}";

View File

@@ -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()
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
using Geometry;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
using Geometry;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
using Geometry;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
using Geometry;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
using Geometry;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
using Geometry;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.PathConstruction
{
internal class CloseSubpath : IGraphicsStateOperation
{

View File

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

View File

@@ -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}";
}
}
}

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.SpecialGraphicsState
{
using System;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextPositioning
{
internal class MoveToNextLine : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextPositioning
{
internal class MoveToNextLineWithOffset : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextPositioning
{
internal class MoveToNextLineWithOffsetSetLeading : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextPositioning
{
using System;

View File

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

View File

@@ -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;

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
internal class SetCharacterSpacing : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
using Cos;

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
internal class SetHorizontalScaling : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
internal class SetTextLeading : IGraphicsStateOperation
{

View File

@@ -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()

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
internal class SetTextRise : IGraphicsStateOperation
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics.Operations
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
internal class SetWordSpacing : IGraphicsStateOperation
{

View File

@@ -0,0 +1,44 @@
namespace UglyToad.Pdf.Graphics
{
internal enum RenderingIntent
{
/// <summary>
/// No correction for the output medium's white point. Colors
/// only represented relative to the light source.
/// </summary>
AbsoluteColorimetric = 0,
/// <summary>
/// Combines light source and output medium's white point.
/// </summary>
RelativeColorimetric = 1,
/// <summary>
/// Emphasises saturation rather than colorimetric accuracy.
/// </summary>
Saturation = 2,
/// <summary>
/// Modifies from colorimetric values to provide a "pleasing perceptual appearance".
/// </summary>
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;
}
}
}
}

View File

@@ -0,0 +1,44 @@
namespace UglyToad.Pdf.Graphics
{
internal enum RenderingMode
{
/// <summary>
/// Fill text.
/// </summary>
/// <remarks>
/// Corresponds to filling the entire letter region.
/// </remarks>
Fill = 0,
/// <summary>
/// Stroke text.
/// </summary>
/// <remarks>
/// Corresponds to drawing the border/outline of the letter.
/// </remarks>
Stroke = 1,
/// <summary>
/// Fill then stroke text.
/// </summary>
FillThenStroke = 2,
/// <summary>
/// Neither fill nor stroke text thereby causing text to become invisible.
/// </summary>
Neither = 3,
/// <summary>
/// Fill the text and add to the clipping path.
/// </summary>
FillClip = 4,
/// <summary>
/// Stroke the text and add to the clipping path.
/// </summary>
StrokeClip = 5,
/// <summary>
/// Fill then stroke the text and then add to the clipping path.
/// </summary>
FillThenStrokeClip = 6,
/// <summary>
/// Neither fill nor stroke but add to the clipping path.
/// </summary>
NeitherClip = 7
}
}

View File

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