有时我的图片太大而且我收到了这个错误:
线程中的异常" main" java.lang.NegativeArraySizeException at java.awt.image.DataBufferByte。(未知来源)at java.awt.image.Raster.createInterleavedRaster(未知来源)at java.awt.image.BufferedImage。(未知来源)
每当我得到这个,我想在保持比率的同时将我的图像调整到尽可能大的尺寸。
我最终得到了以下公式:
if ( targetWidth * targetHeight >= Integer.MAX_VALUE || targetWidth * targetHeight < 0 ) {
System.out.println( "Target image too big... Size will be adjusted!" );
if ( targetWidth > targetHeight ) {
targetWidth = (int)Math.sqrt( ( Integer.MAX_VALUE ) * (float)( targetWidth / targetHeight ) );
targetHeight = ( Integer.MAX_VALUE ) / targetWidth;
} else {
targetHeight = (int)Math.sqrt( ( Integer.MAX_VALUE ) * (float)( targetHeight / targetWidth ) );
targetWidth = ( Integer.MAX_VALUE ) / targetHeight;
}
}
我仍然遇到同样的问题,我的条件也很满意。 我想那个
宽度*高度&lt; Integer.MAX_VALUE的
显然不是我正在寻找的条件 有什么帮助吗?
编辑:经过一番讨论后,我认为这个问题的真正问题是: 为了不在以下位置获取NegativeArraySizeException,我可以传递给BufferedImage构造函数的最大可能大小是多少:
at java.awt.image.DataBufferByte。(Unknown Source)
答案 0 :(得分:1)
Raster
类(ref)的限制, BufferedImage
限制与byte[Integer.MAX_VALUE]
的限制相同。您还有标头的开销,这是平台和实现相关的。这就是为什么我推荐一个长度为long
的安全缓冲区。
(Integer.MAX_VALUE - 8) / 4
应该是一个很好的安全限制。
注意:您必须考虑每个像素的大小(ref)。例如,BufferedImage.TYPE_4BYTE_ABGR
是每像素4个字节。这意味着在这种情况下您的区域限制为Integer.MAX_VALUE / 4
。当然,每个像素消耗的字节数因您使用的类型而异。通过表示每个像素的字节数来调整测试最大区域。您必须查看API才能弄明白:https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html。
为了在保持宽高比的同时调整图像大小,数学运算非常简单:
double aspectRatio = width / height;
if (aspectRatio < 1) {
// taller than wide
targetHeight = maxDimension;
targetWidth = (int)(targetHeight * aspectRatio);
} else {
// wider than tall
targetWidth = maxDimension;
targetHeight = (int)(targetWidth / aspectRatio);
}
离开是基于图像的总面积计算maxDimension
的问题。为了论证,我们说最大面积是Integer.MAX_VALUE - 8
(relatively safe)。我们可以使用代数推断它。我们知道width * height = area
,使用上面的公式,我们有两种方法需要为最大区域求解。
对于aspectRatio < 1
,我们用公式替换宽度来获取它:
身高*身高* aspectRatio =面积
解决高度:
height^2 * aspectRatio = area
height^2 = area / aspectRatio
height = Math.sqrt(area / aspectRatio
对于asptectRatio >= 1
,我们用公式代替高度来获取它:
width * width / aspectRatio = area
求解宽度:
现在我们可以更新基本公式以考虑最大区域中的形状:
public static final long MAX_AREA = (Integer.MAX_VALUE - 8) / 4;
if (aspectRatio < 1) {
targetHeight = Math.sqrt(MAX_AREA / aspectRatio);
targetWidth = (int)(targetHeight * aspectRatio);
} else {
// wider than tall
targetWidth = Math.sqrt(MAX_AREA * aspectRatio);
targetHeight = (int)(targetWidth / aspectRatio);
}
当然,如果超过最大面积阈值,这就留下了测试的基本问题。这需要使用int
之外的其他内容来完成。
public static final long MAX_AREA = (Integer.MAX_VALUE - 8) / 4;
long area = (long)width * (long)height;
if(area < MAX_AREA) {
// recalculate size
}
否则你会遇到溢出问题。