diff --git a/PdfSharpCore/Internal/FontFamilyModel.cs b/PdfSharpCore/Internal/FontFamilyModel.cs index 02d326c9..98afde81 100644 --- a/PdfSharpCore/Internal/FontFamilyModel.cs +++ b/PdfSharpCore/Internal/FontFamilyModel.cs @@ -6,7 +6,6 @@ namespace PdfSharpCore.Internal public class FontFamilyModel { public string Name { get; set; } - public Dictionary FontFiles = new Dictionary(); public bool IsStyleAvailable(XFontStyle fontStyle) diff --git a/PdfSharpCore/Utils/FontFileInfo.cs b/PdfSharpCore/Utils/FontFileInfo.cs new file mode 100644 index 00000000..3ab08d57 --- /dev/null +++ b/PdfSharpCore/Utils/FontFileInfo.cs @@ -0,0 +1,38 @@ +using PdfSharpCore.Drawing; +using SixLabors.Fonts; + +namespace PdfSharpCore.Utils +{ + internal struct FontFileInfo + { + private FontFileInfo(string path, FontDescription fontDescription) + { + Path = path; + FontDescription = fontDescription; + } + + public string Path { get; } + public FontDescription FontDescription { get; } + public string FamilyName => FontDescription.FontFamilyInvariantCulture; + + public XFontStyle GuessFontStyle() + { + switch (FontDescription.Style) + { + case FontStyle.Bold: + return XFontStyle.Bold; + case FontStyle.Italic: + return XFontStyle.Italic; + case FontStyle.BoldItalic: + return XFontStyle.BoldItalic; + default: + return XFontStyle.Regular; + } + } + public static FontFileInfo Load(string path) + { + var fontDescription = FontDescription.LoadDescription(path); + return new FontFileInfo(path, fontDescription); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore/Utils/FontResolver.cs b/PdfSharpCore/Utils/FontResolver.cs index f233a7d0..2494619d 100644 --- a/PdfSharpCore/Utils/FontResolver.cs +++ b/PdfSharpCore/Utils/FontResolver.cs @@ -1,232 +1,214 @@ - -using System.Linq; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Collections.Generic; - -using PdfSharpCore.Internal; -using PdfSharpCore.Drawing; +using PdfSharpCore.Drawing; using PdfSharpCore.Fonts; - -using SixLabors.Fonts; - +using PdfSharpCore.Internal; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; namespace PdfSharpCore.Utils { - - - public class FontResolver - : IFontResolver + public class FontResolver : IFontResolver { - public string DefaultFontName => "Arial"; - - private static readonly Dictionary InstalledFonts = new Dictionary(); + private static bool _isInitialized; - private static readonly string[] SSupportedFonts; + private static readonly List installedFonts = new List(); + private static string[] installedFontFilePaths; public FontResolver() { - } - - static FontResolver() - { - string fontDir; - - bool isOSX = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX); - if (isOSX) + if(_isInitialized) { - fontDir = "/Library/Fonts/"; - SSupportedFonts = System.IO.Directory.GetFiles(fontDir, "*.ttf", System.IO.SearchOption.AllDirectories); - SetupFontsFiles(SSupportedFonts); return; } - bool isLinux = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux); - if (isLinux) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - SSupportedFonts = LinuxSystemFontResolver.Resolve(); - SetupFontsFiles(SSupportedFonts); - return; + installedFontFilePaths = LoadWindowsFonts(); } - - bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows); - if (isWindows) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - fontDir = System.Environment.ExpandEnvironmentVariables(@"%SystemRoot%\Fonts"); - var fontPaths = new List(); - - var systemFontPaths = System.IO.Directory.GetFiles(fontDir, "*.ttf", System.IO.SearchOption.AllDirectories); - fontPaths.AddRange(systemFontPaths); - - var appdataFontDir = System.Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Microsoft\Windows\Fonts"); - if(System.IO.Directory.Exists(appdataFontDir)) - { - var appdataFontPaths = System.IO.Directory.GetFiles(appdataFontDir, "*.ttf", System.IO.SearchOption.AllDirectories); - fontPaths.AddRange(appdataFontPaths); - } - - SSupportedFonts = fontPaths.ToArray(); - SetupFontsFiles(SSupportedFonts); - return; + installedFontFilePaths = LoadOSXFonts(); } - - throw new System.NotImplementedException("FontResolver not implemented for this platform (PdfSharpCore.Utils.FontResolver.cs)."); - } - - - private readonly struct FontFileInfo - { - private FontFileInfo(string path, FontDescription fontDescription) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - this.Path = path; - this.FontDescription = fontDescription; + installedFontFilePaths = LinuxSystemFontResolver.Resolve(); + } + else + { + throw new NotImplementedException($"FontResolver not implemented for this platform (PdfSharpCore.Utils.FontResolver.cs)."); } - public string Path { get; } - - public FontDescription FontDescription { get; } + SetupFontFiles(); - public string FamilyName => this.FontDescription.FontFamilyInvariantCulture; + _isInitialized = true; + } + public string DefaultFontName => "Arial"; + public bool NullIfFontNotFound { get; set; } = false; - public XFontStyle GuessFontStyle() + public virtual byte[] GetFont(string faceName) + { + using (var ms = new MemoryStream()) { - switch (this.FontDescription.Style) + var fontFilepath = string.Empty; + try + { + var fontFileName = Path.GetFileName(faceName).ToLower(); + fontFilepath = installedFontFilePaths + .First(x => x.ToLower().Contains(fontFileName)); + + if (File.Exists(fontFilepath)) + { + using (var fileStream = File.OpenRead(fontFilepath)) + { + fileStream.CopyTo(ms); + ms.Position = 0; + return ms.ToArray(); + } + } + else + { + throw new FileNotFoundException(fontFilepath); + } + } + catch (Exception) { - case FontStyle.Bold: - return XFontStyle.Bold; - case FontStyle.Italic: - return XFontStyle.Italic; - case FontStyle.BoldItalic: - return XFontStyle.BoldItalic; - default: - return XFontStyle.Regular; + throw new Exception($"Font file with name {faceName} and path {fontFilepath} not found."); } } - - public static FontFileInfo Load(string path) + } + public virtual FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) + { + if (installedFonts.Count == 0) { - FontDescription fontDescription = FontDescription.LoadDescription(path); - return new FontFileInfo(path, fontDescription); + throw new FileNotFoundException("No Fonts installed on this device!"); } - } - - public static void SetupFontsFiles(string[] sSupportedFonts) - { - List tempFontInfoList = new List(); - foreach (string fontPathFile in sSupportedFonts) + var fontFamily = installedFonts.Find(x => x.Name.ToLower().Equals(familyName.ToLower())); + if (fontFamily != null) { - try + if (isBold && isItalic) { - FontFileInfo fontInfo = FontFileInfo.Load(fontPathFile); - Debug.WriteLine(fontPathFile); - tempFontInfoList.Add(fontInfo); + if (fontFamily.FontFiles.TryGetValue(XFontStyle.BoldItalic, out string boldItalicFile)) + { + return new FontResolverInfo(Path.GetFileName(boldItalicFile)); + } } - catch (System.Exception e) + else if (isBold) { - System.Console.Error.WriteLine(e); + if (fontFamily.FontFiles.TryGetValue(XFontStyle.Bold, out string boldFile)) + { + return new FontResolverInfo(Path.GetFileName(boldFile)); + } } - } - - // Deserialize all font families - foreach (IGrouping familyGroup in tempFontInfoList.GroupBy(info => info.FamilyName)) - try + else if (isItalic) { - string familyName = familyGroup.Key; - FontFamilyModel family = DeserializeFontFamily(familyName, familyGroup); - InstalledFonts.Add(familyName.ToLower(), family); + if (fontFamily.FontFiles.TryGetValue(XFontStyle.Italic, out string italicFile)) + { + return new FontResolverInfo(Path.GetFileName(italicFile)); + } } - catch (System.Exception e) + + if (fontFamily.FontFiles.TryGetValue(XFontStyle.Regular, out string regularFile)) { - System.Console.Error.WriteLine(e); + return new FontResolverInfo(Path.GetFileName(regularFile)); } - } + return new FontResolverInfo(Path.GetFileName(fontFamily.FontFiles.First().Value)); + } - [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] - private static FontFamilyModel DeserializeFontFamily(string fontFamilyName, IEnumerable fontList) + if (NullIfFontNotFound) + { + return null; + } + + var firstFontPath = installedFonts.First().FontFiles.First().Value; + return new FontResolverInfo(Path.GetFileName(firstFontPath)); + } + + private static string[] LoadOSXFonts() + { + var fontDirectory = "/Library/Fonts/"; + return Directory.GetFiles(fontDirectory, "*.ttf", SearchOption.AllDirectories); + } + private static string[] LoadWindowsFonts() { - FontFamilyModel font = new FontFamilyModel { Name = fontFamilyName }; + var fontPaths = new List(); - // there is only one font - if (fontList.Count() == 1) - font.FontFiles.Add(XFontStyle.Regular, fontList.First().Path); - else + var systemFontPath = @"%SystemRoot%\Fonts"; + var localAppDataFontPath = @"%LOCALAPPDATA%\Microsoft\Windows\Fonts"; + + var systemFontDirectory = Environment.ExpandEnvironmentVariables(systemFontPath); + var systemFontPaths = Directory.GetFiles(systemFontDirectory, "*.ttf", SearchOption.AllDirectories); + fontPaths.AddRange(systemFontPaths); + + var appdataFontDirectory = Environment.ExpandEnvironmentVariables(localAppDataFontPath); + if (Directory.Exists(appdataFontDirectory)) { - foreach (FontFileInfo info in fontList) - { - XFontStyle style = info.GuessFontStyle(); - if (!font.FontFiles.ContainsKey(style)) - font.FontFiles.Add(style, info.Path); - } + var appdataFontPaths = Directory.GetFiles(appdataFontDirectory, "*.ttf", SearchOption.AllDirectories); + fontPaths.AddRange(appdataFontPaths); } - return font; + return fontPaths.ToArray(); } - - public virtual byte[] GetFont(string faceFileName) + private static void SetupFontFiles() { - using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) + var fontFiles = new List(); + foreach (var fontFilePath in installedFontFilePaths) { - string ttfPathFile = ""; try { - ttfPathFile = SSupportedFonts.ToList().First(x => x.ToLower().Contains( - System.IO.Path.GetFileName(faceFileName).ToLower()) - ); - - using (System.IO.Stream ttf = System.IO.File.OpenRead(ttfPathFile)) - { - ttf.CopyTo(ms); - ms.Position = 0; - return ms.ToArray(); - } + var fontFileInfo = FontFileInfo.Load(fontFilePath); + fontFiles.Add(fontFileInfo); } - catch (System.Exception e) + catch (Exception e) { - System.Console.WriteLine(e); - throw new System.Exception("No Font File Found - " + faceFileName + " - " + ttfPathFile); + Console.Error.WriteLine(e); } } - } - - public bool NullIfFontNotFound { get; set; } = false; - public virtual FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) - { - if (InstalledFonts.Count == 0) - throw new System.IO.FileNotFoundException("No Fonts installed on this device!"); - - if (InstalledFonts.TryGetValue(familyName.ToLower(), out FontFamilyModel family)) + foreach (var familyGroup in fontFiles.GroupBy(info => info.FamilyName)) { - if (isBold && isItalic) + try { - if (family.FontFiles.TryGetValue(XFontStyle.BoldItalic, out string boldItalicFile)) - return new FontResolverInfo(System.IO.Path.GetFileName(boldItalicFile)); + var familyName = familyGroup.Key; + FontFamilyModel family = DeserializeFontFamily(familyName, familyGroup); + installedFonts.Add(family); } - else if (isBold) + catch (Exception e) { - if (family.FontFiles.TryGetValue(XFontStyle.Bold, out string boldFile)) - return new FontResolverInfo(System.IO.Path.GetFileName(boldFile)); + Console.Error.WriteLine(e); } - else if (isItalic) + } + } + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + private static FontFamilyModel DeserializeFontFamily(string familyName, IEnumerable fontFiles) + { + var fontFamilyModel = new FontFamilyModel + { + Name = familyName + }; + + if (fontFiles.Count() == 1) + { + fontFamilyModel.FontFiles.Add(XFontStyle.Regular, fontFiles.First().Path); + } + else + { + foreach (var info in fontFiles) { - if (family.FontFiles.TryGetValue(XFontStyle.Italic, out string italicFile)) - return new FontResolverInfo(System.IO.Path.GetFileName(italicFile)); + var style = info.GuessFontStyle(); + if (!fontFamilyModel.FontFiles.ContainsKey(style)) + { + fontFamilyModel.FontFiles.Add(style, info.Path); + } } - - if (family.FontFiles.TryGetValue(XFontStyle.Regular, out string regularFile)) - return new FontResolverInfo(System.IO.Path.GetFileName(regularFile)); - - return new FontResolverInfo(System.IO.Path.GetFileName(family.FontFiles.First().Value)); } - if (NullIfFontNotFound) - return null; - - string ttfFile = InstalledFonts.First().Value.FontFiles.First().Value; - return new FontResolverInfo(System.IO.Path.GetFileName(ttfFile)); + return fontFamilyModel; } } }