diff --git a/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs b/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs index 9b5ace7f..22a454b0 100644 --- a/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs +++ b/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs @@ -12,6 +12,9 @@ internal class TrueTypeSimpleFont : IFont { + private static readonly TransformationMatrix DefaultTransformation = + TransformationMatrix.FromValues(1m / 1000m, 0, 0, 1m / 1000m, 0, 0); + private readonly FontDescriptor descriptor; [CanBeNull] @@ -90,32 +93,51 @@ { var fontMatrix = GetFontMatrix(); - var boundingBox = GetBoundingBoxInGlyphSpace(characterCode); + var boundingBox = GetBoundingBoxInGlyphSpace(characterCode, out var fromFont); - boundingBox = fontMatrix.Transform(boundingBox); + var boundingBoxPreTransform = boundingBox.Width; + if (fromFont) + { + boundingBox = fontMatrix.Transform(boundingBox); + } + else + { + boundingBox = DefaultTransformation.Transform(boundingBox); + } + decimal width; if (font == null) { + fromFont = false; width = widths[characterCode]; } else { if (!font.TryGetBoundingAdvancedWidth(characterCode, out width)) { - width = boundingBox.Width; + width = boundingBoxPreTransform; } } var advancedRectangle = new PdfRectangle(0, 0, width, 0); - advancedRectangle = fontMatrix.Transform(advancedRectangle); + if (fromFont) + { + advancedRectangle = fontMatrix.Transform(advancedRectangle); + } + else + { + advancedRectangle = DefaultTransformation.Transform(advancedRectangle); + } return new CharacterBoundingBox(boundingBox, advancedRectangle); } - private PdfRectangle GetBoundingBoxInGlyphSpace(int characterCode) + private PdfRectangle GetBoundingBoxInGlyphSpace(int characterCode, out bool fromFont) { + fromFont = true; + if (font == null) { return descriptor.BoundingBox; @@ -131,6 +153,8 @@ return new PdfRectangle(0, 0, width, 0); } + fromFont = false; + return new PdfRectangle(0, 0, GetWidth(characterCode), 0); } diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapSubTables/Format4CMapTable.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapSubTables/Format4CMapTable.cs index 604a6df8..b08a6594 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapSubTables/Format4CMapTable.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapSubTables/Format4CMapTable.cs @@ -45,7 +45,7 @@ namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables if (segment.IdRangeOffset == 0) { - return (characterCode + segment.IdDelta) % ushort.MaxValue; + return (characterCode + segment.IdDelta) & 0xFFFF; } var offset = segment.IdRangeOffset / 2 + (characterCode - segment.StartCode); diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapTable.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapTable.cs index 9775074d..c0aa5a82 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapTable.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Tables/CMapTable.cs @@ -30,6 +30,8 @@ return false; } + var windowsMapping = default(ICMapSubTable); + foreach (var subTable in subTables) { glyphIndex = subTable.CharacterCodeToGlyphIndex(characterCode); @@ -38,6 +40,37 @@ { return true; } + + if (subTable.EncodingId == 0 && subTable.PlatformId == 3) + { + windowsMapping = subTable; + } + } + + if (windowsMapping != null && characterCode >= 0 && characterCode <= 255) + { + // the CMap may use one of the following code ranges, so that we have to add the high byte to get the + // mapped value + glyphIndex = windowsMapping.CharacterCodeToGlyphIndex(characterCode + 0xF000); + + if (glyphIndex != 0) + { + return true; + } + + glyphIndex = windowsMapping.CharacterCodeToGlyphIndex(characterCode + 0xF100); + + if (glyphIndex != 0) + { + return true; + } + + glyphIndex = windowsMapping.CharacterCodeToGlyphIndex(characterCode + 0xF200); + + if (glyphIndex != 0) + { + return true; + } } return false;