//
// 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 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
{
// This sample shows how to create article threads in a PDF document.
// An article thread is a sequence of related pages or page areas that can be
// navigated sequentially (forward or back) in a supporting PDF viewer.
// In this sample we load a number of photos from a folder and render them
// one per page in a random order.
// Some photos are associated (via known file names) with a specific subject
// (buildings, art, etc.), and we put all images associated with
// each subject into a subject-specific article thread (images that are not
// associated with any known subject are put in the 'Miscellaneous' thread).
// In addition we create 3 threads for different aspect ratios (horizontal,
// vertical and square), and add each image to the appropriate aspect article.
// See section 'Article threads' in Navigating PDF pages
// for details on how to navigate article threads in Acrobat
// (our JavaScript PDF viewer provides a similar UI for this).
public class ImageArticles
{
// Article names:
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";
}
// Associate known image file names with appropriate subjects:
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 },
// Images not in this list are 'misc'.
};
// Class to hold image info:
private class ImageInfo
{
public string Name;
public IImage Image;
public string Subject;
public string Aspect;
}
public int CreatePDF(Stream stream)
{
// Load images and their associated infos:
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
});
}
// Randomize the order of images in the PDF:
imageInfos.Shuffle();
// Keys are article thread names (from ArticleNames),
// values are ArticleThread objects to be added to the PDF:
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 }
};
// Create the document:
var doc = new GcPdfDocument();
// Add images (one per page) to the PDF and article threads:
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);
// Note that we get the actual image bounds to precisely specify the page area in the thread:
page.Graphics.DrawImage(ii.Image, rc, null, ia, out RectangleF[] imageBounds);
var bounds = imageBounds[0];
// Add the image to proper subject and aspect threads:
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 });
}
// Add subject and aspect article threads to the 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);
// Done:
doc.Save(stream);
return doc.Pages.Count;
}
}
}