2D-Grafik BufferedImage sauber rotieren

Luk10

Top Contributor
Grüße,

Ich habe ein BufferedImage das eine 50x50 Png Datei enthält. Nun will ich diese Image in einem bestimmten Winkel drehen.

Dabei stoße ich auf folgende Probleme:
- Gibt es eine Methode, die das einfach für mich lösen kann? Habe keine passende in der API gefunden
- Da das Image quadratisch ist, und von der Position (x, y) nicht verändert werden soll muss der Bezugpunkt des Images geändert werden

Hier eine Skizze dazu:

Das dünner Quadrat ist nur gedacht!
Die Quadrate sollen gleich große sein ... mein MSPaint ist nicht so prall :autsch:

rotieren.png


Kann mir jemand Tipps geben wie sich das machen lässt?

Danke,
-Luk10-
 
Java Platform SE 6

[noparse]
-> http://download.oracle.com/javase/6/docs/api/java/awt/Graphics2D.html#rotate(double, double, double)

-> http://download.oracle.com/javase/6/docs/api/java/awt/Graphics.html#drawImage(java.awt.Image, int, int, java.awt.Color, java.awt.image.ImageObserver)
[/noparse]

...Profit !
 
Zuletzt bearbeitet:
Hm komisch dass ich diese Methode nicht gefunden habe ...
Danke dafür!

Wie sieht das mit dem oben agesprochenen Problem des Bezugpunktes aus? Man gibt ja nur Werte zur Rotation selbst an? Wie wird der gewählt?

-Luk10-
 
Das bedeutet also, wenn ich bei einem 50x50 Pixel Image rotieren an 0, 0 um 90° ist der Bezugspunkt bei 50, 0?

Das wäre ja nicht das ich will ...
 
Hmja, das hilft ja alles nichts: Das Bild muss ja auch verschoben werden, und man muss ausrechnen, wie groß das Zielbild sein muss, damit das gedrehte Bild reingemalt werden kann. Alles nicht schwierig, aber ein paar mehr Infos, WIE genau das am Ende aussehen soll, wären nicht verkehrt...Dann kann man da bei Gelegenheit mal die paar Zeilen zusammenhacken...
 
Für die Bildgröße hab ich noch das hier rumliegen:
Java:
    /**
     * Rotiert ein Rechteck und gibt die Maße des neuen umfassenden Rechtecks aus
     * @param data Das Rechteck, [0] = width; [1] = height. Dieses Array wird mit den Ergebnissen gefüllt !
     * @param angle Bogenmass der Drehung
     * @return ein float[2]; [0] = width; [1] = height. Es wird das Array, welches als data übergeben wird, bearbeitet.
     */
    public static float[] rotateDimension(float[] data, float angle) {
        if (data == null || data.length != 2) {
            throw new IllegalArgumentException("The data-array needs to have a length of 2 !!!");
        }
        double sinAngle = sin(angle);
        double cosAngle = cos(angle);
        float d0 = data[0];
        data[0] = (float) (abs(cosAngle * data[0]) + abs(sinAngle * data[1]));
        data[1] = (float) (abs(sinAngle * d0) + abs(cosAngle * data[1]));
        return data;
    }
Hab den Code mal irgendwo verwendet, sollte funktionieren.
Keine Ahnung, ob es dafür auch schon was in der API gebe...

Verschoben muss es nicht werden ?
Der Ablauf sollte sein:
-Berechne Größe des neuen Bildes.
-Lege neues Bild an.
-Zeichne altes Bild auf neues Bild mit der gewünschten Rotation.
 
Es soll nur rotiert werden und seine eigentliche Position (Also die man auf dem Screen sieht) nicht verändern.

Was aber verändert werden muss ist folgendes:

- Bei einem "normalen" Image zeichnet mir drawImage(x, y) das Image bei de Koordinaten x, y ausgehend von links oben des Images (0, 0 des Images)

- Wenn ich diese Image nun rotiere (in der mitte) wird dieser Punkt wohl auch mitrotiert. Somit wird bei drawImage(x, y) das Image an eine andere Position gezeichnet. Das will ich nicht.

Was ich will ist folgendes:

- Ich hab eine (vereinfacht) Ellipse in einem 50x50 Image. Diese soll nun um z.B. 48° im Uhrzeigersinn, im Mittelpunkt des 50x50 Images gedreht werden.

- Dabei soll
+ die Position der Ellipse, abgesehen von ihrer Ausrichtung nicht verändert werden
+ die Ellipse möglichst einfach mit drawImage(x, y) gezeichnet werden

- Dabei stelle ich mir vor,
+ dass es am einfachsten ist 0, 0 des Images "neu zu setzten" um einfach mit drawImage zu zeichnen
+ dass um das Image ein vorgestelltes Quadrat zu legen, welches paralell zu den x, y Achsen ist und somit wieder normal funktioniert

Wie genau sich das umsetzten lässt weiß ich nicht. Deshalb frage ich hier.

Den Code von Cola, danke dafür, verstehe ich so nicht ... ich werde ihn trotzdem bei Gelegenheit mal testen.

Danke,
-Luk10-
 
Hmja, nochmal: Wenn du in dem Bild im ersten Post mal den Mittelpunkt der Quadrate einzeichnest, wirst du sehen, dass der Mittelpunkt sich (bezogen auf (0,0)) nach rechts unten bewegt hat. Mir ist auch noch nicht klar, ob du ein Bild drehen willst, oder nur ein gedrehtes Bild zeichnen willst.
 
Sowas ?

Java:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.JFrame;


/**
 *
 * @author Colin Clausen
 */
public class TestFrame extends JFrame{
    
    public static void main(String[] img) throws IOException, InterruptedException {
        BufferedImage image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, 50, 50);
        
        TestFrame frame = new TestFrame(image);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setSize(400, 400);
        frame.setVisible(true);
        while(true) {
            frame.draw();
            Thread.sleep(100);
        }
    }
    
    private RotatingImage panelImg;
    
    public TestFrame (Image img) throws IOException {
        panelImg = new RotatingImage(img);
        this.add(panelImg);
    }
    
    public void draw() {
        panelImg.incAngle();
        panelImg.repaint();
    }
}

Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import javax.swing.JPanel;


/**
 *
 * @author Colin Clausen
 */
public class RotatingImage extends JPanel{
    private Image srcImage;
    // Bogenmaß !
    private float angle;
    
    public RotatingImage(Image img) {
        srcImage = img;
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, getWidth(), getHeight());
        AffineTransform transform = g2d.getTransform();
        
        g2d.rotate(angle, getWidth()/2, getHeight()/2);
        g2d.drawImage(srcImage, getWidth()/2 - srcImage.getWidth(null)/2,
                getHeight()/2 - srcImage.getHeight(null)/2, null);
        
        g2d.setColor(Color.RED);
        g2d.fillOval(getWidth()/2 - 1, getHeight()/2 - 1, 2, 2);
        
        g2d.setTransform(transform);
    }

    public void incAngle() {
        angle += 0.1f;
    }
}
 
Danke für das Beispiel.

Damit kann ich mal schaun wie ich das auf meine Situation übertragen kann.

Da ich mir den Code jetzt noch nicht besonders intensiv angeschaut habe, da ich gerade an etwas anderem arbeite, kannst du mir kurz sagen, ob man nach dem rotieren einfach wieder mit
Code:
drawImage(x, y)
das Image zeichnen kann oder ob man da einen Ausgleich wie
Code:
drawImage(x+a, y+b)
machen muss.

Vielen Dank für deine Mühe!
-Luk10-
 
einfach Zeichnen. Der Ausgleich in meinem Code rührt daher, dass ich das Bild mittig aufs Panel zeichnen will.
drawImage erwartet aber die linke obere Ecke des Bildes.
 
Dann wirst du wohl die Position des Bildes verwenden müssen....

Um es zu verdeutlichen:
Java:
    @Override
    protected void paintComponent(Graphics g) {
        int imageMiddleX = getWidth()/2;
        int imageMiddleY = getHeight()/2;

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, getWidth(), getHeight());
        AffineTransform transform = g2d.getTransform();
        
        g2d.rotate(angle, imageMiddleX, getHeight()/2);
        g2d.drawImage(srcImage, imageMiddleX - srcImage.getWidth(null)/2,
                imageMiddleY - srcImage.getHeight(null)/2, null);
        
        // Zeigt nur den Mittelpunkt auf
        g2d.setColor(Color.RED);
        g2d.fillOval(imageMiddleX - 1, imageMiddleY - 1, 2, 2);
        
        g2d.setTransform(transform);
    }

imageMiddleX und Y kannst du einsetzen was immer du willst....
So und jetzt probiere es eben einfach mal aus ;P

Ich denke ich habe eine Vorstellung, von dem was du machen willst und die hier genannten Mittel reichen dazu aus.
 

Neue Themen


Zurück
Oben