Swing JLabel icon: use same image for all resolutions - java

I know they are quite a few forums that kinda talks about this, but my problem is that I have a JLabel with an icon which I do NOT want to scale when resolution is <> 100% ! I.e. (sorry, in french):
Initially, I set my JLabel icon with something like:
lblImage.setIcon( getNoteIcon() );
//...
ImageIcon getNoteIcon(){
return new ImageIcon( getClass().getResource('path/to/file.png') );
}
This results are that my image displays blurry when HiDPI resolution is set to higher than 100%. Examples:
At 100%:
And at 150%:
You can see that the music note image is fuzzier in the 150% resolution.
What I want: I DO NOT want it to up or downscale the image! I want to keep the original size, unless I can provide different image sizes for various resolutions.
That being said, I looked and tried to use the BaseMultiResolutionImage class to deal with resolutions, passing along an array of the "same size image", but I get the same results when I change the resolution. This is the code I tried :
ImageIcon getNoteIcon(){
List<Image> imgList = new ArrayList<Image>();
/* all images are width = 108 height = 83 */
imgList.add(ImageIO.read(new File('path/to/file.png'))); // 100%
imgList.add(ImageIO.read(new File('path/to/file.png'))); // 125%
imgList.add(ImageIO.read(new File('path/to/file.png'))); // 150%
imgList.add(ImageIO.read(new File('path/to/file.png'))); // 175%
imgList.add(ImageIO.read(new File('path/to/file.png'))); // 200%
BaseMultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(imgList.toArray(new Image[0]));
return new ImageIcon(
multiResolutionImage
);
}
I don't understand what I'm doing wrong, or if I'm even using BaseMultiResolutionImage correctly. Finally, if I do manage say to give 3 different images for 3 resolutions, (i.e. 100, 125, 150%), is there a way to tell it the "default" one to use when I do not have an image for a given resolution (i.e. 200%) ?
Can anyone shed a light on all of this? Seems like a lot of confusion on my end just to get an image to NOT scale in my window...
Much thanks!
Pat
UPDATE AFTER "PROPER" USE OF BaseMultiResolutionImage:
try {
List<Image> imgList = new ArrayList<Image>();
imgList.add(ImageIO.read(getClass().getResource("images/notes/hidpi_100/file.png"))); // 100% - 108x83
imgList.add(ImageIO.read(getClass().getResource("images/notes/hidpi_125/file.png"))); // 125% - 135x104
imgList.add(ImageIO.read(getClass().getResource("images/notes/hidpi_150/file.png"))); // 150% - 162x124
imgList.add(ImageIO.read(getClass().getResource("images/notes/hidpi_175/file.png"))); // 175% - 189x145
imgList.add(ImageIO.read(getClass().getResource("images/notes/hidpi_200/file.png"))); // 200% - 216x166
BaseMultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(imgList.toArray(new Image[0]));
ImageIcon icon = new ImageIcon(multiResolutionImage);
return icon;
}
catch(IOException ex){
ex.printStackTrace();
return null;
}
On screen font DPI set to 175% in Windows, this results in:
Before using BaseMultiResolutionImage
After using BaseMultiResolutionImage
Here is a comparison of what I get (left), with the actual image file it's supposed to show on the right hand side (mind you Paint doesn't take into account background transparency):
Any ideas as to why this "choppy" image is showing? What am I missing ?
Thanks again.
Pat

Related

How can I stop JLabel scaling an image?

I have a Swing app that can display an image by loading it into a JLabel. Up to Java 8, this worked fine. Since Java 9 there are changes intended to make apps resize on higher pixel densities, including rescaling images: when pixel density is high, images are scaled up. The results are ugly in many cases. As an example, if I have a photo with a high pixel count, my app scales it down to fit the available space, but then it's automatically scaled back up to allow for the higher pixel density - ugly.
A couple of options I can see for avoiding this problem are:
Implementing the interface java.awt.image.MultiResolutionImage which looks like it should help, but I don't see how to use that with JLabel.
Maybe there's a way to fool Swing into thinking that no pixel scaling is necessary, but I can't find anything like that
The following code is a simple example of displaying an image in a label. In Java 8, the image is displayed pixel-for-pixel. In Java 9+, the whole UI including the image is scaled up according to what your OS thinks is your pixel density. You should be able to set this scaling explicitly - Windows 10 has it under "Display", "Scale and Layout". Mine is set to 125% which seems to be a perfect amount to make almost any image look ugly.
import java.awt.*;
import javax.imageio.*;
import javax.swing.*;
import java.io.*;
public class Img extends JFrame {
public static void main( String[] args ) throws IOException {
new Img( new File( args[0] ) );
}
private Img( File file ) throws IOException {
super( "Img: " + file.getName () );
ImageIcon img = new ImageIcon( ImageIO.read( file ) );
JLabel label = new JLabel( img );
label.setPreferredSize( new Dimension( img.getIconWidth(), img.getIconHeight() ) );
add( label );
setDefaultCloseOperation( EXIT_ON_CLOSE );
pack();
setVisible( true );
}
}

Change screen resolution without resize window or use fullscreen (LWJGL 2)

I have a simple game made with LWJGL 2, and i want it to get the best resolution that's possible for a given window size.
It seems that there is something to do with the DisplayMod, but if i am not in FullScreen mod, it doesn't change game resolution, it just resize the window.
I am able to do what i want in FullScreen via: Display.setDisplayMode(DisplayMode), but as i said, if the Display is not in full screen mod, it just change the window size, but not the resolution.
So my question is, how to get a better resolution without fullscreen/resizing the window?
EDIT (04/08/2017):
To help you to understand my problem, i have recored a short video when a switch to FullScreen/Windowed: https://www.mediafire.com/file/j9t06qa3aaw9e59/Resolution%20bug.mov
To change the game resolution in Fullscreen when you create your frame juste put
Display.setFullscreen(true);
and after create a new ArrayList of DisplayMode
ArrayList<DisplayMode> Mode = new ArrayList<DisplayMode>();
after create your new ArrayList get all screen size support by your graphic cards
try {
DisplayMode[] modes;
modes = Display.getAvailableDisplayModes(); //get all resolution
for (int i=0;i<modes.length;i++) {
DisplayMode current = modes[i]; //add all DisplaMode to arraylist
Resolutions.add(current);
}
} catch (LWJGLException e) {
e.printStackTrace();
}
for (DisplayMode mode : Resolutions) { //optional just to see all resolution
System.out.println(mode.getWidth() + "x" + mode.getHeight() + "x"+mode.getBitsPerPixel() + " " + mode.getFrequency() + "Hz");
}
And to load a DisplayMode
Display.setDisplayMode(Mode.get(int));
In order to set the resolution, you will need to use frame buffers. You will need to render to a frame buffer, then when you are ready to send the framebuffer of the proper resolution to the screen, you will blit the framebuffer to the window's back buffer. Here is a tutorial, albeit in C++. This should get you pointed in the right direction!

How to set size of custom button?

I've created a GUI program with custom icons for buttons. I'm unable, however, to set the size of these buttons in Java, so they remain their original size, 230x227. I'm trying to get them to be around 20x20 so I used the following code:
classAlcBtn.setPreferredSize(new Dimension(20,20));
classAlcBtn.setIcon(new ImageIcon(getClass().getResource("Alchemist.png")));
classAlcBtn.setBorder(null);
classAlcBtn.setBorderPainted(false);
classAlcBtn.setContentAreaFilled(false);
classAlcBtn.setPressedIcon(
new ImageIcon(getClass().getResource("alchemistClicked.png")));
classAlcBtn.setCursor(new Cursor(Cursor.HAND_CURSOR));
Is there a way to force these icons to size down, or do I have to size down the actual icon file? Thanks for any help.
Assuming you can size down the buttons, without icons. So use the following method to size down the image, without changing the size of original file:
ImageIcon icon = new ImageIcon("whatever.jpg");
Image img = icon.getImage() ;
Image newImg = img.getScaledInstance( NEW_WIDTH, NEW_HEIGHT, java.awt.Image.SCALE_SMOOTH ) ;
icon = new ImageIcon( newImg );
...
classAlcBtn.setIcon(icon);
And if Button resizing itself is not working, then you can try using setMaximumSize() instead of setPreferredSize() method as following:
classAlcBtn.setMaximumSize(new Dimension(100,100));
See this for more info. about sizes. Hope this Helps:)

How do you Scale and display specific sections of an image using Java

So I took it upon myself to learn Java.
A decision I regret more with every crash of Elipse.
Fortunately I have actually managed to get this block of my self inflicted project to actually 'work' but obviously being self taught I am quite sure I have made a lot of errors in my layout and
In total, the program will create a JFrame then stick a JscrollPane inside that into which it inserts a a JPanel (wrapPage). It then loops through a process that generates an array of TMTile Objects which are extended JPanels containing the tile images which are drawn from a source folder of jpg images. Once that has finished it places that array as a grid using the GridBagLayout within the wrapPage Jpanel resulting in a nice little perfect maze.
That all works perfectly, but the big let down is that the size of the image used to create the tiles is dictating everything. I can't for the life of me figure out how to scale the image and efforts to find a suitable process have only got me methods of creating new image files or alternating between stretching and tiling images to fit a within their containing component or suggestions I just couldn't follow to save my life.
Fortunately. The image handling is part of the TMTile class file! This means I can show you the entire relevant bit of script;
The following are imported for use in this file
from java.awt: Color, GridBagConstraints, GridBagLayout, Insets
from javax.swing: ImageIcon, JLabel, JPanel
public class TMTile extends JPanel
{
private static final long serialVersionUID = 1L;
private int paths; // values 0 to 15, uses bitwise & | to set or check open paths
private JLabel tileWrap; // to contain the ImageIcon
private ImageIcon tileImg; // the image to be used
GridBagConstraints bag;
public TMTile( int inDir ) // called by maze constructor
{
paths = inDir;
this.setBackground( Color.RED ); // so I can tell if the image didn't load right
this.setLayout( new GridBagLayout() ); // GridBagLayout is probably overkill but it what I am most familiar with now.
bag = new GridBagConstraints();
bag.insets = new Insets( 0, 0, 0, 0 );
tileImg = tileImage( paths );
tileWrap = new JLabel( "", tileImg, JLabel.CENTER );
this.add( tileWrap, bag );
}
public void open( int inDir ) // called by maze constructor when tile value changes resulting from the perfect maze backtrack method
{
paths = paths | inDir;
tileImg = tileImage( paths );
tileWrap.setIcon( tileImg );
}
private ImageIcon tileImage( int paths ) // created to cut down on duplicate code and make updating easier
{
String inEnd;
if(paths < 10)
{
inEnd = "0"+ paths;
}
else
{
inEnd = ""+ paths;
}
ImageIcon tileImg = new ImageIcon( "imgs/MAZE_"+ inEnd +".jpg" );
System.out.println( "imgs/MAZE_"+ inEnd +".jpg" );
Image newimg = tileImg.getImage().getScaledInstance( 40, 40, java.awt.Image.SCALE_DEFAULT );
tileImg = new ImageIcon( newimg );
return tileImg;
}
public int getOpen()
{
return paths;
}
}
Thanks to nachokk and MadProgrammer I now once again have a working maze program and the maze tiles are scalable. That just leaves the final goal of doing away with individual tile .jpgs and switching to a single image file with all 16 stored within in.
What I would love to have is the ability to utilize a single large image file which is divided into 16 sections, 1 section for each tile value. I started out working toward this goal but had to abandon it fairly quickly as I couldn’t figure out how to only display the section of the image needed which would also need to be scaled in the way described above.
Since I am very much still learning Java advice on any alternatives is welcome but ideally I would love to know how to accomplish this as planned.

Make JCheckbox bigger..?

i want to make my JCheckboxes in a JTable bigger (for Touchscreen), but it doesn't change the size.
I tried it with
setPrefferedSize
setSize
What should I do?..
I assume you mean you want a bigger check box. If so then you need to create images to represent the unselected and selected icons of the check box. Then you can create a renderer and editor using these icons. Finally you would need to increase the height of each row in the table. The code might look something like:
Icon normal = new ImageIcon(...);
Icon selected = new ImageIcon(...);
JTable table = new JTable(...);
table.setRowHeight(...);
TableCellRenderer renderer = table.getDefaultRenderer(Boolean.class);
JCheckBox checkBoxRenderer = (JCheckBox)renderer;
checkBoxRenderer.setIcon( normal );
checkBoxRenderer.setSelectedIcon( selected );
DefaultCellEditor editor = (DefaultCellEditor)table.getDefaultEditor(Boolean.class);
JCheckBox checkBoxEditor = (JCheckBox)editor.getComponent();
checkBoxEditor.setIcon( normal );
checkBoxEditor.setSelectedIcon( selected );
IMPORTANT NOTE: This was only tested with the default 'Metal' look and feel. I do not guarantee that this will work for any other look and feel. Also I am not entirely sure how it works because it is admittedly a bit of a hack.
I was able to solve this in a slightly different way.
I wanted to use the existing images and just apply a scale to it. I am already scaling the font of my application using the UI defaults and so I have a rather large font. I wondered if I could leverage that and scale the check boxes accordingly.
After scouring the internet and trying a bunch of things I came up with this method:
public static void scaleCheckBoxIcon(JCheckBox checkbox){
boolean previousState = checkbox.isSelected();
checkbox.setSelected(false);
FontMetrics boxFontMetrics = checkbox.getFontMetrics(checkbox.getFont());
Icon boxIcon = UIManager.getIcon("CheckBox.icon");
BufferedImage boxImage = new BufferedImage(
boxIcon.getIconWidth(), boxIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = boxImage.createGraphics();
try{
boxIcon.paintIcon(checkbox, graphics, 0, 0);
}finally{
graphics.dispose();
}
ImageIcon newBoxImage = new ImageIcon(boxImage);
Image finalBoxImage = newBoxImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
checkbox.setIcon(new ImageIcon(finalBoxImage));
checkbox.setSelected(true);
Icon checkedBoxIcon = UIManager.getIcon("CheckBox.icon");
BufferedImage checkedBoxImage = new BufferedImage(
checkedBoxIcon.getIconWidth(), checkedBoxIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB
);
Graphics checkedGraphics = checkedBoxImage.createGraphics();
try{
checkedBoxIcon.paintIcon(checkbox, checkedGraphics, 0, 0);
}finally{
checkedGraphics.dispose();
}
ImageIcon newCheckedBoxImage = new ImageIcon(checkedBoxImage);
Image finalCheckedBoxImage = newCheckedBoxImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
checkbox.setSelectedIcon(new ImageIcon(finalCheckedBoxImage));
checkbox.setSelected(false);
checkbox.setSelected(previousState);
}
What it does is get the size of the font from the checkbox's font metrics. Then using that it derives a new icon based on the icon found in the 'Look and Feel'.
One odd thing that I am not able to explain is how the icon for the checkbox in its 'un-selected' or default state, changes to the 'selected' icon, when I am accessing the same property to get each one.
I start by saving the state of the control so I can restore it at the end. This is done because in order for the icons to be set properly, the state needs to be unchecked when you first request the icon from the UIManager and then it will need to be checked when you request the icon the second time to get the 'selected' icon.
I am not entirely sure how the UIManager works or why the checkbox icon changes when we call the same property just by setting the 'selected' value of a single checkbox, but that is what is required in order to get both the necessary icons.
If you did not want to base the size on the font you could easily just pass in the height and width as parameters and use them instead of the font's height when setting the buffered image size.
I might mention that this same methodology works with radiobuttons

Categories

Resources