初识Android Bitmap

Bitmap

Drawable,Canvas和Bitmap

  • drawable:通用的图形对象,用于装载常用格式的图像,既可以是PNG,JPG,gif这样的图像。同时包含13种Drawable类型的可视化对象,StateListDrawable,BitmapDrawable...
  • Canvas:画布,也就是我们可以绘制的区域。提供了drawXXX()等方法来便捷的绘制图形。
  • Bitmap:是一种存储像素的数据结构,通过这个对象可以得到一系列的图像属性。还可以对图像进行旋转,切割,放大,缩小等操作。

个人理解:Bitmap是一种数据结构,存储像素信息。Drawable 储存的是 对 Canvas 的一系列操作。而 BitmapDrawable 储存的是「把 Bitmap 渲染到 Canvas 上」这个操作。

Bitmap,BitmapFactory,BitmapFacotry.Options

获取Bitmap

由于Bitmap的构造方法私有化,所以我们不能在外部直接实例化一个Bitmap对象。我们只能通过BitmapFactory来得到Bitmap对象。

BitmapFractory常用获取Bitmap的方法:

途径 方法
从文件中解析 decodeFile(String pathName, Options), decodeFile(String pathName)
从res/目录下解析 decodeResource(Resources res,int id), decodeResurce(Resources res, int id, Options)
从字节数组中解析 decodeByteArray(byte[] data, int offset, int length), decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
从流中解析 decodeStream(InputStream is), decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)

通过上述表格我们发现,无论是哪一种途径得到的Bitmap都有一种重载方法的参数列中多了一个BitmapFacotry.Options参数。那么BitmapFacotry.Options是干嘛的呢?

举个例子,我们为了缩放图像想要获取该图像的大小,那么首先要在代码中获取这个图像的Bitmap对象,然后通过Bitmap.getWidth()和getheight()方法来获取图像的大小。但是如果想要获取一个大图像的大小,在得到Bitmap对象时会造成oom。这时我们就可以用到BitmapFractory.Options对象的inJustDecodeBounds字段。操作方法:

  • 首先获取一个Options对象,并将inJustDecodeBounds设置为True。
  • 然后选择一种获取Bitmap途径的方法,并传入Options对象。此时该方法返回的Bitmap为null。
  • 然后通过Options.outWidth和outHeight来获取院士图片的大小
  • 通过设置Options.inSampleSize来决定获取Bitmap时缩小图像长宽的系数。
  • 最后我们把Options实例的inJustDecodeBounds设置为false,并通过该实例获取大图像的Bitmap。这样就防止了OOM

BitmapFactory.Options类有一个参数inSampleSize,该参数为int型,他的值指示了在解析图片为Bitmap时在长宽两个方向上像素缩小的倍数。inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理),且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。参考博文高效使用Bitmaps(一) 大Bitmap的加载,BitmapFactory.Options详解

Bitmap常用方法

  • public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) 将位图的压缩到指定的OutputStream,可以理解成将Bitmap保存到文件中!
    • format:格式,PNG,JPG等;
    • quality:压缩质量,0-100,0表示最低画质压缩,100最大质量(PNG无损,会忽略品质设定)
    • stream:输出流
    • 返回值代表是否成功压缩到指定流!
  • void recycle():回收位图占用的内存空间,把位图标记为Dead
  • boolean isRecycled():判断位图内存是否已释放
  • int getWidth():获取位图的宽度
  • int getHeight():获取位图的高度
  • boolean isMutable():图片是否可修改
  • int getScaledWidth(Canvas canvas):获取指定密度转换后的图像的宽度
  • int getScaledHeight(Canvas canvas):获取指定密度转换后的图像的高度
  • Bitmap createBitmap(Bitmap src):以src为原图生成不可变得新图像
  • Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter):以src为原图,创建新的图像,指定新图像的高宽以及是否变。
  • Bitmap createBitmap(int width, int height, Config config):创建指定格式、大小的位图
  • Bitmap createBitmap(Bitmap source, int x, int y, int width, int
    height)以source为原图,创建新的图片,指定起始坐标以及新图像的高宽。
  • public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
    Matrix m, boolean filter)

BitmapFractory.Options字段

  • boolean inJustDecodeBounds——如果设置为true,不获取图片,不分配内存,但会返回图片的高宽度信息。
  • int inSampleSize——图片缩放的倍数。如果设为4,则宽和高都为原来的1/4,则图是原来的1/16。
  • int outWidth——获取图片的宽度值
  • int outHeight——获取图片的高度值
  • int inDensity——用于位图的像素压缩比
  • int inTargetDensity——用于目标位图的像素压缩比(要生成的位图)
  • boolean inScaled——设置为true时进行图片压缩,从inDensity到inTargetDensity。

获取Bitmap实例

从资源中获取位图的方式有两种:通过BitmapDrawable或者BitmapFactory。

BitmapDrawable

Android支持三种格式的位图图像:.png (preferred),.jpg (acceptable), .gif (discouraged)。
括号里的说明,代表这三种格式的图片在Android中的支持情况,.png格式图片优先,.jpg格式也可以,但是效果没有.png好,.gif支持最差。

在构建应用的时候,Bitmap文件可能会被appt工具压缩自动优化为无损图像。例如,一个真彩色PNG,不需要超过256的颜色可以被转换成一个8位PNG和调色板。这将导致一个图像质量相同,但这需要更少的内存。所以要意识到,在drawable目录中图像的二进制文件在构建程序时可以改变。如果你打算读一个图像作为字节流并将它转换成一个位图,把你的图片放在在res /raw/文件夹里,在那里他们不会被优化。参考博文Android Drawable Resource学习(二)、BitmapDrawable和Bitmap

获取BitmapDrawable

  • Bitmap file
    我们可以直接从res/drawable目录下的图片文件(.jpg,.png,.gif)获取drawable对象,并将其转型为BitmapDrawable

res/drawable目录下的图片文件(.jpg,.png,.gif)编译资源数据类型:指向BitmapDrawable类型的指针。

  • XML Bitmap:
    一个XML bitmap是一个在XML文件中定义的指向一个bitmap文件的资源。其效果是作为一个原始位图文件的别名,并且可以指定一些额外的属性。<bitmap>是Bitmap XML的根标签,它有很多属性设置,实现平铺、拉伸或保持图片原始大小,也可以指定对齐方式等效果。可以参考博文Android样式的开发:drawable汇总篇

同样编译资源类型指向BitmapDrawable类型的指针

Drawable向下转型

Resources res=getResources();  
Drawable drawable = res.getDrawable(R.drawable.file_name);  
//实际上这是一个BitmapDrawable对象  
BitmapDrawable bitmapDrawable=(BitmapDrawable)drawable;  
//可以在调用getBitmap方法,得到这个位图  
Bitmap bitmap=bitmapDrawable.getBitmap(); 

BitmapDrawable构造方法

InputStream is=res.openRawResource(R.drawable.file_name);
BitmapDrawable bmpDraw=new BitmapDrawable(is);
Bitmap bmp=bmpDraw.getBitmap();

还有其他构造方法,可以查阅官方文档

Bitmap 2 BitmapDrawable

Drawable drawable = new BitmapDrawable(bitmap);

BitmapFactory

通过上述表格中各种途径的静态方法来获取Bitmap

//res/drawable目录下资源id获取
BitmapFactory.decodeResource(res, resId);
//文件路径获取
BitmapFactory.decodeFile(pathName);
//输入流获取
BitmapFactory.decodeStream(inputStream);

字节流

从字节流获取Bitmap

public Bitmap Bytes2Bimap(byte[] b) {  
    if (b.length != 0) {  
        return BitmapFactory.decodeByteArray(b, 0, b.length);  
    } else {  
        return null;  
    }  
} 

Bitmap转换为字节流

public byte[] Bitmap2Bytes(Bitmap bm) {  
    ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    bm.compress(Bitmap.CompressFormat.PNG, 100, baos);  
    return baos.toByteArray();  
}  

Bitmap.Config

在Bitmap类里createBitmap(intwidth, int height, Bitmap.Config config)方法里有一个参数Bitmap.Config是用来做什么的呢?

要解决Bitmap的OOM问题可以有两种方法:

  • 压缩大图片的大小,缩放
  • 改变大图片的色彩存储方法

那么Bitmap.Config就是图片存储颜色。在Bitmap.Config文档中我们看到四个枚举变量。

  • Bitmap.Config : ALPHA_8, 就是Alpha由8位组成
  • Bitmap.Config : ARGB_4444, 就是由4个4位组成即16位,
  • Bitmap.Config : ARGB_8888, 就是由4个8位组成即32位,
  • Bitmap.Config : RGB_565, 就是R为5位,G为6位,B为5位共16位

ARGB指的是一种色彩模式,里面A代表Alpha,R表示red,G表示green,B表示blue,其实所有的可见色都是右红绿蓝组成的,所以红绿蓝又称为三原色,每个原色都存储着所表示颜色的信息值。位图位数越高代表其可以存储的颜色信息越多,当然图像也就越逼真。

参考博文android图片压缩质量参数Bitmap.Config RGB_565等的含义

Bitmap缩放

public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        float srcWidth = options.outWidth;
        float srcHeight = options.outHeight;

        int inSampleSize = 1;
        if(srcHeight > destHeight || srcWidth > destWidth) {
            if(srcWidth > srcHeight) {
                inSampleSize = Math.round(srcHeight / destHeight);
            } else {
                inSampleSize = Math.round(srcWidth /destWidth);
            }
        }

        options = new BitmapFactory.Options();
        options.inSampleSize = inSampleSize;

        return BitmapFactory.decodeFile(path, options);
    }

参考

android图片压缩质量参数Bitmap.Config RGB_565等的含义

Android基础入门教程——8.2.1 Bitmap(位图)详解

高效使用Bitmaps(一) 大Bitmap的加载,BitmapFactory.Options详解

Android样式的开发:drawable汇总篇

【Android】Drawable、Bitmap、Canvas、Paint之间区别

目标

  • 图片的两种解决OOM问题
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容