How to draw image with automatic scaling in Java
- Details
- Written by Nam Ha Minh
- Last Updated on 10 August 2019   |   Print Email
In this article, we show you how to draw an image in a parent container in a way that scales the image automatically to fit the container’s canvas every time the container’s size gets changed. For example: we draw an image inside a JFramewindow. When the frame is resized, the image is re-scaled automatically to fit the frame’s new size. In other words, the whole picture always gets displayed regardless of the canvas size, while maintaining the image aspect ratio. This would be useful for applications that display images of different (or unknown) sizes, e.g. images provided by the user.
Here’s source code of a utility class for drawing an image in the way mentioned above:
package net.codejava.graphics; import java.awt.Component; import java.awt.Graphics; import java.awt.Image; /** * This utility class draws and scales an image to fit canvas of a component. * if the image is smaller than the canvas, it is kept as it is. * * @author www.codejava.net * */ public class ImageDrawer { public static void drawScaledImage(Image image, Component canvas, Graphics g) { int imgWidth = image.getWidth(null); int imgHeight = image.getHeight(null); double imgAspect = (double) imgHeight / imgWidth; int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); double canvasAspect = (double) canvasHeight / canvasWidth; int x1 = 0; // top left X position int y1 = 0; // top left Y position int x2 = 0; // bottom right X position int y2 = 0; // bottom right Y position if (imgWidth < canvasWidth && imgHeight < canvasHeight) { // the image is smaller than the canvas x1 = (canvasWidth - imgWidth) / 2; y1 = (canvasHeight - imgHeight) / 2; x2 = imgWidth + x1; y2 = imgHeight + y1; } else { if (canvasAspect > imgAspect) { y1 = canvasHeight; // keep image aspect ratio canvasHeight = (int) (canvasWidth * imgAspect); y1 = (y1 - canvasHeight) / 2; } else { x1 = canvasWidth; // keep image aspect ratio canvasWidth = (int) (canvasHeight / imgAspect); x1 = (x1 - canvasWidth) / 2; } x2 = canvasWidth + x1; y2 = canvasHeight + y1; } g.drawImage(image, x1, y1, x2, y2, 0, 0, imgWidth, imgHeight, null); } }
The drawScaledImage() is designed to be generic so it can be reused easily. To understand how this method works, let’s take a look at the following pictures:
- When the image is smaller than the canvas:
- When the canvas aspect ratio is greater than the image aspect ratio:
- When the image aspect ratio is greater than the canvas aspect ratio:
Note that the scaled image always has the same aspect ratio as the original one.
In Java, it’s very often that we use a JLabel component to display an image via its setIcon() method. So the following class extends the JLabel component in order to use the utility class above:
package net.codejava.graphics; import java.awt.Graphics; import javax.swing.ImageIcon; import javax.swing.JLabel; /** * This is an extended version of a JLabel which draws its icon image using * the ImageDrawer utility. * * @author www.codejava.net * */ public class ScaledImageLabel extends JLabel { protected void paintComponent(Graphics g) { ImageIcon icon = (ImageIcon) getIcon(); if (icon != null) { ImageDrawer.drawScaledImage(icon.getImage(), this, g); } } }
Note that this class overrides its super’s paintComponent() method to re-draw the image icon.
And following is a demo program which is a JFrame window that allows the user to enter file path of an image then display it using the ScaledImageLabel class above:
package net.codejava.graphics; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.SwingUtilities; /** * This is a test program that draws an image provided by the user and scales * the image to fit its parent container (a JLabel). * * @author www.codejava.net * */ public class ImageFrameDemo extends JFrame implements ActionListener { private JLabel labelImgFilePath = new JLabel("Enter Image File Path: "); private JTextField fieldImgFilePath = new JTextField(20); private JButton buttonDisplay = new JButton("Display"); private JLabel labelImage = new ScaledImageLabel(); public ImageFrameDemo() { super("Image Frame Demo"); setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.insets = new Insets(10, 10, 10, 10); constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.NORTHWEST; constraints.gridy = 0; constraints.gridx = 0; add(labelImgFilePath, constraints); constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weightx = 1.0; constraints.gridx = 1; add(fieldImgFilePath, constraints); constraints.gridx = 2; constraints.fill = GridBagConstraints.NONE; constraints.weightx = 0.0; add(buttonDisplay, constraints); constraints.fill = GridBagConstraints.BOTH; constraints.weightx = 1.0; constraints.weighty = 1.0; constraints.gridy = 1; constraints.gridx = 0; constraints.gridwidth = 3; labelImage.setPreferredSize(new Dimension(400, 300)); add(labelImage, constraints); buttonDisplay.addActionListener(this); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setLocationRelativeTo(null); } @Override public void actionPerformed(ActionEvent event) { String filePath = fieldImgFilePath.getText(); try { Image image = ImageIO.read(new File(filePath)); labelImage.setIcon(new ImageIcon(image)); } catch (Exception ex) { System.err.println(ex); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new ImageFrameDemo().setVisible(true); } }); } }
Here are some sample outputs when running this program:
- When the image is small enough to be displayed entirely inside the frame:
- When the image is quite big:
Try to resize the frame window, and we will see the image is scaled accordingly.
Other Java Graphics Tutorials:
- How to add watermark for images using Java
- How to resize images using Java
- How to convert image format using Java
- How to capture screenshot programmatically in Java
- How to draw text vertically with Java Graphics2D
- How to Create Zoomable User Interface Java Programs with Piccolo2D Framework
- Drawing lines examples with Java Graphics2D
- Drawing Rectangles Examples with Java Graphics2D
- Using JFreechart to draw line chart with CategoryDataset
- Using JFreechart to draw XY line chart with XYDataset
Comments