First commit

Send all results
This commit is contained in:
2020-09-04 12:49:15 +05:00
commit 330a2ccfda
2819 changed files with 226201 additions and 0 deletions

View File

@@ -0,0 +1,398 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
#if GDI
using System.Drawing;
using System.Drawing.Drawing2D;
#endif
#if WPF
using System.Windows;
using System.Windows.Media;
#endif
using PdfSharp.Pdf.Internal;
using PdfSharp.Fonts;
#if !EDF_CORE
using PdfSharp.Drawing;
#endif
#pragma warning disable 0649
namespace PdfSharp.Fonts.OpenType
{
// TODO: Needs to be refactored #???
/// <summary>
/// Base class for all font descriptors.
/// Currently only OpenTypeDescriptor is derived from this base class.
/// </summary>
internal class FontDescriptor
{
protected FontDescriptor(string key)
{
_key = key;
}
public string Key
{
get { return _key; }
}
readonly string _key;
///// <summary>
/////
///// </summary>
//public string FontFile
//{
// get { return _fontFile; }
// private set { _fontFile = value; } // BUG: never set
//}
//string _fontFile;
///// <summary>
/////
///// </summary>
//public string FontType
//{
// get { return _fontType; }
// private set { _fontType = value; } // BUG: never set
//}
//string _fontType;
/// <summary>
///
/// </summary>
public string FontName
{
get { return _fontName; }
protected set { _fontName = value; }
}
string _fontName;
///// <summary>
/////
///// </summary>
//public string FullName
//{
// get { return _fullName; }
// private set { _fullName = value; } // BUG: never set
//}
//string _fullName;
///// <summary>
/////
///// </summary>
//public string FamilyName
//{
// get { return _familyName; }
// private set { _familyName = value; } // BUG: never set
//}
//string _familyName;
/// <summary>
///
/// </summary>
public string Weight
{
get { return _weight; }
private set { _weight = value; } // BUG: never set
}
string _weight;
/// <summary>
/// Gets a value indicating whether this instance belongs to a bold font.
/// </summary>
public virtual bool IsBoldFace
{
get { return false; }
}
/// <summary>
///
/// </summary>
public float ItalicAngle
{
get { return _italicAngle; }
protected set { _italicAngle = value; }
}
float _italicAngle;
/// <summary>
/// Gets a value indicating whether this instance belongs to an italic font.
/// </summary>
public virtual bool IsItalicFace
{
get { return false; }
}
/// <summary>
///
/// </summary>
public int XMin
{
get { return _xMin; }
protected set { _xMin = value; }
}
int _xMin;
/// <summary>
///
/// </summary>
public int YMin
{
get { return _yMin; }
protected set { _yMin = value; }
}
int _yMin;
/// <summary>
///
/// </summary>
public int XMax
{
get { return _xMax; }
protected set { _xMax = value; }
}
int _xMax;
/// <summary>
///
/// </summary>
public int YMax
{
get { return _yMax; }
protected set { _yMax = value; }
}
int _yMax;
/// <summary>
///
/// </summary>
public bool IsFixedPitch
{
get { return _isFixedPitch; }
private set { _isFixedPitch = value; } // BUG: never set
}
bool _isFixedPitch;
/// <summary>
///
/// </summary>
public int UnderlinePosition
{
get { return _underlinePosition; }
protected set { _underlinePosition = value; }
}
int _underlinePosition;
/// <summary>
///
/// </summary>
public int UnderlineThickness
{
get { return _underlineThickness; }
protected set { _underlineThickness = value; }
}
int _underlineThickness;
/// <summary>
///
/// </summary>
public int StrikeoutPosition
{
get { return _strikeoutPosition; }
protected set { _strikeoutPosition = value; }
}
int _strikeoutPosition;
/// <summary>
///
/// </summary>
public int StrikeoutSize
{
get { return _strikeoutSize; }
protected set { _strikeoutSize = value; }
}
int _strikeoutSize;
/// <summary>
///
/// </summary>
public string Version
{
get { return _version; }
private set { _version = value; } // BUG: never set
}
string _version;
///// <summary>
/////
///// </summary>
//public string Notice
//{
// get { return Notice; }
//}
//protected string notice;
/// <summary>
///
/// </summary>
public string EncodingScheme
{
get { return _encodingScheme; }
private set { _encodingScheme = value; } // BUG: never set
}
string _encodingScheme;
/// <summary>
///
/// </summary>
public int UnitsPerEm
{
get { return _unitsPerEm; }
protected set { _unitsPerEm = value; }
}
int _unitsPerEm;
/// <summary>
///
/// </summary>
public int CapHeight
{
get { return _capHeight; }
protected set { _capHeight = value; }
}
int _capHeight;
/// <summary>
///
/// </summary>
public int XHeight
{
get { return _xHeight; }
protected set { _xHeight = value; }
}
int _xHeight;
/// <summary>
///
/// </summary>
public int Ascender
{
get { return _ascender; }
protected set { _ascender = value; }
}
int _ascender;
/// <summary>
///
/// </summary>
public int Descender
{
get { return _descender; }
protected set { _descender = value; }
}
int _descender;
/// <summary>
///
/// </summary>
public int Leading
{
get { return _leading; }
protected set { _leading = value; }
}
int _leading;
/// <summary>
///
/// </summary>
public int Flags
{
get { return _flags; }
private set { _flags = value; } // BUG: never set
}
int _flags;
/// <summary>
///
/// </summary>
public int StemV
{
get { return _stemV; }
protected set { _stemV = value; }
}
int _stemV;
/// <summary>
///
/// </summary>
public int LineSpacing
{
get { return _lineSpacing; }
protected set { _lineSpacing = value; }
}
int _lineSpacing;
internal static string ComputeKey(XFont font)
{
return font.GlyphTypeface.Key;
//return ComputeKey(font.GlyphTypeface.Fontface.FullFaceName, font.Style);
//XGlyphTypeface glyphTypeface = font.GlyphTypeface;
//string key = glyphTypeface.Fontface.FullFaceName.ToLowerInvariant() +
// (glyphTypeface.IsBold ? "/b" : "") + (glyphTypeface.IsItalic ? "/i" : "");
//return key;
}
internal static string ComputeKey(string name, XFontStyle style)
{
return ComputeKey(name,
(style & XFontStyle.Bold) == XFontStyle.Bold,
(style & XFontStyle.Italic) == XFontStyle.Italic);
}
internal static string ComputeKey(string name, bool isBold, bool isItalic)
{
string key = name.ToLowerInvariant() + '/'
+ (isBold ? "b" : "") + (isItalic ? "i" : "");
return key;
}
internal static string ComputeKey(string name)
{
string key = name.ToLowerInvariant();
return key;
}
}
}

View File

@@ -0,0 +1,70 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
//using Fixed = System.Int32;
//using FWord = System.Int16;
//using UFWord = System.UInt16;
namespace PdfSharp.Fonts.OpenType
{
#if true_
/// <summary>
/// Generic font table. Not yet used
/// </summary>
internal class GenericFontTable : OpenTypeFontTable
{
public GenericFontTable(OpenTypeFontTable fontTable)
: base(null, "xxxx")
{
DirectoryEntry.Tag = fontTable.DirectoryEntry.Tag;
int length = fontTable.DirectoryEntry.Length;
if (length > 0)
{
_table = new byte[length];
Buffer.BlockCopy(fontTable.FontData.Data, fontTable.DirectoryEntry.Offset, _table, 0, length);
}
}
public GenericFontTable(OpenTypeFontface fontData, string tag)
: base(fontData, tag)
{
_fontData = fontData;
}
protected override OpenTypeFontTable DeepCopy()
{
GenericFontTable fontTable = (GenericFontTable)base.DeepCopy();
fontTable._table = (byte[])_table.Clone();
return fontTable;
}
byte[] _table;
}
#endif
}

View File

@@ -0,0 +1,190 @@

#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
#define VERBOSE_
using System;
using System.Collections.Generic;
//using Fixed = System.Int32;
//using FWord = System.Int16;
//using UFWord = System.UInt16;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// This table contains information that describes the glyphs in the font in the TrueType outline format.
/// Information regarding the rasterizer (scaler) refers to the TrueType rasterizer.
/// http://www.microsoft.com/typography/otspec/glyf.htm
/// </summary>
internal class GlyphDataTable : OpenTypeFontTable
{
public const string Tag = TableTagNames.Glyf;
internal byte[] GlyphTable;
public GlyphDataTable()
: base(null, Tag)
{
DirectoryEntry.Tag = TableTagNames.Glyf;
}
public GlyphDataTable(OpenTypeFontface fontData)
: base(fontData, Tag)
{
DirectoryEntry.Tag = TableTagNames.Glyf;
Read();
}
/// <summary>
/// Converts the bytes in a handy representation
/// </summary>
public void Read()
{
try
{
// not yet needed...
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Gets the data of the specified glyph.
/// </summary>
public byte[] GetGlyphData(int glyph)
{
IndexToLocationTable loca = _fontData.loca;
int start = GetOffset(glyph);
int next = GetOffset(glyph + 1);
int count = next - start;
byte[] bytes = new byte[count];
Buffer.BlockCopy(_fontData.FontSource.Bytes, start, bytes, 0, count);
return bytes;
}
/// <summary>
/// Gets the size of the byte array that defines the glyph.
/// </summary>
public int GetGlyphSize(int glyph)
{
IndexToLocationTable loca = _fontData.loca;
return GetOffset(glyph + 1) - GetOffset(glyph);
}
/// <summary>
/// Gets the offset of the specified glyph relative to the first byte of the font image.
/// </summary>
public int GetOffset(int glyph)
{
return DirectoryEntry.Offset + _fontData.loca.LocaTable[glyph];
}
/// <summary>
/// Adds for all composite glyphs the glyphs the composite one is made of.
/// </summary>
public void CompleteGlyphClosure(Dictionary<int, object> glyphs)
{
int count = glyphs.Count;
int[] glyphArray = new int[glyphs.Count];
glyphs.Keys.CopyTo(glyphArray, 0);
if (!glyphs.ContainsKey(0))
glyphs.Add(0, null);
for (int idx = 0; idx < count; idx++)
AddCompositeGlyphs(glyphs, glyphArray[idx]);
}
/// <summary>
/// If the specified glyph is a composite glyph add the glyphs it is made of to the glyph table.
/// </summary>
void AddCompositeGlyphs(Dictionary<int, object> glyphs, int glyph)
{
//int start = fontData.loca.GetOffset(glyph);
int start = GetOffset(glyph);
// Has no contour?
if (start == GetOffset(glyph + 1))
return;
_fontData.Position = start;
int numContours = _fontData.ReadShort();
// Is not a composite glyph?
if (numContours >= 0)
return;
_fontData.SeekOffset(8);
for (; ; )
{
int flags = _fontData.ReadUFWord();
int cGlyph = _fontData.ReadUFWord();
if (!glyphs.ContainsKey(cGlyph))
glyphs.Add(cGlyph, null);
if ((flags & MORE_COMPONENTS) == 0)
return;
int offset = (flags & ARG_1_AND_2_ARE_WORDS) == 0 ? 2 : 4;
if ((flags & WE_HAVE_A_SCALE) != 0)
offset += 2;
else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0)
offset += 4;
if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0)
offset += 8;
_fontData.SeekOffset(offset);
}
}
/// <summary>
/// Prepares the font table to be compiled into its binary representation.
/// </summary>
public override void PrepareForCompilation()
{
base.PrepareForCompilation();
if (DirectoryEntry.Length == 0)
DirectoryEntry.Length = GlyphTable.Length;
DirectoryEntry.CheckSum = CalcChecksum(GlyphTable);
}
/// <summary>
/// Converts the font into its binary representation.
/// </summary>
public override void Write(OpenTypeFontWriter writer)
{
writer.Write(GlyphTable, 0, DirectoryEntry.PaddedLength);
}
// ReSharper disable InconsistentNaming
// Constants from OpenType spec.
const int ARG_1_AND_2_ARE_WORDS = 1;
const int WE_HAVE_A_SCALE = 8;
const int MORE_COMPONENTS = 32;
const int WE_HAVE_AN_X_AND_Y_SCALE = 64;
const int WE_HAVE_A_TWO_BY_TWO = 128;
// ReSharper restore InconsistentNaming
}
}

View File

@@ -0,0 +1,116 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using PdfSharp.Drawing;
using PdfSharp.Internal;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Global table of all glyph typefaces.
/// </summary>
internal class GlyphTypefaceCache
{
GlyphTypefaceCache()
{
_glyphTypefacesByKey = new Dictionary<string, XGlyphTypeface>();
}
public static bool TryGetGlyphTypeface(string key, out XGlyphTypeface glyphTypeface)
{
try
{
Lock.EnterFontFactory();
bool result = Singleton._glyphTypefacesByKey.TryGetValue(key, out glyphTypeface);
return result;
}
finally { Lock.ExitFontFactory(); }
}
public static void AddGlyphTypeface(XGlyphTypeface glyphTypeface)
{
try
{
Lock.EnterFontFactory();
GlyphTypefaceCache cache = Singleton;
Debug.Assert(!cache._glyphTypefacesByKey.ContainsKey(glyphTypeface.Key));
cache._glyphTypefacesByKey.Add(glyphTypeface.Key, glyphTypeface);
}
finally { Lock.ExitFontFactory(); }
}
/// <summary>
/// Gets the singleton.
/// </summary>
static GlyphTypefaceCache Singleton
{
get
{
// ReSharper disable once InvertIf
if (_singleton == null)
{
try
{
Lock.EnterFontFactory();
if (_singleton == null)
_singleton = new GlyphTypefaceCache();
}
finally { Lock.ExitFontFactory(); }
}
return _singleton;
}
}
static volatile GlyphTypefaceCache _singleton;
internal static string GetCacheState()
{
StringBuilder state = new StringBuilder();
state.Append("====================\n");
state.Append("Glyph typefaces by name\n");
Dictionary<string, XGlyphTypeface>.KeyCollection familyKeys = Singleton._glyphTypefacesByKey.Keys;
int count = familyKeys.Count;
string[] keys = new string[count];
familyKeys.CopyTo(keys, 0);
Array.Sort(keys, StringComparer.OrdinalIgnoreCase);
foreach (string key in keys)
state.AppendFormat(" {0}: {1}\n", key, Singleton._glyphTypefacesByKey[key].DebuggerDisplay);
state.Append("\n");
return state.ToString();
}
/// <summary>
/// Maps typeface key to glyph typeface.
/// </summary>
readonly Dictionary<string, XGlyphTypeface> _glyphTypefacesByKey;
}
}

View File

@@ -0,0 +1,83 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using Fixed = System.Int32;
using FWord = System.Int16;
using UFWord = System.UInt16;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Represents an indirect reference to an existing font table in a font image.
/// Used to create binary copies of an existing font table that is not modified.
/// </summary>
// ReSharper disable once InconsistentNaming - "I" stands for "indirect", not "interface".
internal class IRefFontTable : OpenTypeFontTable
{
public IRefFontTable(OpenTypeFontface fontData, OpenTypeFontTable fontTable)
: base(null, fontTable.DirectoryEntry.Tag)
{
_fontData = fontData;
_irefDirectoryEntry = fontTable.DirectoryEntry;
}
readonly TableDirectoryEntry _irefDirectoryEntry;
/// <summary>
/// Prepares the font table to be compiled into its binary representation.
/// </summary>
public override void PrepareForCompilation()
{
base.PrepareForCompilation();
DirectoryEntry.Length = _irefDirectoryEntry.Length;
DirectoryEntry.CheckSum = _irefDirectoryEntry.CheckSum;
#if DEBUG
// Check the checksum algorithm
if (DirectoryEntry.Tag != TableTagNames.Head)
{
byte[] bytes = new byte[DirectoryEntry.PaddedLength];
Buffer.BlockCopy(_irefDirectoryEntry.FontTable._fontData.FontSource.Bytes, _irefDirectoryEntry.Offset, bytes, 0, DirectoryEntry.PaddedLength);
uint checkSum1 = DirectoryEntry.CheckSum;
uint checkSum2 = CalcChecksum(bytes);
// TODO: Sometimes this Assert fails,
//Debug.Assert(checkSum1 == checkSum2, "Bug in checksum algorithm.");
}
#endif
}
/// <summary>
/// Converts the font into its binary representation.
/// </summary>
public override void Write(OpenTypeFontWriter writer)
{
writer.Write(_irefDirectoryEntry.FontTable._fontData.FontSource.Bytes, _irefDirectoryEntry.Offset, _irefDirectoryEntry.PaddedLength);
}
}
}

View File

@@ -0,0 +1,149 @@

#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
#define VERBOSE_
using System;
using System.Diagnostics;
//using Fixed = System.Int32;
//using FWord = System.Int16;
//using UFWord = System.UInt16;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// The indexToLoc table stores the offsets to the locations of the glyphs in the font,
/// relative to the beginning of the glyphData table. In order to compute the length of
/// the last glyph element, there is an extra entry after the last valid index.
/// </summary>
internal class IndexToLocationTable : OpenTypeFontTable
{
public const string Tag = TableTagNames.Loca;
internal int[] LocaTable;
public IndexToLocationTable()
: base(null, Tag)
{
DirectoryEntry.Tag = TableTagNames.Loca;
}
public IndexToLocationTable(OpenTypeFontface fontData)
: base(fontData, Tag)
{
DirectoryEntry = _fontData.TableDictionary[TableTagNames.Loca];
Read();
}
public bool ShortIndex;
/// <summary>
/// Converts the bytes in a handy representation
/// </summary>
public void Read()
{
try
{
ShortIndex = _fontData.head.indexToLocFormat == 0;
_fontData.Position = DirectoryEntry.Offset;
if (ShortIndex)
{
int entries = DirectoryEntry.Length / 2;
Debug.Assert(_fontData.maxp.numGlyphs + 1 == entries,
"For your information only: Number of glyphs mismatch in font. You can ignore this assertion.");
LocaTable = new int[entries];
for (int idx = 0; idx < entries; idx++)
LocaTable[idx] = 2 * _fontData.ReadUFWord();
}
else
{
int entries = DirectoryEntry.Length / 4;
Debug.Assert(_fontData.maxp.numGlyphs + 1 == entries,
"For your information only: Number of glyphs mismatch in font. You can ignore this assertion.");
LocaTable = new int[entries];
for (int idx = 0; idx < entries; idx++)
LocaTable[idx] = _fontData.ReadLong();
}
}
catch (Exception)
{
GetType();
throw;
}
}
/// <summary>
/// Prepares the font table to be compiled into its binary representation.
/// </summary>
public override void PrepareForCompilation()
{
DirectoryEntry.Offset = 0;
if (ShortIndex)
DirectoryEntry.Length = LocaTable.Length * 2;
else
DirectoryEntry.Length = LocaTable.Length * 4;
_bytes = new byte[DirectoryEntry.PaddedLength];
int length = LocaTable.Length;
int byteIdx = 0;
if (ShortIndex)
{
for (int idx = 0; idx < length; idx++)
{
int value = LocaTable[idx] / 2;
_bytes[byteIdx++] = (byte)(value >> 8);
_bytes[byteIdx++] = (byte)(value);
}
}
else
{
for (int idx = 0; idx < length; idx++)
{
int value = LocaTable[idx];
_bytes[byteIdx++] = (byte)(value >> 24);
_bytes[byteIdx++] = (byte)(value >> 16);
_bytes[byteIdx++] = (byte)(value >> 8);
_bytes[byteIdx++] = (byte)value;
}
}
DirectoryEntry.CheckSum = CalcChecksum(_bytes);
}
byte[] _bytes;
/// <summary>
/// Converts the font into its binary representation.
/// </summary>
public override void Write(OpenTypeFontWriter writer)
{
writer.Write(_bytes, 0, DirectoryEntry.PaddedLength);
}
}
}

View File

@@ -0,0 +1,425 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Diagnostics;
using System.Text;
#if GDI
using System.Drawing;
using System.Drawing.Drawing2D;
#endif
#if WPF
using System.Windows;
using System.Windows.Media;
#endif
using PdfSharp.Pdf.Internal;
#if !EDF_CORE
using PdfSharp.Drawing;
#endif
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// The OpenType font descriptor.
/// Currently the only font type PDFsharp supports.
/// </summary>
internal sealed class OpenTypeDescriptor : FontDescriptor
{
/// <summary>
/// New...
/// </summary>
public OpenTypeDescriptor(string fontDescriptorKey, string name, XFontStyle stlye, OpenTypeFontface fontface, XPdfFontOptions options)
: base(fontDescriptorKey)
{
FontFace = fontface;
FontName = name;
Initialize();
}
public OpenTypeDescriptor(string fontDescriptorKey, XFont font)
: base(fontDescriptorKey)
{
try
{
FontFace = font.GlyphTypeface.Fontface;
FontName = font.Name;
Initialize();
}
catch
{
GetType();
throw;
}
}
internal OpenTypeDescriptor(string fontDescriptorKey, string idName, byte[] fontData)
: base(fontDescriptorKey)
{
try
{
FontFace = new OpenTypeFontface(fontData, idName);
// Try to get real name form name table
if (idName.Contains("XPS-Font-") && FontFace.name != null && FontFace.name.Name.Length != 0)
{
string tag = String.Empty;
if (idName.IndexOf('+') == 6)
tag = idName.Substring(0, 6);
idName = tag + "+" + FontFace.name.Name;
if (FontFace.name.Style.Length != 0)
idName += "," + FontFace.name.Style;
//idName = idName.Replace(" ", "");
}
FontName = idName;
Initialize();
}
catch (Exception)
{
GetType();
throw;
}
}
internal OpenTypeFontface FontFace;
void Initialize()
{
// TODO: Respect embedding restrictions.
//bool embeddingRestricted = fontData.os2.fsType == 0x0002;
//fontName = image.n
ItalicAngle = FontFace.post.italicAngle;
XMin = FontFace.head.xMin;
YMin = FontFace.head.yMin;
XMax = FontFace.head.xMax;
YMax = FontFace.head.yMax;
UnderlinePosition = FontFace.post.underlinePosition;
UnderlineThickness = FontFace.post.underlineThickness;
// PDFlib states that some Apple fonts miss the OS/2 table.
Debug.Assert(FontFace.os2 != null, "TrueType font has no OS/2 table.");
StrikeoutPosition = FontFace.os2.yStrikeoutPosition;
StrikeoutSize = FontFace.os2.yStrikeoutSize;
// No documentation found how to get the set vertical stems width from the
// TrueType tables.
// The following formula comes from PDFlib Lite source code. Acrobat 5.0 sets
// /StemV to 0 always. I think the value doesn't matter.
//float weight = (float)(image.os2.usWeightClass / 65.0f);
//stemV = (int)(50 + weight * weight); // MAGIC
StemV = 0;
UnitsPerEm = FontFace.head.unitsPerEm;
// Calculate Ascent, Descent, Leading and LineSpacing like in WPF Source Code (see FontDriver.ReadBasicMetrics)
// OS/2 is an optional table, but we can't determine if it is existing in this font.
bool os2SeemsToBeEmpty = FontFace.os2.sTypoAscender == 0 && FontFace.os2.sTypoDescender == 0 && FontFace.os2.sTypoLineGap == 0;
//Debug.Assert(!os2SeemsToBeEmpty); // Are there fonts without OS/2 table?
bool dontUseWinLineMetrics = (FontFace.os2.fsSelection & 128) != 0;
if (!os2SeemsToBeEmpty && dontUseWinLineMetrics)
{
// Comment from WPF: The font specifies that the sTypoAscender, sTypoDescender, and sTypoLineGap fields are valid and
// should be used instead of winAscent and winDescent.
int typoAscender = FontFace.os2.sTypoAscender;
int typoDescender = FontFace.os2.sTypoDescender;
int typoLineGap = FontFace.os2.sTypoLineGap;
// Comment from WPF: We include the line gap in the ascent so that white space is distributed above the line. (Note that
// the typo line gap is a different concept than "external leading".)
Ascender = typoAscender + typoLineGap;
// Comment from WPF: Typo descent is a signed value where the positive direction is up. It is therefore typically negative.
// A signed typo descent would be quite unusual as it would indicate the descender was above the baseline
Descender = -typoDescender;
LineSpacing = typoAscender + typoLineGap - typoDescender;
}
else
{
// Comment from WPF: get the ascender field
int ascender = FontFace.hhea.ascender;
// Comment from WPF: get the descender field; this is measured in the same direction as ascender and is therefore
// normally negative whereas we want a positive value; however some fonts get the sign wrong
// so instead of just negating we take the absolute value.
int descender = Math.Abs(FontFace.hhea.descender);
// Comment from WPF: get the lineGap field and make sure it's >= 0
int lineGap = Math.Max((short)0, FontFace.hhea.lineGap);
if (!os2SeemsToBeEmpty)
{
// Comment from WPF: we could use sTypoAscender, sTypoDescender, and sTypoLineGap which are supposed to represent
// optimal typographic values not constrained by backwards compatibility; however, many fonts get
// these fields wrong or get them right only for Latin text; therefore we use the more reliable
// platform-specific Windows values. We take the absolute value of the win32descent in case some
// fonts get the sign wrong.
int winAscent = FontFace.os2.usWinAscent;
int winDescent = Math.Abs(FontFace.os2.usWinDescent);
Ascender = winAscent;
Descender = winDescent;
// Comment from WPF: The following calculation for designLineSpacing is per [....]. The default line spacing
// should be the sum of the Mac ascender, descender, and lineGap unless the resulting value would
// be less than the cell height (winAscent + winDescent) in which case we use the cell height.
// See also http://www.microsoft.com/typography/otspec/recom.htm.
// Note that in theory it's valid for the baseline-to-baseline distance to be less than the cell
// height. However, Windows has never allowed this for Truetype fonts, and fonts built for Windows
// sometimes rely on this behavior and get the hha values wrong or set them all to zero.
LineSpacing = Math.Max(lineGap + ascender + descender, winAscent + winDescent);
}
else
{
Ascender = ascender;
Descender = descender;
LineSpacing = ascender + descender + lineGap;
}
}
Debug.Assert(Descender >= 0);
int cellHeight = Ascender + Descender;
int internalLeading = cellHeight - UnitsPerEm; // Not used, only for debugging.
int externalLeading = LineSpacing - cellHeight;
Leading = externalLeading;
// sCapHeight and sxHeight are only valid if Version >= 2
if (FontFace.os2.version >= 2 && FontFace.os2.sCapHeight != 0)
CapHeight = FontFace.os2.sCapHeight;
else
CapHeight = Ascender;
if (FontFace.os2.version >= 2 && FontFace.os2.sxHeight != 0)
XHeight = FontFace.os2.sxHeight;
else
XHeight = (int)(0.66 * Ascender);
//flags = image.
#if !EDF_CORE
Encoding ansi = PdfEncoders.WinAnsiEncoding; // System.Text.Encoding.Default;
#else
Encoding ansi = null; //$$$ PdfEncoders.WinAnsiEncoding; // System.Text.Encoding.Default;
#endif
Encoding unicode = Encoding.Unicode;
byte[] bytes = new byte[256];
bool symbol = FontFace.cmap.symbol;
Widths = new int[256];
for (int idx = 0; idx < 256; idx++)
{
bytes[idx] = (byte)idx;
// PDFlib handles some font flaws here...
// We wait for bug reports.
char ch = (char)idx;
string s = ansi.GetString(bytes, idx, 1);
if (s.Length != 0)
{
if (s[0] != ch)
ch = s[0];
}
//Debug.Assert(ch == idx);
//int glyphIndex;
//if (symbol)
//{
// glyphIndex = idx + (FontFace.os2. usFirstCharIndex & 0xFF00);
// glyphIndex = CharCodeToGlyphIndex((char)glyphIndex);
//}
//else
//{
// //Debug.Assert(idx + (fontData.os2.usFirstCharIndex & 0xFF00) == idx);
// //glyphIndex = CharCodeToGlyphIndex((char)idx);
// glyphIndex = CharCodeToGlyphIndex(ch);
//}
if (symbol)
{
// Remap ch for symbol fonts.
ch = (char)(ch | (FontFace.os2.usFirstCharIndex & 0xFF00)); // @@@ refactor
}
int glyphIndex = CharCodeToGlyphIndex(ch);
Widths[idx] = GlyphIndexToPdfWidth(glyphIndex);
}
}
public int[] Widths;
/// <summary>
/// Gets a value indicating whether this instance belongs to a bold font.
/// </summary>
public override bool IsBoldFace
{
get
{
// usWeightClass 700 is Bold
//Debug.Assert((fontData.os2.usWeightClass >= 700) == ((fontData.os2.fsSelection & (ushort)OS2Table.FontSelectionFlags.Bold) != 0));
return FontFace.os2.IsBold;
}
}
/// <summary>
/// Gets a value indicating whether this instance belongs to an italic font.
/// </summary>
public override bool IsItalicFace
{
get { return FontFace.os2.IsItalic; }
}
internal int DesignUnitsToPdf(double value)
{
return (int)Math.Round(value * 1000.0 / FontFace.head.unitsPerEm);
}
/// <summary>
/// Maps a unicode to the index of the corresponding glyph.
/// See OpenType spec "cmap - Character To Glyph Index Mapping Table / Format 4: Segment mapping to delta values"
/// for details about this a little bit strange looking algorithm.
/// </summary>
public int CharCodeToGlyphIndex(char value)
{
try
{
CMap4 cmap = FontFace.cmap.cmap4;
int segCount = cmap.segCountX2 / 2;
int seg;
for (seg = 0; seg < segCount; seg++)
{
if (value <= cmap.endCount[seg])
break;
}
Debug.Assert(seg < segCount);
if (value < cmap.startCount[seg])
return 0;
if (cmap.idRangeOffs[seg] == 0)
return (value + cmap.idDelta[seg]) & 0xFFFF;
int idx = cmap.idRangeOffs[seg] / 2 + (value - cmap.startCount[seg]) - (segCount - seg);
Debug.Assert(idx >= 0 && idx < cmap.glyphCount);
if (cmap.glyphIdArray[idx] == 0)
return 0;
return (cmap.glyphIdArray[idx] + cmap.idDelta[seg]) & 0xFFFF;
}
catch
{
GetType();
throw;
}
}
/// <summary>
/// Converts the width of a glyph identified by its index to PDF design units.
/// </summary>
public int GlyphIndexToPdfWidth(int glyphIndex)
{
try
{
int numberOfHMetrics = FontFace.hhea.numberOfHMetrics;
int unitsPerEm = FontFace.head.unitsPerEm;
// glyphIndex >= numberOfHMetrics means the font is mono-spaced and all glyphs have the same width
if (glyphIndex >= numberOfHMetrics)
glyphIndex = numberOfHMetrics - 1;
int width = FontFace.hmtx.Metrics[glyphIndex].advanceWidth;
// Sometimes the unitsPerEm is 1000, sometimes a power of 2.
if (unitsPerEm == 1000)
return width;
return width * 1000 / unitsPerEm; // normalize
}
catch (Exception)
{
GetType();
throw;
}
}
public int PdfWidthFromCharCode(char ch)
{
int idx = CharCodeToGlyphIndex(ch);
int width = GlyphIndexToPdfWidth(idx);
return width;
}
/// <summary>
/// //Converts the width of a glyph identified by its index to PDF design units.
/// </summary>
public double GlyphIndexToEmfWidth(int glyphIndex, double emSize)
{
try
{
int numberOfHMetrics = FontFace.hhea.numberOfHMetrics;
int unitsPerEm = FontFace.head.unitsPerEm;
// glyphIndex >= numberOfHMetrics means the font is mono-spaced and all glyphs have the same width
if (glyphIndex >= numberOfHMetrics)
glyphIndex = numberOfHMetrics - 1;
int width = FontFace.hmtx.Metrics[glyphIndex].advanceWidth;
return width * emSize / unitsPerEm; // normalize
}
catch (Exception)
{
GetType();
throw;
}
}
/// <summary>
/// //Converts the width of a glyph identified by its index to PDF design units.
/// </summary>
public int GlyphIndexToWidth(int glyphIndex)
{
try
{
int numberOfHMetrics = FontFace.hhea.numberOfHMetrics;
// glyphIndex >= numberOfHMetrics means the font is mono-spaced and all glyphs have the same width
if (glyphIndex >= numberOfHMetrics)
glyphIndex = numberOfHMetrics - 1;
int width = FontFace.hmtx.Metrics[glyphIndex].advanceWidth;
return width;
}
catch (Exception)
{
GetType();
throw;
}
}
}
}

View File

@@ -0,0 +1,118 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Diagnostics;
//using Fixed = System.Int32;
//using FWord = System.Int16;
//using UFWord = System.UInt16;
#if SILVERLIGHT
using PdfSharp;
#endif
namespace PdfSharp.Fonts.OpenType
{
// TODO: Create a font driver for reading and writing OpenType font files.
/// <summary>
/// Base class for all OpenType tables used in PDFsharp.
/// </summary>
internal class OpenTypeFontTable : ICloneable
{
public OpenTypeFontTable(OpenTypeFontface fontData, string tag)
{
_fontData = fontData;
if (fontData != null && fontData.TableDictionary.ContainsKey(tag))
DirectoryEntry = fontData.TableDictionary[tag];
else
DirectoryEntry = new TableDirectoryEntry(tag);
DirectoryEntry.FontTable = this;
}
/// <summary>
/// Creates a deep copy of the current instance.
/// </summary>
public object Clone()
{
return DeepCopy();
}
protected virtual OpenTypeFontTable DeepCopy()
{
OpenTypeFontTable fontTable = (OpenTypeFontTable)MemberwiseClone();
fontTable.DirectoryEntry.Offset = 0;
fontTable.DirectoryEntry.FontTable = fontTable;
return fontTable;
}
/// <summary>
/// Gets the font image the table belongs to.
/// </summary>
public OpenTypeFontface FontData
{
get { return _fontData; }
}
internal OpenTypeFontface _fontData;
public TableDirectoryEntry DirectoryEntry;
/// <summary>
/// When overridden in a derived class, prepares the font table to be compiled into its binary representation.
/// </summary>
public virtual void PrepareForCompilation()
{ }
/// <summary>
/// When overridden in a derived class, converts the font into its binary representation.
/// </summary>
public virtual void Write(OpenTypeFontWriter writer)
{ }
/// <summary>
/// Calculates the checksum of a table represented by its bytes.
/// </summary>
public static uint CalcChecksum(byte[] bytes)
{
Debug.Assert((bytes.Length & 3) == 0);
// Cannot use Buffer.BlockCopy because 32-bit values are Big-endian in fonts.
uint byte3, byte2, byte1, byte0;
byte3 = byte2 = byte1 = byte0 = 0;
int length = bytes.Length;
for (int idx = 0; idx < length;)
{
byte3 += bytes[idx++];
byte2 += bytes[idx++];
byte1 += bytes[idx++];
byte0 += bytes[idx++];
}
return (byte3 << 24) + (byte2 << 16) + (byte1 << 8) + byte0;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System.Diagnostics;
using System.IO;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Represents a writer for True Type font files.
/// </summary>
internal class OpenTypeFontWriter : FontWriter
{
/// <summary>
/// Initializes a new instance of the <see cref="OpenTypeFontWriter"/> class.
/// </summary>
public OpenTypeFontWriter(Stream stream)
: base(stream)
{ }
/// <summary>
/// Writes a table name.
/// </summary>
public void WriteTag(string tag)
{
Debug.Assert(tag.Length == 4);
WriteByte((byte)(tag[0]));
WriteByte((byte)(tag[1]));
WriteByte((byte)(tag[2]));
WriteByte((byte)(tag[3]));
}
}
}

View File

@@ -0,0 +1,746 @@

#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
#define VERBOSE_
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.IO;
#if GDI
using System.Drawing;
using System.Drawing.Drawing2D;
using GdiFontFamily = System.Drawing.FontFamily;
using GdiFont = System.Drawing.Font;
using GdiFontStyle = System.Drawing.FontStyle;
#endif
#if WPF
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using WpfFontFamily = System.Windows.Media.FontFamily;
using WpfTypeface = System.Windows.Media.Typeface;
using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface;
#endif
using PdfSharp.Fonts;
#if !EDF_CORE
using PdfSharp.Drawing;
using PdfSharp.Internal;
#endif
using Fixed = System.Int32;
using FWord = System.Int16;
using UFWord = System.UInt16;
#pragma warning disable 0649
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Represents an OpenType fontface in memory.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay}")]
internal sealed class OpenTypeFontface
{
// Implementation Notes
// OpenTypeFontface represents a 'decompiled' font file in memory.
//
// * An OpenTypeFontface can belong to more than one
// XGlyphTypeface because of StyleSimulations.
//
// * Currently there is a one to one relationship to XFontSource.
//
// * Consider OpenTypeFontface as an decompiled XFontSource.
//
// http://www.microsoft.com/typography/otspec/
/// <summary>
/// Shallow copy for font subset.
/// </summary>
OpenTypeFontface(OpenTypeFontface fontface)
{
_offsetTable = fontface._offsetTable;
_fullFaceName = fontface._fullFaceName;
}
/// <summary>
/// Initializes a new instance of the <see cref="OpenTypeFontface"/> class.
/// </summary>
public OpenTypeFontface(byte[] data, string faceName)
{
_fullFaceName = faceName;
// Always save a copy of the font bytes.
int length = data.Length;
//FontSource = new XFontSource(faceName, new byte[length]);
Array.Copy(data, FontSource.Bytes, length);
Read();
}
public OpenTypeFontface(XFontSource fontSource)
{
FontSource = fontSource;
Read();
_fullFaceName = name.FullFontName;
}
public static OpenTypeFontface CetOrCreateFrom(XFontSource fontSource)
{
OpenTypeFontface fontface;
if (OpenTypeFontfaceCache.TryGetFontface(fontSource.Key, out fontface))
{
return fontface;
}
// Each font source already contains its OpenTypeFontface.
Debug.Assert(fontSource.Fontface != null);
fontface = OpenTypeFontfaceCache.AddFontface(fontSource.Fontface);
Debug.Assert(ReferenceEquals(fontSource.Fontface, fontface));
return fontface;
}
/// <summary>
/// Gets the full face name from the name table.
/// Name is also used as the key.
/// </summary>
public string FullFaceName
{
get { return _fullFaceName; }
}
readonly string _fullFaceName;
public ulong CheckSum
{
get
{
if (_checkSum == 0)
_checkSum = FontHelper.CalcChecksum(FontSource.Bytes);
return _checkSum;
}
}
ulong _checkSum;
/// <summary>
/// Gets the bytes that represents the font data.
/// </summary>
public XFontSource FontSource
{
get { return _fontSource; }
private set
{
// Stop working if font was not found.
if (value == null)
throw new InvalidOperationException("Font cannot be resolved.");
_fontSource = value;
}
}
XFontSource _fontSource;
internal FontTechnology _fontTechnology;
internal OffsetTable _offsetTable;
/// <summary>
/// The dictionary of all font tables.
/// </summary>
internal Dictionary<string, TableDirectoryEntry> TableDictionary = new Dictionary<string, TableDirectoryEntry>();
// Keep names identical to OpenType spec.
// ReSharper disable InconsistentNaming
internal CMapTable cmap;
internal ControlValueTable cvt;
internal FontProgram fpgm;
internal MaximumProfileTable maxp;
internal NameTable name;
internal ControlValueProgram prep;
internal FontHeaderTable head;
internal HorizontalHeaderTable hhea;
internal HorizontalMetricsTable hmtx;
internal OS2Table os2;
internal PostScriptTable post;
internal GlyphDataTable glyf;
internal IndexToLocationTable loca;
internal GlyphSubstitutionTable gsub;
internal VerticalHeaderTable vhea; // TODO
internal VerticalMetricsTable vmtx; // TODO
// ReSharper restore InconsistentNaming
public bool CanRead
{
get { return FontSource != null; }
}
public bool CanWrite
{
get { return FontSource == null; }
}
/// <summary>
/// Adds the specified table to this font image.
/// </summary>
public void AddTable(OpenTypeFontTable fontTable)
{
if (!CanWrite)
throw new InvalidOperationException("Font image cannot be modified.");
if (fontTable == null)
throw new ArgumentNullException("fontTable");
if (fontTable._fontData == null)
{
fontTable._fontData = this;
}
else
{
Debug.Assert(fontTable._fontData.CanRead);
// Create a reference to this font table
fontTable = new IRefFontTable(this, fontTable);
}
//Debug.Assert(fontTable.FontData == null);
//fontTable.fontData = this;
TableDictionary[fontTable.DirectoryEntry.Tag] = fontTable.DirectoryEntry;
switch (fontTable.DirectoryEntry.Tag)
{
case TableTagNames.CMap:
cmap = fontTable as CMapTable;
break;
case TableTagNames.Cvt:
cvt = fontTable as ControlValueTable;
break;
case TableTagNames.Fpgm:
fpgm = fontTable as FontProgram;
break;
case TableTagNames.MaxP:
maxp = fontTable as MaximumProfileTable;
break;
case TableTagNames.Name:
name = fontTable as NameTable;
break;
case TableTagNames.Head:
head = fontTable as FontHeaderTable;
break;
case TableTagNames.HHea:
hhea = fontTable as HorizontalHeaderTable;
break;
case TableTagNames.HMtx:
hmtx = fontTable as HorizontalMetricsTable;
break;
case TableTagNames.OS2:
os2 = fontTable as OS2Table;
break;
case TableTagNames.Post:
post = fontTable as PostScriptTable;
break;
case TableTagNames.Glyf:
glyf = fontTable as GlyphDataTable;
break;
case TableTagNames.Loca:
loca = fontTable as IndexToLocationTable;
break;
case TableTagNames.GSUB:
gsub = fontTable as GlyphSubstitutionTable;
break;
case TableTagNames.Prep:
prep = fontTable as ControlValueProgram;
break;
}
}
/// <summary>
/// Reads all required tables from the font data.
/// </summary>
internal void Read()
{
// Determine font technology
// ReSharper disable InconsistentNaming
const uint OTTO = 0x4f54544f; // Adobe OpenType CFF data, tag: 'OTTO'
const uint TTCF = 0x74746366; // TrueType Collection tag: 'ttcf'
// ReSharper restore InconsistentNaming
try
{
#if DEBUG_
if (Name == "Cambria")
Debug-Break.Break();
#endif
// Check if data is a TrueType collection font.
uint startTag = ReadULong();
if (startTag == TTCF)
{
_fontTechnology = FontTechnology.TrueTypeCollection;
throw new InvalidOperationException("TrueType collection fonts are not yet supported by PDFsharp.");
}
// Read offset table
_offsetTable.Version = startTag;
_offsetTable.TableCount = ReadUShort();
_offsetTable.SearchRange = ReadUShort();
_offsetTable.EntrySelector = ReadUShort();
_offsetTable.RangeShift = ReadUShort();
// Move to table dictionary at position 12
Debug.Assert(_pos == 12);
//tableDictionary = (offsetTable.TableCount);
if (_offsetTable.Version == OTTO)
_fontTechnology = FontTechnology.PostscriptOutlines;
else
_fontTechnology = FontTechnology.TrueTypeOutlines;
for (int idx = 0; idx < _offsetTable.TableCount; idx++)
{
TableDirectoryEntry entry = TableDirectoryEntry.ReadFrom(this);
TableDictionary.Add(entry.Tag, entry);
#if VERBOSE
Debug.WriteLine(String.Format("Font table: {0}", entry.Tag));
#endif
}
// PDFlib checks this, but it is not part of the OpenType spec anymore
if (TableDictionary.ContainsKey("bhed"))
throw new NotSupportedException("Bitmap fonts are not supported by PDFsharp.");
// Read required tables
if (Seek(CMapTable.Tag) != -1)
cmap = new CMapTable(this);
if (Seek(ControlValueTable.Tag) != -1)
cvt = new ControlValueTable(this);
if (Seek(FontProgram.Tag) != -1)
fpgm = new FontProgram(this);
if (Seek(MaximumProfileTable.Tag) != -1)
maxp = new MaximumProfileTable(this);
if (Seek(NameTable.Tag) != -1)
name = new NameTable(this);
if (Seek(FontHeaderTable.Tag) != -1)
head = new FontHeaderTable(this);
if (Seek(HorizontalHeaderTable.Tag) != -1)
hhea = new HorizontalHeaderTable(this);
if (Seek(HorizontalMetricsTable.Tag) != -1)
hmtx = new HorizontalMetricsTable(this);
if (Seek(OS2Table.Tag) != -1)
os2 = new OS2Table(this);
if (Seek(PostScriptTable.Tag) != -1)
post = new PostScriptTable(this);
if (Seek(GlyphDataTable.Tag) != -1)
glyf = new GlyphDataTable(this);
if (Seek(IndexToLocationTable.Tag) != -1)
loca = new IndexToLocationTable(this);
if (Seek(GlyphSubstitutionTable.Tag) != -1)
gsub = new GlyphSubstitutionTable(this);
if (Seek(ControlValueProgram.Tag) != -1)
prep = new ControlValueProgram(this);
}
catch (Exception)
{
GetType();
throw;
}
}
/// <summary>
/// Creates a new font image that is a subset of this font image containing only the specified glyphs.
/// </summary>
public OpenTypeFontface CreateFontSubSet(Dictionary<int, object> glyphs, bool cidFont)
{
// Create new font image
OpenTypeFontface fontData = new OpenTypeFontface(this);
// Create new loca and glyf table
IndexToLocationTable locaNew = new IndexToLocationTable();
locaNew.ShortIndex = loca.ShortIndex;
GlyphDataTable glyfNew = new GlyphDataTable();
// Add all required tables
//fontData.AddTable(os2);
if (!cidFont)
fontData.AddTable(cmap);
if (cvt != null)
fontData.AddTable(cvt);
if (fpgm != null)
fontData.AddTable(fpgm);
fontData.AddTable(glyfNew);
fontData.AddTable(head);
fontData.AddTable(hhea);
fontData.AddTable(hmtx);
fontData.AddTable(locaNew);
if (maxp != null)
fontData.AddTable(maxp);
//fontData.AddTable(name);
if (prep != null)
fontData.AddTable(prep);
// Get closure of used glyphs.
glyf.CompleteGlyphClosure(glyphs);
// Create a sorted array of all used glyphs.
int glyphCount = glyphs.Count;
int[] glyphArray = new int[glyphCount];
glyphs.Keys.CopyTo(glyphArray, 0);
Array.Sort(glyphArray);
// Calculate new size of glyph table.
int size = 0;
for (int idx = 0; idx < glyphCount; idx++)
size += glyf.GetGlyphSize(glyphArray[idx]);
glyfNew.DirectoryEntry.Length = size;
// Create new loca table
int numGlyphs = maxp.numGlyphs;
locaNew.LocaTable = new int[numGlyphs + 1];
// Create new glyf table
glyfNew.GlyphTable = new byte[glyfNew.DirectoryEntry.PaddedLength];
// Fill new glyf and loca table
int glyphOffset = 0;
int glyphIndex = 0;
for (int idx = 0; idx < numGlyphs; idx++)
{
locaNew.LocaTable[idx] = glyphOffset;
if (glyphIndex < glyphCount && glyphArray[glyphIndex] == idx)
{
glyphIndex++;
byte[] bytes = glyf.GetGlyphData(idx);
int length = bytes.Length;
if (length > 0)
{
Buffer.BlockCopy(bytes, 0, glyfNew.GlyphTable, glyphOffset, length);
glyphOffset += length;
}
}
}
locaNew.LocaTable[numGlyphs] = glyphOffset;
// Compile font tables into byte array
fontData.Compile();
return fontData;
}
/// <summary>
/// Compiles the font to its binary representation.
/// </summary>
void Compile()
{
MemoryStream stream = new MemoryStream();
OpenTypeFontWriter writer = new OpenTypeFontWriter(stream);
int tableCount = TableDictionary.Count;
int selector = _entrySelectors[tableCount];
_offsetTable.Version = 0x00010000;
_offsetTable.TableCount = tableCount;
_offsetTable.SearchRange = (ushort)((1 << selector) * 16);
_offsetTable.EntrySelector = (ushort)selector;
_offsetTable.RangeShift = (ushort)((tableCount - (1 << selector)) * 16);
_offsetTable.Write(writer);
// Sort tables by tag name
string[] tags = new string[tableCount];
TableDictionary.Keys.CopyTo(tags, 0);
Array.Sort(tags, StringComparer.Ordinal);
#if VERBOSE
Debug.WriteLine("Start Compile");
#endif
// Write tables in alphabetical order
int tablePosition = 12 + 16 * tableCount;
for (int idx = 0; idx < tableCount; idx++)
{
TableDirectoryEntry entry = TableDictionary[tags[idx]];
#if DEBUG
if (entry.Tag == "glyf" || entry.Tag == "loca")
GetType();
#endif
entry.FontTable.PrepareForCompilation();
entry.Offset = tablePosition;
writer.Position = tablePosition;
entry.FontTable.Write(writer);
int endPosition = writer.Position;
tablePosition = endPosition;
writer.Position = 12 + 16 * idx;
entry.Write(writer);
#if VERBOSE
Debug.WriteLine(String.Format(" Write Table '{0}', offset={1}, length={2}, checksum={3}, ", entry.Tag, entry.Offset, entry.Length, entry.CheckSum));
#endif
}
#if VERBOSE
Debug.WriteLine("End Compile");
#endif
writer.Stream.Flush();
int l = (int)writer.Stream.Length;
FontSource = XFontSource.CreateCompiledFont(stream.ToArray());
}
// 2^entrySelector[n] <= n
static readonly int[] _entrySelectors = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
public int Position
{
get { return _pos; }
set { _pos = value; }
}
int _pos;
public int Seek(string tag)
{
if (TableDictionary.ContainsKey(tag))
{
_pos = TableDictionary[tag].Offset;
return _pos;
}
return -1;
}
public int SeekOffset(int offset)
{
_pos += offset;
return _pos;
}
/// <summary>
/// Reads a System.Byte.
/// </summary>
public byte ReadByte()
{
return _fontSource.Bytes[_pos++];
}
/// <summary>
/// Reads a System.Int16.
/// </summary>
public short ReadShort()
{
int pos = _pos;
_pos += 2;
return (short)((_fontSource.Bytes[pos] << 8) | (_fontSource.Bytes[pos + 1]));
}
/// <summary>
/// Reads a System.UInt16.
/// </summary>
public ushort ReadUShort()
{
int pos = _pos;
_pos += 2;
return (ushort)((_fontSource.Bytes[pos] << 8) | (_fontSource.Bytes[pos + 1]));
}
/// <summary>
/// Reads a System.Int32.
/// </summary>
public int ReadLong()
{
int pos = _pos;
_pos += 4;
return (_fontSource.Bytes[pos] << 24) | (_fontSource.Bytes[pos + 1] << 16) | (_fontSource.Bytes[pos + 2] << 8) | (_fontSource.Bytes[pos + 3]);
}
/// <summary>
/// Reads a System.UInt32.
/// </summary>
public uint ReadULong()
{
int pos = _pos;
_pos += 4;
return (uint)((_fontSource.Bytes[pos] << 24) | (_fontSource.Bytes[pos + 1] << 16) | (_fontSource.Bytes[pos + 2] << 8) | (_fontSource.Bytes[pos + 3]));
}
/// <summary>
/// Reads a System.Int32.
/// </summary>
public Fixed ReadFixed()
{
int pos = _pos;
_pos += 4;
return (_fontSource.Bytes[pos] << 24) | (_fontSource.Bytes[pos + 1] << 16) | (_fontSource.Bytes[pos + 2] << 8) | (_fontSource.Bytes[pos + 3]);
}
/// <summary>
/// Reads a System.Int16.
/// </summary>
public short ReadFWord()
{
int pos = _pos;
_pos += 2;
return (short)((_fontSource.Bytes[pos] << 8) | (_fontSource.Bytes[pos + 1]));
}
/// <summary>
/// Reads a System.UInt16.
/// </summary>
public ushort ReadUFWord()
{
int pos = _pos;
_pos += 2;
return (ushort)((_fontSource.Bytes[pos] << 8) | (_fontSource.Bytes[pos + 1]));
}
/// <summary>
/// Reads a System.Int64.
/// </summary>
public long ReadLongDate()
{
int pos = _pos;
_pos += 8;
byte[] bytes = _fontSource.Bytes;
return (((long)bytes[pos]) << 56) | (((long)bytes[pos + 1]) << 48) | (((long)bytes[pos + 2]) << 40) | (((long)bytes[pos + 3]) << 32) |
(((long)bytes[pos + 4]) << 24) | (((long)bytes[pos + 5]) << 16) | (((long)bytes[pos + 6]) << 8) | bytes[pos + 7];
}
/// <summary>
/// Reads a System.String with the specified size.
/// </summary>
public string ReadString(int size)
{
char[] chars = new char[size];
for (int idx = 0; idx < size; idx++)
chars[idx] = (char)_fontSource.Bytes[_pos++];
return new string(chars);
}
/// <summary>
/// Reads a System.Byte[] with the specified size.
/// </summary>
public byte[] ReadBytes(int size)
{
byte[] bytes = new byte[size];
for (int idx = 0; idx < size; idx++)
bytes[idx] = _fontSource.Bytes[_pos++];
return bytes;
}
/// <summary>
/// Reads the specified buffer.
/// </summary>
public void Read(byte[] buffer)
{
Read(buffer, 0, buffer.Length);
}
/// <summary>
/// Reads the specified buffer.
/// </summary>
public void Read(byte[] buffer, int offset, int length)
{
Buffer.BlockCopy(_fontSource.Bytes, _pos, buffer, offset, length);
_pos += length;
}
/// <summary>
/// Reads a System.Char[4] as System.String.
/// </summary>
public string ReadTag()
{
return ReadString(4);
}
/// <summary>
/// Gets the DebuggerDisplayAttribute text.
/// </summary>
// ReSharper disable UnusedMember.Local
internal string DebuggerDisplay
// ReSharper restore UnusedMember.Local
{
get { return string.Format(CultureInfo.InvariantCulture, "OpenType fontfaces: {0}", _fullFaceName); }
}
/// <summary>
/// Represents the font offset table.
/// </summary>
internal struct OffsetTable
{
/// <summary>
/// 0x00010000 for Version 1.0.
/// </summary>
public uint Version;
/// <summary>
/// Number of tables.
/// </summary>
public int TableCount;
/// <summary>
/// (Maximum power of 2 ≤ numTables) x 16.
/// </summary>
public ushort SearchRange;
/// <summary>
/// Log2(maximum power of 2 ≤ numTables).
/// </summary>
public ushort EntrySelector;
/// <summary>
/// NumTables x 16-searchRange.
/// </summary>
public ushort RangeShift;
/// <summary>
/// Writes the offset table.
/// </summary>
public void Write(OpenTypeFontWriter writer)
{
writer.WriteUInt(Version);
writer.WriteShort(TableCount);
writer.WriteUShort(SearchRange);
writer.WriteUShort(EntrySelector);
writer.WriteUShort(RangeShift);
}
}
}
}

View File

@@ -0,0 +1,157 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using PdfSharp.Internal;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Global table of all OpenType fontfaces cached by their face name and check sum.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay}")]
internal class OpenTypeFontfaceCache
{
OpenTypeFontfaceCache()
{
_fontfaceCache = new Dictionary<string, OpenTypeFontface>(StringComparer.OrdinalIgnoreCase);
_fontfacesByCheckSum = new Dictionary<ulong, OpenTypeFontface>();
}
/// <summary>
/// Tries to get fontface by its key.
/// </summary>
public static bool TryGetFontface(string key, out OpenTypeFontface fontface)
{
try
{
Lock.EnterFontFactory();
bool result = Singleton._fontfaceCache.TryGetValue(key, out fontface);
return result;
}
finally { Lock.ExitFontFactory(); }
}
/// <summary>
/// Tries to get fontface by its check sum.
/// </summary>
public static bool TryGetFontface(ulong checkSum, out OpenTypeFontface fontface)
{
try
{
Lock.EnterFontFactory();
bool result = Singleton._fontfacesByCheckSum.TryGetValue(checkSum, out fontface);
return result;
}
finally { Lock.ExitFontFactory(); }
}
public static OpenTypeFontface AddFontface(OpenTypeFontface fontface)
{
try
{
Lock.EnterFontFactory();
OpenTypeFontface fontfaceCheck;
if (TryGetFontface(fontface.FullFaceName, out fontfaceCheck))
{
if (fontfaceCheck.CheckSum != fontface.CheckSum)
throw new InvalidOperationException("OpenTypeFontface with same signature but different bytes.");
return fontfaceCheck;
}
Singleton._fontfaceCache.Add(fontface.FullFaceName, fontface);
Singleton._fontfacesByCheckSum.Add(fontface.CheckSum, fontface);
return fontface;
}
finally { Lock.ExitFontFactory(); }
}
/// <summary>
/// Gets the singleton.
/// </summary>
static OpenTypeFontfaceCache Singleton
{
get
{
// ReSharper disable once InvertIf
if (_singleton == null)
{
try
{
Lock.EnterFontFactory();
if (_singleton == null)
_singleton = new OpenTypeFontfaceCache();
}
finally { Lock.ExitFontFactory(); }
}
return _singleton;
}
}
static volatile OpenTypeFontfaceCache _singleton;
internal static string GetCacheState()
{
StringBuilder state = new StringBuilder();
state.Append("====================\n");
state.Append("OpenType fontfaces by name\n");
Dictionary<string, OpenTypeFontface>.KeyCollection familyKeys = Singleton._fontfaceCache.Keys;
int count = familyKeys.Count;
string[] keys = new string[count];
familyKeys.CopyTo(keys, 0);
Array.Sort(keys, StringComparer.OrdinalIgnoreCase);
foreach (string key in keys)
state.AppendFormat(" {0}: {1}\n", key, Singleton._fontfaceCache[key].DebuggerDisplay);
state.Append("\n");
return state.ToString();
}
/// <summary>
/// Maps face name to OpenType fontface.
/// </summary>
readonly Dictionary<string, OpenTypeFontface> _fontfaceCache;
/// <summary>
/// Maps font source key to OpenType fontface.
/// </summary>
readonly Dictionary<ulong, OpenTypeFontface> _fontfacesByCheckSum;
/// <summary>
/// Gets the DebuggerDisplayAttribute text.
/// </summary>
// ReSharper disable UnusedMember.Local
string DebuggerDisplay
// ReSharper restore UnusedMember.Local
{
get { return string.Format(CultureInfo.InvariantCulture, "Fontfaces: {0}", _fontfaceCache.Count); }
}
}
}

View File

@@ -0,0 +1,130 @@

#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
#define VERBOSE_
using System.Diagnostics;
//using Fixed = System.Int32;
//using FWord = System.Int16;
//using UFWord = System.UInt16;
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Represents an entry in the fonts table dictionary.
/// </summary>
internal class TableDirectoryEntry
{
/// <summary>
/// Initializes a new instance of the <see cref="TableDirectoryEntry"/> class.
/// </summary>
public TableDirectoryEntry()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="TableDirectoryEntry"/> class.
/// </summary>
public TableDirectoryEntry(string tag)
{
Debug.Assert(tag.Length == 4);
Tag = tag;
//CheckSum = 0;
//Offset = 0;
//Length = 0;
//FontTable = null;
}
/// <summary>
/// 4 -byte identifier.
/// </summary>
public string Tag;
/// <summary>
/// CheckSum for this table.
/// </summary>
public uint CheckSum;
/// <summary>
/// Offset from beginning of TrueType font file.
/// </summary>
public int Offset;
/// <summary>
/// Actual length of this table in bytes.
/// </summary>
public int Length;
/// <summary>
/// Gets the length rounded up to a multiple of four bytes.
/// </summary>
public int PaddedLength
{
get { return (Length + 3) & ~3; }
}
/// <summary>
/// Associated font table.
/// </summary>
public OpenTypeFontTable FontTable;
/// <summary>
/// Creates and reads a TableDirectoryEntry from the font image.
/// </summary>
public static TableDirectoryEntry ReadFrom(OpenTypeFontface fontData)
{
TableDirectoryEntry entry = new TableDirectoryEntry();
entry.Tag = fontData.ReadTag();
entry.CheckSum = fontData.ReadULong();
entry.Offset = fontData.ReadLong();
entry.Length = (int)fontData.ReadULong();
return entry;
}
public void Read(OpenTypeFontface fontData)
{
Tag = fontData.ReadTag();
CheckSum = fontData.ReadULong();
Offset = fontData.ReadLong();
Length = (int)fontData.ReadULong();
}
public void Write(OpenTypeFontWriter writer)
{
Debug.Assert(Tag.Length == 4);
Debug.Assert(Offset != 0);
Debug.Assert(Length != 0);
writer.WriteTag(Tag);
writer.WriteUInt(CheckSum);
writer.WriteInt(Offset);
writer.WriteUInt((uint)Length);
}
}
}

View File

@@ -0,0 +1,52 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// Identifies the technology of an OpenType font file.
/// </summary>
enum FontTechnology
{
/// <summary>
/// Font is Adobe Postscript font in CFF.
/// </summary>
PostscriptOutlines,
/// <summary>
/// Font is a TrueType font.
/// </summary>
TrueTypeOutlines,
/// <summary>
/// Font is a TrueType font collection.
/// </summary>
TrueTypeCollection
}
}

View File

@@ -0,0 +1,211 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
// ReSharper disable InconsistentNaming
namespace PdfSharp.Fonts.OpenType
{
/// <summary>
/// TrueType font table names.
/// </summary>
static class TableTagNames
{
// --- Required Tables ---
/// <summary>
/// Character to glyph mapping.
/// </summary>
public const string CMap = "cmap";
/// <summary>
/// Font header .
/// </summary>
public const string Head = "head";
/// <summary>
/// Horizontal header.
/// </summary>
public const string HHea = "hhea";
/// <summary>
/// Horizontal Metrics.
/// </summary>
public const string HMtx = "hmtx";
/// <summary>
/// Maximum profile.
/// </summary>
public const string MaxP = "maxp";
/// <summary>
/// Naming table.
/// </summary>
public const string Name = "name";
/// <summary>
/// OS/2 and Windows specific Metrics.
/// </summary>
public const string OS2 = "OS/2";
/// <summary>
/// PostScript information.
/// </summary>
public const string Post = "post";
// --- Tables Related to TrueType Outlines ---
/// <summary>
/// Control Value Table.
/// </summary>
public const string Cvt = "cvt ";
/// <summary>
/// Font program.
/// </summary>
public const string Fpgm = "fpgm";
/// <summary>
/// Glyph data.
/// </summary>
public const string Glyf = "glyf";
/// <summary>
/// Index to location.
/// </summary>
public const string Loca = "loca";
/// <summary>
/// CVT Program.
/// </summary>
public const string Prep = "prep";
// --- Tables Related to PostScript Outlines ---
/// <summary>
/// PostScript font program (compact font format).
/// </summary>
public const string Cff = "CFF";
/// <summary>
/// Vertical Origin.
/// </summary>
public const string VOrg = "VORG";
// --- Tables Related to Bitmap Glyphs ---
/// <summary>
/// Embedded bitmap data.
/// </summary>
public const string EBDT = "EBDT";
/// <summary>
/// Embedded bitmap location data.
/// </summary>
public const string EBLC = "EBLC";
/// <summary>
/// Embedded bitmap scaling data.
/// </summary>
public const string EBSC = "EBSC";
// --- Advanced Typographic Tables ---
/// <summary>
/// Baseline data.
/// </summary>
public const string BASE = "BASE";
/// <summary>
/// Glyph definition data.
/// </summary>
public const string GDEF = "GDEF";
/// <summary>
/// Glyph positioning data.
/// </summary>
public const string GPOS = "GPOS";
/// <summary>
/// Glyph substitution data.
/// </summary>
public const string GSUB = "GSUB";
/// <summary>
/// Justification data.
/// </summary>
public const string JSTF = "JSTF";
// --- Other OpenType Tables ---
/// <summary>
/// Digital signature.
/// </summary>
public const string DSIG = "DSIG";
/// <summary>
/// Grid-fitting/Scan-conversion.
/// </summary>
public const string Gasp = "gasp";
/// <summary>
/// Horizontal device Metrics.
/// </summary>
public const string Hdmx = "hdmx";
/// <summary>
/// Kerning.
/// </summary>
public const string Kern = "kern";
/// <summary>
/// Linear threshold data.
/// </summary>
public const string LTSH = "LTSH";
/// <summary>
/// PCL 5 data.
/// </summary>
public const string PCLT = "PCLT";
/// <summary>
/// Vertical device Metrics.
/// </summary>
public const string VDMX = "VDMX";
/// <summary>
/// Vertical Header.
/// </summary>
public const string VHea = "vhea";
/// <summary>
/// Vertical Metrics.
/// </summary>
public const string VMtx = "vmtx";
}
}