Git Product home page Git Product logo

Comments (9)

2mik avatar 2mik commented on May 27, 2024 1

Thank you. I used NewFontResolver as an example to develop CustomFontResolver. The key difference is that NewFontResolver contains the predefined list of fonts, while CustomFontResolver can load any existing font.

from pdfsharp.

ThomasHoevel avatar ThomasHoevel commented on May 27, 2024
  1. Getting a warning when building with the "Arial" font called, possibly all fonts.
    info: PdfSharp.Snippets.Font.FailsafeFontResolver[0] 'Arial' bold was substituted by a SegoeWP font.

You use a FontResolver that uses SegoeWP for every unknown font (including Arial). It's a feature, not a bug. If you want Arial, then use a font resolver that supports Arial.

  1. Vertical spacing of fonts doesn't seem to be correct. Spacing slightly favors the bottom.

Looks correct. Fonts need room for dots and accents above the letters ("ÄÖÜÁÀ").
There also is gfx.MeasureString.
See also:
http://pdfsharp.net/wiki/TextLayout-sample.ashx
https://github.com/empira/PDFsharp/blob/master/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Layout/XTextFormatter.cs

from pdfsharp.

nepgituser avatar nepgituser commented on May 27, 2024

Thanks for the detailed explanation. The "Arial" font issue was fixed by implementing IFontResolver. Don't generally use fonts like that, so didn't think about it. Makes sense though. That said, "Arial" doesn't seem to leave as much spacing. At any rate, thank you!

from pdfsharp.

2mik avatar 2mik commented on May 27, 2024

Hello,

Thank you for your work of porting the libs to .NET6.
Could you provide an example how to "use a font resolver that supports Arial" ?
Even the example that uses Arial actually creates a document with the Segoe font. I've tested the example on Windows 11, Arial is installed.

FailsafeFontResolver also tries to load the specified font before Segoe. Despite that, Arial was not loaded.

font

from pdfsharp.

ThomasHoevel avatar ThomasHoevel commented on May 27, 2024

Could you provide an example how to "use a font resolver that supports Arial"?

A good place to ask this question would be the PDFsharp support forum.

There you can find the EZFontResolver sample:
https://forum.pdfsharp.net/viewtopic.php?f=8&t=3244

And this IFontResolver sample:
https://forum.pdfsharp.net/viewtopic.php?f=8&t=3073

In the PDFsharp source code you can find this sample:
https://github.com/empira/PDFsharp/blob/master/src/foundation/src/shared/src/PdfSharp.Snippets/Font/fontresolving/ExoticFontsFontResolver.cs
https://github.com/empira/PDFsharp/blob/master/src/foundation/src/shared/src/PdfSharp.Snippets/Font/fontresolving/ExoticFontsDataHelper.cs
https://github.com/empira/PDFsharp/blob/master/src/foundation/src/shared/src/PdfSharp.Snippets/Font/fontresolving/ExoticFontResolverSnippet.cs

I admit that these samples do not use "Arial", but replacing "ubuntu" by "Arial" is left as an exercise to the reader.

from pdfsharp.

2mik avatar 2mik commented on May 27, 2024

Thank you.
If anyone is interested, topic is continued here

from pdfsharp.

2mik avatar 2mik commented on May 27, 2024

Just for information, this and this links describe the approach for solving the similar font problem, used by ClosedXML library that generates Excel workbooks.

from pdfsharp.

2mik avatar 2mik commented on May 27, 2024

This font resolver might be useful to someone:

#nullable disable

using PdfSharp.Fonts;
using PdfSharp.Snippets.Font;
using PdfSharp.WPFonts;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PdfSharpTest
{
    public class CustomFontResolver : IFontResolver
    {
        /// <summary>
        /// Identifies a font.
        /// </summary>
        private readonly record struct FontKey(
            string FamilyName,
            bool IsBold,
            bool IsItalic)
        {
            public string GetFaceName() =>
                (string.IsNullOrEmpty(FamilyName) ? "Empty" : FamilyName) +
                (IsBold ? "-Bold" : "") +
                (IsItalic ? "-Italic" : "");
        };

        /// <summary>
        /// Represents information associated with a font.
        /// </summary>
        private class FontMeta
        {
            public string FileName { get; init; }
        }

        /// <summary>
        /// Specifies how to search for the font.
        /// </summary>
        private static readonly EnumerationOptions FontSearchOptions = new()
        {
            RecurseSubdirectories = true,
            MatchCasing = MatchCasing.CaseInsensitive,
            AttributesToSkip = 0,
            IgnoreInaccessible = true
        };


        private readonly SegoeWpFontResolver fallbackFontResolver;
        private readonly Dictionary<string, FontMeta> fontsByFace;


        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        public CustomFontResolver()
        {
            fallbackFontResolver = new SegoeWpFontResolver();
            fontsByFace = new Dictionary<string, FontMeta>();
        }


        /// <summary>
        /// Finds the specified font in the file system.
        /// </summary>
        private static FontResolverInfo FindFont(FontKey fontKey, out string fileName)
        {
            if (string.IsNullOrEmpty(fontKey.FamilyName))
            {
                fileName = "";
                return null;
            }

            try
            {
                ICollection<string> fontDirectories = GetFontDirectories();
                ICollection<string> desiredNames = GetDesiredNames(fontKey);
                ICollection<string> candidateNames = GetCandidateNames(fontKey);
                FileInfo candidateFileInfo = null;

                foreach (string fontDirectory in fontDirectories)
                {
                    if (!Directory.Exists(fontDirectory))
                        continue;

                    foreach (FileInfo fileInfo in new DirectoryInfo(fontDirectory)
                        .EnumerateFiles(fontKey.FamilyName + "*.ttf", FontSearchOptions))
                    {
                        if (desiredNames.Any(name => name.Equals(fileInfo.Name, StringComparison.OrdinalIgnoreCase)))
                        {
                            fileName = fileInfo.FullName;
                            return new FontResolverInfo(fontKey.GetFaceName(), false, false);
                        }

                        if (candidateFileInfo == null &&
                            candidateNames.Any(name => name.Equals(fileInfo.Name, StringComparison.OrdinalIgnoreCase)))
                        {
                            candidateFileInfo = fileInfo;
                        }
                    }
                }

                if (candidateFileInfo != null)
                {
                    fileName = candidateFileInfo.FullName;
                    return new FontResolverInfo(fontKey.GetFaceName(), fontKey.IsBold, fontKey.IsItalic);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }

            fileName = "";
            return null;
        }

        /// <summary>
        /// Gets the font directories depending on the OS.
        /// </summary>
        private static ICollection<string> GetFontDirectories()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return new string[]
                {
                    @"C:\Windows\Fonts\",
                    Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                        @"Microsoft\Windows\Fonts")
                };
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return new string[]
                {
                    "/usr/share/fonts/truetype/"
                };
            }
            else
            {
                return Array.Empty<string>();
            }
        }

        /// <summary>
        /// Gets desired font file names.
        /// </summary>
        private static ICollection<string> GetDesiredNames(FontKey fontKey)
        {
            if (fontKey.IsBold && fontKey.IsItalic)
            {
                return new string[]
                {
                    fontKey.FamilyName + "bi.ttf",
                    fontKey.FamilyName + "-BoldItalic.ttf",
                    fontKey.FamilyName + "-BoldOblique.ttf"
                };
            }
            else if (fontKey.IsBold)
            {
                return new string[]
                {
                    fontKey.FamilyName + "bd.ttf",
                    fontKey.FamilyName + "-Bold.ttf"
                };
            }
            else if (fontKey.IsItalic)
            {
                return new string[]
                {
                    fontKey.FamilyName + "i.ttf",
                    fontKey.FamilyName + "-Italic.ttf",
                    fontKey.FamilyName + "-Oblique.ttf"
                };
            }
            else
            {
                return new string[]
                {
                    fontKey.FamilyName + ".ttf",
                    fontKey.FamilyName + "-Regular.ttf"
                };
            }
        }

        /// <summary>
        /// Gets possible font file names.
        /// </summary>
        private static ICollection<string> GetCandidateNames(FontKey fontKey)
        {
            if (fontKey.IsBold || fontKey.IsItalic)
            {
                return new string[]
                {
                    fontKey.FamilyName + ".ttf",
                    fontKey.FamilyName + "-Regular.ttf"
                };
            }
            else
            {
                return Array.Empty<string>();
            }
        }


        /// <summary>
        /// Converts specified information about a required typeface into a specific font.
        /// </summary>
        /// <remarks>
        /// PDFsharp calls ResolveTypeface only once for each unique combination of familyName, isBold, and isItalic.
        /// </remarks>
        public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
        {
            FontKey fontKey = new(familyName, isBold, isItalic);
            FontResolverInfo resolverInfo =
                FindFont(fontKey, out string fileName) ??
                fallbackFontResolver.ResolveTypeface(isBold
                    ? SegoeWpFontResolver.FamilyNames.SegoeWPBold
                    : SegoeWpFontResolver.FamilyNames.SegoeWP,
                    false, isItalic) ??
                new FontResolverInfo(fontKey.GetFaceName(), isBold, isItalic);

            fontsByFace[resolverInfo.FaceName] = new FontMeta { FileName = fileName };
            return resolverInfo;
        }

        /// <summary>
        /// Gets the bytes of a physical font with specified face name.
        /// </summary>
        /// <remarks>
        /// A face name previously retrieved by ResolveTypeface.
        /// PDFsharp never calls GetFont twice with the same face name.
        /// </remarks>
        public byte[] GetFont(string faceName)
        {
            try
            {
                if (fontsByFace.TryGetValue(faceName, out FontMeta fontMeta))
                {
                    byte[] font = string.IsNullOrEmpty(fontMeta.FileName)
                        ? fallbackFontResolver.GetFont(faceName)
                        : File.ReadAllBytes(fontMeta.FileName);

                    if (font != null)
                        return font;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }

            return FontDataHelper.SegoeWP;
        }
    }
}

from pdfsharp.

ThomasHoevel avatar ThomasHoevel commented on May 27, 2024

This font resolver might be useful to someone:

The NewFontResolver that comes with PDFsharp might be useful, too. It was tested with Windows and Linux, but not with MacOS.
See:
src/foundation/src/shared/src/PdfSharp.Snippets/Font/fontresolving/NewFontResolver.cs

The name might change with future releases of PDFsharp.

from pdfsharp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.