#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.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using PdfSharp.Fonts; #if CORE || GDI using System.Drawing; using System.Drawing.Drawing2D; using GdiFontFamily = System.Drawing.FontFamily; using GdiFont = System.Drawing.Font; using GdiFontStyle = System.Drawing.FontStyle; using GdiPrivateFontCollection = System.Drawing.Text.PrivateFontCollection; #endif #if WPF using System.Windows.Markup; using WpfFonts = System.Windows.Media.Fonts; using WpfFontFamily = System.Windows.Media.FontFamily; using WpfTypeface = System.Windows.Media.Typeface; using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; #endif namespace PdfSharp.Drawing { #if true /// /// Makes fonts that are not installed on the system available within the current application domain.
/// In Silverlight required for all fonts used in PDF documents. ///
public sealed class XPrivateFontCollection { // This one is global and can only grow. It is not possible to remove fonts that have been added. /// /// Initializes a new instance of the class. /// XPrivateFontCollection() { // HACK: Use one global PrivateFontCollection in GDI+ } #if GDI //internal PrivateFontCollection PrivateFontCollection //{ // get { return privateFontCollection; } // set { privateFontCollection = value; } //} GdiPrivateFontCollection GetPrivateFontCollection() { // Create only if really needed. if (_privateFontCollection == null) _privateFontCollection = new GdiPrivateFontCollection(); return _privateFontCollection; } // PrivateFontCollection of GDI+ private GdiPrivateFontCollection _privateFontCollection; #endif /// /// Gets the global font collection. /// internal static XPrivateFontCollection Singleton { get { return _singleton; } } internal static XPrivateFontCollection _singleton = new XPrivateFontCollection(); #if GDI /// /// Adds the font data to the font collections. /// [Obsolete("Use Add(Stream stream)")] public void AddFont(byte[] data, string familyName) { if (String.IsNullOrEmpty(familyName)) throw new ArgumentNullException("familyName"); //if (glyphTypeface == null) // throw new ArgumentNullException("glyphTypeface"); // Add to GDI+ PrivateFontCollection int length = data.Length; // Copy data without unsafe code IntPtr ip = Marshal.AllocCoTaskMem(length); Marshal.Copy(data, 0, ip, length); GetPrivateFontCollection().AddMemoryFont(ip, length); // Do not free the memory here, AddMemoryFont stores a pointer, not a copy! //Marshal.FreeCoTaskMem(ip); //privateFonts.Add(glyphTypeface); } #endif /// /// Adds the specified font data to the global PrivateFontCollection. /// Family name and style are automatically retrieved from the font. /// #if GDI [Obsolete("Use Add(Stream stream)")] #else [Obsolete("Use the GDI build of PDFsharp and use Add(Stream stream)")] #endif public static void AddFont(string filename) { throw new NotImplementedException(); //XGlyphTypeface glyphTypeface = new XGlyphTypeface(filename); //Global.AddGlyphTypeface(glyphTypeface); } #if GDI /// /// Adds the specified font data to the global PrivateFontCollection. /// Family name and style are automatically retrieved from the font. /// [Obsolete("Use Add(stream).")] public static void AddFont(Stream stream) { Add(stream); } /// /// Adds the specified font data to the global PrivateFontCollection. /// Family name and style are automatically retrieved from the font. /// public static void Add(Stream stream) { int length = (int)stream.Length; byte[] bytes = new byte[length]; stream.Read(bytes, 0, length); Add(bytes); } /// /// Adds the specified font data to the global PrivateFontCollection. /// Family name and style are automatically retrieved from the font. /// public static void Add(byte[] font) { IntPtr unmanagedPointer = Marshal.AllocCoTaskMem(font.Length); Marshal.Copy(font, 0, unmanagedPointer, font.Length); Singleton.GetPrivateFontCollection().AddMemoryFont(unmanagedPointer, font.Length); // Do not free the memory here, AddMemoryFont stores a pointer, not a copy! //Marshal.FreeCoTaskMem(ip); XFontSource fontSource = XFontSource.GetOrCreateFrom(font); string familyName = fontSource.FontName; if (familyName.EndsWith(" Regular", StringComparison.OrdinalIgnoreCase)) familyName = familyName.Substring(0, familyName.Length - 8); bool bold = fontSource.Fontface.os2.IsBold; bool italic = fontSource.Fontface.os2.IsItalic; IncompetentlyMakeAHackToFixAProblemYouWoldNeverHaveIfYouUseAFontResolver(fontSource, ref familyName, ref bold, ref italic); string key = MakeKey(familyName, bold, italic); Singleton._fontSources.Add(key, fontSource); string typefaceKey = XGlyphTypeface.ComputeKey(familyName, bold, italic); FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); } static void IncompetentlyMakeAHackToFixAProblemYouWoldNeverHaveIfYouUseAFontResolver(XFontSource fontSource, ref string familyName, ref bool bold, ref bool italic) { const string regularSuffix = " Regular"; const string boldSuffix = " Bold"; const string italicSuffix = " Italic"; const string boldItalicSuffix = " Bold Italic"; const string italicBoldSuffix = " Italic Bold"; if (familyName.EndsWith(regularSuffix, StringComparison.OrdinalIgnoreCase)) { familyName = familyName.Substring(0, familyName.Length - regularSuffix.Length); Debug.Assert(!bold && !italic); bold = italic = false; } else if (familyName.EndsWith(boldItalicSuffix, StringComparison.OrdinalIgnoreCase) || familyName.EndsWith(italicBoldSuffix, StringComparison.OrdinalIgnoreCase)) { familyName = familyName.Substring(0, familyName.Length - boldItalicSuffix.Length); Debug.Assert(bold && italic); bold = italic = true; } else if (familyName.EndsWith(boldSuffix, StringComparison.OrdinalIgnoreCase)) { familyName = familyName.Substring(0, familyName.Length - boldSuffix.Length); Debug.Assert(bold && !italic); bold = true; italic = false; } else if (familyName.EndsWith(italicSuffix, StringComparison.OrdinalIgnoreCase)) { familyName = familyName.Substring(0, familyName.Length - italicSuffix.Length); Debug.Assert(!bold && italic); bold = false; italic = true; } else { Debug.Assert(!bold && !italic); bold = false; italic = false; } } #endif /// /// Adds the specified font data to the global PrivateFontCollection. /// Family name and style are automatically retrieved from the font. /// #if GDI [Obsolete("Use Add(Stream stream)")] #else [Obsolete("Use the GDI build of PDFsharp and use Add(Stream stream)")] #endif public static void AddFont(Stream stream, string facename) { throw new NotImplementedException(); //XGlyphTypeface glyphTypeface = new XGlyphTypeface(stream, facename); //Global.AddGlyphTypeface(glyphTypeface); } // /// // /// Adds XGlyphTypeface to internal collection. // /// Family name and style are automatically retrieved from the font. // /// // void AddGlyphTypeface(XGlyphTypeface glyphTypeface) // { // string name = MakeName(glyphTypeface); // if (_typefaces.ContainsKey(name)) // throw new InvalidOperationException(PSSR.FontAlreadyAdded(glyphTypeface.DisplayName)); // _typefaces.Add(name, glyphTypeface); // //Debug.WriteLine("Font added: " + name); //#if GDI // // Add to GDI+ PrivateFontCollection singleton. // byte[] data = glyphTypeface.Fontface.FontSource.Bytes; // int length = data.Length; // IntPtr ip = Marshal.AllocCoTaskMem(length); // Marshal.Copy(data, 0, ip, length); // _privateFontCollection.AddMemoryFont(ip, length); // // Do not free the memory here, AddMemoryFont stores a pointer, not a copy! // // Marshal.FreeCoTaskMem(ip); //#endif //#if WPF //#endif // } #if WPF /// /// Initializes a new instance of the FontFamily class from the specified font family name and an optional base uniform resource identifier (URI) value. /// Sample: Add(new Uri("pack://application:,,,/"), "./myFonts/#FontFamilyName");) /// /// Specifies the base URI that is used to resolve familyName. /// The family name or names that comprise the new FontFamily. Multiple family names should be separated by commas. public static void Add(Uri baseUri, string familyName) { Uri uri = new Uri("pack://application:,,,/"); // TODO: What means 'Multiple family names should be separated by commas.'? // does not work if (String.IsNullOrEmpty(familyName)) throw new ArgumentNullException("familyName"); if (familyName.Contains(",")) throw new NotImplementedException("Only one family name is supported."); // Family name starts right of '#'. int idxHash = familyName.IndexOf('#'); if (idxHash < 0) throw new ArgumentException("Family name must contain a '#'. Example './#MyFontFamilyName'", "familyName"); string key = familyName.Substring(idxHash + 1); if (String.IsNullOrEmpty(key)) throw new ArgumentException("familyName has invalid format."); if (Singleton._fontFamilies.ContainsKey(key)) throw new ArgumentException("An entry with the specified family name already exists."); #if !SILVERLIGHT #if DEBUG_ foreach (WpfFontFamily fontFamily1 in WpfFonts.GetFontFamilies(baseUri, familyName)) { ICollection wpfTypefaces = fontFamily1.GetTypefaces(); wpfTypefaces.GetType(); } #endif // Create WPF font family. WpfFontFamily fontFamily = new WpfFontFamily(baseUri, familyName); //System.Windows.Media.FontFamily x; // Required for new Uri("pack://application:,,,/") // ReSharper disable once ObjectCreationAsStatement // new System.Windows.Application(); #else System.Windows.Media.FontFamily fontFamily = new System.Windows.Media.FontFamily(familyName); #endif // Check whether font data really exists #if DEBUG && !SILVERLIGHT ICollection list = fontFamily.GetTypefaces(); foreach (WpfTypeface typeFace in list) { Debug.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}", familyName, typeFace.FaceNames[FontHelper.XmlLanguageEnUs], typeFace.Style, typeFace.Weight, typeFace.Stretch)); WpfGlyphTypeface glyphTypeface; if (!typeFace.TryGetGlyphTypeface(out glyphTypeface)) { Debug.WriteLine(" Glyph typeface does not exists."); //throw new ArgumentException("Font with the specified family name does not exist."); } } #endif Singleton._fontFamilies.Add(key, fontFamily); } #endif //internal static XGlyphTypeface TryGetXGlyphTypeface(string familyName, XFontStyle style) //{ // string name = MakeName(familyName, style); // XGlyphTypeface typeface; // _global._typefaces.TryGetValue(name, out typeface); // return typeface; //} #if GDI internal static GdiFont TryCreateFont(string name, double size, GdiFontStyle style, out XFontSource fontSource) { fontSource = null; try { GdiPrivateFontCollection pfc = Singleton._privateFontCollection; if (pfc == null) return null; #if true string key = MakeKey(name, (XFontStyle)style); if (Singleton._fontSources.TryGetValue(key, out fontSource)) { GdiFont font = new GdiFont(name, (float)size, style, GraphicsUnit.World); #if DEBUG_ Debug.Assert(StringComparer.OrdinalIgnoreCase.Compare(name, font.Name) == 0); Debug.Assert(font.Bold == ((style & GdiFontStyle.Bold) != 0)); Debug.Assert(font.Italic == ((style & GdiFontStyle.Italic) != 0)); #endif return font; } return null; #else foreach (GdiFontFamily family in pfc.Families) { if (string.Compare(family.Name, name, StringComparison.OrdinalIgnoreCase) == 0) { GdiFont font = new GdiFont(family, (float)size, style, GraphicsUnit.World); if (string.Compare(font.Name, name, StringComparison.OrdinalIgnoreCase) != 0) { // Style simulation is not implemented in GDI+. // Use WPF build. } return font; } } #endif } catch (Exception ex) { // Ignore exception and return null. Debug.WriteLine(ex.ToString()); } return null; } #endif #if WPF && !SILVERLIGHT internal static WpfTypeface TryCreateTypeface(string name, XFontStyle style, out WpfFontFamily fontFamily) { if (Singleton._fontFamilies.TryGetValue(name, out fontFamily)) { WpfTypeface typeface = FontHelper.CreateTypeface(fontFamily, style); return typeface; } return null; } #endif static string MakeKey(string familyName, XFontStyle style) { return MakeKey(familyName, (style & XFontStyle.Bold) != 0, (style & XFontStyle.Italic) != 0); } static string MakeKey(string familyName, bool bold, bool italic) { return familyName + "#" + (bold ? "b" : "") + (italic ? "i" : ""); } readonly Dictionary _typefaces = new Dictionary(); #if GDI //List privateFonts = new List(); readonly Dictionary _fontSources = new Dictionary(StringComparer.OrdinalIgnoreCase); #endif #if WPF readonly Dictionary _fontFamilies = new Dictionary(StringComparer.OrdinalIgnoreCase); #endif } #endif }