make classes internal and scaffold reading of glyphs

This commit is contained in:
Eliot Jones
2017-12-02 14:57:44 +00:00
parent 188c6efa61
commit 257439b8a3
9 changed files with 153 additions and 36 deletions

View File

@@ -38,28 +38,28 @@ ET";
var result = parser.Parse(operationFactory, input.Bytes);
Assert.Equal(7, result.GraphicsStateOperations.Count);
Assert.Equal(7, result.Count);
Assert.Equal(BeginText.Value, result.GraphicsStateOperations[0]);
Assert.Equal(BeginText.Value, result[0]);
var font = Assert.IsType<SetFontAndSize>(result.GraphicsStateOperations[1]);
var font = Assert.IsType<SetFontAndSize>(result[1]);
Assert.Equal(CosName.Create("F13"), font.Font);
Assert.Equal(48, font.Size);
var nextLine = Assert.IsType<MoveToNextLineWithOffset>(result.GraphicsStateOperations[2]);
var nextLine = Assert.IsType<MoveToNextLineWithOffset>(result[2]);
Assert.Equal(20, nextLine.Tx);
Assert.Equal(38, nextLine.Ty);
var renderingMode = Assert.IsType<SetTextRenderingMode>(result.GraphicsStateOperations[3]);
var renderingMode = Assert.IsType<SetTextRenderingMode>(result[3]);
Assert.Equal(RenderingMode.Stroke, renderingMode.Mode);
var lineWidth = Assert.IsType<SetLineWidth>(result.GraphicsStateOperations[4]);
var lineWidth = Assert.IsType<SetLineWidth>(result[4]);
Assert.Equal(2, lineWidth.Width);
var text = Assert.IsType<ShowText>(result.GraphicsStateOperations[5]);
var text = Assert.IsType<ShowText>(result[5]);
Assert.Equal("ABC", text.Text);
Assert.Equal(EndText.Value, result.GraphicsStateOperations[6]);
Assert.Equal(EndText.Value, result[6]);
}
[Fact]
@@ -74,18 +74,18 @@ ET";
var result = parser.Parse(operationFactory, input.Bytes);
Assert.Equal(4, result.GraphicsStateOperations.Count);
Assert.Equal(4, result.Count);
Assert.Equal(BeginText.Value, result.GraphicsStateOperations[0]);
Assert.Equal(BeginText.Value, result[0]);
var moveLine = Assert.IsType<MoveToNextLineWithOffset>(result.GraphicsStateOperations[1]);
var moveLine = Assert.IsType<MoveToNextLineWithOffset>(result[1]);
Assert.Equal(21, moveLine.Tx);
Assert.Equal(32, moveLine.Ty);
var renderingMode = Assert.IsType<SetTextRenderingMode>(result.GraphicsStateOperations[2]);
var renderingMode = Assert.IsType<SetTextRenderingMode>(result[2]);
Assert.Equal(RenderingMode.Fill, renderingMode.Mode);
Assert.Equal(EndText.Value, result.GraphicsStateOperations[3]);
Assert.Equal(EndText.Value, result[3]);
}
private const string SimpleGoogleDocPageContent = @"

View File

@@ -93,8 +93,10 @@
var textContents = OtherEncodings.BytesAsLatin1String(contents);
}
Content = parsingArguments.Container.Get<PageContentParser>()
var operations = parsingArguments.Container.Get<PageContentParser>()
.Parse(parsingArguments.Container.Get<IGraphicsStateOperationFactory>(), new ByteArrayInputBytes(contents));
}
}
}

View File

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

View File

@@ -166,5 +166,15 @@
{
return $"{A}, {B}, 0\r\n{C}, {D}, 0\r\n{E}, {F}, 1";
}
public static TransformationMatrix GetTranslationMatrix(decimal x, decimal y)
{
return new TransformationMatrix(new []
{
1, 0, 0,
0, 1, 0,
x, y, 1
});
}
}
}

View File

@@ -2,22 +2,50 @@
{
using Cmap;
using Cos;
using Geometry;
using IO;
public interface IFont
internal interface IFont
{
CosName Name { get; }
CosName SubType { get; }
string BaseFontType { get; }
CMap ToUnicode { get; }
bool IsVertical { get; }
int ReadCharacterCode(IInputBytes bytes, out int codeLength);
string GetUnicode(int characterCode);
PdfVector GetDisplacement(int characterCode);
}
public class CompositeFont : IFont
internal class CompositeFont : IFont
{
public CosName Name { get; }
public CosName SubType { get; }
public string BaseFontType { get; }
public bool IsVertical { get; }
public CMap ToUnicode { get; }
public int ReadCharacterCode(IInputBytes bytes, out int codeLength)
{
throw new System.NotImplementedException();
}
public string GetUnicode(int characterCode)
{
throw new System.NotImplementedException();
}
public PdfVector GetDisplacement(int characterCode)
{
throw new System.NotImplementedException();
}
}
}

View File

@@ -0,0 +1,25 @@
namespace UglyToad.Pdf.Geometry
{
internal struct PdfVector
{
public decimal X { get; }
public decimal Y { get; }
public PdfVector(decimal x, decimal y)
{
X = x;
Y = y;
}
public PdfVector Scale(decimal scale)
{
return new PdfVector(X * scale, Y * scale);
}
public override string ToString()
{
return $"({X}, {Y})";
}
}
}

View File

@@ -3,43 +3,50 @@
using System;
using System.Collections.Generic;
using Content;
using Fonts;
using Geometry;
using IO;
using Operations;
using Pdf.Core;
internal class ContentStreamProcessor : IOperationContext
{
private readonly IResourceStore resourceStore;
private readonly Stack<CurrentGraphicsState> graphicsStack = new Stack<CurrentGraphicsState>();
private 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)
public PageContent Process(IReadOnlyList<IGraphicsStateOperation> operations)
{
var currentState = CloneAllStates();
ProcessOperations(operations);
return new PageContent();
}
private void ProcessOperations(IReadOnlyList<IGraphicsStateOperation> operations)
{
foreach (var stateOperation in operations)
{
// stateOperation.Run();
stateOperation.Run(this, resourceStore);
}
}
private Stack<CurrentGraphicsState> CloneAllStates()
{
throw new NotImplementedException();
var saved = graphicsStack;
graphicsStack = new Stack<CurrentGraphicsState>();
graphicsStack.Push(saved.Peek().DeepClone());
return saved;
}
public CurrentGraphicsState GetCurrentState()
@@ -59,9 +66,57 @@
public void ShowText(IInputBytes bytes)
{
var renderingMatrix = TextMatrices.GetRenderingMatrix(GetCurrentState());
var font = resourceStore.GetFont(GetCurrentState().FontState.FontName);
var fontSize = GetCurrentState().FontState.FontSize;
var horizontalScaling = GetCurrentState().FontState.HorizontalScaling;
var characterSpacing = GetCurrentState().FontState.CharacterSpacing;
while (bytes.MoveNext())
{
var code = font.ReadCharacterCode(bytes, out int codeLength);
var unicode = font.GetUnicode(code);
var wordSpacing = 0m;
if (code == ' ' && codeLength == 1)
{
wordSpacing += GetCurrentState().FontState.WordSpacing;
}
var renderingMatrix = TextMatrices.GetRenderingMatrix(GetCurrentState());
if (font.IsVertical)
{
throw new NotImplementedException("Vertical fonts are currently unsupported, please submit a pull request.");
}
var displacement = font.GetDisplacement(code);
ShowGlyph(renderingMatrix, font, code, unicode, displacement);
decimal tx, ty;
if (font.IsVertical)
{
tx = 0;
ty = displacement.Y * fontSize + characterSpacing + wordSpacing;
}
else
{
tx = (displacement.X * fontSize + characterSpacing + wordSpacing) * horizontalScaling;
ty = 0;
}
var translate = TransformationMatrix.GetTranslationMatrix(tx, ty);
TextMatrices.TextMatrix = translate.Multiply(TextMatrices.TextMatrix);
}
}
private void ShowGlyph(TransformationMatrix renderingMatrix, IFont font,
int characterCode, string unicode, PdfVector displacement)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,11 +1,12 @@
namespace UglyToad.Pdf.Parser
{
using Content;
using System.Collections.Generic;
using Graphics;
using Graphics.Operations;
using IO;
internal interface IPageContentParser
{
PageContent Parse(IGraphicsStateOperationFactory operationFactory, IInputBytes inputBytes);
IReadOnlyList<IGraphicsStateOperation> Parse(IGraphicsStateOperationFactory operationFactory, IInputBytes inputBytes);
}
}

View File

@@ -1,7 +1,6 @@
namespace UglyToad.Pdf.Parser
{
using System.Collections.Generic;
using Content;
using Graphics;
using Graphics.Operations;
using IO;
@@ -10,7 +9,7 @@
internal class PageContentParser : IPageContentParser
{
public PageContent Parse(IGraphicsStateOperationFactory operationFactory, IInputBytes inputBytes)
public IReadOnlyList<IGraphicsStateOperation> Parse(IGraphicsStateOperationFactory operationFactory, IInputBytes inputBytes)
{
var scanner = new CoreTokenScanner(inputBytes);
@@ -41,10 +40,7 @@
}
}
return new PageContent
{
GraphicsStateOperations = graphicsStateOperations
};
return graphicsStateOperations;
}
}
}