Page 1 of 1

Java Image Manipulation – Part 2: Resizing Rate Topic: -----

#1 Dogstopper  Icon User is offline

  • The Ninjaducky
  • member icon



Reputation: 2874
  • View blog
  • Posts: 11,032
  • Joined: 15-July 08

Posted 18 March 2010 - 10:50 AM

Java Image Manipulation – Part 2
~ Dogstopper

In the first tutorial in my series, I showed you how to load images as ImageIcons and BufferedImages. In this tutorial, I'm going to show you several ways to resize images that are far too large to images that are easier to use. (In my sample today, we will use this image: http://antwrp.gsfc.n..._carruthers.jpg )

As you can see, it's much larger than many modern day screens. However, you really like it and want to use it as the background to your game (which, say is 800x600). If you paint it the way that I showed you in my last tutorial, you'll only see the top-left corner of the image and the rest of it is pushed offscreen. What you need to do is to scale that image, something that I am about to show you how to do. There are two ways that I will show you, using the Graphics object, and using the Image object:

Resize To Fit Screen
The following methods that I will show you will make that huge image fit completely into the PicturePanel (the class that we developed last tutorial). This time, we will not scale it to have the same dimensions. For now, we will worry about just making it fit (which is what we want in some cases). Let's show you the method using the Graphics Object first.
boolean Graphics.drawImage(Image img,
                           int dstx1, int dsty1, int dstx2, int dsty2,
                           int srcx1, int srcy1, int srcx2, int srcy2,
                           ImageObserver observer)



That's how the method appears in the API, and not very well explained. Let's let me explain it now. The Image img parameter is the image that you wish to draw to the screen.
Now the next 4 ints are the top-left and bottom-right corners of the destination (the scaled destination). dstx1 and dsty1 describe the top-right corner, dstx2 and dsty2 describe the bottom-right corner of the destination.

Next, the other 4 ints describe the part of the image that we want to use. In our image manipulation this tutorial, we want to always use the same full image, not a part of it.
Finally, the ImageObserver is a class that “helps” the image, but with BufferedImage, I've never needed it.

So, now to make that huge image fit the screen! I'm just going to make a new PicturePanel and hope that by reading my first tutorial, you know how to use it in a JFrame.
	private class PicturePanel extends JPanel {
		
		BufferedImage img;
		
		public PicturePanel() {
			// Load the image 
			img = getImage("http://antwrp.gsfc.nasa.gov/apod/image/1003/centaurusA_carruthers.jpg");
			
			// Make the panel as big as the image is.
			this.setPreferredSize(new Dimension(800, 600));
		}
		
		public void paintComponent(Graphics g) {
			g.drawImage(img, 0,0,getWidth(),getHeight(),0,0,img.getWidth(),img.getHeight(), null);
		}
		
		private BufferedImage getImage(String filename) {
			// This time, you can use an InputStream to load
			try {
				// Grab the URL for the image
				URL url = new URL(filename);
				
				// Then read it in.
				return ImageIO.read(url);
			} catch (IOException e) {
				System.out.println("The image was not loaded.");
				System.exit(1);
			}
			return null;
		}
	}




So, you see this line?
g.drawImage(img, 0, 0, getWidth(), getHeight(), 0, 0, img.getWidth(), img.getHeight(), null);



The img argument is the image that we want to draw, the next four arguments state that the destination rectangle is from the coordinates (0,0) at the top-left corner to the bottom corner (getWidth(), getHeight()). That allows the image to resize as you change the page. The next four arguments state that we want to use the whole image, from the image's origin (0,0) to the image's end (img.getWidth(), img.getHeight()). The final argument is the ImageObserver that we don't need.

However, we don't always have to change the graphics painting; sometimes we can actually change the image and then print out normally. This requires the use of Image.getScaledInstance(). The API defines it like so:
public Image getScaledInstance(int width,
                               int height,
                               int hints)


Where width and height are the new width and new height and hints is one of these:
Image.SCALE_DEFAULT,
Image.SCALE_FAST,
Image.SCALE_SMOOTH,
Image.SCALE_REPLICATE,
Image.SCALE_AREA_AVERAGING

Usually, You will just use Image.SCALE_DEFAULT.

So, to do the same thing as above, but by changing the image instead you'd use this:
	private class PicturePanel extends JPanel {
		
		BufferedImage img;
		
		public PicturePanel() {
			// Load the image 
			img = getImage("http://antwrp.gsfc.nasa.gov/apod/image/1003/centaurusA_carruthers.jpg");
			
			// Make the panel as big as the image is.
			this.setPreferredSize(new Dimension(800, 600));
		}
		
		public void paintComponent(Graphics g) {
			Image scaledImage = img.getScaledInstance(getWidth(), getHeight(),
					Image.SCALE_DEFAULT);
			g.drawImage(scaledImage, 0, 0, null);
		}
		
		private BufferedImage getImage(String filename) {
			// This time, you can use an InputStream to load
			try {
				// Grab the URL for the image
				URL url = new URL(filename);
				
				// Then read it in.
				return ImageIO.read(url);
			} catch (IOException e) {
				System.out.println("The image was not loaded.");
				System.exit(1);
			}
			return null;
		}
	}



Note that this operation is extremely slow memory-wise and if used at all should probably be implemented as a window listener and only rescaled when the screen is resized.

Scale Image To Fit Screen
Now, I'm going to demonstrate how to actually scale an image instead of changing it's width AND height. Most commonly, the image is only resized when the height is increased and the width is scaled down based on the height. It merely requires a simple ratio. Let me show you using the Graphics object.

	private class PicturePanel extends JPanel {
		
		BufferedImage img;
		
		public PicturePanel() {
			// Load the image 
			img = getImage("http://antwrp.gsfc.nasa.gov/apod/image/1003/centaurusA_carruthers.jpg");
			
			// Make the panel as big as the image is.
			this.setPreferredSize(new Dimension(900, 600));
		}
		
		public void paintComponent(Graphics g) {
			// Get the ratio
			double ratio = (double)img.getWidth()/img.getHeight();
			
			// Multiply it by the height because it resizes vertically.
			int scaledWidth = (int)(ratio * getHeight());
			g.drawImage(img, 0,0,scaledWidth,getHeight(),0,0,img.getWidth(),img.getHeight(), null);
		}
		
		private BufferedImage getImage(String filename) {
			// This time, you can use an InputStream to load
			try {
				// Grab the URL for the image
				URL url = new URL(filename);
				
				// Then read it in.
				return ImageIO.read(url);
			} catch (IOException e) {
				System.out.println("The image was not loaded.");
				System.exit(1);
			}
			return null;
		}
	}



Again, you can do this with the Image.getScaledInstane(). Passing it a width or height of 0 will result in an error, but passing it a negative value will make it scale. Since you want it to resize vertically, you'd base it on the height again.
img.getScaledInstance(-1, getHeight(), Image.SCALE_DEFAULT);



Both methods work and usually the Graphics object makes it easier for normal task, however, sometimes you may find yourself using the getScaledInstance() method such as Centering things on the screen. It frees up the graphics object to paint the image in different manner and so forth.

See my snippet on centering an image in the center of the screen:
http://www.dreaminco...snippet5174.htm

Stay tuned for more tutorials on image manipulation.

Is This A Good Question/Topic? 1
  • +

Replies To: Java Image Manipulation – Part 2: Resizing

#2 Dogstopper  Icon User is offline

  • The Ninjaducky
  • member icon



Reputation: 2874
  • View blog
  • Posts: 11,032
  • Joined: 15-July 08

Posted 18 March 2010 - 09:57 PM

I forgot to mention that there is a super fast way to center an image not using the method described in my snippet. My snippet actually, because it directly manipulates the image, is not as fast as using the Graphics object.

Notice how I set the destination rectangle to the center.
		public void paintComponent(Graphics g) {
			// Get the ratio
			double ratio = (double)img.getWidth()/img.getHeight();
			
			// Multiply it by the height because it resizes vertically.
			int scaledWidth = (int)(ratio * getHeight());

			// Center the left and right destination x coordinates.
			int leftOffset = getWidth()/2 - scaledWidth/2;
			int rightOffset = getWidth()/2 + scaledWidth/2;
			
			g.drawImage(img, 
					leftOffset, 0, rightOffset, getHeight(), 
					0, 0, img.getWidth(), img.getHeight(), 
					null);

		}


Was This Post Helpful? 0
  • +
  • -

#3 NeoTifa  Icon User is online

  • Whorediot
  • member icon





Reputation: 2699
  • View blog
  • Posts: 15,738
  • Joined: 24-September 08

Posted 10 August 2010 - 09:44 AM

I have a comment about your comment. :P

Quote

09         // Make the panel as big as the image is.  
10         this.setPreferredSize(new Dimension(900, 600));  



I think this is maybe copy pasta, but you're driving hard numbers, and it's still saying that in the comments. Just thought I'd point that out.
Was This Post Helpful? 0
  • +
  • -

#4 RascalRobot  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 9
  • Joined: 03-August 10

Posted 10 August 2010 - 01:02 PM

View PostDogstopper, on 18 March 2010 - 09:50 AM, said:

dstx1 and dsty1 describe the top-right corner, dstx2 and dsty2 describe the bottom-right corner of the destination.


Just a typo I noticed, dstx1 and dsty1 describe the top-left corner.

Great articles, they are extremely helpful. I'm looking forward to more of them.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1