PDFBox: put two A4 pages on one A3 - java

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

Related

PDFBOX 2.0+ java flatten annotations freetext created by foxit

I ran into a very tough issue. We have forms that were supposed to be filled out, but some people used annotation freeform text comments in foxit instead of filling the form fields, so the annotations never flatten. When our render software generates the final document annotations are not included.
The solution I tried is to basically go through the document, get the annotation text content and write it to the pdf so it is on the final document then remove the actual annotation, but I run into an issue where I don't know the font the annotation is using, line space, etc so cannot find out how to get it from a pdfbox to recreate exacactly as the annotation looks on the unflattened form.
Basically I want to flatten annotatations that are freeform created in foxit (The typewriter comment feature)
Here is the code. It is working, but again I am struggling with figuring out how to get the annotations to write to my final pdf document. Again flatten on the acroform is not working because these are not acroform fields! The live code filters out anything that is not a freetext type annotation, but below code should show my issue.
public static void main(String [] args)
{
String startDoc = "C:/test2/test.pdf";
String finalFlat = "C:/test2/test_FLAT.pdf";
try {
// for testing
try {
//BasicConfigurator.configure();
File myFile = new File(startDoc);
PDDocument pdDoc = PDDocument.load( myFile );
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
// set the NeedApperances flag
pdAcroForm.setNeedAppearances(false);
// correct the missing page link for the annotations
for (PDPage page : pdDoc.getPages()) {
for (PDAnnotation annot : page.getAnnotations()) {
System.out.println(annot.getContents());
System.out.println(annot.isPrinted());
System.out.println(annot.isLocked());
System.out.println(annot.getAppearance().toString());
PDPageContentStream contentStream = new PDPageContentStream(pdDoc, page, PDPageContentStream.AppendMode.APPEND,true,true);
int fontHeight = 14;
contentStream.setFont(PDType1Font.TIMES_ROMAN, fontHeight);
float height = annot.getRectangle().getLowerLeftY();
String s = annot.getContents().replaceAll("\t", " ");
String ss[] = s.split("\\r");
for(String sss : ss)
{
contentStream.beginText();
contentStream.newLineAtOffset(annot.getRectangle().getLowerLeftX(),height );
contentStream.showText(sss);
height = height + fontHeight * 2 ;
contentStream.endText();
}
contentStream.close();
page.getAnnotations().remove(annot);
}
}
pdAcroForm.flatten();
pdDoc.save(finalFlat);
pdDoc.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
catch (Exception e) {
System.err.println("Exception: " + e.getLocalizedMessage());
}
}
This was not a fun one. After a million different tests, and I STILL do not understand all the nuances, but this is the version that appeas to flatten all pdf files and annotations if they are visible on PDF. Tested about half a dozen pdf creators and if an annotation is visible on a page this hopefully flattens it. I suspect there is a better way by pulling the matrix and transforming it and what not, but this is the only way I got it to work everywhere.
public static void flattenv3(String startDoc, String endDoc) {
org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.INFO);
String finalFlat = endDoc;
try {
try {
//BasicConfigurator.configure();
File myFile = new File(startDoc);
PDDocument pdDoc = PDDocument.load(myFile);
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
if (pdAcroForm != null) {
pdAcroForm.setNeedAppearances(false);
pdAcroForm.flatten();
}
// set the NeedApperances flag
boolean isContentStreamWrapped;
int ii = 0;
for (PDPage page: pdDoc.getPages()) {
PDPageContentStream contentStream;
isContentStreamWrapped = false;
List < PDAnnotation > annotations = new ArrayList < > ();
for (PDAnnotation annotation: page.getAnnotations()) {
if (!annotation.isInvisible() && !annotation.isHidden() && annotation.getNormalAppearanceStream() != null)
{
ii++;
if (ii > 1) {
// contentStream.close();
// continue;
}
if (!isContentStreamWrapped) {
contentStream = new PDPageContentStream(pdDoc, page, AppendMode.APPEND, true, true);
isContentStreamWrapped = true;
} else {
contentStream = new PDPageContentStream(pdDoc, page, AppendMode.APPEND, true);
}
PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
PDFormXObject fieldObject = new PDFormXObject(appearanceStream.getCOSObject());
contentStream.saveGraphicsState();
boolean needsTranslation = resolveNeedsTranslation(appearanceStream);
Matrix transformationMatrix = new Matrix();
boolean transformed = false;
float lowerLeftX = annotation.getNormalAppearanceStream().getBBox().getLowerLeftX();
float lowerLeftY = annotation.getNormalAppearanceStream().getBBox().getLowerLeftY();
PDRectangle bbox = appearanceStream.getBBox();
PDRectangle fieldRect = annotation.getRectangle();
float xScale = fieldRect.getWidth() - bbox.getWidth();
transformed = true;
lowerLeftX = fieldRect.getLowerLeftX();
lowerLeftY = fieldRect.getLowerLeftY();
if (bbox.getLowerLeftX() <= 0 && bbox.getLowerLeftY() < 0 && Math.abs(xScale) < 1) //BASICALLY EQUAL TO 0 WITH ROUNDING
{
lowerLeftY = fieldRect.getLowerLeftY() - bbox.getLowerLeftY();
if (bbox.getLowerLeftX() < 0 && bbox.getLowerLeftY() < 0) //THis is for the o
{
lowerLeftX = lowerLeftX - bbox.getLowerLeftX();
}
} else if (bbox.getLowerLeftX() == 0 && bbox.getLowerLeftY() < 0 && xScale >= 0) {
lowerLeftX = fieldRect.getUpperRightX();
} else if (bbox.getLowerLeftY() <= 0 && xScale >= 0) {
lowerLeftY = fieldRect.getLowerLeftY() - bbox.getLowerLeftY() - xScale;
} else if (bbox.getUpperRightY() <= 0) {
if (annotation.getNormalAppearanceStream().getMatrix().getShearY() < 0) {
lowerLeftY = fieldRect.getUpperRightY();
lowerLeftX = fieldRect.getUpperRightX();
}
} else {
}
transformationMatrix.translate(lowerLeftX,
lowerLeftY);
contentStream.transform(transformationMatrix);
contentStream.drawForm(fieldObject);
contentStream.restoreGraphicsState();
contentStream.close();
}
}
page.setAnnotations(annotations);
}
pdDoc.save(finalFlat);
pdDoc.close();
File file = new File(finalFlat);
// Desktop.getDesktop().browse(file.toURI());
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
System.err.println("Exception: " + e.getLocalizedMessage());
}
}
}

PDFBOX: Indexing using pdfbox

I am in requirement of creating an index for PDF document & based on the index i want to display the page.
problem is page number are created dynamically so static page number cannot be used, can anyone suggest me links or examples
here is my code and it works for me to redirect into different pages while clicking in the page number on index page
public class LinkPdf {
static final float INCH = 72;
public static List<PDAnnotation> annotations;
#SuppressWarnings("null")
public static void main(String[] args) throws Exception {
PDRectangle position = null;
PDDocument document = new PDDocument();
try {
for (int i = 0; i < 10; i++) {
PDPage page = new PDPage();
document.addPage(page);
}
PDPage page1 = document.getPage(0);
HashMap<Integer, String> pgs = new HashMap<Integer, String>();
for (int i = 0; i < document.getNumberOfPages(); i++) {
pgs.put(i, "Jump to Page" + i);
}
PDFont font = PDType1Font.HELVETICA_BOLD;
PDPageContentStream contents = new PDPageContentStream(document,
page1);
contents.beginText();
contents.setFont(font, 18);
contents.newLineAtOffset(50, 600);
contents.setLeading(20f);
contents.showText("PDFBox");
position = new PDRectangle();
for (int i = 0; i < document.getNumberOfPages(); i++) {
contents.newLine();
contents.showText(pgs.get(i));
contents.newLine();
}
contents.endText();
contents.close();
PDRectangle[] pos1 = new PDRectangle[document.getNumberOfPages()];
for(int i=0;i<document.getNumberOfPages();i++){
pos1[i]=new PDRectangle();
pos1[i].setLowerLeftX(50);
pos1[i].setLowerLeftY(575-(i*40));
pos1[i].setUpperRightX(INCH + 100);
pos1[i].setUpperRightY(585-(i*40));
getPage(document, page1, pgs.get(i), i, pos1[i]);
}
document.save("D:/link.pdf");
System.out.println("Completed");
} finally {
document.close();
}
}
public static void getPage(PDDocument document, PDPage page1, String txt,
int pageno, PDRectangle position) throws IOException {
annotations = page1.getAnnotations();
PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
borderThick.setWidth(INCH / 12); // 12th inch
PDBorderStyleDictionary borderThin = new PDBorderStyleDictionary();
borderThin.setWidth(INCH / 72); // 1 point
PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
borderULine.setWidth(INCH / 72); // 1 point
float pw = page1.getMediaBox().getUpperRightX();
float ph = page1.getMediaBox().getUpperRightY();
float textWidth = PDType1Font.TIMES_BOLD.getStringWidth("PDFBox") / 1000 * 18;
PDAnnotationLink pageLink = new PDAnnotationLink();
pageLink.setBorderStyle(borderULine);
textWidth = PDType1Font.TIMES_BOLD.getStringWidth(txt) / 1000 * 18;
pageLink.setRectangle(position);
PDActionGoTo actionGoto = new PDActionGoTo();
PDPageDestination dest = new PDPageFitWidthDestination();
dest.setPage(document.getPage(pageno));
actionGoto.setDestination(dest);
pageLink.setAction(actionGoto);
annotations.add(pageLink);
}
}

How to find blank pages inside a PDF using PDFBox?

Here is the challenge I'm currently facing.
I have a lot of PDFs and I have to remove the blank pages inside them and display only the pages with content (text or images).
The problem is that those pdfs are scanned documents.
So the blank pages have some dirty left behind by the scanner.
I did some research and ended up with this code that checks for 99% of the page as white or light gray.
I needed the gray factor as the scanned documents sometimes are not pure white.
private static Boolean isBlank(PDPage pdfPage) throws IOException {
BufferedImage bufferedImage = pdfPage.convertToImage();
long count = 0;
int height = bufferedImage.getHeight();
int width = bufferedImage.getWidth();
Double areaFactor = (width * height) * 0.99;
for (int x = 0; x < width ; x++) {
for (int y = 0; y < height ; y++) {
Color c = new Color(bufferedImage.getRGB(x, y));
// verify light gray and white
if (c.getRed() == c.getGreen() && c.getRed() == c.getBlue()
&& c.getRed() >= 248) {
count++;
}
}
}
if (count >= areaFactor) {
return true;
}
return false;
}
#Shoyo's code works fine for PDFBox version < 2.0. For future readers, there's no much change but, just in case, here is the code for PDFBOX 2.0+ to make your life easier.
In your main (By main, I mean the place where you are loading your PDF into PDDocument) method:
try {
PDDocument document = PDDocument.load(new File("/home/codemantra/Downloads/tetml_ct_access/C.pdf"));
PDFRenderer renderedDoc = new PDFRenderer(document);
for (int pageNumber = 0; pageNumber < document.getNumberOfPages(); pageNumber++) {
if(isBlank(renderedDoc.renderImage(pageNumber))) {
System.out.println("Blank Page Number : " + pageNumber + 1);
}
}
} catch (Exception e) {
e.printStackTrace();
}
And isBlank method will just have BufferedImage passed in:
private static Boolean isBlank(BufferedImage pageImage) throws IOException {
BufferedImage bufferedImage = pageImage;
long count = 0;
int height = bufferedImage.getHeight();
int width = bufferedImage.getWidth();
Double areaFactor = (width * height) * 0.99;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Color c = new Color(bufferedImage.getRGB(x, y));
if (c.getRed() == c.getGreen() && c.getRed() == c.getBlue() && c.getRed() >= 248) {
count++;
}
}
}
if (count >= areaFactor) {
return true;
}
return false;
}
All the credits goes to #Shoyo
Update:
Some PDFs have "This Page was Intentionally Left Blank" to which the above code considers as blank. If this is your requirement then feel free to use the above code. But, my requirement was only to filter out the pages that were completely blank (No any images present nor consisting of any fonts). So, I ended up using this code (Plus this code runs faster :P) :
public static void main(String[] args) {
try {
PDDocument document = PDDocument.load(new File("/home/codemantra/Downloads/CTP2040.pdf"));
PDPageTree allPages = document.getPages();
Integer pageNumber = 1;
for (PDPage page : allPages) {
Iterable<COSName> xObjects = page.getResources().getXObjectNames();
Iterable<COSName> fonts = page.getResources().getFontNames();
if(xObjects.spliterator().getExactSizeIfKnown() == 0 && fonts.spliterator().getExactSizeIfKnown() == 0) {
System.out.println(pageNumber);
}
pageNumber++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
This will return the page numbers of those pages which are completely blank.
Hope this helps someone! :)
#Pramesh Bajracharya, Your solution to find a blank page in a PDF document is intact!
If in case the requirement is to remove the blank pages the same code can be enhanced as below
List<Integer> blankPageList = new ArrayList<Integer>();
for( PDPage page : allPages )
{
Iterable<COSName> xObjects = page.getResources().getXObjectNames();
Iterable<COSName> fonts = page.getResources().getFontNames();
// condition to determine if the page is a blank page
if( xObjects.spliterator().getExactSizeIfKnown() == 0 && fonts.spliterator().getExactSizeIfKnown() == 0 )
{
pageRemovalList.add( pageNumber );
}
pageNumber++;
}
// remove the blank pages from the pdf document using the blank page numbers list
for( Integer i : blankPageList )
{
document.removePage( i );
}
http://www.rgagnon.com/javadetails/java-detect-and-remove-blank-page-in-pdf.html
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.io.RandomAccessSourceFactory;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
public class RemoveBlankPageFromPDF {
// value where we can consider that this is a blank image
// can be much higher or lower depending of what is considered as a blank page
public static final int BLANK_THRESHOLD = 160;
public static void removeBlankPdfPages(String source, String destination)
throws IOException, DocumentException
{
PdfReader r = null;
RandomAccessSourceFactory rasf = null;
RandomAccessFileOrArray raf = null;
Document document = null;
PdfCopy writer = null;
try {
r = new PdfReader(source);
// deprecated
// RandomAccessFileOrArray raf
// = new RandomAccessFileOrArray(pdfSourceFile);
// itext 5.4.1
rasf = new RandomAccessSourceFactory();
raf = new RandomAccessFileOrArray(rasf.createBestSource(source));
document = new Document(r.getPageSizeWithRotation(1));
writer = new PdfCopy(document, new FileOutputStream(destination));
document.open();
PdfImportedPage page = null;
for (int i=1; i<=r.getNumberOfPages(); i++) {
// first check, examine the resource dictionary for /Font or
// /XObject keys. If either are present -> not blank.
PdfDictionary pageDict = r.getPageN(i);
PdfDictionary resDict = (PdfDictionary) pageDict.get( PdfName.RESOURCES );
boolean noFontsOrImages = true;
if (resDict != null) {
noFontsOrImages = resDict.get( PdfName.FONT ) == null &&
resDict.get( PdfName.XOBJECT ) == null;
}
System.out.println(i + " noFontsOrImages " + noFontsOrImages);
if (!noFontsOrImages) {
byte bContent [] = r.getPageContent(i,raf);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
bs.write(bContent);
System.out.println
(i + bs.size() + " > BLANK_THRESHOLD " + (bs.size() > BLANK_THRESHOLD));
if (bs.size() > BLANK_THRESHOLD) {
page = writer.getImportedPage(r, i);
writer.addPage(page);
}
}
}
}
finally {
if (document != null) document.close();
if (writer != null) writer.close();
if (raf != null) raf.close();
if (r != null) r.close();
}
}
public static void main (String ... args) throws Exception {
removeBlankPdfPages
("C://temp//documentwithblank.pdf", "C://temp//documentwithnoblank.pdf");
}
}

pdfbox generate multi page

When I generate second page, I get a blank page. I have two functions. One generates a table with text, and another generates a PDF. When end place in first page, I add another page and I want write in new page. When I open generated PDF file, the second page is blank:
//global variables
PDPage nowa=null;
PDPageContentStream contentStream1 = null;
//function to generate table
private void print_sumActionPerformed(java.awt.event.ActionEvent evt){
try {
PDDocument doc = null;
PDPage page = null;
int max_row=55;
int suma=0;
int pozycja=0;
final int starty=760;
final int startx=30;
try{
doc = new PDDocument();
page = new PDPage(PDPage.PAGE_SIZE_A4);
doc.addPage(page);
PDFont font = PDType1Font.HELVETICA;
PDPageContentStream content = new PDPageContentStream(doc, page,true,true);
//some code to generate table
drawTable(page, content, starty, startx, content1,doc);
content.close();
doc.save("path");
doc.close();
Thread.sleep(500);
} catch (Exception e){
System.out.println(e);
}
} catch (IOException ex) {
Logger.getLogger(Okno.class.getName()).log(Level.SEVERE, null, ex);
} catch (PrinterException ex) {
Logger.getLogger(Okno.class.getName()).log(Level.SEVERE, null, ex);
}
}
function to generate table in pdf
private void drawTable(PDPage page, PDPageContentStream contentStream,float y, float margin, String[][] content,PDDocument doc) throws IOException, InterruptedException {
final int rows = content.length;
final int cols = content[0].length;
final float rowHeight = 13f;
final float marginCell=5;
final float startx=30;
final int tableWidth3=200;
final int tableWidth5=250;
boolean new_kol;
if (margin<230){
new_kol=false;
}else {
new_kol=true;
}
float textx;
final float odst=20;
final float starty = y;
float texty=starty-rowHeight+3;
//width table
int tableWidth;
if(cols==5)tableWidth=tableWidth5;
else tableWidth=tableWidth3;
//start print table in pdf
if(!new_kol){
contentStream.drawLine(startx,starty,tableWidth+startx+marginCell,starty);
textx=startx+marginCell;
}else {
contentStream.drawLine(startx+tableWidth5+odst, starty, 2*tableWidth5+(startx)+odst+marginCell,starty);
textx=startx+marginCell+tableWidth+odst;
}
for(int i = 0; i < content.length; i++){
for(int j = 0 ; j < content[i].length; j++){
//linia pionowa
contentStream.drawLine(textx-marginCell,texty-3,textx-marginCell,texty-3+rowHeight);
String text=content[i][j];
if(text.contains("AB")){
contentStream.setFont(PDType1Font.HELVETICA_BOLD,10);
}else contentStream.setFont(PDType1Font.HELVETICA,8);
contentStream.beginText();
contentStream.moveTextPositionByAmount(textx,texty);
contentStream.drawString(text);
contentStream.endText();
switch(j){
case 0: textx+=30;
break;
case 1:
if (cols==5) textx += 120;
else textx+=150;
break;
case 2: textx+=15;
if(cols==3 ) contentStream.drawLine(textx+marginCell,texty-3,textx+marginCell,texty-3+rowHeight);
break;
case 3: textx+=40;
break;
case 4: textx+=40;
contentStream.drawLine(textx+marginCell,texty-3,textx+marginCell,texty-3+rowHeight);
break;
}
}
if(new_kol){
textx=tableWidth+startx+odst+marginCell;
contentStream.drawLine(textx-marginCell,texty-3,textx+tableWidth,texty-3);
}
else {
textx=startx+marginCell;
contentStream.drawLine(textx-marginCell,texty-3,textx+tableWidth,texty-3);
}
if((texty-=rowHeight)<50){
if(!new_kol){
new_kol=true;
contentStream.drawLine(startx,texty+10,startx+tableWidth+marginCell,texty+10);
texty=760-10;
textx=tableWidth+startx+odst+marginCell;
contentStream.drawLine(textx-marginCell,texty+10,textx+tableWidth,texty+10);
}else{
new_kol=false;
contentStream.drawLine(startx+tableWidth5+odst,texty+10,startx+2*tableWidth,texty+10);
texty=760-10;
textx=startx+marginCell;
//here i add new page when end page height
//i get blank page
contentStream.close();
page=null;
contentStream=null;
nowa=new PDPage(PDPage.PAGE_SIZE_A4);
page=null;
page=nowa;
doc.addPage(nowa);
PDFont font = PDType1Font.HELVETICA;
contentStream1 = new PDPageContentStream(doc, nowa,false,true);
contentStream=contentStream1;
contentStream1=null;
contentStream.drawLine(textx,texty+10,textx+tableWidth,texty+10);
}
}
}
}
It could probably be your constructor. I think if you use :
PDPageContentStream content = new PDPageContentStream(doc, page,true,true, false);
it should work as expected. The final parameter corresponds to the resetContext value in the constructor and decides whether the current graphic context should be reset or not (Source) .

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

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

Categories