Apache POI pptx to image take too much time for processing - java

I have code to convert pptx slide into image and display the image in swing panel.
When i run my code in eclipse, it takes 10 Sec to display the panel whereas same code run via jar, it takes more than one minute to open the panel.
It happens only when user open it first time, Later it loads faster.
Any help would be appreciated and thanks in advance.
Here i included the code
// currentPage - Slide number to display
// source - pptx file path
public void Display(int currentPage, String source) {
try {
FileInputStream is = new FileInputStream(source);
XMLSlideShow ppt = new XMLSlideShow(is);
is.close();
double zoom = 1; // magnify it by 2
AffineTransform at = new AffineTransform();
at.setToScale(zoom, zoom);
Dimension pgsize = ppt.getPageSize();
XSLFSlide[] slides = ppt.getSlides();
all = slides.length;
lblPage.setText(currentPage + " / " + all);
current = currentPage;
BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.transform(at);
graphics.setColor(Color.white);
graphics.clearRect(0, 0, pgsize.width, pgsize.height);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
System.out.println("Before draw: " + new Date());
slides[currentPage - 1].draw(graphics);
System.out.println("After draw: " + new Date());
// save the output
Image newImg = img.getScaledInstance(lblPresentasi.getWidth(), lblPresentasi.getHeight(), Image.SCALE_SMOOTH);
final ImageIcon icon = new ImageIcon(newImg);
lblPresentasi.setIcon(icon);
lblPresentasi.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
JLabel label = (JLabel) e.getComponent();
Dimension size = label.getSize();
Image resized = icon.getImage().getScaledInstance(size.width-10, size.height-10, Image.SCALE_FAST);
label.setIcon(new ImageIcon(resized));
}
});
graphics.dispose();
newImg.flush();
} catch (Exception e) {
e.printStackTrace();
}
}// end of method Display()

This delay was caused by One-Jar custom class loader. At first time, it takes more time to load the dependency libraries and load it classes.
So, I removed one-jar and using JarSplice to load the dependency libraries classes , it works great.

Related

Apache POI - PPTX to PNG skewing text and shapes

I'm currently using Apache POI 3.16 to take a PPTX slide deck and transform it into a set of .png thumbnails. I modeled my PPTX to PNG function closely off of a few pre-made solutions I found across the web.
I'm having issues primarily with text being rendered about 6-8pt larger in the resulting PNGs. Additionally, complex shapes such as hexagons are extremely skewed when being rendered. Can anyone suggest any fixes? I'm mostly concerned with the font sizes being much larger.
Here is my code, commented for readability:
public List<String> generatePNGThumbnails(String inputFilePath) {
// List of the thumbnail paths that will be returned.
ArrayList<String> thumbnailFilePaths = new ArrayList<>();
// Open the file.
File inputFile = new File(inputFilePath);
try {
// Open the PPTX as an XMLSlideShow.
XMLSlideShow slideShow = new XMLSlideShow(OPCPackage.open(inputFile));
// Output size for rendered images.
Dimension pageSize = slideShow.getPageSize();
int width = (int)(pageSize.width * TRANSFORMATION_SCALE);
int height = (int)(pageSize.height * TRANSFORMATION_SCALE);
// Get a list of the slides in the PPTX.
List<XSLFSlide> slides = slideShow.getSlides();
for (int i = 0; i < slides.size(); i++) {
XSLFSlide slide = slides.get(i);
// Create a new image object and prepare it for rendering.
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
// Set graphics rendering options and draw the PPTX slide to the image.
graphics.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
graphics.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY
);
graphics.setRenderingHint(
RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY
);
graphics.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC
);
graphics.setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON
);
graphics.setRenderingHint(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY
);
graphics.setColor(Color.white);
graphics.clearRect(0, 0, width, height);
graphics.scale(TRANSFORMATION_SCALE, TRANSFORMATION_SCALE);
// Draw the slide to the 2DGraphics.
slide.draw(graphics);
// Save the newly created image to the local disk.
String slideFileName = "slide" + i + ".pptx";
FileOutputStream fileOutputStream = new FileOutputStream(slideFileName);
ImageIO.write(img, "png", fileOutputStream);
// Add the output file path to the list of paths to be returned.
thumbnailFilePaths.add(slideFileName);
// Clean up before proceeding to the next slide.
graphics.dispose();
img.flush();
fileOutputStream.close();
}
} catch (InvalidFormatException | IOException e) {
// ...
}
}

Drawing BufferedImage using ImageIO.write causing image to be resized

I have this code:
public void draw(File image, int number, File destination) {
BufferedImage img = null;
try {
img = ImageIO.read(image);
//create graphic object
Graphics2D graphicImg = img.createGraphics();
//select the font
Font font = new Font("TimesRoman", Font.BOLD, 96);
graphicImg.setFont(font);
//draw the text
graphicImg.drawString(String.valueOf(number), 100, 100);
//save on disk
ImageIO.write(img, "jpg", destination);
} catch (Exception e) {
System.out.println("Error while trying to write on image!");
}
}
I pass a File (which will be an image) as first parameter, an int and a File(which will represent the destination) of the file.
The method should draw a number on this file.
The problem is that the image size of the new image will be lower than original. For example, if I give a image with 3Mb as first parameter, the saved image will have around 1.5Mb. Why the size are so different and how I can fix it?
Thank you

How to print all the swing components in a scrollable JFrame?

I'm trying to print a form which consists of swing components which are in a scrollable JFrame. I have tried the below code to do it, but the print I get is only the scrolled area currently in the window. I need to print the whole page.
Code:
public int print(Graphics arg0, PageFormat arg1, int arg2) throws PrinterException {
// TODO Auto-generated method stub
//return 0;
if (arg2 > 0) { /* We have only one page, and 'page' is zero-based */
return NO_SUCH_PAGE;
}
Graphics2D g2d = (Graphics2D)arg0;
g2d.translate((int)arg1.getImageableX(), (int)arg1.getImageableY());
float pageWidth = (float)arg1.getImageableWidth();
float pageHeight = (float)arg1.getImageableHeight();
float imageHeight = (float)this.getHeight();
float imageWidth = (float)this.getWidth();
float scaleFactor = Math.min((float)pageWidth/(float)imageWidth, (float)pageHeight/(float)imageHeight);
int scaledWidth = (int)(((float)imageWidth)*scaleFactor);
int scaledHeight = (int)(((float)imageHeight)*scaleFactor);
BufferedImage canvas = new BufferedImage( this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D gg = canvas.createGraphics();
this.paint( gg );
Image img = canvas ;
g2d.drawImage(img, 0, 0, scaledWidth, scaledHeight, null );
return Printable.PAGE_EXISTS;
}
private void button4ActionPerformed() {
// TODO add your code
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(this);
boolean ok = job.printDialog();
if (ok) {
try {
job.print();
} catch (PrinterException ex) {
System.out.println("Error printing: " + ex);
/* The job did not successfully complete */
}
}
}
Also I need to hide some buttons and textFields from printing. (eg: "Print" button)
Any help would be appreciated.
Instead of the this.paint( gg ); call componentInTheScrollPane.paint(gg);. Even better to call printAll(gg);
If you try to draw a jScrollPane to an image it will fail every time and only print the visible section. To get around this issue you need to instead draw the contents of the jScrollPane, ideally you will have a jLayer, jPanel or some other container inside the jScrollPane and can just draw that directly to an image like so:
Form (jPanel top container)
-> jScrollPane
-> jLayer/jPanel/container
-> Contents (tables, buttons etc)
I wont give you code on how to print a whole form with an entire scrollPane, that requires some math and a little more code, but to get you started here is an example method that will draw the contents of a jLayer to a buffered image regardless if it is out of view in the jScrollPane, and then save that image to file: (I wont cover printing that is another issue)
private void button4ActionPerformed() {
try
{
//get height/width from the jLayeredPane or jPanel inside the scroll pane
int imageHeight = jLayeredPane.getHeight();
int imageWidth = jLayeredPane.getWidth();
//Draw contents of the jLayeredPane or jPanel inside the scroll pane (but not the scroll pane itself)
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D gg = image.createGraphics();
jLayeredPane.paint(gg);
//The "image" now has jLayers contents
//Insert your code here to scale and print the image here
//Some Code
//In my example I have chosen to save the image to file with no scaling
ImageIO.write(canvas, "png", new File("C:\\out.png"));
//Some Code
System.out.println("Done");
}
catch (IOException ex)
{
Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
}
}

Resize a picture to fit a JLabel

I'm trying to make a picture fit a JLabel. I wish to reduce the picture dimensions to something more appropriate for my Swing JPanel.
I tried with setPreferredSize but it doesn't work.
I'm wondering if there is a simple way to do it? Should I scale the image for this purpose?
Outline
Here are the steps to follow.
Read the picture as a BufferedImage.
Resize the BufferedImage to another BufferedImage that's the size of the JLabel.
Create an ImageIcon from the resized BufferedImage.
You do not have to set the preferred size of the JLabel. Once you've scaled the image to the size you want, the JLabel will take the size of the ImageIcon.
Read the picture as a BufferedImage
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
Resize the BufferedImage
Image dimg = img.getScaledInstance(label.getWidth(), label.getHeight(),
Image.SCALE_SMOOTH);
Make sure that the label width and height are the same proportions as the original image width and height. In other words, if the picture is 600 x 900 pixels, scale to 100 X 150. Otherwise, your picture will be distorted.
Create an ImageIcon
ImageIcon imageIcon = new ImageIcon(dimg);
You can try it:
ImageIcon imageIcon = new ImageIcon(new ImageIcon("icon.png").getImage().getScaledInstance(20, 20, Image.SCALE_DEFAULT));
label.setIcon(imageIcon);
Or in one line:
label.setIcon(new ImageIcon(new ImageIcon("icon.png").getImage().getScaledInstance(20, 20, Image.SCALE_DEFAULT)));
The execution time is much more faster than File and ImageIO.
I recommend you to compare the two solutions in a loop.
public static void main(String s[])
{
BufferedImage image = null;
try
{
image = ImageIO.read(new File("your image path"));
} catch (Exception e)
{
e.printStackTrace();
}
ImageIcon imageIcon = new ImageIcon(fitimage(image, label.getWidth(), label.getHeight()));
jLabel1.setIcon(imageIcon);
}
private Image fitimage(Image img , int w , int h)
{
BufferedImage resizedimage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedimage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, 0, 0,w,h,null);
g2.dispose();
return resizedimage;
}
The best and easy way for image resize using Java Swing is:
jLabel.setIcon(new ImageIcon(new javax.swing.ImageIcon(getClass().getResource("/res/image.png")).getImage().getScaledInstance(200, 50, Image.SCALE_SMOOTH)));
For better display, identify the actual height & width of image and resize based on width/height percentage
i have done the following and it worked perfectly
try {
JFileChooser jfc = new JFileChooser();
jfc.showOpenDialog(null);
File f = jfc.getSelectedFile();
Image bi = ImageIO.read(f);
image1.setText("");
image1.setIcon(new ImageIcon(bi.getScaledInstance(int width, int width, int width)));
} catch (Exception e) {
}
Or u can do it this way. The function u put the below 6 lines will throw an IOException. And will take your JLabel as a parameter.
BufferedImage bi=new BufferedImage(label.width(),label.height(),BufferedImage.TYPE_INT_RGB);
Graphics2D g=bi.createGraphics();
Image img=ImageIO.read(new File("path of your image"));
g.drawImage(img, 0, 0, label.width(), label.height(), null);
g.dispose();
return bi;
public void selectImageAndResize(){
int returnVal = jFileChooser.showOpenDialog(this); //open jfilechooser
if (returnVal == jFileChooser.APPROVE_OPTION) { //select image
File file = jFileChooser.getSelectedFile(); //get the image
BufferedImage bi;
try {
//
//transforms selected file to buffer
//
bi=ImageIO.read(file);
ImageIcon iconimage = new ImageIcon(bi);
//
//get image dimensions
//
BufferedImage bi2 = new BufferedImage(iconimage.getIconWidth(), iconimage.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
iconimage.paintIcon(null, g, 0,0);
g.dispose();
//
//resize image according to jlabel
//
BufferedImage resizedimage=resize(bi,jLabel2.getWidth(), jLabel2.getHeight());
ImageIcon resizedicon=new ImageIcon(resizedimage);
jLabel2.setIcon(resizedicon);
} catch (Exception ex) {
System.out.println("problem accessing file"+file.getAbsolutePath());
}
}
else {
System.out.println("File access cancelled by user.");
}
}
Assign your image to a string.
Eg image
Now set icon to a fixed size label.
image.setIcon(new javax.swing.ImageIcon(image.getScaledInstance(50,50,WIDTH)));

resizing animated GIF while keeping it's animation using java

i am using Graphics2D in java to resize images, it works perfect with jpg,png and other formats.
my problem is the animated GIF images, after re-sizing the animation is gone!
here is the method am using:
private BufferedImage doResize(int newWidth, int newHeight, double scaleX,
double scaleY, BufferedImage source) {
GraphicsConfiguration gc = getDefaultConfiguration();
BufferedImage result = gc.createCompatibleImage(newWidth, newHeight, source.getColorModel().getTransparency());
Graphics2D g2d = null;
try {
g2d = result.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.scale(scaleX, scaleY);
g2d.drawImage(source, 0, 0, null);
} finally {
if (g2d != null) {
g2d.dispose();
}
}
return result;
}
so, any clues how can i keep on the animated gif after re-sizing?
Thanks.
So I know this is old but I found a solution, I am using Java 8 not sure if it will work with other versions.
ImageIcon image = ? (whatever/wherever your gif is)
int width = 100;
int height = 100;
image.setImage(image.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT));
you can change SCALE_DEFAULT to the ones listed here except for SCALE_SMOOTH and SCALE_AREA_AVREAGING didn't work for me, it was blank
https://docs.oracle.com/javase/7/docs/api/java/awt/Image.html
I found two sources which when combined can be used to resize the image while keeping the animation.
On this question (
Convert each animated GIF frame to a separate BufferedImage ) look for the answer by Alex Orzechowski. His code takes a gif file and converts it to an array of ImageFrames (which is a class he made which wraps a BufferedImage). Then look at this code which converts a sequence of BufferedImages to a gif file
( http://elliot.kroo.net/software/java/GifSequenceWriter/ ).
As you could probably guess, all you need to do is upload the gif, use Alex's code to convert it to an array of ImageFiles/BufferedImages, use your Graphics2D code to resize each frame (you'll need to add a setImage method to Alex's ImageFrame class), then use Elliot's code to convert the array to a gif! Here is what mine looks like:
public static void main( String[] args )
{
try {
File imageFile = new File( "InputFile" );
FileInputStream fiStream = new FileInputStream( imageFile );
ImageFrame[] frames = readGif( fiStream );
for( int i = 0; i < frames.length; i++ ){
//code to resize the image
BufferedImage image = ImageUtilities.resizeImage( frames[ i ].getImage(), newWidth, newHeight);
frames[ i ].setImage( image );
}
ImageOutputStream output =
new FileImageOutputStream( new File( "OutputFile" ) );
GifSequenceWriter writer =
new GifSequenceWriter( output, frames[0].getImage().getType(), frames[0].getDelay(), true );
writer.writeToSequence( frames[0].getImage() );
for ( int i = 1; i < frames.length; i++ ) {
BufferedImage nextImage = frames[i].getImage();
writer.writeToSequence( nextImage );
}
writer.close();
output.close();
}
catch ( FileNotFoundException e ) {
System.out.println( "File not found" );
}
catch ( IOException e ) {
System.out.println( "IO Exception" );
}
}
This code, however, does not account for gif images with different amount of time elapsing between frames.
Jonny March's solution did not work for me because it processes and outputs only the first image of GIF file.
Here is my solution, it keeps the animation while resizing.
File f = new File("path of your animated gif");
URL img = f.toURL();
ImageIcon icon = new ImageIcon(img);
//You have to convert it to URL because ImageIO just ruins the animation
int width = 100;
int height = 100;
icon.setImage(icon.getImage().getScaledInstance(width, height,Image.SCALE_DEFAULT));
BufferedImage origBuffImg = ImageIO.read(orignalImage);
int type = origBuffImg.getType() == 0? BufferedImage.TYPE_INT_ARGB : origBuffImg.getType();
BufferedImage resizedBuffImg = new BufferedImage(width, height, type);
Graphics2D g = resizedBuffImg.createGraphics();
g.drawImage(origBuffImg, 0, 0, width, height, null);
g.dispose();
String newFile = orignalImage.getAbsolutePath().substring(0,orignalImage.getAbsolutePath().lastIndexOf("."))+"_"+width+"x"+height+"."+extension;
ImageIO.write(resizedBuffImg, extension, new File(newFile));
System.out.println("File created : "+newFile);

Categories