在Java中调整图像大小,同时保持纵横比
我试图用java调整内存中bufferdImage的大小,但要保持图像的纵横比 我有这样的东西,但这不好在Java中调整图像大小,同时保持纵横比,java,image,resize,Java,Image,Resize,我试图用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 >
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);
首先,请看第2行。这不应该是
getHeight()
你不需要一个while循环来调整大小,你需要找出调整大小的比率,这是一个简单的数学问题
(width / height) = (new_width / new_height)
如果您知道其中一种“新”尺寸,则可以通过乘法找到另一种尺寸
new_height * (width / height) = new_width
您还可以使用由buffereImage的
超类映像提供的惰性方法,getScaledInstance()
-对宽度或高度使用-1将保持纵横比
例如:scaledPic=picture.getScaledInstance(新的\u宽度-1,Image.SCALE\u快速)编码>如果您想通过保持纵横比将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);
如果已知源和目标的宽度、高度,请使用以下函数确定图像的比例
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);
您可以看一看,这解释了为什么应该避免在某些答案中使用getScaledInstance()
本文还提供了其他代码。除了Erik关于getScaledInstance的观点之外,如果您不再使用Java2D中推荐的缩放机制,您可能已经注意到您的图像看起来明显更糟
原因是当Java2D不鼓励使用GetScaleInstance和AreaAveragingScaleFilter时,他们并没有用API中的任何易于使用的东西来取代它,而是让我们直接使用Java2D API来使用自己的设备。幸运的是,Chris Campbell(来自J2D团队)提出了使用增量缩放技术的建议,该技术与AreaAveragingScaleFilter具有相似的外观效果,并且运行速度更快;不幸的是,代码的大小还不错,并没有解决您最初关于尊重比例的问题
大约6个月前,我一次又一次地看到关于“在Java中缩放图像”的所有问题,并最终收集了所有建议,尽我所能进行了挖掘和研究,并将所有这些问题汇编成一个“最佳实践”
API非常简单,因为它只有一个类和一堆静态方法。基本用途如下所示:
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非常广泛,涵盖了从超级简单的用例到非常专业的一切。您甚至可以传入自己的BuffereImage操作以应用于映像(库会自动为您修复6年BuffereImage操作JDK错误!)
在Java中成功缩放图像还有很多方法,该库为您提供了很多方法,例如,在对图像进行操作时,始终将图像保持在受支持的最佳RGB或ARGB图像类型之一。如果用于任何图像操作的图像类型不受支持,则Java2D图像处理管道会退回到劣质软件管道
如果这一切听起来很头痛的话,那有点。。。这就是为什么我编写了这个库并将其开源,这样人们就可以调整他们的图像大小,继续他们的生活而不必担心它
希望能有所帮助。我使用这两种方法缩放图像,其中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;
}
是的,它的getHeight输入错误有什么原因我不能将getScaledInstance与BufferdImage一起使用吗?那应该很好,因为BuffereImage扩展了ImageHah,感谢第一个等式。在我混乱的大脑里,有什么东西发出咔哒声!什么代表frontbuffer?这是我的一段代码的摘录,该代码使用交换缓冲渲染动画。frontbuffer只是目前需要显示的BuffereImage。只是看了一下这个库,它帮助了很多;如果可以的话,我会+2这篇文章,事实上你的项目有自己的maven repo托管。谢谢谢谢你的客气话,安德鲁,我很高兴你觉得它很有用@AndrewB我帮你+1他就得到+2。。这当然是值得的。”…将所有这些都汇编到一个“最佳实践”图像缩放库中。”这整句话对我来说是鼓舞人心的。库(v4.2)的问题在于它不能同时尊重高度和宽度。例如,我有一个图像2000x2000。我想把它装在700x200 squire里。我希望输出为200x200,但得到了700x700。是的,我指定了目标高度和目标宽度
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;
}