I'm looking for at least an hour at my code but I can't find the bug. I'm using PDFBox to create PDF's (PDFBox HelloWorld Example). To learn how PDFBox works I just wanted to create some pages with "hello world" and the page number like "hello world 1", "hello world 2" and so on. As you can see I created a for loop to create six pages.
private void drawPDF(PDDocument doc, File file) throws IOException {
for (int pageIndex = 0; pageIndex < 6; pageIndex++) {
PDPage page = new PDPage(PDRectangle.A4);
doc.addPage(page);
PDFont font = PDType1Font.HELVETICA_BOLD;
String message = "hello world " + (pageIndex + 1);
float stringHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() * FONT_SIZE;
PDRectangle pageSize = page.getMediaBox();
try (PDPageContentStream contents = new PDPageContentStream(doc, page)) {
contents.beginText();
contents.setFont(font, FONT_SIZE);
contents.setTextMatrix(Matrix.getTranslateInstance(0, pageSize.getHeight() - stringHeight / 1000f));
contents.showText(message);
System.out.println(message + " - " + doc.getNumberOfPages());
contents.endText();
}
}
doc.save(file);
}
In my console I get the following output (first number is pageIndex, second number is doc.getNumberOfPages()):
hello world 1 - 1
hello world 2 - 2
hello world 3 - 3
hello world 4 - 4
hello world 5 - 5
hello world 6 - 6
This is my load function to view the pdf.
private final ObservableList<Image> pdfFilePages = FXCollections.observableArrayList();
private void loadFile(File file) throws FileNotFoundException, IOException {
if (file != null) {
ByteBuffer buffer = null;
try (RandomAccessFile raf = new RandomAccessFile(file, "r"); FileChannel channel = raf.getChannel()) {
buffer = ByteBuffer.allocate((int) channel.size());
channel.read(buffer);
buffer.flip();
PDFFile pdfFile = new PDFFile(buffer);
List<Image> pages = new ArrayList<>();
for (int i = 0; i < pdfFile.getNumPages(); i++) {
PDFPage page = pdfFile.getPage(i, true);
System.out.println("page: " + i + " - " + pdfFile.getNumPages());
java.awt.geom.Rectangle2D bbox = page.getBBox();
java.awt.geom.Rectangle2D rect = new Rectangle(0, 0, (int) bbox.getWidth(), (int) bbox.getHeight());
BufferedImage buffImage = new BufferedImage((int) (bbox.getWidth() * 2d),
(int) (bbox.getHeight() * 2d), BufferedImage.TYPE_INT_RGB);
java.awt.Image awtImage = page.getImage((int) (bbox.getWidth() * 2.0),
(int) (bbox.getHeight() * 2.0), rect, null, true, true);
java.awt.Graphics2D bufImageGraphics = buffImage.createGraphics();
bufImageGraphics.drawImage(awtImage, 0, 0, null);
Image image = SwingFXUtils.toFXImage(buffImage, null);
pages.add(image);
}
pdfFilePages.addAll(pages);
}
}
}
This is what I get in my console:
page: 0 - 6
page: 1 - 6
page: 2 - 6
page: 3 - 6
page: 4 - 6
page: 5 - 6
When I load the pdf file to display the content in my application i get "hello world 1 - 1" for the first and second page. The following pages have "hello world 2 - 2" to "hello world 5 - 5". I don't understand why I get two pages of "hello world 1 - 1". I hope someone can explain to me where I made a mistake.
With the help of mkl I found the bug in my code. The for loop has to start at 1 and run until the index is equal to pdfFile.getNumPages(). The method getPage() return the first page when the index is 0. Because the index is 1 in the second iteration, the first page will be passed twice. The last page won't be passed since the loop has been finished. This seems to be the right approach.
private void loadFile(File file) throws FileNotFoundException, IOException {
if (file != null) {
ByteBuffer buffer = null;
try (RandomAccessFile raf = new RandomAccessFile(file, "r"); FileChannel channel = raf.getChannel()) {
buffer = ByteBuffer.allocate((int) channel.size());
channel.read(buffer);
buffer.flip();
PDFFile pdfFile = new PDFFile(buffer);
List<Image> pages = new ArrayList<>();
for (int i = 1; i <= pdfFile.getNumPages(); i++) {
PDFPage page = pdfFile.getPage(i, true);
System.out.println("page: " + i + " - " + pdfFile.getNumPages());
java.awt.geom.Rectangle2D bbox = page.getBBox();
java.awt.geom.Rectangle2D rect = new Rectangle(0, 0, (int) bbox.getWidth(), (int) bbox.getHeight());
BufferedImage buffImage = new BufferedImage((int) (bbox.getWidth() * 2d),
(int) (bbox.getHeight() * 2d), BufferedImage.TYPE_INT_RGB);
java.awt.Image awtImage = page.getImage((int) (bbox.getWidth() * 2.0),
(int) (bbox.getHeight() * 2.0), rect, null, true, true);
java.awt.Graphics2D bufImageGraphics = buffImage.createGraphics();
bufImageGraphics.drawImage(awtImage, 0, 0, null);
Image image = SwingFXUtils.toFXImage(buffImage, null);
pages.add(image);
}
pdfFilePages.addAll(pages);
}
}
}
Related
I have (I think) correctly followed the instructions from: https://memorynotfound.com/apache-pdfbox-add-image-pdf-document/
I am attempting to insert an image logo.png. The code runs and doesn't throw up any errors, but the resulting PDF does not contain an image! The text does appear as expected. Does anybody know why this is and how to fix it?
I'm using Java 8 in Apache NetBeans 11.
Thanks. Here's the code:
public void generate(File samplefile) throws IOException {
PDDocument document = new PDDocument();
//Adding the blank page to the document
//Repeat this next line for further pages
PDPage page = new PDPage();
document.addPage(page);
File dir = new File(ArdenRecord.sadd + "/Sample Reports");
if (!dir.exists()) {
dir.mkdir();
}
String fname = samplefile.toString().split("\\.")[0].split("\\\\")[2];
File f = new File(ArdenRecord.sadd + "/Sample Reports/" + fname + ".pdf");
File imfile = new File(ArdenRecord.sadd + "/logo.png");
PDImageXObject pdImage = PDImageXObject.createFromFile(imfile.toString(), document);
PDPageContentStream contents = new PDPageContentStream(document, page);
PDRectangle mediaBox = page.getMediaBox();
float startX = (mediaBox.getWidth() - pdImage.getWidth()) / 2;
float startY = (mediaBox.getHeight() - pdImage.getHeight()) / 2;
contents.drawImage(pdImage, startX, startY);
contents.beginText();
contents.newLineAtOffset(25, 700);
contents.setFont(PDType1Font.TIMES_ROMAN, 12);
BufferedReader br = new BufferedReader(new FileReader(samplefile));
String st;
int n = 0;
while ((st = br.readLine()) != null) {
if (n < 4 || n > 20 && n < 30) {
contents.showText(st);
contents.newLineAtOffset(0, -18);
}
n++;
}
contents.endText();
contents.close();
document.save(f);
document.close();
Desktop.getDesktop().open(f);
}
}```
Maybe there's nothing wrong with your code. I copy-pasted (removed .split("\\\\")[2] to get path right), compiled and tested it with PDFBox 2.0.17, OpenJDK 8, this PNG file and the first chapter of Lorem Ipsum in a text file. See the result below (Adobe Reader screenshot).
At least you should try with a different PNG file.
I have a pdf document with one or more pages A4 paper.
The resulting pdf document should be A3 paper where each page contains two from the first one (odd on the left, even on the right side).
I already got it to render the A4 pages into images and the odd pages are successfully placed on the first parts of a new A3 pages but I cannot get the even pages to be placed.
public class CreateLandscapePDF {
public void renderPDF(File inputFile, String output) {
PDDocument docIn = null;
PDDocument docOut = null;
float width = 0;
float height = 0;
float posX = 0;
float posY = 0;
try {
docIn = PDDocument.load(inputFile);
PDFRenderer pdfRenderer = new PDFRenderer(docIn);
docOut = new PDDocument();
int pageCounter = 0;
for(PDPage pageIn : docIn.getPages()) {
pageIn.setRotation(270);
BufferedImage bufferedImage = pdfRenderer.renderImage(pageCounter);
width = bufferedImage.getHeight();
height = bufferedImage.getWidth();
PDPage pageOut = new PDPage(PDRectangle.A3);
PDImageXObject image = LosslessFactory.createFromImage(docOut, bufferedImage);
PDPageContentStream contentStream = new PDPageContentStream(docOut, pageOut, AppendMode.APPEND, true, true);
if((pageCounter & 1) == 0) {
pageOut.setRotation(90);
docOut.addPage(pageOut);
posX = 0;
posY = 0;
} else {
posX = 0;
posY = width;
}
contentStream.drawImage(image, posX, posY);
contentStream.close();
bufferedImage.flush();
pageCounter++;
}
docOut.save(output + "\\LandscapeTest.pdf");
docOut.close();
docIn.close();
} catch(IOException io) {
io.printStackTrace();
}
}
}
I'm using Apache PDFBox 2.0.2 (pdfbox-app-2.0.2.jar)
Thank you very much for your help and the link to the other question - I think I already read it but wasn't able to use in in my code yet.
But finally the PDFClown made the job, though I think it's not very nice to use PDFBox and PDFClown in the same program.
Anyway here's my working code to combine A4 pages on A3 paper.
public class CombinePages {
public void run(String input, String output) {
try {
Document source = new File(input).getDocument();
Pages sourcePages = source.getPages();
Document target = new File().getDocument();
Page targetPage = null;
int pageCounter = 0;
double moveByX = .0;
for(Page sourcePage : source.getPages()) {
if((pageCounter & 1) == 0) {
//even page gets a blank page
targetPage = new Page(target);
target.setPageSize(PageFormat.getSize(PageFormat.SizeEnum.A3, PageFormat.OrientationEnum.Landscape));
target.getPages().add(targetPage);
moveByX = .0;
} else {
moveByX = .50;
}
//get content from source page
XObject xObject = sourcePages.get(pageCounter).toXObject(target);
PrimitiveComposer composer = new PrimitiveComposer(targetPage);
Dimension2D targetSize = targetPage.getSize();
Dimension2D sourceSize = xObject.getSize();
composer.showXObject(xObject, new Point2D.Double(targetSize.getWidth() * moveByX, targetSize.getHeight() * .0), new Dimension(sourceSize.getWidth(), sourceSize.getHeight()), XAlignmentEnum.Left, YAlignmentEnum.Top, 0);
composer.flush();
pageCounter++;
}
target.getFile().save(output + "\\CombinePages.pdf", SerializationModeEnum.Standard);
source.getFile().close();
} catch (FileNotFoundException fnf) {
log.error(fnf);
} catch (IOException io) {
log.error(io);
}
}
}
I going to convert tiff to pdf file, but image displayed bottom of page, how to start image from top of the pdf page.
private static String convertTiff2Pdf(String tiff) {
// target path PDF
String pdf = null;
try {
pdf = tiff.substring(0, tiff.lastIndexOf('.') + 1) + "pdf";
// New document A4 standard (LETTER)
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdf));
document.setMarginMirroring(true);
int pages = 0;
document.open();
PdfContentByte cb = writer.getDirectContent();
RandomAccessFileOrArray ra = null;
int comps = 0;
ra = new RandomAccessFileOrArray(tiff);
comps = TiffImage.getNumberOfPages(ra);
// Convertion statement
for (int c = 0; c < comps; ++c) {
Image img = TiffImage.getTiffImage(ra, c+1);
if (img != null) {
img.scalePercent(7200f / img.getDpiX(), 7200f / img.getDpiY());
img.setAbsolutePosition(0, 0);
img.scaleAbsolute(600, 250);
cb.addImage(img);
document.newPage();
++pages;
}
}
ra.close();
document.close();
} catch (Exception e) {
System.out.println(e);
pdf = null;
}
System.out.println("[" + tiff + "] -> [" + pdf + "] OK");
return pdf;
}
You are creating a new document with A4 pages (as opposed to using the LETTER format). These pages have a width of 595 pt and a height of 842 pt. The origin of the coordinate system (0, 0) is in the lower-left corner, which is exactly where you're adding the image using the method setAbsolutePosition(0, 0);
Surprisingly, you don't adapt the size of the page to the size of the image. Instead you want to add the image at the top of the page. In this case, you need to change the coordinates of the absolute position like this:
img.setAbsolutePosition(0, PageSize.A4.getHeight() - img.getScaledHeight());
If img.getScaledHeight() exceeds PageSize.A4.getHeight() (which is equal to 842), your image will be clipped at the bottom. The image will be clipped on the right if img.getScaledWidth() exceeds PageSize.A4.getWidth() (which is equal to 595).
Based in the answer, this code center any size image.
image.setAbsolutePosition((PageSize.A4.getWidth() - img.getScaledWidth())/2, (PageSize.A4.getHeight() - img.getScaledHeight())/2 );
Does pdfbox provide some utility to highlight the text when I have it's co-ordinates?
Bounds of the text is known.
I know there are other libraries that provide the same functionality like pdfclown etc. But does pdfbox provide something like that?
well i found this out. it is simple.
PDDocument doc = PDDocument.load(/*path to the file*/);
PDPage page = (PDPage)doc.getDocumentCatalog.getAllPages.get(i);
List annots = page.getAnnotations;
PDAnnotationTextMarkup markup = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.Su....);
markup.setRectangle(/*your PDRectangle*/);
markup.setQuads(/*float array of size eight with all the vertices of the PDRectangle in anticlockwise order*/);
annots.add(markup);
doc.save(/*path to the output file*/);
This is an extended answer from the number 1 here, and basically is the same code as above.
Improves the coordinates points in respect to the page size in the current document, as well the yellow color that is very lighter and sometimes if the word is short and smaller is difficult to see.
Also highlight the full word taking the X, Y coordinates from the top-left to the top-right. Takes the coordinates from the first character and from the last one in the string.
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
public class MainSource extends PDFTextStripper {
public MainSource() throws IOException {
super();
}
public static void main(String[] args) throws IOException {
PDDocument document = null;
String fileName = "C:/AnyPDFFile.pdf";
try {
document = PDDocument.load( new File(fileName) );
PDFTextStripper stripper = new MainSource();
stripper.setSortByPosition( true );
stripper.setStartPage( 0 );
stripper.setEndPage( document.getNumberOfPages() );
Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
stripper.writeText(document, dummy);
File file1 = new File("C:/AnyPDFFile-New.pdf");
document.save(file1);
}
finally {
if( document != null ) {
document.close();
}
}
}
/**
* Override the default functionality of PDFTextStripper.writeString()
*/
#Override
protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
boolean isFound = false;
float posXInit = 0,
posXEnd = 0,
posYInit = 0,
posYEnd = 0,
width = 0,
height = 0,
fontHeight = 0;
String[] criteria = {"Word1", "Word2", "Word3", ....};
for (int i = 0; i < criteria.length; i++) {
if (string.contains(criteria[i])) {
isFound = true;
}
}
if (isFound) {
posXInit = textPositions.get(0).getXDirAdj();
posXEnd = textPositions.get(textPositions.size() - 1).getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidth();
posYInit = textPositions.get(0).getPageHeight() - textPositions.get(0).getYDirAdj();
posYEnd = textPositions.get(0).getPageHeight() - textPositions.get(textPositions.size() - 1).getYDirAdj();
width = textPositions.get(0).getWidthDirAdj();
height = textPositions.get(0).getHeightDir();
System.out.println(string + "X-Init = " + posXInit + "; Y-Init = " + posYInit + "; X-End = " + posXEnd + "; Y-End = " + posYEnd + "; Font-Height = " + fontHeight);
/* numeration is index-based. Starts from 0 */
float quadPoints[] = {posXInit, posYEnd + height + 2, posXEnd, posYEnd + height + 2, posXInit, posYInit - 2, posXEnd, posYEnd - 2};
List<PDAnnotation> annotations = document.getPage(this.getCurrentPageNo() - 1).getAnnotations();
PDAnnotationTextMarkup highlight = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
PDRectangle position = new PDRectangle();
position.setLowerLeftX(posXInit);
position.setLowerLeftY(posYEnd);
position.setUpperRightX(posXEnd);
position.setUpperRightY(posYEnd + height);
highlight.setRectangle(position);
// quadPoints is array of x,y coordinates in Z-like order (top-left, top-right, bottom-left,bottom-right)
// of the area to be highlighted
highlight.setQuadPoints(quadPoints);
PDColor yellow = new PDColor(new float[]{1, 1, 1 / 255F}, PDDeviceRGB.INSTANCE);
highlight.setColor(yellow);
annotations.add(highlight);
}
}
}
This works for pdfbox 2.0.7
PDDocument document = /* get doc */
/* numeration is index-based. Starts from 0 */
List<PDAnnotation> annotations = document.getPage(yourPageNumber - 1).getAnnotations();
PDAnnotationTextMarkup highlight = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
highlight.setRectangle(PDRectangle.A4);
// quadPoints is array of x,y coordinates in Z-like order (top-left, top-right, bottom-left,bottom-right)
// of the area to be highlighted
highlight.setQuadPoints(quadPoints);
PDColor yellow = new PDColor(new float[]{1, 1, 204 / 255F}, PDDeviceRGB.INSTANCE);
highlight.setColor(yellow);
annotations.add(highlight);
Note: such annotation will be displayed if you save doc in file, but it will not appear in image created from page since there is no AppearanceStream created for this annotation. I solved it with code drafts from PDFBOX-3353
Simplest way ... draw a rectangle in the desired location and set the height to 1 and the fill color to BLACK.
or ...
Using PDFBox ...
//create the page PDDocument doc = new PDDocument();
PDPage page1 = new PDPage();
doc.addPage(page1);
//create the stream
PDPageContentStream stream1 = new PDPageContentStream(doc, page1);
//to simply draw an underscore with the coordinates
//where the first is x start, second y start, third x end, fourth y end
stream1.drawLine(20, 740, 590, 740);
//to draw an underscore thicker than one pixel
//first x begin second y begin third length fourth thickness
stream1.addRect(345, 568, 70, 2);
stream1.setNonStrokingColor(Color.BLACK); stream1.fill();
Another solution could be drawing a yellow-ish rectangle with a lower alpha, like in the follow sample code:
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);
PDFont font = PDType1Font.COURIER;
final int fontSize = 16;
//Writing text
contentStream.beginText();
contentStream.setFont(font, fontSize );
contentStream.newLineAtOffset(25, 250);
contentStream.showText("Hello world");
contentStream.endText();
//Changing alpha mode
PDExtendedGraphicsState gs = new PDExtendedGraphicsState();
gs.setNonStrokingAlphaConstant(0.2f);
gs.setStrokingAlphaConstant(0.2f);
gs.setBlendMode(BlendMode.MULTIPLY);
contentStream.setGraphicsStateParameters(gs);
//Setting color
contentStream.setNonStrokingColor(new Color(255, 255, 0, 100));
//Highlighting (that is, drawing a rectangle)
contentStream.addRect(25, 250, font.getStringWidth("Hello world")*fontSize/1000, font.getBoundingBox().getHeight()*fontSize/1000);
contentStream.fill();
contentStream.close();
//Resetting alpha means creating a new content stream...
//writing a new rectangle just to test alpha changing
contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);
gs = new PDExtendedGraphicsState();
gs.setNonStrokingAlphaConstant(1f);
gs.setStrokingAlphaConstant(1f);
gs.setBlendMode(BlendMode.MULTIPLY);
contentStream.setGraphicsStateParameters(gs);
contentStream.setNonStrokingColor(new Color(255, 255, 0, 100));
contentStream.addRect(50, 50, 50, 50);
contentStream.fill();
contentStream.close();
document.save(Constants.PATH);
document.close();
Producing this as result
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
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();
}
}
}
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;
}