CMapResources.cs
// 
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// Copyright (c) GrapeCity inc. All rights reserved.
// 
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;

namespace GcPdfWeb.Samples
{
    // このサンプルは ExtractText サンプルと同じですが、GcPdf に
    // 組み込まれていない、あまり一般的ではない Cmap を使用するPDF を読み込みます。
    // なお、そのような CMap の多くは、オプションの GrapeCity.Documents.Pdf.Resources 
    // パッケージによって提供されています。このパッケージは GcPdf によって自動的
    // には参照されませんが、(このサンプルのように)プロジェクトに追加することで、
    // GcPdfDocument の静的コンストラクタにて自動的に取得され、追加の Cmap が利用
    // 可能になります。
    // 
    // このサンプルで使用されている ExternalCMapTest.pdf には、さほど一般的ではない
    // CMapの1つを使用してエンコードされたテキストが含まれています。
    // GrapeCity.Documents.Pdf.Resources を参照すると、GetText() メソッドを使用して
    // その PDF からテキストを取得できます。
    // このサンプルをダウンロードして、GrapeCity.Documents.Pdf.Resources への参照を
    // 削除すると、サンプルはビルドされて実行されますが、テキストを抽出することは
    // できません。
    // 
    // 必要に応じて、静的な GcPdfDocument.CMapProvider プロパティを使用して、任意の
    // CMap を GcPdf で利用することができます。
    //     
    public class CMapResources
    {
        public int CreatePDF(Stream stream)
        {
            const string pdfName = "ExternalCMapTest.pdf";

            // 起動時に GcPdfDocument クラスのコンストラクタによって 
            // GrapeCity.Documents.Pdf.Resources.dll が検出される場合、以下の行は必要ありません
            // (これはアプリケーションの展開方法によって異なります)。
            GcPdfDocument.CMapProvider = CMapProvider.Instance;

            GcPdfDocument doc = new GcPdfDocument();
            var page = doc.NewPage();

            var rc = Common.Util.AddNote("このサンプルは、PDF を一時的な GcPdfDocument に読み込み、" +
                "Page.GetText() メソッドを使用して読み込まれたドキュメントの各ページからすべてのテキストを取得し、" +
                "それらすべてのテキストを TextLayout に追加して現在のドキュメントにレンダリングします。 " +
                "このサンプルでPDFによって使用されるCMapは、以下のオプションパッケージによって提供されます。 " +
                "https://www.nuget.org/packages/GrapeCity.DioDocs.Pdf.Resources.ja/ " +
                "特定のPDFのテキストのほとんどは、GcPdf自体に組み込まれていないあまり一般的でないCMapを使用して" +
                "いるため、このパッケージを参照しないとそれらが見つかりません。" +
                "\n\n" +
                "プロジェクトで GrapeCity.Documents.Pdf.Resources を使用するには、アセンブリへの参照を追加し、" +
                "GrapeCity.Documents.Pdf.Resources.dll がランタイムディレクトリに存在することを確認するか、" +
                "プロジェクトの初期化コードに以下の行を追加します。" +
                "\n\tGcPdfDocument.CMapProvider = CMapProvider.Instance;",
                page);

            Font arialbd = Font.FromFile(Path.Combine("Resources", "Fonts", "arialbd.ttf"));
            Font segoe = Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf"));
            Font arialuni = Font.FromFile(Path.Combine("Resources", "Fonts", "arialuni.ttf"));
            segoe.AddLinkedFont(arialuni);

            // キャプションのテキスト書式。
            var tf = new TextFormat()
            {
                Font = arialbd,
                FontSize = 14,
                ForeColor = Color.Blue
            };
            // テキストを描画するためのテキストレイアウト。
            var tl = new TextLayout(72);
            tl.DefaultFormat.Font = segoe;
            tl.DefaultFormat.FontSize = 12;
            tl.MaxWidth = doc.PageSize.Width;
            tl.MaxHeight = doc.PageSize.Height;
            tl.MarginAll = rc.Left;
            tl.MarginTop = rc.Bottom + 36;

            // widow/orphan 制御のテキスト分割オプション。
            TextSplitOptions to = new TextSplitOptions(tl)
            {
                MinLinesInFirstParagraph = 2,
                MinLinesInLastParagraph = 2,
                RestMarginTop = rc.Left,
            };

            // 任意の PDF を開き、一時的なドキュメントに読み込んで、マップを使用してテキストを検索します。
            using (var fs = new FileStream(Path.Combine("Resources", "PDFs", pdfName), FileMode.Open, FileAccess.Read))
            {
                var doc1 = new GcPdfDocument();
                doc1.Load(fs);

                // 読み込まれたドキュメントのページのテキストを取得します。
                var texts = new List<string>();
                doc1.Pages.ToList().ForEach(p_ => texts.Add(p_.GetText()));

                // テキストレイアウトにテキストとキャプションを追加します。
                for (int i = 0; i < texts.Count; ++i)
                {
                    tl.AppendLine($"Text from page {i + 1} of {pdfName}:", tf);
                    tl.AppendLine(texts[i]);
                }
                tl.PerformLayout(true);
                while (true)
                {
                    // 'rest' は、収まりきらなかったテキストを受け入れます。
                    var splitResult = tl.Split(to, out TextLayout rest);
                    doc.Pages.Last.Graphics.DrawTextLayout(tl, PointF.Empty);
                    if (splitResult != SplitResult.Split)
                        break;
                    tl = rest;
                    doc.NewPage();
                }
            }
            // PDF ドキュメントを保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}