AllBlendModes.cs
//
// This code is part of Document Solutions for PDF demos.
// Copyright (c) MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Linq;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Imaging;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos
{
    // This sample demonstrates the effects of different blend modes
    // when drawing on a GcPdfGraphics. Note that the current blend mode
    // set on an instance of GcGraphics (including GcPdfGraphics)
    // affects not only images but all drawing operations.
    // In this sample it is demonstrated by rendering the blend mode
    // names on the second page.
    public class AllBlendModes
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var page = doc.NewPage();
            var g = page.Graphics;

            var iorchid = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "orchid.jpg"));
            var ispectr = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "spectrum-pastel-500x500.png"));

            const int margin = 36;
            const int NCOLS = 4;
            var w = (int)((page.Size.Width - margin * 2) / NCOLS);
            var h = (int)((iorchid.Height * w) / iorchid.Width);

            // Text layout for captions:
            var tl = g.CreateTextLayout();
            tl.DefaultFormat.Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "cour.ttf"));
            tl.DefaultFormat.FontSize = 12;
            tl.ParagraphAlignment = ParagraphAlignment.Center;
            tl.TextAlignment = TextAlignment.Center;
            tl.MaxWidth = w;
            tl.MaxHeight = h;
            tl.MarginTop = h - g.MeasureString("QWERTY", tl.DefaultFormat).Height * 1.4f;

            int row = 0, col, dy;
            // Render all blending modes in a grid:
            var modes = Enum.GetValues(typeof(BlendMode));
            for (int i = 0; i < 2; ++i)
            {
                row = col = 0;
                GCDRAW.Image iback, ifore;
                if (i == 0)
                {
                    iback = ispectr;
                    ifore = iorchid;
                    var trc1 = Common.Util.AddNote(
                        "Below are tiles drawn by composing two images (a spectrum and an orchid) using the " +
                        "different blend modes supported by DsPdf. " +
                        "First the spectrum image is drawn normally, then it is overlaid by the orchid image " +
                        "drawn in a supported blend mode. The blend mode name is shown below each tile." +
                        "\n" +
                        "Tiles on the second page are composed of the same images but drawn in reverse order: " +
                        "the orchid is drawn normally, the spectrum is blended with it using the different modes." +
                        "\n" +
                        "Note that the current blend mode affects not only images but any drawing on a GcGraphics. " +
                        "The blend mode names on the 2nd page illustrate this.",
                        page);
                    dy = (int)trc1.Bottom;
                }
                else // i == 1
                {
                    iback = iorchid;
                    ifore = ispectr;
                    page = doc.Pages.Add();
                    g = page.Graphics;
                    dy = 0;
                }
                foreach (var mode in modes)
                {
                    var blendMode = (BlendMode)mode;
                    if (!g.IsBlendModeSupported(blendMode))
                        continue;

                    int x = margin + w * col;
                    int y = margin + h * row + dy;
                    var r = new RectangleF(x, y, w, h);

                    g.BlendMode = BlendMode.Normal;
                    g.DrawImage(iback, r, null, ImageAlign.StretchImage);
                    g.BlendMode = blendMode;
                    g.DrawImage(ifore, r, null, ImageAlign.StretchImage);
                    g.BlendMode = BlendMode.Normal;

                    // Caption:
                    tl.Clear();
                    tl.Append(blendMode.ToString());
                    tl.PerformLayout(true);
                    var rc = tl.ContentRectangle;
                    rc.Offset(x, y);
                    rc.Inflate(4, 2);
                    g.FillRectangle(rc, Color.White);
                    g.DrawTextLayout(tl, new PointF(x, y));
                    nextRowCol();
                }
            }
            // Text blends:
            page = doc.Pages[1];
            g = page.Graphics;
            var trc = Common.Util.AddNote(
                "Below are supported blend mode names rendered into rectangles using the corresponding blend mode. " +
                "Each rectangle is first filled by the spectrum image using BlendMode.Normal, " +
                "then black and white texts are drawn using the current blend mode, " +
                "finally the same spectrum image is drawn using BlendMode.Difference to black out the background. " +
                "Names prefixed with 'B:' are drawn in black, " +
                "while names prefixed with 'W:' are drawn in white. " +
                "Most combinations yield rather colorful results, but for some the results are invisible.",
                page,
                new RectangleF(margin, margin + h * row + 12, page.Bounds.Width - margin * 2, 0));

            var yoff = (int)trc.Bottom + 12;
            tl.DefaultFormat.FontBold = true;
            tl.DefaultFormat.FontSize = 16;
            h = (int)(g.MeasureString("QWERTY", tl.DefaultFormat).Height * 1.4f) * 2;
            tl.MaxWidth = w;
            tl.MaxHeight = h;
            tl.MarginTop = (h - h / 1.4f) / 2;

            tl.DefaultFormat.ForeColor = Color.Black;
            var tfWhite = new TextFormat(tl.DefaultFormat) { ForeColor = Color.White };

            row = col = 0;
            foreach (var mode in modes)
            {
                var blendMode = (BlendMode)mode;
                if (!g.IsBlendModeSupported(blendMode))
                    continue;

                int x = margin + w * col;
                int y = yoff + h * row;
                var r = new RectangleF(x, y, w, h);

                // Draw spectrum image normally:
                g.BlendMode = BlendMode.Normal;
                g.DrawImage(ispectr, r, null, ImageAlign.StretchImage);
                // Draw blend mode name using the current blend mode:
                tl.Clear();
                tl.AppendLine($"B: {blendMode}");
                tl.Append($"W: {blendMode}", tfWhite);
                tl.PerformLayout(true);
                var rc = tl.ContentRectangle;
                rc.Offset(x, y);
                rc.Inflate(4, 2);
                // Current blend mode:
                g.BlendMode = blendMode;
                g.DrawTextLayout(tl, new PointF(x, y));
                // Draw spectrum image again using BlendMode.Difference
                // to produce (mostly) colorful text on black background:
                g.BlendMode = BlendMode.Difference;
                g.DrawImage(ispectr, r, null, ImageAlign.StretchImage);
                // Draw a rectangle to mark the current area:
                g.BlendMode = BlendMode.Normal;
                g.DrawRectangle(r, Color.Gray);
                nextRowCol();
            }
            // Done:
            doc.Save(stream);
            return doc.Pages.Count;

            //
            void nextRowCol()
            {
                if (++col == NCOLS)
                {
                    col = 0;
                    ++row;
                }
            }
        }
    }
}