简体   繁体   中英

How do I rotate and draw a BufferedImage in Java?

I'm trying to develop a small rendering thing for a small project. I've gotten to a place where I can setup a Graphics2D object and call things from a simple render() loop, but when attempting to draw an image in place the image crops itself awkwardly and begins to lose data.

This is what I currently have in my draw function. Renderable is a pre-loaded BufferedImage.

    public void draw(Graphics2D g2d, int x, int y, int scale, int rotation) {
        scale = scale / 2;
        
        AffineTransform at = new AffineTransform();
        at.rotate(Math.toRadians(rotation), renderable.getWidth() / 2, renderable.getHeight() / 2);
        AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
        
        BufferedImage copy = op.filter(renderable, null);
                
        int pX = (400 - ((copy.getWidth() * scale) / 2)) + x;
        int pY = (300 - ((copy.getHeight() * scale) / 2)) + y;      
        
        g2d.drawImage(copy, pX, pY, copy.getWidth() * scale, copy.getHeight() * scale, null);
    }

When the rotation is not divisible by 90

When the rotation is divisible by 0, 90, 180, or 270

Is there something I am missing or should be doing differently? It appears to me that the image is losing data. The Graphics2D object passed into the function is the same one used to render the lines behind the checkered square and should cover the full Canvas, which is 800x600 pixels.

Update

        int rotation = 0;
        
        while (EngineGlue.isValid()) {
            rotation = rotation + 15;
            if (rotation >= 360) {
                rotation = 0;
            }
            
            Graphics2D g2d = (Graphics2D)EngineGlue.getInstance().getCanvas().getBufferStrategy().getDrawGraphics();
            g2d.clearRect(0, 0, 800, 600);
            
            g2d.drawLine(0, 300, 800, 300);
            g2d.drawLine(400, 0, 400, 600);
                        
            //ta1.draw(g2d, -100, 0, 2, rotation);
            //ta2.draw(g2d, 100, 0, 3, -rotation);
            ta3.draw(g2d, 0, 0, 1, rotation);
            
            EngineGlue.getInstance().getCanvas().getBufferStrategy().show();
            Thread.sleep(150);
        }
            frame = new JFrame(title);
            canvas = new Canvas();
            
            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            frame.setResizable(false);
            frame.setVisible(true);
            frame.add(canvas);
            frame.pack();
            frame.setSize(EngineGlue.Dimension.WIDTH.getValue(), EngineGlue.Dimension.HEIGHT.getValue());
            frame.setLocationRelativeTo(null);
            
            canvas.setSize(EngineGlue.Dimension.WIDTH.getValue(), EngineGlue.Dimension.HEIGHT.getValue());
            canvas.createBufferStrategy(3);

You can use an AffineTransform to rotate and scale the image:

import java.awt.*;
import java.util.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.*;
import java.awt.geom.*;
import java.awt.image.*;

public class RotateAndScale extends JPanel
{
    private Image image;

    public RotateAndScale(Image image)
    {
        this.image = image;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
         super.paintComponent(g);

         // create the transform, note that the transformations happen
         // in reversed order (so check them backwards)
         AffineTransform at = new AffineTransform();

         // 4. translate it to the center of the component
         at.translate(getWidth() / 2, getHeight() / 2);

         // 3. do the actual rotation
         at.rotate(Math.toRadians(45));

         // 2. scale the image
         at.scale(0.5, 0.5);

         // 1. translate the object to rotate around the center
         at.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);

         // draw the image
         Graphics2D g2d = (Graphics2D) g;
         g2d.drawImage(image, at, null);

         // continue drawing other stuff (non-transformed)
         //...
    }

    private static void createAndShowGUI()
    {
        try
        {
            BufferedImage image = ImageIO.read(new File("splash.gif"));

            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add( new RotateAndScale(image));
            frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            frame.setSize(400, 400);
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
        catch(Exception e) { System.out.println(e); }
    }

    public static void main(String[] args) throws Exception
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}

Above is code I found somewhere a long time ago.

If you just want to rotate an image, the easiest way is to rotate the graphics context rather than the image itself. This reads in an image of Mars so you'll have to substitute your own image.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class RotateImage extends JPanel {
    
    JFrame frame;
    int width;
    int height;
    
    BufferedImage b = null;
    String imageFile = "f:/redmarble.jpg";

    public RotateImage() {
        frame = new JFrame();
        setPreferredSize(new Dimension(width, height));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(this);
        
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new RotateImage().startup());
    }
    
    public Dimension getPreferredSize() {
        return new Dimension(width, height);
    }
    
    public void startup() {
        try {
            b = ImageIO.read(new File(imageFile));
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
       // calculate the diagonal of the image to size the panel
       // this allows all rotations to fit within the panel
        double diag = Math.hypot(b.getHeight(), b.getWidth());      
        width = (int) diag;
        height = (int) diag;
        
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        repaint();
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (b == null) {
            return;
        }
        
        Graphics2D g2d = (Graphics2D) g.create();
        
        // set the angle of rotation and the center of rotation to the middle of the
        // panel - width and height are equal but I still like to reference them
        // independently (could save debugging time in the future).
        g2d.rotate(Math.toRadians(45), width/2, height/2);
        
        // now draw the image, adjusting  x,y starting point to ensure rotation
        // about the center.
        g2d.drawImage(b, (width-b.getWidth())/2, (height-b.getHeight())/2,null);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM