调整图像大小,同时保持 Java 中的宽高比

2022-09-02 14:14:14

im试图在java的内存中调整缓冲区图像的大小,但要保持图像的宽高比,im有这样的东西,但这不好

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

答案 1

除了 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 图像处理管道将回退到较差的软件管道。

如果这一切听起来像是很多头痛,那有点像......这就是为什么我写了图书馆并开源了它,所以人们可以调整他们的图像大小并继续他们的生活,而不必担心它。

希望有所帮助。


答案 2

如果源和目标的宽度、高度已知,请使用以下函数来确定图像的比例。

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

推荐