我在一个文件中有一个大的位图(比如3888x2592)。现在,我想将位图大小调整为800x533,并将其保存到另一个文件中。
我通常通过调用bitmap来缩放位图。createBitmap方法,但它需要一个源位图作为第一个参数,我不能提供,因为加载原始图像到位图对象当然会超过内存(例如,见这里)。
我也不能读取位图,例如,BitmapFactory.decodeFile(文件,选项),提供BitmapFactory.Options。inSampleSize,因为我想把它调整到精确的宽度和高度。使用inSampleSize将位图大小调整为972x648(如果我使用inSampleSize=4)或778x518(如果我使用inSampleSize=5,这甚至不是2的幂)。
我还希望避免在第一步中使用inSampleSize读取图像,例如,在第一步中使用972x648,然后在第二步中将其大小调整为800x533,因为与直接调整原始图像的大小相比,质量会较差。
总结一下我的问题:
是否有一种方法来读取一个10MP或更多的大图像文件,并将其保存到一个新的图像文件,调整到一个特定的新宽度和高度,而不得到OutOfMemory异常?
我还尝试了BitmapFactory.decodeFile(文件,选项)和设置选项。out theight and Options。outidth值手动为800和533,但它不是这样工作的。
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);
or:
resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);
or:
resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
考虑到你想要调整大小到精确的大小,并想要保持尽可能多的质量,我认为你应该试试这个。
通过调用BitmapFactory.decodeFile并提供checkSizeOptions.inJustDecodeBounds来查找调整后图像的大小
计算您可以在设备上使用的不超过内存的inSampleSize的最大值。bitmapSizeInBytes = 2*width*height;一般来说,对于你的图片inSampleSize=2就可以了,因为你只需要2*1944x1296)=4.8Mbб,这应该是在内存中
使用BitmapFactory.decodeFile和inSampleSize来加载位图
将位图缩放到精确的大小。
动机:多步缩放可以提供更高质量的图片,但不能保证它会比使用high inSampleSize更好。
实际上,我认为你也可以使用inSampleSize 5(不是pow of 2)在一个操作中直接缩放。或者用4,然后你可以在UI中使用那个图像。如果你把它发送到服务器,那么你可以在服务器端进行精确的缩放,这允许你使用高级缩放技术。
注意:如果在步骤3中加载的位图至少是4倍大(所以4*targetWidth < width),你可能会使用几次调整来获得更好的质量。
至少这在通用java中是有效的,在android中你没有指定用于缩放的插值的选项
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
上面的代码更简洁一些。InputStreams最终关闭了包装,以确保它们也被关闭:
*请注意
输入:InputStream is, int w, int h
输出:位图
try
{
final int inWidth;
final int inHeight;
final File tempFile = new File(temp, System.currentTimeMillis() + is.toString() + ".temp");
{
final FileOutputStream tempOut = new FileOutputStream(tempFile);
StreamUtil.copyTo(is, tempOut);
tempOut.close();
}
{
final InputStream in = new FileInputStream(tempFile);
final BitmapFactory.Options options = new BitmapFactory.Options();
try {
// decode image size (decode metadata only, not the whole image)
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
}
finally {
in.close();
}
// save width and height
inWidth = options.outWidth;
inHeight = options.outHeight;
}
final Bitmap roughBitmap;
{
// decode full image pre-resized
final InputStream in = new FileInputStream(tempFile);
try {
final BitmapFactory.Options options = new BitmapFactory.Options();
// calc rought re-size (this is no exact resize)
options.inSampleSize = Math.max(inWidth/w, inHeight/h);
// decode full image
roughBitmap = BitmapFactory.decodeStream(in, null, options);
}
finally {
in.close();
}
tempFile.delete();
}
float[] values = new float[9];
{
// calc exact destination size
Matrix m = new Matrix();
RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
RectF outRect = new RectF(0, 0, w, h);
m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
m.getValues(values);
}
// resize bitmap
final Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);
return resizedBitmap;
}
catch (IOException e) {
logger.error("Error:" , e);
throw new ResourceException("could not create bitmap");
}