在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); 

您可以查看perils-of-image-getscaledinstance.html ,它解释了为什么应该避免在某些答案中使用的getScaledInstance()

该文章还提供了替代代码。

添加到Erik关于getScaledInstance的观点,如果您从使用Java2D中的推荐缩放机制转移到它,您可能已经注意到您的图像看起来明显更糟。

原因是当Java2D不鼓励使用getScaledInstance和AreaAveragingScaleFilter时,他们并没有将它替换 API中易于使用的任何东西,而是直接使用Java2D API留给我们自己的设备。 幸运的是,Chris Campbell(来自J2D团队)接着提出了使用增量缩放技术的建议,该技术为AreaAveragingScaleFilter提供了类似的结果并且运行得更快; 不幸的是,代码大小合适,并没有解决你原来的尊重比例的问题。

大约6个月前,我一次又一次地看到关于“在Java中缩放图像”的所有这些问题并最终收集了所有的建议,完成了我所能进行的所有挖掘和研究,并将所有这些问题编译成单个“最佳实践” 图像缩放图书馆 。

API很简单,因为它只有一个类和一堆静态方法。 基本用法如下:

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

这是最简单的调用 ,其中库将对质量进行最佳猜测,尊重您的图像比例,并将结果拟合到320×320的边界框中。 注意,边界框只是所使用的最大W / H,因为您的图像比例得到尊重,所得到的图像仍然会尊重,例如320×200。

如果你想覆盖自动模式并强制它给你最好看的结果,甚至对结果应用一个非常温和的抗锯齿filter,使它看起来更好(特别适合缩略图),该调用看起来像:

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

这些都只是示例,API很广泛,涵盖了从超简单用例到非常专业的所有内容。 您甚至可以传入自己的BufferedImageOps以应用于图像(并且库会自动修复6年的BufferedImageOp JDK错误!)

在Java中为您成功缩放图像还有很多function,例如,在对其进行操作时,始终将图像保持为最佳支持的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()吗?

您不希望resize的while循环,您想要找出resize比例,这是一个简单的数学运算。

 (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);

我使用这两种方法来缩放图像,其中max是目标图像的较大尺寸。 对于100×100图像,它将是100,对于200×300图像,它将是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; } 

如果要通过保持纵横比来调整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);