6

I currently studying the java swing builder as a new tech skills. I need to study how to import the image on my canvas. Yes it successfully imported and the image clearly define and not blurry. however when I run the project the image that I import to the project it goes blurry. I don't know why it happens. I research some functionality like get scaled but nothing happens it goes same output it get blurry.

Image Dimension: 250x250

Here is my code that I implement on my project:

private Image doctor_ppe = new ImageIcon(LoginScreen.class.getResource("/assets/large.png")).getImage().getScaledInstance(250, 250, Image.SCALE_SMOOTH);


JLabel lblDds = new JLabel("");
    lblDds.setVerticalAlignment(SwingConstants.BOTTOM);
    lblDds.setHorizontalAlignment(SwingConstants.CENTER);
    lblDds.setIcon(new ImageIcon(doctor_ppe));
    lblDds.setBounds(59, 305, 236, 251);
    panel.add(lblDds);

Difference of not runnable project and runnable project:

Image not blurry:

Not blurry image

Image Blurry After I run the project:

Blurry Image after i run the project

Hope someone experience this, hope will help on my problem thank you.

DevGe
  • 1,381
  • 4
  • 35
  • 66

1 Answers1

7

however when I run the project the image that I import to the project it goes blurry.

Probably because your desktop is using a scaling factor greater than 1.0, so the image is upscaled when it is painted.

If you want to change the scaling for the entire application you can try:

  1. using the command line -Dsun.java2d.uiScale=1.0, or
  2. set it programmatically using System.setProperty("sun.java2d.uiScale", "1.0")

Another option might be to prevent only the Icon from scaling:

import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;


public class NoScalingIcon implements Icon
{
    private Icon icon;

    public NoScalingIcon(Icon icon)
    {
        this.icon = icon;
    }

    public int getIconWidth()
    {
        return icon.getIconWidth();
    }

    public int getIconHeight()
    {
        return icon.getIconHeight();
    }

    public void paintIcon(Component c, Graphics g, int x, int y)
    {
        Graphics2D g2d = (Graphics2D)g.create();

        AffineTransform at = g2d.getTransform();

        int scaleX = (int)(x * at.getScaleX());
        int scaleY = (int)(y * at.getScaleY());

        int offsetX = (int)(icon.getIconWidth() * (at.getScaleX() - 1) / 2);
        int offsetY = (int)(icon.getIconHeight() * (at.getScaleY() - 1) / 2);

        int locationX = scaleX + offsetX;
        int locationY = scaleY + offsetY;

        //  Reset scaling to 1.0 by concatenating an inverse scale transfom

        AffineTransform scaled = AffineTransform.getScaleInstance(1.0 / at.getScaleX(), 1.0 / at.getScaleY());
        at.concatenate( scaled );
        g2d.setTransform( at );

        icon.paintIcon(c, g2d, locationX, locationY);

        g2d.dispose();
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI()
    {
        JButton button = new JButton( "Button" );
        NoScalingIcon icon = new NoScalingIcon( new ImageIcon("box.jpg") );
        button.setIcon( icon );

        JPanel panel = new JPanel( );
        panel.add( button );

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(panel);
        f.setSize(200, 200);
        f.setLocationRelativeTo( null );
        f.setVisible(true);
    }
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • this property: System.setProperty("sun.java2d.uiScale", "1.0") solve my problem, however the form getting smaller.? – DevGe Jan 15 '21 at 20:00
  • 1
    Correct. If you scale to 1.0, then entire form gets smaller. If you use the NoScallingIcon then then only the Icon will be smaller. – camickr Jan 15 '21 at 20:16
  • Is this code assuming a 2x scaling? Is there a way to query for the actual scaling factor? – Charlie Sep 22 '21 at 17:54
  • @Charlie, it doesn't assume anything. It gets the current scaling factor from the Graphics AffineTransform object and then inverts the scaling factor so when you concatenate them together the resulting value is 1, so the Icon is painted without any scaling. – camickr Sep 22 '21 at 19:49
  • Does the system scaling manifest as a default afine transform on the Graphics2D matching the system scaling? – Charlie Sep 22 '21 at 23:09
  • 1
    @Charlie That was my findings when I wrote the code. It is easy for you to test/verify since you have complete working code. All you do is add a display statement to display the scale value and test. Then you change the system scaling and retest. – camickr Sep 22 '21 at 23:38
  • 1
    Instead of `AffineTransform scaled = AffineTransform.getScaleInstance(1.0 / at.getScaleX(), 1.0 / at.getScaleY()); at.concatenate( scaled ); g2d.setTransform( at );` you can simply call `g2d.scale(1 / at.getScaleX(), 1 / at.getScaleY())`. – Holger Jun 15 '23 at 09:16