mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-14 19:05:01 +08:00
more tidy up of api for type 1 fonts
This commit is contained in:
@@ -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
|
||||||
{
|
{
|
||||||
|
@@ -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)
|
||||||
|
@@ -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>
|
||||||
|
@@ -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>
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user