PDFBox - merge 2 portrait pages onto a single side by side landscape page

java, pdf, pdfbox

Solution

I ended up doing this with itext

private String createTwoUp(String originalPdfFile) throws IOException, DocumentException {
    String newFilename = FilenameUtils.getBaseName(originalPdfFile) + "_2up." + FilenameUtils.getExtension(originalPdfFile);
    newFilename = FilenameUtils.concat(getPdfFileFolder(), newFilename);
    PdfReader reader = new PdfReader(originalPdfFile);
    Document doc = new Document(new RectangleReadOnly(842f, 595f), 0, 0, 0, 0);
    PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(newFilename));
    doc.open();
    int totalPages = reader.getNumberOfPages();
    for (int i = 1; i <= totalPages; i = i + 2) {
        doc.newPage();
        PdfContentByte cb = writer.getDirectContent();
        PdfImportedPage page = writer.getImportedPage(reader, i); // page #1

        float documentWidth = doc.getPageSize().getWidth() / 2;
        float documentHeight = doc.getPageSize().getHeight();
        if (i > 1) {
            documentHeight = documentHeight - 65f;
        }

        float pageWidth = page.getWidth();
        float pageHeight = page.getHeight();

        float widthScale = documentWidth / pageWidth;
        float heightScale = documentHeight / pageHeight;
        float scale = Math.min(widthScale, heightScale);

        //float offsetX = 50f;
        float offsetX = (documentWidth - (pageWidth * scale)) / 2;
        float offsetY = 0f;

        cb.addTemplate(page, scale, 0, 0, scale, offsetX, offsetY);

        if (i+1 <= totalPages) {

            PdfImportedPage page2 = writer.getImportedPage(reader, i+1); // page #2

            pageWidth = page.getWidth();
            pageHeight = page.getHeight();

            widthScale = documentWidth / pageWidth;
            heightScale = documentHeight / pageHeight;
            scale = Math.min(widthScale, heightScale);

            offsetX = ((documentWidth - (pageWidth * scale)) / 2) + documentWidth;

            cb.addTemplate(page2, scale, 0, 0, scale, offsetX, offsetY);
        }
    }

    doc.close();
    return newFilename;
}

Problem

I am trying to write a pdf conversion, that will take a pdf containing 1-up portrait pages, and create a new document, but merge every 2 pages into one 2-up landscape page ie. the following code will scale down the content 50%, but I cant figure out how to make the new page landscape, while injecting the other page as portrait, and injecting into the top left, and right of centre ``` public static void main(String[] args) throws IOException, DocumentException, COSVisitorException { scalePages("c:/pdf/in.pdf", "c:/pdf/out" + new Date().getTime() + ".pdf", 0.50f); } public static void scalePages(String inFile, String outFile, float scale ) throws IOException, COSVisitorException { PDDocument doc1 = null; try { doc1 = PDDocument.load( inFile ); List allPages = doc1.getDocumentCatalog().getAllPages(); for( int i=0; i<allPages.size(); i++ ) { PDPage page1 = (PDPage)allPages.get(i ); PDRectangle mediaBox = page1.getMediaBox(); float oldX = mediaBox.getUpperRightX(); float newX = oldX * scale; float oldY = mediaBox.getUpperRightY(); float newY = oldY * scale; mediaBox.setUpperRightX(newX); mediaBox.setUpperRightY(newY); PDFStreamParser parser = new PDFStreamParser(page1.getContents()); parser.parse(); List tokens = parser.getTokens(); tokens.add(0,new COSFloat(scale)); tokens.add(1,new COSInteger(0)); tokens.add(2,new COSInteger(0)); tokens.add(3,new COSFloat(scale)); tokens.add(4,new COSInteger(0)); tokens.add(5,new COSInteger(0)); tokens.add(6,PDFOperator.getOperator("cm")); PDStream newContents = new PDStream( doc1 ); ContentStreamWriter writer = new ContentStreamWriter( newContents.createOutputStream() ); writer.writeTokens( tokens ); newContents.addCompression(); page1.setContents(newContents); //page1.setRotation(90); mediaBox.setUpperRightX(oldX); mediaBox.setUpperRightY(oldY); } doc1.save( outFile ); } finally { if( doc1 != null ) { doc1.close(); } } } ``` so the result is as follows any pointers would be greatly appreciated

Original source