Reputation: 41
I'm trying scale an image so it will always fit my JPanel. Unfortunately using this method I don't always receive an Image I wanted to receive. Mostly it is zoomed and I would rather have the whole image but scaled.
Thats the class that creates the image. 600 is the PanelWidth and 400 is the PanelHeight.
Any ideas what goes wrong?
public class Image extends Component{
private BufferedImage img;
protected int width;
protected int height;
private String path;
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
double scale = getScale(600,400,img.getWidth(),img.getHeight());
double xPos = (600 - scale * img.getWidth())/2;
double yPos = (400 - scale *img.getHeight())/2;
AffineTransform at = AffineTransform.getTranslateInstance(xPos, yPos);
at.scale(scale, scale);
g2.drawRenderedImage(img, at);
System.out.println(scale);
}
public Image(String path){
try{
img = ImageIO.read(new File(path));
} catch (IOException e) { }
this.width=img.getWidth();
this.height=img.getHeight();
this.path = path;
}
public double getScale(int panelWidth, int panelHeight, int imageWidth, int imageHeight){
double scale = 1;
double xScale, yScale;
if(imageWidth > panelWidth || imageHeight > panelHeight){
xScale = (double)imageWidth/panelWidth;
yScale = (double)imageHeight/panelHeight;
scale = Math.max(xScale, yScale);
}else if(imageWidth < panelWidth && imageHeight < panelHeight){
xScale = (double)panelWidth/imageWidth;
yScale = (double)panelHeight/imageHeight;
scale = Math.max(xScale, yScale);
}else{
scale = 1;
}
return scale;
}
Upvotes: 2
Views: 330
Reputation: 324088
A JPanel is a Swing component which implies you are using Swing.
For custom painting you should extend JPanel
or JComponent
. Most people use JPanel because it will clear the background of the component for you.
Custom painting of a Swing component is done by overriding paintComponent(...)
so it will always fit my JPanel
Define "fit"?
Assuming you are trying to scale the image to retain its original proportions you could to something like:
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
double imageWidth = image.getWidth(null);
double imageHeight = image.getHeight(null);
double factor = Math.min(getWidth() / imageWidth, getHeight() / imageHeight);
int width = (int)(image.getWidth(null) * factor);
int height = (int)(image.getHeight(null) * factor);
g.drawImage(image, 0, 0, width, height, this);
}
If you are just trying to fit the image on the panel then you do:
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
Upvotes: 2
Reputation: 86754
You don't need to use float if you do your operations in the right order. Assuming imageWidth
, imageHeight
, panelWidth
are all int
:
// Calculate the width of the scaled image; if the image is wider than the
// panel, use the panel width, otherwise use the image width (i.e. don't upscale)
int scaledWidth = Math.min(imageWidth, panelWidth);
// Given the scaled width, calculate the scaled height
// Force it to be at least 1 pixel, since if you have an image that's wider than
// the panel and only 1 pixel tall, this will scale to zero height, which you
// don't want
int scaledHeight = Math.max(1, imageHeight * scaledWidth / imageWidth);
The above assumes you want to fit the width and will be providing a scrolling mechanism if the image height exceeds the panel height. If you want to fit height instead (and horizontal scroll for overflow) just make the necessary changes in variables.
Upvotes: 1