Solved

Java resize image to fit JPanel

Posted on 2007-11-27
9
10,608 Views
Last Modified: 2008-02-01
Hi there,

I'm playing about with Java and I'm trying to create a JPanel that displays a given image.  This image should resize as the panel changes size while maintaining the aspect ratio of the image.

Currently I have the given code for the JPanel.  An instance of this is created and displayed within a JFrame but when I resize the frame the image does not correctly scale to take up the width/height of the panell.  I think that I may have something wrong with getting the scale but I'm a little stuck.

Any help would be appreciated.

Also - does the scaling of the buffered image change the size of the image in the actual memory?  Maybe doesn't make sense but should I copy the buffered image, as shown in code, and resize the copy.  My thinking is that if it is scaled down to 10px by 10px then a rescale to 100px by 100px will have really poor quality - unless i reload the original.

Thanks.
public class ImagePanel 

extends JPanel

{

    private String m_ImageFile;             // the path and name of the image file to be displayed

    private BufferedImage m_Image;          // instance of the image to be displayed

    private BufferedImage m_ScaledImage;    // scaled instance of the image to be displayed

    

    /** Creates a new instance of ImagePanel */

    public ImagePanel(String imageFile) {

        if (imageFile == null) throw new NullPointerException("Image file should not be a null value.");

        this.m_ImageFile = imageFile;

        

        InitComponents();

    }

    

    /** Initialise the class components */

    private void InitComponents() {

        // try to load the image file

        try {

            m_Image = ImageIO.read(new File(m_ImageFile));

        } catch (IOException ex) {

            ex.printStackTrace();

        }

    }
 

    /** Calculate the scale required to correctly fit the image into panel */

    private double GetScale(int panelWidth, int panelHeight, int imageWidth, int imageHeight) {

        double scale = 1;

        double xScale;

        double yScale;

        

        if (imageWidth > panelWidth || imageHeight > panelHeight) {

            xScale = (double)imageWidth  / panelWidth;

            yScale = (double)imageHeight / panelHeight;

            scale = Math.min(xScale, yScale);

        }

        else if (imageWidth < panelWidth && imageHeight < panelHeight) {

            xScale = (double)panelWidth / imageWidth;

            yScale = (double)panelHeight / imageHeight;

            scale = Math.min(xScale, yScale);

        }

        else {

            scale = 1;

        }
 

        return scale;

    }

    

    /** Override paint method of the panel */

    public void paint(Graphics g) {

        if( m_Image != null) {

            super.paintComponent(g);
 

            Graphics2D g2 = (Graphics2D)g;

            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 

            m_ScaledImage = m_Image;

            

            // Get the required sizes for display and calculations

            int panelWidth = this.getWidth();

            int panelHeight = this.getHeight();

            int imageWidth = m_ScaledImage.getWidth();

            int imageHeight = m_ScaledImage.getHeight();

            

            double scale = GetScale(panelWidth, panelHeight, imageWidth, imageHeight);

            

            /**

            System.out.println("---------------------------------------");

            System.out.println("Panel: "+this.getName()+".");

            System.out.println("Size: "+panelWidth+", "+panelHeight+".");

            System.out.println("Image size: "+m_ScaledImage.getWidth()+", "+m_ScaledImage.getHeight()+".");

            System.out.println("Scale: "+scale+".");

             **/

            

            // Calculate the center position of the panel -- with scale

            double xPos = (panelWidth - scale * imageWidth)/2;

            double yPos = (panelHeight - scale * imageHeight)/2;
 

            // Locate, scale and draw image

            AffineTransform at = AffineTransform.getTranslateInstance(xPos, yPos);

            at.scale(scale, scale);

            g2.drawRenderedImage(m_ScaledImage, at);

        }

    }    

}

Open in new window

0
Comment
Question by:VanLouin
  • 3
  • 2
  • 2
  • +1
9 Comments
 
LVL 24

Expert Comment

by:sciuriware
ID: 20358255
If you know the dimensions of the JPanel you can easily resize the picture before display:

   /**
    * Resizes an Image by stretching it to a new size by x factor and y factor.
    *
    * @param picture the initial image.
    * @param xFactor the width stretching factor.
    * @param yFactor the height stretching factor.
    * @return the stretched image.
    */
   public static Image resize(Image picture, double xFactor, double yFactor)
   {
      BufferedImage buffer;
      Graphics2D g;
      AffineTransform transformer;
      AffineTransformOp operation;

      buffer = new BufferedImage
      (
         picture.getWidth(null),
         picture.getHeight(null),
         BufferedImage.TYPE_INT_ARGB
      );
      g = buffer.createGraphics();
      g.drawImage(picture, 0, 0, null);
      transformer = new AffineTransform();
      transformer.scale(xFactor, yFactor);
      operation = new AffineTransformOp(transformer, AffineTransformOp.TYPE_BILINEAR);
      buffer = operation.filter(buffer, null);
      return(Toolkit.getDefaultToolkit().createImage(buffer.getSource()));
   }

;JOOP!
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 20358257
And don't forget some imports:

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;

;JOOP!
0
 

Author Comment

by:VanLouin
ID: 20358311
Currently the image is being resized but it doesn't appear to be acting like I expect it to.

I want the image to stretch to be the same size as one of the panels axis while maintaining the aspect ratio.  The size of the panel is obtained by this.getWidth() and this.getHeight()  - I considered that there may be a problem here due to the panel being resized as I drag the parent JFrame size.  No idea how to check this or other ways to approach it though.

I'm thinking that the problem is either with my GetScale method having wonky logic or it's to do with getting the size of the panel.

Thanks.
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 20358421
If you change the frame size: monitor it with a listener on the frame itself:

see Interface ComponentListener
and its method: componentResized()

;JOOP!
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 92

Accepted Solution

by:
objects earned 500 total points
ID: 20361418
should be able to adapt this:

http://www.objects.com.au/java/qa/1959359983.html

just need to change it to retain aspect ratio
0
 

Author Comment

by:VanLouin
ID: 20364261
Some further investigation and help from the Sun forum has highlighted that I should be overriding the paintComponent() method and not the paint() method for custom painting.  I've no idea why but seemingly I was all wrong on this - maybe something for me to read up on!

The way I was calculation the scaling based on the panel size was also wrong.  An adjustment to the scaling method fixed this so I've attached the code for anyone that wants it.

Thanks anyway guys.
public class ImagePanel 

extends JPanel

{

    private String m_ImageFile;             // the path and name of the image file to be displayed

    private BufferedImage m_Image;          // instance of the image to be displayed

    private BufferedImage m_ScaledImage;    // scaled instance of the image to be displayed

    

    /** Creates a new instance of ImagePanel */

    public ImagePanel(String imageFile) {

        if (imageFile == null) throw new NullPointerException("Image file should not be a null value.");

        this.m_ImageFile = imageFile;

        

        InitComponents();

    }

    

    /** Initialise the class components */

    private void InitComponents() {

        // try to load the image file

        try {

            m_Image = ImageIO.read(new File(m_ImageFile));

        } catch (IOException ex) {

            ex.printStackTrace();

        }

    }
 

    /** Calculate the scale required to correctly fit the image into panel */

     private double GetScale(int panelWidth, int panelHeight, int imageWidth, int imageHeight) {

        double scale = 1;

        double xScale;

        double yScale;

 

        // should check that denom != 0 first.

        xScale = (double) panelWidth / imageWidth;

        yScale = (double) panelHeight / imageHeight;

        scale = Math.min(xScale, yScale);

        return scale;

    }

    

    /** Override paint method of the panel */

    public void paintComponent(Graphics g) {

        if( m_Image != null) {

            super.paintComponent(g);
 

            Graphics2D g2 = (Graphics2D)g;

            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 

            // Grab a copy of the original image for scaling

            m_ScaledImage = m_Image;

            

            // Get the required sizes for display and calculations

            int panelWidth = this.getWidth();

            int panelHeight = this.getHeight();

            int imageWidth = m_ScaledImage.getWidth();

            int imageHeight = m_ScaledImage.getHeight();

            

            // Get the scale that the image should be resized with

            double scale = GetScale(panelWidth, panelHeight, imageWidth, imageHeight);

                     

            // Calculate the center position of the panel -- with scale

            double xPos = (panelWidth - (scale * imageWidth))/2;

            double yPos = (panelHeight - (scale * imageHeight))/2;
 

            // Locate, scale and draw image

            AffineTransform at = AffineTransform.getTranslateInstance(xPos, yPos);

            at.scale(scale, scale);

            g2.drawRenderedImage(m_ScaledImage, at);

        }

    }    

}

Open in new window

0
 
LVL 92

Expert Comment

by:objects
ID: 20364573
that can be simplified a bit, see the code i posted in my earlier comment
0
 
LVL 1

Expert Comment

by:Vee_Mod
ID: 20390963
Force accepted.
Vee_Mod
Community Support Moderator
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
This video teaches viewers about errors in exception handling.

895 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now