mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-19 19:07:56 +08:00
add a run method to all graphics state operations
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
67
src/UglyToad.Pdf/Graphics/ContentStreamProcessor.cs
Normal file
67
src/UglyToad.Pdf/Graphics/ContentStreamProcessor.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Graphics
|
||||
namespace UglyToad.Pdf.Graphics.Core
|
||||
{
|
||||
internal enum LineCapStyle
|
||||
{
|
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Graphics
|
||||
namespace UglyToad.Pdf.Graphics.Core
|
||||
{
|
||||
using System;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Graphics
|
||||
namespace UglyToad.Pdf.Graphics.Core
|
||||
{
|
||||
internal enum LineJoinStyle
|
||||
{
|
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Graphics
|
||||
namespace UglyToad.Pdf.Graphics.Core
|
||||
{
|
||||
internal enum RenderingIntent
|
||||
{
|
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Graphics
|
||||
namespace UglyToad.Pdf.Graphics.Core
|
||||
{
|
||||
internal enum RenderingMode
|
||||
{
|
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Graphics
|
||||
namespace UglyToad.Pdf.Graphics.Core
|
||||
{
|
||||
internal static class RenderingModeExtensions
|
||||
{
|
@@ -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.
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
src/UglyToad.Pdf/Graphics/IOperationContext.cs
Normal file
19
src/UglyToad.Pdf/Graphics/IOperationContext.cs
Normal 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);
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
{
|
||||
using System;
|
||||
using Content;
|
||||
using Core;
|
||||
|
||||
internal class SetLineCap : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -1,6 +1,7 @@
|
||||
namespace UglyToad.Pdf.Graphics.Operations.General
|
||||
{
|
||||
using Content;
|
||||
using Core;
|
||||
|
||||
internal class SetLineDashPattern : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@
|
||||
{
|
||||
using System;
|
||||
using Content;
|
||||
using Core;
|
||||
|
||||
internal class SetLineJoin : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -1,7 +1,11 @@
|
||||
namespace UglyToad.Pdf.Graphics.Operations
|
||||
{
|
||||
using Content;
|
||||
|
||||
internal interface IGraphicsStateOperation
|
||||
{
|
||||
string Operator { get; }
|
||||
|
||||
void Run(IOperationContext operationContext, IResourceStore resourceStore);
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System;
|
||||
using Content;
|
||||
using Core;
|
||||
using Pdf.Core;
|
||||
|
||||
internal class ModifyCurrentTransformationMatrix : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
namespace UglyToad.Pdf.Graphics.Operations.TextObjects
|
||||
{
|
||||
using Content;
|
||||
using Core;
|
||||
using Pdf.Core;
|
||||
|
||||
internal class BeginText : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
namespace UglyToad.Pdf.Graphics.Operations.TextObjects
|
||||
{
|
||||
using Content;
|
||||
using Core;
|
||||
using Pdf.Core;
|
||||
|
||||
internal class EndText : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -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.
|
||||
|
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System;
|
||||
using Content;
|
||||
using Core;
|
||||
using Pdf.Core;
|
||||
|
||||
internal class SetTextMatrix : IGraphicsStateOperation
|
||||
{
|
||||
|
@@ -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}";
|
||||
|
@@ -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}";
|
||||
|
@@ -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}";
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
namespace UglyToad.Pdf.Graphics.Operations.TextState
|
||||
{
|
||||
using Content;
|
||||
using Core;
|
||||
|
||||
internal class SetTextRenderingMode : IGraphicsStateOperation
|
||||
{
|
||||
|
48
src/UglyToad.Pdf/Graphics/TextMatrices.cs
Normal file
48
src/UglyToad.Pdf/Graphics/TextMatrices.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user