FontFallbacks.cs
// 
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
// 
using System;
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos.Basics
{
    // フォールバックフォントは、アプリケーションで指定されたフォントには
    // 存在しないグリフを描画するために使用されるフォントです。
    // DsPdf は自動的に初期化されるフォールバックフォントファミリの
    // デフォルトリストを提供し、一般的なフォントにはグリフがない多くの
    // 言語のフォールバックとして使用するのに適した大きなフォントを含みます。
    // これらの自動的に追加されたフォールバックフォントファミリは、
    // FontCollection.SystemFonts 静的コレクションのメソッドを介して使用
    // できます。
    // 独自のフォールバックフォントを用意し、グローバル FontCollection.SystemFonts
    // によって管理されるフォールバックに追加することで、デフォルト
    // (およびシステム依存)の動作をカスタマイズできます。また、それらを
    // FontCollection の独自のインスタンス、あるいは使用している特定の
    // フォントに追加することによって実現することもできます。
    // このように、フォールバックフォントの振る舞いを細かく調整し、完全に
    // システムに依存しないようにすることができます。
    // 
    // このサンプルでは、フォールバックの基本的な動作(システムフォール
    // バックのクリアと再追加)について説明します。
    // さらに、現在のシステムで見つかったフォールバックフォントのリストを
    // 出力します。
    public class FontFallbacks
    {
        public int CreatePDF(Stream stream)
        {
            // GcPdfDocument のセットアップ。
            var doc = new GcPdfDocument();
            var g = doc.NewPage().Graphics;

            // テキスト行を描画するためのヘルパー変数をいくつか設定します。
            const float margin = 36;
            // テキストの挿入位置(デフォルト解像度は 72 dpi、1/2 インチの余白を使用)。
            var ip = new PointF(margin, margin);
            // 標準フォントの1つでテキスト形式を初期化します。 標準フォントは最小であり、
            // ラテン文字以外の文字に対しては非常に少数のグリフしか含まれません。
            var tf = new TextFormat() { Font = StandardFonts.Courier, FontSize = 14 };

            // フォールバックフォントファミリのリストを取得します。
            string[] fallbacks = FontCollection.SystemFonts.GetFallbackFontFamilies();

            // グローバルフォールバックフォントリストをクリアします。
            FontCollection.SystemFonts.ClearFallbackFontFamilies();
            FontCollection.SystemFonts.ClearFallbackFonts();

            // 現在、グローバルなフォールバックフォントは存在しないため、
            // 標準フォントを使用して作成された日本語テキストでは、実際の日本語文字の代わりに
            // 「空白ボックス」が作成されます。
            g.DrawString("A Japanese text that won't render: この日本語は表示されません", tf, ip);
            ip.Y += 36;

            // フォールバックフォントファミリの元のリストをグローバル SystemFonts に再追加します。
            FontCollection.SystemFonts.AppendFallbackFontFamilies(fallbacks);
            // いくつかのシステムでは、デフォルトのシステムフォールバックは日本語の字形を
            // 提供しない可能性があるので、独自のフォールバックを追加します:
            var arialuni = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "arialuni.ttf"));
            FontCollection.SystemFonts.AppendFallbackFonts(arialuni);

            // フォールバックフォントが再び利用できるようになったので、適切なフォールバックが見つかると、
            // 同じ日本語のテキストが正しくレンダリングされます。
            g.DrawString("Same text with fallbacks available: この日本語は表示されます", tf, ip);
            ip.Y += 36;

            // 最後に、すべてのフォールバックを列挙し、それぞれを使ってテストラインを出力します。
            Action<string> drawTestLine = (fnt_) =>
            {
                var tf1 = new TextFormat() { FontName = fnt_ };
                var tstr = $"{fnt_}: The quick brown fox jumps over the lazy dog.";
                var s = g.MeasureString(tstr, tf1, doc.PageSize.Width - margin * 2);
                g.DrawString(tstr, tf1, new RectangleF(ip, s));
                ip.Y += s.Height * 1.5f;
                if (ip.Y > doc.Pages.Last.Size.Height - margin * 2)
                {
                    g = doc.NewPage().Graphics;
                    ip.Y = 36;
                }
            };
            foreach (var fnt in fallbacks)
                drawTestLine(fnt);

            // PDF ドキュメントを保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}