How to insert graphs into a pdf? - java

I would like to draw two graphs showing stacked bar graphs with labels, into a PDF file in Java. I would get the data from a Mongodb for input to graphs. How to do that?

Using JFreechart and pdfbox I have done something similar to what you are requesting for a report I made once. Making a pie chart was as follows:
public class PieChartExample {
public static void main(String[] args) {
// Create a simple pie chart
DefaultPieDataset pieDataset = new DefaultPieDataset();
pieDataset.setValue("Chrome", new Integer(42));
pieDataset.setValue("Explorer", new Integer(24));
pieDataset.setValue("Firefox", new Integer(24));
pieDataset.setValue("Safari", new Integer(12));
pieDataset.setValue("Opera", new Integer(8));
JFreeChart chart = ChartFactory.createPieChart3D(
"Browser Popularity", // Title
pieDataset, // Dataset
true, // Show legend
true, // Use tooltips
false // Configure chart to generate URLs?
);
try {
ChartUtilities.saveChartAsJPEG(new File("C:\\Users\\myname\\Desktop\\chart.jpg"), chart, 500, 300);
} catch (Exception e) {
System.out.println("Problem occurred creating chart.");
}
}
}
The above example came from a pdf I think is available on their website, it has examples for other charts if you need them. Once saved, I could import it to the pdf similarly to this:
try {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
document.addPage(page);
InputStream in = new FileInputStream(new File("c:/users/myname/desktop/chart.jpg"));
PDJpeg img = new PDJpeg(document, in);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.drawImage(img, 10, 300);
contentStream.close();
document.save("pathway/to/save.pdf");
} catch (IOException e) {
System.out.println(e);
} catch (COSVisitorException cos) {
System.out.println(cos);
}
itext is also a good library for pdf manipulation, but that is commercial after a point whereas pdfbox should be open source.
Good Luck!

You can use gnujavaplot. It's an api enabling you to call gnuplot via Java.

you can use any charting library to generate the chart (somme libraries examples here), and then add it to your PDF using Itext.

You can take a look at JasperReports. It's a Java framework for generating reports in PDF and other file formats.
It has integrated support for various types of charts using the JFreeChart library.
However, I should warn you that the learning curve for JasperReports is quite steep. Perhaps you could consider using a combination of JFreeChart with iText instead, as suggested in this post.

Related

Using Apache PDFBox 1.3.1 - Trying to scale down all images in PDF file

I am forced to use ver. 1.3.1 of Apache PDFBox. I wish I could use ver 2.+ but can't. Anyway, I am trying to scale down the images in some PDF files but am having trouble. If I was using ver 2.+ I could as I understand it use the {PDPageContentStream_obj}.transform(...) method but that's not avail. to me. Instead as I understand it, I need to apply the .concatenate2CTM(...) method. I am trying that but not getting the anticipated results; my resulting .pdf files display their graphics unchanged in scale. Need to do this to reduce file size to under 5 MB so it can be successfully sent through a gateway that would time out if the file was bigger. Changing the gateway timeout is not an option, unfortunately. My code currently looks like this:
private File compressFile2(File file) throws Exception {
try {
PDDocument doc = PDDocument.load(file);
List<PDPage> pdPages = doc.getDocumentCatalog().getAllPages();
Iterator<PDPage> iterPdPages = pdPages.iterator();
while (iterPdPages.hasNext()) {
PDPage page = iterPdPages.next();
PDPageContentStream cs = new PDPageContentStream(doc, page, true, true);
cs.saveGraphicsState();
cs.concatenate2CTM(.5, 0, 0, .5, 0, 0);
cs.saveGraphicsState();
}
doc.save(file.getAbsolutePath() + "_compressed");
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return new File(file.getAbsolutePath() + "_compressed");
}
Any ideas are appreciated. Thank you.

How can I add a background color to my PDF using iText 7?

I simply want to add color to the background of the PDF that I'm generating with this library.
I want my pages to have color as the background or even a picture. The documentation got me dizzy. There are no useful or meaningful descriptions; it can hardly be called documentation.
Why is this simple task so hard to achieve with this library? Do I have to go through the trouble of reading a whole book, just to understand how to use a library?
There is no straightforward answer online, or in their "examples", but I managed to find a similar question about having various page background-colors in the PDF file here.
UPDATE: It seems that the iText-7 eBooks/resources have been updated during the past 3 years. The following links are
working as of 21/07/2021.
NEW EBOOK URL FOR ITEXT-7 BUILDING BLOCKS HERE
VARIOUS CODE EXAMPLES HERE
ALL RESOURCES INDEX HERE
The solution is overly complex, in my opinion. This is just background color and it is a task that could have been made considerably less time consuming to understand. Making a framework as modular and flexible as possible is understandable, but sometimes there are some trivial tasks that people just want to get done quickly.
Anyway, here is the solution for anyone who might have the same problem as I did:
//Class that creates the PDF
public class PdfCreator {
//Helper class so we can add colour to our pages when we call it from outer class
private static class PageBackgroundsEvent implements IEventHandler {
#Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfPage page = docEvent.getPage();
PdfCanvas canvas = new PdfCanvas(page);
Rectangle rect = page.getPageSize();
//I used custom rgb for Color
Color bgColour = new DeviceRgb(255, 204, 204);
canvas .saveState()
.setFillColor(bgColour)
.rectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight())
.fillStroke()
.restoreState();
}
}
//PATH_OF_FILE is the path that the PDF will be created at.
String filename = PATH_OF_FILE + "/myFile.pdf";
OutputStream outputStream = new FileOutputStream(new File(filename));
PdfWriter writer = new PdfWriter(outputStream);
PdfDocument pdfDoc = new PdfDocument(writer);
pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, new PageBackgroundsEvent());
PageSize pageSize = pdfDoc.getDefaultPageSize();
Document document = new Document(pdfDoc, pageSize);
document.close();
}
Background images can be added the same way! See this link
to set a background image :
pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, event -> {
new PdfCanvas(((PdfDocumentEvent)event).getPage())
.addImageAt(ImageFactory.create("filename.png"), 50f, 50f, true);
});

Using Overlay in PDFBox 2.0

What I am trying to do here is to create text and place it onto a blank page. That page would then be overlayed onto another document and that would then be saved as one document. In 1.8 I was able to create a blank PDPage in a PDF, write text to it as needed, then overlay that PDF with another and then save or view on screen using the code below -
overlayDoc = new PDDocument();
page = new PDPage();
overlayDoc.addPage(page);
overlayObj = new Overlay();
font = PDType1Font.COURIER_OBLIQUE;
try {
contentStream = new PDPageContentStream(overlayDoc, page);
contentStream.setFont(font, 10);
}
catch (Exception e){
System.out.println("content stream failed");
}
After I created the stream, when I needed to write something to the overlay document's contentStream, I would call this method, give it my x, y coords and tell it what text to write (again, this is in my 1.8 version):
protected void writeString(int x, int y, String text) {
if (text == null) return;
try {
contentStream.moveTo(x, y);
contentStream.beginText();
contentStream.drawString(text); // deprecated. Use showText(String text)
contentStream.endText();
}
catch (Exception e){
System.out.println(text + " failed. " + e.toString());
}
}
I would call this method whenever I needed to add text and to wherever I needed to do so. After this, I would close my content stream and then merge the documents together as such:
import org.apache.pdfbox.Overlay;
Overlay overlayObj = new Overlay();
....
PDDocument finalDoc = overlayObj.overlay(overlayDoc, originalDoc);
finalDoc now contains a PDDocument which is my original PDF with text overlayed where needed. I could save it and view it as a BufferedImage on the desktop. The reason I moved to 2.0 was that first off I needed to stay on top of the most recent library and also that I was having issues putting an image onto the page (see here).
The issue I am having in this question is that 2.0 no longer has something similar to the org.apache.pdfbox.Overlay class. To confuse me even more is that there are two Overlay classes in 1.8 (org.apache.pdfbox.Overlay and org.apache.pdfbox.util.Overlay) whereas in 2.0 there is only one. The class I need (org.apache.pdfbox.Overlay), or the methods it offers at least, are not present in 2.0 as far as I can tell. I can only find org.apache.pdfbox.multipdf.Overlay.
Here's some quick code that works, it adds "deprecated" over a document and saves it elsewhere:
PDDocument overlayDoc = new PDDocument();
PDPage page = new PDPage();
overlayDoc.addPage(page);
Overlay overlayObj = new Overlay();
PDFont font = PDType1Font.COURIER_OBLIQUE;
PDPageContentStream contentStream = new PDPageContentStream(overlayDoc, page);
contentStream.setFont(font, 50);
contentStream.setNonStrokingColor(0);
contentStream.beginText();
contentStream.moveTextPositionByAmount(200, 200);
contentStream.drawString("deprecated"); // deprecated. Use showText(String text)
contentStream.endText();
contentStream.close();
PDDocument originalDoc = PDDocument.load(new File("...inputfile.pdf"));
overlayObj.setOverlayPosition(Overlay.Position.FOREGROUND);
overlayObj.setInputPDF(originalDoc);
overlayObj.setAllPagesOverlayPDF(overlayDoc);
Map<Integer, String> ovmap = new HashMap<Integer, String>(); // empty map is a dummy
overlayObj.setOutputFile("... result-with-overlay.pdf");
overlayObj.overlay(ovmap);
overlayDoc.close();
originalDoc.close();
What I did additionally to your version:
declare variables
close the content stream
set a color
set to foreground
set a text position (not a stroke path position)
add an empty map
And of course, I read the OverlayPDF source code, it shows more possibilities what you can do with the class.
Bonus content:
Do the same without using the Overlay class, which allows further manipulation of the document before saving it.
PDFont font = PDType1Font.COURIER_OBLIQUE;
PDDocument originalDoc = PDDocument.load(new File("...inputfile.pdf"));
PDPage page1 = originalDoc.getPage(0);
PDPageContentStream contentStream = new PDPageContentStream(originalDoc, page1, true, true, true);
contentStream.setFont(font, 50);
contentStream.setNonStrokingColor(0);
contentStream.beginText();
contentStream.moveTextPositionByAmount(200, 200);
contentStream.drawString("deprecated"); // deprecated. Use showText(String text)
contentStream.endText();
contentStream.close();
originalDoc.save("....result2.pdf");
originalDoc.close();

PDFBox - Create java.io.InputStream from String

I am integrating my RESTful service to support download of documents etc. For that I am exploring PDFBox library which has capability to work with PDF docs (fantastic) and it works OK if I have to create and save documents.
My example code looks like following;
PDDocument doc = null;
PDPage page = null;
try{
doc = new PDDocument();
page = new PDPage();
doc.addPage(page);
PDFont font = PDType1Font.HELVETICA;
PDPageContentStream content = new PDPageContentStream(doc,page);
content.beginText();
content.drawString("Some Content Received At Runtime");
content.endText();
content.close();
doc.save("SomeName.pdf");
doc.close();
// Now load and return the stream
return PDDocument.load("SomeName.pdf").getDocument().createCOSStream().getFilteredStream();
} catch (Exception e) {
// Do nothing for now
}
If you see in above example I have an option to convert document into InputStream but to achieve this I first have to Save the document and then reload! This is not desirable because this will clutter the server I am running on with junk.
What I really want is to achieve this without saving the document! Is it possible? Should I be looking at some other library like iText? If you know an example for the same please share.

Using sun PDF Renderer to display PDFs with embedded fonts

I'm having trouble using Sun's PDF Renderer package to view PDFs with embedded fonts. I have the following code which creates a BufferedImage out of every page of a PDF for viewing in my application, and it works fine when there are no embedded fonts. However, when the PDF has embedded fonts, it shows no text. Any ideas? Also, it opens fine in Adobe's PDF viewer.
File f = new File("C:\\test.pdf");
FileChannel fc = new RandomAccessFile(f, "r").getChannel();
PDFFile pdfFile = new PDFFile(fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()));
for(int x=0; x<pdfFile.getNumPages(); x++) {
try {
BufferedImage bi = (BufferedImage)pdfFile.getPage(x+1).getImage(
(int)pdfFile.getPage(x+1).getWidth(),
(int)pdfFile.getPage(x+1).getHeight(),
new Rectangle((int)pdfFile.getPage(x+1).getWidth(),
(int)pdfFile.getPage(x+1).getHeight()),
null, true, true);
}
catch (Exception e) {
e.printStackTrace();
}
}
I figured this out by changing PDF renders from PDFRenderer to PDFBox, which works much better. More info is available here.
You could also look at Icesoft, IText, JPedal, and Multivalent who offer Open Source PDF tools.

Categories