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 Tokenization.Tokens;
using Type1; using Type1;
using Type1.Parser; using Type1.Parser;
using Util;
internal class Type1FontHandler : IFontHandler internal class Type1FontHandler : IFontHandler
{ {

View File

@@ -8,18 +8,52 @@
internal class Type1CharStrings 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<string, CommandSequence> CharStrings { get; }
public IReadOnlyDictionary<int, CommandSequence> Subroutines { get; } public IReadOnlyDictionary<int, CommandSequence> Subroutines { get; }
public Type1CharStrings(IReadOnlyDictionary<string, CommandSequence> charStrings, IReadOnlyDictionary<int, CommandSequence> subroutines) public Type1CharStrings(IReadOnlyDictionary<string, CommandSequence> charStrings, IReadOnlyDictionary<int, CommandSequence> subroutines)
{ {
CharStrings = charStrings ?? throw new ArgumentNullException(nameof(charStrings)); CharStrings = charStrings ?? throw new ArgumentNullException(nameof(charStrings));
Subroutines = subroutines ?? throw new ArgumentNullException(nameof(subroutines)); 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 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 IReadOnlyList<DiscriminatedUnion<decimal, LazyType1Command>> Commands { get; }
public CommandSequence(IReadOnlyList<DiscriminatedUnion<decimal, LazyType1Command>> commands) public CommandSequence(IReadOnlyList<DiscriminatedUnion<decimal, LazyType1Command>> commands)

View File

@@ -7,7 +7,6 @@
using IO; using IO;
using PdfPig.Parser.Parts; using PdfPig.Parser.Parts;
using Tokenization.Tokens; using Tokenization.Tokens;
using Util;
internal class Type1EncryptedPortionParser internal class Type1EncryptedPortionParser
{ {
@@ -17,7 +16,7 @@
private const int Password = 5839; private const int Password = 5839;
private const int CharstringEncryptionKey = 4330; 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)) if (!IsBinary(bytes))
{ {
@@ -25,11 +24,9 @@
} }
var decrypted = Decrypt(bytes, EexecEncryptionKey, EexecRandomBytes); var decrypted = Decrypt(bytes, EexecEncryptionKey, EexecRandomBytes);
// line 461 of type1parser.java
var str = OtherEncodings.BytesAsLatin1String(decrypted.ToArray());
var tokenizer = new Type1Tokenizer(new ByteArrayInputBytes(decrypted)); var tokenizer = new Type1Tokenizer(new ByteArrayInputBytes(decrypted));
/* /*
* After 4 random characters follows the /Private dictionary and the /CharString dictionary. * 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. * 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(); var length = next.AsInt();
ReadExpected(tokenizer, Type1Token.TokenType.Name, "dict"); 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"); ReadExpectedAfterOptional(tokenizer, Type1Token.TokenType.Name, "def", Type1Token.TokenType.Name, "dup");
ReadExpected(tokenizer, Type1Token.TokenType.Name, "begin"); ReadExpected(tokenizer, Type1Token.TokenType.Name, "begin");
@@ -85,6 +82,7 @@
case Type1Symbols.RdProcedureAlt: case Type1Symbols.RdProcedureAlt:
{ {
var procedureTokens = ReadProcedure(tokenizer); var procedureTokens = ReadProcedure(tokenizer);
builder.Rd = procedureTokens;
ReadTillDef(tokenizer); ReadTillDef(tokenizer);
break; break;
} }
@@ -92,6 +90,7 @@
case Type1Symbols.NoAccessDefAlt: case Type1Symbols.NoAccessDefAlt:
{ {
var procedureTokens = ReadProcedure(tokenizer); var procedureTokens = ReadProcedure(tokenizer);
builder.NoAccessDef = procedureTokens;
ReadTillDef(tokenizer); ReadTillDef(tokenizer);
break; break;
} }
@@ -99,6 +98,7 @@
case Type1Symbols.NoAccessPutAlt: case Type1Symbols.NoAccessPutAlt:
{ {
var procedureTokens = ReadProcedure(tokenizer); var procedureTokens = ReadProcedure(tokenizer);
builder.NoAccessPut = procedureTokens;
ReadTillDef(tokenizer); ReadTillDef(tokenizer);
break; break;
} }
@@ -290,14 +290,15 @@
charStrings = new Type1CharstringDecryptedBytes[0]; charStrings = new Type1CharstringDecryptedBytes[0];
} }
var privateDictionary = builder.Build();
var instructions = Type1CharStringParser.Parse(charStrings, builder.Subroutines ?? new Type1CharstringDecryptedBytes[0]); var instructions = Type1CharStringParser.Parse(charStrings, builder.Subroutines ?? new Type1CharstringDecryptedBytes[0]);
return decrypted; return (privateDictionary, instructions);
} }
/// <summary> /// <summary>
/// To distinguish between binary and hex the first 4 bytes (of the ciphertext) for hex must /// To distinguish between binary and hex the first 4 bytes (of the ciphertext) for hex must obey these restrictions:
/// obey these restrictions:
/// The first byte must not be whitespace. /// The first byte must not be whitespace.
/// One of the first four ciphertext bytes must not be an ASCII hex character. /// One of the first four ciphertext bytes must not be an ASCII hex character.
/// </summary> /// </summary>

View File

@@ -146,9 +146,9 @@
var matrix = GetFontMatrix(dictionaries); var matrix = GetFontMatrix(dictionaries);
var boundingBox = GetBoundingBox(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> /// <summary>

View File

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

View File

@@ -321,6 +321,15 @@
/// <see cref="Type1PrivateDictionary.ExpansionFactor"/>. /// <see cref="Type1PrivateDictionary.ExpansionFactor"/>.
/// </summary> /// </summary>
public decimal? ExpansionFactor { get; set; } 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);
}
} }
} }
} }