[英]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.