use byte values when showing text for document builder #98

when writing text content the current show text operator was just writing the unicode string value and hoping it produced the correct value in the resulting document despite the values being consumed in a different encoding. this change adds a method to retrieve the corresponding byte value for a unicode character and uses that to write a hex show text operator to the page content. this is only implemented for standard14 fonts in this change.

for standard14 fonts we look up the corresponding name for the unicode value from the adobe glyph list. once we find the corresponding glyph name we look up the code value in the encoding we have chosen when writing standard14 fonts (macromanencoding). this value is then the byte value written to the show text operator. if the value does not appear in any of the lookups we throw a not support exception.

this also adds a test case which will still fail for czech characters in a truetype font, the issue reported in #98.
This commit is contained in:
Eliot Jones
2019-12-28 14:42:27 +00:00
parent 5e3f5651b8
commit 87528199c6
7 changed files with 63 additions and 5 deletions

View File

@@ -272,6 +272,31 @@
}
}
public void CanWriteSinglePageWithCzechCharacters()
{
var builder = new PdfDocumentBuilder();
var page = builder.AddPage(PageSize.A4);
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts", "TrueType");
var file = Path.Combine(path, "Roboto-Regular.ttf");
var font = builder.AddTrueTypeFont(File.ReadAllBytes(file));
page.AddText("Hello: řó", 9,
new PdfPoint(30, page.PageSize.Height - 50), font);
var bytes = builder.Build();
WriteFile(nameof(CanWriteSinglePageWithCzechCharacters), bytes);
using (var document = PdfDocument.Open(bytes))
{
var page1 = document.GetPage(1);
Assert.Equal("Hello: řó", page1.Text);
}
}
private static void WriteFile(string name, byte[] bytes)
{
try

View File

@@ -1,6 +1,5 @@
namespace UglyToad.PdfPig.Fonts.Encodings
{
using System;
using System.Collections.Generic;
using Tokens;
@@ -13,7 +12,7 @@
public IReadOnlyDictionary<int, string> CodeToNameMap => CodeToName;
protected readonly Dictionary<string, int> NameToCode = new Dictionary<string, int>(250, StringComparer.OrdinalIgnoreCase);
protected readonly Dictionary<string, int> NameToCode = new Dictionary<string, int>(250);
public IReadOnlyDictionary<string, int> NameToCodeMap => NameToCode;

View File

@@ -1,4 +1,5 @@
namespace UglyToad.PdfPig.Fonts.Simple
// ReSharper disable CompareOfFloatsByEqualityOperator
namespace UglyToad.PdfPig.Fonts.Simple
{
using System;
using Core;

View File

@@ -18,5 +18,7 @@
TransformationMatrix GetFontMatrix();
ObjectToken WriteFont(NameToken fontKeyName, Stream outputStream, BuilderContext context);
byte GetValueForCharacter(char character);
}
}

View File

@@ -14,6 +14,8 @@
using Graphics.Operations.TextPositioning;
using Graphics.Operations.TextShowing;
using Graphics.Operations.TextState;
using Tokens;
using Util;
/// <summary>
/// A builder used to add construct a page in a PDF document.
@@ -227,7 +229,12 @@
operations.Add(BeginText.Value);
operations.Add(new SetFontAndSize(font.Name, fontSize));
operations.Add(new MoveToNextLineWithOffset((decimal)position.X, (decimal)position.Y));
operations.Add(new ShowText(text));
foreach (var letter in text)
{
var b = fontProgram.GetValueForCharacter(letter);
operations.Add(new ShowText(new [] { b }));
}
operations.Add(EndText.Value);
return letters;

View File

@@ -72,6 +72,25 @@
return result;
}
public byte GetValueForCharacter(char character)
{
var name = GlyphList.AdobeGlyphList.UnicodeCodePointToName(character);
if (name == null || !MacRomanEncoding.Instance.NameToCodeMap.TryGetValue(name, out var code))
{
var nameError = name ?? "NULL";
throw new NotSupportedException($"No mapping for character '{character}' exists in the Standard14 font. Glyph name: '{nameError}'.");
}
if (code > byte.MaxValue)
{
throw new NotSupportedException($"Value of code for character '{character}' exceeded the range of a byte. Glyph name: '{name}'.");
}
var result = (byte) code;
return result;
}
}
internal class BuilderContext

View File

@@ -122,6 +122,11 @@
return result;
}
public byte GetValueForCharacter(char character)
{
return (byte) character;
}
private byte[] CompressBytes()
{
using (var memoryStream = new MemoryStream(fontFileBytes.ToArray()))