#21 work on parsing the os2 table to get information for the font descriptor dictionary

This commit is contained in:
Eliot Jones
2018-12-06 19:47:40 +00:00
parent 77311aa6c6
commit c2879ed4b4
10 changed files with 579 additions and 47 deletions

View File

@@ -0,0 +1,9 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Parser
{
using Tables;
internal interface ITrueTypeTableParser<out T> where T : ITable
{
T Parse(TrueTypeHeaderTable header, TrueTypeDataBytes data, TableRegister.Builder register);
}
}

View File

@@ -0,0 +1,104 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Parser
{
using System.Text;
using Tables;
internal class Os2TableParser : ITrueTypeTableParser<Os2Table>
{
public Os2Table Parse(TrueTypeHeaderTable header, TrueTypeDataBytes data, TableRegister.Builder register)
{
data.Seek(header.Offset);
var version = data.ReadUnsignedShort();
var xAvgCharWidth = data.ReadSignedShort();
var weightClass = data.ReadUnsignedShort();
var widthClass = data.ReadUnsignedShort();
var typeFlags = data.ReadUnsignedShort();
var ySubscriptXSize = data.ReadSignedShort();
var ySubscriptYSize = data.ReadSignedShort();
var ySubscriptXOffset = data.ReadSignedShort();
var ySubscriptYOffset = data.ReadSignedShort();
var ySuperscriptXSize = data.ReadSignedShort();
var ySuperscriptYSize = data.ReadSignedShort();
var ySuperscriptXOffset = data.ReadSignedShort();
var ySuperscriptYOffset = data.ReadSignedShort();
var yStrikeoutSize = data.ReadSignedShort();
var yStrikeoutPosition = data.ReadSignedShort();
var familyClass = data.ReadSignedShort();
var panose = data.ReadByteArray(10);
var ulCharRange1 = (uint)data.ReadUnsignedInt();
var ulCharRange2 = (uint)data.ReadUnsignedInt();
var ulCharRange3 = (uint)data.ReadUnsignedInt();
var ulCharRange4 = (uint)data.ReadUnsignedInt();
var vendorId = data.ReadByteArray(4);
var selectionFlags = data.ReadUnsignedShort();
var firstCharacterIndex = data.ReadUnsignedShort();
var lastCharacterIndex = data.ReadUnsignedShort();
var unicodeCharRange = new[] {ulCharRange1, ulCharRange2, ulCharRange3, ulCharRange4};
/*
* Documentation for OS/2 version 0 in Apples TrueType Reference Manual stops at the usLastCharIndex field
* and does not include the last five fields of the table as it was defined by Microsoft.
* Some legacy TrueType fonts may have been built with a shortened version 0 OS/2 table.
* Applications should check the table length for a version 0 OS/2 table before reading these fields.
*/
if (version == 0 && header.Length == 68)
{
return new Os2Table(header, version, xAvgCharWidth,
weightClass, widthClass, typeFlags, ySubscriptXSize,
ySubscriptYSize,
ySubscriptXOffset,
ySubscriptYOffset,
ySuperscriptXSize,
ySuperscriptYSize,
ySuperscriptXOffset,
ySuperscriptYOffset,
yStrikeoutSize,
yStrikeoutPosition,
familyClass,
panose,
unicodeCharRange,
Encoding.Unicode.GetString(vendorId),
selectionFlags,
firstCharacterIndex,
lastCharacterIndex);
}
var sTypoAscender = data.ReadSignedShort();
var sTypoDescender = data.ReadSignedShort();
var sTypoLineGap = data.ReadSignedShort();
var usWinAscent = data.ReadUnsignedShort();
var usWinDescent = data.ReadUnsignedShort();
if (version == 0)
{
return null;
}
var ulCodePageRange1 = data.ReadUnsignedInt();
var ulCodePageRange2 = data.ReadUnsignedInt();
if (version == 1)
{
return null;
}
var sxHeight = data.ReadSignedShort();
var sCapHeight = data.ReadSignedShort();
var usDefaultChar = data.ReadUnsignedShort();
var usBreakChar = data.ReadUnsignedShort();
var usMaxContext = data.ReadUnsignedShort();
if (version < 5)
{
return null;
}
var usLowerOpticalPointSize = data.ReadUnsignedShort();
var usUpperOpticalPointSize = data.ReadUnsignedShort();
return null;
}
}
}

View File

@@ -16,48 +16,4 @@
throw new NotImplementedException();
}
}
internal class Os2TableParser : ITrueTypeTableParser<Os2Table>
{
public Os2Table Parse(TrueTypeHeaderTable header, TrueTypeDataBytes data, TableRegister.Builder register)
{
data.Seek(header.Offset);
var version = data.ReadUnsignedShort();
var xAvgCharWidth = data.ReadSignedShort();
var usWeightClass = data.ReadUnsignedShort();
var usWidthClass = data.ReadUnsignedShort();
var fsType = data.ReadSignedShort();
var ySubscriptXSize = data.ReadSignedShort();
var ySubscriptYSize = data.ReadSignedShort();
var ySubscriptXOffset = data.ReadSignedShort();
var ySubscriptYOffset = data.ReadSignedShort();
var ySuperscriptXSize = data.ReadSignedShort();
var ySuperscriptYSize = data.ReadSignedShort();
var ySuperscriptXOffset = data.ReadSignedShort();
var ySuperscriptYOffset = data.ReadSignedShort();
var yStrikeoutSize = data.ReadSignedShort();
var yStrikeoutPosition = data.ReadSignedShort();
var sFamilyClass = data.ReadSignedShort();
var panose = data.ReadByteArray(10);
var ulCharRange1 = data.ReadUnsignedInt();
var ulCharRange2 = data.ReadUnsignedInt();
var ulCharRange3 = data.ReadUnsignedInt();
var ulCharRange4 = data.ReadUnsignedInt();
var vendorId = data.ReadByteArray(4);
var fsSelection = data.ReadUnsignedShort();
var fsFirstCharIndex = data.ReadUnsignedShort();
var fsLastCharIndex = data.ReadUnsignedShort();
var bytesRead = data.Position - header.Offset;
return null;
}
}
internal interface ITrueTypeTableParser<out T> where T : ITable
{
T Parse(TrueTypeHeaderTable header, TrueTypeDataBytes data, TableRegister.Builder register);
}
}

View File

@@ -77,7 +77,7 @@
{
int characterCode = (i << 8) + (subHeader.FirstCode + j);
var p = data.ReadUnsignedShort();
var p = (int)data.ReadUnsignedShort();
if (p > 0)
{

View File

@@ -0,0 +1,72 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
{
using System.Collections.Generic;
/// <summary>
/// Version 0 was defined in TrueType revision 1.5 and includes fields not in the Apple specification.
/// </summary>
internal class Os2RevisedVersion0Table : Os2Table
{
public short TypographicAscender { get; }
public short TypographicDescender { get; }
public short TypographicLineGap { get; }
public ushort WindowsAscent { get; }
public ushort WindowsDescent { get; }
public Os2RevisedVersion0Table(TrueTypeHeaderTable directoryTable, ushort version, short xAverageCharacterWidth, ushort weightClass,
ushort widthClass,
ushort typeFlags,
short ySubscriptXSize,
short ySubscriptYSize,
short ySubscriptXOffset,
short ySubscriptYOffset,
short ySuperscriptXSize,
short ySuperscriptYSize,
short ySuperscriptXOffset,
short ySuperscriptYOffset,
short yStrikeoutSize,
short yStrikeoutPosition,
short familyClass,
IReadOnlyList<byte> panose,
IReadOnlyList<uint> unicodeRanges,
string vendorId,
ushort fontSelectionFlags,
ushort firstCharacterIndex,
ushort lastCharacterIndex,
short typographicAscender,
short typographicDescender,
short typographicLineGap,
ushort windowsAscent,
ushort windowsDescent) : base(directoryTable, version, xAverageCharacterWidth, weightClass,
widthClass,
typeFlags,
ySubscriptXSize,
ySubscriptYSize,
ySubscriptXOffset,
ySubscriptYOffset,
ySuperscriptXSize,
ySuperscriptYSize,
ySuperscriptXOffset,
ySuperscriptYOffset,
yStrikeoutSize,
yStrikeoutPosition,
familyClass,
panose,
unicodeRanges,
vendorId,
fontSelectionFlags,
firstCharacterIndex,
lastCharacterIndex)
{
TypographicAscender = typographicAscender;
TypographicDescender = typographicDescender;
TypographicLineGap = typographicLineGap;
WindowsAscent = windowsAscent;
WindowsDescent = windowsDescent;
}
}
}

View File

@@ -1,9 +1,178 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
{
using System.Collections.Generic;
/// <summary>
/// The most basic format of the OS/2 table, excluding the fields not included in the Apple version of the specification.
/// </summary>
internal class Os2Table : ITable
{
public string Tag => TrueTypeHeaderTable.Os2;
public TrueTypeHeaderTable DirectoryTable { get; }
/// <summary>
/// The version number 0 - 5 detailing the layout of the OS/2 table.
/// </summary>
public ushort Version { get; }
/// <summary>
/// The average width of all non-zero width characters in the font.
/// </summary>
public short XAverageCharacterWidth { get; }
/// <summary>
/// Indicates the visual weight of characters in the font from 1 - 1000.
/// </summary>
public ushort WeightClass { get; }
/// <summary>
/// The percentage difference from normal of the aspect ratio for this font.
/// </summary>
public ushort WidthClass { get; }
/// <summary>
/// The font embedding licensing rights for this font.
/// </summary>
public ushort TypeFlags { get; }
/// <summary>
/// The recommended horizontal size for subscripts using this font.
/// </summary>
public short YSubscriptXSize { get; }
/// <summary>
/// The recommended vertical size for subscripts using this font.
/// </summary>
public short YSubscriptYSize { get; }
/// <summary>
/// The recommended horizontal offset (from the previous glyph origin to the subscript's origin) for subscripts using this font.
/// </summary>
public short YSubscriptXOffset { get; }
/// <summary>
/// The recommended vertical offset (from the previous glyph origin to the subscript's origin) for subscripts using this font.
/// </summary>
public short YSubscriptYOffset { get; }
/// <summary>
/// The recommended horizontal size for superscripts using this font.
/// </summary>
public short YSuperscriptXSize { get; }
/// <summary>
/// The recommended vertical size for superscripts using this font.
/// </summary>
public short YSuperscriptYSize { get; }
/// <summary>
/// The recommended horizontal offset (from the previous glyph origin to the superscript's origin) for superscripts using this font.
/// </summary>
public short YSuperscriptXOffset { get; }
/// <summary>
/// The recommended vertical offset (from the previous glyph origin to the superscript's origin) for superscripts using this font.
/// </summary>
public short YSuperscriptYOffset { get; }
/// <summary>
/// Thickness of the strikeout stroke.
/// </summary>
public short YStrikeoutSize { get; }
/// <summary>
/// Position of the top of the strikeout stroke relative to the baseline.
/// Positive values being above the baseline, negative values below.
/// </summary>
public short YStrikeoutPosition { get; }
/// <summary>
/// Value registered by IBM for each font family to find substitutes.
/// The high byte is the family class, the low byte is the family subclass.
/// </summary>
public short FamilyClass { get; }
/// <summary>
/// The PANOSE definition of 10 bytes defines various information about the
/// font enabling matching fonts based on requirements. The meaning of each
/// byte in the PANOSE definition depends on the preceding bytes. The first byte
/// is the family type, Lating, Latin Hand Written, etc.
/// </summary>
public IReadOnlyList<byte> Panose { get; }
/// <summary>
/// Specifies Unicode blocks supported by the font file for the Microsoft platform.
/// </summary>
public IReadOnlyList<uint> UnicodeRanges { get; }
/// <summary>
/// The four-character identifier for the vendor of the given type face.
/// </summary>
public string VendorId { get; }
/// <summary>
/// Contains information concerning the nature of the font patterns.
/// </summary>
public ushort FontSelectionFlags { get; }
/// <summary>
/// The minimum Unicode character code in this font.
/// </summary>
public ushort FirstCharacterIndex { get; }
/// <summary>
/// The maximum Unicode character code in this font.
/// </summary>
public ushort LastCharacterIndex { get; }
/// <summary>
/// Create a new <see cref="Os2Table"/>.
/// </summary>
public Os2Table(TrueTypeHeaderTable directoryTable, ushort version, short xAverageCharacterWidth, ushort weightClass,
ushort widthClass,
ushort typeFlags,
short ySubscriptXSize,
short ySubscriptYSize,
short ySubscriptXOffset,
short ySubscriptYOffset,
short ySuperscriptXSize,
short ySuperscriptYSize,
short ySuperscriptXOffset,
short ySuperscriptYOffset,
short yStrikeoutSize,
short yStrikeoutPosition,
short familyClass,
IReadOnlyList<byte> panose,
IReadOnlyList<uint> unicodeRanges,
string vendorId,
ushort fontSelectionFlags,
ushort firstCharacterIndex,
ushort lastCharacterIndex)
{
DirectoryTable = directoryTable;
Version = version;
XAverageCharacterWidth = xAverageCharacterWidth;
WeightClass = weightClass;
WidthClass = widthClass;
TypeFlags = typeFlags;
YSubscriptXSize = ySubscriptXSize;
YSubscriptYSize = ySubscriptYSize;
YSubscriptXOffset = ySubscriptXOffset;
YSubscriptYOffset = ySubscriptYOffset;
YSuperscriptXSize = ySuperscriptXSize;
YSuperscriptYSize = ySuperscriptYSize;
YSuperscriptXOffset = ySuperscriptXOffset;
YSuperscriptYOffset = ySuperscriptYOffset;
YStrikeoutSize = yStrikeoutSize;
YStrikeoutPosition = yStrikeoutPosition;
FamilyClass = familyClass;
Panose = panose;
UnicodeRanges = unicodeRanges;
VendorId = vendorId;
FontSelectionFlags = fontSelectionFlags;
FirstCharacterIndex = firstCharacterIndex;
LastCharacterIndex = lastCharacterIndex;
}
}
}

View File

@@ -0,0 +1,55 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
{
using System.Collections.Generic;
/// <summary>
/// Version 1 was defined in TrueType revision 1.66. Version 1 has two additional fields beyond those in version 0.
/// </summary>
internal class Os2Version1Table : Os2RevisedVersion0Table
{
/// <summary>
/// This field is used to specify the code pages encompassed by the font file in the 'cmap' subtable for the Microsoft platform(3), Unicode BMP encoding (1).
/// </summary>
public byte CodePage1 { get; }
/// <summary>
/// This field is the second byte used to specify the code pages encompassed by the font file in the 'cmap' subtable for the Microsoft platform(3), Unicode BMP encoding (1).
/// </summary>
public byte CodePage2 { get; }
public Os2Version1Table(TrueTypeHeaderTable directoryTable, ushort version, short xAverageCharacterWidth, ushort weightClass, ushort widthClass,
ushort typeFlags,
short ySubscriptXSize,
short ySubscriptYSize,
short ySubscriptXOffset,
short ySubscriptYOffset,
short ySuperscriptXSize,
short ySuperscriptYSize,
short ySuperscriptXOffset,
short ySuperscriptYOffset,
short yStrikeoutSize,
short yStrikeoutPosition,
short familyClass,
IReadOnlyList<byte> panose,
IReadOnlyList<uint> unicodeRanges,
string vendorId,
ushort fontSelectionFlags,
ushort firstCharacterIndex,
ushort lastCharacterIndex,
short typographicAscender,
short typographicDescender,
short typographicLineGap,
ushort windowsAscent,
ushort windowsDescent,
byte codePage1,
byte codePage2) : base(directoryTable, version, xAverageCharacterWidth, weightClass, widthClass,
typeFlags, ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, ySubscriptYOffset, ySuperscriptXSize,
ySuperscriptYSize, ySuperscriptXOffset, ySuperscriptYOffset, yStrikeoutSize, yStrikeoutPosition,
familyClass, panose, unicodeRanges, vendorId, fontSelectionFlags, firstCharacterIndex, lastCharacterIndex,
typographicAscender, typographicDescender, typographicLineGap, windowsAscent, windowsDescent)
{
CodePage1 = codePage1;
CodePage2 = codePage2;
}
}
}

View File

@@ -0,0 +1,92 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
{
using System.Collections.Generic;
/// <summary>
/// Version 4 was defined in OpenType 1.5. Version 4 has the same fields as in version 2 and version 3.
/// Although new fields were not added beyond those in version 2 and 3, the specification of certain fields was revised.
/// </summary>
internal class Os2Version2To4OpenTypeTable : Os2Version1Table
{
/// <summary>
/// This metric specifies the distance between the baseline and the approximate height of non-ascending lowercase letters.
/// </summary>
public short XHeight { get; }
/// <summary>
/// This metric specifies the distance between the baseline and the approximate height of uppercase letters.
/// </summary>
public short CapHeight { get; }
/// <summary>
/// This is the Unicode code point, in UTF-16 encoding, of a character that can be used for a default glyph if a requested character is not supported.
/// If the value of this field is zero, glyph Id 0 is to be used for the default character.
/// </summary>
public ushort DefaultCharacter { get; }
/// <summary>
/// This is the Unicode code point, in UTF-16 encoding, of a character that can be used as a default break character.
/// The break character is used to separate words and justify text.
/// Most fonts specify U+0020 SPACE as the break character.
/// </summary>
public ushort BreakCharacter { get; }
/// <summary>
/// The maximum distance in glyphs that any feature of this font is capable of effecting. For example
/// kerning has a value of 2 (1 for each glyph in the kerning pair).
/// Fonts with the 'f f i' ligature would have a value of 3.
/// </summary>
public ushort MaximumContext { get; }
/// <summary>
/// Create a new <see cref="Os2Version2To4OpenTypeTable"/>.
/// </summary>
public Os2Version2To4OpenTypeTable(TrueTypeHeaderTable directoryTable, ushort version,
short xAverageCharacterWidth,
ushort weightClass,
ushort widthClass,
ushort typeFlags,
short ySubscriptXSize,
short ySubscriptYSize,
short ySubscriptXOffset,
short ySubscriptYOffset,
short ySuperscriptXSize,
short ySuperscriptYSize,
short ySuperscriptXOffset,
short ySuperscriptYOffset,
short yStrikeoutSize,
short yStrikeoutPosition,
short familyClass,
IReadOnlyList<byte> panose,
IReadOnlyList<uint> unicodeRanges,
string vendorId,
ushort fontSelectionFlags,
ushort firstCharacterIndex,
ushort lastCharacterIndex,
short typographicAscender,
short typographicDescender,
short typographicLineGap,
ushort windowsAscent,
ushort windowsDescent,
byte codePage1,
byte codePage2,
short xHeight,
short capHeight,
ushort defaultCharacter,
ushort breakCharacter,
ushort maximumContext) : base(directoryTable, version, xAverageCharacterWidth, weightClass, widthClass,
typeFlags, ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, ySubscriptYOffset, ySuperscriptXSize,
ySuperscriptYSize, ySuperscriptXOffset, ySuperscriptYOffset, yStrikeoutSize, yStrikeoutPosition,
familyClass, panose, unicodeRanges, vendorId, fontSelectionFlags, firstCharacterIndex, lastCharacterIndex,
typographicAscender, typographicDescender, typographicLineGap, windowsAscent, windowsDescent,
codePage1, codePage2)
{
XHeight = xHeight;
CapHeight = capHeight;
DefaultCharacter = defaultCharacter;
BreakCharacter = breakCharacter;
MaximumContext = maximumContext;
}
}
}

View File

@@ -0,0 +1,75 @@
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
{
using System.Collections.Generic;
/// <summary>
/// Version 5 was defined in OpenType 1.7.
/// Version 5 has two additional fields beyond those in versions 2 - 4.
/// </summary>
internal class Os2Version5OpenTypeTable : Os2Version2To4OpenTypeTable
{
/// <summary>
/// This value is the lower value of the size range for which this font has been designed.
/// The units for this field are TWIPs (one-twentieth of a point, or 1440 per inch).
/// This is the inclusive lower bound.
/// </summary>
public ushort LowerOpticalPointSize { get; }
/// <summary>
/// This value is the upper value of the size range for which this font has been designed.
/// The units for this field are TWIPs (one-twentieth of a point, or 1440 per inch).
/// This is the exclusive upper bound.
/// </summary>
public ushort UpperOpticalPointSize { get; }
/// <summary>
/// Create a new <see cref="Os2Version5OpenTypeTable"/>.
/// </summary>
public Os2Version5OpenTypeTable(TrueTypeHeaderTable directoryTable,
ushort version, short xAverageCharacterWidth,
ushort weightClass,
ushort widthClass,
ushort typeFlags,
short ySubscriptXSize,
short ySubscriptYSize,
short ySubscriptXOffset,
short ySubscriptYOffset,
short ySuperscriptXSize,
short ySuperscriptYSize,
short ySuperscriptXOffset,
short ySuperscriptYOffset,
short yStrikeoutSize,
short yStrikeoutPosition,
short familyClass,
IReadOnlyList<byte> panose,
IReadOnlyList<uint> unicodeRanges,
string vendorId,
ushort fontSelectionFlags,
ushort firstCharacterIndex,
ushort lastCharacterIndex,
short typographicAscender,
short typographicDescender,
short typographicLineGap,
ushort windowsAscent,
ushort windowsDescent,
byte codePage1,
byte codePage2,
short xHeight,
short capHeight,
ushort defaultCharacter,
ushort breakCharacter,
ushort maximumContext,
ushort lowerOpticalPointSize,
ushort upperOpticalPointSize) : base(directoryTable, version, xAverageCharacterWidth, weightClass,
widthClass, typeFlags, ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, ySubscriptYOffset,
ySuperscriptXSize, ySuperscriptYSize, ySuperscriptXOffset, ySuperscriptYOffset, yStrikeoutSize,
yStrikeoutPosition, familyClass, panose, unicodeRanges, vendorId, fontSelectionFlags,
firstCharacterIndex, lastCharacterIndex, typographicAscender, typographicDescender,
typographicLineGap, windowsAscent, windowsDescent, codePage1, codePage2, xHeight,
capHeight, defaultCharacter, breakCharacter, maximumContext)
{
LowerOpticalPointSize = lowerOpticalPointSize;
UpperOpticalPointSize = upperOpticalPointSize;
}
}
}

View File

@@ -31,11 +31,11 @@
return unchecked((short)((internalBuffer[0] << 8) + (internalBuffer[1] << 0)));
}
public int ReadUnsignedShort()
public ushort ReadUnsignedShort()
{
ReadBuffered(internalBuffer, 2);
return (internalBuffer[0] << 8) + (internalBuffer[1] << 0);
return (ushort)((internalBuffer[0] << 8) + (internalBuffer[1] << 0));
}
public int ReadUnsignedByte()