I have created a servlet to handle the save of a JFreeChart displayed in a JSP to a PDF file.
The code I am using so far is:
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jfree.chart.JFreeChart;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.DefaultFontMapper;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;
public class ChartPrintServlet extends HttpServlet {
private static final long serialVersionUID = -2445101551756014281L;
protected void doPost ( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
JFreeChart jFreeChart = (JFreeChart) request.getSession().getAttribute("jFreeChart");
String url = "";
int height = 1024;
int width = 1152;
if (jFreeChart == null)
{
url = "/do/error";
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(url);
dispatcher.forward(request, response);
}
else
{
AbsencesGanttChartPostProcessor postProc = new AbsencesGanttChartPostProcessor();
postProc.processChart(jFreeChart, null);
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"absences.pdf\"");
OutputStream out = response.getOutputStream();
try
{
Rectangle pagesize = new Rectangle(width, height);
Document document = new Document(pagesize.rotate(), 30, 30, 30, 30);
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate tp = cb.createTemplate(height, width);
Graphics2D g2 = tp.createGraphics(height, width, new DefaultFontMapper());
Rectangle2D r2D = new Rectangle2D.Double(0, 0, height, width);
jFreeChart.draw(g2, r2D);
g2.dispose();
cb.addTemplate(tp, 0, 0);
document.close();
}
catch (DocumentException de)
{
System.err.println(de.getMessage());
}
finally
{
out.close();
}
}
}
protected void doGet ( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
}
I have swapped the height and width everywhere in order to get the PDF to look half-decent, but what I really want is to be able to create a PDF as if it were in landscape mode.
If I try
Graphics2D g2 = tp.createGraphics(height, width, new DefaultFontMapper());
g2.rotate(90)
then the PDF just prints a white, blank page.
What is the correct way with the itext / Java awt APIs to go about rotating the entire document (including the JFreeChart underneath) when creating a PDF?
First this: your referring to my name in your code. I'd like you to use itextpdf instead. See http://lowagie.com/itext2
Now for your question. There's an easy way to achieve what you want, and there's a more difficult way.
You only use three parameters in this method: cb.addTemplate(tp, 0, 0); which means that you only want iText to do a translation (zero up, zero to the right). If you also want a rotation, you need to use the method with seven parameters, six of which define the transformation matrix. This is simple algebra; it's explained in my book "iText in Action", but most of the developers I know don't like doing math and they say this is the difficult way.
The easy way, is to wrap tp inside an Image object, and rotate the image:
Image img = Image.getInstance(tp);
img.setRotationDegrees(90);
There's also a setRotation() method that takes radians as a parameter.
Additional notes:
Don't worry about the Image class rasterizing your content. A PdfTemplate wrapped inside an Image object will result in a Form XObject, it won't be changed into an Image XObject.
Be careful not to rotate your image 'outside your page'. You may need to take into account the pivot point.
You rotate your Graphics counterclockwise around the top left corner, and doing so moves everything out of the drawing area. This is why you just get the blank page. You need to apply translation also to shift graphics back into the painting area. Translate y downwards by the width of you image:
g.rotate(Math.PI / 2);
g.translate(0, width);
Also, Graphics2D.rotate expects radians, not degrees.
After that, JFreeChart should draw the transformed chart if you pass transformed Graphics2D for it.
Related
I am trying to convert the pptx to png images using apache-poi in java but it doesn't work with pptx generated by LibreOffice Impress (works fine with others ) and there is no exception thrown.
The resulting images I get are just the background with out the text content of the pptx.
Please see the links for the results.
The resulting image
Screen shot of Actual pptx slide
This is the basic code I got :
package com.preview;
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 java.io.IOException;
import java.util.List;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
public class PptxToPng {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileInputStream is = new FileInputStream("~/Downloads/pptx/SamplePPTX.pptx");
XMLSlideShow ppt = new XMLSlideShow(is);
is.close();
double zoom = 2;
AffineTransform at = new AffineTransform();
at.setToScale(zoom, zoom);
Dimension pgsize = ppt.getPageSize();
List<XSLFSlide> slide = ppt.getSlides();
BufferedImage 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.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
// Draw first page in the PPTX. First page starts at 0 position
slide.get(0).draw(graphics);
FileOutputStream out = new FileOutputStream("~/Downloads/pptx/converted.png");
javax.imageio.ImageIO.write(img, "png", out);
out.close();
ppt.close();
System.out.println("DONE");
}
}
poi-ooxml-3.15.jar comes with a tool called PPTX2PNG. It can be found in the package org.apache.poi.xslf.util
Execute it eg with parameters -scale 1 -format jpg pptx-file.pptx and it should write an image file to the same directory as the origin pptx file.
BTW: despite the name, it can write to png, jpg and gif formats.
I'm using apache poi library to make a ppt file in my java program.
To insert elements, I added elements to a Document object.
the add order is below.
Picture1 -> rectangle1 -> Picture2 -> rectangle2
But, All Pictures is over all rectangles in output ppt file.
How to set z-order of elements such as the order of add?
Well, here is what you can do. The order of adding is, as you see, Rectangle1, Picture, Rectangle2. And the z-order is respected (we can see all Rectangle2, but a Rectangle1 is partly hidden behind the image):
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hslf.model.PPGraphics2D;
import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.model.ShapeGroup;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
public class PowerPointTest {
public static void main( String[] args ) {
SlideShow slideShow = new SlideShow();
Slide slide = slideShow.createSlide();
try {
// Rectangle1 (partly hidden)
fillRectangle( slide, Color.blue, 20, 20, 300, 300 );
// Image
int index = slideShow.addPicture(new File("IMG_8499.jpg"), Picture.JPEG);
Picture picture = new Picture(index);
picture.setAnchor(new Rectangle( 50, 50, 300, 200 ));
slide.addShape(picture);
// Rectangle2 (all visible)
fillRectangle( slide, Color.yellow, 250, 150, 50, 10 );
FileOutputStream out = new FileOutputStream( "z-order.ppt" );
slideShow.write( out );
out.close();
} catch ( FileNotFoundException e ) {
e.printStackTrace();
} catch ( IOException e ) {
e.printStackTrace();
}
}
private static void fillRectangle( Slide slide, Color color, int x, int y, int width, int height ) {
// Objects are drawn into a shape group, so we need to create one
ShapeGroup group = new ShapeGroup();
// Define position of the drawing inside the slide
Rectangle bounds = new Rectangle(x, y, width, height);
group.setAnchor(bounds);
slide.addShape(group);
// Drawing a rectangle
Graphics2D graphics = new PPGraphics2D(group);
graphics.setColor(color);
graphics.fillRect(x, y, width, height);
}
}
Take a look at this tutorial.
If you need not just to a draw a rectangle using lines, but, for example, adding a table with text cells, see examples here. Hope it helps!
Edit I'm using Eclipse ADT bundle but when I try importing the library in the suggested answer above it doesn't work.
I'm using a combination of LibGDX and Java (90-99% java) to blur an image. The blur works but it takes nearly a second to take a screenshot, save it, access it, blur it, save it, and re-access it. I can't do much pre-processing because it takes a screenshot of the game to blur. Here is what I'm using currently for blurring: (I'll put drawing and screenshots up if you need to see them, but I think the issue lies in the blurring of an 800x480 png.)
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
public class Blur {
private static BufferedImage mshi;
private BufferedImage databuf;
private static int blurRad = 300;
public static void createBlur(FileHandle file) throws IOException {
mshi = ImageIO.read(file.file());
BufferedImage databuf = new BufferedImage(mshi.getWidth(null),
mshi.getHeight(null),
BufferedImage.TYPE_INT_BGR);
java.awt.Graphics g = databuf.getGraphics();
g.drawImage(mshi, 455, 255, null);
float[] blurKernel = new float[blurRad*blurRad];
for(int i =0; i<blurRad*blurRad; i++) {
blurKernel[i] = 1.0f/256.0f;
}
BufferedImageOp op = new ConvolveOp( new Kernel(20, 20, blurKernel), ConvolveOp.EDGE_ZERO_FILL, null );
mshi = op.filter(mshi, databuf);
g.dispose();
File outputfile = Gdx.files.local("Blur.png").file();
ImageIO.write(mshi, "png", outputfile);
}
}
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();
}
Does anyone know of a good example of converting a PPTX powerpoint presentation to some form of image? PNG/GIF/etc?
I can do it for a PPT but looking for a PPTX conversion example
Thanks
In the meantime it works (... copied it from there):
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.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
public class PptToPng {
public static void main(String[] args) throws Exception {
FileInputStream is = new FileInputStream("example.pptx");
XMLSlideShow ppt = new XMLSlideShow(is);
is.close();
double zoom = 2; // magnify it by 2
AffineTransform at = new AffineTransform();
at.setToScale(zoom, zoom);
Dimension pgsize = ppt.getPageSize();
XSLFSlide[] slide = ppt.getSlides();
for (int i = 0; i < slide.length; i++) {
BufferedImage 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);
FileOutputStream out = new FileOutputStream("slide-" + (i + 1) + ".png");
javax.imageio.ImageIO.write(img, "png", out);
out.close();
}
}
}
Answering my own question, I subscribed to the development mailing list and asked this question.
The answer is that this functionailty is currently not supported by apache poi
There's an example class PPTX2PNG now bundled with POI that seems to work with decent results for the PPTX decks I've thrown at it:
http://svn.apache.org/repos/asf/poi/trunk/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
pptx4j can help you to create SVG in HTML (though there is still work to do to support all shapes); and then you could use one of the tools which create a image from an automated browser window.