大多数的内存来调整位图在Android上有效的方式? [英] Most memory efficient way to resize bitmaps on android?

查看:149
本文介绍了大多数的内存来调整位图在Android上有效的方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个图像密集型的社会应用程序,其中图像被从服务器向设备发送。当该设备具有更小的屏幕分辨率,我需要调整的位图,在设备,以满足他们的需要的显示尺寸。

的问题是,使用的 <一href="http://developer.android.com/reference/android/graphics/Bitmap.html#createScaledBitmap(android.graphics.Bitmap,%20int,%20int,%20boolean)">createScaledBitmap使我调整缩略图的部落后遇到了很多内存不足的错误。

什么是调整位图在Android上最内存高效的方法?

解决方案
  

此答案由装载大位图总结高效的   这也解释了如何使用inSampleSize加载一个缩小的位图   版本。

     

在特定的<一个href="https://www.youtube.com/watch?v=HY9aaXHx8yA&index=28&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">$p$p-scaling位图解释各种细节   方法,如何将它们结合起来,并且这是最有效的记忆

有三大主导方式来调整在Android上的位图具有不同的内存性能:

<一个href="http://developer.android.com/reference/android/graphics/Bitmap.html#createScaledBitmap(android.graphics.Bitmap,%20int,%20int,%20boolean)">createScaledBitmap API

这个API将在现有的位图,并创建一个新的位图与您所选择的精确的尺寸。

在积极的一面,你可以得到正是你要寻找的图像尺寸(不管它的外观)。但不利的一面,的是,这个API需要一个现有位,以便工作的。这意味着图像必须被加载,德codeD和位图建立,能够创建一个新的,更小的版本之前。这是理想让您的确切尺寸方面,但可怕的额外内存开销方面。因此,这是一个大忌一种,对于大多数应用程序开发谁往往是内存意识

<一个href="http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize">inSampleSize标志

BitmapFactory.Options 有一个属性标注为 inSampleSize ,将调整你的形象,同时对其进行解码,以避免需要去code到一个临时的位图。这这里使用整型值将加载的图像以1 / X尺寸减小。例如,设置 inSampleSize 2返回一个图像的一半大小,并将其设置为4返回一个形象,就是1/4的大小。基本上,图像大小将永远是权力的两部分比你的源代码尺寸更小。

从存储的角度来看,使用 inSampleSize 是一个非常快速的操作。实际上,它只会去code图像的每个像素的第十届到您的生成位图。有两个主要问题,虽然 inSampleSize

  • 它不会给你确切的决议。它不仅降低了您的位图的由2部分权力的大小。

  • 这不会产生最优质的大小调整。大多数调整过滤器通过读取像素块,然后加权他们生产有问题的大小像素产生良好的图像。 inSampleSize 避免这一切仅仅阅读每隔几个像素。其结果是相当高性能,低内存,但质量受到影响。

如果你只处理一些POW2尺寸缩小图像和过滤是不是一个问题,那么你就不能找到一个更高效的内存(或性能更高)方法比 inSampleSize

<一个href="http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled">inScaled,强度气体,inTargetDensity标志

如果您需要将图像缩放到一个层面,这不是等于二的幂,那么你就需要在 inScaled 强度气体放 inTargetDensity BitmapOptions 的标志。当 inScaled 标志已设置,系统会得出标定值由 inTargetDensity 通过将应用到您的位图在强度气体值。

  mBitmapOptions.inScaled = TRUE;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;

//将加载和放大器;调整图片的大小为1 / inSampleSize尺寸
mCurrentBitmap = BitmapFactory.de codeResources(getResources()
      mImageIDs,mBitmapOptions);
 

使用此方法将重新大小的图像,并且还应用了调整大小过滤器吧,那就是,最后的结果会更好看,因为一些额外的数学已经考虑在调整一步。但要注意:额外的过滤器的步骤,需要额外的处理时间,并能迅速增加的大图像,从而导致缓慢调整图像尺寸,以及过滤器本身额外的内存分配

这通常不是这种技术应用到图像,它比你想要的大小显著较大,由于额外的滤波的开销是个好主意。

魔法组合

从内存和性能的角度来看,你可以将这些选项的最佳结果。 (设置 inSampleSize inScaled 强度气体 inTargetDensity 标志)

inSampleSize 将首先被应用到图像,它让下一个不是你的目标大小幂的两个较大。然后,强度气体&放大器; inTargetDensity 用于标定结果苛求你想要的尺寸,应用过滤器操作来清理图像。

结合这两个是更快操作中,由于 inSampleSize 步骤将减少的像素所得到的基于密度的步骤将需要应用它的上调整滤波器的数目

  mBitmapOptions.inScaled = TRUE;
mBitmapOptions.inSampleSize = 4
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;

//将加载和放大器;调整图片的大小为1 / inSampleSize尺寸
mCurrentBitmap = BitmapFactory.de codeFILE(文件名,mBitmapOptions);
 

如果你需要,以适应图像以具体的尺寸的的一些更好的过滤,那么这个技术是获得正确尺寸的最佳桥梁,但在一个快速,低内存中完成足迹操作。

获取图像尺寸

获取图像尺寸没有整个图像进行解码 为了调整您的位图,你需要知道传入的尺寸。您可以使用 inJustDe codeBounds 标记,以帮助你得到的图像的尺寸,W / O型需要C中的像素数据来实际代$ C $。

  //德code就在边界值
mBitmapOptions.inJustDe codeBounds = TRUE;
BitmapFactory.de codeFILE(文件名,mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;


//现在去图像调整到你想要的大小
 

您可以使用此标志第一次去$ C C尺寸$,然后计算出正确的值扩展到您的目标分辨率。

I’m building an image-intensive social app where images are sent from the server to the device. When the device has smaller screen resolutions, I need to resize the bitmaps, on device, to match their intended display sizes.

The problem is that using createScaledBitmap causes me to run into a lot of out-of-memory errors after resizing a horde of thumbnail images.

What’s the most memory efficient way to resize bitmaps on Android?

解决方案

This answer is summarized from Loading large bitmaps Efficiently which explains how to use inSampleSize to load a down-scaled bitmap version.

In particular Pre-scaling bitmaps explains the details of various methods, how to combine them, and which are the most memory efficient.

There are three dominant ways to resize a bitmap on Android which have different memory properties:

createScaledBitmap API

This API will take in an existing bitmap, and create a NEW bitmap with the exact dimensions you’ve selected.

On the plus side, you can get exactly the image size you’re looking for (regardless of how it looks). But the downside, is that this API requires an existing bitmap in order to work. Meaning the image would have to be loaded, decoded, and a bitmap created, before being able to create a new, smaller version. This is ideal in terms of getting your exact dimensions, but horrible in terms of additional memory overhead. As such, this is kind-of a deal breaker for most app developers who tend to be memory conscious

inSampleSize flag

BitmapFactory.Options has a property noted as inSampleSize that will resize your image while decoding it, to avoid the need to decode to a temporary bitmap. This integer value used here will load an image at a 1/x reduced size. For example, setting inSampleSize to 2 returns an image that’s half the size, and Setting it to 4 returns an image that’s 1/ 4th the size. Basically image sizes will always be some power-of-two smaller than your source size.

From a memory perspective, using inSampleSize is a really fast operation. Effectively, it will only decode every Xth pixel of your image into your resulting bitmap. There’s two main issues with inSampleSize though:

  • It doesn’t give you exact resolutions. It only decreases the size of your bitmap by some power of 2.

  • It doesn’t produce the best quality resize. Most resizing filters produce good looking images by reading blocks of pixels, and then weighting them to produce the resized pixel in question. inSampleSize avoids all this by just reading every few pixels. The result is quite performant, and low memory, but quality suffers.

If you're only dealing with shrinking your image by some pow2 size, and filtering isn't an issue, then you can't find a more memory efficient (or performance efficient) method than inSampleSize.

inScaled, inDensity, inTargetDensity flags

If you need to scale an image to a dimension that’s not equal to a power of two, then you’ll need the inScaled, inDensity and inTargetDensity flags of BitmapOptions. When inScaled flag has been set, the system will derive the scaling value to apply to your bitmap by dividing the inTargetDensity by the inDensity values.

mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity =  dstWidth;

// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(), 
      mImageIDs, mBitmapOptions);

Using this method will re-size your image, and also apply a ‘resizing filter’ to it, that is, the end result will look better because some additional math has been taken into account during the resizing step. But be warned: that extra filter step, takes extra processing time, and can quickly add up for big images, resulting in slow resizes, and extra memory allocations for the filter itself.

It’s generally not a good idea to apply this technique to an image that’s significantly larger than your desired size, due to the extra filtering overhead.

Magic Combination

From a memory and performance perspective, you can combine these options for the best results. (setting the inSampleSize, inScaled, inDensity and inTargetDensity flags)

inSampleSize will first be applied to the image, getting it to the next power-of-two LARGER than your target size. Then, inDensity & inTargetDensity are used to scale the result to exact dimensions that you want, applying a filter operation to clean up the image.

Combining these two is a much faster operation, since the inSampleSize step will reduce the number of pixels that the resulting Density-based step will need to apply it’s resizing filter on.

mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity =  dstWidth * mBitmapOptions.inSampleSize;

// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);

If you're needing to fit an image to specific dimensions, and some nicer filtering, then this technique is the best bridge to getting the right size, but done in a fast, low-memory footprint operation.

Getting image dimensions

Getting the image size without decoding the whole image In order to resize your bitmap, you’ll need to know the incoming dimensions. You can use the inJustDecodeBounds flag to help you get the dimensions of the image, w/o needing to actually decode the pixel data.

// Decode just the boundries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;


//now go resize the image to the size you want

You can use this flag to decode the size first, and then calculate the proper values for scaling to your target resolution.

这篇关于大多数的内存来调整位图在Android上有效的方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆