mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-03-10 00:23:29 +08:00
move classes to new projects
to make the project more useful and expose more usable classes we're rearchitecting in the following way. code used to read fonts from external file formats like truetype, adobe font metrics (afm) and adobe type 1 fonts are moving to a new project which doesn't reference most of the pdf logic. the shared logic is moving to a new flat-structured project called core. this is a sort-of onion type architecture, with core being the... core, fonts being the next layer of the onion, pdfpig itself the next. this will then support additional libraries/projects as outer layers of the onion as well as releasing standalone version of the font library as pdfbox does with fontbox.
This commit is contained in:
@@ -1,15 +1,22 @@
|
||||
namespace UglyToad.PdfPig.IO
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
internal class ByteArrayInputBytes : IInputBytes
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Input bytes from a byte array.
|
||||
/// </summary>
|
||||
public class ByteArrayInputBytes : IInputBytes
|
||||
{
|
||||
private readonly int upperBound;
|
||||
private readonly byte[] bytes;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ByteArrayInputBytes"/>.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public ByteArrayInputBytes(IReadOnlyList<byte> bytes)
|
||||
{
|
||||
@@ -32,6 +39,9 @@
|
||||
currentOffset = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ByteArrayInputBytes"/>.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public ByteArrayInputBytes(byte[] bytes)
|
||||
{
|
||||
@@ -41,8 +51,10 @@
|
||||
}
|
||||
|
||||
private int currentOffset;
|
||||
/// <inheritdoc />
|
||||
public long CurrentOffset => currentOffset + 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (currentOffset == upperBound)
|
||||
@@ -55,10 +67,13 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte CurrentByte { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public long Length => bytes.Length;
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte? Peek()
|
||||
{
|
||||
if (currentOffset == upperBound)
|
||||
@@ -69,17 +84,20 @@
|
||||
return bytes[currentOffset + 1];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAtEnd()
|
||||
{
|
||||
return currentOffset == upperBound;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Seek(long position)
|
||||
{
|
||||
currentOffset = (int)position - 1;
|
||||
CurrentByte = currentOffset < 0 ? (byte)0 : bytes[currentOffset];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Read(byte[] buffer, int? length = null)
|
||||
{
|
||||
var bytesToRead = buffer.Length;
|
||||
@@ -118,6 +136,7 @@
|
||||
return readLength;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace UglyToad.PdfPig.Util
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// NET 4.5 compatible Array.Empty.
|
||||
/// </summary>
|
||||
internal static class EmptyArray<T>
|
||||
public static class EmptyArray<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty array.
|
||||
13
src/UglyToad.PdfPig.Core/IDeepCloneable.cs
Normal file
13
src/UglyToad.PdfPig.Core/IDeepCloneable.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type may be cloned making entirely independent copies.
|
||||
/// </summary>
|
||||
public interface IDeepCloneable<out T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Clone the type including all referenced data.
|
||||
/// </summary>
|
||||
T DeepClone();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.PdfPig.IO
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
namespace UglyToad.PdfPig.IO
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a data structure can be written to an output stream.
|
||||
/// </summary>
|
||||
internal interface IWriteable
|
||||
public interface IWriteable
|
||||
{
|
||||
/// <summary>
|
||||
/// Write the data to the output stream.
|
||||
@@ -1,16 +1,22 @@
|
||||
namespace UglyToad.PdfPig.Util
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
internal static class OtherEncodings
|
||||
/// <summary>
|
||||
/// Convenience access to frequently used encodings.
|
||||
/// </summary>
|
||||
public static class OtherEncodings
|
||||
{
|
||||
/// <summary>
|
||||
/// Latin 1 Encoding: ISO 8859-1 is a single-byte encoding that can represent the first 256 Unicode characters.
|
||||
/// </summary>
|
||||
public static Encoding Iso88591 = Encoding.GetEncoding("ISO-8859-1");
|
||||
|
||||
/// <summary>
|
||||
/// Convert the string to bytes using the ISO 8859-1 encoding.
|
||||
/// </summary>
|
||||
public static byte[] StringAsLatin1Bytes(string s)
|
||||
{
|
||||
if (s == null)
|
||||
@@ -21,8 +27,16 @@
|
||||
return Iso88591.GetBytes(s);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the bytes to string using the ISO 8859-1 encoding.
|
||||
/// </summary>
|
||||
public static string BytesAsLatin1String(IReadOnlyList<byte> bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (bytes is byte[] arr)
|
||||
{
|
||||
return BytesAsLatin1String(arr);
|
||||
@@ -31,6 +45,9 @@
|
||||
return BytesAsLatin1String(bytes.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the bytes to string using the ISO 8859-1 encoding.
|
||||
/// </summary>
|
||||
public static string BytesAsLatin1String(byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
39
src/UglyToad.PdfPig.Core/PdfDocumentFormatException.cs
Normal file
39
src/UglyToad.PdfPig.Core/PdfDocumentFormatException.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// This exception will be thrown where the contents of the PDF document do not match the specification in such a way that it
|
||||
/// renders the document unreadable.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PdfDocumentFormatException : Exception
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Create a new <see cref="T:UglyToad.PdfPig.Exceptions.PdfDocumentFormatException" />.
|
||||
/// </summary>
|
||||
public PdfDocumentFormatException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PdfDocumentFormatException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PdfDocumentFormatException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected PdfDocumentFormatException(
|
||||
SerializationInfo info,
|
||||
StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.PdfPig.Geometry
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -88,11 +88,6 @@
|
||||
return new PdfPoint(X + dx, Y + dy);
|
||||
}
|
||||
|
||||
internal PdfVector ToVector()
|
||||
{
|
||||
return new PdfVector(X, Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether this <see cref="PdfPoint"/> is equal to a specified <see cref="PdfPoint"/> .
|
||||
/// </summary>
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.PdfPig.Geometry
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A rectangle in a PDF file.
|
||||
@@ -70,8 +70,15 @@
|
||||
/// </summary>
|
||||
public double Bottom => BottomRight.Y;
|
||||
|
||||
internal PdfRectangle(PdfPoint point1, PdfPoint point2) : this(point1.X, point1.Y, point2.X, point2.Y) { }
|
||||
internal PdfRectangle(short x1, short y1, short x2, short y2) : this((double)x1, y1, x2, y2) { }
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PdfRectangle"/>.
|
||||
/// </summary>
|
||||
public PdfRectangle(PdfPoint point1, PdfPoint point2) : this(point1.X, point1.Y, point2.X, point2.Y) { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PdfRectangle"/>.
|
||||
/// </summary>
|
||||
public PdfRectangle(short x1, short y1, short x2, short y2) : this((double)x1, y1, x2, y2) { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PdfRectangle"/>.
|
||||
@@ -112,12 +119,10 @@
|
||||
BottomRight = new PdfPoint(right, bottom);
|
||||
}
|
||||
|
||||
internal PdfRectangle(PdfVector topLeft, PdfVector topRight, PdfVector bottomLeft, PdfVector bottomRight)
|
||||
: this(topLeft.ToPoint(), topRight.ToPoint(), bottomLeft.ToPoint(), bottomRight.ToPoint())
|
||||
{
|
||||
}
|
||||
|
||||
internal PdfRectangle(PdfPoint topLeft, PdfPoint topRight, PdfPoint bottomLeft, PdfPoint bottomRight)
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PdfRectangle"/>.
|
||||
/// </summary>
|
||||
public PdfRectangle(PdfPoint topLeft, PdfPoint topRight, PdfPoint bottomLeft, PdfPoint bottomRight)
|
||||
{
|
||||
TopLeft = topLeft;
|
||||
TopRight = topRight;
|
||||
@@ -1,18 +1,47 @@
|
||||
namespace UglyToad.PdfPig.Parser.Parts
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Exceptions;
|
||||
using IO;
|
||||
using Util;
|
||||
|
||||
internal static class ReadHelper
|
||||
/// <summary>
|
||||
/// Helper methods for reading from PDF files.
|
||||
/// </summary>
|
||||
public static class ReadHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// The line-feed '\n' character.
|
||||
/// </summary>
|
||||
public const byte AsciiLineFeed = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The carriage return '\r' character.
|
||||
/// </summary>
|
||||
public const byte AsciiCarriageReturn = 13;
|
||||
|
||||
private static readonly HashSet<int> EndOfNameCharacters = new HashSet<int>
|
||||
{
|
||||
' ',
|
||||
AsciiCarriageReturn,
|
||||
AsciiLineFeed,
|
||||
9,
|
||||
'>',
|
||||
'<',
|
||||
'[',
|
||||
'/',
|
||||
']',
|
||||
')',
|
||||
'(',
|
||||
0,
|
||||
'\f'
|
||||
};
|
||||
|
||||
private static readonly int MaximumNumberStringLength = long.MaxValue.ToString("D").Length;
|
||||
|
||||
/// <summary>
|
||||
/// Read a string from the input until a newline.
|
||||
/// </summary>
|
||||
public static string ReadLine(IInputBytes bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
@@ -50,6 +79,9 @@
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip any whitespace characters.
|
||||
/// </summary>
|
||||
public static void SkipSpaces(IInputBytes bytes)
|
||||
{
|
||||
const int commentCharacter = 37;
|
||||
@@ -81,24 +113,10 @@
|
||||
bytes.Seek(bytes.CurrentOffset - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<int> EndOfNameCharacters = new HashSet<int>
|
||||
{
|
||||
' ',
|
||||
AsciiCarriageReturn,
|
||||
AsciiLineFeed,
|
||||
9,
|
||||
'>',
|
||||
'<',
|
||||
'[',
|
||||
'/',
|
||||
']',
|
||||
')',
|
||||
'(',
|
||||
0,
|
||||
'\f'
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given character value is the end of a PDF Name token.
|
||||
/// </summary>
|
||||
public static bool IsEndOfName(int ch)
|
||||
{
|
||||
return EndOfNameCharacters.Contains(ch);
|
||||
@@ -115,22 +133,38 @@
|
||||
return c == 0 || c == 32 || c == AsciiLineFeed || c == AsciiCarriageReturn || c == 9 || c == 12;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the character is an end of line character.
|
||||
/// </summary>
|
||||
public static bool IsEndOfLine(char c) => IsEndOfLine((byte) c);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the character is an end of line character.
|
||||
/// </summary>
|
||||
public static bool IsEndOfLine(byte b)
|
||||
{
|
||||
return IsLineFeed(b) || IsCarriageReturn(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the character is an line feed '\n' character.
|
||||
/// </summary>
|
||||
public static bool IsLineFeed(byte? c)
|
||||
{
|
||||
return AsciiLineFeed == c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the character is a carriage return '\r' character.
|
||||
/// </summary>
|
||||
public static bool IsCarriageReturn(byte c)
|
||||
{
|
||||
return AsciiCarriageReturn == c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given string is at this position in the input.
|
||||
/// </summary>
|
||||
public static bool IsString(IInputBytes bytes, string s)
|
||||
{
|
||||
bool found = true;
|
||||
@@ -153,6 +187,9 @@
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a long from the input.
|
||||
/// </summary>
|
||||
public static long ReadLong(IInputBytes bytes)
|
||||
{
|
||||
SkipSpaces(bytes);
|
||||
@@ -175,7 +212,84 @@
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static readonly int MaximumNumberStringLength = long.MaxValue.ToString("D").Length;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given value is a digit or not.
|
||||
/// </summary>
|
||||
public static bool IsDigit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an int from the input.
|
||||
/// </summary>
|
||||
public static int ReadInt(IInputBytes bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bytes));
|
||||
}
|
||||
|
||||
SkipSpaces(bytes);
|
||||
int result;
|
||||
|
||||
var intBuffer = ReadStringNumber(bytes);
|
||||
|
||||
try
|
||||
{
|
||||
result = int.Parse(intBuffer.ToString(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
bytes.Seek(bytes.CurrentOffset - OtherEncodings.StringAsLatin1Bytes(intBuffer.ToString()).Length);
|
||||
|
||||
throw new PdfDocumentFormatException($"Error: Expected an integer type at offset {bytes.CurrentOffset}", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given character is a space.
|
||||
/// </summary>
|
||||
public static bool IsSpace(int c)
|
||||
{
|
||||
return c == ' ';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given character value is a valid hex value.
|
||||
/// </summary>
|
||||
public static bool IsHex(byte b) => IsHex((char) b);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given character value is a valid hex value.
|
||||
/// </summary>
|
||||
public static bool IsHex(char ch)
|
||||
{
|
||||
return char.IsDigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given input bytes are valid UTF8.
|
||||
/// </summary>
|
||||
public static bool IsValidUtf8(byte[] input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var d = Encoding.UTF8.GetDecoder();
|
||||
|
||||
var charLength = d.GetCharCount(input, 0, input.Length);
|
||||
var chars = new char[charLength];
|
||||
d.Convert(input, 0, input.Length, chars, 0, charLength, true, out _, out _, out _);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static StringBuilder ReadStringNumber(IInputBytes reader)
|
||||
{
|
||||
@@ -205,74 +319,6 @@
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will tell if the given value is a digit or not.
|
||||
/// </summary>
|
||||
public static bool IsDigit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
public static int ReadInt(IInputBytes bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bytes));
|
||||
}
|
||||
|
||||
SkipSpaces(bytes);
|
||||
int result;
|
||||
|
||||
var intBuffer = ReadStringNumber(bytes);
|
||||
|
||||
try
|
||||
{
|
||||
result = int.Parse(intBuffer.ToString(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
bytes.Seek(bytes.CurrentOffset - OtherEncodings.StringAsLatin1Bytes(intBuffer.ToString()).Length);
|
||||
|
||||
throw new PdfDocumentFormatException($"Error: Expected an integer type at offset {bytes.CurrentOffset}", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will tell if the given value is a space or not.
|
||||
*
|
||||
* @param c The character to check against space
|
||||
* @return true if the next byte in the stream is a space character.
|
||||
*/
|
||||
public static bool IsSpace(int c)
|
||||
{
|
||||
return ' ' == c;
|
||||
}
|
||||
|
||||
public static bool IsHex(byte b) => IsHex((char) b);
|
||||
public static bool IsHex(char ch)
|
||||
{
|
||||
return char.IsDigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
|
||||
}
|
||||
|
||||
public static bool IsValidUtf8(byte[] input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var d = Encoding.UTF8.GetDecoder();
|
||||
|
||||
var charLength = d.GetCharCount(input, 0, input.Length);
|
||||
var chars = new char[charLength];
|
||||
d.Convert(input, 0, input.Length, chars, 0, charLength, true, out _, out _, out _);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
namespace UglyToad.PdfPig.IO
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
internal class StreamInputBytes : IInputBytes
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Input bytes from a stream.
|
||||
/// </summary>
|
||||
public class StreamInputBytes : IInputBytes
|
||||
{
|
||||
private readonly Stream stream;
|
||||
private readonly bool shouldDispose;
|
||||
|
||||
private bool isAtEnd;
|
||||
|
||||
/// <inheritdoc />
|
||||
public long CurrentOffset => stream.Position;
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte CurrentByte { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public long Length => stream.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StreamInputBytes"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to use, should be readable and seekable.</param>
|
||||
/// <param name="shouldDispose">Whether this class should dispose the stream once finished.</param>
|
||||
public StreamInputBytes(Stream stream, bool shouldDispose = true)
|
||||
{
|
||||
if (stream == null)
|
||||
@@ -37,6 +49,7 @@
|
||||
this.shouldDispose = shouldDispose;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool MoveNext()
|
||||
{
|
||||
var b = stream.ReadByte();
|
||||
@@ -52,6 +65,7 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte? Peek()
|
||||
{
|
||||
var current = CurrentOffset;
|
||||
@@ -68,11 +82,13 @@
|
||||
return (byte)b;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAtEnd()
|
||||
{
|
||||
return isAtEnd;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Seek(long position)
|
||||
{
|
||||
isAtEnd = false;
|
||||
@@ -89,6 +105,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Read(byte[] buffer, int? length = null)
|
||||
{
|
||||
var bytesToRead = buffer.Length;
|
||||
@@ -123,6 +140,7 @@
|
||||
return read;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (shouldDispose)
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the conversion from the transformed coordinate space to the original untransformed coordinate space.
|
||||
@@ -190,20 +189,6 @@
|
||||
return xt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform a vector using this transformation matrix.
|
||||
/// </summary>
|
||||
/// <param name="original">The original vector.</param>
|
||||
/// <returns>A new vector which is the result of applying this transformation matrix.</returns>
|
||||
[Pure]
|
||||
internal PdfVector Transform(PdfVector original)
|
||||
{
|
||||
var x = A * original.X + C * original.Y + E;
|
||||
var y = B * original.X + D * original.Y + F;
|
||||
|
||||
return new PdfVector(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform a rectangle using this transformation matrix.
|
||||
/// </summary>
|
||||
17
src/UglyToad.PdfPig.Core/UglyToad.PdfPig.Core.csproj
Normal file
17
src/UglyToad.PdfPig.Core/UglyToad.PdfPig.Core.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net45;net451;net452;net46;net461;net462;net47</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<DocumentationFile>obj\Debug\netstandard2.0\UglyToad.PdfPig.Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net45' OR '$(TargetFramework)'=='net451' OR '$(TargetFramework)'=='net452' OR '$(TargetFramework)'=='net46' OR '$(TargetFramework)'=='net461' OR '$(TargetFramework)'=='net462' OR '$(TargetFramework)'=='net47'">
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,75 +1,114 @@
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace UglyToad.PdfPig.Util
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal abstract class Union<A, B>
|
||||
/// <summary>
|
||||
/// Defines a type which is a union of two types.
|
||||
/// </summary>
|
||||
public abstract class Union<A, B>
|
||||
{
|
||||
/// <summary>
|
||||
/// Take an action for the item of the given type.
|
||||
/// </summary>
|
||||
public abstract void Match(Action<A> first, Action<B> second);
|
||||
|
||||
/// <summary>
|
||||
/// Run a func against the item of the given type.
|
||||
/// </summary>
|
||||
public abstract TResult Match<TResult>(Func<A, TResult> first, Func<B, TResult> second);
|
||||
|
||||
private Union() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a value of the first type.
|
||||
/// </summary>
|
||||
public static Case1 One(A item)
|
||||
{
|
||||
return new Case1(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a value of the second type.
|
||||
/// </summary>
|
||||
public static Case2 Two(B item)
|
||||
{
|
||||
return new Case2(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type representing items of the first type in a union.
|
||||
/// </summary>
|
||||
public sealed class Case1 : Union<A, B>
|
||||
{
|
||||
/// <summary>
|
||||
/// The item.
|
||||
/// </summary>
|
||||
public readonly A Item;
|
||||
|
||||
/// <summary>
|
||||
/// Create first type.
|
||||
/// </summary>
|
||||
public Case1(A item)
|
||||
{
|
||||
Item = item;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DebuggerStepThrough]
|
||||
public override void Match(Action<A> first, Action<B> second)
|
||||
{
|
||||
first(Item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DebuggerStepThrough]
|
||||
public override TResult Match<TResult>(Func<A, TResult> first, Func<B, TResult> second)
|
||||
{
|
||||
return first(Item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Item?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type representing items of the second type in a union.
|
||||
/// </summary>
|
||||
public sealed class Case2 : Union<A, B>
|
||||
{
|
||||
/// <summary>
|
||||
/// The item.
|
||||
/// </summary>
|
||||
public readonly B Item;
|
||||
|
||||
/// <summary>
|
||||
/// Create second type.
|
||||
/// </summary>
|
||||
public Case2(B item)
|
||||
{
|
||||
Item = item;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DebuggerStepThrough]
|
||||
public override void Match(Action<A> first, Action<B> second)
|
||||
{
|
||||
second(Item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DebuggerStepThrough]
|
||||
public override TResult Match<TResult>(Func<A, TResult> first, Func<B, TResult> second)
|
||||
{
|
||||
return second(Item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Item?.ToString() ?? string.Empty;
|
||||
@@ -1,10 +1,19 @@
|
||||
namespace UglyToad.PdfPig.Util
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
internal static class WritingExtensions
|
||||
/// <summary>
|
||||
/// Handles writing specified data types to an output stream in a valid PDF compliant format.
|
||||
/// </summary>
|
||||
public static class WritingExtensions
|
||||
{
|
||||
public static void WriteUInt(this Stream stream, long value) => WriteUInt(stream, (uint) value);
|
||||
/// <summary>
|
||||
/// Write the <see langword="long"/> to the stream as a <see langword="uint"/>.
|
||||
/// </summary>
|
||||
public static void WriteUInt(this Stream stream, long value) => WriteUInt(stream, (uint)value);
|
||||
/// <summary>
|
||||
/// Write the <see langword="uint"/> to the stream as a <see langword="uint"/>.
|
||||
/// </summary>
|
||||
public static void WriteUInt(this Stream stream, uint value)
|
||||
{
|
||||
var buffer = new[]
|
||||
@@ -18,7 +27,13 @@
|
||||
stream.Write(buffer, 0, 4);
|
||||
}
|
||||
|
||||
public static void WriteUShort(this Stream stream, int value) => WriteUShort(stream, (ushort) value);
|
||||
/// <summary>
|
||||
/// Write the <see langword="int"/> to the stream as a <see langword="ushort"/>.
|
||||
/// </summary>
|
||||
public static void WriteUShort(this Stream stream, int value) => WriteUShort(stream, (ushort)value);
|
||||
/// <summary>
|
||||
/// Write the <see langword="ushort"/> to the stream as a <see langword="ushort"/>.
|
||||
/// </summary>
|
||||
public static void WriteUShort(this Stream stream, ushort value)
|
||||
{
|
||||
var buffer = new[]
|
||||
@@ -30,7 +45,13 @@
|
||||
stream.Write(buffer, 0, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the <see langword="ushort"/> to the stream as a <see langword="short"/>.
|
||||
/// </summary>
|
||||
public static void WriteShort(this Stream stream, ushort value) => WriteShort(stream, (short)value);
|
||||
/// <summary>
|
||||
/// Write the <see langword="short"/> to the stream as a <see langword="short"/>.
|
||||
/// </summary>
|
||||
public static void WriteShort(this Stream stream, short value)
|
||||
{
|
||||
var buffer = new[]
|
||||
226
src/UglyToad.PdfPig.Fonts/AdobeFontMetrics/AdobeFontMetrics.cs
Normal file
226
src/UglyToad.PdfPig.Fonts/AdobeFontMetrics/AdobeFontMetrics.cs
Normal file
@@ -0,0 +1,226 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// The global metrics for a font program and the metrics of each character.
|
||||
/// </summary>
|
||||
public class AdobeFontMetrics
|
||||
{
|
||||
/// <summary>
|
||||
/// Version of the Adobe Font Metrics specification used to generate this file.
|
||||
/// </summary>
|
||||
public decimal AfmVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Any comments in the file.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> Comments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The writing directions described by these metrics.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsWritingDirections MetricSets { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Font name.
|
||||
/// </summary>
|
||||
public string FontName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Font full name.
|
||||
/// </summary>
|
||||
public string FullName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Font family name.
|
||||
/// </summary>
|
||||
public string FamilyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Font weight.
|
||||
/// </summary>
|
||||
public string Weight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum bounding box for all characters in the font.
|
||||
/// </summary>
|
||||
public PdfRectangle BoundingBox { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Font program version identifier.
|
||||
/// </summary>
|
||||
public string Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Font name trademark or copyright notice.
|
||||
/// </summary>
|
||||
public string Notice { get; }
|
||||
|
||||
/// <summary>
|
||||
/// String indicating the default encoding vector for this font program.
|
||||
/// Common ones are AdobeStandardEncoding and JIS12-88-CFEncoding.
|
||||
/// Special font programs might state FontSpecific.
|
||||
/// </summary>
|
||||
public string EncodingScheme { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Describes the mapping scheme.
|
||||
/// </summary>
|
||||
public int MappingScheme { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The bytes value of the escape-character used if this font is escape-mapped.
|
||||
/// </summary>
|
||||
public int EscapeCharacter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Describes the character set of this font.
|
||||
/// </summary>
|
||||
public string CharacterSet { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of characters in this font.
|
||||
/// </summary>
|
||||
public int Characters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this is a base font.
|
||||
/// </summary>
|
||||
public bool IsBaseFont { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A vector from the origin of writing direction 0 to direction 1.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsVector VVector { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether <see cref="VVector"/> is the same for every character in this font.
|
||||
/// </summary>
|
||||
public bool IsFixedV { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Usually the y-value of the top of capital 'H'.
|
||||
/// </summary>
|
||||
public decimal CapHeight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Usually the y-value of the top of lowercase 'x'.
|
||||
/// </summary>
|
||||
public decimal XHeight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Usually the y-value of the top of lowercase 'd'.
|
||||
/// </summary>
|
||||
public decimal Ascender { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Usually the y-value of the bottom of lowercase 'p'.
|
||||
/// </summary>
|
||||
public decimal Descender { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Distance from the baseline for underlining.
|
||||
/// </summary>
|
||||
public decimal UnderlinePosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the line for underlining.
|
||||
/// </summary>
|
||||
public decimal UnderlineThickness { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Angle in degrees counter-clockwise from the vertical of the vertical linea.
|
||||
/// Zero for non-italic fonts.
|
||||
/// </summary>
|
||||
public decimal ItalicAngle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If present all characters have this width and height.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsCharacterSize CharacterWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal stem width.
|
||||
/// </summary>
|
||||
public decimal HorizontalStemWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Vertical stem width.
|
||||
/// </summary>
|
||||
public decimal VerticalStemWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Metrics for the individual characters.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, AdobeFontMetricsIndividualCharacterMetric> CharacterMetrics { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AdobeFontMetrics"/>.
|
||||
/// </summary>
|
||||
public AdobeFontMetrics(decimal afmVersion, IReadOnlyList<string> comments, int metricSets, string fontName,
|
||||
string fullName,
|
||||
string familyName,
|
||||
string weight,
|
||||
PdfRectangle boundingBox,
|
||||
string version,
|
||||
string notice,
|
||||
string encodingScheme,
|
||||
int mappingScheme,
|
||||
int escapeCharacter,
|
||||
string characterSet,
|
||||
int characters,
|
||||
bool isBaseFont,
|
||||
AdobeFontMetricsVector vVector,
|
||||
bool isFixedV,
|
||||
decimal capHeight,
|
||||
decimal xHeight,
|
||||
decimal ascender,
|
||||
decimal descender,
|
||||
decimal underlinePosition,
|
||||
decimal underlineThickness,
|
||||
decimal italicAngle,
|
||||
AdobeFontMetricsCharacterSize characterWidth,
|
||||
decimal horizontalStemWidth,
|
||||
decimal verticalStemWidth,
|
||||
IReadOnlyDictionary<string, AdobeFontMetricsIndividualCharacterMetric> characterMetrics)
|
||||
{
|
||||
AfmVersion = afmVersion;
|
||||
Comments = comments;
|
||||
MetricSets = (AdobeFontMetricsWritingDirections)metricSets;
|
||||
FontName = fontName;
|
||||
FullName = fullName;
|
||||
FamilyName = familyName;
|
||||
Weight = weight;
|
||||
BoundingBox = boundingBox;
|
||||
Version = version;
|
||||
Notice = notice;
|
||||
EncodingScheme = encodingScheme;
|
||||
MappingScheme = mappingScheme;
|
||||
EscapeCharacter = escapeCharacter;
|
||||
CharacterSet = characterSet;
|
||||
Characters = characters;
|
||||
IsBaseFont = isBaseFont;
|
||||
VVector = vVector;
|
||||
IsFixedV = isFixedV;
|
||||
CapHeight = capHeight;
|
||||
XHeight = xHeight;
|
||||
Ascender = ascender;
|
||||
Descender = descender;
|
||||
UnderlinePosition = underlinePosition;
|
||||
UnderlineThickness = underlineThickness;
|
||||
ItalicAngle = italicAngle;
|
||||
CharacterWidth = characterWidth;
|
||||
HorizontalStemWidth = horizontalStemWidth;
|
||||
VerticalStemWidth = verticalStemWidth;
|
||||
CharacterMetrics = characterMetrics;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"AFM Font {FontName ?? FullName} with {Characters} characters.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
namespace UglyToad.PdfPig.Fonts
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Geometry;
|
||||
using Core;
|
||||
using Standard14Fonts;
|
||||
|
||||
internal class FontMetricsBuilder
|
||||
internal class AdobeFontMetricsBuilder
|
||||
{
|
||||
public decimal AfmVersion { get; }
|
||||
|
||||
public List<string> Comments { get; }
|
||||
|
||||
public List<IndividualCharacterMetric> CharacterMetrics { get; } = new List<IndividualCharacterMetric>();
|
||||
public List<AdobeFontMetricsIndividualCharacterMetric> CharacterMetrics { get; }
|
||||
= new List<AdobeFontMetricsIndividualCharacterMetric>();
|
||||
|
||||
/// <summary>
|
||||
/// Name of the font as seen by PostScript.
|
||||
@@ -113,15 +115,15 @@
|
||||
|
||||
public int EscapeCharacter { get; set; }
|
||||
|
||||
public CharacterWidth CharacterWidth { get; private set; }
|
||||
public AdobeFontMetricsCharacterSize CharacterWidth { get; private set; }
|
||||
|
||||
public int Characters { get; set; }
|
||||
|
||||
public PdfVector VVector { get; private set; }
|
||||
public AdobeFontMetricsVector VVector { get; private set; }
|
||||
|
||||
public bool IsFixedV { get; set; }
|
||||
|
||||
public FontMetricsBuilder(decimal afmVersion)
|
||||
public AdobeFontMetricsBuilder(decimal afmVersion)
|
||||
{
|
||||
AfmVersion = afmVersion;
|
||||
Comments = new List<string>();
|
||||
@@ -134,19 +136,19 @@
|
||||
|
||||
public void SetCharacterWidth(double x, double y)
|
||||
{
|
||||
CharacterWidth = new CharacterWidth(x, y);
|
||||
CharacterWidth = new AdobeFontMetricsCharacterSize(x, y);
|
||||
}
|
||||
|
||||
public void SetVVector(double x, double y)
|
||||
{
|
||||
VVector = new PdfVector(x, y);
|
||||
VVector = new AdobeFontMetricsVector(x, y);
|
||||
}
|
||||
|
||||
public FontMetrics Build()
|
||||
public AdobeFontMetrics Build()
|
||||
{
|
||||
var dictionary = CharacterMetrics.ToDictionary(x => x.Name);
|
||||
|
||||
return new FontMetrics(AfmVersion, Comments, 0, FontName, FullName,
|
||||
return new AdobeFontMetrics(AfmVersion, Comments, 0, FontName, FullName,
|
||||
FamilyName, Weight, PdfBoundingBox, Version, Notice, EncodingScheme,
|
||||
MappingScheme, EscapeCharacter, CharacterSet, Characters, IsBaseFont, VVector,
|
||||
IsFixedV, CapHeight, XHeight, Ascender, Descender, UnderlinePosition, UnderlineThickness,
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
/// <summary>
|
||||
/// The x and y components of the width vector of the font's characters.
|
||||
/// Presence implies that IsFixedPitch is true.
|
||||
/// </summary>
|
||||
public class AdobeFontMetricsCharacterSize
|
||||
{
|
||||
/// <summary>
|
||||
/// The horizontal width.
|
||||
/// </summary>
|
||||
public double X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The vertical width.
|
||||
/// </summary>
|
||||
public double Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AdobeFontMetricsCharacterSize"/>.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsCharacterSize(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{X}, {Y}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// The metrics for an individual character.
|
||||
/// </summary>
|
||||
public class AdobeFontMetricsIndividualCharacterMetric
|
||||
{
|
||||
/// <summary>
|
||||
/// Character code.
|
||||
/// </summary>
|
||||
public int CharacterCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// PostScript language character name.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Width.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsVector Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Width for writing direction 0.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsVector WidthDirection0 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Width for writing direction 1.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsVector WidthDirection1 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Vector from origin of writing direction 1 to origin of writing direction 0.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsVector VVector { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Character bounding box.
|
||||
/// </summary>
|
||||
public PdfRectangle BoundingBox { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ligature information.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsLigature Ligature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AdobeFontMetricsIndividualCharacterMetric"/>.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsIndividualCharacterMetric(int characterCode, string name, AdobeFontMetricsVector width,
|
||||
AdobeFontMetricsVector widthDirection0,
|
||||
AdobeFontMetricsVector widthDirection1,
|
||||
AdobeFontMetricsVector vVector,
|
||||
PdfRectangle boundingBox,
|
||||
AdobeFontMetricsLigature ligature)
|
||||
{
|
||||
CharacterCode = characterCode;
|
||||
Name = name;
|
||||
Width = width;
|
||||
WidthDirection0 = widthDirection0;
|
||||
WidthDirection1 = widthDirection1;
|
||||
VVector = vVector;
|
||||
BoundingBox = boundingBox;
|
||||
Ligature = ligature;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{CharacterCode}] {Name} Width: {Width}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
using Core;
|
||||
|
||||
internal class AdobeFontMetricsIndividualCharacterMetricBuilder
|
||||
{
|
||||
public int CharacterCode { get; set; }
|
||||
|
||||
public double WidthX { get; set; }
|
||||
public double WidthY { get; set; }
|
||||
|
||||
public double WidthXDirection0 { get; set; }
|
||||
public double WidthYDirection0 { get; set; }
|
||||
|
||||
public double WidthXDirection1 { get; set; }
|
||||
public double WidthYDirection1 { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public AdobeFontMetricsVector VVector { get; set; }
|
||||
|
||||
public PdfRectangle BoundingBox { get; set; }
|
||||
|
||||
public AdobeFontMetricsLigature Ligature { get; set; }
|
||||
|
||||
public AdobeFontMetricsIndividualCharacterMetric Build()
|
||||
{
|
||||
return new AdobeFontMetricsIndividualCharacterMetric(CharacterCode, Name, new AdobeFontMetricsVector(WidthX, WidthY),
|
||||
new AdobeFontMetricsVector(WidthXDirection0, WidthYDirection0),
|
||||
new AdobeFontMetricsVector(WidthXDirection1, WidthYDirection1),
|
||||
VVector,
|
||||
BoundingBox,
|
||||
Ligature);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
/// <summary>
|
||||
/// A ligature in an Adobe Font Metrics individual character.
|
||||
/// </summary>
|
||||
public class AdobeFontMetricsLigature
|
||||
{
|
||||
/// <summary>
|
||||
/// The character to join with to form a ligature.
|
||||
/// </summary>
|
||||
public string Successor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current character.
|
||||
/// </summary>
|
||||
public string Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AdobeFontMetricsLigature"/>.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsLigature(string successor, string value)
|
||||
{
|
||||
Successor = successor;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Ligature: {Value} -> Successor: {Successor}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
namespace UglyToad.PdfPig.Fonts.Parser
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Exceptions;
|
||||
using Geometry;
|
||||
using IO;
|
||||
using PdfPig.Parser.Parts;
|
||||
using Core;
|
||||
using Fonts;
|
||||
|
||||
internal class AdobeFontMetricsParser : IAdobeFontMetricsParser
|
||||
internal static class AdobeFontMetricsParser
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a comment in a AFM file.
|
||||
@@ -321,7 +319,7 @@
|
||||
|
||||
private static readonly char[] CharmetricsKeySplit = {' '};
|
||||
|
||||
public FontMetrics Parse(IInputBytes bytes, bool useReducedDataSet)
|
||||
public static AdobeFontMetrics Parse(IInputBytes bytes, bool useReducedDataSet)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
@@ -334,7 +332,7 @@
|
||||
|
||||
var version = ReadDecimal(bytes, stringBuilder);
|
||||
|
||||
var builder = new FontMetricsBuilder(version);
|
||||
var builder = new AdobeFontMetricsBuilder(version);
|
||||
|
||||
while ((token = ReadString(bytes, stringBuilder)) != EndFontMetrics)
|
||||
{
|
||||
@@ -514,13 +512,13 @@
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private static IndividualCharacterMetric ReadCharacterMetric(IInputBytes bytes, StringBuilder stringBuilder)
|
||||
private static AdobeFontMetricsIndividualCharacterMetric ReadCharacterMetric(IInputBytes bytes, StringBuilder stringBuilder)
|
||||
{
|
||||
var line = ReadLine(bytes, stringBuilder);
|
||||
|
||||
var split = line.Split(IndividualCharmetricsSplit, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var metric = new IndividualCharacterMetric();
|
||||
var metric = new AdobeFontMetricsIndividualCharacterMetricBuilder();
|
||||
|
||||
foreach (var s in split)
|
||||
{
|
||||
@@ -590,7 +588,8 @@
|
||||
}
|
||||
case CharmetricsVv:
|
||||
{
|
||||
metric.VVector = new PdfVector(double.Parse(parts[1], CultureInfo.InvariantCulture), double.Parse(parts[2], CultureInfo.InvariantCulture));
|
||||
metric.VVector = new AdobeFontMetricsVector(double.Parse(parts[1], CultureInfo.InvariantCulture),
|
||||
double.Parse(parts[2], CultureInfo.InvariantCulture));
|
||||
break;
|
||||
}
|
||||
case CharmetricsN:
|
||||
@@ -608,7 +607,7 @@
|
||||
}
|
||||
case CharmetricsL:
|
||||
{
|
||||
metric.Ligature = new Ligature(parts[1], parts[2]);
|
||||
metric.Ligature = new AdobeFontMetricsLigature(parts[1], parts[2]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -616,30 +615,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
return metric;
|
||||
return metric.Build();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Ligature
|
||||
{
|
||||
public string Successor { get; }
|
||||
|
||||
public string Value { get; }
|
||||
|
||||
public Ligature(string successor, string value)
|
||||
{
|
||||
Successor = successor;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Ligature: {Value} -> Successor: {Successor}";
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IAdobeFontMetricsParser
|
||||
{
|
||||
FontMetrics Parse(IInputBytes bytes, bool useReducedDataSet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
/// <summary>
|
||||
/// A vector in the Adobe Font Metrics.
|
||||
/// </summary>
|
||||
public struct AdobeFontMetricsVector
|
||||
{
|
||||
/// <summary>
|
||||
/// The x component of the vector.
|
||||
/// </summary>
|
||||
public double X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The y component of the vector.
|
||||
/// </summary>
|
||||
public double Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AdobeFontMetricsVector"/>.
|
||||
/// </summary>
|
||||
public AdobeFontMetricsVector(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{X}, {Y}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace UglyToad.PdfPig.Fonts.AdobeFontMetrics
|
||||
{
|
||||
/// <summary>
|
||||
/// The meaning of the metric sets field.
|
||||
/// </summary>
|
||||
public enum AdobeFontMetricsWritingDirections
|
||||
{
|
||||
/// <summary>
|
||||
/// Writing direction 0 only.
|
||||
/// </summary>
|
||||
Direction0Only = 0,
|
||||
/// <summary>
|
||||
/// Writing direction 1 only.
|
||||
/// </summary>
|
||||
Direction1Only = 1,
|
||||
/// <summary>
|
||||
/// Writing direction 0 and 1.
|
||||
/// </summary>
|
||||
Direction0And1 = 2
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.PdfPig.Fonts.Exceptions
|
||||
namespace UglyToad.PdfPig.Fonts
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace UglyToad.PdfPig.Fonts
|
||||
namespace UglyToad.PdfPig.Fonts.Standard14Fonts
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using IO;
|
||||
using Parser;
|
||||
using Util.JetBrains.Annotations;
|
||||
using AdobeFontMetrics;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// There are 14 special Type 1 fonts which must be available. The list of PostScript names for these is given in the remarks section.
|
||||
@@ -30,13 +29,12 @@
|
||||
/// Helvetica−BoldOblique<br/>
|
||||
/// Courier−BoldOblique
|
||||
/// </remarks>
|
||||
internal static class Standard14
|
||||
public static class Standard14
|
||||
{
|
||||
private static readonly AdobeFontMetricsParser Parser = new AdobeFontMetricsParser();
|
||||
private static readonly HashSet<string> Standard14Names = new HashSet<string>();
|
||||
private static readonly Dictionary<string, string> Standard14Mapping = new Dictionary<string, string>(34);
|
||||
private static readonly Dictionary<string, FontMetrics> Standard14AfmMap = new Dictionary<string, FontMetrics>(34);
|
||||
private static readonly Dictionary<Standard14Font, FontMetrics> Standard14AfmTypeMap = new Dictionary<Standard14Font, FontMetrics>(14);
|
||||
private static readonly Dictionary<string, AdobeFontMetrics> Standard14AfmMap = new Dictionary<string, AdobeFontMetrics>(34);
|
||||
private static readonly Dictionary<Standard14Font, AdobeFontMetrics> Standard14AfmTypeMap = new Dictionary<Standard14Font, AdobeFontMetrics>(14);
|
||||
|
||||
static Standard14()
|
||||
{
|
||||
@@ -99,17 +97,22 @@
|
||||
{
|
||||
var assembly = typeof(Standard14).Assembly;
|
||||
|
||||
var name = $"UglyToad.PdfPig.Resources.AdobeFontMetrics.{afmName}.afm";
|
||||
var name = $"UglyToad.PdfPig.Fonts.Resources.AdobeFontMetrics.{afmName}.afm";
|
||||
|
||||
IInputBytes bytes;
|
||||
using (var memory = new MemoryStream())
|
||||
using (var resource = assembly.GetManifestResourceStream(name))
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find AFM resource with name: {name}.");
|
||||
}
|
||||
|
||||
resource.CopyTo(memory);
|
||||
bytes = new ByteArrayInputBytes(memory.ToArray());
|
||||
}
|
||||
|
||||
Standard14AfmMap[fontName] = Parser.Parse(bytes, true);
|
||||
Standard14AfmMap[fontName] = AdobeFontMetricsParser.Parse(bytes, true);
|
||||
if (type.HasValue)
|
||||
{
|
||||
Standard14AfmTypeMap[type.Value] = Standard14AfmMap[fontName];
|
||||
@@ -120,20 +123,22 @@
|
||||
throw new InvalidOperationException($"Could not load {fontName} from the AFM files.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the Adobe Font Metrics as <see cref="FontMetrics"/> for a font.
|
||||
/// Get the Adobe Font Metrics as <see cref="AdobeFontMetrics"/> for a font.
|
||||
/// If the font is not found this returns <see langword="null"/>.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public static FontMetrics GetAdobeFontMetrics(string baseName)
|
||||
public static AdobeFontMetrics GetAdobeFontMetrics(string baseName)
|
||||
{
|
||||
Standard14AfmMap.TryGetValue(baseName, out var metrics);
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public static FontMetrics GetAdobeFontMetrics(Standard14Font fontType)
|
||||
/// <summary>
|
||||
/// Get the Adobe Font Metrics as <see cref="AdobeFontMetrics"/> for a Standard14 font.
|
||||
/// </summary>
|
||||
public static AdobeFontMetrics GetAdobeFontMetrics(Standard14Font fontType)
|
||||
{
|
||||
return Standard14AfmTypeMap[fontType];
|
||||
}
|
||||
@@ -141,7 +146,6 @@
|
||||
/// <summary>
|
||||
/// Determines if a font with this name is a standard 14 font.
|
||||
/// </summary>
|
||||
[Pure]
|
||||
public static bool IsFontInStandard14(string baseName)
|
||||
{
|
||||
return Standard14Names.Contains(baseName);
|
||||
@@ -150,7 +154,6 @@
|
||||
/// <summary>
|
||||
/// Returns the set of Standard 14 font names, including additional names.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public static HashSet<string> GetNames()
|
||||
{
|
||||
return new HashSet<string>(Standard14Names);
|
||||
@@ -159,7 +162,6 @@
|
||||
/// <summary>
|
||||
/// Get the official Standard 14 name of the actual font which the given font name maps to.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public static string GetMappedFontName(string baseName)
|
||||
{
|
||||
Standard14Mapping.TryGetValue(baseName, out var mappedName);
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.PdfPig.Fonts
|
||||
namespace UglyToad.PdfPig.Fonts.Standard14Fonts
|
||||
{
|
||||
/// <summary>
|
||||
/// The Standard 14 fonts included by default in PDF readers.
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace UglyToad.PdfPig.Fonts.SystemFonts
|
||||
{
|
||||
using TrueType;
|
||||
|
||||
internal interface ISystemFontFinder
|
||||
{
|
||||
TrueTypeFont GetTrueTypeFont(string name);
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,17 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using IO;
|
||||
using Core;
|
||||
using Standard14Fonts;
|
||||
using TrueType;
|
||||
using TrueType.Parser;
|
||||
using Util;
|
||||
|
||||
internal class SystemFontFinder : ISystemFontFinder
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<string, string[]> NameSubstitutes;
|
||||
|
||||
private static readonly object CacheLock = new object();
|
||||
private static readonly Dictionary<string, TrueTypeFontProgram> Cache = new Dictionary<string, TrueTypeFontProgram>(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly Dictionary<string, TrueTypeFont> Cache = new Dictionary<string, TrueTypeFont>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
static SystemFontFinder()
|
||||
{
|
||||
@@ -102,7 +102,7 @@
|
||||
availableFonts = new Lazy<IReadOnlyList<SystemFontRecord>>(() => lister.GetAllFonts().ToList());
|
||||
}
|
||||
|
||||
public TrueTypeFontProgram GetTrueTypeFont(string name)
|
||||
public TrueTypeFont GetTrueTypeFont(string name)
|
||||
{
|
||||
var result = GetTrueTypeFontNamed(name);
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
return EmptyArray<string>.Instance;
|
||||
}
|
||||
|
||||
private TrueTypeFontProgram GetTrueTypeFontNamed(string name)
|
||||
private TrueTypeFont GetTrueTypeFontNamed(string name)
|
||||
{
|
||||
lock (CacheLock)
|
||||
{
|
||||
@@ -200,7 +200,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool TryGetTrueTypeFont(string name, SystemFontRecord record, out TrueTypeFontProgram font)
|
||||
private bool TryGetTrueTypeFont(string name, SystemFontRecord record, out TrueTypeFont font)
|
||||
{
|
||||
font = null;
|
||||
if (record.Type == SystemFontType.TrueType)
|
||||
@@ -216,7 +216,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryReadFile(string fileName, bool readNameFirst, string fontName, out TrueTypeFontProgram font)
|
||||
private bool TryReadFile(string fileName, bool readNameFirst, string fontName, out TrueTypeFont font)
|
||||
{
|
||||
font = null;
|
||||
readFiles.Add(fileName);
|
||||
@@ -2,8 +2,11 @@
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the meaning of the transformation entries for a composite glyph definition.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum CompositeGlyphFlags : ushort
|
||||
public enum CompositeGlyphFlags : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// If set arguments are words, otherwise they are bytes.
|
||||
@@ -1,6 +1,9 @@
|
||||
namespace UglyToad.PdfPig.Geometry
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Glyphs
|
||||
{
|
||||
internal struct PdfMatrix3By2
|
||||
using Core;
|
||||
|
||||
internal struct CompositeTransformMatrix3By2
|
||||
{
|
||||
private readonly double r0c0;
|
||||
private readonly double r0c1;
|
||||
@@ -9,7 +12,7 @@
|
||||
private readonly double r2c0;
|
||||
private readonly double r2c1;
|
||||
|
||||
public PdfMatrix3By2(double r0C0, double r0C1, double r1C0, double r1C1, double r2C0, double r2C1)
|
||||
public CompositeTransformMatrix3By2(double r0C0, double r0C1, double r1C0, double r1C1, double r2C0, double r2C1)
|
||||
{
|
||||
r0c0 = r0C0;
|
||||
r0c1 = r0C1;
|
||||
@@ -19,13 +22,12 @@
|
||||
r2c1 = r2C1;
|
||||
}
|
||||
|
||||
public static PdfMatrix3By2 Identity { get; } = new PdfMatrix3By2(1, 0, 0, 1, 0, 0);
|
||||
public static PdfMatrix3By2 CreateTranslation(PdfVector vector) => new PdfMatrix3By2(1, 0, 0, 1, vector.X, vector.Y);
|
||||
public static PdfMatrix3By2 CreateTranslation(double x, double y) => new PdfMatrix3By2(1, 0, 0, 1, x, y);
|
||||
public static CompositeTransformMatrix3By2 Identity { get; } = new CompositeTransformMatrix3By2(1, 0, 0, 1, 0, 0);
|
||||
public static CompositeTransformMatrix3By2 CreateTranslation(double x, double y) => new CompositeTransformMatrix3By2(1, 0, 0, 1, x, y);
|
||||
|
||||
public PdfMatrix3By2 WithTranslation(double x, double y)
|
||||
public CompositeTransformMatrix3By2 WithTranslation(double x, double y)
|
||||
{
|
||||
return new PdfMatrix3By2(r0c0, r0c1, r1c0, r1c1, x, y);
|
||||
return new CompositeTransformMatrix3By2(r0c0, r0c1, r1c0, r1c1, x, y);
|
||||
}
|
||||
|
||||
public PdfPoint ScaleAndRotate(PdfPoint source)
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Glyphs
|
||||
{
|
||||
using System;
|
||||
using Geometry;
|
||||
using Core;
|
||||
|
||||
internal class Glyph : IGlyphDescription
|
||||
{
|
||||
@@ -99,7 +99,7 @@
|
||||
return endPoints;
|
||||
}
|
||||
|
||||
public IGlyphDescription Transform(PdfMatrix3By2 matrix)
|
||||
public IGlyphDescription Transform(CompositeTransformMatrix3By2 matrix)
|
||||
{
|
||||
var newPoints = new GlyphPoint[Points.Length];
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Glyphs
|
||||
{
|
||||
/// <summary>
|
||||
/// The pair of horizontal metrics for an individual glyph.
|
||||
/// </summary>
|
||||
public struct HorizontalMetric
|
||||
{
|
||||
/// <summary>
|
||||
/// The advance width.
|
||||
/// </summary>
|
||||
public ushort AdvanceWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The left side bearing.
|
||||
/// </summary>
|
||||
public short LeftSideBearing { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="HorizontalMetric"/>.
|
||||
/// </summary>
|
||||
public HorizontalMetric(ushort advanceWidth, short leftSideBearing)
|
||||
{
|
||||
AdvanceWidth = advanceWidth;
|
||||
LeftSideBearing = leftSideBearing;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Width: {AdvanceWidth}. LSB: {LeftSideBearing}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Glyphs
|
||||
{
|
||||
using Geometry;
|
||||
using Core;
|
||||
|
||||
internal interface IGlyphDescription : IMergeableGlyph, ITransformableGlyph
|
||||
{
|
||||
@@ -18,14 +18,4 @@
|
||||
|
||||
IGlyphDescription DeepClone();
|
||||
}
|
||||
|
||||
internal interface IMergeableGlyph
|
||||
{
|
||||
IGlyphDescription Merge(IGlyphDescription glyph);
|
||||
}
|
||||
|
||||
internal interface ITransformableGlyph
|
||||
{
|
||||
IGlyphDescription Transform(PdfMatrix3By2 matrix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Glyphs
|
||||
{
|
||||
internal interface IMergeableGlyph
|
||||
{
|
||||
IGlyphDescription Merge(IGlyphDescription glyph);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Glyphs
|
||||
{
|
||||
internal interface ITransformableGlyph
|
||||
{
|
||||
IGlyphDescription Transform(CompositeTransformMatrix3By2 matrix);
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,11 @@
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the meaning of each coordinate in the simple glyph definition.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum SimpleGlyphFlags : byte
|
||||
public enum SimpleGlyphFlags : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The point is on the curve.
|
||||
@@ -0,0 +1,141 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Names
|
||||
{
|
||||
/// <summary>
|
||||
/// The meaning of the platform specific encoding identifier when the <see cref="TrueTypePlatformIdentifier"/> is <see cref="TrueTypePlatformIdentifier.Macintosh"/>.
|
||||
/// </summary>
|
||||
public enum TrueTypeMacintoshEncodingIdentifier : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Roman.
|
||||
/// </summary>
|
||||
Roman = 0,
|
||||
/// <summary>
|
||||
/// Japanese.
|
||||
/// </summary>
|
||||
Japanese = 1,
|
||||
/// <summary>
|
||||
/// Traditional Chinese.
|
||||
/// </summary>
|
||||
ChineseTraditional = 2,
|
||||
/// <summary>
|
||||
/// Korean.
|
||||
/// </summary>
|
||||
Korean = 3,
|
||||
/// <summary>
|
||||
/// Arabic.
|
||||
/// </summary>
|
||||
Arabic = 5,
|
||||
/// <summary>
|
||||
/// Hebrew.
|
||||
/// </summary>
|
||||
Hebrew = 5,
|
||||
/// <summary>
|
||||
/// Greek.
|
||||
/// </summary>
|
||||
Greek = 6,
|
||||
/// <summary>
|
||||
/// Russian.
|
||||
/// </summary>
|
||||
Russian = 7,
|
||||
/// <summary>
|
||||
/// RSymbol.
|
||||
/// </summary>
|
||||
RSymbol = 8,
|
||||
/// <summary>
|
||||
/// Devanagari.
|
||||
/// </summary>
|
||||
Devanagari = 9,
|
||||
/// <summary>
|
||||
/// Gurmukhi.
|
||||
/// </summary>
|
||||
Gurmukhi = 10,
|
||||
/// <summary>
|
||||
/// Gujarati.
|
||||
/// </summary>
|
||||
Gujarati = 11,
|
||||
/// <summary>
|
||||
/// Oriya.
|
||||
/// </summary>
|
||||
Oriya = 12,
|
||||
/// <summary>
|
||||
/// Bengali.
|
||||
/// </summary>
|
||||
Bengali = 13,
|
||||
/// <summary>
|
||||
/// Tamil.
|
||||
/// </summary>
|
||||
Tamil = 14,
|
||||
/// <summary>
|
||||
/// Telugu.
|
||||
/// </summary>
|
||||
Telugu = 15,
|
||||
/// <summary>
|
||||
/// Kannada.
|
||||
/// </summary>
|
||||
Kannada = 16,
|
||||
/// <summary>
|
||||
/// Malayalam.
|
||||
/// </summary>
|
||||
Malayalam = 17,
|
||||
/// <summary>
|
||||
/// Sinhalese.
|
||||
/// </summary>
|
||||
Sinhalese = 18,
|
||||
/// <summary>
|
||||
/// Burmese.
|
||||
/// </summary>
|
||||
Burmese = 19,
|
||||
/// <summary>
|
||||
/// Khmer.
|
||||
/// </summary>
|
||||
Khmer = 20,
|
||||
/// <summary>
|
||||
/// Thai.
|
||||
/// </summary>
|
||||
Thai = 21,
|
||||
/// <summary>
|
||||
/// Laotian.
|
||||
/// </summary>
|
||||
Laotian = 22,
|
||||
/// <summary>
|
||||
/// Georgian.
|
||||
/// </summary>
|
||||
Georgian = 23,
|
||||
/// <summary>
|
||||
/// Armenian.
|
||||
/// </summary>
|
||||
Armenian = 24,
|
||||
/// <summary>
|
||||
/// Simplified Chinese.
|
||||
/// </summary>
|
||||
ChineseSimplified = 25,
|
||||
/// <summary>
|
||||
/// Tibetan.
|
||||
/// </summary>
|
||||
Tibetan = 26,
|
||||
/// <summary>
|
||||
/// Mongolian.
|
||||
/// </summary>
|
||||
Mongolian = 27,
|
||||
/// <summary>
|
||||
/// Ge'ez.
|
||||
/// </summary>
|
||||
Geez = 28,
|
||||
/// <summary>
|
||||
/// Slavic.
|
||||
/// </summary>
|
||||
Slavic = 29,
|
||||
/// <summary>
|
||||
/// Vietnamese.
|
||||
/// </summary>
|
||||
Vietnamese = 30,
|
||||
/// <summary>
|
||||
/// Sindhi.
|
||||
/// </summary>
|
||||
Sindhi = 31,
|
||||
/// <summary>
|
||||
/// Uninterpreted.
|
||||
/// </summary>
|
||||
Uninterpreted = 32
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Names
|
||||
{
|
||||
/// <summary>
|
||||
/// Uniquely defines the language in which the name character string is written
|
||||
/// for a name record in a name table.
|
||||
/// </summary>
|
||||
public enum TrueTypeMacintoshLanguageIdentifier : ushort
|
||||
{
|
||||
///<summary>English.</summary>
|
||||
English = 0,
|
||||
///<summary>French.</summary>
|
||||
French = 1,
|
||||
///<summary>German.</summary>
|
||||
German = 2,
|
||||
///<summary>Italian.</summary>
|
||||
Italian = 3,
|
||||
///<summary>Dutch.</summary>
|
||||
Dutch = 4,
|
||||
///<summary>Swedish.</summary>
|
||||
Swedish = 5,
|
||||
///<summary>Spanish.</summary>
|
||||
Spanish = 6,
|
||||
///<summary>Danish.</summary>
|
||||
Danish = 7,
|
||||
///<summary>Portuguese.</summary>
|
||||
Portuguese = 8,
|
||||
///<summary>Norwegian.</summary>
|
||||
Norwegian = 9,
|
||||
///<summary>Hebrew.</summary>
|
||||
Hebrew = 10,
|
||||
///<summary>Japanese.</summary>
|
||||
Japanese = 11,
|
||||
///<summary>Arabic.</summary>
|
||||
Arabic = 12,
|
||||
///<summary>Finnish.</summary>
|
||||
Finnish = 13,
|
||||
///<summary>Greek.</summary>
|
||||
Greek = 14,
|
||||
///<summary>Icelandic.</summary>
|
||||
Icelandic = 15,
|
||||
///<summary>Maltese.</summary>
|
||||
Maltese = 16,
|
||||
///<summary>Turkish.</summary>
|
||||
Turkish = 17,
|
||||
///<summary>Croatian.</summary>
|
||||
Croatian = 18,
|
||||
///<summary>Traditional Chinese.</summary>
|
||||
ChineseTraditional = 19,
|
||||
///<summary>Urdu.</summary>
|
||||
Urdu = 20,
|
||||
///<summary>Hindi.</summary>
|
||||
Hindi = 21,
|
||||
///<summary>Thai.</summary>
|
||||
Thai = 22,
|
||||
///<summary>Korean.</summary>
|
||||
Korean = 23,
|
||||
///<summary>Lithuanian.</summary>
|
||||
Lithuanian = 24,
|
||||
///<summary>Polish.</summary>
|
||||
Polish = 25,
|
||||
///<summary>Hungarian.</summary>
|
||||
Hungarian = 26,
|
||||
///<summary>Estonian.</summary>
|
||||
Estonian = 27,
|
||||
///<summary>Latvian.</summary>
|
||||
Latvian = 28,
|
||||
///<summary>Sami.</summary>
|
||||
Sami = 29,
|
||||
///<summary>Faroese.</summary>
|
||||
Faroese = 30,
|
||||
///<summary>Farsi (Persian).</summary>
|
||||
FarsiPersian = 31,
|
||||
///<summary>Russian.</summary>
|
||||
Russian = 32,
|
||||
///<summary>Simplified Chinese.</summary>
|
||||
ChineseSimplified = 33,
|
||||
///<summary>Flemish.</summary>
|
||||
Flemish = 34,
|
||||
///<summary>Irish Gaelic.</summary>
|
||||
IrishGaelic = 35,
|
||||
///<summary>Albanian.</summary>
|
||||
Albanian = 36,
|
||||
///<summary>Romanian.</summary>
|
||||
Romanian = 37,
|
||||
///<summary>Czech.</summary>
|
||||
Czech = 38,
|
||||
///<summary>Slovak.</summary>
|
||||
Slovak = 39,
|
||||
///<summary>Slovenian.</summary>
|
||||
Slovenian = 40,
|
||||
///<summary>Yiddish.</summary>
|
||||
Yiddish = 41,
|
||||
///<summary>Serbian.</summary>
|
||||
Serbian = 42,
|
||||
///<summary>Macedonian.</summary>
|
||||
Macedonian = 43,
|
||||
///<summary>Bulgarian.</summary>
|
||||
Bulgarian = 44,
|
||||
///<summary>Ukrainian.</summary>
|
||||
Ukrainian = 45,
|
||||
///<summary>Byelorussian.</summary>
|
||||
Byelorussian = 46,
|
||||
///<summary>Uzbek.</summary>
|
||||
Uzbek = 47,
|
||||
///<summary>Kazakh.</summary>
|
||||
Kazakh = 48,
|
||||
///<summary>Azerbaijani (Cyrillic).</summary>
|
||||
AzerbaijaniCyrillic = 49,
|
||||
///<summary>Azerbaijani (Arabic).</summary>
|
||||
AzerbaijaniArabic = 50,
|
||||
///<summary>Armenian.</summary>
|
||||
Armenian = 51,
|
||||
///<summary>Georgian.</summary>
|
||||
Georgian = 52,
|
||||
///<summary>Moldavian.</summary>
|
||||
Moldavian = 53,
|
||||
///<summary>Kirghiz.</summary>
|
||||
Kirghiz = 54,
|
||||
///<summary>Tajiki.</summary>
|
||||
Tajiki = 55,
|
||||
///<summary>Turkmen.</summary>
|
||||
Turkmen = 56,
|
||||
///<summary>Mongolian.</summary>
|
||||
Mongolian = 57,
|
||||
///<summary>Mongolian (Cyrillic).</summary>
|
||||
MongolianCyrillic = 58,
|
||||
///<summary>Pashto.</summary>
|
||||
Pashto = 59,
|
||||
///<summary>Kurdish.</summary>
|
||||
Kurdish = 60,
|
||||
///<summary>Kashmiri.</summary>
|
||||
Kashmiri = 61,
|
||||
///<summary>Sindhi.</summary>
|
||||
Sindhi = 62,
|
||||
///<summary>Tibetan.</summary>
|
||||
Tibetan = 63,
|
||||
///<summary>Nepali.</summary>
|
||||
Nepali = 64,
|
||||
///<summary>Sanskrit.</summary>
|
||||
Sanskrit = 65,
|
||||
///<summary>Marathi.</summary>
|
||||
Marathi = 66,
|
||||
///<summary>Bengali.</summary>
|
||||
Bengali = 67,
|
||||
///<summary>Assamese.</summary>
|
||||
Assamese = 68,
|
||||
///<summary>Gujarati.</summary>
|
||||
Gujarati = 69,
|
||||
///<summary>Punjabi.</summary>
|
||||
Punjabi = 70,
|
||||
///<summary>Oriya.</summary>
|
||||
Oriya = 71,
|
||||
///<summary>Malayalam.</summary>
|
||||
Malayalam = 72,
|
||||
///<summary>Kannada.</summary>
|
||||
Kannada = 73,
|
||||
///<summary>Tamil.</summary>
|
||||
Tamil = 74,
|
||||
///<summary>Telugu.</summary>
|
||||
Telugu = 75,
|
||||
///<summary>Sinhalese.</summary>
|
||||
Sinhalese = 76,
|
||||
///<summary>Burmese.</summary>
|
||||
Burmese = 77,
|
||||
///<summary>Khmer.</summary>
|
||||
Khmer = 78,
|
||||
///<summary>Lao.</summary>
|
||||
Lao = 79,
|
||||
///<summary>Vietnamese.</summary>
|
||||
Vietnamese = 80,
|
||||
///<summary>Indonesian.</summary>
|
||||
Indonesian = 81,
|
||||
///<summary>Tagalog.</summary>
|
||||
Tagalog = 82,
|
||||
///<summary>Malay (Roman).</summary>
|
||||
MalayRoman = 83,
|
||||
///<summary>Malay (Arabic).</summary>
|
||||
MalayArabic = 84,
|
||||
///<summary>Amharic.</summary>
|
||||
Amharic = 85,
|
||||
///<summary>Tigrinya.</summary>
|
||||
Tigrinya = 86,
|
||||
///<summary>Galla.</summary>
|
||||
Galla = 87,
|
||||
///<summary>Somali.</summary>
|
||||
Somali = 88,
|
||||
///<summary>Swahili.</summary>
|
||||
Swahili = 89,
|
||||
///<summary>Kinyarwanda Ruanda.</summary>
|
||||
KinyarwandaRuanda = 90,
|
||||
///<summary>Rundi.</summary>
|
||||
Rundi = 91,
|
||||
///<summary>NyanjaChewa.</summary>
|
||||
NyanjaChewa = 92,
|
||||
///<summary>Malagasy.</summary>
|
||||
Malagasy = 93,
|
||||
///<summary>Esperanto.</summary>
|
||||
Esperanto = 94,
|
||||
///<summary>Welsh.</summary>
|
||||
Welsh = 128,
|
||||
///<summary>Basque.</summary>
|
||||
Basque = 129,
|
||||
///<summary>Catalan.</summary>
|
||||
Catalan = 130,
|
||||
///<summary>Latin.</summary>
|
||||
Latin = 131,
|
||||
///<summary>Quechua.</summary>
|
||||
Quechua = 132,
|
||||
///<summary>Guarani.</summary>
|
||||
Guarani = 133,
|
||||
///<summary>Aymara.</summary>
|
||||
Aymara = 134,
|
||||
///<summary>Tatar.</summary>
|
||||
Tatar = 135,
|
||||
///<summary>Uighur.</summary>
|
||||
Uighur = 136,
|
||||
///<summary>Dzongkha.</summary>
|
||||
Dzongkha = 137,
|
||||
///<summary>Javanese (Roman).</summary>
|
||||
JavaneseRoman = 138,
|
||||
///<summary>Sundanese (Roman).</summary>
|
||||
SundaneseRoman = 139,
|
||||
///<summary>Galician.</summary>
|
||||
Galician = 140,
|
||||
///<summary>Afrikaans.</summary>
|
||||
Afrikaans = 141,
|
||||
///<summary>Breton.</summary>
|
||||
Breton = 142,
|
||||
///<summary>Inuktitut.</summary>
|
||||
Inuktitut = 143,
|
||||
///<summary>Scottish Gaelic.</summary>
|
||||
ScottishGaelic = 144,
|
||||
///<summary>Manx Gaelic.</summary>
|
||||
ManxGaelic = 145,
|
||||
///<summary>Irish Gaelic With Dot Above.</summary>
|
||||
IrishGaelicWithDotAbove = 146,
|
||||
///<summary>Tongan.</summary>
|
||||
Tongan = 147,
|
||||
///<summary>Greek Polytonic.</summary>
|
||||
GreekPolytonic = 148,
|
||||
///<summary>Greenlandic.</summary>
|
||||
Greenlandic = 149,
|
||||
///<summary>Azerbaijani (Roman).</summary>
|
||||
AzerbaijaniRoman = 150
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Names
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// A record in a TrueType font which is a human-readable name for
|
||||
/// a feature, setting, copyright notice, font name or other font related
|
||||
/// information.
|
||||
/// </summary>
|
||||
public class TrueTypeNameRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// The supported platform identifier.
|
||||
/// </summary>
|
||||
public TrueTypePlatformIdentifier PlatformId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The platform specific encoding id. Interpretation depends on the value of the <see cref="PlatformId"/>.
|
||||
/// </summary>
|
||||
public ushort PlatformEncodingId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The language id uniquely defines the language in which the string is written for this record.
|
||||
/// </summary>
|
||||
public ushort LanguageId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to reference this record by other tables in the font.
|
||||
/// </summary>
|
||||
public ushort NameId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of this record.
|
||||
/// </summary>
|
||||
public string Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TrueTypeNameRecord"/>.
|
||||
/// </summary>
|
||||
public TrueTypeNameRecord(TrueTypePlatformIdentifier platformId,
|
||||
ushort platformEncodingId,
|
||||
ushort languageId,
|
||||
ushort nameId,
|
||||
string value)
|
||||
{
|
||||
PlatformId = platformId;
|
||||
PlatformEncodingId = platformEncodingId;
|
||||
LanguageId = languageId;
|
||||
NameId = nameId;
|
||||
Value = value ?? throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"(Platform: {PlatformId}, Id: {NameId}) - {Value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// The platform identifier for a TrueType/OpenType font allows for platform specific implementations.
|
||||
/// </summary>
|
||||
internal enum TrueTypePlatformIdentifier
|
||||
public enum TrueTypePlatformIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Unicode
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// The meaning of the platform specific encoding when the <see cref="TrueTypePlatformIdentifier"/> is <see cref="TrueTypePlatformIdentifier.Unicode"/>.
|
||||
/// </summary>
|
||||
internal enum TrueTypeUnicodeEncodingIndentifier
|
||||
public enum TrueTypeUnicodeEncodingIndentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Default semantics.
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// The meaning of the platform specific encoding when the <see cref="TrueTypePlatformIdentifier"/> is <see cref="TrueTypePlatformIdentifier.Windows"/>.
|
||||
/// </summary>
|
||||
internal enum TrueTypeWindowsEncodingIdentifier
|
||||
public enum TrueTypeWindowsEncodingIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Symbol.
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var subTableHeaders = new SubTableHeaderEntry[numberOfEncodingTables];
|
||||
|
||||
for (int i = 0; i < numberOfEncodingTables; i++)
|
||||
for (var i = 0; i < numberOfEncodingTables; i++)
|
||||
{
|
||||
var platformId = (TrueTypeCMapPlatform)data.ReadUnsignedShort();
|
||||
var encodingId = data.ReadUnsignedShort();
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Parser
|
||||
{
|
||||
using Glyphs;
|
||||
using Tables;
|
||||
|
||||
internal class HorizontalMetricsTableParser : ITrueTypeTableParser<HorizontalMetricsTable>
|
||||
@@ -13,7 +14,7 @@
|
||||
var bytesRead = 0;
|
||||
|
||||
|
||||
var horizontalMetrics = new HorizontalMetricsTable.HorizontalMetric[metricCount];
|
||||
var horizontalMetrics = new HorizontalMetric[metricCount];
|
||||
|
||||
|
||||
for (var i = 0; i < metricCount; i++)
|
||||
@@ -21,7 +22,7 @@
|
||||
var width = data.ReadUnsignedShort();
|
||||
var lsb = data.ReadSignedShort();
|
||||
|
||||
horizontalMetrics[i] = new HorizontalMetricsTable.HorizontalMetric(width, lsb);
|
||||
horizontalMetrics[i] = new HorizontalMetric(width, lsb);
|
||||
|
||||
bytesRead += 4;
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Parser
|
||||
{
|
||||
using System.Text;
|
||||
using Core;
|
||||
using Names;
|
||||
using Tables;
|
||||
using Util;
|
||||
using Util.JetBrains.Annotations;
|
||||
|
||||
internal class NameTableParser : ITrueTypeTableParser<NameTable>
|
||||
{
|
||||
@@ -75,7 +74,6 @@
|
||||
return new NameTable(header, GetName(4, strings), GetName(1, strings), GetName(2, strings), strings);
|
||||
}
|
||||
|
||||
[CanBeNull]
|
||||
private static string GetName(int nameId, TrueTypeNameRecord[] names)
|
||||
{
|
||||
const int windowsEnUs = 409;
|
||||
@@ -27,10 +27,10 @@
|
||||
var yStrikeoutPosition = data.ReadSignedShort();
|
||||
var familyClass = data.ReadSignedShort();
|
||||
var panose = data.ReadByteArray(10);
|
||||
var ulCharRange1 = (uint)data.ReadUnsignedInt();
|
||||
var ulCharRange2 = (uint)data.ReadUnsignedInt();
|
||||
var ulCharRange3 = (uint)data.ReadUnsignedInt();
|
||||
var ulCharRange4 = (uint)data.ReadUnsignedInt();
|
||||
var ulCharRange1 = data.ReadUnsignedInt();
|
||||
var ulCharRange2 = data.ReadUnsignedInt();
|
||||
var ulCharRange3 = data.ReadUnsignedInt();
|
||||
var ulCharRange4 = data.ReadUnsignedInt();
|
||||
var vendorIdBytes = data.ReadByteArray(4);
|
||||
var selectionFlags = data.ReadUnsignedShort();
|
||||
var firstCharacterIndex = data.ReadUnsignedShort();
|
||||
@@ -100,8 +100,8 @@
|
||||
usWinDescent);
|
||||
}
|
||||
|
||||
var ulCodePageRange1 = (uint)data.ReadUnsignedInt();
|
||||
var ulCodePageRange2 = (uint)data.ReadUnsignedInt();
|
||||
var ulCodePageRange1 = data.ReadUnsignedInt();
|
||||
var ulCodePageRange2 = data.ReadUnsignedInt();
|
||||
if (version == 1)
|
||||
{
|
||||
return new Os2Version1Table(header, version, xAvgCharWidth,
|
||||
@@ -2,17 +2,15 @@
|
||||
{
|
||||
using System;
|
||||
using Tables;
|
||||
using Util.JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Holds tables while contained in a TrueType font.
|
||||
/// The set of tables in a TrueType font interpreted by the library.
|
||||
/// </summary>
|
||||
internal class TableRegister
|
||||
{
|
||||
/// <summary>
|
||||
/// This table contains global information about the font.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public HeaderTable HeaderTable { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -23,13 +21,11 @@
|
||||
/// <summary>
|
||||
/// This table contains information needed to layout fonts whose characters are written horizontally.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public HorizontalHeaderTable HorizontalHeaderTable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This table contains metric information for the horizontal layout each of the glyphs in the font.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public HorizontalMetricsTable HorizontalMetricsTable { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -40,10 +36,8 @@
|
||||
/// <summary>
|
||||
/// This table establishes the memory requirements for the font.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public BasicMaximumProfileTable MaximumProfileTable { get; }
|
||||
|
||||
[CanBeNull]
|
||||
public NameTable NameTable { get; }
|
||||
|
||||
public PostScriptTable PostScriptTable { get; }
|
||||
@@ -63,7 +57,7 @@
|
||||
/// Create a new <see cref="TableRegister"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder with necessary tables set.</param>
|
||||
public TableRegister([NotNull] Builder builder)
|
||||
public TableRegister(Builder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
@@ -86,7 +80,7 @@
|
||||
/// <summary>
|
||||
/// Used to gather the necessary tables for a TrueType font.
|
||||
/// </summary>
|
||||
public class Builder
|
||||
internal class Builder
|
||||
{
|
||||
public GlyphDataTable GlyphDataTable { get; set; }
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Exceptions;
|
||||
using Tables;
|
||||
using Util.JetBrains.Annotations;
|
||||
|
||||
internal class TrueTypeFontParser
|
||||
{
|
||||
public TrueTypeFontProgram Parse(TrueTypeDataBytes data)
|
||||
public TrueTypeFont Parse(TrueTypeDataBytes data)
|
||||
{
|
||||
var version = data.Read32Fixed();
|
||||
int numberOfTables = data.ReadUnsignedShort();
|
||||
@@ -37,7 +35,6 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
[CanBeNull]
|
||||
private static TrueTypeHeaderTable? ReadTable(TrueTypeDataBytes data)
|
||||
{
|
||||
var tag = data.ReadTag();
|
||||
@@ -51,10 +48,10 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TrueTypeHeaderTable(tag, (uint)checksum, (uint)offset, (uint)length);
|
||||
return new TrueTypeHeaderTable(tag, checksum, offset, length);
|
||||
}
|
||||
|
||||
private static TrueTypeFontProgram ParseTables(float version, IReadOnlyDictionary<string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data)
|
||||
private static TrueTypeFont ParseTables(float version, IReadOnlyDictionary<string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data)
|
||||
{
|
||||
var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff);
|
||||
|
||||
@@ -122,7 +119,7 @@
|
||||
OptionallyParseTables(tables, data, builder);
|
||||
}
|
||||
|
||||
return new TrueTypeFontProgram(version, tables, builder.Build());
|
||||
return new TrueTypeFont(version, tables, builder.Build());
|
||||
}
|
||||
|
||||
public NameTable GetNameTable(TrueTypeDataBytes data)
|
||||
@@ -1,13 +1,11 @@
|
||||
namespace UglyToad.PdfPig.Writer.Fonts.Subsetting
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Subsetting
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using PdfPig.Fonts.Exceptions;
|
||||
using PdfPig.Fonts.TrueType;
|
||||
using PdfPig.Fonts.TrueType.Glyphs;
|
||||
using PdfPig.Fonts.TrueType.Tables;
|
||||
using Util;
|
||||
using Core;
|
||||
using Glyphs;
|
||||
using TrueType;
|
||||
using IndexMap = TrueTypeSubsetter.OldToNewGlyphIndex;
|
||||
|
||||
/// <summary>
|
||||
@@ -22,7 +20,7 @@
|
||||
/// <param name="fontBytes">The raw bytes of the input font.</param>
|
||||
/// <param name="mapping">The mapping of old glyph indices to new glyph indices.</param>
|
||||
/// <returns>A new glyph table and associated information for use in creating a valid TrueType font file.</returns>
|
||||
public static TrueTypeSubsetGlyphTable SubsetGlyphTable(TrueTypeFontProgram font, byte[] fontBytes, IndexMap[] mapping)
|
||||
public static TrueTypeSubsetGlyphTable SubsetGlyphTable(TrueTypeFont font, byte[] fontBytes, IndexMap[] mapping)
|
||||
{
|
||||
if (font == null)
|
||||
{
|
||||
@@ -63,7 +61,7 @@
|
||||
}
|
||||
|
||||
var glyphLocations = new List<uint>();
|
||||
var advanceWidths = new List<HorizontalMetricsTable.HorizontalMetric>();
|
||||
var advanceWidths = new List<HorizontalMetric>();
|
||||
|
||||
var compositeIndicesToReplace = new List<(uint offset, ushort newIndex)>();
|
||||
|
||||
@@ -146,7 +144,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static GlyphRecord[] GetGlyphRecordsInFont(TrueTypeFontProgram font, TrueTypeDataBytes data)
|
||||
private static GlyphRecord[] GetGlyphRecordsInFont(TrueTypeFont font, TrueTypeDataBytes data)
|
||||
{
|
||||
var indexToLocationTable = font.TableRegister.IndexToLocationTable;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
namespace UglyToad.PdfPig.Writer.Fonts
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Subsetting
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using IO;
|
||||
using Util;
|
||||
using Core;
|
||||
|
||||
internal class TrueTypeOffsetSubtable : IWriteable
|
||||
{
|
||||
private static readonly byte[] VersionHeader = { 0, 1, 0, 0 };
|
||||
|
||||
private readonly byte numberOfTables;
|
||||
|
||||
|
||||
public TrueTypeOffsetSubtable(byte numberOfTables)
|
||||
{
|
||||
this.numberOfTables = numberOfTables;
|
||||
@@ -24,8 +23,8 @@
|
||||
var maximumPowerOf2 = GetHighestPowerOf2(numberOfTables);
|
||||
var searchRange = (ushort)(maximumPowerOf2 * 16);
|
||||
var entrySelector = (ushort)Math.Log(maximumPowerOf2, 2);
|
||||
var rangeShift = (ushort) ((numberOfTables * 16) - searchRange);
|
||||
|
||||
var rangeShift = (ushort)((numberOfTables * 16) - searchRange);
|
||||
|
||||
stream.WriteUShort(searchRange);
|
||||
stream.WriteUShort(entrySelector);
|
||||
stream.WriteUShort(rangeShift);
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.PdfPig.Writer.Fonts.Subsetting
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Subsetting
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Writer.Fonts.Subsetting
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Subsetting
|
||||
{
|
||||
using System;
|
||||
using PdfPig.Fonts.TrueType.Tables;
|
||||
using Glyphs;
|
||||
|
||||
/// <summary>
|
||||
/// Details of the new glyph 'glyf' table created when subsetting a TrueType font.
|
||||
@@ -21,7 +21,7 @@
|
||||
/// <summary>
|
||||
/// The corresponding horizontal metrics for each glyph.
|
||||
/// </summary>
|
||||
public HorizontalMetricsTable.HorizontalMetric[] HorizontalMetrics { get; }
|
||||
public HorizontalMetric[] HorizontalMetrics { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of glyphs in the new table.
|
||||
@@ -31,7 +31,7 @@
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TrueTypeSubsetGlyphTable"/>.
|
||||
/// </summary>
|
||||
public TrueTypeSubsetGlyphTable(byte[] bytes, uint[] glyphOffsets, HorizontalMetricsTable.HorizontalMetric[] horizontalMetrics)
|
||||
public TrueTypeSubsetGlyphTable(byte[] bytes, uint[] glyphOffsets, HorizontalMetric[] horizontalMetrics)
|
||||
{
|
||||
Bytes = bytes ?? throw new ArgumentNullException(nameof(bytes));
|
||||
GlyphOffsets = glyphOffsets ?? throw new ArgumentNullException(nameof(glyphOffsets));
|
||||
@@ -1,15 +1,13 @@
|
||||
namespace UglyToad.PdfPig.Writer.Fonts.Subsetting
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Subsetting
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using IO;
|
||||
using PdfPig.Fonts.Exceptions;
|
||||
using PdfPig.Fonts.TrueType;
|
||||
using PdfPig.Fonts.TrueType.Parser;
|
||||
using PdfPig.Fonts.TrueType.Tables;
|
||||
using PdfPig.Fonts.TrueType.Tables.CMapSubTables;
|
||||
using Util;
|
||||
using Core;
|
||||
using Parser;
|
||||
using Tables;
|
||||
using Tables.CMapSubTables;
|
||||
using TrueType;
|
||||
|
||||
internal static class TrueTypeSubsetter
|
||||
{
|
||||
@@ -212,7 +210,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static OldToNewGlyphIndex[] GetIndexMapping(TrueTypeFontProgram font, TrueTypeSubsetEncoding newEncoding)
|
||||
private static OldToNewGlyphIndex[] GetIndexMapping(TrueTypeFont font, TrueTypeSubsetEncoding newEncoding)
|
||||
{
|
||||
var result = new OldToNewGlyphIndex[newEncoding.Characters.Count + 1];
|
||||
|
||||
@@ -236,7 +234,7 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private static CMapTable GetCMapTable(TrueTypeFontProgram font, DirectoryEntry entry, OldToNewGlyphIndex[] encoding)
|
||||
private static CMapTable GetCMapTable(TrueTypeFont font, DirectoryEntry entry, OldToNewGlyphIndex[] encoding)
|
||||
{
|
||||
var data = new byte[256];
|
||||
for (var i = 0; i < data.Length; i++)
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
using System.IO;
|
||||
using IO;
|
||||
using Util;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// The format 0 sub-table where character codes and glyph indices are restricted to a single bytes.
|
||||
@@ -5,7 +5,7 @@
|
||||
/// A font which can run on multiple platforms will have multiple encoding tables. These are stored as multiple
|
||||
/// sub-tables. The <see cref="ICMapSubTable"/> represents a single subtotal.
|
||||
/// </summary>
|
||||
internal interface ICMapSubTable
|
||||
public interface ICMapSubTable
|
||||
{
|
||||
/// <summary>
|
||||
/// The platform identifier.
|
||||
@@ -24,27 +24,4 @@
|
||||
/// <returns>The index of the glyph information for this character.</returns>
|
||||
int CharacterCodeToGlyphIndex(int characterCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The platform identifier for a CMap table.
|
||||
/// </summary>
|
||||
internal enum TrueTypeCMapPlatform : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Unicode.
|
||||
/// </summary>
|
||||
Unicode = 0,
|
||||
/// <summary>
|
||||
/// Apple Macintosh.
|
||||
/// </summary>
|
||||
Macintosh = 1,
|
||||
/// <summary>
|
||||
/// Unused.
|
||||
/// </summary>
|
||||
Reserved2 = 2,
|
||||
/// <summary>
|
||||
/// Microsoft Windows.
|
||||
/// </summary>
|
||||
Windows = 3
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,7 @@ namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using IO;
|
||||
using Util;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// A format 6 CMap sub-table which uses 2 bytes to map a contiguous range of character codes to glyph indices.
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.CMapSubTables
|
||||
{
|
||||
/// <summary>
|
||||
/// The platform identifier for a CMap table.
|
||||
/// </summary>
|
||||
public enum TrueTypeCMapPlatform : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Unicode.
|
||||
/// </summary>
|
||||
Unicode = 0,
|
||||
/// <summary>
|
||||
/// Apple Macintosh.
|
||||
/// </summary>
|
||||
Macintosh = 1,
|
||||
/// <summary>
|
||||
/// Unused.
|
||||
/// </summary>
|
||||
Reserved2 = 2,
|
||||
/// <summary>
|
||||
/// Microsoft Windows.
|
||||
/// </summary>
|
||||
Windows = 3
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using CMapSubTables;
|
||||
using IO;
|
||||
using Util;
|
||||
using Core;
|
||||
|
||||
internal class CMapTable : ITrueTypeTable, IWriteable
|
||||
{
|
||||
@@ -2,10 +2,9 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Geometry;
|
||||
using Core;
|
||||
using Glyphs;
|
||||
using Parser;
|
||||
using Util.JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// The 'glyf' table contains the data that defines the appearance of the glyphs in the font.
|
||||
@@ -17,7 +16,6 @@
|
||||
|
||||
public TrueTypeHeaderTable DirectoryTable { get; }
|
||||
|
||||
[ItemCanBeNull]
|
||||
public IReadOnlyList<IGlyphDescription> Glyphs { get; }
|
||||
|
||||
public GlyphDataTable(TrueTypeHeaderTable directoryTable, IReadOnlyList<IGlyphDescription> glyphs)
|
||||
@@ -188,7 +186,7 @@
|
||||
|
||||
if (HasFlag(flags, CompositeGlyphFlags.ArgsAreXAndYValues))
|
||||
{
|
||||
components.Add(new CompositeComponent(glyphIndex, new PdfMatrix3By2(xscale, scale01, scale10, yscale, arg1, arg2)));
|
||||
components.Add(new CompositeComponent(glyphIndex, new CompositeTransformMatrix3By2(xscale, scale01, scale10, yscale, arg1, arg2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -318,9 +316,9 @@
|
||||
{
|
||||
public int Index { get; }
|
||||
|
||||
public PdfMatrix3By2 Transformation { get; }
|
||||
public CompositeTransformMatrix3By2 Transformation { get; }
|
||||
|
||||
public CompositeComponent(int index, PdfMatrix3By2 transformation)
|
||||
public CompositeComponent(int index, CompositeTransformMatrix3By2 transformation)
|
||||
{
|
||||
Index = index;
|
||||
Transformation = transformation;
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
|
||||
{
|
||||
using System;
|
||||
using Geometry;
|
||||
using PdfPig.Exceptions;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// The 'head' table contains global information about the font.
|
||||
@@ -105,7 +104,7 @@
|
||||
{
|
||||
created = data.ReadInternationalDate();
|
||||
}
|
||||
catch (PdfDocumentFormatException)
|
||||
catch (InvalidFontFormatException)
|
||||
{
|
||||
created = DateTime.MinValue;
|
||||
}
|
||||
@@ -115,7 +114,7 @@
|
||||
{
|
||||
modified = data.ReadInternationalDate();
|
||||
}
|
||||
catch (PdfDocumentFormatException)
|
||||
catch (InvalidFontFormatException)
|
||||
{
|
||||
modified = DateTime.MinValue;
|
||||
}
|
||||
@@ -1,19 +1,27 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using IO;
|
||||
using Util;
|
||||
using Core;
|
||||
using Glyphs;
|
||||
|
||||
/// <inheritdoc cref="ITrueTypeTable" />
|
||||
/// <summary>
|
||||
/// The 'hmtx' table contains metric information for the horizontal layout each of the glyphs in the font.
|
||||
/// </summary>
|
||||
internal class HorizontalMetricsTable : ITrueTypeTable, IWriteable
|
||||
public class HorizontalMetricsTable : ITrueTypeTable, IWriteable
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Tag => TrueTypeHeaderTable.Hmtx;
|
||||
|
||||
/// <inheritdoc />
|
||||
public TrueTypeHeaderTable DirectoryTable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The left-side bearing and advance widths for the glyphs in the font. For a monospace font
|
||||
/// this may only contain a single entry and the left-side bearings will be defined in <see cref="AdditionalLeftSideBearings"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyList<HorizontalMetric> HorizontalMetrics { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -24,17 +32,30 @@
|
||||
/// </summary>
|
||||
public IReadOnlyList<short> AdditionalLeftSideBearings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="HorizontalMetricsTable"/>.
|
||||
/// </summary>
|
||||
public HorizontalMetricsTable(TrueTypeHeaderTable directoryTable,
|
||||
IReadOnlyList<HorizontalMetric> horizontalMetrics,
|
||||
IReadOnlyList<short> additionalLeftSideBearings)
|
||||
{
|
||||
DirectoryTable = directoryTable;
|
||||
HorizontalMetrics = horizontalMetrics;
|
||||
AdditionalLeftSideBearings = additionalLeftSideBearings;
|
||||
HorizontalMetrics = horizontalMetrics
|
||||
?? throw new ArgumentNullException(nameof(horizontalMetrics));
|
||||
AdditionalLeftSideBearings = additionalLeftSideBearings
|
||||
?? throw new ArgumentNullException(nameof(additionalLeftSideBearings));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the advance width for a glyph at the given index.
|
||||
/// </summary>
|
||||
public ushort GetAdvanceWidth(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Index cannot be less than zero.");
|
||||
}
|
||||
|
||||
if (index < HorizontalMetrics.Count)
|
||||
{
|
||||
return HorizontalMetrics[index].AdvanceWidth;
|
||||
@@ -44,6 +65,7 @@
|
||||
return HorizontalMetrics[HorizontalMetrics.Count - 1].AdvanceWidth;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Write(Stream stream)
|
||||
{
|
||||
for (var i = 0; i < HorizontalMetrics.Count; i++)
|
||||
@@ -59,27 +81,5 @@
|
||||
stream.WriteShort(lsb);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The pair of horizontal metrics for an individual glyph.
|
||||
/// </summary>
|
||||
public struct HorizontalMetric
|
||||
{
|
||||
/// <summary>
|
||||
/// The advance width.
|
||||
/// </summary>
|
||||
public ushort AdvanceWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The left side bearing.
|
||||
/// </summary>
|
||||
public short LeftSideBearing { get; }
|
||||
|
||||
internal HorizontalMetric(ushort advanceWidth, short leftSideBearing)
|
||||
{
|
||||
AdvanceWidth = advanceWidth;
|
||||
LeftSideBearing = leftSideBearing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Exceptions;
|
||||
using IO;
|
||||
using Core;
|
||||
using Parser;
|
||||
using Util;
|
||||
|
||||
/// <inheritdoc cref="ITrueTypeTable"/>
|
||||
/// <summary>
|
||||
@@ -81,12 +79,14 @@
|
||||
|
||||
var glyphCount = maximumProfileTable.NumberOfGlyphs + 1;
|
||||
|
||||
var offsets = new uint[glyphCount];
|
||||
uint[] offsets;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case EntryFormat.Short:
|
||||
{ // The local offset divided by 2 is stored.
|
||||
{
|
||||
// The local offset divided by 2 is stored.
|
||||
offsets = new uint[glyphCount];
|
||||
for (var i = 0; i < glyphCount; i++)
|
||||
{
|
||||
offsets[i] = (uint)(data.ReadUnsignedShort() * 2);
|
||||
@@ -96,7 +96,7 @@
|
||||
case EntryFormat.Long:
|
||||
{
|
||||
// The actual offset is stored.
|
||||
data.ReadUnsignedIntArray(offsets, glyphCount);
|
||||
offsets = data.ReadUnsignedIntArray(glyphCount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -2,6 +2,9 @@
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// The type of kerning covered by this table.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum KernCoverage
|
||||
{
|
||||
@@ -1,6 +1,9 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables.Kerning
|
||||
{
|
||||
internal struct KernPair
|
||||
/// <summary>
|
||||
/// A kerning value for a pair of glyphs.
|
||||
/// </summary>
|
||||
public struct KernPair
|
||||
{
|
||||
/// <summary>
|
||||
/// The index of the left-hand glyph.
|
||||
@@ -18,6 +21,9 @@
|
||||
/// </summary>
|
||||
public short Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="KernPair"/>.
|
||||
/// </summary>
|
||||
public KernPair(int leftGlyphIndex, int rightGlyphIndex, short value)
|
||||
{
|
||||
LeftGlyphIndex = leftGlyphIndex;
|
||||
@@ -25,6 +31,7 @@
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Left: {LeftGlyphIndex}, Right: {RightGlyphIndex}, Value {Value}.";
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace UglyToad.PdfPig.Fonts.TrueType.Tables
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Names;
|
||||
using Util.JetBrains.Annotations;
|
||||
|
||||
internal class NameTable : ITrueTypeTable
|
||||
{
|
||||
@@ -28,14 +28,13 @@
|
||||
FontName = fontName;
|
||||
FontFamilyName = fontFamilyName;
|
||||
FontSubFamilyName = fontSubFamilyName;
|
||||
NameRecords = nameRecords;
|
||||
NameRecords = nameRecords ?? throw new ArgumentNullException(nameof(nameRecords));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the PostScript name for the font if specified, preferring the Windows platform name if present.
|
||||
/// </summary>
|
||||
/// <returns>The PostScript name for the font if found or <see langword="null"/>.</returns>
|
||||
[CanBeNull]
|
||||
public string GetPostscriptName()
|
||||
{
|
||||
string any = null;
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Util;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// Version 0 was defined in TrueType revision 1.5 and includes fields not in the Apple specification.
|
||||
@@ -3,8 +3,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using IO;
|
||||
using Util;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// The most basic format of the OS/2 table, excluding the fields not included in the Apple version of the specification.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user