support format 6 cmap sub tables for truetype fonts. pass the truetypefont to the ifont implementation so we can use it to access font data

This commit is contained in:
Eliot Jones
2018-03-31 12:11:12 +01:00
parent 796a3d615e
commit 92c0ef14cb
9 changed files with 100 additions and 15 deletions

View File

@@ -122,7 +122,7 @@
name = "cvt ";
}
var match = font.Tables[name];
var match = font.TableHeaders[name];
var offset = long.Parse(parts[1]);
var length = long.Parse(parts[2]);

View File

@@ -70,7 +70,7 @@
Encoding encoding = encodingReader.Read(dictionary, isLenientParsing, descriptor);
return new TrueTypeSimpleFont(name, firstCharacter, lastCharacter, widths, descriptor, toUnicodeCMap, encoding);
return new TrueTypeSimpleFont(name, firstCharacter, lastCharacter, widths, descriptor, toUnicodeCMap, encoding, font);
}
private TrueTypeFont ParseTrueTypeFont(FontDescriptor descriptor)

View File

@@ -7,6 +7,7 @@
using Geometry;
using IO;
using Tokenization.Tokens;
using TrueType;
using Util.JetBrains.Annotations;
internal class TrueTypeSimpleFont : IFont
@@ -19,6 +20,8 @@
private readonly FontDescriptor descriptor;
[CanBeNull]
private readonly Encoding encoding;
[CanBeNull]
private readonly TrueTypeFont font;
public NameToken Name { get; }
@@ -27,16 +30,18 @@
[NotNull]
public ToUnicodeCMap ToUnicode { get; set; }
public TrueTypeSimpleFont(NameToken name, int firstCharacterCode, int lastCharacterCode, decimal[] widths,
public TrueTypeSimpleFont(NameToken name, int firstCharacterCode, int lastCharacterCode, decimal[] widths,
FontDescriptor descriptor,
[CanBeNull]CMap toUnicodeCMap,
[CanBeNull]Encoding encoding)
[CanBeNull] CMap toUnicodeCMap,
[CanBeNull] Encoding encoding,
[CanBeNull]TrueTypeFont font)
{
this.firstCharacterCode = firstCharacterCode;
this.lastCharacterCode = lastCharacterCode;
this.widths = widths;
this.descriptor = descriptor;
this.encoding = encoding;
this.font = font;
Name = name;
IsVertical = false;

View File

@@ -11,9 +11,13 @@
{
var version = (decimal)data.Read32Fixed();
int numberOfTables = data.ReadUnsignedShort();
// Read these data points to move to the correct data location.
// ReSharper disable UnusedVariable
int searchRange = data.ReadUnsignedShort();
int entrySelector = data.ReadUnsignedShort();
int rangeShift = data.ReadUnsignedShort();
// ReSharper restore UnusedVariable
var tables = new Dictionary<string, TrueTypeHeaderTable>();
@@ -80,7 +84,6 @@
tableRegister.MaximumProfileTable = BasicMaximumProfileTable.Load(data, maxHeaderTable);
// post
var postScriptTable = default(PostScriptTable);
if (tables.TryGetValue(TrueTypeHeaderTable.Post, out var postscriptHeaderTable))
{
tableRegister.PostScriptTable = PostScriptTable.Load(data, table, tableRegister.MaximumProfileTable);
@@ -108,7 +111,7 @@
OptionallyParseTables(tables, data, tableRegister);
}
return new TrueTypeFont(version, tables, tableRegister.HeaderTable);
return new TrueTypeFont(version, tables, tableRegister);
}
private static void OptionallyParseTables(IReadOnlyDictionary<string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data, TableRegister tableRegister)

View File

@@ -69,10 +69,11 @@ namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
var idRangeOffsets = data.ReadUnsignedShortArray(segmentCount);
const int singleIntsRead = 16;
const int singleIntsRead = 8;
const int intArraysRead = 8;
var remainingBytes = length - (singleIntsRead + intArraysRead * segmentCount);
// ReSharper disable once ArrangeRedundantParentheses
var remainingBytes = length - ((singleIntsRead * 2) + intArraysRead * segmentCount);
var remainingInts = remainingBytes / 2;

View File

@@ -23,6 +23,11 @@
/// </summary>
int EncodingId { get; }
/// <summary>
/// Maps from a character code to the array index of the glyph in the font data.
/// </summary>
/// <param name="characterCode">The character code.</param>
/// <returns>The index of the glyph information for this character.</returns>
int CharacterCodeToGlyphIndex(int characterCode);
}
}

View File

@@ -0,0 +1,60 @@
// ReSharper disable UnusedVariable
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
{
using System;
/// <inheritdoc />
/// <summary>
/// A format 6 CMap sub-table which uses 2 bytes to map a contiguous range of character codes to glyph indices.
/// </summary>
internal class TrimmedTableMappingCMapTable : ICMapSubTable
{
private readonly int firstCharacterCode;
private readonly int entryCount;
private readonly int[] glyphIndices;
public int PlatformId { get; }
public int EncodingId { get; }
/// <summary>
/// Create a new <see cref="TrimmedTableMappingCMapTable"/>.
/// </summary>
public TrimmedTableMappingCMapTable(int platformId, int encodingId, int firstCharacterCode, int entryCount, int[] glyphIndices)
{
this.firstCharacterCode = firstCharacterCode;
this.entryCount = entryCount;
this.glyphIndices = glyphIndices ?? throw new ArgumentNullException(nameof(glyphIndices));
PlatformId = platformId;
EncodingId = encodingId;
}
public int CharacterCodeToGlyphIndex(int characterCode)
{
if (characterCode < firstCharacterCode || characterCode > firstCharacterCode + entryCount)
{
return 0;
}
var offset = characterCode - firstCharacterCode;
return glyphIndices[offset];
}
public static TrimmedTableMappingCMapTable Load(TrueTypeDataBytes data, int platformId, int encodingId)
{
var length = data.ReadUnsignedShort();
var language = data.ReadUnsignedShort();
// First character code in the range.
var firstCode = data.ReadUnsignedShort();
// Number of character codes in the range.
var entryCount = data.ReadUnsignedShort();
var glyphIndices = data.ReadUnsignedShortArray(entryCount);
return new TrimmedTableMappingCMapTable(platformId, encodingId, firstCode, entryCount, glyphIndices);
}
}
}

View File

@@ -88,12 +88,12 @@
// Microsoft's standard mapping table.
var item = Format4CMapTable.Load(data, header.PlatformId, header.EncodingId);
tables.Add(item);
break;
}
case 6:
{
// TODO: support format 6 for modern fonts.
var item = TrimmedTableMappingCMapTable.Load(data, header.PlatformId, header.EncodingId);
tables.Add(item);
break;
}
}

View File

@@ -1,22 +1,33 @@
namespace UglyToad.PdfPig.Fonts.TrueType
{
using System;
using System.Collections.Generic;
using CidFonts;
using Parser;
using Tables;
internal class TrueTypeFont : ICidFontProgram
{
public decimal Version { get; }
public IReadOnlyDictionary<string, TrueTypeHeaderTable> Tables { get; }
public IReadOnlyDictionary<string, TrueTypeHeaderTable> TableHeaders { get; }
public HeaderTable HeaderTable { get; }
public CMapTable CMapTable { get; }
public GlyphDataTable GlyphTable { get; }
public TrueTypeFont(decimal version, IReadOnlyDictionary<string, TrueTypeHeaderTable> tables, HeaderTable headerTable)
public TrueTypeFont(decimal version, IReadOnlyDictionary<string, TrueTypeHeaderTable> tableHeaders, TableRegister tableRegister)
{
if (tableRegister == null)
{
throw new ArgumentNullException(nameof(tableRegister));
}
Version = version;
Tables = tables;
HeaderTable = headerTable;
TableHeaders = tableHeaders;
HeaderTable = tableRegister.HeaderTable;
CMapTable = tableRegister.CMapTable;
GlyphTable = tableRegister.GlyphDataTable;
}
}
}