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

namespace GcPdfWeb.Samples.Basics
{
    // このサンプルは、矩形領域(この場合は画像)の周りに大きなテキストブロックをフロー
    // させる方法を示します。また、特定の ImageAlign を使用してページに描画された画像の
    // 実際の境界を取得する方法も示します。
    public class TextAroundImages
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var g = doc.NewPage().Graphics;
            const string fontname = "Yu Gothic";
            // 最初のページの任意の場所に3枚の画像を描画し、
            // 2~3ページのテキストを印刷して、最初のページの
            // 画像を囲むようにしたいと考えています。
            // 
            // 画像とその矩形を取得します。すべての画像に正方形の
            // 領域を指定しますが、元の縦横比を維持してその領域内に
            // 配置されるので、後で画像が描かれた実際の長方形を
            // 取得します。
            using (var imgPuffins = Image.FromFile("Resources/Images/puffins.jpg"))
            using (var imgReds = Image.FromFile("Resources/Images/reds.jpg"))
            using (var imgLavender = Image.FromFile("Resources/Images/lavender.jpg"))
            {
                var rectPuffins = new RectangleF(100, 70, 180, 180);
                var rectReds = new RectangleF(300, 280, 180, 180);
                var rectLavender = new RectangleF(190, 510, 180, 180);
                // 画像の元のアスペクト比を維持しながら、指定された領域に画像を
                // 収めて中央に配置する ImageAlign を設定します。
                ImageAlign ia = new ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Center, true, true, true, false, false);
                // 各画像を描画し、各 DrawImage 呼び出しの出力パラメータとして長方形の配列を
                // 提供します。これにより、画像によって実際に取得される矩形が得られます
                // (タイル画像を処理するには配列が必要です)。
                g.DrawImage(imgPuffins, rectPuffins, null, ia, out RectangleF[] rectsPuffins);
                g.DrawImage(imgReds, rectReds, null, ia, out RectangleF[] rectsReds);
                g.DrawImage(imgLavender, rectLavender, null, ia, out RectangleF[] rectsLavender);
                // テキストを出力するための TextLayout オブジェクトを作成して設定します。
                var tl = g.CreateTextLayout();
                tl.DefaultFormat.FontName = fontname;
                tl.DefaultFormat.FontSize = 9;
                tl.TextAlignment = TextAlignment.Justified;
                tl.ParagraphSpacing = 72 / 8;
                tl.MaxWidth = doc.PageSize.Width;
                tl.MaxHeight = doc.PageSize.Height;
                // 周囲に 1/2 インチの余白。
                tl.MarginAll = 72 / 2;
                // ObjectRect は、TextLayout にフロー領域を指定するために使用される型です。
                // イメージ矩形に基づいて ObjecRect を作成するローカル関数を設定し、
                // いくつかのパディングを追加して、結果がよりよく見えるようにしています。
                Func<RectangleF, ObjectRect> makeObjectRect = rect_ =>
                    new ObjectRect(rect_.X - 6, rect_.Y - 2, rect_.Width + 12, rect_.Height + 4);
                // TextLayout に ObjectRect の配列を指定します。
                tl.ObjectRects = new List<ObjectRect>()
                {
                    makeObjectRect(rectsPuffins[0]),
                    makeObjectRect(rectsReds[0]),
                    makeObjectRect(rectsLavender[0]),
                };
                // いくつかのテキストの段落を追加します。
                tl.Append(Common.Util.getString_ja(1, 0, 8));
                // グリフを計算し、テキストをレイアウトします。
                tl.PerformLayout(true);
                // ページ間のテキストの分割を制御するオプションを分割します。
                // デフォルトのコンストラクタを使用して MaxWidth などの値を設定するか、
                // TextLayout に基づいて TextSplitOptions を作成し、RestObjectRects を
                // クリアすることができます。
                TextSplitOptions to = new TextSplitOptions(tl)
                {
                    RestObjectRects = null,
                    MinLinesInFirstParagraph = 2,
                    MinLinesInLastParagraph = 2
                };
                // ループ内で、テキストを分割して描画します。
                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;
                    // 最初のページにのみ画像を描画します。
                    tl.ObjectRects = null;
                    doc.Pages.Add();
                }
                // PDF ドキュメントを保存します。
                doc.Save(stream);
                return doc.Pages.Count;
            }
        }
    }
}