TextAroundImages.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 GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Drawing

'' This sample shows how to flow a large block of text around rectangular areas,
'' in this case images. It also demonstrates how to get the actual bounds
'' of an image that has been rendered on a page using a specific ImageAlign.
Public Class TextAroundImages
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()
        Dim g = doc.NewPage().Graphics
        ''
        '' We want to draw 3 images in certain arbitrary locations on the first page, 
        '' and then print a text that would take 2-3 pages, and have it flow around
        '' the images on the first page.
        ''
        '' Get the images and their rectangles. Note that we specify a square
        '' area for all images - but they will be aligned within that area
        '' preserving their original aspect ratios, so we will later retrieve
        '' the actual rectangles where the images were drawn:
        Using imgPuffins As Image = Image.FromFile(Path.Combine("Resources", "Images", "puffins.jpg")),
            imgReds As Image = Image.FromFile(Path.Combine("Resources", "Images", "reds.jpg")),
            imgLavender As Image = Image.FromFile(Path.Combine("Resources", "Images", "lavender.jpg"))
            Dim rectPuffins = New RectangleF(100, 70, 180, 180)
            Dim rectReds = New RectangleF(300, 280, 180, 180)
            Dim rectLavender = New RectangleF(190, 510, 180, 180)
            '' Set up ImageAlign that would fit and center an image within a specified area,
            '' preserving the image's original aspect ratio:
            Dim ia = New ImageAlign(ImageAlignHorz.Center, ImageAlignVert.Center, True, True, True, False, False)
            '' Draw each image, providing an array of rectangles as an output parameter for each DrawImage call,
            '' so that we get the actual rectangle taken by the image (an array is needed to handle tiled images):
            Dim rectsPuffins As RectangleF() = Nothing
            g.DrawImage(imgPuffins, rectPuffins, Nothing, ia, rectsPuffins)
            Dim rectsReds As RectangleF() = Nothing
            g.DrawImage(imgReds, rectReds, Nothing, ia, rectsReds)
            Dim rectsLavender As RectangleF() = Nothing
            g.DrawImage(imgLavender, rectLavender, Nothing, ia, rectsLavender)
            '' Create and set up a TextLayout object to print the text:
            Dim tl = g.CreateTextLayout()
            tl.DefaultFormat.Font = StandardFonts.Times
            tl.DefaultFormat.FontSize = 9
            tl.TextAlignment = TextAlignment.Justified
            tl.ParagraphSpacing = 72 / 8
            tl.MaxWidth = doc.PageSize.Width
            tl.MaxHeight = doc.PageSize.Height
            '' 1/2" margins all around
            tl.MarginAll = 72 / 2
            '' ObjectRect is the type used to specify the areas to flow around to TextLayout.
            '' We set up a local function to create an ObjecRect based on an image rectangle,
            '' adding some padding so that the result looks nicer:
            Dim makeObjectRect As Func(Of RectangleF, ObjectRect) =
            Function(ByVal rect_)
                Return New ObjectRect(rect_.X - 6, rect_.Y - 2, rect_.Width + 12, rect_.Height + 4)
            End Function
            '' Specify the array of ObjectRects on the TextLayout:
            tl.ObjectRects = New List(Of ObjectRect)() From {
                makeObjectRect(rectsPuffins(0)),
                makeObjectRect(rectsReds(0)),
                makeObjectRect(rectsLavender(0))
            }
            '' Add several paragraphs of text:
            tl.Append(Util.LoremIpsum(7, 5, 6, 28, 32))
            '' Calculate glyphs and lay out the text:
            tl.PerformLayout(True)
            '' Split options to control splitting of text between pages.
            '' We can either use the default ctor and set up values like MaxWidth etc,
            '' or create a TextSplitOptions based on the TextLayout, and clear RestObjectRects:
            Dim tso = New TextSplitOptions(tl) With {
                .RestObjectRects = Nothing,
                .MinLinesInFirstParagraph = 2,
                .MinLinesInLastParagraph = 2
            }
            '' In a loop, split and render the text:
            While True
                '' 'rest' will accept the text that did not fit:
                Dim rest As TextLayout = Nothing
                Dim splitResult = tl.Split(tso, rest)
                doc.Pages.Last.Graphics.DrawTextLayout(tl, PointF.Empty)
                If splitResult <> SplitResult.Split Then
                    Exit While
                End If
                tl = rest
                '' We only draw images on the first page:
                tl.ObjectRects = Nothing
                doc.Pages.Add()
            End While
            ''
            '' Done:
            doc.Save(stream)
            Return doc.Pages.Count
        End Using
    End Function
End Class