mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-14 19:05:01 +08:00
merge from upstream
This commit is contained in:
@@ -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]);
|
||||
|
@@ -85,6 +85,11 @@
|
||||
return new PdfRectangle(0, 0, fromFont, 0);
|
||||
}
|
||||
|
||||
public PdfRectangle GetBoundingBox(int characterCode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public TransformationMatrix GetFontMatrix()
|
||||
{
|
||||
return CidFont.FontMatrix;
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
PdfRectangle GetDisplacement(int characterCode);
|
||||
|
||||
PdfRectangle GetBoundingBox(int characterCode);
|
||||
|
||||
TransformationMatrix GetFontMatrix();
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -7,6 +7,7 @@
|
||||
using Geometry;
|
||||
using IO;
|
||||
using Tokenization.Tokens;
|
||||
using TrueType;
|
||||
using Util.JetBrains.Annotations;
|
||||
|
||||
internal class TrueTypeSimpleFont : IFont
|
||||
@@ -21,6 +22,8 @@
|
||||
|
||||
[CanBeNull]
|
||||
private readonly Encoding encoding;
|
||||
[CanBeNull]
|
||||
private readonly TrueTypeFont font;
|
||||
|
||||
public NameToken Name { get; }
|
||||
|
||||
@@ -34,13 +37,15 @@
|
||||
public TrueTypeSimpleFont(NameToken name, int firstCharacterCode, int lastCharacterCode, decimal[] widths,
|
||||
FontDescriptor descriptor,
|
||||
[CanBeNull] CMap toUnicodeCMap,
|
||||
[CanBeNull]Encoding encoding)
|
||||
[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;
|
||||
@@ -100,6 +105,23 @@
|
||||
return new PdfRectangle(0, 0, widths[index], 0);
|
||||
}
|
||||
|
||||
public PdfRectangle GetBoundingBox(int characterCode)
|
||||
{
|
||||
if (font?.CMapTable == null)
|
||||
{
|
||||
return descriptor.BoundingBox;
|
||||
}
|
||||
|
||||
if (!font.CMapTable.TryGetGlyphIndex(characterCode, out var index))
|
||||
{
|
||||
return descriptor.BoundingBox;
|
||||
}
|
||||
|
||||
var glyph = font.GlyphTable.Glyphs[index];
|
||||
|
||||
return glyph?.GlyphBounds ?? descriptor.BoundingBox;
|
||||
}
|
||||
|
||||
public TransformationMatrix GetFontMatrix()
|
||||
{
|
||||
// TODO: should this also use units per em?
|
||||
|
@@ -96,6 +96,11 @@
|
||||
return new PdfRectangle(0, 0, widths[characterCode - firstChar], 0);
|
||||
}
|
||||
|
||||
public PdfRectangle GetBoundingBox(int characterCode)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public TransformationMatrix GetFontMatrix()
|
||||
{
|
||||
return fontMatrix;
|
||||
|
@@ -61,6 +61,11 @@
|
||||
return new PdfRectangle(0, 0, metrics.WidthX, 0);
|
||||
}
|
||||
|
||||
public PdfRectangle GetBoundingBox(int characterCode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public TransformationMatrix GetFontMatrix()
|
||||
{
|
||||
return fontMatrix;
|
||||
|
@@ -78,6 +78,11 @@
|
||||
return new PdfRectangle(0, 0, widths[characterCode - firstChar], 0); ;
|
||||
}
|
||||
|
||||
public PdfRectangle GetBoundingBox(int characterCode)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public TransformationMatrix GetFontMatrix()
|
||||
{
|
||||
return fontMatrix;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Parser
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Tables;
|
||||
|
||||
/// <summary>
|
||||
@@ -22,5 +20,12 @@
|
||||
public BasicMaximumProfileTable MaximumProfileTable { get; set; }
|
||||
|
||||
public PostScriptTable PostScriptTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines mapping of character codes to glyph index values in the font.
|
||||
/// Can contain mutliple sub-tables to support multiple encoding schemes.
|
||||
/// Where a character code isn't found it should map to index 0.
|
||||
/// </summary>
|
||||
public CMapTable CMapTable { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -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,12 +111,16 @@
|
||||
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)
|
||||
{
|
||||
// cmap
|
||||
if (tables.TryGetValue(TrueTypeHeaderTable.Cmap, out var cmap))
|
||||
{
|
||||
tableRegister.CMapTable = CMapTable.Load(data, cmap, tableRegister);
|
||||
}
|
||||
|
||||
// hmtx
|
||||
if (tables.TryGetValue(TrueTypeHeaderTable.Hmtx, out var hmtxHeaderTable))
|
||||
@@ -133,3 +140,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,15 +1,45 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// The format 0 sub-total where character codes and glyph indices are restricted to a single bytes.
|
||||
/// </summary>
|
||||
internal class ByteEncodingCMapTable : ICMapSubTable
|
||||
{
|
||||
public static ByteEncodingCMapTable Load(TrueTypeDataBytes data)
|
||||
private const int GlyphMappingLength = 256;
|
||||
private readonly byte[] glyphMapping;
|
||||
|
||||
public int PlatformId { get; }
|
||||
|
||||
public int EncodingId { get; }
|
||||
|
||||
private ByteEncodingCMapTable(int platformId, int encodingId, byte[] glyphMapping)
|
||||
{
|
||||
this.glyphMapping = glyphMapping;
|
||||
PlatformId = platformId;
|
||||
EncodingId = encodingId;
|
||||
}
|
||||
|
||||
public static ByteEncodingCMapTable Load(TrueTypeDataBytes data, int platformId, int encodingId)
|
||||
{
|
||||
// ReSharper disable UnusedVariable
|
||||
var length = data.ReadUnsignedShort();
|
||||
var version = data.ReadUnsignedShort();
|
||||
// ReSharper restore UnusedVariable
|
||||
|
||||
var glyphMapping = data.ReadByteArray(256);
|
||||
var glyphMapping = data.ReadByteArray(GlyphMappingLength);
|
||||
|
||||
return new ByteEncodingCMapTable();
|
||||
return new ByteEncodingCMapTable(platformId, encodingId, glyphMapping);
|
||||
}
|
||||
|
||||
public int CharacterCodeToGlyphIndex(int characterCode)
|
||||
{
|
||||
if (characterCode < 0 || characterCode >= GlyphMappingLength)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return glyphMapping[characterCode];
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,158 @@
|
||||
// ReSharper disable UnusedVariable
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// A format 4 CMap sub-table which defines gappy ranges of character code to glyph index mappings.
|
||||
/// </summary>
|
||||
internal class Format4CMapTable : ICMapSubTable
|
||||
{
|
||||
public int PlatformId { get; }
|
||||
|
||||
public int EncodingId { get; }
|
||||
|
||||
public int Language { get; }
|
||||
|
||||
public IReadOnlyList<Segment> Segments { get; }
|
||||
|
||||
public IReadOnlyList<int> GlyphIds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Format4CMapTable"/>.
|
||||
/// </summary>
|
||||
public Format4CMapTable(int platformId, int encodingId, int language, IReadOnlyList<Segment> segments, IReadOnlyList<int> glyphIds)
|
||||
{
|
||||
PlatformId = platformId;
|
||||
EncodingId = encodingId;
|
||||
Language = language;
|
||||
Segments = segments ?? throw new ArgumentNullException(nameof(segments));
|
||||
GlyphIds = glyphIds ?? throw new ArgumentNullException(nameof(glyphIds));
|
||||
}
|
||||
|
||||
public int CharacterCodeToGlyphIndex(int characterCode)
|
||||
{
|
||||
for (var i = 0; i < Segments.Count; i++)
|
||||
{
|
||||
var segment = Segments[i];
|
||||
|
||||
if (segment.EndCode < characterCode || segment.StartCode > characterCode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (segment.IdRangeOffset == 0)
|
||||
{
|
||||
return (characterCode + segment.IdDelta) % ushort.MaxValue;
|
||||
}
|
||||
|
||||
var offset = segment.IdRangeOffset / 2 + (characterCode - segment.StartCode);
|
||||
|
||||
return GlyphIds[offset - Segments.Count + i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Format4CMapTable Load(TrueTypeDataBytes data, int platformId, int encodingId)
|
||||
{
|
||||
// Length in bytes.
|
||||
var length = data.ReadUnsignedShort();
|
||||
|
||||
// Used for sub-tables with a Macintosh platform ID.
|
||||
var version = data.ReadUnsignedShort();
|
||||
|
||||
var doubleSegmentCount = data.ReadUnsignedShort();
|
||||
|
||||
// Defines the number of contiguous segments.
|
||||
var segmentCount = doubleSegmentCount / 2;
|
||||
|
||||
// Some crazy sum.
|
||||
var searchRange = data.ReadUnsignedShort();
|
||||
var entrySelector = data.ReadUnsignedShort();
|
||||
var rangeShift = data.ReadUnsignedShort();
|
||||
|
||||
// End character codes for each segment.
|
||||
var endCounts = data.ReadUnsignedShortArray(segmentCount);
|
||||
|
||||
// Should be zero.
|
||||
var reservedPad = data.ReadUnsignedShort();
|
||||
|
||||
// Start character codes for each segment.
|
||||
var startCounts = data.ReadUnsignedShortArray(segmentCount);
|
||||
|
||||
// Delta for all character codes in the segment. Contrary to the spec this is actually a short[].
|
||||
var idDeltas = data.ReadShortArray(segmentCount);
|
||||
|
||||
var idRangeOffsets = data.ReadUnsignedShortArray(segmentCount);
|
||||
|
||||
const int singleIntsRead = 8;
|
||||
const int intArraysRead = 8;
|
||||
|
||||
// ReSharper disable once ArrangeRedundantParentheses
|
||||
var remainingBytes = length - ((singleIntsRead * 2) + intArraysRead * segmentCount);
|
||||
|
||||
var remainingInts = remainingBytes / 2;
|
||||
|
||||
var glyphIndices = data.ReadUnsignedShortArray(remainingInts);
|
||||
|
||||
var segments = new Segment[endCounts.Length];
|
||||
for (int i = 0; i < endCounts.Length; i++)
|
||||
{
|
||||
var start = startCounts[i];
|
||||
var end = endCounts[i];
|
||||
|
||||
var delta = idDeltas[i];
|
||||
var offsets = idRangeOffsets[i];
|
||||
|
||||
segments[i] = new Segment(start, end, delta, offsets);
|
||||
}
|
||||
|
||||
return new Format4CMapTable(platformId, encodingId, version, segments, glyphIndices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A contiguous segment which maps character to glyph codes in a Format 4 CMap sub-table.
|
||||
/// </summary>
|
||||
public struct Segment
|
||||
{
|
||||
/// <summary>
|
||||
/// The start character code in the range.
|
||||
/// </summary>
|
||||
public int StartCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The end character code in the range.
|
||||
/// </summary>
|
||||
public int EndCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The delta for the codes in the segment.
|
||||
/// </summary>
|
||||
public int IdDelta { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset in bytes to glyph index array.
|
||||
/// </summary>
|
||||
public int IdRangeOffset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Segment"/>.
|
||||
/// </summary>
|
||||
public Segment(int startCode, int endCode, int idDelta, int idRangeOffset)
|
||||
{
|
||||
StartCode = startCode;
|
||||
EndCode = endCode;
|
||||
IdDelta = idDelta;
|
||||
IdRangeOffset = idRangeOffset;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Start: {StartCode}, End: {EndCode}, Delta: {IdDelta}, Offset: {IdRangeOffset}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,12 +3,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// A format 2 sub-table for Chinese, Japanese and Korean characters.
|
||||
/// Contains mixed 8/16 bit encodings.
|
||||
/// </summary>
|
||||
internal class HighByteMappingCMapTable : ICMapSubTable
|
||||
{
|
||||
public static HighByteMappingCMapTable Load(TrueTypeDataBytes data, int numberOfGlyphs)
|
||||
private readonly IReadOnlyDictionary<int, int> characterCodesToGlyphIndices;
|
||||
|
||||
public int PlatformId { get; }
|
||||
|
||||
public int EncodingId { get; }
|
||||
|
||||
private HighByteMappingCMapTable(int platformId, int encodingId, IReadOnlyDictionary<int, int> characterCodesToGlyphIndices)
|
||||
{
|
||||
this.characterCodesToGlyphIndices = characterCodesToGlyphIndices ?? throw new ArgumentNullException(nameof(characterCodesToGlyphIndices));
|
||||
PlatformId = platformId;
|
||||
EncodingId = encodingId;
|
||||
}
|
||||
|
||||
public int CharacterCodeToGlyphIndex(int characterCode)
|
||||
{
|
||||
if (!characterCodesToGlyphIndices.TryGetValue(characterCode, out var index))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public static HighByteMappingCMapTable Load(TrueTypeDataBytes data, int numberOfGlyphs, int platformId, int encodingId)
|
||||
{
|
||||
// ReSharper disable UnusedVariable
|
||||
var length = data.ReadUnsignedShort();
|
||||
var version = data.ReadUnsignedShort();
|
||||
// ReSharper restore UnusedVariable
|
||||
|
||||
var subHeaderKeys = new int[256];
|
||||
var maximumSubHeaderIndex = 0;
|
||||
@@ -63,7 +93,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
return new HighByteMappingCMapTable();
|
||||
return new HighByteMappingCMapTable(platformId, encodingId, characterCodeToGlyphId);
|
||||
}
|
||||
|
||||
public struct SubHeader
|
||||
|
@@ -1,7 +1,33 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
/// <summary>
|
||||
/// In a TrueType font the CMap table maps from character codes to glyph indices
|
||||
/// A font which can run on multiple platforms will have multiple encoding tables. These are stored as multiple
|
||||
/// sub-tables. The <see cref="ICMapSubTable"/> represents a single subtotal.
|
||||
/// </summary>
|
||||
internal interface ICMapSubTable
|
||||
{
|
||||
/// <summary>
|
||||
/// The platform identifier.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0: Unicode
|
||||
/// 1: Macintosh
|
||||
/// 2: Reserved
|
||||
/// 3: Microsoft
|
||||
/// </remarks>
|
||||
int PlatformId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Platform specific encoding indentifier.
|
||||
/// </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);
|
||||
}
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
internal class SegmentMappingDeltaValuesCMapTable : ICMapSubTable
|
||||
{
|
||||
public static SegmentMappingDeltaValuesCMapTable Load(TrueTypeDataBytes data)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -21,6 +21,28 @@
|
||||
DirectoryTable = directoryTable;
|
||||
}
|
||||
|
||||
public bool TryGetGlyphIndex(int characterCode, out int glyphIndex)
|
||||
{
|
||||
glyphIndex = 0;
|
||||
|
||||
if (subTables.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var subTable in subTables)
|
||||
{
|
||||
glyphIndex = subTable.CharacterCodeToGlyphIndex(characterCode);
|
||||
|
||||
if (glyphIndex != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static CMapTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister tableRegister)
|
||||
{
|
||||
data.Seek(table.Offset);
|
||||
@@ -52,19 +74,47 @@
|
||||
|
||||
var format = data.ReadUnsignedShort();
|
||||
|
||||
/*
|
||||
* There are 9 currently available formats:
|
||||
* 0: Character code and glyph indices are restricted to a single byte. Rare.
|
||||
* 2: Suitable for CJK characters. Contain mixed 8/16 byte encoding.
|
||||
* 4: 2 byte encoding format. Used when character codes fall into (gappy) contiguous ranges.
|
||||
* 6: 'Trimmed table mapping', used when character codes fall into a single contiguous range. This is dense mapping.
|
||||
* 8: 16/32 bit coverage. Uses mixed length character codes.
|
||||
* 10: Similar to format 6, trimmed table/array for 32 bits.
|
||||
* 12: Segmented coverage, similar to format 4 but for 32 bit/4 byte.
|
||||
* 13: Many to one mappings. Used by Apple for the LastResort font.
|
||||
* 14: Unicode variation sequences.
|
||||
*
|
||||
* Many of the formats are obsolete or not really used. Modern fonts will tend to use formats 4, 6 and 12.
|
||||
* For PDF we will support 0, 2 and 4 since these are in the original TrueType spec.
|
||||
*/
|
||||
switch (format)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// Simple 1 to 1 mapping of character codes to glyph codes.
|
||||
var item = ByteEncodingCMapTable.Load(data);
|
||||
var item = ByteEncodingCMapTable.Load(data, header.PlatformId, header.EncodingId);
|
||||
tables.Add(item);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// Useful for CJK characters. Use mixed 8/16 bit encoding.
|
||||
var item = HighByteMappingCMapTable.Load(data, numberofGlyphs);
|
||||
var item = HighByteMappingCMapTable.Load(data, numberofGlyphs, header.PlatformId, header.EncodingId);
|
||||
tables.Add(item);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
// Microsoft's standard mapping table.
|
||||
var item = Format4CMapTable.Load(data, header.PlatformId, header.EncodingId);
|
||||
tables.Add(item);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
var item = TrimmedTableMappingCMapTable.Load(data, header.PlatformId, header.EncodingId);
|
||||
tables.Add(item);
|
||||
break;
|
||||
}
|
||||
|
@@ -173,5 +173,17 @@
|
||||
offsets[i] = ReadUnsignedInt();
|
||||
}
|
||||
}
|
||||
|
||||
public short[] ReadShortArray(int length)
|
||||
{
|
||||
var result = new short[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result[i] = ReadSignedShort();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user