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

namespace DsPdfWeb.Demos.Basics
{
    // 水平方向の列を持つレイアウトを使用して、右から左に縦書きのテキストを描画します。
    // ArabicColumnsMultiLangVerticalText も参照してください。
    public class VerticalTextJP
    {
        const string text = "日本語(にほんご、にっぽんご)は、主として、日本列島で使用されてきた言語である。日本手話を母語とする者などを除いて、ほぼ全ての日本在住者は日本語を第一言語とする。日本国は法令上、公用語を明記していないが、事実上の公用語となっており、学校教育の「国語」で教えられる。使用者は、日本国内を主として約\uFF11億\uFF13千万人。日本語の文法体系や音韻体系を反映する手話として日本語対応手話がある。";

        public int CreatePDF(Stream stream)
        {
            using var clouds = GCDRAW.Image.FromFile(Path.Combine("Resources", "Images", "clouds.jpg"));
            using var firth = GCDRAW.Image.FromFile(Path.Combine("Resources", "Images", "firth.jpg"));
            using var lavender = GCDRAW.Image.FromFile(Path.Combine("Resources", "Images", "lavender.jpg"));

            var fnt = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "NotoSansJP-Regular.ttf"));
            var ia = new ImageAlign(ImageAlignHorz.Left, ImageAlignVert.Top, true, true, true, false, false);
            var doc = new GcPdfDocument();

            // テキストを保持および描画する TextLayout。
            var tl = new TextLayout(72);
            tl.FirstLineIndent = 18;
            tl.ParagraphSpacing = 6;
            tl.FlowDirection = FlowDirection.VerticalRightToLeft;
            tl.TextAlignment = TextAlignment.Justified;
            var tf = new TextFormat() { Font = fnt, FontSize = 12 };
            // いくつかのページを埋めるためにテストテキストを繰り返します。
            for (int i = 0; i < 25; ++i)
            {
                tl.Append(text, tf);
                tl.AppendLine();
            }

            // 4つの水平な列のレイアウトテキスト。
            // (このサンプルのロジック/コードは ArabicColumns と同じです)
            const int NCOLS = 4;
            var margin = 36f;
            var gap = 18f;
            var page = doc.NewPage();
            page.Landscape = true;
            var colHeight = (page.Size.Height - margin * 2 - gap * (NCOLS - 1)) / NCOLS;
            tl.MaxWidth = page.Size.Width;
            tl.MaxHeight = page.Size.Height;
            tl.MarginLeft = tl.MarginRight = margin;
            tl.MarginTop = margin;
            tl.MarginBottom = margin + (colHeight + gap) * (NCOLS - 1);
            // 外周にテキストがフローする矩形を任意に指定することができます。
            // このケースでは、画像を描画するために3つの領域を追加します。
            tl.ObjectRects = new List<ObjectRect>()
            {
                new ObjectRect(page.Size.Width - margin - 267, margin, 267, 200),
                new ObjectRect(margin + 100, margin + 60, 133, 100),
                new ObjectRect(margin, page.Size.Height - margin - 301, 200, 301),
            };
            // オブジェクトをイメージ領域に変換し、調整して見栄えの良いパディングを提供します。
            var rClouds = tl.ObjectRects[0].ToRectangleF();
            rClouds.Inflate(-4, -3);
            var rFirth = tl.ObjectRects[1].ToRectangleF();
            rFirth.Inflate(-4, -3);
            var rLavender = tl.ObjectRects[2].ToRectangleF();
            rLavender.Inflate(-4, -3);
            page.Graphics.DrawImage(clouds, rClouds, null, ia);
            page.Graphics.DrawImage(firth, rFirth, null, ia);
            page.Graphics.DrawImage(lavender, rLavender, null, ia);

            // 呼び出し:テキストを描画するのに必要なグリフを計算し、それをレイアウトします。
            tl.PerformLayout(true);

            // 描画するテキストがまだある間はループします。
            bool done = false;
            while (!done)
            {
                for (int col = 0; col < NCOLS; ++col)
                {
                    int nextcol = (col < NCOLS - 1) ? col + 1 : 0;
                    // TextSplitOptions は、残りのテキストのレイアウト方法を TextLayout.Split() に伝えます。
                    // 今回のケースでは、上下のマージンを更新することによって、列ごとに進めます。
                    var tso = new TextSplitOptions(tl)
                    {
                        RestMarginTop = margin + (colHeight + gap) * nextcol,
                        RestMarginBottom = margin + (colHeight + gap) * (NCOLS - 1 - nextcol)
                    };
                    var split = tl.Split(tso, out TextLayout rest);
                    page.Graphics.DrawTextLayout(tl, PointF.Empty);
                    if (split != SplitResult.Split)
                    {
                        done = true;
                        break;
                    }
                    tl = rest;
                }
                if (!done)
                {
                    page = doc.NewPage();
                    page.Landscape = true;
                    // 最初のページに画像を描画したいだけなので、ObjectRects をクリアします。
                    if (tl.ObjectRects != null)
                    {
                        tl.ObjectRects = null;
                        // レイアウトをやり直す必要がありますが、グリフを再計算する必要はありません。
                        tl.PerformLayout(false);
                    }
                }
            }
            // PDF ドキュメントを保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}