Tubc
Tubc

Reputation: 416

iTextSharp PDF Merging and adding page number in one go

I use this code to merge and add page number to the document:

            Using stream As FileStream = New FileStream(targetPDF, FileMode.Create)
            Dim myDoc As Document
            If (ExportOption.Orientation = Global.GenerateReport.GenerateReport.Orientation.Portrait) Then
                myDoc = New Document(New iTextSharp.text.Rectangle(PAGE_WIDTH, PAGE_HEIGHT), MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM)
                myDoc.SetPageSize(PageSize.A4)
            Else
                myDoc = New Document(New iTextSharp.text.Rectangle(PAGE_WIDTH, PAGE_HEIGHT), MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM)
                myDoc.SetPageSize(PageSize.A4.Rotate())
            End If
            Dim pdfCopy As PdfCopy = New PdfCopy(myDoc, stream)
            myDoc.Open()

            Dim files() As String = Directory.GetFiles(sourceDir)
            For Each pdffile As String In files
                Dim reader As PdfReader = New PdfReader(pdffile)
                pdfCopy.AddDocument(reader)
                reader.Close()
            Next

            If (Not myDoc Is Nothing) Then
                myDoc.Close()
                pdfCopy.Close()
            End If
        End Using

        Dim bytes As Byte() = File.ReadAllBytes(targetPDF)
        Dim blackFont As iTextSharp.text.Font = FontFactory.GetFont("HELVETICA", 8, iTextSharp.text.Font.NORMAL, BaseColor.BLACK)
        Using stream As New MemoryStream()
            Dim reader As New PdfReader(bytes)
            Using stamper As New PdfStamper(reader, stream)

                Dim bottom As Single = 10.0F
                Dim left As Single = 550.0F

                Dim pages As Integer = reader.NumberOfPages
                For i As Integer = 1 To pages
                    ColumnText.ShowTextAligned(stamper.GetUnderContent(i), Element.ALIGN_RIGHT, New Phrase("Page " & i.ToString() & " of " & reader.NumberOfPages, blackFont), left, bottom, 0)
                Next
            End Using
            bytes = stream.ToArray()
        End Using
        File.WriteAllBytes(targetPDF, bytes)

How can I do it in just one go?

Some more details about my situation: I need to create a big file, in normal way the code ran for several days and threw Out of memory exception, so I split it to smaller documents, it works great but the page number is all wrong, then I come to this part.

Upvotes: 0

Views: 2627

Answers (2)

Chris Haas
Chris Haas

Reputation: 55457

Just a note, an OOM with iTextSharp is usually triggered when you aren't properly disposing things and doesn't always means that you're working with files that are too large. The runtime will swamp "memory" from RAM to disk for you which will slow things down but shouldn't crash anything (unless you run out of disk space of course).

For your first block I'd encourage you to use the using pattern as much as possible to handle this for you automatically. I didn't run this code through VS so it might not be 100% correct but should be pretty much accurate.

Using stream As New FileStream(targetPDF, FileMode.Create)
    Using myDoc As New Document(New iTextSharp.text.Rectangle(PAGE_WIDTH, PAGE_HEIGHT), MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM)

        If (ExportOption.Orientation = Global.GenerateReport.GenerateReport.Orientation.Portrait) Then
            myDoc.SetPageSize(PageSize.A4)
        Else
            myDoc.SetPageSize(PageSize.A4.Rotate())
        End If

        Using pdfCopy New PdfCopy(myDoc, stream)

            myDoc.Open()

            Dim files() As String = Directory.GetFiles(sourceDir)
            For Each pdffile As String In files
                Using reader As PdfReader = New PdfReader(pdffile)
                    pdfCopy.AddDocument(reader)
                End Using
            Next

            myDoc.Close()

        End Using
    End Using
End Using

@mkl's solution shows you how to do it in one pass which is what you asked for, I just wanted to make sure that you knew when and how Dispose of things.

Upvotes: 2

mkl
mkl

Reputation: 96039

To merge documents and stamp something on them at the same time, you can use a PdfCopy.PageStamp. The sample ConcatenateStamp.cs (corresponding to the java sample ConcatenateStamp.java from the book "iText in Action - 2nd Edition") demonstrates the use of a PdfCopy.PageStamp:

using (Document document = new Document()) {
    using (PdfCopy copy = new PdfCopy(document, OUTPUT_STREAM)) {
        document.Open();
        // reader for document 1
        PdfReader reader1 = new PdfReader(r1);
        int n1 = reader1.NumberOfPages;
        // reader for document 2
        PdfReader reader2 = new PdfReader(r2);
        int n2 = reader2.NumberOfPages;
        // initializations
        PdfImportedPage page;
        PdfCopy.PageStamp stamp;
        // Loop over the pages of document 1
        for (int i = 0; i < n1; ) {
            page = copy.GetImportedPage(reader1, ++i);
            stamp = copy.CreatePageStamp(page);
            // add page numbers
            ColumnText.ShowTextAligned(
              stamp.GetUnderContent(), Element.ALIGN_CENTER,
              new Phrase(string.Format("page {0} of {1}", i, n1 + n2)),
              297.5f, 28, 0
            );
            stamp.AlterContents();
            copy.AddPage(page);
        }

        // Loop over the pages of document 2
        for (int i = 0; i < n2; ) {
            page = copy.GetImportedPage(reader2, ++i);
            stamp = copy.CreatePageStamp(page);
            // add page numbers
            ColumnText.ShowTextAligned(
              stamp.GetUnderContent(), Element.ALIGN_CENTER,
              new Phrase(string.Format("page {0} of {1}", n1 + i, n1 + n2)),
              297.5f, 28, 0
            );
            stamp.AlterContents();
            copy.AddPage(page);
        }   
    }   
}

(The sample is in C#, not VB but it should serve to give an idea...)

Upvotes: 3

Related Questions