SvgFontAwesome.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.Linq;
using System.Collections.Generic;
using GrapeCity.Documents.Imaging;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Svg;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
using DsImagingWeb.Demos.Common;

namespace DsImagingWeb.Demos
{
    // This sample shows how to render SVG icons included in the "Free for Web" download of Font Awesome.
    // The sample code also shows how to change the default color of the glyphs.
    public class SvgFontAwesome
    {
        private Random _rnd = Util.NewRandom();

        public Stream GenerateImageStream(string targetMime, Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
        {
            if (sampleParams == null)
                sampleParams = GetSampleParamsList()[0];

            // Font and format for captions:
            const float sMargin = 96f / 8;
            var font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf"));
            var tf = new TextFormat() { Font = font, FontSize = sMargin * 0.65f };

            // Set up a layout grid:
            var background = Color.White;
            var foreground = Color.Black;
            const float margin = 36;
            const int rows = 10;
            const int cols = 10;
            float gapx = 96f / 8, gapy = gapx;
            float sWidth = (pixelSize.Width - margin * 2 + gapx) / cols;
            float sHeight = (pixelSize.Height - margin * 2 + gapy) / rows;
            if (sWidth > sHeight)
            {
                gapx += sWidth - sHeight;
                sWidth = sHeight;
            }
            else
            {
                gapy += sHeight - sWidth;
                sHeight = sWidth;
            }
            var ip = new PointF(margin, margin);
            var colorize = sampleParams[3] == "colorize";
            var maxFiles = targetMime == Util.MimeTypes.TIFF ? int.MaxValue : rows * cols;
            var fileNames = Directory.GetFiles(Path.Combine("Resources", "FontAwesome", colorize ? string.Empty : sampleParams[3]), "*.svg", SearchOption.AllDirectories).ToList();
            if (colorize)
                fileNames.Shuffle();
            else
                fileNames.Sort(StringComparer.Ordinal);
            var files = fileNames.Take(maxFiles);

            var images = new List<(string, GcSvgDocument)>(files.Count());
            foreach (var fname in files)
                images.Add((fname, GcSvgDocument.FromFile(fname)));

            // Render all images within the grid, adding new pages as needed:
            var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, false, dpi, dpi);
            var g = bmp.CreateGraphics(Color.White);
            var ms = new MemoryStream();
            GcTiffWriter tw = null;
            if (targetMime == Util.MimeTypes.TIFF)
                tw = new GcTiffWriter(ms);

            for (int i = 0; i < images.Count(); ++i)
            {
                // Draw border around image:
                var rect = new RectangleF(ip, new SizeF(sWidth - gapx, sHeight - gapy));
                g.FillRectangle(rect, background);
                g.DrawRectangle(rect, foreground, 0.5f);
                rect.Inflate(-sMargin, -sMargin);

                // Draw the SVG:
                var svg = images[i].Item2;
                var s = svg.GetIntrinsicSize(SvgLengthUnits.Points);
                if (s.Width > 0 && s.Height > 0)
                {
                    // If image proportions are different from our target rectangle,
                    // we resize the rectangle centering the image in it:
                    var qSrc = s.Width / s.Height;
                    var qTgt = rect.Width / rect.Height;
                    if (qSrc < qTgt)
                        rect.Inflate(rect.Width * (qSrc / qTgt - 1) / 2, 0);
                    else if (qSrc > qTgt)
                        rect.Inflate(0, rect.Height * (qTgt / qSrc - 1) / 2);
                }
                //
                if (colorize)
                    svg.RootSvg.Fill = new SvgPaint(Color.FromArgb(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256)));

                // Render the SVG:
                g.DrawSvg(svg, rect);

                // Print the icon file name as caption in the bottom margin:
                g.DrawString(Path.GetFileNameWithoutExtension(images[i].Item1), tf,
                    new RectangleF(rect.X, rect.Bottom, rect.Width, sMargin),
                    TextAlignment.Center, ParagraphAlignment.Near, false);
                ip.X += sWidth;
                if (ip.X + sWidth > pixelSize.Width && i < images.Count() - 1)
                {
                    ip.X = margin;
                    ip.Y += sHeight;
                    if (ip.Y + sHeight > pixelSize.Height)
                    {
                        if (targetMime != Util.MimeTypes.TIFF)
                            throw new Exception("Unexpected: should get here only if target is TIFF.");

                        tw.AppendFrame(bmp);
                        bmp.Clear(Color.White);
                        ip.Y = margin;
                    }
                }
            }
            switch (targetMime)
            {
                case Common.Util.MimeTypes.TIFF:
                    tw.Dispose();
                    break;
                case Common.Util.MimeTypes.JPEG:
                    bmp.SaveAsJpeg(ms);
                    break;
                case Common.Util.MimeTypes.PNG:
                    bmp.SaveAsPng(ms);
                    break;
                case Common.Util.MimeTypes.BMP:
                    bmp.SaveAsBmp(ms);
                    break;
                case Common.Util.MimeTypes.GIF:
                    bmp.SaveAsGif(ms);
                    break;
                case Common.Util.MimeTypes.WEBP:
                    bmp.SaveAsWebp(ms);
                    break;
                default:
                    throw new Exception($"Encoding {targetMime} is not supported.");
            }
            bmp.Dispose();
            g.Dispose();
            // Dispose images when done:
            images.ForEach(t_ => t_.Item2.Dispose());
            return ms;
        }

        public static List<string[]> GetSampleParamsList()
        {
            // Strings are name, description, info, rest are arbitrary strings:
            return new List<string[]>()
            {
                new string[] { "@b-svg/Font Awesome - brands", "Render Font Awesome SVG glyphs from the \"svgs/brands\" directory",
                    "This sample renders the SVG icons included in the \"svgs/brands/\" directory of the Font Awesome \"Free for Web\" download, sorted by file name.",
                    "brands" },
                new string[] { "@b-svg/Font Awesome - regular", "Render Font Awesome SVG glyphs from the \"svgs/brands\" directory",
                    "This sample renders the SVG icons included in the \"svgs/regular/\" directory of the Font Awesome \"Free for Web\" download, sorted by file name.",
                    "regular" },
                new string[] { "@b-svg/Font Awesome - solid", "Render Font Awesome SVG glyphs from the \"svgs/solid\" directory",
                    "This sample renders the SVG icons included in the \"svgs/solid/\" directory of the Font Awesome \"Free for Web\" download, sorted by file name.",
                    "solid" },
                new string[] { "@b-svg/Font Awesome - colorize", "Render Font Awesome SVG glyphs using random order and colors",
                    "This sample renders the SVG icons included in the \"svgs/\" directory of the Font Awesome \"Free for Web\" download, randomizing the order of the icons and their colors.",
                    "colorize" },
            };
        }
    }
}