TransparentShadow.cs
//
// This code is part of Document Solutions for Imaging demos.
// Copyright (c) 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
{
    // This example shows how to draw a window with a solid frame
    // and four semi-transparent colored window panes,
    // floating above a solid brick wall with some text written on it,
    // and casting a semi-transparent colored shadow on the wall.
    public class TransparentShadow
    {
        private GCTEXT.Font _font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoesc.ttf"));

        public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
        {
            // A temporary bitmap to hold the shadow:
            using var shadow = new GcBitmap(pixelSize.Width, pixelSize.Height, false);

            // Draw the window on the shadow bitmap; the offsetX/offsetY (64/82)
            // account for the shadow's offset relative to the floating window
            // that will be drawn later:
            using (var g = shadow.CreateGraphics(Color.Transparent))
                DrawWindow(g, pixelSize, 64, 82);

            // Create a shadow without blur in 'shadowTemp' and blend it with the main shadow bitmap
            // in order to render colored shadows of the semi-transparent window panes:
            using (var gs = shadow.ToGrayscaleBitmap(ColorChannel.Alpha))
            using (var shadowTemp = gs.ToShadowBitmap(Color.DarkSlateGray))
                shadow.AlphaBlend(shadowTemp, 0, 0);

            // At this point 'shadow' contains opaque colored shadow without blur,
            // we apply the blur effect and make it semi-transparent:
            shadow.ApplyEffect(GaussianBlurEffect.Get(29));
            shadow.ApplyEffect(OpacityEffect.Get(0.85f));

            // Prepare the brick wall image:
            var wall = new GcBitmap(pixelSize.Width, pixelSize.Height, true);
            using (var g = wall.CreateGraphics(Color.DarkSalmon))
                DrawWall(g, pixelSize);

            // Blend the shadow with the wall:
            wall.AlphaBlend(shadow, 0, 0);

            // Finally draw the window floating in front of the wall:
            using (var g = wall.CreateGraphics())
                DrawWindow(g, pixelSize, 0, 0);

            // Done
            return wall;
        }

        // Draw a window with four colored semi-transparent panes:
        void DrawWindow(GcGraphics g, Size pixelSize, float offsetX, float offsetY)
        {
            var w = pixelSize.Width * 0.4f;
            var h = pixelSize.Height * 0.5f;
            var x = pixelSize.Width / 2 - w / 2;
            var y = pixelSize.Height / 2 - h / 2;

            g.Transform = Matrix3x2.CreateTranslation(offsetX, offsetY);

            var wnd = new RectangleF(x, y, w, h);
            var winHalf = new SizeF(wnd.Width / 2, wnd.Height / 2);
            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);

            var outline = Color.DarkSlateGray;
            g.DrawRectangle(wnd, new GCDRAW.Pen(outline, 34));
            g.DrawLine(wnd.Left, wnd.Top + wnd.Height / 2, wnd.Right, wnd.Top + wnd.Height / 2, outline, 24);
            g.DrawLine(wnd.Left + wnd.Width / 2, wnd.Top, wnd.Left + wnd.Width / 2, wnd.Bottom, outline, 24);
            var frame = Color.LightGoldenrodYellow;
            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;
        }

        // Draw a brick wall with a white text:
        void DrawWall(GcGraphics g, Size pixelSize)
        {
            // The brick pattern:
            var brick = new Size(112, 44);
            var pen = new GCDRAW.Pen(Color.DimGray, 2);
            var off = brick.Width / 2;
            for (int y = -brick.Height / 3; y < pixelSize.Height; y += brick.Height)
            {
                for (int x = off + brick.Width / 3; x < pixelSize.Width; x += brick.Width)
                {
                    g.DrawLine(x, y, x, y + brick.Height, pen);
                }
                off = off == 0 ? brick.Width / 2 : 0;
                g.DrawLine(0, y, pixelSize.Width, y, pen);
            }
            // Graffiti-like white text (overlay blend mode is used to visually preserve the joints):
            var tl = g.CreateTextLayout();
            tl.MaxWidth = pixelSize.Width;
            tl.MaxHeight = pixelSize.Height;
            tl.ParagraphAlignment = ParagraphAlignment.Center;
            tl.TextAlignment = TextAlignment.Center;
            tl.DefaultFormat.Font = _font;
            tl.DefaultFormat.FontSize = 270;
            tl.DefaultFormat.ForeColor = Color.White;
            tl.ParagraphSpacing = -120;
            tl.Append("The\nWall");
            g.BlendMode = BlendMode.Overlay;
            g.DrawTextLayout(tl, Point.Empty);
            g.BlendMode = BlendMode.Normal;
        }
    }
}