wire up cidtogid map for type2cid fonts

This commit is contained in:
Eliot Jones
2018-04-14 18:53:31 +01:00
parent 983933b6e8
commit f1c01b5576
8 changed files with 106 additions and 17 deletions

View File

@@ -0,0 +1,49 @@
namespace UglyToad.PdfPig.Fonts.CidFonts
{
/// <summary>
/// Specifies mapping from character identifiers to glyph indices.
/// Can either be defined as a name in which case it must be Identity or a stream which defines the mapping.
/// </summary>
internal class CharacterIdentifierToGlyphIndexMap
{
private readonly bool isIdentity;
private readonly int[] map;
public CharacterIdentifierToGlyphIndexMap()
{
isIdentity = true;
map = null;
}
public CharacterIdentifierToGlyphIndexMap(byte[] streamBytes)
{
var numberOfEntries = streamBytes.Length / 2;
map = new int[numberOfEntries];
var offset = 0;
for (var i = 0; i < numberOfEntries; i++)
{
var glyphIndex = (streamBytes[offset] << 8) | streamBytes[offset + 1];
map[i] = glyphIndex;
offset += 2;
}
}
public int GetGlyphIndex(int characterIdentifier)
{
if (isIdentity)
{
return characterIdentifier;
}
if (characterIdentifier >= map.Length || characterIdentifier < 0)
{
return 0;
}
return map[characterIdentifier];
}
}
}

View File

@@ -42,6 +42,6 @@
decimal GetWidthFromDictionary(int cid);
PdfRectangle GetBoundingBox(int characterCode);
PdfRectangle GetBoundingBox(int characterIdentifier);
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Fonts.CidFonts
{
using System;
using Geometry;
/// <summary>
@@ -8,5 +9,6 @@
internal interface ICidFontProgram
{
bool TryGetBoundingBox(int characterCode, out PdfRectangle boundingBox);
bool TryGetBoundingBox(int characterCode, Func<int, int> characterIdentifierToGlyphIndex, out PdfRectangle boundingBox);
}
}

View File

@@ -34,7 +34,7 @@
throw new System.NotImplementedException();
}
public PdfRectangle GetBoundingBox(int characterCode)
public PdfRectangle GetBoundingBox(int characterIdentifier)
{
throw new System.NotImplementedException();
}

View File

@@ -15,6 +15,7 @@
private readonly ICidFontProgram fontProgram;
private readonly VerticalWritingMetrics verticalWritingMetrics;
private readonly IReadOnlyDictionary<int, decimal> widths;
private readonly CharacterIdentifierToGlyphIndexMap cidToGid;
public NameToken Type { get; }
public NameToken SubType { get; }
@@ -24,10 +25,11 @@
public CidFontType CidFontType => CidFontType.Type2;
public FontDescriptor Descriptor { get; }
public Type2CidFont(NameToken type, NameToken subType, NameToken baseFont, CharacterIdentifierSystemInfo systemInfo,
public Type2CidFont(NameToken type, NameToken subType, NameToken baseFont, CharacterIdentifierSystemInfo systemInfo,
FontDescriptor descriptor, ICidFontProgram fontProgram,
VerticalWritingMetrics verticalWritingMetrics,
IReadOnlyDictionary<int, decimal> widths)
IReadOnlyDictionary<int, decimal> widths,
CharacterIdentifierToGlyphIndexMap cidToGid)
{
Type = type;
SubType = subType;
@@ -37,6 +39,7 @@
this.fontProgram = fontProgram;
this.verticalWritingMetrics = verticalWritingMetrics;
this.widths = widths;
this.cidToGid = cidToGid;
// TODO: This should maybe take units per em into account?
var scale = 1 / 1000m;
@@ -49,9 +52,9 @@
throw new System.NotImplementedException();
}
public decimal GetWidthFromDictionary(int cid)
public decimal GetWidthFromDictionary(int characterIdentifier)
{
if (widths.TryGetValue(cid, out var width))
if (widths.TryGetValue(characterIdentifier, out var width))
{
return width;
}
@@ -59,14 +62,14 @@
return Descriptor.MissingWidth;
}
public PdfRectangle GetBoundingBox(int characterCode)
public PdfRectangle GetBoundingBox(int characterIdentifier)
{
if (fontProgram == null)
{
return Descriptor.BoundingBox;
}
if (fontProgram.TryGetBoundingBox(characterCode, out var result))
if (fontProgram.TryGetBoundingBox(characterIdentifier, cidToGid.GetGlyphIndex, out var result))
{
return result;
}

View File

@@ -90,7 +90,9 @@
public PdfRectangle GetBoundingBox(int characterCode)
{
return CidFont.GetBoundingBox(characterCode);
var cid = CMap.ConvertToCid(characterCode);
return CidFont.GetBoundingBox(cid);
}
public TransformationMatrix GetFontMatrix()

View File

@@ -52,7 +52,7 @@
var baseFont = dictionary.GetNameOrDefault(NameToken.BaseFont);
var systemInfo = GetSystemInfo(dictionary);
var subType = dictionary.GetNameOrDefault(NameToken.Subtype);
if (NameToken.CidFontType0.Equals(subType))
{
@@ -61,12 +61,14 @@
if (NameToken.CidFontType2.Equals(subType))
{
return new Type2CidFont(type, subType, baseFont, systemInfo, descriptor, fontProgram, verticalWritingMetrics, widths);
var cidToGid = GetCharacterIdentifierToGlyphIndexMap(dictionary, isLenientParsing);
return new Type2CidFont(type, subType, baseFont, systemInfo, descriptor, fontProgram, verticalWritingMetrics, widths, cidToGid);
}
return null;
}
private bool TryGetFontDescriptor(DictionaryToken dictionary, out DictionaryToken descriptorDictionary)
{
descriptorDictionary = null;
@@ -152,7 +154,7 @@
return widths;
}
private VerticalWritingMetrics ReadVerticalDisplacements(DictionaryToken dict)
private static VerticalWritingMetrics ReadVerticalDisplacements(DictionaryToken dict)
{
var verticalDisplacements = new Dictionary<int, decimal>();
var positionVectors = new Dictionary<int, PdfVector>();
@@ -237,6 +239,30 @@
return new CharacterIdentifierSystemInfo(registry, ordering, supplement);
}
private CharacterIdentifierToGlyphIndexMap GetCharacterIdentifierToGlyphIndexMap(DictionaryToken dictionary, bool isLenientParsing)
{
if (!dictionary.TryGet(NameToken.CidToGidMap, out var entry))
{
return new CharacterIdentifierToGlyphIndexMap();
}
if (entry is NameToken name)
{
if (!name.Equals(NameToken.CidToGidMap) && !isLenientParsing)
{
throw new InvalidOperationException($"The CIDToGIDMap in a Type 0 font should have the value /Identity, instead got: {name}.");
}
return new CharacterIdentifierToGlyphIndexMap();
}
var stream = DirectObjectFinder.Get<StreamToken>(entry, pdfScanner);
var bytes = stream.Decode(filterProvider);
return new CharacterIdentifierToGlyphIndexMap(bytes);
}
private string SafeKeyAccess(DictionaryToken dictionary, NameToken keyName)
{
if (!dictionary.TryGet(keyName, out var token))

View File

@@ -31,16 +31,23 @@
GlyphTable = tableRegister.GlyphDataTable;
}
public bool TryGetBoundingBox(int characterCode, out PdfRectangle boundingBox)
public bool TryGetBoundingBox(int characterCode, out PdfRectangle boundingBox) => TryGetBoundingBox(characterCode, null, out boundingBox);
public bool TryGetBoundingBox(int characterCode, Func<int, int> characterIdentifierToGlyphIndex, out PdfRectangle boundingBox)
{
boundingBox = default(PdfRectangle);
int index;
if (CMapTable == null)
{
return false;
}
if (characterIdentifierToGlyphIndex == null)
{
return false;
}
if (!CMapTable.TryGetGlyphIndex(characterCode, out var index))
index = characterIdentifierToGlyphIndex(characterCode);
}
else if (!CMapTable.TryGetGlyphIndex(characterCode, out index))
{
return false;
}