support system fonts without descriptors and also enable overridden widths #101

This commit is contained in:
Eliot Jones
2019-12-17 17:32:22 +00:00
parent ec4f8ac5bf
commit 57fb3d3e79
2 changed files with 86 additions and 5 deletions

View File

@@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.Linq;
using SystemFonts;
using Cmap;
using Encodings;
@@ -48,7 +49,9 @@
public IFont Generate(DictionaryToken dictionary, bool isLenientParsing)
{
if (!dictionary.TryGetOptionalTokenDirect(NameToken.FirstChar, pdfScanner, out NumericToken firstCharacterToken))
if (!dictionary.TryGetOptionalTokenDirect(NameToken.FirstChar, pdfScanner, out NumericToken firstCharacterToken)
|| !dictionary.TryGet<IToken>(NameToken.FontDescriptor, pdfScanner, out _)
|| !dictionary.TryGet(NameToken.Widths, out IToken _))
{
if (!dictionary.TryGetOptionalTokenDirect(NameToken.BaseFont, pdfScanner, out NameToken baseFont))
{
@@ -72,7 +75,22 @@
thisEncoding = new AdobeFontMetricsEncoding(standard14Font);
}
return new TrueTypeStandard14FallbackSimpleFont(baseFont, standard14Font, thisEncoding, fileSystemFont);
int? firstChar = null;
decimal[] widthsOverride = null;
if (dictionary.TryGet(NameToken.FirstChar, pdfScanner, out firstCharacterToken))
{
firstChar = firstCharacterToken.Int;
}
if (dictionary.TryGet(NameToken.Widths, pdfScanner, out ArrayToken widthsArray))
{
widthsOverride = widthsArray.Data.OfType<NumericToken>()
.Select(x => x.Data).ToArray();
}
return new TrueTypeStandard14FallbackSimpleFont(baseFont, standard14Font, thisEncoding, fileSystemFont,
new TrueTypeStandard14FallbackSimpleFont.MetricOverrides(firstChar, widthsOverride));
}
var firstCharacter = firstCharacterToken.Int;

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Fonts.Simple
{
using System;
using System.Collections.Generic;
using Core;
using Encodings;
using IO;
@@ -18,16 +19,19 @@
private readonly FontMetrics fontMetrics;
private readonly Encoding encoding;
private readonly TrueTypeFontProgram font;
private readonly MetricOverrides overrides;
public NameToken Name { get; }
public bool IsVertical { get; } = false;
public TrueTypeStandard14FallbackSimpleFont(NameToken name, FontMetrics fontMetrics, Encoding encoding, TrueTypeFontProgram font)
public TrueTypeStandard14FallbackSimpleFont(NameToken name, FontMetrics fontMetrics, Encoding encoding, TrueTypeFontProgram font,
MetricOverrides overrides)
{
this.fontMetrics = fontMetrics;
this.encoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
this.font = font;
this.overrides = overrides;
Name = name;
}
@@ -61,18 +65,39 @@
public CharacterBoundingBox GetBoundingBox(int characterCode)
{
var width = 0m;
var fontMatrix = GetFontMatrix();
if (font != null && font.TryGetBoundingBox(characterCode, out var bounds))
{
bounds = fontMatrix.Transform(bounds);
return new CharacterBoundingBox(bounds, bounds.Width);
if (overrides?.TryGetWidth(characterCode, out width) != true)
{
width = bounds.Width;
}
else
{
width = DefaultTransformation.TransformX(width);
}
return new CharacterBoundingBox(bounds, width);
}
var name = encoding.GetName(characterCode);
var metrics = fontMetrics.CharacterMetrics[name];
if (overrides?.TryGetWidth(characterCode, out width) != true)
{
width = fontMatrix.TransformX(metrics.WidthX);
}
else
{
width = DefaultTransformation.TransformX(width);
}
bounds = fontMatrix.Transform(metrics.BoundingBox);
var width = fontMatrix.TransformX(metrics.WidthX);
return new CharacterBoundingBox(bounds, width);
}
@@ -88,5 +113,43 @@
return DefaultTransformation;
}
public class MetricOverrides
{
public int? FirstCharacterCode { get; }
public IReadOnlyList<decimal> Widths { get; }
public bool HasOverriddenMetrics { get; }
public MetricOverrides(int? firstCharacterCode, IReadOnlyList<decimal> widths)
{
FirstCharacterCode = firstCharacterCode;
Widths = widths;
HasOverriddenMetrics = FirstCharacterCode.HasValue && Widths != null
&& Widths.Count > 0;
}
public bool TryGetWidth(int characterCode, out decimal width)
{
width = 0;
if (!HasOverriddenMetrics || !FirstCharacterCode.HasValue)
{
return false;
}
var index = characterCode - FirstCharacterCode.Value;
if (index < 0 || index >= Widths.Count)
{
return false;
}
width = Widths[index];
return true;
}
}
}
}