mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-20 11:37:57 +08:00
add horizontal header table parsing
This commit is contained in:
@@ -69,7 +69,7 @@
|
|||||||
Assert.Equal(2396, font.HeaderTable.XMax);
|
Assert.Equal(2396, font.HeaderTable.XMax);
|
||||||
Assert.Equal(2163, font.HeaderTable.YMax);
|
Assert.Equal(2163, font.HeaderTable.YMax);
|
||||||
|
|
||||||
Assert.Equal(0, font.HeaderTable.MacStyle);
|
Assert.Equal(HeaderTable.HeaderMacStyle.None, font.HeaderTable.MacStyle);
|
||||||
Assert.Equal(9, font.HeaderTable.LowestRecommendedPpem);
|
Assert.Equal(9, font.HeaderTable.LowestRecommendedPpem);
|
||||||
|
|
||||||
Assert.Equal(HeaderTable.FontDirection.StronglyLeftToRightWithNeutrals, font.HeaderTable.FontDirectionHint);
|
Assert.Equal(HeaderTable.FontDirection.StronglyLeftToRightWithNeutrals, font.HeaderTable.FontDirectionHint);
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
namespace UglyToad.Pdf.Fonts.TrueType.Parser
|
|
||||||
{
|
|
||||||
using Tables;
|
|
||||||
|
|
||||||
internal class HeaderTableParser
|
|
||||||
{
|
|
||||||
public string Tag => TrueTypeFontTable.Head;
|
|
||||||
|
|
||||||
public HeaderTable Parse(TrueTypeDataBytes data, TrueTypeFontTable table)
|
|
||||||
{
|
|
||||||
data.Seek(table.Offset - 1);
|
|
||||||
var version = data.Read32Fixed();
|
|
||||||
var fontRevision = data.Read32Fixed();
|
|
||||||
var checkSumAdjustment = data.ReadUnsignedInt();
|
|
||||||
var magicNumber = data.ReadUnsignedInt();
|
|
||||||
var flags = data.ReadUnsignedShort();
|
|
||||||
var unitsPerEm = data.ReadUnsignedShort();
|
|
||||||
var created = data.ReadInternationalDate();
|
|
||||||
var modified = data.ReadInternationalDate();
|
|
||||||
var xMin = data.ReadSignedShort();
|
|
||||||
var yMin = data.ReadSignedShort();
|
|
||||||
var xMax = data.ReadSignedShort();
|
|
||||||
var yMax = data.ReadSignedShort();
|
|
||||||
var macStyle = data.ReadUnsignedShort();
|
|
||||||
var lowestRecPpem = data.ReadUnsignedShort();
|
|
||||||
var fontDirectionHint = data.ReadSignedShort();
|
|
||||||
var indexToLocFormat = data.ReadSignedShort();
|
|
||||||
var glyphDataFormat = data.ReadSignedShort();
|
|
||||||
|
|
||||||
return new HeaderTable(table, (decimal)version, (decimal)fontRevision, checkSumAdjustment,
|
|
||||||
magicNumber, flags, unitsPerEm, created, modified,
|
|
||||||
xMin, yMin, xMax, yMax, macStyle, lowestRecPpem,
|
|
||||||
fontDirectionHint, indexToLocFormat, glyphDataFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
namespace UglyToad.Pdf.Fonts.TrueType.Parser
|
|
||||||
{
|
|
||||||
using Tables;
|
|
||||||
|
|
||||||
internal interface ITrueTypeTableParser
|
|
||||||
{
|
|
||||||
string Tag { get; }
|
|
||||||
|
|
||||||
ITable Parse(TrueTypeDataBytes data, TrueTypeFontTable table);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,14 +2,11 @@
|
|||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Tables;
|
||||||
using Util.JetBrains.Annotations;
|
using Util.JetBrains.Annotations;
|
||||||
|
|
||||||
internal class TrueTypeFontParser
|
internal class TrueTypeFontParser
|
||||||
{
|
{
|
||||||
private const int TagLength = 4;
|
|
||||||
|
|
||||||
private static readonly HeaderTableParser HeaderTableParser = new HeaderTableParser();
|
|
||||||
|
|
||||||
public TrueTypeFont Parse(TrueTypeDataBytes data)
|
public TrueTypeFont Parse(TrueTypeDataBytes data)
|
||||||
{
|
{
|
||||||
var version = (decimal)data.Read32Fixed();
|
var version = (decimal)data.Read32Fixed();
|
||||||
@@ -18,15 +15,15 @@
|
|||||||
int entrySelector = data.ReadUnsignedShort();
|
int entrySelector = data.ReadUnsignedShort();
|
||||||
int rangeShift = data.ReadUnsignedShort();
|
int rangeShift = data.ReadUnsignedShort();
|
||||||
|
|
||||||
var tables = new Dictionary<string, TrueTypeFontTable>();
|
var tables = new Dictionary<string, TrueTypeHeaderTable>();
|
||||||
|
|
||||||
for (var i = 0; i < numberOfTables; i++)
|
for (var i = 0; i < numberOfTables; i++)
|
||||||
{
|
{
|
||||||
var table = ReadTable(data);
|
var table = ReadTable(data);
|
||||||
|
|
||||||
if (table != null)
|
if (table.HasValue)
|
||||||
{
|
{
|
||||||
tables[table.Tag] = table;
|
tables[table.Value.Tag] = table.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,32 +33,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private static TrueTypeFontTable ReadTable(TrueTypeDataBytes data)
|
private static TrueTypeHeaderTable? ReadTable(TrueTypeDataBytes data)
|
||||||
{
|
{
|
||||||
var tag = data.ReadString(TagLength);
|
var tag = data.ReadTag();
|
||||||
var checksum = data.ReadUnsignedInt();
|
var checksum = data.ReadUnsignedInt();
|
||||||
var offset = data.ReadUnsignedInt();
|
var offset = data.ReadUnsignedInt();
|
||||||
var length = data.ReadUnsignedInt();
|
var length = data.ReadUnsignedInt();
|
||||||
|
|
||||||
// skip tables with zero length (except glyf)
|
// skip tables with zero length (except glyf)
|
||||||
if (length == 0 && !string.Equals(tag, TrueTypeFontTable.Glyf))
|
if (length == 0 && !string.Equals(tag, TrueTypeHeaderTable.Glyf))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TrueTypeFontTable(tag, checksum, offset, length);
|
return new TrueTypeHeaderTable(tag, checksum, offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TrueTypeFont ParseTables(decimal version, IReadOnlyDictionary<string, TrueTypeFontTable> tables, TrueTypeDataBytes data)
|
private static TrueTypeFont ParseTables(decimal version, IReadOnlyDictionary<string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data)
|
||||||
{
|
{
|
||||||
var isPostScript = tables.ContainsKey(TrueTypeFontTable.Cff);
|
var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff);
|
||||||
|
|
||||||
if (!tables.TryGetValue(TrueTypeFontTable.Head, out var table))
|
if (!tables.TryGetValue(TrueTypeHeaderTable.Head, out var table))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"The {TrueTypeFontTable.Head} table is required.");
|
throw new InvalidOperationException($"The {TrueTypeHeaderTable.Head} table is required.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var header = HeaderTableParser.Parse(data, table);
|
var header = HeaderTable.Load(data, table);
|
||||||
|
|
||||||
|
if (!tables.TryGetValue(TrueTypeHeaderTable.Hhea, out var hHead))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The horizontal header table is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var horizontalHeader = HorizontalHeaderTable.Load(data, hHead);
|
||||||
|
|
||||||
return new TrueTypeFont(version, header);
|
return new TrueTypeFont(version, header);
|
||||||
}
|
}
|
||||||
|
@@ -7,19 +7,9 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class HeaderTable : ITable
|
internal class HeaderTable : ITable
|
||||||
{
|
{
|
||||||
public string Tag => TrueTypeFontTable.Head;
|
public string Tag => TrueTypeHeaderTable.Head;
|
||||||
|
|
||||||
/// <summary>
|
public TrueTypeHeaderTable DirectoryTable { get; }
|
||||||
/// Bold macStyle flag.
|
|
||||||
/// </summary>
|
|
||||||
public const int MacStyleBold = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Italic macStyle flag.
|
|
||||||
/// </summary>
|
|
||||||
public const int MacStyleItalic = 2;
|
|
||||||
|
|
||||||
public TrueTypeFontTable DirectoryTable { get; }
|
|
||||||
|
|
||||||
public decimal Version { get; }
|
public decimal Version { get; }
|
||||||
|
|
||||||
@@ -45,7 +35,7 @@
|
|||||||
|
|
||||||
public short YMax { get; }
|
public short YMax { get; }
|
||||||
|
|
||||||
public int MacStyle { get; }
|
public HeaderMacStyle MacStyle { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Smallest readable size in pixels.
|
/// Smallest readable size in pixels.
|
||||||
@@ -64,7 +54,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public short GlyphDataFormat { get; }
|
public short GlyphDataFormat { get; }
|
||||||
|
|
||||||
public HeaderTable(TrueTypeFontTable directoryTable, decimal version, decimal revision, long checkSumAdjustment,
|
public HeaderTable(TrueTypeHeaderTable directoryTable, decimal version, decimal revision, long checkSumAdjustment,
|
||||||
long magicNumber, int flags, int unitsPerEm,
|
long magicNumber, int flags, int unitsPerEm,
|
||||||
DateTime created, DateTime modified,
|
DateTime created, DateTime modified,
|
||||||
short xMin, short yMin,
|
short xMin, short yMin,
|
||||||
@@ -75,7 +65,7 @@
|
|||||||
short indexToLocFormat,
|
short indexToLocFormat,
|
||||||
short glyphDataFormat)
|
short glyphDataFormat)
|
||||||
{
|
{
|
||||||
DirectoryTable = directoryTable ?? throw new ArgumentNullException(nameof(directoryTable));
|
DirectoryTable = directoryTable;
|
||||||
Version = version;
|
Version = version;
|
||||||
Revision = revision;
|
Revision = revision;
|
||||||
CheckSumAdjustment = checkSumAdjustment;
|
CheckSumAdjustment = checkSumAdjustment;
|
||||||
@@ -88,13 +78,52 @@
|
|||||||
YMin = yMin;
|
YMin = yMin;
|
||||||
XMax = xMax;
|
XMax = xMax;
|
||||||
YMax = yMax;
|
YMax = yMax;
|
||||||
MacStyle = macStyle;
|
MacStyle = (HeaderMacStyle)macStyle;
|
||||||
LowestRecommendedPpem = lowestRecommendedPpem;
|
LowestRecommendedPpem = lowestRecommendedPpem;
|
||||||
FontDirectionHint = (FontDirection)fontDirectionHint;
|
FontDirectionHint = (FontDirection)fontDirectionHint;
|
||||||
IndexToLocFormat = indexToLocFormat;
|
IndexToLocFormat = indexToLocFormat;
|
||||||
GlyphDataFormat = glyphDataFormat;
|
GlyphDataFormat = glyphDataFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HeaderTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table)
|
||||||
|
{
|
||||||
|
data.Seek(table.Offset - 1);
|
||||||
|
var version = data.Read32Fixed();
|
||||||
|
var fontRevision = data.Read32Fixed();
|
||||||
|
var checkSumAdjustment = data.ReadUnsignedInt();
|
||||||
|
var magicNumber = data.ReadUnsignedInt();
|
||||||
|
|
||||||
|
if (magicNumber != 0x5F0F3CF5)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The magic number for this TrueType font was incorrect. Value was: " + magicNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = data.ReadUnsignedShort();
|
||||||
|
var unitsPerEm = data.ReadUnsignedShort();
|
||||||
|
|
||||||
|
if (unitsPerEm < 16 || unitsPerEm > 16384)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"The units per em for this TrueType font was incorrect, value should be between 16 and 16384 but found {unitsPerEm} istead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var created = data.ReadInternationalDate();
|
||||||
|
var modified = data.ReadInternationalDate();
|
||||||
|
var xMin = data.ReadSignedShort();
|
||||||
|
var yMin = data.ReadSignedShort();
|
||||||
|
var xMax = data.ReadSignedShort();
|
||||||
|
var yMax = data.ReadSignedShort();
|
||||||
|
var macStyle = data.ReadUnsignedShort();
|
||||||
|
var lowestRecPpem = data.ReadUnsignedShort();
|
||||||
|
var fontDirectionHint = data.ReadSignedShort();
|
||||||
|
var indexToLocFormat = data.ReadSignedShort();
|
||||||
|
var glyphDataFormat = data.ReadSignedShort();
|
||||||
|
|
||||||
|
return new HeaderTable(table, (decimal)version, (decimal)fontRevision, checkSumAdjustment,
|
||||||
|
magicNumber, flags, unitsPerEm, created, modified,
|
||||||
|
xMin, yMin, xMax, yMax, macStyle, lowestRecPpem,
|
||||||
|
fontDirectionHint, indexToLocFormat, glyphDataFormat);
|
||||||
|
}
|
||||||
|
|
||||||
public enum FontDirection
|
public enum FontDirection
|
||||||
{
|
{
|
||||||
StronglyRightToLeftWithNeutrals = -2,
|
StronglyRightToLeftWithNeutrals = -2,
|
||||||
@@ -103,5 +132,18 @@
|
|||||||
StronglyLeftToRight = 1,
|
StronglyLeftToRight = 1,
|
||||||
StronglyLeftToRightWithNeutrals = 2
|
StronglyLeftToRightWithNeutrals = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum HeaderMacStyle : ushort
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Bold = 1 << 0,
|
||||||
|
Italic = 1 << 1,
|
||||||
|
Underline = 1 << 2,
|
||||||
|
Outline = 1 << 3,
|
||||||
|
Shadow = 1 << 4,
|
||||||
|
Condensed = 1 << 5,
|
||||||
|
Extended = 1 << 6,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
147
src/UglyToad.Pdf/Fonts/TrueType/Tables/HorizontalHeaderTable.cs
Normal file
147
src/UglyToad.Pdf/Fonts/TrueType/Tables/HorizontalHeaderTable.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
namespace UglyToad.Pdf.Fonts.TrueType.Tables
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
internal class HorizontalHeaderTable
|
||||||
|
{
|
||||||
|
public string Tag => TrueTypeHeaderTable.Hhea;
|
||||||
|
|
||||||
|
public TrueTypeHeaderTable DirectoryTable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Major version number of this table (1).
|
||||||
|
/// </summary>
|
||||||
|
public int MajorVersion { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minor version number of this table (0).
|
||||||
|
/// </summary>
|
||||||
|
public int MinorVersion { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Distance from baseline to highest ascender.
|
||||||
|
/// </summary>
|
||||||
|
public short Ascender { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Distance from baseline to lower descender.
|
||||||
|
/// </summary>
|
||||||
|
public short Descender { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The typographic line gap.
|
||||||
|
/// </summary>
|
||||||
|
public short LineGap { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum advance width value as given by the Horizontal Metrics table.
|
||||||
|
/// </summary>
|
||||||
|
public int AdvanceWidthMaximum { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum left side bearing as given by the Horizontal Metrics table.
|
||||||
|
/// </summary>
|
||||||
|
public short MinimumLeftSideBearing { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum right sidebearing.
|
||||||
|
/// </summary>
|
||||||
|
public short MinimumRightSideBearing { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum X extent.
|
||||||
|
/// </summary>
|
||||||
|
public short XMaxExtent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to calculate the slope of the cursor. 1 is vertical.
|
||||||
|
/// </summary>
|
||||||
|
public short CaretSlopeRise { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0 is vertical.
|
||||||
|
/// </summary>
|
||||||
|
public short CaretSlopeRun { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount by which a slanted highlight on a glyph should be shifted to provide the best appearance. 0 for non-slanted fonts.
|
||||||
|
/// </summary>
|
||||||
|
public short CaretOffset { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0 for the current format.
|
||||||
|
/// </summary>
|
||||||
|
public short MetricDataFormat { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of horizontal metrics in the Horizontal Metrics table.
|
||||||
|
/// </summary>
|
||||||
|
public int NumberOfHeaderMetrics { get; }
|
||||||
|
|
||||||
|
public HorizontalHeaderTable(TrueTypeHeaderTable directoryTable, int majorVersion, int minorVersion, short ascender, short descender, short lineGap, int advanceWidthMaximum, short minimumLeftSideBearing, short minimumRightSideBearing, short xMaxExtent, short caretSlopeRise, short caretSlopeRun, short caretOffset, short metricDataFormat, int numberOfHeaderMetrics)
|
||||||
|
{
|
||||||
|
DirectoryTable = directoryTable;
|
||||||
|
MajorVersion = majorVersion;
|
||||||
|
MinorVersion = minorVersion;
|
||||||
|
Ascender = ascender;
|
||||||
|
Descender = descender;
|
||||||
|
LineGap = lineGap;
|
||||||
|
AdvanceWidthMaximum = advanceWidthMaximum;
|
||||||
|
MinimumLeftSideBearing = minimumLeftSideBearing;
|
||||||
|
MinimumRightSideBearing = minimumRightSideBearing;
|
||||||
|
XMaxExtent = xMaxExtent;
|
||||||
|
CaretSlopeRise = caretSlopeRise;
|
||||||
|
CaretSlopeRun = caretSlopeRun;
|
||||||
|
CaretOffset = caretOffset;
|
||||||
|
MetricDataFormat = metricDataFormat;
|
||||||
|
NumberOfHeaderMetrics = numberOfHeaderMetrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HorizontalHeaderTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table)
|
||||||
|
{
|
||||||
|
data.Seek(table.Offset - 1);
|
||||||
|
var majorVersion = data.ReadUnsignedShort();
|
||||||
|
var minorVersion = data.ReadUnsignedShort();
|
||||||
|
|
||||||
|
var ascender = data.ReadSignedShort();
|
||||||
|
var descender = data.ReadSignedShort();
|
||||||
|
var lineGap = data.ReadSignedShort();
|
||||||
|
|
||||||
|
var advancedWidthMax = data.ReadUnsignedShort();
|
||||||
|
|
||||||
|
var minLeftSideBearing = data.ReadSignedShort();
|
||||||
|
var minRightSideBearing = data.ReadSignedShort();
|
||||||
|
var xMaxExtent = data.ReadSignedShort();
|
||||||
|
|
||||||
|
var caretSlopeRise = data.ReadSignedShort();
|
||||||
|
var caretSlopeRun = data.ReadSignedShort();
|
||||||
|
var caretOffset = data.ReadSignedShort();
|
||||||
|
|
||||||
|
// Reserved section
|
||||||
|
data.ReadSignedShort();
|
||||||
|
data.ReadSignedShort();
|
||||||
|
data.ReadSignedShort();
|
||||||
|
data.ReadSignedShort();
|
||||||
|
|
||||||
|
var metricDataFormat = data.ReadSignedShort();
|
||||||
|
|
||||||
|
if (metricDataFormat != 0)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The metric data format for a horizontal header table should be 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var numberOfHeaderMetrics = data.ReadSignedShort();
|
||||||
|
|
||||||
|
return new HorizontalHeaderTable(table, majorVersion, minorVersion, ascender,
|
||||||
|
descender, lineGap, advancedWidthMax,
|
||||||
|
minLeftSideBearing,
|
||||||
|
minRightSideBearing,
|
||||||
|
xMaxExtent,
|
||||||
|
caretSlopeRise,
|
||||||
|
caretSlopeRun,
|
||||||
|
caretOffset,
|
||||||
|
metricDataFormat,
|
||||||
|
numberOfHeaderMetrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -4,6 +4,6 @@
|
|||||||
{
|
{
|
||||||
string Tag { get; }
|
string Tag { get; }
|
||||||
|
|
||||||
TrueTypeFontTable DirectoryTable { get; }
|
TrueTypeHeaderTable DirectoryTable { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
namespace UglyToad.Pdf.Fonts.TrueType
|
namespace UglyToad.Pdf.Fonts.TrueType
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using IO;
|
using IO;
|
||||||
using Util;
|
|
||||||
|
|
||||||
internal class TrueTypeDataBytes
|
internal class TrueTypeDataBytes
|
||||||
{
|
{
|
||||||
|
private readonly byte[] internalBuffer = new byte[16];
|
||||||
private readonly IInputBytes inputBytes;
|
private readonly IInputBytes inputBytes;
|
||||||
|
|
||||||
public TrueTypeDataBytes(IInputBytes inputBytes)
|
public TrueTypeDataBytes(IInputBytes inputBytes)
|
||||||
@@ -25,106 +24,69 @@
|
|||||||
|
|
||||||
public short ReadSignedShort()
|
public short ReadSignedShort()
|
||||||
{
|
{
|
||||||
int ch1 = Read();
|
ReadBuffered(internalBuffer, 2);
|
||||||
int ch2 = Read();
|
|
||||||
if ((ch1 | ch2) < 0)
|
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (short)((ch1 << 8) + (ch2 << 0));
|
return unchecked((short)((internalBuffer[0] << 8) + (internalBuffer[1] << 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadUnsignedShort()
|
public int ReadUnsignedShort()
|
||||||
{
|
{
|
||||||
int ch1 = Read();
|
ReadBuffered(internalBuffer, 2);
|
||||||
int ch2 = Read();
|
|
||||||
if ((ch1 | ch2) < 0)
|
return (internalBuffer[0] << 8) + (internalBuffer[1] << 0);
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ch1 << 8) + (ch2 << 0);
|
private void ReadBuffered(byte[] buffer, int length)
|
||||||
}
|
|
||||||
|
|
||||||
public int Read()
|
|
||||||
{
|
{
|
||||||
// We're no longer moving because we're at the end.
|
var numberRead = 0;
|
||||||
if (!inputBytes.MoveNext())
|
while (numberRead < length)
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = inputBytes.CurrentByte;
|
|
||||||
|
|
||||||
return (result + 256) % 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Read(int numberOfBytes)
|
|
||||||
{
|
|
||||||
byte[] data = new byte[numberOfBytes];
|
|
||||||
int amountRead = 0;
|
|
||||||
|
|
||||||
while (amountRead < numberOfBytes)
|
|
||||||
{
|
{
|
||||||
if (!inputBytes.MoveNext())
|
if (!inputBytes.MoveNext())
|
||||||
{
|
{
|
||||||
throw new EndOfStreamException();
|
throw new EndOfStreamException($"Could not read a buffer of {length} bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
data[amountRead] = inputBytes.CurrentByte;
|
buffer[numberRead] = inputBytes.CurrentByte;
|
||||||
amountRead++;
|
numberRead++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
/// <summary>
|
||||||
}
|
/// Reads the 4 character tag from the TrueType file.
|
||||||
|
/// </summary>
|
||||||
public string ReadString(int length)
|
public string ReadTag()
|
||||||
{
|
{
|
||||||
return ReadString(length, OtherEncodings.Iso88591);
|
return ReadString(4, Encoding.UTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ReadString(int length, Encoding encoding)
|
public string ReadString(int bytesToRead, Encoding encoding)
|
||||||
{
|
{
|
||||||
byte[] buffer = Read(length);
|
byte[] data = new byte[bytesToRead];
|
||||||
|
ReadBuffered(data, bytesToRead);
|
||||||
var str = encoding.GetString(buffer);
|
return encoding.GetString(data, 0, data.Length);
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long ReadUnsignedInt()
|
public long ReadUnsignedInt()
|
||||||
{
|
{
|
||||||
long byte1 = Read();
|
ReadBuffered(internalBuffer, 4);
|
||||||
long byte2 = Read();
|
|
||||||
long byte3 = Read();
|
|
||||||
long byte4 = Read();
|
|
||||||
|
|
||||||
if (byte4 < 0)
|
return (internalBuffer[0] << 24) + (internalBuffer[1] << 16) + (internalBuffer[2] << 8) + (internalBuffer[3] << 0);
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + (byte4 << 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadSignedInt()
|
public int ReadSignedInt()
|
||||||
{
|
{
|
||||||
int ch1 = Read();
|
ReadBuffered(internalBuffer, 4);
|
||||||
int ch2 = Read();
|
|
||||||
int ch3 = Read();
|
|
||||||
int ch4 = Read();
|
|
||||||
if ((ch1 | ch2 | ch3 | ch4) < 0)
|
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0);
|
return (internalBuffer[0] << 24) + (internalBuffer[1] << 16) + (internalBuffer[2] << 8) + (internalBuffer[3] << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long ReadLong()
|
public long ReadLong()
|
||||||
{
|
{
|
||||||
return (ReadSignedInt() << 32) + (ReadSignedInt() & 0xFFFFFFFFL);
|
ReadBuffered(internalBuffer, 8);
|
||||||
|
|
||||||
|
var result = FromBytes(internalBuffer, 0, 8);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime ReadInternationalDate()
|
public DateTime ReadInternationalDate()
|
||||||
@@ -132,7 +94,7 @@
|
|||||||
// TODO: this returns the wrong value, investigate...
|
// TODO: this returns the wrong value, investigate...
|
||||||
long secondsSince1904 = ReadLong();
|
long secondsSince1904 = ReadLong();
|
||||||
|
|
||||||
var date = new DateTime(1904, 1, 1, 0, 0, 0, 0, new GregorianCalendar());
|
var date = new DateTime(1904, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
var result = date.AddSeconds(secondsSince1904);
|
var result = date.AddSeconds(secondsSince1904);
|
||||||
result = result.AddMonths(1);
|
result = result.AddMonths(1);
|
||||||
@@ -145,5 +107,16 @@
|
|||||||
{
|
{
|
||||||
inputBytes.Seek(position);
|
inputBytes.Seek(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
for (int i = 0; i < bytesToConvert; i++)
|
||||||
|
{
|
||||||
|
ret = unchecked((ret << 8) | buffer[startIndex + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A table directory entry from the TrueType font file.
|
/// A table directory entry from the TrueType font file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class TrueTypeFontTable
|
internal struct TrueTypeHeaderTable
|
||||||
{
|
{
|
||||||
#region RequiredTableTags
|
#region RequiredTableTags
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public long Length { get; }
|
public long Length { get; }
|
||||||
|
|
||||||
public TrueTypeFontTable(string tag, long checkSum, long offset, long length)
|
public TrueTypeHeaderTable(string tag, long checkSum, long offset, long length)
|
||||||
{
|
{
|
||||||
Tag = tag;
|
Tag = tag;
|
||||||
CheckSum = checkSum;
|
CheckSum = checkSum;
|
Reference in New Issue
Block a user