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
Related
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
I have png icons and use them as icons in JButton / JLabel.
The problem is that the image displayed at runtime is larger than the original icon, and because of this resizing, it's super ugly.
Here is an example:
Original icon (left) and how it's rendered in the JButton (right)
The source code for this minimal example is simply:
public class Main {
public static void main(String... args) {
JFrame frame = new JFrame("Test");
frame.setBounds(0, 0, 120, 80);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new FlowLayout());
ImageIcon icon = new ImageIcon("icon.png");
frame.getContentPane().add(new JButton("Test", icon));
frame.setVisible(true);
}
}
Is this expected? If not, how can I avoid this? I tried many things around forcing the size of the image, the button, etc. but could not get a proper image displayed.
I have tested with icons of various sizes: 16x16, 17x17, 18x18, 19x19, 20x20, and each time the icon displayed on the JButton is a bit larger than the original which makes it look ugly:
Thank you!
Cheers.
This is because you are using Windows scaling. The entire component is scaled, both the icon and the text.
You could turn the scaling of the Icon off by using a wrapper Icon:
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;
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);
}
}
The scaling adjustment will position the Icon at the top/left of the button area.
The offset adjustment will then attempt to center the Icon in the scaled icon painting area.
Using the default transform will have a scaling factor of 0 for the Icon.
Thank you all.
The problem was the default scaling factor (which was 1.25).
As I want to be fully in control of the size independently from DPI, I solved my issue by forcing the scaling factor to 1.0.
This answer was helpful
So, either pass to the command line
-Dsun.java2d.uiScale=1.0,
or set it programmatically
System.setProperty("sun.java2d.uiScale", "1.0")
Look at the source code for the constructor of class ImageIcon that takes a string parameter. It uses class java.awt.Toolkit to create the image from the file. This made me think that it must be doing some scaling. So I thought of creating the icon differently. ImageIcon has another constructor that takes an Image parameter. So I created a BufferedImage from the file and then used that image to create an ImageIcon. The BufferedImage is not scaled.
Note that your link to the icon file didn't work for me so I just downloaded a different 16x16 icon.
java.awt.image.BufferedImage img = javax.imageio.ImageIO.read(new java.io.File("cellphon.png"));
javax.swing.Icon ico = new javax.swing.ImageIcon(img);
javax.swing.JButton button = new javax.swing.JButton("Test", ico);
This question already has answers here:
Why does the first panel added to a frame disappear?
(2 answers)
Closed 5 years ago.
I've been trying all day long to make this happen with no success. What can be going wrong?
I want 2 threads printing simultaneously in my JFrame:
Thread-1: Prints Squares
Thread-2: Prints Circles
I'am ending up with only one thread printing on the JFrame. The other get executed but don't print in the JFrame.
Look, only squares are getting printed:
This is my main class:
public class Main {
public static void main(String[] args) {
FigurePlacer circle = new FigurePlacer("circle");
FigurePlacer square = new FigurePlacer("square");
JFrame window = new JFrame();
window.add(circle);
window.add(square);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("Task");
window.setSize(700, 700);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
This is the Threading Class:
import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import java.util.Random;
public class FigurePlacer extends JPanel implements Runnable{
String figure;
final int width = 700;
final int height = 700;
int x_pos = 0;
int y_pos = 0;
int x_width = 50;
int y_height = 50;
public FigurePlacer(String str){
figure = str;
randomCoord();
Thread th = new Thread (this);
th.start();
}
private void randomCoord(){ //this ramdomize x,y coord to place a new object
Random random = new Random();
x_pos = random.nextInt(width);
y_pos = random.nextInt(height);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK); //sets the black color in background
g.fillRect(0, 0, 700, 700);
System.out.println(figure);
switch (figure){
case "square":
g.setColor(Color.GREEN);
g.fillRect(x_pos, y_pos, x_width, y_height);
break;
case "circle":
g.setColor(Color.BLUE);
g.fillOval(x_pos, y_pos, x_width, y_height);
break;
}
}
#Override
public void run(){ //paints the objects
while (true){
randomCoord();
paintImmediately(x_pos, y_pos, x_width, y_height);
try{
Thread.sleep (50);
}
catch (InterruptedException ex){}
}
}
}
JFrame window = new JFrame();
window.add(circle);
window.add(square);
The default layout manager for a JFrame is the BorderLayout. When you add a component to a panel using the BorderLayout and don't specify a constraint then the component goes to the CENTER. However only one component can ever be displayed in the CENTER, so only the last component added is painted.
You could use the OverlayLayout, which allows you to stack two panels on top of one another. Of course you will need to make the top panel non-opaque.
The easier solution is to not attempt to use two panels, just create on panel that can display circles or squares.
Also, your painting code is wrong. You should not be using paintImmediately(...) to do painting. The paintComponent() method should paint every object every time the method is invoked. Try resizing your frame and you will see that all your object disappear since the paintComponent() method will clear all the old paintings.
See Custom Painting Approaches for the two common approaches for this kind of painting.
i am not a native english speaker so, firstly sorry for the grammar.
I want to do an app that capture a selected area of a screen and save it. I did a few research and i did the code down below.
My questions are:
1 - How can i open a pdf file in this app ? (i tried use a method but it didnt work. I dont know exactly where to put it on the code)
2 - How can i save the selected area in a new file ? (a image file : JPEG, JPG,png)
3 - [the complex part] right now, the code only "save" one selected area each time. I want to capture a lot of parts of screen and save this in the same image file. one beside the other. How can i do this ?
Java Code:
package javaapplication39;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class ScreenCaptureRectangle {
Rectangle captureRect;
ScreenCaptureRectangle(final BufferedImage screen) {
final BufferedImage screenCopy = new BufferedImage(
screen.getWidth(),
screen.getHeight(),
screen.getType());
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension(
(int)(screen.getWidth()/3),
(int)(screen.getHeight()/3)));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
final JLabel selectionLabel = new JLabel(
"Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screen, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
Point start = new Point();
#Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
repaint(screen, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start,
new Dimension(end.x-start.x, end.y-start.y));
repaint(screen, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
JOptionPane.showMessageDialog(null, panel);
System.out.println("Rectangle of interest: " + captureRect);
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig,0,0, null);
if (captureRect!=null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255,255,255,150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().
getScreenSize();
final BufferedImage screen = robot.createScreenCapture(
new Rectangle(screenSize));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
}
}
1 - How can i open a pdf file in this app ? (i tried use a method but it didnt work. I dont know exactly where to put it on the code)
Take a look at How to Integrate with the Desktop Class
2 - How can i save the selected area in a new file ? (a image file : JPEG, JPG,png)
Take a look at Writing/Saving an Image
3 - [the complex part] right now, the code only "save" one selected area each time. I want to capture a lot of parts of screen and save this in the same image file. one beside the other. How can i do this ?
Is, as you say, a much more complex question. You will have to modify the code so that instead of displaying the panel in a JOptionPane, it shows it within a JFrame, you then need to be able to either monitor the mouseReleaseEvent or provide some kind of action, may be a toolbar or menu option, that allows the user to save the selection.
Have a look at How to Use Menus, How to Use Buttons, Check Boxes, and Radio Buttons, How to Write an Action Listeners and How to Use Tool Bars for more details.
As a side note, the code will only allow you to capture a single screen, you might consider something like Drawing a bounding rectangle to select what area to record which will allow you to capture the entire virtual desktop (multiple screeens)
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