在Android中解码正确大小的位图

我使用BitmapFactory.decodeFile解码来自SD卡的位图。 有时位图比应用程序需要的或者堆允许的大,所以我使用BitmapFactory.Options.inSampleSize来请求二次采样(较小)的位图。

问题是平台没有强制执行inSampleSize的确切值,而且有时候我得到的位图太小了,或者对于可用内存来说太大了。

从http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize :

注意:解码器将尝试完成这个请求,但是由此产生的位图可能有不同的尺寸,正是所要求的。 另外,2的幂次对于解码器来说通常更快/更容易兑现。

我应该如何解码从SD卡的位图获得我需要的确切大小的位图,而尽可能less的内存来解码它?

编辑:

当前源代码:

 BitmapFactory.Options bounds = new BitmapFactory.Options(); this.bounds.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, bounds); if (bounds.outWidth == -1) { // TODO: Error } int width = bounds.outWidth; int height = bounds.outHeight; boolean withinBounds = width <= maxWidth && height <= maxHeight; if (!withinBounds) { int newWidth = calculateNewWidth(int width, int height); float sampleSizeF = (float) width / (float) newWidth; int sampleSize = Math.round(sampleSizeF); BitmapFactory.Options resample = new BitmapFactory.Options(); resample.inSampleSize = sampleSize; bitmap = BitmapFactory.decodeFile(filePath, resample); } 

您处于正确的轨道上,但是您一次尝试着做两件事:读取文件并将其缩放到适当的大小。

第一步是使用BitmapFactory.Options.inSampleSize将文件读取到比您需要的位图稍大的位图,以确保在所需的只是较小的缩略图或屏幕分辨率图像时,不会消耗读取较大位图的过多内存。

第二步是调用Bitmap.createScaledBitmap()来创build一个新的位图,以达到您所需的精确分辨率。

确保在临时位图之后清理以回收其内存。 (要么让variables超出范围,并让GC处理它,要么调用.recycle()如果你正在加载大量的图像,并在内存上运行紧张。)

你可能想要使用inJustDecodeBounds 。 将其设置为TRUE并按原样加载文件。

图像不会被加载到内存中。 但BitmapFactory.Options的 outheightoutwidth属性将包含指定图像的实际大小参数。 计算你想要多less子样本。 即1/2或1/4或1/8等,并相应地指定2/4/8 等于inSampleSize

现在将inJustDecodeBounds设置为FALSE并调用BitmapFactory.decodeFile()来加载上面计算的确切大小的图像。

首先,您需要将图像采样到最近的采样值,以便位图变得高效,这是您完美描述的。 一旦完成,您可以将其缩放以适应您的屏幕。

 // This function taking care of sampling backImage =decodeSampledBitmapFromResource(getResources(),R.drawable.back, width, height); // This will scale it to your screen width and height. you need to pass screen width and height. backImage = Bitmap.createScaledBitmap(backImage, width, height, false); 

由于API已经指出,样本大小可能会或可能不会被兑现。 所以我猜你使用BitmapFactory时运气不好。

但出路将使用自己的位图阅读器。 但是我build议你坚持使用BitmapFactory,因为它相当好的testing和标准化。

我会尽量不要太担心一些额外的内存消耗,但试着找出为什么不尊重价值观。 可悲的是,我不知道那个:(

 ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filesPath), THUMBSIZE, THUMBSIZE)) 

您可以根据您的要求直接设置THUMBSIZE,但我不确定较低级别的实现细节,输出图像质量和性能,但我通常更喜欢它,当我需要显示缩略图时。

对于那些从资源中寻找确切尺寸图像的人。

对于确切的宽度传递reqHight = 0,对于确切的高度传递reqWidth = 0

 public static Bitmap decodeBitmapResource(Context context, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(context.getResources(), resId, options); float scale = 1; if (reqWidth != 0 && reqHeight == 0) { options.inSampleSize = (int) Math.ceil(options.outWidth / (float) reqWidth); scale = (float) options.outWidth / (float) reqWidth; } else if (reqHeight != 0 && reqWidth == 0) { options.inSampleSize = (int) Math.ceil(options.outHeight / (float) reqHeight); scale = (float) options.outHeight / (float) reqHeight; } else if (reqHeight != 0 && reqWidth != 0) { float x = (float) options.outWidth / (float) reqWidth; float y = (float) options.outHeight / (float) reqHeight; scale = x > y ? x : y; } reqWidth = (int) ((float) options.outWidth / scale); reqHeight = (int) ((float) options.outHeight / scale); options.inJustDecodeBounds = false; Bitmap tmp = BitmapFactory.decodeResource(context.getResources(), resId, options); Bitmap out = Bitmap.createScaledBitmap(tmp, reqWidth, reqHeight, false); tmp.recycle(); tmp = null; return out; } 

由于我使用inSampleSize,我再也不会遇到内存不足的问题。 所以inSampleSize对我来说工作相当稳定。 我会build议你仔细检查问题。 大小可能并不像你所要求的那么大。 但无论如何应该减less,不应该有更多的“内存不足”。 我也build议在这里发布你的代码片段,也许有什么问题。

100rabh说,如果你使用BitmapFactory你没有太多的select。 但是,位图解码非常简单,取决于您要使用的缩放algorithm,通常非常简单,可以即时进行缩放,而不必将大部分原始位图读取到内存中(一般来说,只需要将原始位图的1-2行所需的内存加倍)。

当inScaled标志被设置时(默认为TRUE),如果inDensity和inTargetDensity不是0,位图将被加载时匹配inTargetDensity,而不是依靠graphics系统每次绘制到Canvas时缩放它。 所以简单的设置inScaled为false就可以了。

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; 

我能够通过将解码图像文件重新缩放到其位图大小的70%来近似得到“正确的大小”。

 Bitmap myBitmap = BitmapFactory.decodeFile(path); if(myBitmap != null) { //reduce to 70% size; bitmaps produce larger than actual image size Bitmap rescaledMyBitmap = Bitmap.createScaledBitmap( myBitmap, myBitmap.getWidth()/10*7, myBitmap.getHeight()/10*7, false); image.setImageBitmap(rescaledMyBitmap); } 

我希望这能帮助你以某种方式! 和平!