SlidePages.cs
// 
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// Copyright (c) GrapeCity inc. All rights reserved.
// 
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 GcPdfWeb.Samples.Common;

namespace GcPdfWeb.Samples
{
    // ディレクトリにあるすべての画像から「スライド」のページを作成します。
    // 
    // 重要:GcPdf 内で画像を複数回描画するとき(例えば、すべてのページのページヘッダの一部として
    // 同じ画像を描画するなど)、すべてのページで同じイメージオブジェクトを使用する場合は、
    // 自動的に辞書に追加され、ドキュメント全体で再利用されます。
    // そのため、必要になるたびにファイル(またはストリーム)から同じ画像を読み込むのではなく、
    // 画像を一度読み込んでイメージオブジェクトにキャッシュすることが常に望ましいです。
    // これは、GcPdf(Image、RawImage)で利用できるすべての画像形式に適用されます。
    public class SlidePages
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            // キャプション用のフォントを取得します。
            var font = 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;
            // 画像を指定された領域内の中心に配置するよう設定します。
            ImageAlign ia = new ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Center, true, true, true, false, false);
            // 画像キャプションのテキスト書式。
            TextFormat tf = new TextFormat() { Font = font, FontSize = sMargin * 0.65f };
            // 挿入位置。
            PointF 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;
                    }
                }
            }
            // PDF ドキュメントを保存します。
            doc.Save(stream);
            // PDF を保存した後に画像を廃棄します。
            images.ForEach(t_ => t_.Item2.Dispose());
            return doc.Pages.Count;
        }
    }
}