add a run method to all graphics state operations

This commit is contained in:
Eliot Jones
2017-12-02 14:11:20 +00:00
parent ced3a86293
commit 188c6efa61
28 changed files with 291 additions and 93 deletions

View File

@@ -2,6 +2,9 @@
{
using System.Collections.Generic;
using Content;
using IO;
using Pdf.Cos;
using Pdf.Fonts;
using Pdf.Graphics;
internal class TestOperationContext : IOperationContext
@@ -33,10 +36,17 @@
{
StateStack.Push(StateStack.Peek().DeepClone());
}
public void ShowText(IInputBytes bytes)
{
}
}
internal class TestResourceStore : IResourceStore
{
public IFont GetFont(CosName name)
{
return null;
}
}
}

View File

@@ -2,6 +2,7 @@
{
using Pdf.Cos;
using Pdf.Graphics;
using Pdf.Graphics.Core;
using Pdf.Graphics.Operations.General;
using Pdf.Graphics.Operations.TextObjects;
using Pdf.Graphics.Operations.TextPositioning;

View File

@@ -9,7 +9,7 @@
public interface IResourceStore
{
IFont GetFont(CosName name);
}
public class ResourceContainer : IResourceStore
@@ -52,6 +52,11 @@
loadedFonts[pair.Key] = font;
}
}
public IFont GetFont(CosName name)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,67 @@
namespace UglyToad.Pdf.Graphics
{
using System;
using System.Collections.Generic;
using Content;
using Geometry;
using IO;
using Operations;
internal class ContentStreamProcessor : IOperationContext
{
private readonly IResourceStore resourceStore;
private readonly Stack<CurrentGraphicsState> graphicsStack = new Stack<CurrentGraphicsState>();
public TextMatrices TextMatrices { get; } = new TextMatrices();
public int StackSize => graphicsStack.Count;
public ContentStreamProcessor(PdfRectangle cropBox, IResourceStore resourceStore)
{
this.resourceStore = resourceStore;
}
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());
}
public void ShowText(IInputBytes bytes)
{
var renderingMatrix = TextMatrices.GetRenderingMatrix(GetCurrentState());
var font = resourceStore.GetFont(GetCurrentState().FontState.FontName);
}
}
}

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics
namespace UglyToad.Pdf.Graphics.Core
{
internal enum LineCapStyle
{

View File

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

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics
namespace UglyToad.Pdf.Graphics.Core
{
internal enum LineJoinStyle
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics
namespace UglyToad.Pdf.Graphics.Core
{
internal enum RenderingIntent
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics
namespace UglyToad.Pdf.Graphics.Core
{
internal enum RenderingMode
{

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Graphics
namespace UglyToad.Pdf.Graphics.Core
{
internal static class RenderingModeExtensions
{

View File

@@ -3,6 +3,7 @@ namespace UglyToad.Pdf.Graphics
{
using Core;
using Cos;
using Pdf.Core;
/// <summary>
/// The current state of text related parameters for a content stream.

View File

@@ -1,12 +1,15 @@
namespace UglyToad.Pdf.Graphics
{
using System;
using System.Collections.Generic;
using Core;
using Geometry;
using Operations;
using Operations.SpecialGraphicsState;
using Pdf.Core;
/// <summary>
/// The state of the current graphics control parameters.
/// </summary>
/// <remarks>
/// Initialized per page.
/// </remarks>
internal class CurrentGraphicsState : IDeepCloneable<CurrentGraphicsState>
{
/// <summary>
@@ -14,11 +17,6 @@
/// </summary>
public CurrentFontState FontState { get; set; }
/// <summary>
/// Map positions from user coordinates to device coordinates. Values set by <see cref="ModifyCurrentTransformationMatrix"/> (cm).
/// </summary>
public TransformationMatrix CurrentTransformationText { get; set; } = TransformationMatrix.Identity;
/// <summary>
/// Thickness in user space units of path to be stroked.
/// </summary>
@@ -105,78 +103,22 @@
return new CurrentGraphicsState
{
FontState = FontState?.DeepClone(),
RenderingIntent = RenderingIntent
RenderingIntent = RenderingIntent,
LineDashPattern = LineDashPattern,
CurrentTransformationMatrix = CurrentTransformationMatrix,
LineWidth = LineWidth,
JoinStyle = JoinStyle,
Overprint = Overprint,
CapStyle = CapStyle,
MiterLimit = MiterLimit,
Flatness = Flatness,
AlphaConstant = AlphaConstant,
AlphaSource = AlphaSource,
NonStrokingOverprint = NonStrokingOverprint,
OverprintMode = OverprintMode,
Smoothness = Smoothness,
StrokeAdjustment = StrokeAdjustment
};
}
}
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,19 @@
namespace UglyToad.Pdf.Graphics
{
using IO;
internal interface IOperationContext
{
CurrentGraphicsState GetCurrentState();
TextMatrices TextMatrices { get; }
int StackSize { get; }
void PopState();
void PushState();
void ShowText(IInputBytes bytes);
}
}

View File

@@ -2,6 +2,7 @@
{
using System;
using Content;
using Core;
internal class SetLineCap : IGraphicsStateOperation
{

View File

@@ -1,6 +1,7 @@
namespace UglyToad.Pdf.Graphics.Operations.General
{
using Content;
using Core;
internal class SetLineDashPattern : IGraphicsStateOperation
{

View File

@@ -2,6 +2,7 @@
{
using System;
using Content;
using Core;
internal class SetLineJoin : IGraphicsStateOperation
{

View File

@@ -1,7 +1,11 @@
namespace UglyToad.Pdf.Graphics.Operations
{
using Content;
internal interface IGraphicsStateOperation
{
string Operator { get; }
void Run(IOperationContext operationContext, IResourceStore resourceStore);
}
}

View File

@@ -2,7 +2,7 @@
{
using System;
using Content;
using Core;
using Pdf.Core;
internal class ModifyCurrentTransformationMatrix : IGraphicsStateOperation
{

View File

@@ -1,7 +1,7 @@
namespace UglyToad.Pdf.Graphics.Operations.TextObjects
{
using Content;
using Core;
using Pdf.Core;
internal class BeginText : IGraphicsStateOperation
{

View File

@@ -1,7 +1,7 @@
namespace UglyToad.Pdf.Graphics.Operations.TextObjects
{
using Content;
using Core;
using Pdf.Core;
internal class EndText : IGraphicsStateOperation
{

View File

@@ -1,7 +1,7 @@
namespace UglyToad.Pdf.Graphics.Operations.TextPositioning
{
using Content;
using Core;
using Pdf.Core;
/// <summary>
/// Move to the start of the next line offset by Tx Ty.

View File

@@ -2,7 +2,7 @@
{
using System;
using Content;
using Core;
using Pdf.Core;
internal class SetTextMatrix : IGraphicsStateOperation
{

View File

@@ -1,18 +1,41 @@
namespace UglyToad.Pdf.Graphics.Operations.TextShowing
{
using Content;
using TextPositioning;
using Util.JetBrains.Annotations;
internal class MoveToNextLineShowText : IGraphicsStateOperation
{
public const string Symbol = "'";
public string Operator => Symbol;
[CanBeNull]
public string Text { get; }
[CanBeNull]
public byte[] Bytes { get; }
public MoveToNextLineShowText(string text)
{
Text = text;
}
public MoveToNextLineShowText(byte[] hexBytes)
{
Bytes = hexBytes;
}
public void Run(IOperationContext operationContext, IResourceStore resourceStore)
{
var move = MoveToNextLine.Value;
var showText = Text != null ? new ShowText(Text) : new ShowText(Bytes);
move.Run(operationContext, resourceStore);
showText.Run(operationContext, resourceStore);
}
public override string ToString()
{
return $"{Text} {Symbol}";

View File

@@ -1,5 +1,10 @@
namespace UglyToad.Pdf.Graphics.Operations.TextShowing
{
using Content;
using TextPositioning;
using TextState;
using Util.JetBrains.Annotations;
internal class MoveToNextLineShowTextWithSpacing : IGraphicsStateOperation
{
public const string Symbol = "\"";
@@ -10,6 +15,10 @@
public decimal CharacterSpacing { get; }
[CanBeNull]
public byte[] Bytes { get; }
[CanBeNull]
public string Text { get; }
public MoveToNextLineShowTextWithSpacing(decimal wordSpacing, decimal characterSpacing, string text)
@@ -19,6 +28,26 @@
Text = text;
}
public MoveToNextLineShowTextWithSpacing(decimal wordSpacing, decimal characterSpacing, byte[] hexBytes)
{
WordSpacing = wordSpacing;
CharacterSpacing = characterSpacing;
Bytes = hexBytes;
}
public void Run(IOperationContext operationContext, IResourceStore resourceStore)
{
var setWordSpacing = new SetWordSpacing(WordSpacing);
var setCharacterSpacing = new SetCharacterSpacing(CharacterSpacing);
var moveToNextLine = MoveToNextLine.Value;
var showText = Text != null ? new ShowText(Text) : new ShowText(Bytes);
setWordSpacing.Run(operationContext, resourceStore);
setCharacterSpacing.Run(operationContext, resourceStore);
moveToNextLine.Run(operationContext, resourceStore);
showText.Run(operationContext, resourceStore);
}
public override string ToString()
{
return $"{WordSpacing} {CharacterSpacing} {Text} {Symbol}";

View File

@@ -1,18 +1,55 @@
namespace UglyToad.Pdf.Graphics.Operations.TextShowing
{
using Content;
using IO;
using Util;
using Util.JetBrains.Annotations;
/// <summary>
/// Show a text string
/// </summary>
/// <remarks>
/// <para>The input is a sequence of character codes to be shown as glyphs.</para>
/// <para>
/// Generally each byte represents a single character code, however starting in version 1.2+
/// a composite font might use multi-byte character codes to map to glyphs.
/// For these composite fonts, the <see cref="Fonts.Cmap.CMap"/> of the font defines the mapping from code to glyph.
/// </para>
/// <para>
/// The grouping of character codes in arguments to this operator does not have any impact on the meaning; for example:<br/>
/// (Abc) Tj is equivalent to (A) Tj (b) Tj (c) Tj<br/>
/// However grouping character codes makes the document easier to search and extract text from.
/// </para>
/// </remarks>
internal class ShowText : IGraphicsStateOperation
{
public const string Symbol = "Tj";
public string Operator => Symbol;
[CanBeNull]
public string Text { get; }
[CanBeNull]
public byte[] Bytes { get; }
public ShowText(string text)
{
Text = text;
}
public ShowText(byte[] hexBytes)
{
Bytes = hexBytes;
}
public void Run(IOperationContext operationContext, IResourceStore resourceStore)
{
var input = new ByteArrayInputBytes(Text != null ? OtherEncodings.StringAsLatin1Bytes(Text) : Bytes);
operationContext.ShowText(input);
}
public override string ToString()
{
return $"{Text} {Symbol}";

View File

@@ -1,5 +1,8 @@
namespace UglyToad.Pdf.Graphics.Operations.TextShowing
{
using System;
using Content;
internal class ShowTextsWithPositioning : IGraphicsStateOperation
{
public const string Symbol = "TJ";
@@ -12,5 +15,10 @@
{
Array = array;
}
public void Run(IOperationContext operationContext, IResourceStore resourceStore)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,6 +1,7 @@
namespace UglyToad.Pdf.Graphics.Operations.TextState
{
using Content;
using Core;
internal class SetTextRenderingMode : IGraphicsStateOperation
{

View File

@@ -0,0 +1,48 @@
namespace UglyToad.Pdf.Graphics
{
using Pdf.Core;
/// <summary>
/// Manages the Text Matrix (Tm), Text line matrix (Tlm) and Text Rendering Matrix (Trm).
/// </summary>
internal class TextMatrices
{
public TransformationMatrix TextMatrix { get; set; }
public TransformationMatrix TextLineMatrix { get; set; }
/// <summary>
/// Gets the Text Rendering Matrix (Trm) which maps from text space to device space.
/// </summary>
/// <remarks>
/// <para>The rendering matrix is temporary and is calculated for each glyph in a text showing operation.</para>
/// <para>
/// The rendering matrix is calculated as follows:<br/>
/// | (Tfs * Th) 0 0 |<br/>
/// | 0 Tfs 0 | * Tm * CTM<br/>
/// | 0 Trise 1 |<br/>
/// Where Tfs is the font size, Th is the horizontal scaling, Trise is the text rise, Tm is the current <see cref="TextMatrix"/> and CTM is the
/// <see cref="CurrentGraphicsState.CurrentTransformationMatrix"/>.
/// </para>
/// </remarks>
public TransformationMatrix GetRenderingMatrix(CurrentGraphicsState currentGraphicsState)
{
var fontSize = currentGraphicsState.FontState.FontSize;
var horizontalScaling = currentGraphicsState.FontState.HorizontalScaling;
var rise = currentGraphicsState.FontState.Rise;
var initialMatrix = TransformationMatrix.FromArray(new[]
{
(fontSize * horizontalScaling), 0, 0,
0, fontSize, 0,
0, rise, 1
});
var multipledByTextMatrix = initialMatrix.Multiply(TextMatrix);
var result = multipledByTextMatrix.Multiply(currentGraphicsState.CurrentTransformationMatrix);
return result;
}
}
}