Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

pdf

pdfbox

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

like image 647
kabal Avatar asked Dec 26 '22 19:12

kabal


2 Answers

Here is an example that "stitches" two one page PDFs side-by-side and saves result in a new file using PDFBox. Enjoy!

function void generateSideBySidePDF() {
    File pdf1File = new File(FILE1_PATH);
    File pdf2File = new File(FILE2_PATH);
    File outPdfFile = new File(OUTFILE_PATH);
    PDDocument pdf1 = null;
    PDDocument pdf2 = null;
    PDDocument outPdf = null;
    try {
        pdf1 = PDDocument.load(pdf1File);
        pdf2 = PDDocument.load(pdf2File);
        outPdf = new PDDocument();

        // Create output PDF frame
        PDRectangle pdf1Frame = pdf1.getPage(0).getCropBox();
        PDRectangle pdf2Frame = pdf2.getPage(0).getCropBox();
        PDRectangle outPdfFrame = new PDRectangle(pdf1Frame.getWidth()+pdf2Frame.getWidth(), Math.max(pdf1Frame.getHeight(), pdf2Frame.getHeight()));

        // Create output page with calculated frame and add it to the document
        COSDictionary dict = new COSDictionary();
        dict.setItem(COSName.TYPE, COSName.PAGE);
        dict.setItem(COSName.MEDIA_BOX, outPdfFrame);
        dict.setItem(COSName.CROP_BOX, outPdfFrame);
        dict.setItem(COSName.ART_BOX, outPdfFrame);
        PDPage outPdfPage = new PDPage(dict);
        outPdf.addPage(outPdfPage);

        // Source PDF pages has to be imported as form XObjects to be able to insert them at a specific point in the output page
        LayerUtility layerUtility = new LayerUtility(outPdf);
        PDFormXObject formPdf1 = layerUtility.importPageAsForm(pdf1, 0);
        PDFormXObject formPdf2 = layerUtility.importPageAsForm(pdf2, 0);

        // Add form objects to output page
        AffineTransform afLeft = new AffineTransform();
        layerUtility.appendFormAsLayer(outPdfPage, formPdf1, afLeft, "left");
        AffineTransform afRight = AffineTransform.getTranslateInstance(pdf1Frame.getWidth(), 0.0);
        layerUtility.appendFormAsLayer(outPdfPage, formPdf2, afRight, "right");

        outPdf.save(outPdfFile);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (pdf1 != null) pdf1.close();
            if (pdf2 != null) pdf2.close();
            if (outPdf != null) outPdf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
like image 114
Emil Avatar answered Dec 29 '22 08:12

Emil


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;
}
like image 35
kabal Avatar answered Dec 29 '22 07:12

kabal