编写:徐建祥(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!