mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
add postscript table
This commit is contained in:
parent
c0618a303f
commit
8d9960ef98
@ -74,6 +74,20 @@
|
||||
|
||||
var maximumProfile = BasicMaximumProfileTable.Load(data, maxHeaderTable);
|
||||
|
||||
var postScriptTable = default(PostScriptTable);
|
||||
if (tables.TryGetValue(TrueTypeHeaderTable.Post, out var postscriptHeaderTable))
|
||||
{
|
||||
postScriptTable = PostScriptTable.Load(data, table, maximumProfile);
|
||||
}
|
||||
|
||||
if (!isPostScript)
|
||||
{
|
||||
if (!tables.TryGetValue(TrueTypeHeaderTable.Loca, out var indexToLocationHeaderTable))
|
||||
{
|
||||
throw new InvalidOperationException("The location to index table is required for non-PostScript fonts.");
|
||||
}
|
||||
}
|
||||
|
||||
return new TrueTypeFont(version, header);
|
||||
}
|
||||
}
|
||||
|
212
src/UglyToad.Pdf/Fonts/TrueType/Tables/PostScriptTable.cs
Normal file
212
src/UglyToad.Pdf/Fonts/TrueType/Tables/PostScriptTable.cs
Normal file
@ -0,0 +1,212 @@
|
||||
namespace UglyToad.Pdf.Fonts.TrueType.Tables
|
||||
{
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// This table contains information for TrueType fonts on PostScript printers.
|
||||
/// This includes data for the FontInfo dictionary and the PostScript glyph names.
|
||||
/// </summary>
|
||||
internal class PostScriptTable : ITable
|
||||
{
|
||||
public string Tag => TrueTypeHeaderTable.Post;
|
||||
|
||||
public TrueTypeHeaderTable DirectoryTable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Format 1 contains the 258 standard Mac TrueType font file.<br/>
|
||||
/// Format 2 is the Microsoft font format.<br/>
|
||||
/// Format 2.5 is a space optimised subset of the standard Mac glyph set.<br/>
|
||||
/// Format 3 enables a special font type which provides no PostScript information.<br/>
|
||||
/// </summary>
|
||||
public decimal FormatType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Angle in counter-clockwise degrees from vertical. 0 for upright text, negative for right-leaning text.
|
||||
/// </summary>
|
||||
public decimal ItalicAngle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Suggested values for the underline position with negative values below the baseline.
|
||||
/// </summary>
|
||||
public short UnderlinePosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Suggested values for the underline thickness.
|
||||
/// </summary>
|
||||
public short UnderlineThickness { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 0 if the font is proportionally spaced, non-zero for monospace or other
|
||||
/// non-proportional spacing.
|
||||
/// </summary>
|
||||
public long IsFixedPitch { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum memory usage when the TrueType font is downloaded.
|
||||
/// </summary>
|
||||
public long MinimumMemoryType42 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum memory usage when the TrueType font is downloaded.
|
||||
/// </summary>
|
||||
public long MaximumMemoryType42 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum memory usage when the TrueType font is downloaded as a Type 1 font.
|
||||
/// </summary>
|
||||
public long MinimumMemoryType1 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum memory usage when the TrueType font is downloaded as a Type 1 font.
|
||||
/// </summary>
|
||||
public long MaximumMemoryType1 { get; }
|
||||
|
||||
public string[] GlyphNames { get; }
|
||||
|
||||
public PostScriptTable(TrueTypeHeaderTable directoryTable, decimal formatType, decimal italicAngle, short underlinePosition, short underlineThickness, long isFixedPitch, long minimumMemoryType42, long maximumMemoryType42, long minimumMemoryType1, long maximumMemoryType1, string[] glyphNames)
|
||||
{
|
||||
DirectoryTable = directoryTable;
|
||||
FormatType = formatType;
|
||||
ItalicAngle = italicAngle;
|
||||
UnderlinePosition = underlinePosition;
|
||||
UnderlineThickness = underlineThickness;
|
||||
IsFixedPitch = isFixedPitch;
|
||||
MinimumMemoryType42 = minimumMemoryType42;
|
||||
MaximumMemoryType42 = maximumMemoryType42;
|
||||
MinimumMemoryType1 = minimumMemoryType1;
|
||||
MaximumMemoryType1 = maximumMemoryType1;
|
||||
GlyphNames = glyphNames ?? throw new ArgumentNullException(nameof(glyphNames));
|
||||
}
|
||||
|
||||
public static PostScriptTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, BasicMaximumProfileTable maximumProfileTable)
|
||||
{
|
||||
data.Seek(table.Offset - 1);
|
||||
var formatType = data.Read32Fixed();
|
||||
var italicAngle = data.Read32Fixed();
|
||||
var underlinePosition = data.ReadSignedShort();
|
||||
var underlineThickness = data.ReadSignedShort();
|
||||
var isFixedPitch = data.ReadUnsignedInt();
|
||||
var minMemType42 = data.ReadUnsignedInt();
|
||||
var maxMemType42 = data.ReadUnsignedInt();
|
||||
var mimMemType1 = data.ReadUnsignedInt();
|
||||
var maxMemType1 = data.ReadUnsignedInt();
|
||||
|
||||
var glyphNames = GetGlyphNamesByFormat(data, maximumProfileTable, formatType);
|
||||
|
||||
return new PostScriptTable(table, (decimal)formatType, (decimal)italicAngle,
|
||||
underlinePosition, underlineThickness, isFixedPitch,
|
||||
minMemType42, maxMemType42, mimMemType1,
|
||||
maxMemType1, glyphNames);
|
||||
}
|
||||
|
||||
private static string[] GetGlyphNamesByFormat(TrueTypeDataBytes data, BasicMaximumProfileTable maximumProfileTable,
|
||||
float formatType)
|
||||
{
|
||||
string[] glyphNames;
|
||||
if (Math.Abs(formatType - 1) < float.Epsilon)
|
||||
{
|
||||
glyphNames = new string[WindowsGlyphList4.NumberOfMacGlyphs];
|
||||
Array.Copy(WindowsGlyphList4.MacGlyphNames, glyphNames, WindowsGlyphList4.NumberOfMacGlyphs);
|
||||
}
|
||||
else if (Math.Abs(formatType - 2) < float.Epsilon)
|
||||
{
|
||||
glyphNames = GetFormat2GlyphNames(data);
|
||||
}
|
||||
else if (Math.Abs(formatType - 2.5) < float.Epsilon)
|
||||
{
|
||||
var glyphNameIndex = new int[maximumProfileTable?.NumberOfGlyphs ?? 0];
|
||||
|
||||
for (var i = 0; i < glyphNameIndex.Length; i++)
|
||||
{
|
||||
var offset = data.ReadSignedByte();
|
||||
glyphNameIndex[i] = i + 1 + offset;
|
||||
}
|
||||
|
||||
glyphNames = new string[glyphNameIndex.Length];
|
||||
|
||||
for (var i = 0; i < glyphNames.Length; i++)
|
||||
{
|
||||
var name = WindowsGlyphList4.MacGlyphNames[glyphNameIndex[i]];
|
||||
|
||||
if (name != null)
|
||||
{
|
||||
glyphNames[i] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Math.Abs(formatType - 3) < float.Epsilon)
|
||||
{
|
||||
glyphNames = new string[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Format type {formatType} is not supported for the PostScript table.");
|
||||
}
|
||||
|
||||
return glyphNames;
|
||||
}
|
||||
|
||||
private static string[] GetFormat2GlyphNames(TrueTypeDataBytes data)
|
||||
{
|
||||
const int reservedIndexStart = 32768;
|
||||
|
||||
var numberOfGlyphs = data.ReadUnsignedShort();
|
||||
|
||||
var glyphNameIndex = new int[numberOfGlyphs];
|
||||
|
||||
var glyphNames = new string[numberOfGlyphs];
|
||||
|
||||
var maxIndex = int.MinValue;
|
||||
for (var i = 0; i < numberOfGlyphs; i++)
|
||||
{
|
||||
var index = data.ReadUnsignedShort();
|
||||
|
||||
glyphNameIndex[i] = index;
|
||||
|
||||
if (index < reservedIndexStart)
|
||||
{
|
||||
maxIndex = Math.Max(maxIndex, index);
|
||||
}
|
||||
}
|
||||
|
||||
var nameArray = default(string[]);
|
||||
|
||||
if (maxIndex >= WindowsGlyphList4.NumberOfMacGlyphs)
|
||||
{
|
||||
var namesLength = maxIndex - WindowsGlyphList4.NumberOfMacGlyphs + 1;
|
||||
nameArray = new string[namesLength];
|
||||
|
||||
for (var i = 0; i < namesLength; i++)
|
||||
{
|
||||
var numberOfCharacters = data.ReadUnsignedByte();
|
||||
nameArray[i] = data.ReadString(numberOfCharacters, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberOfGlyphs; i++)
|
||||
{
|
||||
var index = glyphNameIndex[i];
|
||||
if (index < WindowsGlyphList4.NumberOfMacGlyphs)
|
||||
{
|
||||
glyphNames[i] = WindowsGlyphList4.MacGlyphNames[index];
|
||||
}
|
||||
else if (index >= WindowsGlyphList4.NumberOfMacGlyphs && index < reservedIndexStart)
|
||||
{
|
||||
if (nameArray == null)
|
||||
{
|
||||
throw new InvalidOperationException("The name array was null despite the number of glyphs exceeding the maximum Mac Glyphs.");
|
||||
}
|
||||
|
||||
glyphNames[i] = nameArray[index - WindowsGlyphList4.NumberOfMacGlyphs];
|
||||
}
|
||||
else
|
||||
{
|
||||
glyphNames[i] = ".undefined";
|
||||
}
|
||||
}
|
||||
|
||||
return glyphNames;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,14 @@
|
||||
return (internalBuffer[0] << 8) + (internalBuffer[1] << 0);
|
||||
}
|
||||
|
||||
public int ReadUnsignedByte()
|
||||
{
|
||||
ReadBuffered(internalBuffer, 1);
|
||||
|
||||
// TODO: the cast from int -> byte -> int here suggest we are treating data incorrectly.
|
||||
return internalBuffer[0];
|
||||
}
|
||||
|
||||
private void ReadBuffered(byte[] buffer, int length)
|
||||
{
|
||||
var numberRead = 0;
|
||||
@ -69,7 +77,7 @@
|
||||
public long ReadUnsignedInt()
|
||||
{
|
||||
ReadBuffered(internalBuffer, 4);
|
||||
|
||||
|
||||
return (internalBuffer[0] << 24) + (internalBuffer[1] << 16) + (internalBuffer[2] << 8) + (internalBuffer[3] << 0);
|
||||
}
|
||||
|
||||
@ -93,7 +101,7 @@
|
||||
{
|
||||
// TODO: this returns the wrong value, investigate...
|
||||
long secondsSince1904 = ReadLong();
|
||||
|
||||
|
||||
var date = new DateTime(1904, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
var result = date.AddSeconds(secondsSince1904);
|
||||
@ -118,5 +126,12 @@
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int ReadSignedByte()
|
||||
{
|
||||
ReadBuffered(internalBuffer, 1);
|
||||
var signedByte = internalBuffer[0];
|
||||
return signedByte < 127 ? signedByte : signedByte - 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
76
src/UglyToad.Pdf/Fonts/TrueType/WindowsGlyphList4.cs
Normal file
76
src/UglyToad.Pdf/Fonts/TrueType/WindowsGlyphList4.cs
Normal file
@ -0,0 +1,76 @@
|
||||
namespace UglyToad.Pdf.Fonts.TrueType
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
internal static class WindowsGlyphList4
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of standard mac glyph names.
|
||||
/// </summary>
|
||||
public static readonly int NumberOfMacGlyphs = 258;
|
||||
|
||||
/// <summary>
|
||||
/// The 258 standard mac glyph names used in 'post' format 1 and 2.
|
||||
/// </summary>
|
||||
public static readonly string[] MacGlyphNames = {
|
||||
".notdef",".null", "nonmarkingreturn", "space", "exclam", "quotedbl",
|
||||
"numbersign", "dollar", "percent", "ampersand", "quotesingle",
|
||||
"parenleft", "parenright", "asterisk", "plus", "comma", "hyphen",
|
||||
"period", "slash", "zero", "one", "two", "three", "four", "five",
|
||||
"six", "seven", "eight", "nine", "colon", "semicolon", "less",
|
||||
"equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
|
||||
"T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
|
||||
"bracketright", "asciicircum", "underscore", "grave", "a", "b",
|
||||
"c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
|
||||
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft",
|
||||
"bar", "braceright", "asciitilde", "Adieresis", "Aring",
|
||||
"Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute",
|
||||
"agrave", "acircumflex", "adieresis", "atilde", "aring",
|
||||
"ccedilla", "eacute", "egrave", "ecircumflex", "edieresis",
|
||||
"iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute",
|
||||
"ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave",
|
||||
"ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
|
||||
"section", "bullet", "paragraph", "germandbls", "registered",
|
||||
"copyright", "trademark", "acute", "dieresis", "notequal", "AE",
|
||||
"Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
|
||||
"yen", "mu", "partialdiff", "summation", "product", "pi",
|
||||
"integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash",
|
||||
"questiondown", "exclamdown", "logicalnot", "radical", "florin",
|
||||
"approxequal", "Delta", "guillemotleft", "guillemotright",
|
||||
"ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE",
|
||||
"oe", "endash", "emdash", "quotedblleft", "quotedblright",
|
||||
"quoteleft", "quoteright", "divide", "lozenge", "ydieresis",
|
||||
"Ydieresis", "fraction", "currency", "guilsinglleft",
|
||||
"guilsinglright", "fi", "fl", "daggerdbl", "periodcentered",
|
||||
"quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
|
||||
"Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
|
||||
"Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
|
||||
"apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
|
||||
"circumflex", "tilde", "macron", "breve", "dotaccent", "ring",
|
||||
"cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash",
|
||||
"Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
|
||||
"Yacute", "yacute", "Thorn", "thorn", "minus", "multiply",
|
||||
"onesuperior", "twosuperior", "threesuperior", "onehalf",
|
||||
"onequarter", "threequarters", "franc", "Gbreve", "gbreve",
|
||||
"Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron",
|
||||
"ccaron", "dcroat"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The indices of the standard mac glyph names.
|
||||
/// </summary>
|
||||
public static readonly IReadOnlyDictionary<string, int> MacGlyphNamesIndices;
|
||||
|
||||
static WindowsGlyphList4()
|
||||
{
|
||||
var indices = new Dictionary<string, int>(NumberOfMacGlyphs);
|
||||
for (int i = 0; i < NumberOfMacGlyphs; ++i)
|
||||
{
|
||||
indices[MacGlyphNames[i]] = i;
|
||||
}
|
||||
|
||||
MacGlyphNamesIndices = indices;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user