Zoomen mit AffineTransform

Stefan774

Grünschnabel
Es gibt zwar schon Beiträge die sich mit dem Zoomen eines Images befassen aber ich hab kein Problem mit dem vergrößern des img sondern mit dem Anpassen der X und Y-Koordinaten.

Ich möchte ganz einfach ein Image Zoomen und es sollte so gezoomt werden als währe der Koordinatenursprung in der Mitte des Images.
Da aber der Ursprung in der linken oberen Ecke liegt sieht es so aus als würde das Img nach rechts unten aus dem Bildschirmfliegen.
Führ eine Antwort währe ich sehr dankbar (bin noch ein newbie in Java)

Ach und hier mal mein Ansatz mit dem Zomm und AffineTransform

PHP:
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;


public class Star {
	
	
	public double zoom;
	public int posX;
	public int posY;
	public int n=0;
	protected BufferedImage img;
	public mainStar st;
	
	public SpriteCache sprite;
	AffineTransform trans = new AffineTransform();
	
	public Star (){ 
		sprite = new SpriteCache();
		img = sprite.getSprite("bicho.gif");
	}
	
	public void paint(Graphics2D g){

		g.setTransform(trans);
		g.drawImage(img,posX,posY,st);

	}
	
	public void setZoom(double z){zoom = z;}
	public void setpositionX(int pX){posX = pX;}
	public void setpositionY(int pY){posY = pY;}
	public double getPositionX(){return posX;}
	public double getPositionY(){return posY;}
	
	public void fly(){
		trans.scale(zoom, zoom);
//		posX-=trans.getScaleX();    // genau hier hab ich probleme ich komm einfach
// 	        posY-=trans.getScaleY();  // nicht drauf wie man das anpasst 
	}

	public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
		// TODO Auto-generated method stub
		return false;
	}
	
}

Und was mir noch aufgefallen ist daß wenn ich mein Image an der posX=0 und posY=0 zeichnen lasse bleibt das Bild auf den gleichen Koordinaten. Wenn ich aber die Koordinaten verändere (d.h. einen anderen Wert als 0 wähle) scheint es zu wandern also auch wieder nach rechts unten. Ist doch echt komisch da ich die Koordinaten nicht verändere.
 
Zuletzt bearbeitet:
Hallo Stefan,

wenn Du die Transformation direkt an das Graphics-Object ansetzt, wird die ganze Fläche skaliert und nicht nur das Image. Deswegen das komische Verhalten, das Du beschrieben hast. Wenn Du nur das Bild skalieren willst, kannst Du einfach mit der Methode getScaledInstance() der Klasse Image arbeiten und Dir immer eine skalierte Instanz von dem Image holen, abhängig von dem aktuellen Skalierungsfaktor.

Hier ein kleines Beispiel, das meinen Ansatz veranschaulichen soll:
Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
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.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * The Class ScaleImageTest.
 */
public class ScaleImageTest extends JFrame {
    private double scaleFactor = 1.0;
    private BufferedImage sourceImage;

    /**
     * Create a new instance of <code>ScaleImageTest</code>.
     */
    public ScaleImageTest() {
        super("ScaleImageTest");
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

		try {
			sourceImage = ImageIO.read(new File("duke_skateboard.jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
        final JPanel panel = new JPanel() {
        	protected void paintComponent(Graphics g) {
				final Graphics2D g2D = (Graphics2D) g;
        		final Dimension panelSize = getSize();
        		final int width = panelSize.width;
        		final int height = panelSize.height;
        		g.setColor(Color.WHITE);
        		g.fillRect(0, 0, width, height);
        		g.setColor(Color.BLACK);
        		g.drawLine(width / 2, 0, width / 2, height);
        		g.drawLine(0, height / 2, width, height / 2);
        		
        		final int imageWidth = 
        			(int) (sourceImage.getWidth() * scaleFactor);
        		final int imageHeight = 
        			(int) (sourceImage.getHeight() * scaleFactor);
        		final int imageX = width / 2 - imageWidth / 2;
        		final int imageY = height / 2 - imageHeight / 2;
        		final Image image = sourceImage.getScaledInstance(
        				imageWidth, imageHeight, Image.SCALE_SMOOTH);
        		g2D.drawImage(image, imageX, imageY, null);
        	}
        };
        final JSlider slider = new JSlider(0, 200);
        slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				final int value = slider.getValue();
				if (value > 0) {
					scaleFactor = (double) value / 100.0;
					panel.repaint();
				}
			}
        });
        getContentPane().add(panel, BorderLayout.CENTER);
        getContentPane().add(slider, BorderLayout.SOUTH);
    }

    /**
     * The main method.
     *
     * @param args the arguments
     */
    public static void main(String[] args) {
        final JFrame frame = new ScaleImageTest();
        final Dimension frameSize = new Dimension(600, 400);
        frame.setSize(frameSize);
        final Dimension screenSize =
            Toolkit.getDefaultToolkit().getScreenSize();
        final int frameX = (screenSize.width - frameSize.width) / 2;
        final int frameY = (screenSize.height - frameSize.height) / 2;
        frame.setLocation(frameX, frameY);
        frame.setVisible(true);
    }    
}
Hier das Image, damit das Beispiel funktioniert: duke_skateboard.jpg

Hoffe, das hilft Dir weiter.

Grüße
Vincent
 
Danke für die schnelle Antwort Vincentius!!

Ich werd mich gleich mal dran machen aber das was du sagst erklärt natürlich einiges wenn ich die komplette Ebene Zoome (skaliere) dann versteh ich auch warum sich das Image so verhält.
 
Hallo,

ich wollte nur anmerken, dass der Aufruf von getScaledInstance bei großen Bilder sehr schlecht ist, was die Leistung angeht. Diese Methode stammt noch aus den Urzeiten von Java (JDK 1.0).
Die bessere Methode wäre diese:

Java:
public BufferedImage scale( Image p_image, double p_dScaleFactor )
{
    // calculate new width and height
    int iWidth = ( int ) ( p_image.getWidth(null)*p_dScaleFactor );
    int iHeight = ( int ) ( p_image.getHeight(null)*p_dScaleFactor );

    // create a BufferedImage instance
    BufferedImage bufferedImage = new BufferedImage( iWidth, iHeight, BufferedImage.TYPE_INT_RGB );

    // create the image's graphics
    Graphics2D g = bufferedImage.createGraphics();

    // Drawing hints with focus on quality
    g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
    g.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
    g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC );

    // Apply scalefactor
    g.drawImage( p_image, 0, 0, iWidth, iHeight, null );

    return bufferedImage;
}
Das Augenmerk liegt hier auf der Qualität. Die RenderingHints können auch anders gewählt werden um eine bessere Performance zu erreichen (z.B. VALUE_INTERPOLATION_NEAREST_NEIGHBOR). Hierzu findet sich auch ein sehr schöner Artikel (leider in englischer Sprache) auf java.net.

Viel Spaß beim Ausprobieren :)
 
Zurück