diff --git a/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Andada-Regular.ttf b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Andada-Regular.ttf new file mode 100644 index 00000000..f235bfb3 Binary files /dev/null and b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Andada-Regular.ttf differ diff --git a/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs index 47fe9316..56535361 100644 --- a/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs +++ b/src/UglyToad.PdfPig.Tests/Fonts/TrueType/Parser/TrueTypeFontParserTests.cs @@ -2,7 +2,6 @@ { using System; using System.IO; - using System.Linq; using System.Text.RegularExpressions; using PdfPig.Fonts.TrueType; using PdfPig.Fonts.TrueType.Parser; @@ -14,17 +13,13 @@ { private static byte[] GetFileBytes(string name) { - var manifestFiles = typeof(TrueTypeFontParserTests).Assembly.GetManifestResourceNames(); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts", "TrueType"); - var match = manifestFiles.Single(x => x.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) >= 0); + name = name.EndsWith(".ttf") ? name : name + ".ttf"; - using (var memoryStream = new MemoryStream()) - using (var stream = typeof(TrueTypeFontParserTests).Assembly.GetManifestResourceStream(match)) - { - stream.CopyTo(memoryStream); + var file = Path.Combine(path, name); - return memoryStream.ToArray(); - } + return File.ReadAllBytes(file); } private readonly TrueTypeFontParser parser = new TrueTypeFontParser(); @@ -136,13 +131,27 @@ } [Fact] - public void ParseEmbeddedSimpleGoogleDocssGautmi() + public void ParseSimpleGoogleDocssGautmi() { var bytes = GetFileBytes("google-simple-doc"); var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes)); - parser.Parse(input); + var font = parser.Parse(input); + + Assert.NotNull(font.GlyphTable); + } + + [Fact] + public void ParseAndadaRegular() + { + var bytes = GetFileBytes("Andada-Regular"); + + var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes)); + + var font = parser.Parse(input); + + Assert.NotNull(font.GlyphTable); } [Fact] diff --git a/src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs b/src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs new file mode 100644 index 00000000..d01d4c3f --- /dev/null +++ b/src/UglyToad.PdfPig.Tests/Tokens/BooleanTokenTests.cs @@ -0,0 +1,45 @@ +namespace UglyToad.PdfPig.Tests.Tokens +{ + using PdfPig.Tokens; + using Xunit; + + public class BooleanTokenTests + { + [Fact] + public void BooleanTokensObjectEquals() + { + var one = BooleanToken.True; + var two = (object) BooleanToken.True; + + Assert.True(one.Equals(two)); + } + + [Fact] + public void BooleanTokensObjectNotEqual() + { + var one = BooleanToken.False; + var two = (object)BooleanToken.True; + + Assert.False(one.Equals(two)); + } + + [Fact] + public void BooleanTokensHashCodeMatch() + { + Assert.Equal(BooleanToken.True.GetHashCode(), BooleanToken.True.GetHashCode()); + } + + [Fact] + public void BooleanTokensHashCodeNotMatch() + { + Assert.NotEqual(BooleanToken.True.GetHashCode(), BooleanToken.False.GetHashCode()); + } + + [Fact] + public void BooleanTokensStringRepresentationCorrect() + { + Assert.Equal("True", BooleanToken.True.ToString()); + Assert.Equal("False", BooleanToken.False.ToString()); + } + } +} diff --git a/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs b/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs index 3b89a82b..13dabd33 100644 --- a/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs +++ b/src/UglyToad.PdfPig.Tests/Tokens/DictionaryTokenTests.cs @@ -3,6 +3,7 @@ namespace UglyToad.PdfPig.Tests.Tokens { using System; using System.Collections.Generic; + using Exceptions; using PdfPig.Tokens; using Xunit; @@ -73,5 +74,43 @@ namespace UglyToad.PdfPig.Tests.Tokens Assert.True(result); Assert.Equal("None", Assert.IsType(token).Data); } + + [Fact] + public void CreateWithNonNameTokensThrows() + { + Action action = () => new DictionaryToken(new Dictionary + { + { new NumericToken(7), NameToken.N } + }); + + Assert.Throws(action); + } + + [Fact] + public void GetWithObjectNotOfTypeOrReferenceThrows() + { + var dictionary = new DictionaryToken(new Dictionary + { + { NameToken.Count, new StringToken("twelve") } + }); + + Action action = () => dictionary.Get(NameToken.Count, new TestPdfTokenScanner()); + + Assert.Throws(action); + } + + [Fact] + public void WithCorrectlyAddsKey() + { + var dictionary = new DictionaryToken(new Dictionary + { + { NameToken.Count, new StringToken("12") } + }); + + var newDictionary = dictionary.With(NameToken.ActualText, new StringToken("The text")); + + Assert.True(newDictionary.ContainsKey(NameToken.ActualText)); + Assert.Equal("The text", newDictionary.Get(NameToken.ActualText, new TestPdfTokenScanner()).Data); + } } } diff --git a/src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs b/src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs new file mode 100644 index 00000000..c28e43fa --- /dev/null +++ b/src/UglyToad.PdfPig.Tests/Tokens/TestPdfTokenScanner.cs @@ -0,0 +1,43 @@ +// ReSharper disable ObjectCreationAsStatement +namespace UglyToad.PdfPig.Tests.Tokens +{ + using System; + using PdfPig.Tokenization; + using PdfPig.Tokenization.Scanner; + using PdfPig.Tokens; + + internal class TestPdfTokenScanner : IPdfTokenScanner + { + public bool MoveNext() + { + throw new NotImplementedException(); + } + + public IToken CurrentToken { get; set; } + public bool TryReadToken(out T token) where T : class, IToken + { + throw new NotImplementedException(); + } + + public void Seek(long position) + { + throw new NotImplementedException(); + } + + public long CurrentPosition { get; set; } + public void RegisterCustomTokenizer(byte firstByte, ITokenizer tokenizer) + { + throw new NotImplementedException(); + } + + public void DeregisterCustomTokenizer(ITokenizer tokenizer) + { + throw new NotImplementedException(); + } + + public ObjectToken Get(IndirectReference reference) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj b/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj index a2dcc646..1cba82ba 100644 --- a/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj +++ b/src/UglyToad.PdfPig.Tests/UglyToad.PdfPig.Tests.csproj @@ -30,6 +30,9 @@ + + + @@ -45,6 +48,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs index 9e3faa55..b0495a4a 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs @@ -71,7 +71,7 @@ return new TrueTypeSimpleFont(name, descriptor, toUnicodeCMap, encoding, font, firstCharacter, widths); } - private TrueTypeFont ParseTrueTypeFont(FontDescriptor descriptor) + private TrueTypeFontProgram ParseTrueTypeFont(FontDescriptor descriptor) { if (descriptor?.FontFile == null) { diff --git a/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs b/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs index 4729c728..479f6f41 100644 --- a/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs +++ b/src/UglyToad.PdfPig/Fonts/Simple/TrueTypeSimpleFont.cs @@ -22,7 +22,7 @@ private readonly Encoding encoding; [CanBeNull] - private readonly TrueTypeFont font; + private readonly TrueTypeFontProgram fontProgram; private readonly int firstCharacter; @@ -39,13 +39,13 @@ FontDescriptor descriptor, [CanBeNull] CMap toUnicodeCMap, [CanBeNull] Encoding encoding, - [CanBeNull] TrueTypeFont font, + [CanBeNull] TrueTypeFontProgram fontProgram, int firstCharacter, decimal[] widths) { this.descriptor = descriptor; this.encoding = encoding; - this.font = font; + this.fontProgram = fontProgram; this.firstCharacter = firstCharacter; this.widths = widths; @@ -115,9 +115,9 @@ fromFont = false; width = widths[index]; } - else if (font != null) + else if (fontProgram != null) { - if (!font.TryGetBoundingAdvancedWidth(characterCode, out width)) + if (!fontProgram.TryGetBoundingAdvancedWidth(characterCode, out width)) { width = boundingBoxPreTransform; } @@ -143,17 +143,17 @@ { fromFont = true; - if (font == null) + if (fontProgram == null) { return descriptor.BoundingBox; } - if (font.TryGetBoundingBox(characterCode, out var bounds)) + if (fontProgram.TryGetBoundingBox(characterCode, out var bounds)) { return bounds; } - if (font.TryGetBoundingAdvancedWidth(characterCode, out var width)) + if (fontProgram.TryGetBoundingAdvancedWidth(characterCode, out var width)) { return new PdfRectangle(0, 0, width, 0); } @@ -179,9 +179,9 @@ { var scale = 1000m; - if (font?.HeaderTable != null) + if (fontProgram?.HeaderTable != null) { - scale = font.GetFontMatrixMultiplier(); + scale = fontProgram.GetFontMatrixMultiplier(); } return TransformationMatrix.FromValues(1m / scale, 0, 0, 1m / scale, 0, 0); diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs index b997bc80..d5554b2f 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TableRegister.cs @@ -23,7 +23,7 @@ /// /// Defines mapping of character codes to glyph index values in the font. - /// Can contain mutliple sub-tables to support multiple encoding schemes. + /// Can contain multiple sub-tables to support multiple encoding schemes. /// Where a character code isn't found it should map to index 0. /// public CMapTable CMapTable { get; set; } diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs index 1cd6c9ad..a36436df 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/Parser/TrueTypeFontParser.cs @@ -7,7 +7,7 @@ internal class TrueTypeFontParser { - public TrueTypeFont Parse(TrueTypeDataBytes data) + public TrueTypeFontProgram Parse(TrueTypeDataBytes data) { var version = (decimal)data.Read32Fixed(); int numberOfTables = data.ReadUnsignedShort(); @@ -53,7 +53,7 @@ return new TrueTypeHeaderTable(tag, checksum, offset, length); } - private static TrueTypeFont ParseTables(decimal version, IReadOnlyDictionary tables, TrueTypeDataBytes data) + private static TrueTypeFontProgram ParseTables(decimal version, IReadOnlyDictionary tables, TrueTypeDataBytes data) { var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff); @@ -111,7 +111,7 @@ OptionallyParseTables(tables, data, tableRegister); } - return new TrueTypeFont(version, tables, tableRegister); + return new TrueTypeFontProgram(version, tables, tableRegister); } private static void OptionallyParseTables(IReadOnlyDictionary tables, TrueTypeDataBytes data, TableRegister tableRegister) diff --git a/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFont.cs b/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFontProgram.cs similarity index 94% rename from src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFont.cs rename to src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFontProgram.cs index ec0b1f91..838f7d46 100644 --- a/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFont.cs +++ b/src/UglyToad.PdfPig/Fonts/TrueType/TrueTypeFontProgram.cs @@ -7,7 +7,7 @@ using Parser; using Tables; - internal class TrueTypeFont : ICidFontProgram + internal class TrueTypeFontProgram : ICidFontProgram { public decimal Version { get; } @@ -18,7 +18,7 @@ public GlyphDataTable GlyphTable { get; } public TableRegister TableRegister { get; } - public TrueTypeFont(decimal version, IReadOnlyDictionary tableHeaders, TableRegister tableRegister) + public TrueTypeFontProgram(decimal version, IReadOnlyDictionary tableHeaders, TableRegister tableRegister) { Version = version; TableHeaders = tableHeaders; diff --git a/src/UglyToad.PdfPig/Tokens/BooleanToken.cs b/src/UglyToad.PdfPig/Tokens/BooleanToken.cs index c037ce37..95e16168 100644 --- a/src/UglyToad.PdfPig/Tokens/BooleanToken.cs +++ b/src/UglyToad.PdfPig/Tokens/BooleanToken.cs @@ -5,7 +5,7 @@ /// /// The boolean object either () or (). /// - public class BooleanToken : IDataToken + public sealed class BooleanToken : IDataToken { /// /// The boolean token corresponding to . @@ -43,15 +43,7 @@ return other.Data == Data; } - - /// - /// Check if two boolean tokens are equal in value. - /// - protected bool Equals(BooleanToken other) - { - return Data == other.Data; - } - + /// public override int GetHashCode() { diff --git a/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs b/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs index 356d257b..622a0efe 100644 --- a/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs +++ b/src/UglyToad.PdfPig/Tokens/DictionaryToken.cs @@ -42,7 +42,7 @@ else { // For now: - throw new PdfDocumentFormatException("Key for dictionary token was not a string! " + keyValuePair.Key); + throw new PdfDocumentFormatException($"Key for dictionary token was not a name! {keyValuePair.Key}"); } } @@ -60,7 +60,7 @@ { if (!(token is IndirectReferenceToken indirectReference)) { - throw new InvalidOperationException($"Dictionary does not contain token with name {name} of type {typeof(T).Name}."); + throw new PdfDocumentFormatException($"Dictionary does not contain token with name {name} of type {typeof(T).Name}."); } typedToken = DirectObjectFinder.Get(indirectReference, scanner);