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

namespace DsImagingWeb.Demos
{
    // このサンプルでは、GcGraphics.DrawSlantedText() メソッドを
    // さまざまな引数の組み合わせで使用した場合の結果を示します。
    // DrawSlantedText() メソッドは、枠線付きの MS Excel のセル内で
    // 回転文字が描画される場合と同様に、指定された矩形内で
    // テキストを傾斜させて描画します。
    // 関連デモとして DrawRotatedText_0 も参照してください。
    public class DrawSlantedText
    {
        static string[] s_names = new []
        {
            "Horizontal Stacking 1",
            "Horizontal Stacking 2",
            "Horizontal Stacking 3",
            "Horizontal Stacking 4",
            "Horizontal Stacking 5",
            "Horizontal Stacking 6",
            "Horizontal Stacking 7",
            "Horizontal Stacking 8",

            "Vertical Stacking 1",
            "Vertical Stacking 2",
            "Vertical Stacking 3",
            "Vertical Stacking 4",
        };

        public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
        {
            sampleParams ??= GetSampleParamsList()[0];

            var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi);
            using var g = bmp.CreateGraphics(Color.White);
            // レイアウトを管理するための値を設定します。
            var margin = g.Resolution;
            var gap = g.Resolution;
            var w = pixelSize.Width * 0.3f;
            var h = w;

            if (sampleParams[0] == s_names[0])
            {
                // SlantedTextAlignment.BelowRotatedInside を使用したさまざまなテキスト配置。
                Draw(g, q0(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Leading);
                Draw(g, q1(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Center);
                Draw(g, q3(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[1])
            {
                // SlantedTextAlignment.BelowRotatedOutside を使用したさまざまなテキスト配置。
                Draw(g, q0(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Leading);
                Draw(g, q1(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Center);
                Draw(g, q3(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[2])
            {
                // SlantedTextAlignment.AboveRotatedInside を使用したさまざまなテキスト配置。
                Draw(g, q0(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Leading);
                Draw(g, q1(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Center);
                Draw(g, q3(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[3])
            {
                // SlantedTextAlignment.AboveRotatedOutside を使用したさまざまなテキスト配置。
                Draw(g, q0(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Leading);
                Draw(g, q1(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Center);
                Draw(g, q3(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[4])
            {
                // SlantedTextAlignment.CenterInsideOutside を使用したさまざまなテキスト配置。
                Draw(g, q0(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Leading);
                Draw(g, q1(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Center);
                Draw(g, q3(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[5])
            {
                // SlantedTextAlignment.CenterOutsideInside を使用したさまざまなテキスト配置。
                Draw(g, q0(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Leading);
                Draw(g, q1(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Center);
                Draw(g, q3(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[6])
            {
                // SlantedTextAlignment.BelowRotatedInside を使用した正の回転角度の例。
                Draw(g, q0(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Leading);
                Draw(g, q1(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Center);
                Draw(g, q3(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[7])
            {
                // SlantedTextAlignment.AboveRotatedInside を使用した正の回転角度の例。
                Draw(g, q0(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Leading);
                Draw(g, q1(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Center);
                Draw(g, q3(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Distributed);
            }
            // 垂直スタック。
            else if (sampleParams[0] == s_names[8])
            {
                // SlantedTextAlignment.BelowRotatedInside を使用して負の角度に回転させた垂直スタックテキスト。
                Draw(g, q0(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Leading);
                Draw(g, q1(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Center);
                Draw(g, q3(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[9])
            {
                // SlantedTextAlignment.BelowRotatedOutside を使用して負の角度に回転させた垂直スタックテキスト。
                Draw(g, q0(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Leading);
                Draw(g, q1(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Trailing);
                Draw(g, q2(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Center);
                Draw(g, q3(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[10])
            {
                // SlantedTextAlignment.AboveRotatedOutside を使用して正の角度に回転させた垂直スタックテキスト。
                Draw(g, q0(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Leading);
                Draw(g, q1(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Trailing);
                Draw(g, q2(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Center);
                Draw(g, q3(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Distributed);
            }
            else if (sampleParams[0] == s_names[11])
            {
                // SlantedTextAlignment.CenterOutsideInside を使用して正の角度に回転させた垂直スタックテキスト。
                Draw(g, q0(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Leading);
                Draw(g, q1(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Trailing);
                Draw(g, q2(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Center);
                Draw(g, q3(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Distributed);
            }
            return bmp;

            RectangleF q0()
            {
                return new RectangleF(margin, margin, w, h);
            }
            RectangleF q1()
            {
                return new RectangleF(pixelSize.Width - margin - w, margin, w, h);
            }
            RectangleF q2()
            {
                return new RectangleF(margin, margin + h + gap, w, h);
            }
            RectangleF q3()
            {
                return new RectangleF(pixelSize.Width - margin - w, margin + h + gap, w, h);
            }
        }

        static void Draw(GcGraphics g, RectangleF rect, int angle, bool verticalStacking,
            SlantedTextAlignment slantedAlign, TextAlignment textAlign)
        {
            // 現在の DrawRotatedText 引数の値を説明する凡例を描画します。
            var tlLegend = g.CreateTextLayout();
            tlLegend.DefaultFormat.FontName = "Calibri";
            tlLegend.DefaultFormat.FontSize = 9;
            tlLegend.AppendLine($"Rotation angle: {angle}°");
            tlLegend.AppendLine($"Text alignment: {textAlign}");
            tlLegend.AppendLine($"Slanted text alignment: {slantedAlign}");
            tlLegend.AppendLine($"Is vertical stacking: {verticalStacking}");
            g.DrawTextLayout(tlLegend, rect.Location);

            // DrawRotatedText 呼び出しのターゲット矩形。
            var d = tlLegend.ContentHeight + g.Resolution;
            rect.Y += d;
            rect.Height -= d;
            rect.Width -= d / 2;
            var x = rect.X;
            var y = rect.Y;
            var w = rect.Width;
            var h = rect.Height;

            // ターゲット矩形を描画します。
            g.DrawRectangle(rect, new GCDRAW::Pen(Color.PaleGreen, 3));

            if (!verticalStacking)
            {
                float dx = (float)(h / Math.Tan(Math.PI * angle / -180.0));
                switch (slantedAlign)
                {
                    case SlantedTextAlignment.BelowRotatedInside:
                    case SlantedTextAlignment.AboveRotatedOutside:
                    case SlantedTextAlignment.CenterInsideOutside:
                        g.DrawPolygon(new[] {
                            new PointF(x + dx, y), new PointF(x + dx + w, y),
                            new PointF(x + w, y + h), new PointF(x, y + h)},
                            new GCDRAW::Pen(Color.Red, 1));
                        break;
                    case SlantedTextAlignment.BelowRotatedOutside:
                    case SlantedTextAlignment.AboveRotatedInside:
                    case SlantedTextAlignment.CenterOutsideInside:
                        g.DrawPolygon(new[] {
                            new PointF(x, y), new PointF(x + w, y),
                            new PointF(x - dx + w, y + h), new PointF(x - dx, y + h)},
                            new GCDRAW::Pen(Color.Red, 1));
                        break;
                }
            }
            else
            {
                float dy = (float)(w * Math.Tan(Math.PI * angle / 180.0));
                switch (slantedAlign)
                {
                    case SlantedTextAlignment.BelowRotatedInside:
                    case SlantedTextAlignment.AboveRotatedOutside:
                    case SlantedTextAlignment.CenterInsideOutside:
                        if (angle >= 0)
                            g.DrawPolygon(new[] {
                                new PointF(x, y), new PointF(x + w, y + dy), new PointF(x + w, y + dy + h), new PointF(x, y + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        else
                            g.DrawPolygon(new[] {
                                new PointF(x, y - dy), new PointF(x + w, y), new PointF(x + w, y + h), new PointF(x, y - dy + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        break;
                    case SlantedTextAlignment.BelowRotatedOutside:
                    case SlantedTextAlignment.AboveRotatedInside:
                    case SlantedTextAlignment.CenterOutsideInside:
                        if (angle >= 0)
                            g.DrawPolygon(new[] {
                                new PointF(x, y - dy), new PointF(x + w, y), new PointF(x + w, y + h), new PointF(x, y - dy + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        else
                            g.DrawPolygon(new[] {
                                new PointF(x, y), new PointF(x + w, y + dy), new PointF(x + w, y + dy + h), new PointF(x, y + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        break;
                }
            }
            // 傾斜テキストを描画します。
            var tl = g.CreateTextLayout();
            tl.DefaultFormat.FontName = "Calibri";
            tl.DefaultFormat.FontSize = 12;
            tl.TextAlignment = textAlign;
            tl.Append("The quick brown fox jumps over the lazy dog. ");
            tl.Append("The quick brown fox jumps over the lazy dog.");
            g.DrawSlantedText(tl, angle, verticalStacking, rect, slantedAlign);
        }

        public static List<string[]> GetSampleParamsList()
        {
            return new List<string[]>()
            {
                // 各文字列は名前、説明、情報です。残りは任意の文字列です。
                new string[] { s_names[0], "SlantedTextAlignment.BelowRotatedInside を使用したさまざまなテキスト配置を描画する", null},
                new string[] { s_names[1], "SlantedTextAlignment.BelowRotatedOutside を使用したさまざまなテキスト配置を描画する", null},
                new string[] { s_names[2], "SlantedTextAlignment.AboveRotatedInside を使用したさまざまなテキスト配置を描画する", null},
                new string[] { s_names[3], "SlantedTextAlignment.AboveRotatedOutside を使用したさまざまなテキスト配置を描画する", null},
                new string[] { s_names[4], "SlantedTextAlignment.CenterInsideOutside を使用したさまざまなテキスト配置を描画する", null},
                new string[] { s_names[5], "SlantedTextAlignment.CenterOutsideInside を使用したさまざまなテキスト配置を描画する", null},
                new string[] { s_names[6], "SlantedTextAlignment.BelowRotatedInside を使用して正の回転角度で描画する例", null},
                new string[] { s_names[7], "SlantedTextAlignment.AboveRotatedInside を使用して正の回転角度で描画する例", null},
                new string[] { s_names[8], "SlantedTextAlignment.BelowRotatedInside を使用して負の角度に回転させた垂直スタックテキストを描画する", null},
                new string[] { s_names[9], "SlantedTextAlignment.BelowRotatedOutside を使用して負의 角度に回転させた垂直スタックテキストを描画する", null},
                new string[] { s_names[10], "SlantedTextAlignment.AboveRotatedOutside を使用して正の角度に回転させた垂直スタックテキストを描画する", null},
                new string[] { s_names[11], "SlantedTextAlignment.CenterOutsideInside を使用して正の角度に回転させた垂直スタックテキストを描画する", null},
            };
        }
    }
}