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

namespace DsPdfWeb.Demos.Basics
{
    // 水平方向の列を持つレイアウトを使用して、小説の文章をテキストとして描画します。
    //  ArabicColumnsMultiLangVerticalText、VerticalTextJPも参照してください。
    public class VerticalTextJP2
    {
        public int CreatePDF(Stream stream)
        {
            var clouds = GCDRAW.Image.FromFile(Path.Combine("Resources", "Images", "hanamaki.jpg"));
            var firth = GCDRAW.Image.FromFile(Path.Combine("Resources", "Images", "cello.jpg"));
            var kenji = GCDRAW.Image.FromFile(Path.Combine("Resources", "Images", "kenji.jpg"));
            var ia = new GCDRAW.ImageAlign(GCDRAW.ImageAlignHorz.Left, GCDRAW.ImageAlignVert.Top, true, true, true, false, false);

            var doc = new GcPdfDocument();

            // テキストを保持してレンダリングするTextLayout:
            var tl = new TextLayout(72);
            tl.ParagraphSpacing = 6;
            tl.FlowDirection = FlowDirection.VerticalRightToLeft;
            tl.TextAlignment = TextAlignment.Justified;
            // IPAゴシックフォントを埋め込み
            var font = Common.Util.getFont();
            doc.FontEmbedMode = FontEmbedMode.EmbedFullFont;

            var tf = new TextFormat() { Font = font, FontSize = 11 };
            var tf2 = new TextFormat() { Font = font, FontSize = 14 };
            // テストテキストを繰り返していくつかのページを埋める:


            StreamReader sr = new StreamReader(Path.Combine("Resources", "Text", "gingatetsudono_yoru.txt"));
            List<string> textList = getTextList();
            for (int i = 0; i < textList.Count; i++)
            {
                string  line = textList[i];
                // 半角数字が3桁以上続く場合を抽出
                line = Regex.Replace(line,("[0-9]{3,}"),new System.Text.RegularExpressions.MatchEvaluator(HanToZen));
                // 半角数字1桁のみのパターン(前後が半角数字ではない数字一桁)を抽出
                line = Regex.Replace(line,("(?<![0-9])[0-9]{1,}(?![0-9])"),new System.Text.RegularExpressions.MatchEvaluator(HanToZen));

                // 見出しの処理
                if (line.StartsWith("[#5字下げ]"))
                {
                    var result = Regex.Replace(line.Replace("[#5字下げ]", ""), "[#「.*]|《.*》", "");
                    tl.Append(result, tf2);
                }
                else
                {
                    var result = Regex.Replace(line, "[#「.*]|《.*》", "");
                    tl.Append(result, tf);
                }
                tl.AppendLine();
                
            }

            sr.Close();

            // 2つの水平な列のレイアウトテキスト:
            // (このサンプルのロジック/コードはArabicColumnsと同じです):
            const int NCOLS = 2;
            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 - 600, margin, 320, 180),
                new ObjectRect(page.Size.Width - margin - 250, page.Size.Height - margin - 270, 180, 270),
            };
            //オブジェクトをイメージ領域に変換し、調整して見栄えの良いパディングを提供する:
            var rClouds = tl.ObjectRects[0].ToRectangleF();
            rClouds.Inflate(-4, -3);
            var rkenji = tl.ObjectRects[1].ToRectangleF();
            rkenji.Inflate(-4, -3);
            page.Graphics.DrawImage(clouds, rClouds, null, ia);
            page.Graphics.DrawImage(kenji, rkenji, 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;
                    // 最初のページにイメージをレンダリングしたいだけなので、ObjectRectをクリアします:
                    if (tl.ObjectRects != null)
                    {
                        tl.ObjectRects = null;
                        // レイアウトをやり直す必要がありますが、グリフを再計算する必要はありません:
                        tl.PerformLayout(false);
                    }
                }
            }
            // PDF ドキュメントの保存
            doc.Save(stream);
            return doc.Pages.Count;
        }
        private List<string> _textList = new List<string>();
        private List<string> getTextList(int lines=1000)
        {
            try
            {   
                using (StreamReader sr = new StreamReader(Path.Combine("Resources", "Text", "gingatetsudono_yoru.txt")))
                {                    
                    for (int i = 0; i < lines; i++)
                    {
                        if (sr.EndOfStream)
                        {
                            i = lines;
                        }
                        else
                        {
                        _textList.Add(sr.ReadLine());                            
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("The file could not be read:");
                Console.WriteLine(e.Message);
            }
            return _textList;
        }
        //MatchEvaluatorデリゲートメソッド
        private static string HanToZen(System.Text.RegularExpressions.Match m)
        {
            string result = "";
            //引数で取得した文字列をCharの配列に変換
            Char[] charAr = m.Value.ToCharArray();
            //Charの配列でマッチした数字を全角に変換
            foreach (var charValue in charAr)
            {
                // Charの文字コードで'0'との差分に'0'を足すと半角が全角にかわる
                // '0'〜'9' は '0'〜'9'の並びと同じ
                //(例 2は0の2つとなりにあるように、2は0の2つとなりにある 
                result +=  ((char)((charValue - '0') + '0')).ToString();                
            }
            return result;
        }        


    }
}