Created
June 9, 2022 00:59
-
-
Save RustyKnight/03d7ee521803359a7653dedfef372ef7 to your computer and use it in GitHub Desktop.
Example of a scalable background image in Swing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Dimension; | |
import java.awt.EventQueue; | |
import java.awt.Graphics; | |
import java.awt.Graphics2D; | |
import java.awt.RenderingHints; | |
import java.awt.Transparency; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.awt.event.ComponentAdapter; | |
import java.awt.event.ComponentEvent; | |
import java.awt.image.BufferedImage; | |
import java.io.IOException; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
import javax.imageio.ImageIO; | |
import javax.swing.JFrame; | |
import javax.swing.JPanel; | |
import javax.swing.Timer; | |
public class ScalableBackground { | |
public static void main(String[] args) { | |
new ScalableBackground(); | |
} | |
public ScalableBackground() { | |
EventQueue.invokeLater(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
BufferedImage img = ImageIO.read(getClass().getResource("/images/Mando01.jpeg")); | |
JFrame frame = new JFrame(); | |
frame.add(new BackgroundPane(img)); | |
frame.pack(); | |
frame.setLocationRelativeTo(null); | |
frame.setVisible(true); | |
} catch (IOException ex) { | |
Logger.getLogger(ScalableBackground.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
}); | |
} | |
public class BackgroundPane extends JPanel { | |
private BufferedImage masterImage; | |
private BufferedImage scaledImage; | |
private Timer debounce; | |
public BackgroundPane(BufferedImage image) { | |
masterImage = image; | |
scaledImage = masterImage; | |
debounce = new Timer(500, new ActionListener() { | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
scaleBackgroundToFit(); | |
} | |
}); | |
debounce.setRepeats(false); | |
addComponentListener(new ComponentAdapter() { | |
@Override | |
public void componentResized(ComponentEvent e) { | |
debounce.start(); | |
} | |
}); | |
} | |
@Override | |
public Dimension getPreferredSize() { | |
BufferedImage image = scaledImage == null ? masterImage : scaledImage; | |
if (image != null) { | |
return new Dimension(image.getWidth(), image.getHeight()); | |
} | |
return super.getPreferredSize(); | |
} | |
protected void scaleBackgroundToFit() { | |
scaledImage = ImageUtil.getScaledInstanceToFill(masterImage, getSize()); | |
repaint(); | |
} | |
@Override | |
protected void paintComponent(Graphics g) { | |
super.paintComponent(g); | |
if (scaledImage != null) { | |
int xPos = (getWidth() - scaledImage.getWidth()) / 2; | |
int yPos = (getHeight() - scaledImage.getHeight()) / 2; | |
g.drawImage(scaledImage, xPos, yPos, this); | |
} | |
} | |
} | |
public class ImageUtil { | |
public static BufferedImage getScaledInstanceToFit(BufferedImage source, Dimension destination) { | |
Dimension original = new Dimension(source.getWidth(), source.getHeight()); | |
double scaleFactor = getScaleFactorToFit(original, destination); | |
return getScaledInstance(source, scaleFactor); | |
} | |
public static BufferedImage getScaledInstanceToFill(BufferedImage source, Dimension destination) { | |
Dimension original = new Dimension(source.getWidth(), source.getHeight()); | |
double scaleFactor = getScaleFactorToFill(original, destination); | |
return getScaledInstance(source, scaleFactor); | |
} | |
// | |
// protected static Dimension getSizeToFit(Dimension original, Dimension toFit) { | |
// double factor = getScaleFactorToFit(original, toFit); | |
// Dimension size = new Dimension(original); | |
// size.width *= factor; | |
// size.height *= factor; | |
// return size; | |
// } | |
// | |
// protected static Dimension getSizeToFill(Dimension original, Dimension toFit) { | |
// double factor = getScaleFactorToFill(original, toFit); | |
// Dimension size = new Dimension(original); | |
// size.width *= factor; | |
// size.height *= factor; | |
// return size; | |
// } | |
protected static double getScaleFactor(int iMasterSize, int iTargetSize) { | |
return (double) iTargetSize / (double) iMasterSize; | |
} | |
protected static double getScaleFactorToFit(Dimension original, Dimension toFit) { | |
double dScale = 1d; | |
if (original != null && toFit != null) { | |
double dScaleWidth = getScaleFactor(original.width, toFit.width); | |
double dScaleHeight = getScaleFactor(original.height, toFit.height); | |
dScale = Math.min(dScaleHeight, dScaleWidth); | |
} | |
return dScale; | |
} | |
protected static double getScaleFactorToFill(Dimension masterSize, Dimension targetSize) { | |
double dScaleWidth = getScaleFactor(masterSize.width, targetSize.width); | |
double dScaleHeight = getScaleFactor(masterSize.height, targetSize.height); | |
return Math.max(dScaleHeight, dScaleWidth); | |
} | |
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) { | |
BufferedImage imgScale = img; | |
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor); | |
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor); | |
if (dScaleFactor <= 1.0d) { | |
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight); | |
} else { | |
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight); | |
} | |
return imgScale; | |
} | |
protected static void applyQualityRenderingHints(Graphics2D g2d) { | |
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); | |
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); | |
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); | |
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); | |
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); | |
} | |
protected static BufferedImage getScaledDownInstance(BufferedImage img, | |
int targetWidth, | |
int targetHeight) { | |
int type = (img.getTransparency() == Transparency.OPAQUE) | |
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; | |
BufferedImage ret = (BufferedImage) img; | |
if (targetHeight > 0 || targetWidth > 0) { | |
// Use multi-step technique: start with original size, then | |
// scale down in multiple passes with drawImage() | |
// until the target size is reached | |
int w = img.getWidth(); | |
int h = img.getHeight(); | |
do { | |
if (w > targetWidth) { | |
w /= 2; | |
if (w < targetWidth) { | |
w = targetWidth; | |
} | |
} | |
if (h > targetHeight) { | |
h /= 2; | |
if (h < targetHeight) { | |
h = targetHeight; | |
} | |
} | |
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type); | |
Graphics2D g2 = tmp.createGraphics(); | |
applyQualityRenderingHints(g2); | |
g2.drawImage(ret, 0, 0, w, h, null); | |
g2.dispose(); | |
ret = tmp; | |
} while (w != targetWidth || h != targetHeight); | |
} else { | |
ret = new BufferedImage(1, 1, type); | |
} | |
return ret; | |
} | |
protected static BufferedImage getScaledUpInstance(BufferedImage img, | |
int targetWidth, | |
int targetHeight) { | |
int type = BufferedImage.TYPE_INT_ARGB; | |
BufferedImage ret = (BufferedImage) img; | |
int w = img.getWidth(); | |
int h = img.getHeight(); | |
do { | |
if (w < targetWidth) { | |
w *= 2; | |
if (w > targetWidth) { | |
w = targetWidth; | |
} | |
} | |
if (h < targetHeight) { | |
h *= 2; | |
if (h > targetHeight) { | |
h = targetHeight; | |
} | |
} | |
BufferedImage tmp = new BufferedImage(w, h, type); | |
Graphics2D g2 = tmp.createGraphics(); | |
applyQualityRenderingHints(g2); | |
g2.drawImage(ret, 0, 0, w, h, null); | |
g2.dispose(); | |
ret = tmp; | |
tmp = null; | |
} while (w != targetWidth || h != targetHeight); | |
return ret; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment