more tidy up of api for type 1 fonts

This commit is contained in:
Eliot Jones
2018-11-01 22:26:10 +00:00
parent 1fb2f879d9
commit ab9de799f9
6 changed files with 64 additions and 17 deletions

View File

@@ -13,7 +13,6 @@
using Tokenization.Tokens;
using Type1;
using Type1.Parser;
using Util;
internal class Type1FontHandler : IFontHandler
{

View File

@@ -8,6 +8,9 @@
internal class Type1CharStrings
{
private readonly object locker = new object();
private readonly Dictionary<string, CommandSequence> charStrings = new Dictionary<string, CommandSequence>();
public IReadOnlyDictionary<string, CommandSequence> CharStrings { get; }
public IReadOnlyDictionary<int, CommandSequence> Subroutines { get; }
@@ -18,8 +21,39 @@
Subroutines = subroutines ?? throw new ArgumentNullException(nameof(subroutines));
}
public void Generate(string name)
{
lock (locker)
{
if (charStrings.TryGetValue(name, out var result))
{
return;
}
}
if (!CharStrings.TryGetValue(name, out var sequence))
{
throw new InvalidOperationException($"No charstring sequence with the name /{name} in this font.");
}
Run(sequence);
lock (locker)
{
charStrings[name] = sequence;
}
}
private void Run(CommandSequence sequence)
{
}
public class CommandSequence
{
/// <summary>
/// The ordered list of numbers and commands for a Type 1 charstring or subroutine.
/// </summary>
public IReadOnlyList<DiscriminatedUnion<decimal, LazyType1Command>> Commands { get; }
public CommandSequence(IReadOnlyList<DiscriminatedUnion<decimal, LazyType1Command>> commands)

View File

@@ -7,7 +7,6 @@
using IO;
using PdfPig.Parser.Parts;
using Tokenization.Tokens;
using Util;
internal class Type1EncryptedPortionParser
{
@@ -17,7 +16,7 @@
private const int Password = 5839;
private const int CharstringEncryptionKey = 4330;
public IReadOnlyList<byte> Parse(IReadOnlyList<byte> bytes, bool isLenientParsing)
public (Type1PrivateDictionary, Type1CharStrings) Parse(IReadOnlyList<byte> bytes, bool isLenientParsing)
{
if (!IsBinary(bytes))
{
@@ -26,10 +25,8 @@
var decrypted = Decrypt(bytes, EexecEncryptionKey, EexecRandomBytes);
// line 461 of type1parser.java
var str = OtherEncodings.BytesAsLatin1String(decrypted.ToArray());
var tokenizer = new Type1Tokenizer(new ByteArrayInputBytes(decrypted));
/*
* After 4 random characters follows the /Private dictionary and the /CharString dictionary.
* The first defines a number of technical terms involving character construction, and contains also an array of subroutines used in character paths.
@@ -54,8 +51,8 @@
var length = next.AsInt();
ReadExpected(tokenizer, Type1Token.TokenType.Name, "dict");
// actually could also be "/Private 10 dict def Private begin"
// instead of the "dup"
// Could also be "/Private 10 dict def Private begin" instead of the "dup"
ReadExpectedAfterOptional(tokenizer, Type1Token.TokenType.Name, "def", Type1Token.TokenType.Name, "dup");
ReadExpected(tokenizer, Type1Token.TokenType.Name, "begin");
@@ -85,6 +82,7 @@
case Type1Symbols.RdProcedureAlt:
{
var procedureTokens = ReadProcedure(tokenizer);
builder.Rd = procedureTokens;
ReadTillDef(tokenizer);
break;
}
@@ -92,6 +90,7 @@
case Type1Symbols.NoAccessDefAlt:
{
var procedureTokens = ReadProcedure(tokenizer);
builder.NoAccessDef = procedureTokens;
ReadTillDef(tokenizer);
break;
}
@@ -99,6 +98,7 @@
case Type1Symbols.NoAccessPutAlt:
{
var procedureTokens = ReadProcedure(tokenizer);
builder.NoAccessPut = procedureTokens;
ReadTillDef(tokenizer);
break;
}
@@ -290,14 +290,15 @@
charStrings = new Type1CharstringDecryptedBytes[0];
}
var privateDictionary = builder.Build();
var instructions = Type1CharStringParser.Parse(charStrings, builder.Subroutines ?? new Type1CharstringDecryptedBytes[0]);
return decrypted;
return (privateDictionary, instructions);
}
/// <summary>
/// To distinguish between binary and hex the first 4 bytes (of the ciphertext) for hex must
/// obey these restrictions:
/// To distinguish between binary and hex the first 4 bytes (of the ciphertext) for hex must obey these restrictions:
/// The first byte must not be whitespace.
/// One of the first four ciphertext bytes must not be an ASCII hex character.
/// </summary>

View File

@@ -146,9 +146,9 @@
var matrix = GetFontMatrix(dictionaries);
var boundingBox = GetBoundingBox(dictionaries);
var binaryPortion = encryptedPortionParser.Parse(eexecPortion, false);
var (privateDictionary, charStrings) = encryptedPortionParser.Parse(eexecPortion, false);
return new Type1Font(name, encoding, matrix, boundingBox ?? new PdfRectangle());
return new Type1Font(name, encoding, matrix, boundingBox ?? new PdfRectangle(), privateDictionary);
}
/// <summary>

View File

@@ -1,7 +1,7 @@
namespace UglyToad.PdfPig.Fonts.Type1
{
using System;
using System.Collections.Generic;
using Cos;
using Geometry;
using Tokenization.Tokens;
using Util.JetBrains.Annotations;
@@ -21,12 +21,16 @@
[CanBeNull]
public PdfRectangle BoundingBox { get; }
public Type1Font(string name, IReadOnlyDictionary<int, string> encoding, ArrayToken fontMatrix, PdfRectangle boundingBox)
public Type1PrivateDictionary PrivateDictionary { get; }
public Type1Font(string name, IReadOnlyDictionary<int, string> encoding, ArrayToken fontMatrix, PdfRectangle boundingBox,
Type1PrivateDictionary privateDictionary)
{
Name = name;
Encoding = encoding;
FontMatrix = fontMatrix;
BoundingBox = boundingBox;
PrivateDictionary = privateDictionary ?? throw new ArgumentNullException(nameof(privateDictionary));
}
}
}

View File

@@ -321,6 +321,15 @@
/// <see cref="Type1PrivateDictionary.ExpansionFactor"/>.
/// </summary>
public decimal? ExpansionFactor { get; set; }
/// <summary>
/// Generate a <see cref="Type1PrivateDictionary"/> from the values in this builder.
/// </summary>
/// <returns>The generated <see cref="Type1PrivateDictionary"/>.</returns>
public Type1PrivateDictionary Build()
{
return new Type1PrivateDictionary(this);
}
}
}
}