java 上传图片 OOM_Android: 缩放图片文件引起的OOM异常

编写:徐建祥(netpirate@gmail.com)

日期:2010/12/06

网址:http://www.anymobile.org

传输文件,或者设置头像,我们一般都会检查原始图片的大小,作缩放处理。

常用的Java版缩放图片代码:

publicBitmap getZoomImage(Bitmap src,intdesW,intdesH)

{

Bitmap desImg = null;

intsrcW = src.getWidth();// 原始图像宽

intsrcH = src.getHeight();// 原始图像高

int[] srcBuf =newint[srcW * srcH];// 原始图片像素信息缓存

src.getPixels(srcBuf, 0, srcW,0,0, srcW, srcH);

// 计算插值表

int[] tabY =newint[desH];

int[] tabX =newint[desW];

intsb =0;

intdb =0;

inttems =0;

inttemd =0;

intdistance = srcH > desH ? srcH : desH;

for(inti =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(inti =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 =newint[desW * desH];

intdx =0;

intdy =0;

intsy =0;

intoldy = -1;

for(inti =0; i 

{

if(oldy == tabY[i])

{

System.arraycopy(desBuf, dy - desW, desBuf, dy, desW);

}

else

{

dx = 0;

for(intj =0; 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);

returndesImg;

}

常用的Android版缩放图片代码:

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

}

//原始图片的尺寸

intbmpWidth  = bitmap.getWidth();

intbmpHeight = bitmap.getHeight();

//缩放图片的尺寸

floatscaleWidth  = (float)40/ bmpWidth;

floatscaleHeight = (float)40/ bmpHeight;

Matrix matrix = newMatrix();

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:

packagecom.android.mms.ui;

publicclassUriImage

{

privateintmWidth;

privateintmHeight;

... ...

//

privatevoiddecodeBoundsInfo()

{

InputStream input = null;

try

{

input = mContext.getContentResolver().openInputStream(mUri);

BitmapFactory.Options opt = newBitmapFactory.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);

}

}

}

}

privatebyte[] getResizedImageData(intwidthLimit,intheightLimit)

{

intoutWidth = mWidth;

intoutHeight = mHeight;

ints =1;

while((outWidth / s > widthLimit) || (outHeight / s > heightLimit))

{

s *= 2;

}

//先设置选项

BitmapFactory.Options options = newBitmapFactory.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) {

returnnull;

}

ByteArrayOutputStream os = newByteArrayOutputStream();

b.compress(CompressFormat.JPEG, MessageUtils.IMAGE_COMPRESSION_QUALITY, os);

returnos.toByteArray();

} catch(FileNotFoundException e) {

Log.e(TAG, e.getMessage(), e);

returnnull;

} finally{

if(input !=null) {

try{

input.close();

} catch(IOException e) {

Log.e(TAG, e.getMessage(), e);

}

}

}

}

... ...

}

可以看出,MMS应用的方法是:先设置缩放选项,再读取缩放的图片数据到内存,规避了内存引起的OOM。

修改后的代码:

ContentResolver cr =this.getContentResolver();

try

{

InputStream in = cr.openInputStream(uri);

BitmapFactory.Options options = newBitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeStream(in, null, options);

try

{

in.close();

}

catch(IOException e)

{

e.printStackTrace();

}

intmWidth = options.outWidth;

intmHeight = options.outHeight;

intsWidth  =40;

intsHeight =40;

ints =1;

while((mWidth / s > sWidth *2) || (mHeight / s > sHeight *2))

{

s *= 2;

}

options = newBitmapFactory.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;

}

//原始图片的尺寸

intbmpWidth  = bitmap.getWidth();

intbmpHeight = bitmap.getHeight();

//缩放图片的尺寸

floatscaleWidth  = (float) sWidth / bmpWidth;

floatscaleHeight = (float) sHeight / bmpHeight;

Matrix matrix = newMatrix();

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

privatebyte[] bitmap2Bytes(Bitmap bm)

{

ByteArrayOutputStream baos = newByteArrayOutputStream();

bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);

returnbaos.toByteArray();

}

OVER!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值