Related
I'm trying to get my Jframe to match my image dimensions exactly, so that when i attempt to get the Rectangle2D co-ordinates of an area via drawing a rectangle, it's give me the true co-ordinates of where it would appear on the actual image.
The objective with this solution is to convert a PDF to a image, identify a particular area using the visual mapper and then use PDFBox (PDFTextStripperbyArea) to extract against this area.
The co-ordinates being given by the below code is not extracting the required area's.
This is the code:
public class PDFVisualMapper extends JFrame {
BufferedImage image = null;
public static void main(String[] args) throws IOException {
new PDFVisualMapper();
}
public PDFVisualMapper() throws IOException {
this.setSize(1700, 2200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new PaintSurface(), BorderLayout.CENTER);
this.setVisible(true);
}
private class PaintSurface extends JComponent {
ArrayList<Shape> shapes = new ArrayList<Shape>();
Point startDrag, endDrag;
public PaintSurface() throws IOException {
image = ImageIO.read(new File("C:\\Users\\Rusty\\Desktop\\temp\\Test_PDF-1.png"));
if ( image != null ) {
Dimension size = new Dimension(image.getWidth(null), image.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startDrag = new Point(e.getX(), e.getY());
endDrag = startDrag;
repaint();
}
public void mouseReleased(MouseEvent e) {
Shape r = makeRectangle(startDrag.x, startDrag.y, e.getX(), e.getY());
shapes.add(r);
startDrag = null;
endDrag = null;
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
endDrag = new Point(e.getX(), e.getY());
repaint();
}
});
}
private void paintBackground(Graphics2D g2) {
g2.setPaint(Color.LIGHT_GRAY);
for (int i = 0; i < getSize().width; i += 10) {
Shape line = new Line2D.Float(i, 0, i, getSize().height);
g2.draw(line);
}
for (int i = 0; i < getSize().height; i += 10) {
Shape line = new Line2D.Float(0, i, getSize().width, i);
g2.draw(line);
}
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
paintBackground(g2);
Color[] colors = { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.BLUE, Color.PINK };
int colorIndex = 0;
g2.drawImage(image, null, 0, 0);
g2.setStroke(new BasicStroke(2));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));
for (Shape s : shapes) {
g2.setPaint(Color.BLACK);
g2.draw(s);
g2.setPaint(colors[(colorIndex++) % 6]);
g2.fill(s);
}
if (startDrag != null && endDrag != null) {
g2.setPaint(Color.LIGHT_GRAY);
Shape r = makeRectangle(startDrag.x, startDrag.y, endDrag.x, endDrag.y);
g2.draw(r);
System.out.println(r.getBounds2D());
}
}
}
private Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
Can anybody help?
This might be simpler: using a JLabel within the contentpane, using FlowLayout:
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class WarpImage {
public static void main(String[] args) throws IOException {
displayImage();
}
private static void displayImage() throws IOException{
URL url = new URL("http://www.digitalphotoartistry.com/rose1.jpg");
BufferedImage image = ImageIO.read(url);
ImageIcon icon= new ImageIcon(image);
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JLabel lbl= new JLabel();
lbl.setIcon(icon);
frame.add(lbl);
frame.pack();
//check size :
Rectangle bounds = lbl.getBounds();
System.out.println(bounds.getWidth() +"-"+ bounds.getHeight());
frame.setVisible(true);
}
}
I'm trying to get my Jframe to match my image dimensions exactly, so that when i attempt to get the Rectangle2D co-ordinates of an area via drawing a rectangle, it's give me the true co-ordinates of where it would appear on the actual image.
Then you paint the image yourself. Why? Because components like JLabel have their own internal layout mechanics which provide no way for you to determine the offset of the image within in, if the image is to large or to small for the component size.
Something like this, for example:
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane(BufferedImage img) {
this.img = img;
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(0, 0) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.drawImage(img, 0, 0, this);
g2.dispose();
}
}
}
This places the image in the top left corner of the component, so if it's resized for some reason, the image will always be in the top left position. To be frank, it wouldn't be hard to generate an offset to allow the image to be centred, this could then be used by decedents of the component to calculate the offset required to adjust their own output as needed
i have read about a lot of articles of drawing images, but i cant get those to work when i need to keep the background. I'm trying to rotate an image which is over another image after click on a JButton. The background image is generated on a JPanel by:
public void paintComponent(Graphics g){
int index = 0;
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
try {
image = ImageIO.read(url1);
image2 = ImageIO.read(url2);
image3 = ImageIO.read(url3);
} catch (IOException e) {
}
g.drawImage(image, 0, 0, null);
g.drawImage(image3, 0, 0, null);
if(scaleDrawnFlag == 0){
for(index = 0; index < 60; index ++){
tx = AffineTransform.getRotateInstance(Math.toRadians(6*index), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image3, null), 0, 0, null);
}
scaleDrawnFlag = 1;
}
g.drawImage(image2, 0, 0, null);
}
Which is into a JPanel named panel and draw a image only one time to keep the refresh performance, only for the animated image. This draws a scale for a tachometer, by a total of 60 lines, where each line is a copy of image3
The animated image, is generated by pressing a JButton, and is made by:
public void paintComponent(Graphics g){
super.paintComponent(g);
BufferedImage img = new BufferedImage(370, 370, BufferedImage.TRANSLUCENT);
Graphics2D g2d = img.createGraphics();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
Graphics2D temp = (Graphics2D) g;
tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
temp.drawImage(op.filter(image2, null), 0, 0, null);
temp.dispose();
}
Which is into another JPanel named overPanel, which is over the initial JPanel.
But, when i call the methods:
public void up(){
degrees ++;
if(degrees == 360) degrees = 0;
repaint();
}
public void down(){
degrees --;
if(degrees == -360) degrees = 0;
repaint();
}
Which are on the overPanel class, the JPanel is entirely cleared. The animation is working well but, the Background disappear.
What must i do to keep the Background?
I also tried another solution, by drawing the 60 lines again on every up() and down() call. The background is repainted, but takes too much time to complete, so, the animation to rotate the tachometer's indicator lags.
Never dispose of a Graphics object given to you by the JVM. You're doing this:
// temp **is** the same object as g and is the Graphics object given by the JVM
Graphics2D temp = (Graphics2D) g;
//....
temp.dispose();
and shouldn't do it since it completely breaks the painting chain. You should instead be disposing of the g2d object, one you created.
Also, this would be OK
Graphics2D temp = (Graphics2D) g.create(); // temp **is** a new object
//....
temp.dispose(); // this is OK
Other issues:
I also wouldn't be creating my BufferedImage inside of paintComponent but rather would make it a field of the class, and display it inside paintComponent.
Your top code shows ignored critical exceptions -- you don't want to do this.
It also shows reading in of image files within a painting method, something that will unnecessarily slow down graphics. Again, don't do this, read in the images once outside of any painting method, store the results, and use them in the painting method.
The paintComponent method is protected, not public. Avoid increasing its visibility unnecessarily.
In your minimal example program, your scaleDrawnFlag variable and its associated if-block appear to be messing you up. What is the purpose of that variable and the if block? If you get rid of the variable and the if block, your background would persist. Myself, I'd do things differently by creating a stable background image and drawing it every time in the paintComponent(...) method. I would not override update(...) either as that's an AWT kludge and not for Swing graphics. I also try to avoid null layouts and setBounds(...) like the plague since that leads to inflexible, rigid GUI's that are very difficult to debug, maintain and enhance. For example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyMainPanel extends JPanel {
private MyDrawingPanel myDrawingPanel;
public MyMainPanel() {
try {
myDrawingPanel = new MyDrawingPanel();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new GridLayout(0, 1, 5, 5));
rightPanel.add(new JButton(new MyUpAction("Up", KeyEvent.VK_U)));
rightPanel.add(new JButton(new MyDownAction("Down", KeyEvent.VK_D)));
JPanel rightWrapPanel = new JPanel(new BorderLayout());
rightWrapPanel.add(rightPanel, BorderLayout.PAGE_START);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout());
add(myDrawingPanel, BorderLayout.CENTER);
add(rightWrapPanel, BorderLayout.LINE_END);
}
private class MyUpAction extends AbstractAction {
public MyUpAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
myDrawingPanel.up();
}
}
private class MyDownAction extends AbstractAction {
public MyDownAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
myDrawingPanel.down();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MyMainPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyDrawingPanel extends JPanel {
private static final String NEEDLE_IMG_PATH = "http://1.bp.blogspot.com/"
+ "-fq-oPGBSLp4/Ttoj7DoAMWI/AAAAAAAABtc/t7gKJlfRQuo/s400/secondHand.png";
private static final String ORANGE_DISK_IMG_PATH = "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Circle_Fulvous_Solid.svg/200px-Circle_Fulvous_Solid.svg.png";
private static final String GREEN_LINE_IMG_PATH = "http://www.xtremeskater.com/math/images/circle_radius.png";
private static final int MAX_DEGREES = 360;
private int imgWidth = 0;
private int imgHeight = 0;
private BufferedImage needleImg = null;
private BufferedImage orangeDiskImg = null;
private BufferedImage greenLineImg = null;
private BufferedImage backgroundImg = null;
private int degrees;
public MyDrawingPanel() throws IOException {
URL needleUrl = new URL(NEEDLE_IMG_PATH);
URL orangeDiskUrl = new URL(ORANGE_DISK_IMG_PATH);
URL greenLineUrl = new URL(GREEN_LINE_IMG_PATH);
needleImg = ImageIO.read(needleUrl);
orangeDiskImg = ImageIO.read(orangeDiskUrl);
greenLineImg = ImageIO.read(greenLineUrl);
imgWidth = Math.max(orangeDiskImg.getWidth(),
greenLineImg.getWidth());
imgHeight = Math.max(orangeDiskImg.getHeight(),
greenLineImg.getHeight());
backgroundImg = new BufferedImage(imgWidth, imgHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = backgroundImg.createGraphics();
drawBackground(g2, imgWidth, imgHeight);
g2.dispose();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(imgWidth, imgHeight);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, null);
}
AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(degrees),
this.getHeight() / 2, this.getWidth() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(needleImg, null), 0, 0, null);
}
public void up() {
degrees++;
degrees %= MAX_DEGREES;
repaint();
}
public void down() {
degrees--;
degrees += MAX_DEGREES;
degrees %= MAX_DEGREES;
repaint();
}
public int getDregrees() {
return degrees;
}
private void drawBackground(Graphics2D g2, int biWidth, int biHeight) {
int index;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(orangeDiskImg, 0, 0, null);
g2.drawImage(greenLineImg, 0, 0, null);
AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(6),
biWidth / 2, biHeight / 2);
for (index = 0; index < 60; index++) {
g2.transform(tx);
g2.drawImage(greenLineImg, 0, 0, null);
}
}
}
i have found the way to make the Background permanent, by first creating it into a Buffered image, then on each action, repaint that image, without redraw all the primitive forms or the image rotations. I mean, first, i create the Background rotating a basic image multiple times. This is created using a Buffered image. Then, on the paintComponent() method, i redraw the buffered image:
public MyPanel(){
try {
image = ImageIO.read(url1);
image2 = ImageIO.read(url2);
image3 = ImageIO.read(url3);
} catch (IOException e) {
}
img = createImage();
}
private Image createImage(){
double index = 0;
BufferedImage bufferedImage = new BufferedImage(370,370,BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
for(index = 0; index <= scale; index = index + count){
tx = AffineTransform.getRotateInstance(Math.toRadians(deg2), 185, 185);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image3, null), 0, 0, null);
deg2 = deg2 + (270.0/(scale/count));
}
return bufferedImage;
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image, 0, 0, null); //Indicator drawing
g.drawImage(img, 0, 0, null); //Scale drawing
//Indicator rotation
tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image2, null), 0, 0, null);
}
Here the complete code for a basic example:
package rotateOnImage;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.swing.Action;
public class MainFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private MyPanel panel = new MyPanel();
private final Action upAction = new upAction();
private final Action dnAction = new dnAction();
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFrame frame = new MainFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public MainFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 345, 227);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JButton btnNewButton = new JButton("UP");
btnNewButton.setAction(upAction);
btnNewButton.setBounds(212, 12, 117, 25);
contentPane.add(btnNewButton);
JButton button = new JButton("DN");
button.setAction(dnAction);
button.setBounds(212, 49, 117, 25);
contentPane.add(button);
panel.setBounds(0, 0, 200, 200);
contentPane.add(panel);
}
private class upAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = 1L;
public upAction() {
putValue(NAME, "UP");
}
public void actionPerformed(ActionEvent e) {
panel.up();
}
}
private class dnAction extends AbstractAction {
/**
*
*/
private static final long serialVersionUID = 1L;
public dnAction() {
putValue(NAME, "DN");
}
public void actionPerformed(ActionEvent e) {
panel.down();
}
}
}
class MyPanel extends JPanel{
private static final long serialVersionUID = 1L;
/**
*
*/
private int degrees = 0;
private AffineTransform tx = null;
private AffineTransformOp op = null;
private BufferedImage image1 = null;
private BufferedImage image2 = null;
private BufferedImage image3 = null;
Image img = null;
public static final String IMAGE_PATH1 = "http://1.bp.blogspot.com/"+"-fq-oPGBSLp4/Ttoj7DoAMWI/AAAAAAAABtc/t7gKJlfRQuo/s400/secondHand.png";
public static final String IMAGE_PATH2 = "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Circle_Fulvous_Solid.svg/200px-Circle_Fulvous_Solid.svg.png";
public static final String IMAGE_PATH3 ="http://www.xtremeskater.com/math/images/circle_radius.png";
public MyPanel(){
try {
URL url1 = new URL(IMAGE_PATH1);
URL url2 = new URL(IMAGE_PATH2);
URL url3 = new URL(IMAGE_PATH3);
image1 = ImageIO.read(url1);
image2 = ImageIO.read(url2);
image3 = ImageIO.read(url3);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
img = createImage();
}
public void up(){
degrees ++;
if(degrees == 360) degrees = 0;
repaint();
}
public void down(){
degrees --;
if(degrees == -360) degrees = 0;
repaint();
}
public int getDregrees(){
return degrees;
}
private Image createImage(){
double index = 0.0;
BufferedImage bufferedImage = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
for(index = 0.0; index <= 36; index ++){
tx = AffineTransform.getRotateInstance(Math.toRadians(index*10), 100, 100);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image3, null), 0, 0, null);
}
return bufferedImage;
}
public void update(Graphics g){
paint(g);
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image2, 0, 0, null); //Dibujado de la manecilla
g.drawImage(img, 0, 0, null); //Dibujado de la escala
//RotaciĆ³n de la manecilla
tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
g.drawImage(op.filter(image1, null), 0, 0, null);
}
}
I recently saw this question on how to rotate an image in Java. I copy/pasted it directly from that answer. On implementation, it seems to only rotate images that are squares(that is have the same size, width and height). When I try to use it for a non-square image, it seems to cut off that part that would make it be a rectangle, if that makes sense. Like this
How can I fix/work around this?
Edit: The code I'm using. Also, I won't have a scroll bar as this will be a "game", and also won't be in full screen all of the time.
public class Player extends Entity { //Entity has basic values such as (float) x & y values, along with some getters and setters
double theta;
Reticle reticle; //draws a reticle where the cursor was(basically just replaces java.awt.Cursor due to something not neccessary for me to get into)
Sprite currentImage; //basically just a BufferedImage that you can apply aspect ratios to
//constructor
#Override
public void tick() {
//(this line) gets the Reticle from the main-method class and set it to this reticle object
reticleX = reticle.getX(); //basically gets the mouse coordinates
reticleY = reticle.getY();
x += dX; //delta or change in X
y += dY //delta or change in Y
checkCollision(); //bounds checking
//getCentralizedX()/Y() gets the center of the currentImage
theta = getAngle(getCentralizedX(), getCentralizedY(), reticleX, reticleY);
currentImage = Images.rotateSprite(currentImage, theta);
}
#Override
public void render(Graphics g) {
currentImage.render(g, x, y);
g.drawLine((int) getCentralizedX(), (int) getCentralizedY(), (int) reticleX, (int) reticleY);
}
public double getAngle(float startX, float startY, float goalX, float goalY) {
double angle = Math.atan2(goalY - startY, goalX - startX);
//if(angle < 0) { //removed this as this was the thing messing up the rotation
//angle += 360;
//}
}
If the angle of the soldier is from 90 < angle < 270, then it is (basically), however, if its its 90 > angle > 270, then it gets a little wonky. Here are some pictures. It is not the angle of the aim-line(the blue line) that is wrong.
Removed all of the images as removing the if(angle < 0) inside of getAngle() fixed the rotation bug. Now the only problem is that it doesn't rotate in place.
EDIT 2: My SSCCE, which uses the same method as my game, but freaks out for some reason.
public class RotateEx extends Canvas implements Runnable {
Player player;
public RotateEx(BufferedImage image) {
player = new Player(image, 50, 50);
setPreferredSize(new Dimension(600, 600));
}
public void setDegrees(int degrees) {
player.theta = Math.toRadians(degrees);
}
public BufferedImage rotateImage(BufferedImage original, double theta) {
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = original.getWidth();
double height = original.getHeight();
int w = (int) (width * cos + height * sin);
int h = (int) (width * sin + height * cos);
BufferedImage out = new BufferedImage(w, h, original.getType());
Graphics2D g2 = out.createGraphics();
double x = w / 2; //the middle of the two new values
double y = h / 2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width) / 2;
y = (h - height) / 2;
at.translate(x, y);
g2.drawRenderedImage(original, at);
g2.dispose();
return out;
}
public void tick() {
player.tick();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
createBufferStrategy(4);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
player.render(g);
g.dispose();
bs.show();
}
public static void main(String args[]) throws IOException, InterruptedException {
String loc = "FILELOCATION"; //of course this would be a valid image file
BufferedImage image = ImageIO.read(new File(loc));
final RotateEx ex = new RotateEx(image);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int value = slider.getValue();
ex.setDegrees(value);
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(ex);
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
new Thread(ex).start();
}
#Override
public void run() {
long lastTime = System.nanoTime();
final double numTicks = 60.0;
double n = 1000000000 / numTicks;
double delta = 0;
int frames = 0;
int ticks = 0;
long timer = System.currentTimeMillis();
while (true) {
long currentTime = System.nanoTime();
delta += (currentTime - lastTime) / n;
lastTime = currentTime;
render();
tick();
frames++;
if (delta >= 1) {
ticks++;
delta--;
}
}
}
class Player {
public float x, y;
int width, height;
public double theta; //how much to rotate, in radians
BufferedImage currentImage; //this image would change, according to the animation and what frame its on
public Player(BufferedImage image, float x, float y) {
this.x = x;
this.y = y;
width = image.getWidth();
height = image.getHeight();
currentImage = image;
}
public void tick() {
currentImage = rotateImage(currentImage, theta);
}
public void render(Graphics g) {
g.drawImage(currentImage, (int) x, (int) y, null);
}
}
}
When you rotate an image the width and height also change and your code doesn't take this into account.
Here is some old code I have lying around that should work better:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation
{
BufferedImage image;
JLabel label;
public Rotation(BufferedImage image)
{
this.image = image;
}
private BufferedImage getImage(double theta)
{
// Determine the size of the rotated image
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = image.getWidth();
double height = image.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Rotate and paint the original image onto a BufferedImage
BufferedImage out = new BufferedImage(w, h, image.getType());
Graphics2D g2 = out.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0,0,w,h);
double x = w/2;
double y = h/2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width)/2;
y = (h - height)/2;
at.translate(x, y);
g2.drawRenderedImage(image, at);
g2.dispose();
return out;
}
private JLabel getLabel()
{
ImageIcon icon = new ImageIcon(image);
label = new JLabel(icon);
label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
private JSlider getSlider()
{
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage bi = getImage(Math.toRadians(value));
label.setIcon(new ImageIcon(bi));
}
});
return slider;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
Rotation r = new Rotation(bi);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(r.getLabel()));
f.getContentPane().add(r.getSlider(), "South");
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Edit:
Another option is to create an Icon, then you can use the Rotated Icon. Then you can rotate and paint the icon in your painting code. Something like:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation3 extends JPanel
{
private Icon icon;
private Icon rotated;
private int degrees;
public Rotation3(BufferedImage image)
{
icon = new ImageIcon( image );
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
double radians = Math.toRadians( degrees );
rotated = new RotatedIcon(icon, degrees);
// translate x/y so Icon is rotated around a specific point (300, 300)
int x = 300 - (rotated.getIconWidth() / 2);
int y = 300 - (rotated.getIconHeight() / 2);
rotated.paintIcon(this, g, x, y);
g.setColor(Color.RED);
g.fillOval(295, 295, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
double radians = Math.toRadians( degrees );
rotated = new RotatedIcon(icon, degrees);
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "dukewavered.gif";
ClassLoader cl = Rotation3.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
final Rotation3 r = new Rotation3(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Edit 2:
Even easier than I thought here is an example:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation2 extends JPanel
{
BufferedImage image;
int degrees;
int point = 250;
public Rotation2(BufferedImage image)
{
this.image = image;
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
double radians = Math.toRadians( degrees );
g2.translate(point, point);
g2.rotate(radians);
g2.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2.drawImage(image, 0, 0, null);
g2.dispose();
g.setColor(Color.RED);
g.fillOval(point - 5, point - 5, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
// String path = "mong.jpg";
String path = "dukewavered.gif";
ClassLoader cl = Rotation2.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
final Rotation2 r = new Rotation2(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
The rotation code was taken from: How to rotate an image gradually in Swing?
A far far easier way is to use the following library. Just call img.rotate(30) or whatever and it rotates, no messing about with AWT.
http://www.javaxt.com/javaxt-core/io/Image/
I am trying to make a java desktop application. I have a JLabel where I am shuffling image but all image sizes are different so I want to fix size of the image on JLabel.
How can I do this?
Here is my code :
public class ImageShuffle1 extends JPanel {
private List<Icon> list = new ArrayList<Icon>();
private List<Icon> shuffled;
private JLabel label = new JLabel();
private Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
public ImageShuffle1() {
this.setLayout(new GridLayout(1, 0));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\e.jpg"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\d.jpg"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\yellow.png"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\f.jpg"));
list.add(new ImageIcon("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\l.jpg"));
//label.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
for(Icon icon: list){
Image img = icon.getImage() ;
// put here the size properties
Image newimg = img.getScaledInstance( 45, 34, java.awt.Image.SCALE_SMOOTH ) ;
icon = new ImageIcon(newimg);
}
shuffled = new ArrayList<Icon>(list);
Collections.shuffle(shuffled);
timer.start();
}
private void update() {
if (shuffled.isEmpty()) {
shuffled = new ArrayList<Icon>(list);
Collections.shuffle(shuffled);
}
Icon icon = shuffled.remove(0);
label.setIcon(icon);
}
private void display() {
JFrame f = new JFrame("ImageShuffle");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(label);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageShuffle1().display();
}
});
}
}
I am getting error herein this.
line/variable getimage can not found mage img = icon.getImage() ;
Thanks in advance
Use BufferedImage in place of Icon that has a functionality to re size it.
Here is the code
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ImageShuffle1 extends JPanel {
private List<BufferedImage> list = new ArrayList<BufferedImage>();
private List<BufferedImage> shuffled;
private JLabel label = new JLabel();
private int width = 50;
private int height = 100;
private Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
public ImageShuffle1() {
try {
list.add(resizeImage(ImageIO.read(new File("resources/1.png"))));
list.add(resizeImage(ImageIO.read(new File("resources/2.png"))));
list.add(resizeImage(ImageIO.read(new File("resources/6.png"))));
list.add(resizeImage(ImageIO.read(new File("resources/Tulips.jpg"))));
} catch (IOException e) {
e.printStackTrace();
}
shuffled = new ArrayList<BufferedImage>(list);
Collections.shuffle(shuffled);
timer.start();
}
private BufferedImage resizeImage(BufferedImage originalImage) throws IOException {
BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
private void update() {
if (shuffled.isEmpty()) {
shuffled = new ArrayList<BufferedImage>(list);
Collections.shuffle(shuffled);
}
BufferedImage icon = shuffled.remove(0);
label.setIcon(new ImageIcon(icon));
}
private void display() {
JFrame f = new JFrame("ImageShuffle");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(label);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageShuffle1().display();
}
});
}
}
Lets start with this...
for(Icon icon: list){
Image img = icon.getImage() ;
Icon does not have a method getImage, there is actually no way to get the "image" data maintained by the Icon class without first rendering it to something (like a BufferedImage)
A better solution might be to load the images into a List that supports BufferedImage. BufferedImage is a more versatile starting point and because it extends from Image, it can be used with ImageIcon. For example...
private List<BufferedImage> list = new ArrayList<BufferedImage>();
//...
list.add(ImageIO.read("E:\\SOFTWARE\\TrainPIS\\res\\drawable\\e.jpg"));
Take a look at Reading/Loading an Image
For scaling you might like to take a look at
The Perils of Image.getScaledInstance
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
First you resize every image to a fixed size and it must be fit in JLabel
public static Boolean resizeImage(String sourceImage, String destinationImage, Integer Width, Integer Height) {
BufferedImage origImage;
try {
origImage = ImageIO.read(new File(sourceImage));
int type = origImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : origImage.getType();
//*Special* if the width or height is 0 use image src dimensions
if (Width == 0) {
Width = origImage.getWidth();
}
if (Height == 0) {
Height = origImage.getHeight();
}
int fHeight = Height;
int fWidth = Width;
//Work out the resized width/height
if (origImage.getHeight() > Height || origImage.getWidth() > Width) {
fHeight = Height;
int wid = Width;
float sum = (float)origImage.getWidth() / (float)origImage.getHeight();
fWidth = Math.round(fHeight * sum);
if (fWidth > wid) {
//rezise again for the width this time
fHeight = Math.round(wid/sum);
fWidth = wid;
}
}
BufferedImage resizedImage = new BufferedImage(fWidth, fHeight, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(origImage, 0, 0, fWidth, fHeight, null);
g.dispose();
ImageIO.write(resizedImage, "png", new File(destinationImage));
...
I want to draw a PARTIALLY transparent image on top of another (Making shadows over things). I am currently using java's Graphics2D class to render, I've been told to set the composite to AlphaComposite, but that only sets it completely transparent.
Can I do this with my current setup? What do I have to do to fix this?
This is the code I was told that would make it partially transparent:
AlphaComposite ac = java.awt.AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.5F);
g.setComposite(ac);
(I am using png images by the way)
Heres your sscce (these are all in different classes but i put them together for simplicity) (I use an image called "Test" in the local folder "Images", you can use whatever for this as long as it is a png Image named the same
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Window;
import javax.swing.ImageIcon;
import com.blazingkin.atrox.ScreenManager;
public class AtroxAdventrum{
public static void main(String[] args) {
new AtroxAdventrum().run();
}
private static DisplayMode modes[] = {
//new DisplayMode(1080,720,32,0),
//new DisplayMode(1080,720,24,0),
//new DisplayMode(1080,720,16,0),
//new DisplayMode(1440,900,32,0),
//new DisplayMode(1440,900,24,0),
//new DisplayMode(1440,900,16,0),
};
private boolean running = true;
public ScreenManager s;
public void stop(){
running = false;
}
public void run(){
try{
init();
gameLoop();
}finally{
s.restoreScreen();
}
}
public void init(){
s = new ScreenManager();
DisplayMode dm = s.findFirstCompatibleMode(modes);
s.setFullScreen(dm);
Window w = s.getFullScreenWindow();
w.setFont(new Font("Arial", Font.PLAIN, 20));
w.setBackground(Color.black);
w.setForeground(Color.white);
}
public void gameLoop(){
long startTime = System.currentTimeMillis();
long cumTime = startTime;
while (running)
{
long timePassed = System.currentTimeMillis() - cumTime;
cumTime += timePassed;
if (limitfps){
try{
Thread.sleep(15);
}catch(Exception e){}
}
update(timePassed);
Graphics2D g = s.getGraphics();
draw(g);
g.dispose();
s.update();
}
}
public void update(long timePassed){
}
public boolean limitfps = false;
public void draw(Graphics2D g){
g.clearRect(0, 0, s.getWidth(), s.getHeight());
AlphaComposite ac = java.awt.AlphaComposite.getInstance(AlphaComposite.CLEAR,0.5F);
g.setComposite(ac);
g.drawImage(new ImageIcon("Images/Test.png").getImage(), 30, 30, 30, 30, null);
}
}
If you run this you will have to alt + tab out and end the process (as it doesnt have anything in this portion of code to do such)
You're using the wrong rule -- don't use AlphaComposite.CLEAR.
The AlphaComposite API states this about CLEAR:
Both the color and the alpha of the destination are cleared (Porter-Duff Clear rule). Neither the source nor the destination is used as input.
So this will make the image disappear. Experiment with other rules. While you were creating your SSCCE, I created mine. See what happens when you comment out the one rule line for the other. For example change this
// int rule = AlphaComposite.CLEAR;
int rule = AlphaComposite.SRC_OVER;
to this:
int rule = AlphaComposite.CLEAR;
// int rule = AlphaComposite.SRC_OVER;
The whole SSCCE:
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class TestAlphaComposite extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Stroke BASIC_STROKE = new BasicStroke(6f);
BufferedImage backgroundImage;
BufferedImage overlayImage;
public TestAlphaComposite() {
backgroundImage = createBackGroundImage();
overlayImage = createOverlayImage();
}
private BufferedImage createBackGroundImage() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(BASIC_STROKE);
g2.setColor(Color.blue);
int circleCount = 10;
for (int i = 0; i < circleCount ; i++) {
int x = (i * PREF_W) / (2 * circleCount);
int y = x;
int w = PREF_W - 2 * x;
int h = w;
g2.drawOval(x, y, w, h);
}
g2.dispose();
return img;
}
private BufferedImage createOverlayImage() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(BASIC_STROKE);
g2.setColor(Color.red);
int circleCount = 10;
for (int i = 0; i < circleCount + 1; i++) {
int x1 = (i * PREF_W) / (circleCount);
int y1 = 0;
int x2 = PREF_W - x1;
int y2 = PREF_H;
float alpha = (float)i / circleCount;
if (alpha > 1f) {
alpha = 1f;
}
// int rule = AlphaComposite.CLEAR;
int rule = AlphaComposite.SRC_OVER;
Composite comp = AlphaComposite.getInstance(rule , alpha );
g2.setComposite(comp );
g2.drawLine(x1, y1, x2, y2);
}
g2.dispose();
return img;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImage != null) {
g.drawImage(backgroundImage, 0, 0, null);
}
if (overlayImage != null) {
g.drawImage(overlayImage, 0, 0, null);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("TestAlphaComposite");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TestAlphaComposite());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
By the way, your SSCCE isn't a true SSCCE. There's no way that any of us can compile or run that code as it has dependencies that we don't have access to, namely "com.blazingkin.atrox.ScreenManager". If you need our help in the future, you'll want to write better complying sscce's.