ImageArticles.vb
''
'' This code is part of GrapeCity Documents for PDF samples.
'' Copyright (c) GrapeCity, Inc. All rights reserved.
''
Imports System.IO
Imports System.Drawing
Imports System.Linq
Imports System.Collections.Generic
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.Articles
Imports GrapeCity.Documents.Imaging
Imports GrapeCity.Documents.Drawing

'' 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:
    Class ArticleNames
        Public Shared Landscape = "Subject: landscape"
        Public Shared Art = "Subject: art"
        Public Shared Flora = "Subject: flora"
        Public Shared Buildings = "Subject: buildings"
        Public Shared Misc = "Subject: Miscellaneous"
        Public Shared AspectHorz = "Aspect: horizontal"
        Public Shared AspectVert = "Aspect: vertical"
        Public Shared AspectSquare = "Aspect: square"
    End Class

    '' Associate known image file names with appropriate subjects:
    Shared _subjects As New Dictionary(Of String, String)() From
        {
            {"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},
            {"out.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:
    Class ImageInfo
        Public Name As String
        Public Image As IImage
        Public Subject As String
        Public Aspect As String
    End Class

    Function CreatePDF(ByVal stream As Stream) As Integer
        '' Load images and their associated infos:
        Dim imageInfos = New List(Of ImageInfo)
        For Each fname In Directory.GetFiles(Path.Combine("Resources", "Images"), "*", SearchOption.AllDirectories)
            Dim image = Util.ImageFromFile(fname)
            Dim aspect As String
            If image.Width > image.Height Then
                aspect = ArticleNames.AspectHorz
            ElseIf image.Width < image.Height Then
                aspect = ArticleNames.AspectVert
            Else
                aspect = ArticleNames.AspectSquare
            End If
            Dim name = Path.GetFileName(fname)
            Dim subject As String = Nothing
            _subjects.TryGetValue(name, subject)
            If String.IsNullOrEmpty(subject) Then
                subject = ArticleNames.Misc
            End If
            imageInfos.Add(New ImageInfo() With {
                .Name = name,
                .Image = image,
                .Subject = subject,
                .Aspect = aspect
                })
        Next
        '' 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:
        Dim articles = New Dictionary(Of String, ArticleThread)()
        For Each subject In _subjects.Values.Distinct()
            articles.Add(subject,
                         New ArticleThread() With {
                            .Info = New DocumentInfo() With {.Title = subject}
                         })
        Next
        articles.Add(ArticleNames.Misc,
                     New ArticleThread() With {.Info = New DocumentInfo() With {.Title = ArticleNames.Misc}})
        Dim horizontals = New ArticleThread() With {.Info = New DocumentInfo() With {.Title = ArticleNames.AspectHorz}}
        Dim verticals = New ArticleThread() With {.Info = New DocumentInfo() With {.Title = ArticleNames.AspectVert}}
        Dim squares = New ArticleThread() With {.Info = New DocumentInfo() With {.Title = ArticleNames.AspectSquare}}

        '' Create the document:
        Dim doc = New GcPdfDocument()

        '' Add images (one per page) to the PDF and article threads:
        Dim ia = New ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Top, True, True, True, False, False)
        For i = 0 To imageInfos.Count - 1
            Dim page = doc.NewPage()
            Dim ii = imageInfos(i)
            Dim 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:
            Dim imageBounds As RectangleF() = Nothing
            page.Graphics.DrawImage(ii.Image, rc, Nothing, ia, imageBounds)
            Dim bounds = imageBounds(0)
            '' Add the image to proper subject and aspect threads:
            articles(ii.Subject).Beads.Add(New ArticleBead() With {.Page = page, .Bounds = bounds})
            If (ii.Aspect = ArticleNames.AspectHorz) Then
                horizontals.Beads.Add(New ArticleBead() With {.Page = page, .Bounds = bounds})
            ElseIf (ii.Aspect = ArticleNames.AspectVert) Then
                verticals.Beads.Add(New ArticleBead() With {.Page = page, .Bounds = bounds})
            Else
                squares.Beads.Add(New ArticleBead() With {.Page = page, .Bounds = bounds})
            End If
        Next
        '' Add subject and aspect article threads to the PDF:
        For Each article In articles.Select(Function(a_) a_.Value)
            doc.ArticleThreads.Add(article)
        Next
        doc.ArticleThreads.Add(horizontals)
        doc.ArticleThreads.Add(verticals)
        doc.ArticleThreads.Add(squares)

        '' Done
        doc.Save(stream)
        Return doc.Pages.Count
    End Function
End Class