SlidePages.cs
// 完毕:
using System;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Drawing;
using DsPdfWeb.Demos.Common;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos
{
    // 从目录中找到的所有图像创建“幻灯片”页面。
    // 
    // 重要提示:当您在 GcDocs.Pdf 中多次渲染图像时(例如渲染
    // 相同的图像作为所有页面上页眉的一部分),它将自动
    // 添加到字典中并在整个文档中重复使用,前提是您使用
    // 所有页面上的相同图像对象。因此,不要从以下位置加载相同的图像
    // 每次需要文件(或流)时,最好加载图像
    // 一次并将其缓存在图像对象中。这适用于所有可用的图像类型
    // GcDocs.Pdf(图像、RawImage)。
    public class SlidePages
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            // 获取标题字体:
            var font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf"));
            // GcPdfDocument.ImageOptions 允许您控制各种与图像相关的设置。
            // 特别是,我们可以将 JPEG 质量从默认的 75% 降低以减小文件大小:
            doc.ImageOptions.JpegQuality = 50;

            // 从 Resources/Images 文件夹加载所有图像:
            List<Tuple<string, IImage>> images = new List<Tuple<string, IImage>>();
            foreach (var fname in Directory.GetFiles(Path.Combine("Resources", "Images"), "*", SearchOption.AllDirectories))
                images.Add(Tuple.Create(Path.GetFileName(fname), Util.ImageFromFile(fname)));
            images.Shuffle();
            // 将所有图像打印为 3x4 网格中的幻灯片,四周留有 1/2 英寸边距:
            const float margin = 36;
            const int rows = 4;
            const int cols = 3;
            float gapx = 72f / 4, gapy = gapx;
            float sWidth = (doc.PageSize.Width - margin * 2 + gapx) / cols;
            float sHeight = (doc.PageSize.Height - margin * 2 + gapy) / rows;
            if (sWidth > sHeight)
            {
                gapx += sWidth - sHeight;
                sWidth = sHeight;
            }
            else
            {
                gapy += sHeight - sWidth;
                sHeight = sWidth;
            }
            const float sMargin = 72f / 6;
            // 设置图像对齐方式,使图像在指定区域内居中:
            var ia = new ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Center, true, true, true, false, false);
            // 图像标题的文本格式:
            var tf = new TextFormat() { Font = font, FontSize = sMargin * 0.65f };
            // 插入点:
            var ip = new PointF(margin, margin);
            var g = doc.NewPage().Graphics;
            for (int i = 0; i < images.Count(); ++i)
            {
                var rect = new RectangleF(ip, new SizeF(sWidth - gapx, sHeight - gapy));
                g.FillRectangle(rect, Color.LightGray);
                g.DrawRectangle(rect, Color.Black, 0.5f);
                rect.Inflate(-sMargin, -sMargin);
                // 我们通过 DrawImage 方法获得了绘制图像的实际矩形
                // (通过输出参数)这样我们就可以在图像周围绘制一个细边框
                // (需要一个数组,因为图像可以平铺,在这种情况下需要多个矩形
                // 将被退回):
                g.DrawImage(images[i].Item2, rect, null, ia, out RectangleF[] imageRect);
                g.DrawRectangle(imageRect[0], Color.DarkGray, 1);
                // 在幻灯片底部边距中打印图像文件名作为标题:
                g.DrawString(Path.GetFileName(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 > doc.PageSize.Width && i < images.Count() - 1)
                {
                    ip.X = margin;
                    ip.Y += sHeight;
                    if (ip.Y + sHeight > doc.PageSize.Height)
                    {
                        g = doc.NewPage().Graphics;
                        ip.Y = margin;
                    }
                }
            }
            // 完毕:
            doc.Save(stream);
            // 保存 PDF 后处理图像:
            images.ForEach(t_ => t_.Item2.Dispose());
            return doc.Pages.Count;
        }
    }
}