Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.
Toon posts:

[JAVA] Roteren van een resized BufferedImage

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hoi allemaal,

Ik heb het volgende probleem.
Een BufferedImage, met daarop een tekening, is geplaatst op het canvas van een JPanel.
Middels de muis is de gebruiker in staat deze image te verplaatsen en te roteren. Ook kan hij het formaat van de image wijzigen.

Het wijzigen van het formaat betekent het wijzigen van de size van de image en de daarbij horende canvas (er zijn dus meer pixels; stel dat ik een rechthoek teken op het canvas van de BufferedImage, dan kan deze nu groter zijn). Het betreft dus geen AffineTransform.scale operatie (deze vergroot de BufferedImage).

Wanneer de gebruiker de image vergroot 'naar het noorden' en de image is niet geroteerd dan betekent dit dus dat het punt waar de image getekend wordt naar boven gaat en de totale hoogte van de image toeneemt. Dit werkt goed.

Roteren doe ik als volgt:
- Roteer de canvas middels een AffineTransform in het centrum van de image
- Teken de image

Als ik op deze manier de image roteer zodat de bovenkant van het plaatje naar beneden wijst, en de gebruiker probeert de image dan te resizen 'naar het noorden' (op het scherm is dit nu dus naar het zuiden) dan gaat het fout: omdat ik de origin van de image naar boven verplaats tekent hij nu de image te ver naar boven.

Ik zoek eigenlijk een manier om een BufferedImage te tekenen op een canvas en dáárna de viewport als het ware te roteren. Op die manier zou het volgens mij wel goed moeten gaan.

Onderstaand een sterk vereenvoudigd stuk voorbeeld code.
Er wordt een rechthoek getekend met een stip die de bovenkant aangeeft (op een BufferedImage dus). Door op 'R' te drukken roteert de rechthoek 90 graden en door op een van de pijltjestoetsen te drukken wordt de image groter.

Iemand enig idee hoe ik dit op kan lossen ?

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

/*****************************************************************************
 * Creates a BufferedImage that displays a simple image.
 * 
 * This Image will can be rotated 1/2 PI degrees by pressing 'R'.
 * By pressing any of the arrow-keys, the image is resized as if stretching
 * the top of the image. (i.e. in the original, non-rotated, image it 
 * simply moves the origin of the image and increases the height).
 *****************************************************************************/
public class ImageTest extends JPanel implements KeyListener
{
   double theta = 0.0; // rotation angle
   
   Point origin = new Point(50,50); // origin of the image 
   Dimension size = new Dimension(100,100); // size of the image
   
   public static void main(String[] args)
   {
      JFrame mainFrame = new JFrame("Image Tester");
      ImageTest imageTest = new ImageTest();
      mainFrame.getContentPane().add(imageTest);
      mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mainFrame.setSize(400,400);
      mainFrame.show();
      mainFrame.addKeyListener(imageTest);
   }
   
   // draw the image on the JPanel
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      
      // create a BufferedImage and draw something on it (a rectangle)
      BufferedImage image = 
         new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
      Graphics g2 = image.createGraphics();
      g2.drawRect(0, 0, size.width - 1, size.height - 1);
      g2.fillOval(size.width / 2, 0, 3, 3); // draw a little 'north' indicator
      g2.dispose();
      
      // now rotate g 
      Graphics2D g2d = (Graphics2D)g;
      g2d.rotate(theta, 
                 origin.x + size.width / 2.0, 
                 origin.y + size.height / 2.0);
      
      // and draw the image on the specified origin
      g2d.drawImage(image, origin.x, origin.y, null);
   }

   /*******************************************************************************
    * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
    *******************************************************************************/
   public void keyPressed(KeyEvent arg0)
   {
      switch(arg0.getKeyCode())
      {
         case (KeyEvent.VK_R):
            // rotate! add 1 / 2 PI degrees of rotation
            theta += Math.PI / 2;
            repaint();
            break;
         case (KeyEvent.VK_LEFT):
         case (KeyEvent.VK_RIGHT):
         case (KeyEvent.VK_DOWN):
         case (KeyEvent.VK_UP):
            // make the image 5 pixels larger
            origin.y = origin.y - 5;
            size.height += 5;
            repaint();
            break;
      }
   }

   /*******************************************************************************
    * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
    *******************************************************************************/
   public void keyReleased(KeyEvent arg0)
   {}

   /*******************************************************************************
    * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
    *******************************************************************************/
   public void keyTyped(KeyEvent arg0)
   {}
}

  • Cascade
  • Registratie: Augustus 2006
  • Laatst online: 11-11 11:41
Niet helemaal thuis in Java, maar ik doe een poging.

Je past nu de transformatie toe op het Graphics object zelf, dat bepaalt hoe de image wordt weergeven. De image zelf is eigenlijk niet geroteerd. Kan je dan die transformatie niet al op je image object loslaten ipv op de weergave?

Of, nog anders (simpeler): kan je na je drawImage niet gewoon je rotate op '0' zetten?

Verwijderd

Topicstarter
De image zelf moet ook niet geroteerd zijn, deze heeft zijn eigen coordinaten. Ik wil gewoon een BufferedImage hebben die op verschillende rotaties getoond kan worden (dus één plaatje).

rotate op '0' zetten na drawImage zou als resultaat hebben dat hij hem één keer roteert en daarna normaal weergeeft.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:04

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op dinsdag 05 augustus 2008 @ 10:30:
rotate op '0' zetten na drawImage zou als resultaat hebben dat hij hem één keer roteert en daarna normaal weergeeft.
Nee. Dat soort functies zijn meestal cumulatief, en de documentatie van rotate() impliceert dat ook:
Concatenates the current Graphics2D Transform with a translated rotation transform
.
Na de drawImage dus een rotatie van 0 doen zal de oude transformatie dus behouden. Als je echt de transformatie wilt resetten moet je een setTransform() doen met een identity matrix. Of natuurlijk gewoon een AffineTransform.getRotateInstance() als je een nieuwe rotatie in wilt stellen.

Maar goed, het probleem waar je tegenaan loopt is dat je roteert om de plek waar het plaatje terecht komt in default space, en vervolgens de linkerbovenhoek wilt specificeren waar begonnen moet worden met tekenen met coordinaten in de getransformeerde space. Dit is onhandig, omdat je feitelijk de linkerbovenhoek mee moet roteren om de juiste coordinaten te krijgen.
Begin eerst eens met instellen van een translatie van (-width/2, -height/2) op het Graphics2D object. Als je nu je image wilt gaan tekenen dan zal het midden van je image op de gegeven coordinaten terecht komen. Als je je image geroteerd wilt tekenen, dan kan dat door een extra rotatie toe te voegen om het nulpunt. Je moet natuurlijk wel even je origin anders initializeren omdat het nu het middelpunt voorstelt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
Ik weet dat ze cumulatief zijn.
Ik maak dan ook telkens een nieuw Graphics object waarop ik vervolgens een rotate transformatie uitvoer. Is dus niet cumulatief in mijn geval.

De probleem-oplos suggestie ga ik nu proberen, ik laat weten of het gelukt is.

Verwijderd

Topicstarter
Ik begrijp geloof ik niet helemaal wat je bedoelt met dit:
Begin eerst eens met instellen van een translatie van (-width/2, -height/2) op het Graphics2D object. Als je nu je image wilt gaan tekenen dan zal het midden van je image op de gegeven coordinaten terecht komen. Als je je image geroteerd wilt tekenen, dan kan dat door een extra rotatie toe te voegen om het nulpunt. Je moet natuurlijk wel even je origin anders initializeren omdat het nu het middelpunt voorstelt.
Hoe bedoel je dat ik de image nu kan roteren door een rotatie om het nulpunt uit te voeren?
Dat gaat inderdaad, maar aangezien die rotatie om het nulpunt is verdwijnt mijn rechthoek uit de viewport.

Zou je misschien kunnen aangeven hoe jouw suggestie eruit zou zien in mijn voorbeeldcode?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:04

.oisyn

Moderator Devschuur®

Demotivational Speaker

Uh juist ja, foutje. De coordinaten die je meegeeft om te tekenen moeten natuurlijk ook ongetransformeerd zijn.

Alleen nu ik het zo nog een keer nalees, met de beschrijving van het Graphics2D object van de Java API erbij, snap ik het probleem niet helemaal? Volgens mij doet je code zoals je die nu hebt al een goede transformatie, alleen vind jij dat geen goede transformatie, dus blijkbaar begrijp ik je probleem niet. Wat jouw code doet is altijd roteren om het middelpunt van de image. Maar je wilt dat dat rotatie eigenlijk niet het middelpunt is, maar gewoon op een vast punt op het onvergrootte vierkant blijft?

Als dat zo is, dan kun je het beste een aparte center bijhouden. Die staat standaard op (50,50), maar als je aan de bovenkant y units erbij doet wordt dat dus (50,50+y). Tel dat bij je origin op voor je rotatiepunt, en dan doet het waarschijnlijk wat je wilt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1