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);
}
}
Related
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.
I have a JPanel object called drawPanel. I draw various things like rectangles on it and when I try to create a bufferedimage and save it as following, it only saves a blank image with just the background color and not the rectangles drawn onto the frame.
BufferedImage image = createImage(drawPanel);
File outputfile = new File("MyImage.jpg");
try {
ImageIO.write(image, "jpg", outputfile);
} catch (IOException e) {
e.printStackTrace();
}
public BufferedImage createImage(JPanel panel) {
int w = panel.getWidth();
int h = panel.getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
panel.print(g);
return bi;
}
Kindly help me fix this problem.
This Graphics2D g2 = (Graphics2D) drawPanel.getGraphics(); is your problem. Calling print, printAll or paint will wipe clean anything that was painted to the component using getGraphics.
The short answer is, never use it. The long answer is, create a custom component, that extends from something like JPanel and override it's paintComponent method and perform ALL your custom painting within in it, when it's called.
See Painting in AWT and Swing and Performing Custom Painting for more details
A little hackery with Robot
Simply replace your method createImage with my one. :-)
public BufferedImage createImage(JPanel panel) {
//Get top-left coordinate of drawPanel w.r.t screen
Point p = new Point(0, 0);
SwingUtilities.convertPointToScreen(p, panel);
//Get the region with wiht and heighht of panel and
// starting coordinates of p.x and p.y
Rectangle region = panel.getBounds();
region.x = p.x;
region.y = p.y;
//Get screen capture over the area of region
BufferedImage bi = null;
try {
bi = new Robot().createScreenCapture( region );
} catch (AWTException ex) {
Logger.getLogger(MyPaintBrush.class.getName()).log(Level.SEVERE, null, ex);
}
return bi;
}
(Credit to this dude)
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)));
I am writing a code to make an image file of a chart appearing on a panel. For that purpose I create the buffered image of that and then use ImageIO.write(). It works but it only displays the panel(grey coloured panel) but does not show the chart present on that panel. What to do in this case?? Here is my code
com.objectplanet.chart.NonFlickerPanel p =
new com.objectplanet.chart.NonFlickerPanel(new BorderLayout());
p.add("Center", chart); // this statements adds the chart in the center of the panel
ChartPanel.add("Center", p);
ChartPanel.setSize(500, 200);
ChartPanel.show();
int w = ChartPanel.getWidth();
int h = ChartPanel.getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
ChartPanel.paint(g);
ChartPanel.printAll(g);
File f = new File("D:\\image.png");
try {
// png is an image format (like gif or jpg)
ImageIO.write(bi, "png", f);
} catch (IOException ex) {
ex.printStackTrace();
}
Well i solved the problem .Anyone facing the same problem ,here is the solution
Use paintall function rather than just paint function
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);