翻译自 [某大神在Stack Overflow里的自问自答](http://stackoverflow.com/questions/32121058/most-memory-efficient-way-to-resize-bitmaps-on-android)
(一般我们将Bitmap翻译为位图,但为了更好理解,在本文中我将它翻译成图像);

我们在开发的时候,经常需要从服务器中加载图像到客户端中,但有时手机屏幕较小(服务器传来的图像是大图)导致我们需要重新调整图像的大小以适应手机的屏幕。我们可以使用createScaledBitmap方法来调整图像的大小,可当我们使用createScaledBitmap来得到大量的缩略图后(图像数量较大),会导致许多的内存溢出错误(out-of-memory errors)。那么问题来了,在Android中哪种方式是调整图像大小的最有效的内存的利用方式呢?

文章Loading large bitmaps Efficiently(现在打不开,你懂的) 介绍了怎样利用isSampleSize去加载一个图像的缩略图,这里只是对它进行一个总结;文章Pre-scaling bitmaps(现在打不开,你懂的) 详细介绍了调整图像大小的各种方法,并且怎样去混合使用这些方法得到一个最好的内存利用方式;

在Android中有三种主要的方式来调整图像的大小,并且每种方法会有不同的内存性能:

1. createScaledBitmap API

这个API会加载一个已经存在的图像,并用你希望得到的图像尺寸来创建一个新的图像。一方面,你可以得到你想得到的确切尺寸的图像。但这个API可以正常工作的前提是已经有一个图像(大图)存在了。这意味着在创建新尺寸的图像前,原来的图像会先经历加载,解码,创建的过程(在内存中创建这个大图)。这是理想的得到确切图像尺寸的方式,但这是以额外的内存开销为代价的。

2. inSampleSize 属性

BitmapFactory.Options的属性inSampleSize在解码时就会重新调整图像的大小,避免为临时的图像进行解码操作。在加载图像时,会使用一个整形值x来加载原图1/x的图像。例如,设置inSampleSize的值为2,则会返回一个1/2原图大小的图像,设置inSampleSize的值为4,则会返回一个1/4原图大小的图像。一般来说,图像的大小会比原图尺寸小2的某次方;

从内存性能的角度,使用inSampleSize是最快的一种方式,因为它只解码原图的1/x像素到最终的图像里。inSampleSize也有两个主要的问题:

  • 它不会给你一个确切的分辨率,它只会减小原图的2的某次方大小;
  • 它不会产生重新调整后的最好的图像质量,大部分的调整过滤器都会通过读取像素块,并根据权重来得到调整后的像素。但inSampleSize仅仅是每隔几个像素读取一个像素来保证高性能,低内存,但图像的质量可能就没有那么好。

如果你只是想得到原图的某个比例的图像,但对图像的质量没什么要求,这种方法的最高效的内存利用方式;

3. inScaled, inDensity, inTargetDensity 属性

如果你想得到的图像的尺寸并不是原图的2的某次方之一($1/2^x$),那么你就需要BitmapFactory.Options的这些属性inScaled, inDensity, inTargetDensity。如果设置了inScaled属性,系统就会通过inDensity的值和inTargetDensity的值来得到新图的尺寸并用这个尺寸来创建新图。如:
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);
使用这个方法可以得到较好图像质量的缩略图,因为在调整的过程中,会运用图像过滤器(也就是某些数字方法来补偿)来让图像看起来更好。但需要注意的是:额外的过滤补偿,会带来额外的处理时间,这个时间在处理大图像时会快速增强,会导致调整的时间变慢,并且过滤器本身也需要额外的内存分配。

因此,如果原图比你希望得到的图像的大小大太多的话,这个方法并不会是比较好的选择,因为它需要额外的过滤补偿过程;

4. 混合使用这些方法

从内存和性能的角度考虑,我们可以考虑混合使用这些方法来得到一个最好的结果(设置inSampleSize,inScaled, inDensity, inTargetDensity 属性)。

首先设置inSampleSize比希望得到的图像尺寸的2的某次方大(如:希望得到一个原图1/4大小的图像,则设置inSampleSize的值为2,这些就会先得到原图1/2大小的图像)。然后通过设置inDensity, inTargetDensity属性来精确需要得到图像的尺寸,并使用过滤器来处理图像(让图像变得更好看)。

混合使用这两个方法是比较快速的操作,因为inSampleSize操作会减小后面操作的像素。如:

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);

因此如果你需要得到一个精确尺寸,并且图像质量还可以的图像,这个方法是一个不错的选择。

5. 得到图像的尺寸

为了调整图像的大小在不解码原图的情况下得到原图的尺寸。通过设置inJustDecodeBounds属性来帮助你得到原图的尺寸;如:

// 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

你可以使用这个属性来先得到原图的尺寸,然后计算得到目标图像的具体值;

[译]Android调整图像大小的一些方法的更多相关文章

  1. C#中如何调整图像大小

    在本篇文章中,我将介绍如何在C#中来调整你想要的图像大小.要实现这一目标,我们可以采取以下几个步骤: 1.首先要获取你想要调整大小的图像: string path = Server.MapPath(& ...

  2. 如何在 HTML 中调整图像大小?

    了解在 HTML 中调整图像大小的不同技术.何时应避免在浏览器端调整大小,以及在 Web 上操作和提供图像的正确方法. 如果您的图像不适合布局,您可以在 HTML 中调整其大小.在 HTML 中调整图 ...

  3. (opencv08)cv.resize()调整图像大小

    (opencv08)cv.resize()调整图像大小 img = cv2.resize(src, dsize, dst=None, fx=None, fy=None, interpolation=N ...

  4. PHP获取远程图片并调整图像大小(转)

    <?php /** * *函数:调整图片尺寸或生成缩略图 *修改:2013-2-15 *返回:True/False *参数: * $Image 需要调整的图片(含路径) * $Dw=450 调整 ...

  5. PHP获取远程图片并调整图像大小

    <?php /** * *函数:调整图片尺寸或生成缩略图 *修改:2013-2-15 *返回:True/False *参数: *   $Image   需要调整的图片(含路径) *   $Dw= ...

  6. visio调整画布大小的简便方法

    按住Ctrl,然后鼠标在边缘拉拽即可.

  7. Android动态Java代码调整window大小

    Android调整window大小 举一个例子,设置当前的APP所需要的屏幕高度为设备高度的一半: Window window = getActivity().getWindow(); WindowM ...

  8. Linux中如何使用gThumb批量调整图片大小

    Linux中如何使用gThumb批量调整图片大小 导读 如果你的工作涉及到图片编辑和处理,就一定会有同时对多张图片进行批量大小调整的经历.虽然大多数图片编辑应用都能够非常容易地批量调整多张图片,但对于 ...

  9. CSS 是怎样确定图像大小的?

    本文转自奇舞周刊学习使用侵权删 先来看个例子,热热身. 上面这张图像的原始尺寸是:宽 54px 高 49px. 那么,在以下代码中,每张图像显示的最终尺寸是多少? https://p1.ssl.qhi ...

随机推荐

  1. Java程序设计之整数分解

    题目:题目:将一个正整数分解质因数.例如:输入90,打印出90=2*3*3*5. 解题过程也很简单,下面直接上代码了: import java.util.ArrayList; import java. ...

  2. AC日记——校门外的树 洛谷 P1047

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  3. 详解CSS中:nth-child的用法

    前端的哥们想必都接触过css中一个神奇的玩意,可以轻松选取你想要的标签并给与修改添加样式,是不是很给力,它就是“:nth-child”. 下面我将用几个典型的实例来给大家讲解:nth-child的实际 ...

  4. onselectstart与onselect

    这两个事件看起来很相似,事实上却非常的不同. onselectstart onselectstart几乎可以用于所有对象,其触发时间为目标对象被开始选中时(即选中动作刚开始,尚未实质性被选中).该事件 ...

  5. try catch中用了 Response.Redirect 引发的线程异常终止

    记录一下,提醒自己. 今天写代码的时候,在try 中写了一句  Response.Redirect 在 catch 把页面重定向到了另外一个地方 本来是想打算,如果没出现异常,就定到页面A,如果异常了 ...

  6. C#基础系列——异步编程初探:async和await

    前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了 ...

  7. C#软件设计——小话设计模式原则之:单一职责原则SRP

    前言:上篇C#软件设计——小话设计模式原则之:依赖倒置原则DIP简单介绍了下依赖倒置的由来以及使用,中间插了两篇WebApi的文章,这篇还是回归正题,继续来写写设计模式另一个重要的原则:单一职责原则. ...

  8. 未封装的js放大镜特效

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>j ...

  9. Android 摇一摇功能的注意事项

    /**开始重力传感器的检测*/ public void start() { // 获得传感器管理器 sensorManager = (SensorManager) mContext.getSystem ...

  10. 计算机中位(bit), 字节(byte), 字(word)的关系

    1.位(bit) 来自英文bit,音译为“比特”,表示二进制位.位是计算机内部数据储存的最小单位,11010100是一个8位二进制数.一个二进制位只可以表示0和1两种状态(21):两个二进制位可以表示 ...