3

Using iTextSharp I am creating a PDF composed of a collection of existing PDFs, some of the included PDFs are landscape orientation and need to be rotated. So, I do the following:

    private static void AdjustRotationIfNeeded(PdfImportedPage pdfImportedPage, PdfReader reader, int documentPage)
    {
        float width = pdfImportedPage.Width;
        float height = pdfImportedPage.Height;

        if (pdfImportedPage.Rotation != 0)
        {
            PdfDictionary pageDict = reader.GetPageN(documentPage);
            pageDict.Put(PdfName.ROTATE, new PdfNumber(0));
        }

        if (width > height)
        {
            PdfDictionary pageDict = reader.GetPageN(documentPage);
            pageDict.Put(PdfName.ROTATE, new PdfNumber(270));
        }
    }

This works great. The included PDFs rotated to portrait orientation if needed. The PDF prints correctly on my local printer.

This file is sent to a fulfillment house, and unfortunately, the landscape included files do not print properly when going through their printer and rasterization process. They use Kodak (Creo) NexRip 11.01 or Kodak (Creo) Prinergy 6.1. machines. The fulfillment house's suggestion is to: "generate a new PDF file after we rotate pages or make any changes to a PDF. It is as easy as exporting out to a PostScript and distilling back to a PDF."

I know iTextSharp doesn't support PostScript. Is there another way iTextSharp can rotate included PDFs to hold the orientation when rasterized?

Fluffy
  • 119
  • 3
  • 11

1 Answers1

3

First let me assure you that changing the rotation in the page dictionary is the correct procedure to achieve what you want. As far as I can see your code, there's nothing wrong with it. You are doing the right thing.

Unfortunately, you are faced with a third party product over which you have no control that is not doing the right thing. How to solve this?

I have written an example called IncorrectExample. I have named it that way because I don't want it to be used in a context that is different from yours. You can safely ignore all the warnings I added: they are not meant for you. This example is very specific to your problem.

Please try the following code:

public void manipulatePdf(String src, String dest)
    throws IOException, DocumentException {
    // Creating a reader
    PdfReader reader = new PdfReader(src);
    // step 1
    Rectangle pagesize = getPageSize(reader, 1);
    Document document = new Document(pagesize);
    // step 2
    PdfWriter writer
        = PdfWriter.getInstance(document, new FileOutputStream(dest));
    // step 3
    document.open();
    // step 4
    PdfContentByte cb = writer.getDirectContent();
    for (int i = 1; i <= reader.getNumberOfPages(); i++) {
        pagesize = getPageSize(reader, i);
        document.setPageSize(pagesize);
        document.newPage();
        PdfImportedPage page = writer.getImportedPage(reader, i);
        if (isPortrait(reader, i)) {
            cb.addTemplate(page, 0, 0);
        }
        else {
            cb.addTemplate(page, 0, 1, -1, 0, pagesize.getWidth(), 0);
        }
    }
    // step 4
    document.close();
    reader.close();
}

public Rectangle getPageSize(PdfReader reader, int pagenumber) {
    Rectangle pagesize = reader.getPageSizeWithRotation(pagenumber);
    return new Rectangle(
            Math.min(pagesize.getWidth(), pagesize.getHeight()),
            Math.max(pagesize.getWidth(), pagesize.getHeight()));
}

public boolean isPortrait(PdfReader reader, int pagenumber) {
    Rectangle pagesize = reader.getPageSize(pagenumber);
    return pagesize.getHeight() > pagesize.getWidth();
}

I have taken the pages.pdf file as an example. This file is special in the sense that it has two pages in landscape that are created in a different way:

  • one page is a page of which the width is smaller than the height (sounds like it's a page in portrait), but as there's a /Rotate value of 90 added to the page dictionary, it is shown in landscape.
  • the other page isn't rotated, but it has a height that is smaller than the width.

In my example, I am using the classes Document and PdfWriter to create a copy of the original document. This is wrong in general because it throws away all interaction. I should use PdfStamper or PdfCopy instead, but it is right in your specific case because you don't need the interactivity: the final purpose of the PDF is to be printed.

With Document, I create new pages using a new Rectangle that uses the lowest value of the dimensions of the existing page as the width and the highest value as the height. This way, the page will always be in portrait. Note that I use the method getPageSizeWithRotation() to make sure I get the correct width and height, taking into account any possible rotation.

I then add a PdfImportedPage to the direct content of the writer. I use the isPortrait() method to find out if I need to rotate the page or not. Observe that the isPortrait() method looks at the page size without taking into account the rotation. If we did take into account the rotation, we'd rotate pages that don't need rotating.

The resulting PDF can be found here: pages_changed.pdf

As you can see, some information got lost: there was an annotation on the final page: it's gone. There were specific viewer preferences defined for the original document: they're gone. But that shouldn't matter in your specific case, because all that matters for you is that the pages are printed correctly.

Niby
  • 474
  • 1
  • 6
  • 20
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165