SvgGraphicsPicInArch.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 GrapeCity.Documents.Svg;
using DsImagingWeb.Demos.Common;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsImagingWeb.Demos
{
    // このサンプルでは、グラフィックスパスを使用して
    // GcSvgGraphics 上にアーチを描画する方法を示します。
    // また、パスを使用して描画をクリッピングする方法や、
    // GcSvgGraphics 上にラスタ画像を描画する方法についても示します。
    // アーチの描画コードは SvgGraphicsArch で使用されているものと類似しています。
    public class SvgGraphicsPicInArch
    {
        public string DefaultMime { get => Common.Util.MimeTypes.SVG; }

        public Stream GenerateImageStream(string targetMime, Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
        {
            if (targetMime != Common.Util.MimeTypes.SVG)
                throw new Exception("This sample only supports SVG output format.");

            // 前面イメージは一部が透明なPNGファイルであることに注意してください。
            var imageFn = Path.Combine("Resources", "ImagesBis", "minerva-masked.png");
            var backFn = Path.Combine("Resources", "Images", "colosseum.jpg");

            Color background = Color.FromArgb(230, 153, 77),
                line = Color.FromArgb(102, 34, 0),
                arch = Color.FromArgb(147, 78, 31),
                archBack = Color.FromArgb(0, 191, 255),
                fill = Color.FromArgb(255, 171, 145),
                marks = Color.FromArgb(170, 62, 9),
                text = Color.Black,
                textBack = Color.Cornsilk;

            var Inch = dpi;
            var ms = new MemoryStream();
            using var g = new GcSvgGraphics(pixelSize.Width, pixelSize.Height);
            if (opaque)
                g.FillRectangle(new RectangleF(0, 0, g.Width, g.Height), background);

            // アーチの境界長方形です。
            var rc = new RectangleF(0, 0, Inch * 5, Inch * 6.4f);

            // 変形を使用して、すべての描画を中央に配置します。
            var t = g.Transform;
            g.Transform = Matrix3x2.CreateTranslation(g.Width / 2 - rc.Width / 2, g.Height / 2 - rc.Height / 2);

            // 前面と背景の画像を読み込み、反転させます。
            // graphics上に描画された画像は、そのgraphicsがGcSvgDocumentに変換されるまで
            // 破棄(Dispose)してはいけないことに注意してください。
            using var bmp0 = new GcBitmap(imageFn);
            using var bmp = bmp0.FlipRotate(FlipRotateAction.FlipHorizontal);
            using var backBmpT = new GcBitmap(backFn);
            using var backBmp = backBmpT.FlipRotate(FlipRotateAction.FlipHorizontal);

            // アーチとその内部の画像を描画します。
            using (var innerPath = DrawArch(g, rc, rc.Height * 0.35f, rc.Width * 0.08f, line, arch, fill))
            using (var clip = g.PushClip(innerPath))
            {
                // 背景に色を塗って色合いを調整し、背景画像を半透明で描画します。
                // 前面画像は不透明として描画します(ただし、画像自体に透明なピクセルが含まれています)。
                g.FillRectangle(rc, archBack);
                var ia = new ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Center, true, true, true, false, false);
                g.DrawImage(backBmp, rc, rc, ia, 0.7f);
                g.DrawImage(bmp, rc, rc, ia, 1f);
            }

            // ラベルを追加します。
            var tf = new TextFormat()
            {
                Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSerif.ttf")),
                FontSize = Inch / 6,
                ForeColor = text,
            };
            // g.DrawString("ARCH", tf, rc, TextAlignment.Center, ParagraphAlignment.Center, false);

            // 計測線(寸法線)を描画します。
            var w = Inch / 8;
            var pen = new GCDRAW.Pen(marks);

            var txt = $"{(rc.Width / Inch):F}\"";
            var s = g.MeasureString(txt, tf);
            var d = s.Height * 1.5f;
            g.DrawLine(rc.Left, rc.Top - d, rc.Right, rc.Top - d, pen);
            g.DrawLine(rc.Left, rc.Top - d, rc.Left + w, rc.Top - d - w, pen);
            g.DrawLine(rc.Left, rc.Top - d, rc.Left + w, rc.Top - d + w, pen);
            g.DrawLine(rc.Right, rc.Top - d, rc.Right - w, rc.Top - d - w, pen);
            g.DrawLine(rc.Right, rc.Top - d, rc.Right - w, rc.Top - d + w, pen);

            var rcTxt = new RectangleF(rc.Left + rc.Width / 2 - s.Width / 2, rc.Top - d - s.Height / 2, s.Width, s.Height);
            rcTxt.Inflate(2, 2);
            g.FillRectangle(rcTxt, textBack);
            g.DrawString(txt, tf, rcTxt, TextAlignment.Center, ParagraphAlignment.Center, false);

            txt = $"{(rc.Height / Inch):F}\"";
            s = g.MeasureString(txt, tf);
            d = s.Width;
            g.DrawLine(rc.Left - d, rc.Top, rc.Left - d, rc.Bottom, pen);
            g.DrawLine(rc.Left - d, rc.Top, rc.Left - d - w, rc.Top + w, pen);
            g.DrawLine(rc.Left - d, rc.Top, rc.Left - d + w, rc.Top + w, pen);
            g.DrawLine(rc.Left - d, rc.Bottom, rc.Left - d - w, rc.Bottom - w, pen);
            g.DrawLine(rc.Left - d, rc.Bottom, rc.Left - d + w, rc.Bottom - w, pen);
            rcTxt = new RectangleF(rc.Left - d - s.Width / 2, rc.Top + rc.Height / 2 - s.Height / 2, s.Width, s.Height);
            rcTxt.Inflate(2, 2);
            g.FillRectangle(rcTxt, textBack);
            g.DrawString(txt, tf, rcTxt, TextAlignment.Center, ParagraphAlignment.Center, false);

            // 変形を元に戻します。
            g.Transform = t;

            // 画像ファイルを保存します。
            var svg = g.ToSvgDocument();
            svg.Save(ms);
            ms.Seek(0, SeekOrigin.Begin);
            return ms;
        }

        private IPath DrawArch(GcGraphics g, RectangleF rc, float harc, float wd, Color line, Color arch, Color fill)
        {
            var path = g.CreatePath();
            // 内部の塗りつぶしです(左下から始めて時計回りに描画します)。
            path.BeginFigure(rc.Left + wd, rc.Bottom - wd);
            path.AddLine(rc.Left + wd, rc.Top + harc);
            path.AddArc(new ArcSegment()
            {
                ArcSize = ArcSize.Small,
                Point = new PointF(rc.Right - wd, rc.Top + harc),
                RotationAngle = 0,
                Size = new SizeF(rc.Width / 2f - wd, harc - wd),
                SweepDirection = SweepDirection.Clockwise
            });
            path.AddLine(rc.Right - wd, rc.Bottom - wd);
            path.EndFigure(FigureEnd.Closed);
            g.FillPath(path, fill);
            // path.Dispose();
            var innerPath = path;

            // アーチの外形線です(左下から始めて時計回りに描画します)。
            path = g.CreatePath();
            path.BeginFigure(rc.Left, rc.Bottom);
            path.AddLine(rc.Left, rc.Top + harc);
            path.AddLine(rc.Left + wd, rc.Top + harc);
            path.AddLine(rc.Left + wd, rc.Bottom - wd);
            path.EndFigure(FigureEnd.Closed);
            path.BeginFigure(rc.Left, rc.Top + harc);
            path.AddArc(new ArcSegment()
            {
                ArcSize = ArcSize.Small,
                Point = new PointF(rc.Right, rc.Top + harc),
                RotationAngle = 0,
                Size = new SizeF(rc.Width / 2f, harc),
                SweepDirection = SweepDirection.Clockwise
            });
            path.AddLine(rc.Right - wd, rc.Top + harc);
            path.AddArc(new ArcSegment()
            {
                ArcSize = ArcSize.Small,
                Point = new PointF(rc.Left + wd, rc.Top + harc),
                RotationAngle = 0,
                Size = new SizeF(rc.Width / 2f - wd, harc - wd),
                SweepDirection = SweepDirection.CounterClockwise
            });
            path.EndFigure(FigureEnd.Closed);
            path.BeginFigure(rc.Right, rc.Top + harc);
            path.AddLine(rc.Right, rc.Bottom);
            path.AddLine(rc.Right - wd, rc.Bottom - wd);
            path.AddLine(rc.Right - wd, rc.Top + harc);
            path.EndFigure(FigureEnd.Closed);
            path.BeginFigure(rc.Right, rc.Bottom);
            path.AddLine(rc.Left, rc.Bottom);
            path.AddLine(rc.Left + wd, rc.Bottom - wd);
            path.AddLine(rc.Right - wd, rc.Bottom - wd);
            path.EndFigure(FigureEnd.Closed);

            g.FillPath(path, arch);
            g.DrawPath(path, new GCDRAW.Pen(line, 2));

            path.Dispose();

            return innerPath;
        }
    }
}