1

I'm trying to reorder several pages in a PDF file. I found some code in a blog but couldn't get it to work. I have a two page pdf, and I want to get the last page to appear as first. I always get an exception saying that page number has to match with order. When I checked the document object, it shows 0 pages. But the PDF passed into has two pages.

public void reOrder(string inputFile)
{ 
    Document document = new Document();
    FileStream fs = new FileStream(inputFile, FileMode.Open);
    PdfWriter writer = PdfWriter.GetInstance(document, fs);
    document.AddDocListener(writer);                
    writer.SetLinearPageMode();
    int[] order = {2,1};
    writer.ReorderPages(order);
}
Alexis Pigeon
  • 7,423
  • 11
  • 39
  • 44
IamaC
  • 357
  • 1
  • 10
  • 23

3 Answers3

4

Whenever you use iTextSharp to write something you need to create a new document, it will never write to an existing document. In your case, page reordering would require writing so you need create a new document, bring over the pages and then reorder them. (Of course, you could also just reorder them upon import, too.)

        var inputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Test.pdf");
        var output = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Output.pdf");

        //Bind a reader to our input file
        var reader = new PdfReader(inputFile);

        //Create our output file, nothing special here
        using (FileStream fs = new FileStream(output, FileMode.Create, FileAccess.Write, FileShare.None)) {
            using (Document doc = new Document(reader.GetPageSizeWithRotation(1))) {
                //Use a PdfCopy to duplicate each page
                using (PdfCopy copy = new PdfCopy(doc, fs)) {
                    doc.Open();
                    copy.SetLinearPageMode();
                    for (int i = 1; i <= reader.NumberOfPages; i++) {
                        copy.AddPage(copy.GetImportedPage(reader, i));
                    }
                    //Reorder pages
                    copy.ReorderPages(new int[] { 2, 1 });
                    doc.Close();
                }
            }
        }
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
1

@Chris Haas' answer is good, but it's not the only way.

Here was my situation:

  1. I first generated a document with XMLWorker and a Razor view.
  2. Then I appended zero-to-many images, each as their own page.
  3. The customer wanted to reorder the document so that the image pages would follow page 1 (i.e. As pages 2, 3, 4, etc.).

Here was the code that I used to do this:

    private static void MoveImagesToPage2(ICollection imagesToBePrintedOnSeparatePages, IDocListener pdfDocument, PdfWriter pdfWriter)
    {
        pdfDocument.NewPage(); // required - http://itextpdf.com/examples/iia.php?id=98

        var numberOfPages = pdfWriter.ReorderPages(null);
        var newOrder = new int[numberOfPages];
        newOrder[0] = 1; // Keep page 1 as page 1

        var i = 1;
        for (var j = imagesToBePrintedOnSeparatePages.Count - 1; 0 <= j; j--)
        {
            newOrder[i] = numberOfPages - j;
            i++;
        }

        for (; i < numberOfPages; i++)
        {
            newOrder[i] = i - (imagesToBePrintedOnSeparatePages.Count - 1);
        }

        pdfWriter.ReorderPages(newOrder);
    }

Please be mindful of this line:

pdfDocument.NewPage(); // required - http://itextpdf.com/examples/iia.php?id=98

This line is necessary if you want to move the last page in the document. (I have no idea why.)

But if it's necessary, then you'll need this line to delete the blank page after you're done:

    private static byte[] RemoveTheLastPageWhichWasAddedForReordering(byte[] renderedBuffer)
    {
        var originalPdfReader = new PdfReader(renderedBuffer);

        using (var msCopy = new MemoryStream())
        {
            using (var docCopy = new Document())
            {
                using (var copy = new PdfCopy(docCopy, msCopy))
                {
                    docCopy.Open();
                    for (var pageNum = 1; pageNum <= originalPdfReader.NumberOfPages - 1; pageNum++)
                    {
                        copy.AddPage(copy.GetImportedPage(originalPdfReader, pageNum));
                    }
                    docCopy.Close();
                }
            }

            return msCopy.ToArray();
        }
    }

Special thanks to @Craig Howard for the snippet above.

Community
  • 1
  • 1
Jim G.
  • 15,141
  • 22
  • 103
  • 166
1

From @Mathew Leger's answer:

An option for trimming pages is to use the PdfReader.SelectPages() combined with PdfStamper. I wrote the code below with iTextSharp 5.5.1.

public void SelectPages(string inputPdf, string pageSelection, string outputPdf)
{
    using (PdfReader reader = new PdfReader(inputPdf))
    {
        reader.SelectPages(pageSelection);

        using (PdfStamper stamper = new PdfStamper(reader, File.Create(outputPdf)))
        {
            stamper.Close();
        }
    }
}

Then you just have to call this method with the correct page selection for each condition.

Condition 1:

SelectPages(inputPdf, "1-4", outputPdf);

Condition 2:

SelectPages(inputPdf, "1-4,6", outputPdf);

or

SelectPages(inputPdf, "1-6,!5", outputPdf);

Condition 3:

SelectPages(inputPdf, "1-5", outputPdf);

Here's the comment from the iTextSharp source code on what makes up a page selection. This is in the SequenceList class which is used to process a page selection:

/**
* This class expands a string into a list of numbers. The main use is to select a
* range of pages.
* <p>
* The general systax is:<br>
* [!][o][odd][e][even]start-end
* <p>
* You can have multiple ranges separated by commas ','. The '!' modifier removes the
* range from what is already selected. The range changes are incremental, that is,
* numbers are added or deleted as the range appears. The start or the end, but not both, can be ommited.
*/
Community
  • 1
  • 1
Jim G.
  • 15,141
  • 22
  • 103
  • 166