PDFBox - checkbox is not displayed if set readonly - java

I am generating PDF using PDFBox, where I need to add a checkbox, which needs to be preset to checked and readonly. But some how it does not work.
Please find below code, which adds the checkbox on PDF:
import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckbox;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
public class MyTest {
public static void main(String arg[]) throws IOException, COSVisitorException
{
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
document.addPage(page);
COSDictionary acroFormDict = new COSDictionary();
acroFormDict.setItem(COSName.getPDFName("Fields"), new COSArray()); // Added this line for Tilman's comment
PDAcroForm acroForm = new PDAcroForm(document, acroFormDict);
document.getDocumentCatalog().setAcroForm(acroForm);
float x = 10f;
float y = page.getMediaBox().getHeight();
float yOffset = 15f;
float yCurrent = y - yOffset;
COSDictionary cosDict = new COSDictionary();
COSArray rect = new COSArray();
rect.add(new COSFloat(x));
rect.add(new COSFloat(yCurrent));
rect.add(new COSFloat(x+20));
rect.add(new COSFloat(yCurrent-20));
cosDict.setItem(COSName.RECT, rect);
cosDict.setItem(COSName.FT, COSName.getPDFName("Btn")); // Field Type
cosDict.setItem(COSName.TYPE, COSName.ANNOT);
cosDict.setItem(COSName.SUBTYPE, COSName.getPDFName("Widget"));
cosDict.setItem(COSName.T, new COSString("testChk"));
cosDict.setItem(COSName.DA, new COSString("/Helv 7 Tf 0 g"));
PDCheckbox checkbox = new PDCheckbox(acroForm, cosDict);
// checkbox.setReadonly(true);
// checkbox.setFieldFlags(PDField.FLAG_READ_ONLY);
checkbox.setValue("Yes");
// checkbox.check();
page.getAnnotations().add(checkbox.getWidget());
acroForm.getFields().add(checkbox); // Added this line for Tilman's comment
yCurrent = yCurrent - 20 - yOffset;
File file = new File("C:\\pdf\\CheckBox\\CheckBoxSample1.pdf");
System.out.println("Sample file saved at : " + file.getAbsolutePath());
document.save(file);
document.close();
}
}
Now if you uncomment the line:
checkbox.setReadonly(true);
Or
checkbox.setFieldFlags(PDField.FLAG_READ_ONLY);
The checkbox will no more displayed (or may be there but value is unchecked).
I am using PDFBox 1.8.10
Behavior is similar in Adobe Reader 11 and Foxit.
Also if I generate the PDF without setting the box readonly, in Adobe, I see the checkbox displayed with value set, but when I bring focus on it using tab, it gets disappear. And again on focus out (I click somewhere else other than checkbox), it appears again.
It seems like I am missing a very small thing, but could not find out.
Any help?
Thanks in advance.

You need to give field appearance using PDAppearanceCharacteristicsDictionary class. That will fix above issue.
Please check sample code below:
import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDGamma;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceCharacteristicsDictionary;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckbox;
public class MyCheckBox {
public static void main(String arg[]) throws IOException, COSVisitorException
{
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_LETTER);
document.addPage(page);
PDFont font = PDType1Font.HELVETICA;
PDResources res = new PDResources();
String fontName = res.addFont(font);
String da = "/" + fontName + " 10 Tf 0 0.4 0 rg";
COSDictionary acroFormDict = new COSDictionary();
acroFormDict.setBoolean(COSName.getPDFName("NeedAppearances"), true);
acroFormDict.setItem(COSName.FIELDS, new COSArray());
acroFormDict.setItem(COSName.DA, new COSString(da));
PDAcroForm acroForm = new PDAcroForm(document, acroFormDict);
acroForm.setDefaultResources(res);
document.getDocumentCatalog().setAcroForm(acroForm);
float x = 10f;
float y = page.getMediaBox().getHeight();
float yOffset = 15f;
float yCurrent = y - yOffset;
PDGamma colourBlack = new PDGamma();
PDAppearanceCharacteristicsDictionary fieldAppearance =
new PDAppearanceCharacteristicsDictionary(new COSDictionary());
fieldAppearance.setBorderColour(colourBlack);
COSArray arr = new COSArray();
arr.add(new COSFloat(227/255f));
arr.add(new COSFloat(239/255f));
arr.add(new COSFloat(1f));
fieldAppearance.setBackground(new PDGamma(arr));
COSDictionary cosDict = new COSDictionary();
COSArray rect = new COSArray();
rect.add(new COSFloat(x));
rect.add(new COSFloat(yCurrent));
rect.add(new COSFloat(x+20));
rect.add(new COSFloat(yCurrent-20));
cosDict.setItem(COSName.RECT, rect);
cosDict.setItem(COSName.FT, COSName.getPDFName("Btn")); // Field Type
cosDict.setItem(COSName.TYPE, COSName.ANNOT);
cosDict.setItem(COSName.SUBTYPE, COSName.getPDFName("Widget"));
cosDict.setItem(COSName.TU, new COSString("Test Checkbox with PDFBox"));
cosDict.setItem(COSName.T, new COSString("testChk"));
cosDict.setItem(COSName.DA, new COSString("/F0 10 Tf 0 0.4 0 rg"));
// cosDict.setInt(COSName.FF, 49152); //Radio Button Symbol
cosDict.setInt(COSName.F, 4);
// cosDict.setInt(COSName.FF, 16384);
PDCheckbox checkbox = new PDCheckbox(acroForm, cosDict);
checkbox.setFieldFlags(PDCheckbox.FLAG_READ_ONLY);
checkbox.setValue("Yes");
// checkbox.setValue("Off");
checkbox.getWidget().setAppearanceCharacteristics(fieldAppearance);
page.getAnnotations().add(checkbox.getWidget());
acroForm.getFields().add(checkbox);
yCurrent = yCurrent - 20 - yOffset;
File file = new File("C:\\pdf\\CheckBoxSample.pdf");
System.out.println("Sample file saved at : " + file.getAbsolutePath());
document.save(file);
document.close();
}
}

Related

How to dynamically create a footer with Itext in Java?

I have a serious problem with my footer generator. It has the function to describe one specific word from the page (I think that is called a footnote).
This function doesn't quite work yet, anyways. The problem is that my footer can have 1, all the way to 20 or something lines. And in most cases, it is overlapping with the text.
Here is the code of my footer creator:
Font fontTimes = FontFactory.getFont(FontFactory.TIMES_ROMAN, 10,
Font.NORMAL);
PdfPTable table = new PdfPTable(1);
table.getDefaultCell().setBorder(Rectangle.TOP);
table.addCell("all the descriptions.");
table.writeSelectedRows(0, -1, document.left(document.leftMargin()),
table.getTotalHeight() + document.bottom(document.bottomMargin()),
writer.getDirectContent());
The rest of the pages are just created with lists that contains paragraphs, they are just added in the document. And I use "onEndPage" to put the footer in every page.
Here is some of the code I use to create and write in the document:
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(this.fileStorageLocation.resolve(caminhoDoc) + File.separator + nomeDocumento + ".pdf"));
document.setPageSize(PageSize.A4);
document.setMargins(36, 36, 36, 55);
document.setMarginMirroring(false);
writer.setPageEvent(this);
//creating lists...
document.add(mainList);
The pdf is great, except the footer, that is overlapping the rest of the content. I am not sure how to fix it, I'm thinking that maybe the solution is to calculate the space that the footer will need, then set the specific page size to fit with that blank space for the footer.
Here is a small code sample to add footer dynamically to each page of the pdf using the PdfPageEventHelper interface
package com.asu.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletContext;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.html.WebColors;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;
public class HeaderFooter extends PdfPageEventHelper {
/** Alternating phrase for the header. */
Phrase[] header = new Phrase[2];
/** Current page number (will be reset for every chapter). */
int pagenumber;
private ServletContext context;
private String domainName;
private String createdDate;
public HeaderFooter(ServletContext context, String reportType, String
createdDate, String domainName) {
this.context = context;
this.reportType = reportType;
this.createdDate = createdDate;
this.domainName = domainName;
// TODO Auto-generated constructor stub
}
/**
* Adds the footer.
*
* #see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter,
* com.itextpdf.text.Document)
*/
public void onEndPage(PdfWriter writer, Document document) {
Image image;
Font fontStyle = new Font();
fontStyle.setColor(255, 255, 255);
fontStyle.setSize(6);
try {
image = Image.getInstance(context.getRealPath("template//images//footer1.png"));
int indentation = 0;
float scaler = ((document.getPageSize().getWidth() - indentation) / image.getWidth()) * 100;
image.scalePercent(scaler);
image.setAbsolutePosition(0, 0);
document.add(image);
} catch (Exception e) {
e.printStackTrace();
}
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-YYYY");
String date = sdf.format(new Date());
ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_CENTER,
new Phrase(String.format("Page - %d, Printed on : %s %s", pagenumber, date,
domainName), fontStyle),
(document.getPageSize().getWidth()) / 2, document.bottomMargin() - 28.5f, 0);
}
}
Then call the headerfooter onEndPage() from the pdf generation method
HeaderFooter headerFooter = new HeaderFooter(context, "reportType",
reportCreatedDate, domainName);

getting error while converting ppt file to PDF in java

I'm just beginner in java
I trying to convert PPT file to PDF file using apache poi and Itext library but i'm getting error of NoSuchMethodError
I tried all the version of Apache poi and poi-ooxml but i'm getting same error
please help me to findout Solution for this error
Here is my code :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class PPTtoPDF {
public PPTtoPDF() {
}
#SuppressWarnings("resource")
public void convertPPTToPDF(String sourcepath, String destinationPath) throws Exception {
FileInputStream inputStream = new FileInputStream(sourcepath);
double zoom = 2;
AffineTransform at = new AffineTransform();
at.setToScale(zoom, zoom);
Document pdfDocument = new Document();
PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument, new FileOutputStream(destinationPath));
PdfPTable table = new PdfPTable(1);
pdfWriter.open();
pdfDocument.open();
Dimension pgsize = null;
Image slideImage = null;
BufferedImage img = null;
SlideShow ppt = new SlideShow(inputStream);
pgsize = ppt.getPageSize();
Slide slide[] = ppt.getSlides();
System.out.println("Length----> "+slide.length);
pdfDocument.setPageSize(new Rectangle((float) pgsize.getWidth(), (float) pgsize.getHeight()));
pdfWriter.open();
pdfDocument.open();
for (int i = 0; i < slide.length; i++) {
img = new BufferedImage((int) Math.ceil(pgsize.width * zoom), (int) Math.ceil(pgsize.height * zoom), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setTransform(at);
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
slide[i].draw(graphics);
graphics.getPaint();
slideImage = Image.getInstance(img, null);
table.addCell(new PdfPCell(slideImage, true));
System.out.println(table);
}
pdfDocument.add(table);
pdfDocument.close();
pdfWriter.close();
System.out.println("Powerpoint file converted to PDF successfully");
}
public static void main(String[] args) throws Exception
{
PPTtoPDF pp = new PPTtoPDF();
pp.convertPPTToPDF("D:\\tp\\slides.ppt", "D:\\tp\\1.pdf");
}
}
and the error is
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.poi.POIDocument.<init>(Lorg/apache/poi/poifs/filesystem/DirectoryNode;Lorg/apache/poi/poifs/filesystem/POIFSFileSystem;)V
at org.apache.poi.hslf.HSLFSlideShow.<init>(HSLFSlideShow.java:134)
at org.apache.poi.hslf.HSLFSlideShow.<init>(HSLFSlideShow.java:120)
at org.apache.poi.hslf.HSLFSlideShow.<init>(HSLFSlideShow.java:107)
at org.apache.poi.hslf.usermodel.SlideShow.<init>(SlideShow.java:122)
at convertService.PPTtoPDF.convertPPTToPDF(PPTtoPDF.java:44)
at convertService.PPTtoPDF.main(PPTtoPDF.java:75)
See the Apache POI FAQ entry on this very topic. What has almost certainly happened is that you have added a new copy of POI to your classpath, but an older version was already there (from an earlier need, your framework etc), and Java is now getting confused about which one to use.
You could use tool for that:
mvn dependency
tree JDK 8: jdeps
(https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool)
jdeps is a new command-line tool added since JDK 8 for developers to
use to understand the static dependencies of their applications and
libraries. jdeps is a static analysis tool on the given class files

I am using itext to generate pdf. Now , I want to make paragrap align same with table, what should Ido?

Just like the image, I want to make 1 and 3 align same with 2. The table is default alignment.
What should I do?
Here is a simple way of doing it , add both to the same paragraph
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class ItextMain {
public static final String DEST = "simple_table4.pdf";
public static void main(String[] args) throws IOException, DocumentException {
File file = new File(DEST);
// file.getParentFile().mkdirs();
new ItextMain().createPdf(DEST);
}
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
document.add(new Paragraph("1-Not aligned with table"));
document.add(new Chunk());
Paragraph p = new Paragraph();
p.setIndentationLeft(20);// (20);
PdfPTable table = new PdfPTable(4);
for (int aw = 0; aw < 16; aw++) {
table.addCell("hi");
}
table.setHorizontalAlignment(Element.ALIGN_LEFT);
p.add(table);
//document.add(table);
p.add("3- Aligned with table");
document.add(p);
document.close();
}
}
The iText 5 PdfPTable class has a width percentage attribute which holds the width percentage that the table will occupy in the page. By default this value is 80 and the resulting table is horizontally centered on the page, i.e. in particular it is indented.
To prevent this, simply set the percentage value to 100:
PdfPTable table = ...;
table.setWidthPercentage(100);
Alternatively set the horizontal alignment:
table.setHorizontalAlignment(Element.ALIGN_LEFT);

How to add hyperlink in pdf using pdfbox

I want to add a hyperlink in PDF created using PDFBOX, such that i click on some text example 'Click here' will redirect to URL. I tried using PDAnnotationLink and PDActionURI, but how to add it in contentstream?
PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
PDAnnotationLink txtLink = new PDAnnotationLink();
txtLink.setBorderStyle(borderULine);
txtLink.setColour(colourBlue);
// add an action
PDActionURI action = new PDActionURI();
action.setURI("www.google.com");
txtLink.setAction(action);
contentStream.beginText();
contentStream.moveTextPositionByAmount(400, y-30);
contentStream.drawString(txtLink);----error
contentStream.endText();
To add to contentStream use the following code
PDRectangle position = new PDRectangle();
position.setLowerLeftX(10);
position.setLowerLeftY(20);
position.setUpperRightX(100);
position.setUpperRightY(10);
txtLink.setRectangle(position);
page.getAnnotations().add(txtLink);
There is a library called PDFBox-Layout which makes it easier to add hyperlinks:
Document document = new Document();
Paragraph paragraph = new Paragraph();
paragraph.addMarkup(
"This is a link to {link[https://github.com/ralfstuckert/pdfbox-layout]}PDFBox-Layout{link}",
18f, BaseFont.Helvetica);
document.add(paragraph);
final OutputStream outputStream = new FileOutputStream("link.pdf");
document.save(outputStream);
This is a fully working example, tested with PDFBox 2.0.19:
import java.awt.Color;
import java.io.File;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;
public class MainCreateHyerLink
{
public static void main (final String [] args) throws Exception
{
try (final PDDocument doc = new PDDocument ())
{
final PDPage page = new PDPage (new PDRectangle (250, 150));
doc.addPage (page);
try (final PDPageContentStream contentStream = new PDPageContentStream (doc, page))
{
final PDAnnotationLink txtLink = new PDAnnotationLink ();
// border style
final PDBorderStyleDictionary linkBorder = new PDBorderStyleDictionary ();
linkBorder.setStyle (PDBorderStyleDictionary.STYLE_UNDERLINE);
linkBorder.setWidth (10);
txtLink.setBorderStyle (linkBorder);
// Border color
final Color color = Color.GREEN;
final float [] components = new float [] { color.getRed () / 255f, color.getGreen () / 255f, color.getBlue () / 255f };
txtLink.setColor (new PDColor (components, PDDeviceRGB.INSTANCE));
// Destination URI
final PDActionURI action = new PDActionURI ();
action.setURI ("https://www.helger.com");
txtLink.setAction (action);
// Position
final PDRectangle position = new PDRectangle ();
position.setLowerLeftX (10);
position.setLowerLeftY (10);
position.setUpperRightX (200);
position.setUpperRightY (10 + 2 + 10 + 2);
txtLink.setRectangle (position);
page.getAnnotations ().add (txtLink);
// Main page content
contentStream.beginText ();
contentStream.newLineAtOffset (12, 12);
contentStream.setFont (PDType1Font.COURIER_BOLD, 10);
contentStream.showText ("This is linked to the outside world");
contentStream.endText ();
}
}
}
}

How to create a PDF with multiple pages from a Graphics object with Java and itext

I have an abstract class with an abstract method draw(Graphics2D g2), and the methods print(), showPreview(), printPDF(). For each document in my Java program, I implement draw(), so I can print, show preview and create a PDF file for each document.
My problem is how to create a PDF with multiple pages from that Graphics object.
I solved it by creating a PDF file for each page, and then merge the files into one new file. But there must be a better way.
I have following code to create PDF with one page:
public void printPDF1(){
JFileChooser dialog = new JFileChooser();
String filePath = "";
int dialogResult = dialog.showSaveDialog(null);
if (dialogResult==JFileChooser.APPROVE_OPTION){
filePath = dialog.getSelectedFile().getPath();
}
else return;
try {
Document document = new Document(new Rectangle(_pageWidth, _pageHeight));
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream(filePath));
document.open();
PdfContentByte cb = writer.getDirectContent();
g2 = cb.createGraphics(_pageWidth, _height);
g2.translate(0, (_numberOfPages - _pageNumber) * _pageHeight);
draw(g2);
g2.dispose();
document.close();
}
catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
document.open();
// the same contentByte is returned, it's just flushed & reset during
// new page events.
PdfContentByte cb = writer.getDirectContent();
for (int _pageNumber = 0; _pageNumber < _numberofPages; ++_numberOfPages) {
/*******************/
//harmless in first pass, *necessary* in others
document.newPage();
/*******************/
g2 = cb.createGraphics(_pageWidth, _height);
g2.translate(0, (_numberOfPages - _pageNumber) * _pageHeight);
draw(g2);
g2.dispose();
}
document.close();
So you're rendering your entire interface N times, and only showing a page-sized slice of it in different locations. That's called "striping" in print-world IIRC. Clever, but it could be more efficient in PDF.
Render your entire interface into one huge PdfTemplate (with g2d), once. Then draw that template into all your pages such that the portion you want is visible inside the current page's margins ("media box").
PdfContentByte cb = writer.getDirectContent();
float entireHeight = _numberOfPages * _pageHeight;
PdfTemplate hugeTempl = cb.createTemplate( 0, -entireHeight, pageWidth, _pageHeight );
g2 = hugeTempl.createGraphics(0, -entireHeight, _pageWidth, _pageHeight );
draw(g2);
g2.dispose();
for (int curPg = 0; curPg < _numberOfPages; ++curPg) {
cb.addTemplateSimple( hugeTempl, 0, -_pageHeight * curPg );
document.newPage();
}
PDF's coordinate space sets 0,0 in the lower left corner, and those values increase as you go up and to the right. PdfGraphis2D does a fair amount of magic to hide that difference from you, but we still have to deal with it a bit here... thus the negative coordinates in the bounding box and drawing locations.
This is all "back of the napkin" coding, and it's entirely possible I've made a mistake or two in there... but that's the idea.
I was having trouble following the above code (some of the methods appear to have changed in the current itextpdf version). Here's my solution:
import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.WindowEvent;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class PanelToPDF {
private static JFrame frame= new JFrame();
private static JPanel view= new JPanel();
private static float pageWidth= PageSize.A4.getWidth();
private static float pageHeight= PageSize.A4.getHeight();
public static void main(String[] args) throws Exception {
System.out.println("Page width = " + pageWidth + ", height = " + pageHeight);
initPane();
createMultipagePDF();
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
}
private static void initPane() {
view.setLayout(new MigLayout());
view.setBackground(Color.WHITE);
for (int i= 1; i <= 160; ++i) {
JLabel label= new JLabel("This is a test! " + i);
label.setForeground(Color.BLACK);
view.add(label, "wrap");
JPanel subPanel= new JPanel();
subPanel.setBackground(Color.RED);
view.add(subPanel);
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(Math.round(pageWidth), Math.round(pageHeight)));
frame.add(view);
frame.setVisible(true);
}
private static void createMultipagePDF() throws Exception {
// Calculate the number of pages required. Use the preferred size to get
// the entire panel height, rather than the panel height within the JFrame
int numPages= (int) Math.ceil(view.getPreferredSize().height / pageHeight); // int divided by float
// Output to PDF
OutputStream os= new FileOutputStream("test.pdf");
Document doc= new Document();
PdfWriter writer= PdfWriter.getInstance(doc, os);
doc.open();
PdfContentByte cb= writer.getDirectContent();
// Iterate over pages here
for (int currentPage= 0; currentPage < numPages; ++currentPage) {
doc.newPage(); // not needed for page 1, needed for >1
PdfTemplate template= cb.createTemplate(pageWidth, pageHeight);
Graphics2D g2d= new PdfGraphics2D(template, pageWidth, pageHeight * (currentPage + 1));
view.printAll(g2d);
g2d.dispose();
cb.addTemplate(template, 0, 0);
}
doc.close();
}

Categories