I'd like to have a component that shows an image in Java without zooming on HiDPI screens.
The obvious candidate is to use a JLabel. I've succesfully done it by overwriting the AffineTransform
in paintComponent
but it remains the problem that the label preferred size is incorrect on HiDPI.
The following example seems to work even when I move the window from HiDPI (4K scaled 1.75) to FullHD (scale 1.0) except for the size of the component on HiDPI which is larger than the image displayed.
How can I achieve to have the preferred size of a component not to be zoomed on a HiDPI screen?
public class UnscaledImage extends JPanel {
private AffineTransform noChangeTransform = new AffineTransform();
private JLabel imageLabel;
private JLabel colorLabel = new JLabel("Color");
private BufferedImage image;
private double scale = 1.0;
public UnscaledImage() {
initUI();
packAndShow("Unscaled Image");
}
public void initUI() {
setLayout(new BorderLayout());
ImageIcon imageIcon = (ImageIcon) UIManager.getIcon("OptionPane.warningIcon");
image = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
g2d.drawImage(imageIcon.getImage(), 0, 0, null);
g2d.dispose();
imageLabel = new JLabel() {
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform oldTransform = g2d.getTransform();
scale = oldTransform.getScaleX();
Dimension labelPrefSize = imageLabel.getPreferredSize();
if (scale != 1.0 && labelPrefSize.width == image.getWidth()) {
imageLabel.setSize(new Dimension((int) (labelPrefSize.width / scale), (int) (labelPrefSize.height / scale)));
SwingUtilities.windowForComponent(imageLabel).pack();
}
g2d.setTransform(noChangeTransform);
super.paintComponent(g);
g2d.setTransform(oldTransform);
}
};
imageLabel.setIcon(imageIcon);
imageLabel.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent me) {
int mouseX = (int) (me.getX() * scale);
int mouseY = (int) (me.getY() * scale);
if (mouseX < image.getWidth() && mouseY < image.getHeight()) {
int color = image.getRGB(mouseX, mouseY);
colorLabel.setBackground(new Color(color));
}
}
});
colorLabel.setOpaque(true);
colorLabel.setBackground(Color.WHITE);
add(imageLabel, BorderLayout.CENTER);
add(colorLabel, BorderLayout.SOUTH);
}
public void packAndShow(String title) {
JFrame frame = new JFrame(title);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public final static void main(String[] args) {
SwingUtilities.invokeLater(() -> new UnscaledImage());
}
}