编写:徐建祥(netpirate@gmail.com)
日期:2010/12/06
网址:http://www.anymobile.org
传输文件,或者设置头像,我们一般都会检查原始图片的大小,作缩放处理。
常用的Java版缩放图片代码:
view plaincopy to clipboardprint?
public Bitmap getZoomImage(Bitmap src, int desW, int desH)
{
Bitmap desImg = null;
int srcW = src.getWidth(); // 原始图像宽
int srcH = src.getHeight(); // 原始图像高
int[] srcBuf = new int[srcW * srcH]; // 原始图片像素信息缓存
src.getPixels(srcBuf, 0, srcW, 0, 0, srcW, srcH);
// 计算插值表
int[] tabY = new int[desH];
int[] tabX = new int[desW];
int sb = 0;
int db = 0;
int tems = 0;
int temd = 0;
int distance = srcH > desH ? srcH : desH;
for (int i = 0; i <= distance; i++)
{/* 垂直方向 */
tabY[db] = sb;
tems += srcH;
temd += desH;
if (tems > distance)
{
tems -= distance;
sb++;
}
if (temd > distance)
{
temd -= distance;
db++;
}
}
sb = 0;
db = 0;
tems = 0;
temd = 0;
distance = srcW > desW ? srcW : desW;
for (int i = 0; i <= distance; i++)
{/* 水平方向 */
tabX[db] = (short) sb;
tems += srcW;
temd += desW;
if (tems > distance)
{
tems -= distance;
sb++;
}
if (temd > distance)
{
temd -= distance;
db++;
}
}
// 生成放大缩小后图形像素
int[] desBuf = new int[desW * desH];
int dx = 0;
int dy = 0;
int sy = 0;
int oldy = -1;
for (int i = 0; i < desH; i++)
{
if (oldy == tabY[i])
{
System.arraycopy(desBuf, dy - desW, desBuf, dy, desW);
}
else
{
dx = 0;
for (int j = 0; j < desW; j++)
{
desBuf[dy + dx] = srcBuf[sy + tabX[j]];
dx++;
}
sy += (tabY[i] - oldy) * srcW;
}
oldy = tabY[i];
dy += desW;
}
// 生成图片
desImg = Bitmap.createBitmap(desBuf, desW, desH, Bitmap.Config.ARGB_8888);
return desImg;
}
常用的Android版缩放图片代码:
view plaincopy to clipboardprint?
ContentResolver cr = this.getContentResolver();
try
{
InputStream in = cr.openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(in);
try
{
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
if(null == bitmap)
{
Toast.makeText(this, "Head is not set successful,Decode bitmap failure", 2000);
}
//原始图片的尺寸
int bmpWidth = bitmap.getWidth();
int bmpHeight = bitmap.getHeight();
//缩放图片的尺寸
float scaleWidth = (float) 40 / bmpWidth;
float scaleHeight = (float) 40 / bmpHeight;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
//产生缩放后的Bitmap对象
Bitmap resizeBitmap = Bitmap.createBitmap(
bitmap, 0, 0, bmpWidth, bmpHeight, matrix, false);
bitmap.recycle();
//Bitmap to byte[]
byte[] photoData = Bitmap2Bytes(resizeBitmap);
//save file
String fileName = "/sdcard/test.jpg";
FileUtil.writeToFile(fileName, photoData);
//save photo check sum to db
DataCenter.GetInstance().ModifyIMMUser();
//refresh ImageView
}
catch (FileNotFoundException exp)
{
exp.printStackTrace();
}
如果图片非常大,在执行BitmapFactory.decodeStream的时候就会抛出OOM异常。
我们来看看系统应用MMS是如何处理的,SMS添加了多媒体附件后就作MMS处理了,当附加文件原图超过300K,也会做个缩放处理,具体参考:com.android.mms.ui/.UriImage:
view plaincopy to clipboardprint?
package com.android.mms.ui;
public class UriImage
{
private int mWidth;
private int mHeight;
... ...
//
private void decodeBoundsInfo()
{
InputStream input = null;
try
{
input = mContext.getContentResolver().openInputStream(mUri);
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;//只描边,不读取数据
BitmapFactory.decodeStream(input, null, opt);
mWidth = opt.outWidth;
mHeight = opt.outHeight;
}
catch (FileNotFoundException e)
{
// Ignore
Log.e(TAG, "IOException caught while opening stream", e);
}
finally
{
if (null != input) {
try {
input.close();
} catch (IOException e) {
// Ignore
Log.e(TAG, "IOException caught while closing stream", e);
}
}
}
}
private byte[] getResizedImageData(int widthLimit, int heightLimit)
{
int outWidth = mWidth;
int outHeight = mHeight;
int s = 1;
while ((outWidth / s > widthLimit) || (outHeight / s > heightLimit))
{
s *= 2;
}
//先设置选项
BitmapFactory.Options options = new BitmapFactory.Options();
//returning a smaller image to save memory.
options.inSampleSize = s;
InputStream input = null;
try
{
input = mContext.getContentResolver().openInputStream(mUri);
Bitmap b = BitmapFactory.decodeStream(input, null, options);//注意看options的用法
if (b == null) {
return null;
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
b.compress(CompressFormat.JPEG, MessageUtils.IMAGE_COMPRESSION_QUALITY, os);
return os.toByteArray();
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage(), e);
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
}
}
}
}
... ...
}
可以看出,MMS应用的方法是:先设置缩放选项,再读取缩放的图片数据到内存,规避了内存引起的OOM。
修改后的代码:
view plaincopy to clipboardprint?
ContentResolver cr = this.getContentResolver();
try
{
InputStream in = cr.openInputStream(uri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
try
{
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
int mWidth = options.outWidth;
int mHeight = options.outHeight;
int sWidth = 40;
int sHeight = 40;
int s = 1;
while ((mWidth / s > sWidth * 2) || (mHeight / s > sHeight * 2))
{
s *= 2;
}
options = new BitmapFactory.Options();
options.inSampleSize = s;
in = cr.openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(in, null, options);
try
{
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
if(null == bitmap)
{
Toast.makeText(this, "Head is not set successful,Decode bitmap failure", 2000);
return ;
}
//原始图片的尺寸
int bmpWidth = bitmap.getWidth();
int bmpHeight = bitmap.getHeight();
//缩放图片的尺寸
float scaleWidth = (float) sWidth / bmpWidth;
float scaleHeight = (float) sHeight / bmpHeight;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
//产生缩放后的Bitmap对象
Bitmap resizeBitmap = Bitmap.createBitmap(
bitmap, 0, 0, bmpWidth, bmpHeight, matrix, false);
bitmap.recycle();
Bitmap resizeBitmap = bitmap;
//Bitmap to byte[]
byte[] photoData = bitmap2Bytes(resizeBitmap);
//save file
String fileName = "/sdcard/test.jpg";
FileUtil.writeToFile(fileName, photoData);
view plaincopy to clipboardprint?
private byte[] bitmap2Bytes(Bitmap bm)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
return baos.toByteArray();
}
OVER!
分享到:
相关推荐
总结来说,解决ListView中图片引起的内存溢出问题,我们需要做到以下几点: 1. 利用ListView的视图复用机制,通过ViewHolder重用ImageView。 2. 使用适当的图片解码策略,如设置`inSampleSize`,降低图片内存占用。 ...
在Android中,加载大尺寸图片可能会导致内存溢出(Out Of Memory,OOM)问题,因为原生的Bitmap对象会占用大量内存。为解决这个问题,我们需要采用合适的图片解码策略,如按需加载和缩放图片。例如,可以使用`...
4. **解决Bitmap引起的内存溢出** - **内存优化策略**:使用`BitmapFactory.Options.inSampleSize`来降低图片的解码大小,减少内存消耗。合理设置这个参数,可以在不失真的情况下减小图像的分辨率。 - **使用...
Bitmap 的不当使用很容易导致内存溢出(OOM),严重影响应用的性能和稳定性。因此,了解 Bitmap 占用的内存大小至关重要。本文将深入探讨 Bitmap 内存计算的原理,并提供一种预测 Bitmap 内存占用的方法。 首先,...
在Android开发中,"图片OOM"是一个常见的问题,全称为"Out Of Memory",即内存溢出异常。...通过合理的图片处理方式和利用现有的优秀库,可以有效地避免和处理图片引起的内存溢出问题,提升应用性能和用户体验。
#### 二、如何避免OOM(内存溢出)异常 **OOM异常产生的原因**: - Android应用运行在一个Dalvik虚拟机环境中,默认堆内存通常较小,这使得Android应用更容易发生OOM异常。 - 当程序尝试分配一大块内存但虚拟机无法...
在Android开发中,图片处理是一项常见的任务,尤其是在创建应用程序时,可能会遇到图片过大导致内存溢出或者加载速度过慢的问题。本篇文章将详细介绍如何在Android编程中实现图片的压缩和加载显示,帮助开发者掌握...
通过这些转换,Picasso能有效地减少内存消耗,尤其是对于大图或者高清图,它可以防止因图片过大而引起的内存溢出。同时,Picasso还可以根据设备的屏幕分辨率自动调整图片大小,进一步优化内存使用。 3. **简单的API...
创建时应考虑到内存管理,避免内存溢出。 2. **内存管理**:Bitmap占用的内存大小是其宽度、高度和颜色深度的乘积。Android系统提供了几种配置来控制Bitmap在内存中的存储方式,如ARGB_8888(每个像素4字节),RGB_...
确保考虑到内存管理,避免因加载大图导致内存溢出。可以使用`Options`参数来指定解码尺寸和缩放比例。 2. **转换为字节数组**: 调用`Bitmap`对象的`compress()`方法,将Bitmap压缩为JPEG或PNG格式的字节数组。...
- 通常由未捕获的异常、资源泄漏、内存溢出等问题引起。 以上内容涵盖了Android开发中的关键知识点,对于面试和实际工作都具有很高的参考价值。理解并掌握这些概念,将有助于提升Android开发技能和应对面试挑战。
总结,插入图片到`EditText`是通过`SpannableString`和`ImageSpan`实现的,而防止图片引起的OOM问题则需要合理管理图片资源,包括压缩、使用合适分辨率、缓存以及及时释放。在实际项目中,结合`ImageTextDemo`的代码...
3. **磁盘缓存**:当内存不足以存放所有图片时,可以将部分图片存储到磁盘,避免内存溢出,同时提供离线访问能力。 4. **图片解码**:对下载的图片进行适当的解码处理,比如缩放、裁剪,以适应ListView的item大小,...
本文将深入探讨Android图片压缩的原理和实现方法,以及如何避免因图片过大导致的内存溢出(Out Of Memory,简称OOM)问题。 首先,Android系统对每个应用的内存分配是有限制的,如果直接加载大尺寸的图片,可能导致...
要注意的是,Bitmap占用内存较大,不建议在内存中大量存储,尤其是对于高清大图,可能引起内存溢出。使用后记得及时回收(`bitmap.recycle()`),并考虑使用`BitmapFactory.Options`进行解码优化。 总之,获取...
在安卓开发中,Bitmap是用于处理图像数据的重要类,它占据了大量的内存,特别是在处理高清图片时,可能会引发内存溢出(OutOfMemoryError)问题。因此,对Bitmap进行压缩是优化应用性能的关键环节。这个“完善的压缩...
3. **图片压缩**:Glide支持在加载图片前进行压缩,减小内存占用,防止内存溢出。 4. **自定义网络栈**:虽然默认使用HttpUrlConnection,但Glide允许开发者集成其他网络库,如Volley或OkHttp,以适应不同的网络...