mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-03-10 00:23:29 +08:00
make classes internal and scaffold reading of glyphs
This commit is contained in:
@@ -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 = @"
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
src/UglyToad.Pdf/Geometry/PdfVector.cs
Normal file
25
src/UglyToad.Pdf/Geometry/PdfVector.cs
Normal 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})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user