ImageArticles.cs
// 完毕:
using System;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Pdf.Articles;
using GrapeCity.Documents.Imaging;
using GrapeCity.Documents.Drawing;
using DsPdfWeb.Demos.Common;

namespace DsPdfWeb.Demos
{
    // 此示例演示如何在 PDF 文档中创建文章线索。
    // 文章线索是一系列相关页面或页面区域,可以
    // 在支持的 PDF 查看器中按顺序导航(向前或向后)。
    // 在此示例中,我们从文件夹加载许多照片并渲染它们
    // 每页一个,顺序随机。
    // 有些照片(通过已知的文件名)与特定主题相关联
    // (建筑物、艺术等),我们将所有与相关的图像
    // 每个主题进入特定主题的文章线程(不是图像
    // 与任何已知主题相关的内容都放在“杂项”线程中)。
    // 此外,我们还为不同的纵横比创建了 3 个线程(水平、
    // 垂直和方形),并将每个图像添加到相应的方面文章中。
    // 请参阅 导览 PDF 页面
    // 有关如何在 Acrobat 中导航文章线索的详细信息
    // (我们的 JavaScript PDF 查看器为此提供了类似的 UI)。
    public class ImageArticles
    {
        // 文章名称:
        static class ArticleNames
        {
            public static string Landscape => "Subject: landscape";
            public static string Art => "Subject: art";
            public static string Flora => "Subject: flora";
            public static string Buildings => "Subject: buildings";
            public static string Misc => "Subject: Miscellaneous";
            public static string AspectHorz => "Aspect: horizontal";
            public static string AspectVert => "Aspect: vertical";
            public static string AspectSquare => "Aspect: square";
        }

        // 将已知图像文件名与适当的主题相关联:
        static readonly Dictionary<string, string> _subjects = new Dictionary<string, string>()
        {
            {"aurora.jpg", ArticleNames.Landscape },
            {"chairs.jpg", ArticleNames.Buildings },
            {"clouds.jpg", ArticleNames.Landscape },
            {"colosseum.jpg", ArticleNames.Art },
            {"deadwood.jpg", ArticleNames.Flora },
            {"door.jpg", ArticleNames.Buildings },
            {"ferns.jpg", ArticleNames.Flora },
            {"fiord.jpg", ArticleNames.Landscape },
            {"firth.jpg", ArticleNames.Landscape },
            {"lady.jpg", ArticleNames.Art },
            {"lavender.jpg", ArticleNames.Flora },
            {"maple.jpg", ArticleNames.Buildings },
            {"minerva.jpg", ArticleNames.Art },
            {"newfoundland.jpg", ArticleNames.Landscape },
            {"pines.jpg", ArticleNames.Flora },
            {"purples.jpg", ArticleNames.Flora },
            {"reds.jpg", ArticleNames.Flora },
            {"road.jpg", ArticleNames.Landscape },
            {"rome.jpg", ArticleNames.Art },
            {"roofs.jpg", ArticleNames.Buildings },
            {"sea.jpg", ArticleNames.Landscape },
            {"skye.jpg", ArticleNames.Landscape },
            {"tudor.jpg", ArticleNames.Buildings },
            {"windswept.jpg", ArticleNames.Flora },
            // 不在此列表中的图像为“杂项”。
        };

        // 保存图像信息的类:
        private class ImageInfo
        {
            public string Name;
            public IImage Image;
            public string Subject;
            public string Aspect;
        }

        public int CreatePDF(Stream stream)
        {
            // 加载图像及其相关信息:
            var imageInfos = new List<ImageInfo>();
            foreach (var fname in Directory.GetFiles(Path.Combine("Resources", "Images"), "*", SearchOption.AllDirectories))
            {
                var image = Util.ImageFromFile(fname);
                var aspect = image.Width > image.Height ? ArticleNames.AspectHorz :
                    (image.Width < image.Height ? ArticleNames.AspectVert : ArticleNames.AspectSquare);
                var name = Path.GetFileName(fname);
                _subjects.TryGetValue(name, out string subject);
                if (string.IsNullOrEmpty(subject))
                    subject = ArticleNames.Misc;
                imageInfos.Add(new ImageInfo()
                {
                    Name = name,
                    Image = image,
                    Subject = subject,
                    Aspect = aspect
                });
            }
            // 随机化 PDF 中图像的顺序:
            imageInfos.Shuffle();

            // 键是文章主题名称(来自 ArticleNames),
            // 值是要添加到 PDF 的 ArticleThread 对象:
            var articles = new Dictionary<string, ArticleThread>();
            foreach (var subject in _subjects.Values.Distinct())
                articles.Add(subject,
                    new ArticleThread()
                    {
                        Info = new DocumentInfo() { Title = subject }
                    });
            articles.Add(ArticleNames.Misc,
                new ArticleThread()
                {
                    Info = new DocumentInfo() { Title = ArticleNames.Misc }
                });
            var horizontals = new ArticleThread()
            {
                Info = new DocumentInfo() { Title = ArticleNames.AspectHorz }
            };
            var verticals = new ArticleThread()
            {
                Info = new DocumentInfo() { Title = ArticleNames.AspectVert }
            };
            var squares = new ArticleThread()
            {
                Info = new DocumentInfo() { Title = ArticleNames.AspectSquare }
            };

            // 创建文档:
            var doc = new GcPdfDocument();

            // 将图像(每页一张)添加到 PDF 和文章线程:
            var ia = new ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Top, true, true, true, false, false);
            for (int i = 0; i < imageInfos.Count; ++i)
            {
                var page = doc.NewPage();
                var ii = imageInfos[i];
                var rc = new RectangleF(72, 72, doc.PageSize.Width - 144, doc.PageSize.Height - 144);
                // 请注意,我们获取实际图像边界以精确指定线程中的页面区域:
                page.Graphics.DrawImage(ii.Image, rc, null, ia, out RectangleF[] imageBounds);
                var bounds = imageBounds[0];
                // 将图像添加到适当的主题和方面线程:
                articles[ii.Subject].Beads.Add(new ArticleBead() { Page = page, Bounds = bounds });
                if (ii.Aspect == ArticleNames.AspectHorz)
                    horizontals.Beads.Add(new ArticleBead() { Page = page, Bounds = bounds });
                else if (ii.Aspect == ArticleNames.AspectVert)
                    verticals.Beads.Add(new ArticleBead() { Page = page, Bounds = bounds });
                else
                    squares.Beads.Add(new ArticleBead() { Page = page, Bounds = bounds });
            }
            // 将主题和方面文章线程添加到 PDF:
            foreach (var article in articles.Select(a_ => a_.Value))
                doc.ArticleThreads.Add(article);
            doc.ArticleThreads.Add(horizontals);
            doc.ArticleThreads.Add(verticals);
            doc.ArticleThreads.Add(squares);

            // 完毕:
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}