当Android程序中需要加载特别大的照片时,(指的是照片的分辨率不得超过手机屏幕大小,)
此时内存吃不消,需要缩放图片,否则可能出现OOM(Out Of Memory)即内存溢出。
如下图:
- 首先解析一下基本的知识:
- 位图模式,bitmap颜色位数是1位
- 灰度模式,bitmap颜色位数是8位,和256色一样
- RGB模式,bitmap颜色位数是24位 在RGB模式下,一个像素对应的是红、绿、蓝三个字节
- CMYK模式,bitmap颜色位数是32位 在CMYK模式下,一个像素对应的是青、品、黄、黑四个字节
- 图像文件的字节数(Byte) = 图像分辨率*颜色深度/8(bit/8)
- 例如:一幅640*480图像分辨率、RGB色一般为24位真彩色,图像未经压缩的数据容量为:640X480X24/8=921600字节=900KB(1KB=l千字节=1024字节)。
- 注:一个图像文件占的磁盘空间大小还和磁盘的文件格式有关。如:NTFS最小单位为4KB 所以图像文件大小肯定是4KB的倍数。但是有图图片压缩算法的存在,图片文件在保存时,体积要比在内存的大小小得多,如640x480的图片文件大小一般只在200K~300K。这也是为什么,加载几MB的图片文件,会导致JVM内存溢出,导致OutofMemoryException的原因。
- 由上面的公式,我们可以得出,加载的图片所占的内存大小,取决于其分辨率和颜色数。
- 我们再来看看Google官方的介绍:
- 这个已经非常的明白了,我们VM的app进程所获得的内存只有区区的16MB,普普通通的5MP摄像头拍出来的图片,直接加载,将占用接近19MB的内存。可见,不进行压缩,内存将会直接溢出。
来自 <http://blog.csdn.net/life02/article/details/7992727>
我在程序中通过两种方式来解决问题:
1.采用BitmapFactory.Options 直接缩放:
BitmapFactory.Options bmpFactoryOptions = newBitmapFactory.Options();
bmpFactoryOptions.inSampleSize = 8;
Bitmap bmp =BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
imv.setImageBitmap(bmp);
2.
根据当前屏幕分辨率的大小,加载图片
Display currentDisplay =getWindowManager().getDefaultDisplay();
int dw = currentDisplay.getWidth();
int dh = currentDisplay.getHeight();
BitmapFactory.OptionsbmpFactoryOptions = new BitmapFactory.Options();//解析位图的附加条件
bmpFactoryOptions.inJustDecodeBounds= true; //允许调用者查询位图信息,并且不需要加载到内存中,不去解析真实的位图,只是获取这个位图的头文件信息
Bitmap bmp =BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
int bitmapWidth = bmpFactoryOptions.outHeight;
int bitmapHeight = bmpFactoryOptions.outWidth;
int dx=bitmapWidth/dw;
Int dy=bitmapHeight/dh;
Int scale=1;
if(dx>dy&&dy>1){
scale=dx;//按水平方向缩放图片。
}
if(dy>dx&&dx>1){
scale=dy;
}
bmpFactoryOptions.inSampleSize=scale;
bmpFactoryOptions.inJustDecodeBounds= false;//真正的去解析这个位图;
bmp = BitmapFactory.decodeFile(imageFilePath,bmpFactoryOptions);
如果要对位图修改,最好做一个图形拷贝,不要直接在原位图上修改:
//创建原图的一个副本,可修改(createBitmap,有两种构造方法,一种可以修改,一种不可以),创建的是一个空白的图形。
alterBitmap=Bitmap.createBitmap(srcBmp.getWidth()*2,srcBmp.getHeight()*2,srcBmp.getConfig());
然后修改一个位图可以分为3步:
1.准备一个画板,在上面放上准备好的空白的位图。
Canvascanvas=new Canvas(alterBitmap);
//2.准备一个画笔
Paintpaint=new Paint();
//paint.setColor(Color.BLACK);//设置画笔的默认颜色。
//3.画画
Matrixmatrix=new Matrix();
// canvas.drawBitmap(srcBmp,matrix, paint);//Matrix指的是图片的缩放比例,直接new Matrix()是按1:1
/*设置缩放比例的一种方式
matrix.setValues(newfloat[]{
1,0,0,
0,0.5f,0,
0,0,1
});
X=1x+0y+0z;
Y=0x+1y+0z;
Z=0x+0y+1z;
*/
/*
* 设置缩放比例的另一种方式
matrix.setScale(0.5f,0.5f);
canvas.drawBitmap(srcBmp,matrix, paint);*/
/*
//图形的旋转
matrix.setRotate(180,srcBmp.getWidth()/2, srcBmp.getHeight()/2);
*/
/*
//镜子效果(照镜子)
matrix.setScale(-1.0f,1.0f);
matrix.postTranslate(srcBmp.getWidth(), 0);//x轴平移
*/
//倒影效果
matrix.setScale(1.0f,-1.0f);
matrix.postTranslate(0,srcBmp.getHeight());
canvas.drawBitmap(srcBmp,matrix, paint);
iv2.setImageBitmap(alterBitmap);//把原图的副本设置到界面上
}