Image looses quality in java swing - java

I have used every popular way to display picture in java swing, but with every method the picture losses quality even without any kind of resizing. No matter what format GIF, PNG, JPEG the picture doesn't appear like the original one outside of the code. I have tested swing code to display images on other computers, it works fine on them but not on my computer.
These are the methods I have tried so far:
Note- To keep the things short the code below is for example only.
1.Graphics method
public class mainClass extends Canvas {
public void paint(Graphics g){
Toolkit t = Toolkit.getDefaultToolkit();
Image i = t.getImage(getClass().getResource("monsters.png"));
g.drawImage(i, 0 , 0, this);
}
public static void main(String []args){
mainClass m = new mainClass();
JFrame frame = new JFrame();
frame.add(m);
frame.setSize(800,800);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
Simple JLabel setIcon method
ImageIcon gif = new ImageIcon("Loading2 (1).gif");
label.setIcon("gif");
Scaled JLabel setIcon method
public ImageIcon create(ImageIcon i ,int x,int y){
Image img = i.getImage();
Image imgScaled = img.getScaledInstance(x,y,Image.SCALE_SMOOTH);
return new ImageIcon(imgScaled);
}
Comparison:
Original
JavaOutput

Related

Transparent background GIF on JLabel acting strange

When I try to use a GIF in a JLabel either resized or normal, it smears and produces an odd effect:
The GIF I'm using:
Layout of the JPanel it is attached to is null, and images that are accessed are part of a jar file.
Here's the code for creating and adding the label:
public JLabel j_Anim(String path, int width, int height, int xpos, int ypos, boolean applyscaling) throws Exception {
Image finimage;
if (!applyscaling) {
finimage = new ImageIcon(Main.class.getResource(path)).getImage();
} else {
finimage = (new ImageIcon(Main.class.getResource(path)).getImage()).getScaledInstance(width, height, Image.SCALE_DEFAULT);
}
JLabel im = new JLabel(new ImageIcon(finimage));
group.panel.add(im);
im.setBounds(xpos, ypos, width, height);
return im;
}
I'm fairly new to java, so any help would be greatly appreciated!
EDIT:
Minimal Reproducable Example:
import javax.swing.*;
import java.awt.*;
class Main extends JFrame {
public static void main(String[] args) {
Main ma = new Main();
}
Main() {
JPanel p = new JPanel();
this.setSize(300, 300);
this.add(p);
JLabel im = new JLabel(new ImageIcon(this.getClass().getResource("img/walk.gif")));
p.add(im);
this.setVisible(true);
this.pack();
}
}
EDIT 2:
This behaviour is only happening with gifs that have transparent backgrounds, standard solid-background gifs work fine. However, the issue is still unresolved because I need to use a gif with a transparent background. Thanks for the help so far!
EDIT 3:
The issue was solved by changing the gif's disposal method to background. I used this cmd script with imagemagick to generate a custom gif with the specified disposal method from a spritesheet:
set WIDE=50
set HIGH=75
set XCOORD=0
set YCOORD=0
set FRAMES=8
convert spritesheet.png ^
-set option:distort:viewport %[fx:%FRAMES%*%WIDE%]x%HIGH% ^
-set option:slider %[fx:%YCOORD%*(w/%WIDE%)+%XCOORD%] ^
-crop %WIDE%x%HIGH% +append +repage ^
-distort affine "%[slider],0 0,0" ^
-crop %WIDE%x%HIGH% +repage ^
-set delay 10 -loop 0 -set dispose Background result.gif
pause
exit

Images not visible in JList

I'm writing a little photo application (asked some questions before) and I have one problem which I cannot resolve. The idea is that there are two sections: the upper one is for an overview (using thumbnails) and the lower one shows the selected image in it's full size. I cannot use ImageIO (required by my lecturer).
I'm using a JList for the overview but most images are not visible. I chose a folder with about 20 images and only 2 show up. And one of them isn't even centered.
For some reason, if I delete those lines:
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
One image shows up that wasn't visible before, but now the other two disappear.
This is my code:
public class PVE extends JFrame {
private JFileChooser fileChoose;
//MenuBar
private JMenuBar menubar;
private JMenu file;
private JMenuItem openFolder;
private JMenuItem exit;
//Thumbnails
private JList thumbnaillist;
private DefaultListModel<ImageIcon> listmodel;
private JScrollPane tscroll;
private ImageIcon thumbs;
private int thumbW = 100;
private int thumbH = 100;
//for full size view
private JPanel imgview;
public PVE() {
setLayout(new BorderLayout());
//MenuBar
menubar = new JMenuBar();
file = new JMenu("File");
openFolder = new JMenuItem("Open folder...");
exit = new JMenuItem("Quit");
file.add(openFolder);
file.addSeparator();
file.add(exit);
menubar.add(file);
setJMenuBar(menubar);
fileChoose = new JFileChooser();
openFolder.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
fileChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChoose.showOpenDialog(null);
File chosenDir = fileChoose.getSelectedFile();
loadToThumbView(chosenDir);
}
});
//Thumbnail view
listmodel = new DefaultListModel();
thumbnaillist = new JList(listmodel);
thumbnaillist.setLayoutOrientation(JList.HORIZONTAL_WRAP);
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
thumbnaillist.setVisibleRowCount(1);
tscroll = new JScrollPane(thumbnaillist, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tscroll.setPreferredSize(new Dimension(0, 100));
add(tscroll, "North");
//for full size view
imgview = new JPanel();
imgview.setBackground(Color.decode("#f7f7f7"));
add(imgview, "Center");
setTitle("Photo Viewer");
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
}
setSize(700, 700);
setLocation(200, 200);
setVisible(true);
}
public void loadToThumbView(File folder) {
listmodel.removeAllElements();
File[] imgpaths = folder.listFiles();
for (int j = 0; j < imgpaths.length; j++) {
listmodel.addElement(resizeToThumbnail(new ImageIcon(imgpaths[j].toString())));
}
}
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bf.createGraphics();
g.drawImage(img, 0, 0, thumbW, thumbH, null);
ImageIcon kB = new ImageIcon(bf);
return kB;
}
public static void main(String argv[]) {
PVE pv = new PVE();
}
}
Your problem is because of the way you're scaling your images.
I'm not exactly sure why but I guess it has something to do with the BufferedImage#createGraphics() call and that I was able to reproduce the problem with .jpg images while .png files were correctly painted.
However if you scale your images instead of converting them to a BufferedImage and getting a new ImageIcon from it, you get the correct output:
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
Image scaled = img.getScaledInstance(thumbW, thumbH, Image.SCALE_SMOOTH);
return new ImageIcon(scaled);
}
This is the folder I used to test:
And the outputs with your code and mine:
Important notes
And as as a recommendation don't make a window that big if all you're using is that little bar above. If you're adding something else below, then it's ok but for now it's not that "user friendly" (IMHO). Instead of JFrame#setSize() you could try using JFrame#pack() method so your frame resizes to it's preferred size.
Some other things I noted in your program:
You're not placing it inside the Event Dispatch Thread (EDT) which is dangerous since your application won't be Thread safe that way. You can change that if you change your main method as follows:
public static void main(String argS[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PVE pv = new PVE();
}
});
}
You're setting the JScrollPane preferred size, instead you should override its getPreferredSize() method, see Should I avoid the use of setPreferred|Maximum|MinimumSize methods in Java Swing? (YES)
You're extending JFrame, you should instead create an instance of it unless you're overriding one of its methods (and you're not, so don't do it) or you have any good reason to do it. If you need to extend a Container you should extend JPanel instead, as JFrame is a rigid container which cannot be placed inside another one. See this question and this one.
I think I'm not missing anything, and hope this helps
Your “scaled” images are actually images which are the same size as the original image, but are blank except for a scaled version drawn in the upper left corner. That upper left corner is clipped out of view in each rendered cell (at least for the somewhat large images I tested with).
The scaled image needs to be created with the thumbnail size, not the size of the original image. Meaning, change this:
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
to this:
BufferedImage bf = new BufferedImage(thumbW, thumbH, BufferedImage.TYPE_INT_ARGB);

AWT custom window shape using transparent image

I am trying to make a UI using AWT. I want to use only images and transparent components. Right now I cant understand how to make a main window which is supposed to be a PNG image with a custom shape. All the areas that are transparent in the image are replaced with a black color. Here is the code I use:
public class Test {
static Image image;
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
//switch to the right thread
image = ImageIO.read(Test.class.getClassLoader().getResource("resources/images/panel.png").openStream());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Frame frame = new Frame("Test");
frame.setUndecorated(true);
frame.setBackground(new Color(0,0,0,0));
frame.add(new BackGround(image,image.getWidth(frame),image.getHeight(frame)));
frame.pack();
frame.setSize(image.getWidth(frame), image.getHeight(frame));
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
);
}
private static class BackGround extends Component {
private Image img;
private int wid, hgt;
public BackGround(Image img, int wid, int hgt){
this.img=img;
this.wid=wid;
this.hgt=hgt;
}
#Override
public void paint(Graphics graphics) {
graphics.drawImage(image,0,0,wid,hgt,0,0,wid,hgt,null);
}
}
}
AWT components don't have a concept of transparency, they are always opaque
Try taking a look at ...
How can I smooth my JFrame shape
JFrame the same shape as an Image / Program running in background
Java Swing: Transparent PNG permanently captures original background
How to Create translucent and Shaped Windows
For more examples of using Swing

How to put JFrame into FullScreen and automatically rescale content

I want go full screen and keep everything inside in order.
How should i put the JFrame into full screen AND rescale everything inside: images, generated drawings etc.(sth like zooming it up so the content will fit the screen).
The problem is I am making full screen app, but I don't know on what screen it will be displayed.
This will put the frame into fullscreen, but the content will not be rescaled
frame.dispose();
frame.setUndecorated(true);
frame.setLocation(0, 0);
frame.setSize(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
frame.setVisible(true);
frame.repaint();
Depends on what it is that you want to scale.
If its graphics you draw using Java2D, just figure out how much the stuff needs to be scaled up and use Graphics2D.scale() to scale the gfx appropiately.
If its something with a Swing layout, use a Layout manager to make an adaptive layout.
If its something else, elaborate on your problem
If this really is what you want to do (see warnings from other answers), it's not too hard to do (but takes a little time to figure out). Basically, it involves extending JPanel, and then overwriting the paint method.
Here's a sample that I came up with:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class CustomPanel extends JPanel{
Component myComponent;
public CustomPanel(){
super();
setLayout(null);
}
/**
* Only allows one component to be added
*/
#Override
public Component add(Component c){
super.add(c);
c.setLocation(0, 0);
c.setSize(c.getPreferredSize());
myComponent = c;
return c;
}
#Override
public void paint(final Graphics g){
Dimension d = this.getSize();
Dimension p = myComponent.getPreferredSize();
// Paints the child component to a image
BufferedImage newImg = new BufferedImage(p.width, p.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = newImg.createGraphics();
super.paint(g2d);
// Resizes the image if necessary
Image img;
if(d.height > p.height && d.width > p.width){
System.out.println("Scaled");
float changePercentage = 0;
if(d.height/p.height > d.width/p.width){
changePercentage = (float)d.width/(float)p.width;
} else{
changePercentage = (float)d.height/(float)p.height;
}
System.out.println(changePercentage);
int newHeight = ((Float)(p.height * changePercentage)).intValue();
int newWidth = ((Float)(p.width * changePercentage)).intValue();
img = newImg.getScaledInstance(newWidth, newHeight, 0);
} else{
System.out.println("Not Scaled");
img = newImg;
}
// Paints the image of the child component to the screen.
g.drawImage(img, 0, 0, null);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable(){public void run(){
JFrame frame = new JFrame("Zoom Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
CustomPanel buffer = new CustomPanel();
JPanel content = new JPanel();
content.add(new JLabel("Bogus"));
content.setBackground(Color.red);
buffer.add(content);
frame.setContentPane(buffer);
frame.setVisible(true);
new CustomPanel();
}});
}
}
few days back I just worked with an java full screen app. Have a look at the following link. if that was your requirement I can help you to some extent.
https://docs.google.com/open?id=0B9U-BwYu62ZaeDM3SWZhaTdSYzQ

JFrame image display at frame resize

I have this JFrame containing a children of JPanel wherein it displays the image which is declared in this manner.
BufferedImage image = ImageIO.read(filename);
The program displays the image properly. But the only thing is, it requires to resize the frame to display the image.
Is there a possible way to display the image once the frame appears?
You should override paintComponent(Graphics g) and draw the image therein. In this case, you should do this for the JPanel component (I think? If not, do this for the JComponent(s) you're referring to). Also, since Swing is not thread-safe, ensure these modifications are performed in the EDT.
EXAMPLE
public class Demo{
private static BufferedImage bi;
public static void main(String[] args){
try{
loadImage();
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
createAndShowGUI();
}
});
}
catch (IOException e){
// handle exception
}
}
private static void loadImage() throws IOException{
bi = ImageIO.read(new File("src/resource/braveheart.PNG"));
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(){
#Override
protected void paintComponent(Graphics g){
Graphics g2 = g.create();
g2.drawImage(bi, 0, 0, getWidth(), getHeight(), null);
g2.dispose();
}
#Override
public Dimension getPreferredSize(){
return new Dimension(bi.getWidth(), bi.getHeight());
}
};
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
OUTPUT
It's important to keep in mind that this example ignores rendering hints, so when you maximize the JFrame, the image quality will be very poor. :)
EDIT
When answering this question, I assumed you had a basic understanding of Swing. I suppose I assumed too much. It is important to mention that all components should be added to the top-level container before it's been realized (i.e. made visible). This will ensure that everything is rendered without having to resize your frame. As others have suggested, you could have simply used a JLabel to render the image, and then added it to your JPanel. Instead, I promoted custom painting, which is perfectly acceptable, and to me, cleaner.
for dispaly Image or ImageIcon is better look for JLabel (basic stuff)

Categories