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 ();
}
}
}
}
Related
I create a pdf with databse values using itext pdf in java.Now i need to open that ModelAndView in my angularjs.
Here is my code
Controller.js
$scope.strPdf=function strPdf(id){
$http.get(urlBase+"/stockTransferPdf/"+id).success(function(data){
alert("success");
})
}
controller.java
#RequestMapping(value = "/stockTransferPdf/{id}", method = RequestMethod.GET)
public ModelAndView stockTranferPdfView(#PathVariable int id,HttpServletRequest request,HttpServletResponse response) {
StockTransferRequest str=inventoryService.getStockTransferRequest(id);
ModelAndView m = new ModelAndView("stockTransferPdfView");
m.getModelMap().addAttribute("stockTransfer",str);
return m;
}
My Pdf Creator Class.java
package com.opine.manufacturing_erp.web.report;
import java.io.File;
import java.io.FileOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.FontFactory;
import com.itextpdf.text.Image;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.opine.manufacturing_erp.web.model.StockTransferRequest;
import com.opine.manufacturing_erp.web.model.StockTransferRequestList;
public class stockTransferPdfView extends AbstractITextPdfView{
#Override
public void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer,
HttpServletRequest request, HttpServletResponse response) throws Exception {
try{
String rootPath = getClass().getClassLoader().getResource("").getPath();
System.out.println(rootPath);
File file = new File(rootPath + File.separator +"itext-test.pdf");
FileOutputStream fileout = new FileOutputStream(file);
PdfWriter.getInstance(document, fileout);
StockTransferRequest st=(StockTransferRequest) model.get("stockTransfer");
document.open();
Paragraph header = new Paragraph(
new Chunk("TOBEN LOGISTICS SOLUTION PVT. LTD.", FontFactory.getFont(FontFactory.COURIER_BOLD, 12)));
header.setAlignment(Element.ALIGN_CENTER);
Paragraph adrs_line1 = new Paragraph(
new Chunk("#31 B1, Hare Krishna Illam, First Floor,", FontFactory.getFont(FontFactory.HELVETICA, 10)));
Paragraph adrs_line2 = new Paragraph(
new Chunk("Thilagar Street, R.S.Puram, Coimbatore,", FontFactory.getFont(FontFactory.HELVETICA, 10)));
Paragraph adrs_line3 = new Paragraph(
new Chunk("Tamil Nadu - 641 002, INDIA", FontFactory.getFont(FontFactory.HELVETICA, 10)));
adrs_line1.setAlignment(Element.ALIGN_CENTER);
adrs_line2.setAlignment(Element.ALIGN_CENTER);
adrs_line3.setAlignment(Element.ALIGN_CENTER);
Paragraph date = new Paragraph(new Chunk("Print Date:"+new Date(), FontFactory.getFont(FontFactory.COURIER, 8)));
date.setAlignment(Element.ALIGN_RIGHT);
date.setSpacingAfter(1);
LineSeparator lsp=new LineSeparator();
Font font = FontFactory.getFont(FontFactory.COURIER_BOLD);
font.setColor(BaseColor.WHITE);
Font font1 = new Font(FontFamily.COURIER, 8, Font.NORMAL, GrayColor.BLACK);
//String filename = getClass().getClassLoader().getResource("").getPath() + File.separator+"logo_log.png";
Paragraph stock_transfer_table_heading = new Paragraph(
new Chunk("Stock Transfer Details", FontFactory.getFont(FontFactory.HELVETICA, 10)));
stock_transfer_table_heading.setAlignment(Element.ALIGN_LEFT);
Paragraph stock_transfer_list_table_heading = new Paragraph(
new Chunk("Stock Transfer List", FontFactory.getFont(FontFactory.HELVETICA, 10)));
stock_transfer_list_table_heading.setAlignment(Element.ALIGN_LEFT);
PdfPTable stock_transfer_table=getStockTransferDetails(st,font1);
PdfPTable stock_transfer_list_table=getStockTransferListDetails(st,font1);
document.setMargins(30, 20, 5, 5); // left, right, top/bottom margin
document.newPage();
/* Image image = Image.getInstance(filename);
image.scaleAbsoluteHeight(50);
image.scaleAbsoluteWidth((image.getWidth() * 50) / image.getHeight());
image.setAbsolutePosition(25f, 780f);
document.add(image);*/
document.add(header);
document.add(adrs_line1);
document.add(adrs_line2);
document.add(adrs_line3);
document.add(Chunk.NEWLINE);
document.add(date);
document.add(Chunk.NEWLINE);
document.add(stock_transfer_table_heading);
document.add(Chunk.NEWLINE);
document.add(stock_transfer_table);
document.add(Chunk.NEWLINE);
document.add(stock_transfer_list_table_heading);
document.add(Chunk.NEWLINE);
document.add(stock_transfer_list_table);
document.add(Chunk.NEWLINE);
document.close();
}
catch(Exception e){
e.printStackTrace();
}
}
private PdfPTable getStockTransferDetails(StockTransferRequest str,Font font) {
PdfPTable table= new PdfPTable(2);
table.setWidthPercentage(100);
com.itextpdf.text.List list = new com.itextpdf.text.List();
list.add(new ListItem("Created Date",font));
list.add(new ListItem("Source WareHouse ",font));
list.add(new ListItem("Target WareHouse ",font));
list.add(new ListItem("Total Packages ",font));
list.add(new ListItem("Transfer Status ",font));
com.itextpdf.text.List valueList = new com.itextpdf.text.List();
valueList.add(new ListItem(dateToString(str.getCreatedDate()),font));
valueList.add(new ListItem(str.getSourceWarehouse().getWarehouse_name(),font));
valueList.add(new ListItem(str.getTargetWarehouse().getWarehouse_name(),font));
valueList.add(new ListItem(String.valueOf(str.getTotal_packages()),font));
valueList.add(new ListItem(str.getTransfer_status(),font));
Phrase phraseShipper = new Phrase();
phraseShipper.add(list);
PdfPCell phraseCellShipper = new PdfPCell();
phraseCellShipper.addElement(phraseShipper);
// We add this phrase to a cell-Service info
Phrase phraseService = new Phrase();
phraseService.add(valueList);
PdfPCell phraseCellService = new PdfPCell();
phraseCellService.addElement(phraseService);
table.addCell(phraseCellShipper);
table.addCell(phraseCellService);
return table;
}
private PdfPTable getStockTransferListDetails(StockTransferRequest str,Font font) {
PdfPTable table = getPdfTable(getStockTransferListColumenList(), font);
table.setWidthPercentage(100);
for(StockTransferRequestList strqlist:str.getStockTransferRequestList()){
table.addCell(new Phrase(strqlist.getItem().getProduct_name(),font));
table.addCell(new Phrase(dateToString(strqlist.getCreatedDate()),font));
table.addCell(new Phrase(String.valueOf(strqlist.getQuantity()),font));
table.addCell(new Phrase(strqlist.getUom(),font));
}
return table;
}
private String[] getStockTransferListColumenList() {
String[] stock_transferList = new String[] { "Product", "Created Date", "Quantity", "UOM"};
return stock_transferList;
}
private String dateToString(Date date) {
DateFormat df = new SimpleDateFormat("MM/dd/yyyy ");
return df.format(date);
}
private PdfPTable getPdfTable(String[] ColumnNames, Font font) {
// Create Cargo Table
PdfPTable table = new PdfPTable(ColumnNames.length);
/*font.setColor(BaseColor.WHITE);*/
table.setWidthPercentage(100.0f);
// define table header cell
PdfPCell cell1 = new PdfPCell();
cell1.setBackgroundColor(BaseColor.GRAY);
cell1.setPadding(5);
// write table header
for (String colmn : ColumnNames) {
cell1.setPhrase(new Phrase(colmn, font));
table.addCell(cell1);
}
return table;
}
}
using the above code i can able to create a pdf file with database content but i need to display the pdf file. i don't know how to do this.
i am struck in this from past two days. Can any one help me to achieve my need.
In Spring Controller your method should look like this.
#RequestMapping(value = "createPdf", method = RequestMethod.GET, produces = "application/pdf")
public ResponseEntity<byte[]> createPdf(HttpServletResponse response) {
response.setContentType("application/pdf");
byte[] contents = // populate pdf data
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
headers.set("Content-Disposition", "inline");
return new ResponseEntity<>(contents, headers, HttpStatus.OK);
}
Then in Angular JS.
$http({
url: "url",
method: 'GET',
responseType: 'arraybuffer'
})
.then(({ data }) => {
var file = new Blob([data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
$window.open(fileURL);
})
I'm using PDFBox 2. Trying to write a PNG image file to new PDF file.
I saw there was already an answer that mention it was fixed on PDFBox2:
How to add .png images to pdf using Apache PDFBox and
https://issues.apache.org/jira/browse/PDFBOX-1990
This is my code:
package pdfProj;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
public class b {
public static void main(String[] args) {
PDDocument doc = null;
doc = new PDDocument();
doc.addPage(new PDPage());
try{
BufferedImage awtImage = ImageIO.read( new File( "c://temp//line_chart.png" ) );
PDImageXObject pdImageXObject = LosslessFactory.createFromImage(doc, awtImage);
PDPageContentStream contentStream = new PDPageContentStream(doc, new PDPage(), true, false);
contentStream.drawImage(pdImageXObject, 200, 300, awtImage.getWidth() / 2, awtImage.getHeight() / 2);
contentStream.close();
doc.save( "c://temp//pdf//PDF_image.pdf" );
doc.close();
} catch (Exception io){
System.out.println(" -- fail --" + io);
}
}
}
There is no exception. Just getting an empty PDF file created.
The issue is that you add a new page to the document
doc.addPage(new PDPage());
but then create a content stream for yet another new page which you don't add to the document:
PDPageContentStream contentStream = new PDPageContentStream(doc, new PDPage(), true, false);
You should create the content stream for the page you added to the document, e.g. like this:
PDDocument doc = null;
doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
try{
BufferedImage awtImage = ImageIO.read( new File( "c://temp//line_chart.png" ) );
PDImageXObject pdImageXObject = LosslessFactory.createFromImage(doc, awtImage);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, false);
contentStream.drawImage(pdImageXObject, 200, 300, awtImage.getWidth() / 2, awtImage.getHeight() / 2);
contentStream.close();
doc.save( "c://temp//pdf//PDF_image.pdf" );
doc.close();
} catch (Exception io){
System.out.println(" -- fail --" + io);
}
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();
}
}
I am using iText and some SVG rendering library.
I want to render a SVG image to PDF. I am using following code to do that. Now the problem is I am giving an area chart SVG to it, it is not rendering line properly. Attaching screenshots.
Following classes has been used:
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.svg.SVGDocument;
and here the cop snippet:
String parser = XMLResourceDescriptor.getXMLParserClassName();
factory = new SAXSVGDocumentFactory(parser);
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
builder = new GVTBuilder();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate chartImageTemplate = cb.createTemplate(1000, 1000);
SVGDocument svgDoc=null;
try {
InputStream in = new ByteArrayInputStream(chartImage.getBytes());
svgDoc = factory.createSVGDocument("", in);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try{
GraphicsNode mapGraphics = builder.build(ctx, svgDoc);
DefaultFontMapper mapper = new DefaultFontMapper();
PdfGraphics2D g2 = (PdfGraphics2D)cb.createGraphics(1000, 500, mapper);
Graphics2D g2d = g2;
mapGraphics.paint(g2d);
g2d.dispose();
cb.addTemplate(chartImageTemplate, 0, 0);
return mapGraphics.getGeometryBounds().getHeight();
}catch(Exception e){
}
You can find SVG here:
http://speedy.sh/xvDp8/demo.svg
Actual SVG:
Rendered PDF
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();
}