簡體   English   中英

在 Java 中保持縱橫比的同時調整圖像大小

[英]Resize image while keeping aspect ratio in Java

我試圖在 java 中調整內存中的 bufferdImage 的大小,但為了保持圖像的縱橫比,我有類似的東西,但這並不好

int w = picture.getWidth();
int h = picture.getWidth();
int neww=w;
int newh=h;
int wfactor = w;
int hfactor = h;
if(w > DEFULT_PICTURE_WIDTH || h > DEFULT_PICTURE_HIGHT)
{
    while(neww > DEFULT_PICTURE_WIDTH)
    {
        neww = wfactor /2;
        newh = hfactor /2;
        wfactor = neww;
        hfactor = newh;
    }
}

picture = Utils.resizePicture(picture,neww,newh);

補充 Erik 關於 getScaledInstance 的觀點,如果您從它轉向使用 Java2D 中推薦的縮放機制,您可能已經注意到您的圖像看起來明顯更糟。

這樣做的原因是當 Java2D 不鼓勵使用 getScaledInstance 和 AreaAveragingScaleFilter 時,他們沒有用 API 中易於使用的任何東西來替換它,而是讓我們直接使用 Java2D API 給我們自己的設備。 幸運的是,Chris Campbell(來自 J2D 團隊)遵循了使用增量縮放技術的建議,該技術提供與 AreaAveragingScaleFilter 相似的外觀結果並且運行速度更快; 不幸的是,代碼大小合適,並沒有解決您最初的尊重比例問題。

大約 6 個月前,我一次又一次地在 SO 上看到所有這些關於“在 Java 中縮放圖像”的問題,並最終收集了所有建議,進行了所有我能做的挖掘和研究,並將所有這些編譯成一個“最佳實踐”圖像縮放圖書館

API 非常簡單,因為它只有 1 個類和一堆靜態方法。 基本用法如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 320);

這是最簡單的調用,庫將對質量做出最佳猜測,尊重您的圖像比例,並將結果放入 320x320 邊界框內。 注意,邊界框只是使用的最大 W/H,因為您的圖像比例受到尊重,結果圖像仍然會尊重該比例,例如 320x200。

如果您想覆蓋自動模式並強制它為您提供最佳效果,甚至對結果應用非常溫和的抗鋸齒過濾器,使其看起來更好(尤其適用於縮略圖),該調用將如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

這些都只是示例,API 非常廣泛,涵蓋了從超級簡單的用例到非常專業的所有內容。 您甚至可以傳入您自己的 BufferedImageOps 以應用於圖像(並且該庫會自動為您修復 6 年的 BufferedImageOp JDK 錯誤!)

該庫為您在 Java 中成功縮放圖像還有很多其他功能,例如,在對圖像進行操作時始終將圖像保持在受支持的最佳 RGB 或 ARGB 圖像類型之一。 如果用於任何圖像操作的圖像類型沒有得到很好的支持,那么 Java2D 圖像處理管道就會退回到劣質的軟件管道。

如果這一切聽起來很頭疼,那是……這就是我編寫庫並將其開源的原因,這樣人們就可以調整圖像大小並繼續他們的生活,而無需擔心。

希望有幫助。

如果已知源和目標的寬度、高度,則使用以下函數來確定圖像的比例。

private double determineImageScale(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) {

double scalex = (double) targetWidth / sourceWidth;
double scaley = (double) targetHeight / sourceHeight;
return Math.min(scalex, scaley);

}

然后使用此比例使用以下代碼放大/縮小圖像

Image scaledImage = sourceBufferedImage.getScaledInstance((int) (width * scale), (int) (height * scale), Image.SCALE_SMOOTH);

對於初學者 - 看看第 2 行。那不應該是getHeight()嗎?

您不需要用於調整大小的 while 循環,而是想找出調整大小比率,這是一個簡單的數學運算。

(width / height) = (new_width / new_height)

如果您知道“新”尺寸之一,則可以通過乘法找到另一個

new_height * (width / height) = new_width

您還可以使用BufferedImage's超類 Image getScaledInstance()提供的惰性方法 - 對寬度或高度使用 -1 將保持縱橫比

前任:
scaledPic = picture.getScaledInstance(new_width, -1, Image.SCALE_FAST);

您可能會查看perils-of-image-getscaledinstance.html ,它解釋了為什么應該避免在某些答案中使用getScaledInstance()

文章還提供了替代代碼。

我使用這兩種方法來縮放圖像,其中 max 是目標圖像的較大尺寸。 對於 100x100 圖像,它將是 100,對於 200x300 圖像,它將是 300。

    public static BufferedImage scale(InputStream is, int max) {
    Image image = null;
    try {
        image = ImageIO.read(is);
    } catch (IOException e) {
        e.printStackTrace();
    }
    int width = image.getWidth(null);
    int height = image.getHeight(null);
    double dWidth = 0;
    double dHeight = 0;
    if (width == height) {
        dWidth = max;
        dHeight = max;
    } 
    else if (width > height) {
        dWidth = max;
        dHeight = ((double) height / (double) width) * max;
    }
    else {
        dHeight = max;
        dWidth = ((double) width / (double) height) * max;
    }
    image = image.getScaledInstance((int) dWidth, (int) dHeight, Image.SCALE_SMOOTH);
    BufferedImage bImage = toBufferedImage(image);
    return bImage;

}

public static BufferedImage toBufferedImage(Image img)
{
    if (img instanceof BufferedImage)
    {
        return (BufferedImage) img;
    }

    BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

    Graphics2D bGr = bimage.createGraphics();
    bGr.drawImage(img, 0, 0, null);
    bGr.dispose();

    return bimage;
}
private static BufferedImage resize(BufferedImage img, int width, int height) {

        double scalex = (double) width / img.getWidth();
        double scaley = (double) height / img.getHeight();
        double scale = Math.min(scalex, scaley);

        int w = (int) (img.getWidth() * scale);
        int h = (int) (img.getHeight() * scale);

        Image tmp = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);

        BufferedImage resized = new BufferedImage(w, h, img.getType());
        Graphics2D g2d = resized.createGraphics();
        g2d.drawImage(tmp, 0, 0, null);
        g2d.dispose();

        return resized;
    }

如果你想通過保持縱橫比將w0 x h0的圖片調整為w1 x h1,那么計算垂直和水平比例並選擇較小的。

double scalex = 1;
double scaley = 1;
if (scalingMode == ScalingMode.WINDOW_SIZE) {
  scalex = (double)getWidth() / frontbuffer.getWidth();
  scaley = (double)getHeight() / frontbuffer.getHeight();
} else
if (scalingMode == ScalingMode.KEEP_ASPECT) {
  double sx = (double)getWidth() / frontbuffer.getWidth();
  double sy = (double)getHeight() / frontbuffer.getHeight();
  scalex = Math.min(sx, sy);
  scaley = scalex;
  // center the image
  g2.translate((getWidth() - (frontbuffer.getWidth() * scalex)) / 2,
    (getHeight() - (frontbuffer.getHeight() * scaley)) / 2);
}
g2.scale(scalex, scaley);
if (interpolation != ImageInterpolation.NONE) {
  g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation.hint);
}
g2.drawImage(frontbuffer, 0, 0, null);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM