PDFBox - merge 2 portrait pages onto a single side

2019-05-04 15:00发布

问题:

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

回答1:

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();
        }
    }
}


回答2:

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;
}


标签: java pdf pdfbox