Android Bitmap详解

转载自http://www.cnblogs.com/winter-is-coming/p/9112192.html

获取图片尺寸https://blog.csdn.net/shb2058/article/details/71107774


Android Bitmap详解

Google Developer:Bitmap

一、基本信息

Bitmap位图包括像素以及长、宽、颜色等描述信息。长宽和像素位数是用来描述图片的,可以通过这些信息计算出图片的像素占用内存的大小。

位图可以理解为一个画架,把图放到上面然后可以对图片做一些列的处理。

位图文件图像显示效果好,但是非压缩格式,需要占用较大的存储空间。

1. Config:表示图片像素类型,包括ALPHA_8、RGB_565、ARGB_4444、ARGB_8888 A:透明度;RGB分别是Red、Green、Blue,三种原色

ARGB_8888:四个通道都是8位,每个像素占用4个字节,图片质量是最高的,但是占用的内存也是最大的;

ARGB_4444:四个通道都是4位,每个像素占用2个字节,图片的失真比较严重;

RGB_565:没有A通道,每个像素占用2个字节,图片失真小,但是没有透明度;

ALPHA_8:只有A通道,每个像素占用1个字节大大小,只有透明度,没有颜色值。

使用场景总结:ARGB_4444失真严重,基本不用;ALPHA_8使用场景特殊,比如设置遮盖效果等;不需要设置透明度,RGB_565是个不错的选择;既要设置透明度,对图片质量要求又高,就用ARGB_8888。

2. CompressFormat:Bitmap.CompressFormat.JPEG、Bitmap.CompressFormat.PNG、Bitmap.CompressFormat.WEBP三种压缩格式

JPEG:一种有损压缩(JPEG2000既可以有损也可以无损),".jpg"或者".jpeg"; 优点:采用了直接色,有丰富的色彩,适合存储照片和生动图像效果;缺点:有损,不适合用来存储logo、线框类图。

PNG: 一种无损压缩,".png"; 优点:支持透明、无损,主要用于小图标,透明背景等;缺点:若色彩复杂,则图片生成后文件很大;

WEBP:以WebP算法进行压缩;Google开发的新的图片格式,同时支持无损和有损压缩,使用直接色。无损压缩,相同质量的webp比PNG小大约26%;有损压缩,相同质量的webp比JPEG小25%-34% 支持动图,基本取代gif

详细介绍参见【转】WebP原理和支持现状

二、加载

BitmapFactory提供了四类方法:decodeFile、decodeResource、decodeStream、decodeByteArray

1. 从文件中读取

try {

    FileInputStream in =newFileInputStream("/sdcard/Download/sample.png");

} catch (FileNotFoundException e) {

    e.printStackTrace();

}

Bitmap bitmap = BitmapFactory.decodeStream(in);

Bitmap bm = BitmapFactory.decodeFile(sd_path); // 间接调用 BitmapFactory.decodeStream

2. 从资源中读取

Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sample); // 间接调用 BitmapFactory.decodeStream

3. 从字节序列里读取

// InputStream转换成byte[]Bitmap bm = BitmapFactory.decodeByteArray(myByte,0,myByte.length);

巨图加载:BitmapRegionDecoder,可以按照区域进行加载

高效加载:核心其实也很简单,主要是采样压缩、缓存策略、异步加载等

1. 采样压缩 (->【自】高斯模糊)

BitmapFactory.Options options =new BitmapFactory.Options();  //inJustDecodeBounds为true,不返回bitmap,只返回这个bitmap的尺寸  options.inJustDecodeBounds =true;

BitmapFactory.decodeResource(getResources(), images[position], options);

//利用返回的原图片的宽高,我们就可以计算出缩放比inSampleSize(只能是2的整数次幂)

options.inSampleSize = caluelateInSampleSize(options, reqWidth, reqHeight);//使用RGB_565减少图片大小  options.inPreferredConfig = Bitmap.Config.RGB_565;  //释放内存,共享引用(21版本后失效)  options.inPurgeable =true; 

options.inInputShareable =true; 

            //inJustDecodeBounds为false,返回bitmap  options.inJustDecodeBounds =false; 

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), images[position], options);

privateintcalculateSampleSize(BitmapFactory.Options options,intreqWidth,int reqHeight){intwidth = options.outWidth;

    intheight =options.outHeight;intinSampleSize = 1;

    inthalfWidth = width / 2;

    inthalfHeight = height / 2;

    while((halfWidth / inSampleSize) >= reqWidth && (halfHeight / inSampleSize) >=reqHeight){

        inSampleSize *= 2;

    }

    return inSampleSize;

}

2. 缓存策略

LRU(最近最少使用) -> LruCache和DiskLruCache,LruCache用于内存缓存、DiskLruCache用户存储设备缓存

【转】Fresco缓存分析三级缓存:Bitmap -> 未解码图片缓存 -> 磁盘缓存 ->网络

md5 ->【自】密码学基础

3. 异步加载

【转】Fresco异步加载:线程池、Handler等

三、存储

根据android sdk版本有所不同。

2.3以前:图片像素存储在native内存中。缺点是虚拟机无法自动进行垃圾回收,必须手动使用recycle,很容易导致内存泄露。也不方便调试等;

3.0以后:图片像素存储在Java堆中,垃圾回收能够自动进行,内存占用也能方便的展示在monitor中;

4.0以后:传输方式发生变化,大数据会通过ashmem(匿名共享内存)来传递(不占用Java内存),小数据通过直接拷贝的方式(在内存中操作),放宽了图片大小的限制;

【转】Android4.0 Bitmap Parcel传输源码分析

6.0以后:加强了ashmen存储图片的方式

【转】Android6.0 Bitmap存储以及Parcel传输源码分析

enumclass PixelStorageType {

    Invalid,

    External,

    Java,

    Ashmem,

};

Fresco 5.0以前将图片存储在Ashmen中,不会自动GC,因为不在Java堆中,也不会造成OOM,很大的一个优势。5.0以后系统默认启用了Ashmen模式。

四、转换

// 定义矩阵Matrix matrix =new Matrix();  // 【缩放图像】matrix.postScale(0.8f, 0.9f);  // 【向左旋转】matrix.postRotate(-90);  // 【移动图像】matrix.postTranslate(100, 100);// 【裁减图像】Bitmap.createBitmap(Bitmap source,intx,inty,intwidth,intheight, Matrix m,booleanfilter)

// 【圆角】

//

准备画笔Paint paint =new Paint();

paint.setAntiAlias(true);

// 准备裁剪的矩阵Rect rect =newRect(0, 0, originBitmap.getWidth(), originBitmap.getHeight());

RectF rectF =newRectF(newRect(0, 0, originBitmap.getWidth(), originBitmap.getHeight()));

Bitmap roundBitmap = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);

Canvas canvas =new Canvas(roundBitmap);// 圆角矩阵,radius为圆角大小canvas.drawRoundRect(rectF, radius, radius, paint);

paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));// 这个比较有意思,混合模式  SRC_IN:显示交汇SRC图canvas.drawBitmap(originBitmap, rect, rect, paint);

【转】ndroid图像处理-Paint之Xfermode

//【图片灰阶处理】Bitmap grayBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); 

Canvas canvas =new Canvas(grayBitmap); 

Paint mPaint =new Paint(); 

              //创建颜色变换矩阵  ColorMatrix colorMatrix =new ColorMatrix();  //设置饱和度为0,实现灰阶效果colorMatrix.setSaturation(0);  //创建颜色过滤矩阵  ColorMatrixColorFilter colorFilter =new ColorMatrixColorFilter(colorMatrix);  //设置画笔的颜色过滤矩阵  paint.setColorFilter(colorFilter);  //使用处理后的画笔绘制图像  canvas.drawBitmap(bitmap, 0, 0, paint);

// 【Alpha位图】// 【倒影】// 【图像合成】// 无穷无尽啊...

五、内存优化

基于前面的原理来进行各方面的优化处理,缩放、Config、Compress选择、内存管理、缓存方式等等方面入手

六、开源框架

ImageLoader、Glide(google)、Fresco(FaceBook)、Picasso(Square)

Picasso包体积小、清晰,但功能有局限不能加载gif、只能缓存全尺寸;

Glide功能全面,擅长大型图片流,提交较大;

Fresco内存优化,减少oom,体积更大

你可能感兴趣的:(Android Bitmap详解)