Shadow.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 System.Numerics;
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
{
    // このサンプルでは、指定した量だけオフセットされた、
    // 半透明でぼかしのかかったテキストおよびグラフィックス画像の
    // 影を作成する方法を示します。
    // これを実現するために、本コードでは
    // GrayscaleBitmap クラスの ApplyGaussianBlur メソッドおよび
    // ToShadowBitmap メソッドを使用しております。
    public class Shadow
    {
        private GCTEXT.Font _font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf"));

        public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
        {
            // 透明なビットマップを作成し、その上に影となるイメージを描画します(右に30、下に50オフセットさせます)。
            var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, false);
            using (var g = bmp.CreateGraphics(Color.Transparent))
            {
                Draw(g, 30, 50);
            }

            // GcBitmapからアルファチャンネルを抽出し、GrayscaleBitmapに変換します。
            using var gs = bmp.ToGrayscaleBitmap(ColorChannel.Alpha);

            // GrayscaleBitmapにガウスぼかしを適用し、自然な見た目の影を作成します。
            gs.ApplyGaussianBlur(9);

            // 透明度マスクをGrayscaleBitmapからGcBitmapに変換し、
            // 不透明なピクセルを影の色(CadetBlue)で塗りつぶします。
            // また、結果として得られる「影」をわずかに透明(0.6f)にします。
            gs.ToShadowBitmap(bmp, Color.CadetBlue, 0.6f);

            // 透明な背景を不透明な背景色で置き換えます。
            bmp.ConvertToOpaque(Color.LightGoldenrodYellow);

            // 最後に、元のイメージをオフセットなしで一番上に描画します。
            using (var g = bmp.CreateGraphics())
            {
                Draw(g, 0, 0);
            }

            // 画像ファイルを保存します。
            return bmp;
        }

        private void Draw(GcGraphics g, float offsetX, float offsetY)
        {
            var baseT = Matrix3x2.CreateTranslation(offsetX, offsetY);
            g.Transform = baseT;
            g.DrawEllipse(new RectangleF(100, 100, 300, 200), new GCDRAW.Pen(Color.Orange, 20));
            g.DrawLine(new PointF(50, 400), new PointF(500, 50), new GCDRAW.Pen(Color.RoyalBlue, 20)
            {
                LineCap = PenLineCap.Round
            });
            g.DrawString("Howl's Moving Castle",
                new TextFormat
                {
                    Font = _font,
                    FontSize = 40,
                    ForeColor = Color.MistyRose,
                    StrokePen = new GCDRAW.Pen(Color.DarkRed, 1)
                },
                new PointF(200, 150));
            g.Transform =
                Matrix3x2.CreateRotation((float)(Math.PI / 6)) *
                (Matrix3x2.CreateTranslation(50, 250) * baseT);
            g.DrawString("The quick brown fox jumps over the lazy dog.",
                new TextFormat
                {
                    Font = _font,
                    FontSize = 18,
                    ForeColor = Color.CornflowerBlue
                },
                new PointF(0, 0));
            g.DrawRectangle(new RectangleF(-15, -10, 470, 50), new GCDRAW.Pen(Color.Salmon, 1));

            g.Transform = baseT;

            // 4枚の異なる色の半透明なガラス板を持つ窓を描画します。
            var wnd = new RectangleF(520, 420, 400, 500);
            var winHalf = new SizeF(wnd.Width / 2, wnd.Height / 2);
            var frame = Color.Brown;
            var glassTL = Color.FromArgb(unchecked((int)0x70FF4600));
            var glassTR = Color.FromArgb(unchecked((int)0x70A5FF00));
            var glassBL = Color.FromArgb(unchecked((int)0x70007BFF));
            var glassBR = Color.FromArgb(unchecked((int)0x70FFCD00));

            g.FillRectangle(new RectangleF(wnd.Location, winHalf), glassTL);
            g.FillRectangle(new RectangleF(new PointF(wnd.X + wnd.Width / 2, wnd.Y), winHalf), glassTR);
            g.FillRectangle(new RectangleF(new PointF(wnd.X, wnd.Y + wnd.Height / 2), winHalf), glassBL);
            g.FillRectangle(new RectangleF(new PointF(wnd.X + wnd.Width / 2, wnd.Y + wnd.Height / 2), winHalf), glassBR);

            g.DrawRectangle(wnd, new GCDRAW.Pen(frame, 30));
            g.DrawLine(wnd.Left, wnd.Top + wnd.Height / 2, wnd.Right, wnd.Top + wnd.Height / 2, frame, 20);
            g.DrawLine(wnd.Left + wnd.Width / 2, wnd.Top, wnd.Left + wnd.Width / 2, wnd.Bottom, frame, 20);

            g.Transform = Matrix3x2.Identity;
        }
    }
}