HOWTO · Java

在 Java 中旋轉影象

這篇文章說明了如何在 Java 中旋轉影象

本頁內容

本文將介紹我們如何使用兩種原生方式在 Java 中旋轉影象。

在 Java 中使用 BufferedImage 和 Graphics2D.rotate() 旋轉影象

第一種旋轉影象的方法包括使用 AWT 包附帶的 BufferedImage 和 Graphics2d 類。下面我們建立一個函式 rotateImage(),它接收一個 BufferedImage 物件作為引數並返回一個旋轉的 BufferedImage 物件。

在 rotateImage() 中,我們使用 getWidth()、getHeight() 和 getType() 方法獲取影象的寬度、高度和型別。現在我們呼叫 BufferedImage() 建構函式並將三個變數作為引數傳遞,它返回一個 BufferedImage 物件 newImageFromBuffer。

我們使用 createGraphics() 方法建立新的旋轉影象,該方法返回一個 Graphics2D 物件 graphics2D。使用這個物件,我們呼叫帶有三個引數的 rotate() 函式;第一個是旋轉影象的角度,因為我們想要將它旋轉 90 度,我們通過 Math.radians(90),第二個和第三個引數是 x 和 y 座標。

最後,我們呼叫 graphics2D.drawImage() 來繪製旋轉影象,它有四個引數,即 BufferedImage 物件、要應用的過濾器以及 x 和 y 座標。然後我們返回 newImageFromBuffer 物件。

在 main 函式中,我們使用 File 讀取檔案,然後使用 ImageIO.read() 將其轉換為 BufferedImage 物件。現在我們呼叫 rotateImage() 函式並傳遞返回的 BufferedImage 物件並儲存旋轉後的 BufferedImage 物件。現在我們有了旋轉的影象,我們需要使用 File 和 ImageIO.write() 建立一個新檔案來儲存它,該檔案採用 BufferedImage 物件,其副檔名是空檔案的位置。

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class RotateImage {
  public static BufferedImage rotateImage(BufferedImage imageToRotate) {
    int widthOfImage = imageToRotate.getWidth();
    int heightOfImage = imageToRotate.getHeight();
    int typeOfImage = imageToRotate.getType();

    BufferedImage newImageFromBuffer = new BufferedImage(widthOfImage, heightOfImage, typeOfImage);

    Graphics2D graphics2D = newImageFromBuffer.createGraphics();

    graphics2D.rotate(Math.toRadians(90), widthOfImage / 2, heightOfImage / 2);
    graphics2D.drawImage(imageToRotate, null, 0, 0);

    return newImageFromBuffer;
  }

  public static void main(String[] args) {
    try {
      BufferedImage originalImage = ImageIO.read(new File("mountains.jpeg"));

      BufferedImage subImage = rotateImage(originalImage);

      File rotatedImageFile = new File("C:\\Users\\User1\\Documents\\mountainsRotated.jpeg");

      ImageIO.write(subImage, "jpg", rotatedImageFile);

      System.out.println("New Rotated Image File Path: " + rotatedImageFile.getPath());

    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

輸出:

New Rotated Image File Path: C:\Users\User1\Documents\mountainsRotated.jpeg

原圖:

在 java 中旋轉影象 - 原始影象

旋轉影象:

在 java 中旋轉影象 - 旋轉影象

在 Java 中使用仿射變換旋轉影象

此示例使用 AffineTransform 類,該類將影象從其原始 2D 座標線性對映到其他 2D 座標,而不會損失原始質量。在下面的程式中,我們三個方法,一是讀取和呼叫其他函式,二是順時針旋轉影象,最後一個函式是逆時針旋轉影象。

在 rotateImage() 函式中,我們使用 new File() 讀取影象,並使用 ImageIO.read() 將其轉換為 BufferedImage 物件。然後我們建立另一個 BufferedImage 物件,該物件保留原始影象的屬性並將其稱為 output。接下來,我們呼叫 rotateImageClockWise() 方法並在其中傳遞原始 BufferedImage,該方法返回 AffineTransorm 類的物件。

rotateImageClockWise() 接收 image 並獲取高度和寬度。我們建立一個 AffineTransform 物件 affineTransform 並使用它呼叫 rotate() 方法。在 rotate() 中,我們傳遞三個引數;第一個是以弧度為單位的旋轉角度,這裡我們傳遞 Math.PI / 2,最後兩個引數是 x 和 y 座標,它們是影象寬度和高度的一半。

現在,隨著影象的旋轉,我們使用 translate() 函式在新座標中平移影象,該函式採用兩個引數:x 方向旋轉的距離和 y 方向旋轉的距離。我們使用 (imageWidth - imageHeight) / 2 計算 x 和 y 引數。

要逆時針旋轉影象,我們可以在 rotate() 中呼叫方法 rotateImageCounterClockwise() 而不是 rotateImageClockWise()。

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class RotateImage {
  private static final String INPUT_FILE_NAME = "mountains.jpeg";
  private static final String OUTPUT_FILE_NAME = "mountainsRotated.jpeg";

  private AffineTransform rotateImageClockWise(BufferedImage image) {
    int imageWidth = image.getWidth();
    int imageHeight = image.getHeight();

    AffineTransform affineTransform = new AffineTransform();
    affineTransform.rotate(Math.PI / 2, imageWidth / 2, imageHeight / 2);

    double offset = (imageWidth - imageHeight) / 2;
    affineTransform.translate(offset, offset);
    return affineTransform;
  }

  private AffineTransform rotateImageCounterClockwise(BufferedImage image) {
    int imageWidth = image.getWidth();
    int imageHeight = image.getHeight();

    AffineTransform affineTransform = new AffineTransform();
    affineTransform.rotate(-Math.PI / 2, imageWidth / 2, imageHeight / 2);

    double offset = (imageWidth - imageHeight) / 2;
    affineTransform.translate(-offset, -offset);

    return affineTransform;
  }

  private void rotateImage() throws Exception {
    BufferedImage bufferedImage = ImageIO.read(new File(INPUT_FILE_NAME));

    BufferedImage output = new BufferedImage(
        bufferedImage.getHeight(), bufferedImage.getWidth(), bufferedImage.getType());

    AffineTransform affineTransform = rotateImageClockWise(bufferedImage);
    AffineTransformOp affineTransformOp =
        new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
    affineTransformOp.filter(bufferedImage, output);

    ImageIO.write(output, "jpg", new File(OUTPUT_FILE_NAME));
  }

  public static void main(String[] args) {
    try {
      RotateImage rotateImage = new RotateImage();
      rotateImage.rotateImage();

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

輸出:

原圖:

在 java 中旋轉影象 - 原始影象

影象順時針旋轉:

在 java 中旋轉影象 - 順時針旋轉影象

影象逆時針旋轉:

在 java 中旋轉影象 - 逆時針旋轉影象