kevingreen
kevingreen

Reputation: 1541

Java, using AffineTransform not rotating exactly centered

I'm trying to rotate an image, but it's getting slightly messed up when I'm rotating it, and it looks like it's not rotating it on center. So if I go around it looks like it's being truncated. Is there a better method to get the "center" of the image?

public void RotateImageLeft() {
    try {
        BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), originalImage.getType());
        AffineTransform tx = new AffineTransform();
        tx.rotate(Math.toRadians(-90.0), originalImage.getWidth() / 2, originalImage.getHeight() / 2);



        Graphics2D g2 = newImage.createGraphics();
        g2.drawImage(originalImage, tx, null);

        originalImage = newImage;


        this.repaint();

        g2.dispose();
    } catch (Exception ex) {
        ex.toString();
    }


    //g2d.drawImage(getResImage(), rescale, x, y);


}

For full code disclosure, here's more code. Here's my painComponent overridden method:

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    resizeImage();

    Graphics2D g2d = (Graphics2D) g;
    g2d.drawImage(getResImage(), rescale, x, y);


}

Here's the resizeImage() method that gets called:

public void resizeImage() {
    Graphics g = getResImage().getGraphics();
    g.setColor(Color.WHITE);

    g.fillRect(0, 0, getResImage().getWidth(), getResImage().getHeight());
    int scaledWidth = (int) ((getOriginalImage().getWidth() * getHeight()
            / getOriginalImage().getHeight()));
    if (scaledWidth < getWidth()) {
        int leftOffset = getWidth() / 2 - scaledWidth / 2;
        int rightOffset = getWidth() / 2 + scaledWidth / 2;

        g.drawImage(getOriginalImage(),
                leftOffset, 0, rightOffset, getHeight(),
                0, 0, getOriginalImage().getWidth(), getOriginalImage().getHeight(),
                null);
    } else {
        int scaledHeight = (getOriginalImage().getHeight() * getWidth())
                / getOriginalImage().getWidth();

        int topOffset = getHeight() / 2 - scaledHeight / 2;
        int bottomOffset = getHeight() / 2 + scaledHeight / 2;

        g.drawImage(getOriginalImage(),
                0, topOffset, getWidth(), bottomOffset,
                0, 0, getOriginalImage().getWidth(), getOriginalImage().getHeight(),
                null);
    }
}

I'm using the ResizeImage method since I want any image to fit correctly on my 720/432 panel.

Here's some example pictures. Pre-rotated enter image description here

Post-rotated:

enter image description here

New code: (new image is the correct height/width of rotated image, still getting black bars. Screens below.

public void RotateImageLeft() {
    try {
        BufferedImage newImage = new BufferedImage( originalImage.getHeight(),originalImage.getWidth(), originalImage.getType());
        AffineTransform tx = new AffineTransform();
        tx.rotate(Math.toRadians(-90.0), newImage.getWidth() / 2, (newImage.getHeight() / 2));
        Graphics2D g2 = newImage.createGraphics();
        g2.drawImage(originalImage, tx, null);
        originalImage = newImage;
        this.repaint();
        g2.dispose();
    } catch (Exception ex) {
        ex.toString();
    }
}

Post rotate: enter image description here

Upvotes: 2

Views: 4513

Answers (2)

Adam
Adam

Reputation: 36743

From my answer to another similar question

If you're rotating then this will work for 90 degrees.

  • move image so centered "around" the origin
  • plain rotate() call with no extra parameters
  • Move image back into the center remembering that now width = old height and height = old width.

Also remember the affine transform steps work in reverse order.

AffineTransform tx = new AffineTransform();

// last, width = height and height = width
tx.translate(originalImage.getHeight() / 2,originalImage.getWidth() / 2);
tx.rotate(Math.PI / 2);
// first - center image at the origin so rotate works OK
tx.translate(-originalImage.getWidth() / 2,-originalImage.getHeight() / 2);

Upvotes: 3

Thomas
Thomas

Reputation: 3381

If you want to rotate an image without cropping you need to add black bars around it first, since a rotated rectangle will always have a bigger bounding box than an axis-aligned one (exception: rotating a square by multiples of 90 degrees).

So what you want to do is do some trigonometric calculations beforehand to decide the maximum Width/Height of the rotated image, and combine that with the original Width/Height. Resize your image (centering it) using those dimensions, rotate it, and then crop it back to the Width/Height of the rotated image.

Upvotes: 1

Related Questions