bitmap位图是一种基于rgb颜色编码的点阵图形,由像素组成(一个一个小方块排列组成)**
JPEG:不能保存透明背景(缺少Alpha通道)?有损压缩故图片大小比较小
PNG:能保存透明背景,无损压缩,图片质量好,但是比较大
WEBP:好像是谷歌推出的一种图片格式,压缩率高
注意:WEBP支持不好(略),在android有时候我们做圆角头像如果用到了jpeg的图片你会发现图片后面有黑色背景,这就是因为jpeg不支持透明的原因。
Bitmap.Config getConfig () 返回位图的Config 值 setConfig(Bitmap.Config config) 设置config值 为了更好理解下面几个参数的意思这里解释下相关概念:
图片是由N个像素组成,图片大小和像素多少有关,色位、色深表示单个像素点自身的细化程度即能容纳颜色程度(色位深度),单位是bit(位),这个值的大小衡量了一个图片的质量。
ALPHA_8 :1个像素能存储8位alpha值 二进制:2^8=256 (256色)
ARGB_8888:1个像素能存储32位ARGB值 二进制:2^32=16777216 (真彩色)
RGB_565 :1个像素能存储16位RGB值 二进制:2^16=65536 (高彩色) (默认)
ARGB_4444:这个被废弃了建议使用ARGB_8888
注意:通过如上解释我们知道单个像素能存储的值越大,那么图片质量肯定越好,相印的图片的大小就越大。A-代表alpha透明,R-红色,G-绿色,B-蓝色。
一张800*480的ARGB_8888的图片他大小就是 800x480=384000像素,ARGB_8888 4个8位就是4字节
384000*4/1024=1.4MB
//如果format参数是Bitmap.CompressFormat.PNG,那么quality随便设置多少压缩是无效
public void setCompress(Bitmap bitmap){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
}
isMutable:true表示赋值出来的新位图的像素点是可以本修改的
Bitmap bitmap2=BitmapFactory.decodeResource(getResources(), R.raw.bit);
Bitmap newB1=bitmap2.copy(Bitmap.Config.RGB_565, false);
copyPixelsFromBuffer:从buffer缓存中获取数据
copyPixelsToBuffer:把数据赋值到buffer缓存中
Buffer是java.nio包下的一个缓存类
//获取一张位图
Bitmap bitmap2=BitmapFactory.decodeResource(getResources(), R.raw.bit);
//给buffer缓冲设置大小,这里就设置位图的大小
Buffer buffer= ByteBuffer.allocate(bitmap2.getByteCount());
//把位图bitmap2的数据复制到buffer中
bitmap2.copyPixelsToBuffer(buffer);
buffer.position(0);
//bitmap2再从buffer中获取数据
bitmap2.copyPixelsFromBuffer(buffer);
iv.setImageBitmap(bitmap2);
系统提供了不同方式来创建位图,但是常用的就几个
从源位图src中创建一个新位图,宽高密度都一样
创建一个空位图,就是说这个位图创建出来里面的像素点没有色彩
//获取一张已有的位图
Bitmap bitmap2=BitmapFactory.decodeResource(getResources(), R.raw.bit);
//创建一个空位图,没有色彩,宽高和bitmap2一样
Bitmap bitmap=Bitmap.createBitmap(bitmap2.getWidth(), bitmap2.getHeight(), Bitmap.Config.ARGB_8888);
//把bitmap2位图数据复制到buff缓冲中
Buffer buffer= ByteBuffer.allocate(bitmap2.getByteCount());
bitmap2.copyPixelsToBuffer(buffer);
buffer.position(0);
//然后我们创建的空bitmap再从buffer中获取bitmap2的位图数据
bitmap.copyPixelsFromBuffer(buffer);
iv.setImageBitmap(bitmap);//成功显示
(x,y)定义截取原点的坐标,就是从source位图的那个点开始截取默认是0,0 截取的宽width和高height
从目标bitmap中截取一段点集返回一个不可改变的bitmap,截取的范围由Matrix
m来 决定,返回 的bitmap和目标有相同的density,x,y,width,height分别为目标的起点 和宽高,filter表示目标 是否需要过滤,只有在Matrix包含更多信息的时候才会用到。
把src位图缩放到指定的dstWidth、dstHeight,缩放位图到指定宽高 可以看下源码就是计算缩放比然后用矩阵来缩放
图片宽高就是像素,像素包含色彩,这里就是自己定义若干colors来组成图
返回一个不可改变的bitmap,里边的点的值有colors数组一一对应的设定,offset表示colors数组中的颜色值是从哪个下标开始,stride表示colors数组中每一行有多少个颜色值,该值必须大于width。当width,height没有大于0,或者数组的长度小于bitmap的点的数量时就会抛出异常。
下面三个同上,display参数只是包含了当前显示其他信息如密度等……….
将指定颜色填满到bitmap中,当该bitmap不可改变时将会抛出异常
Bitmap mBitmap=BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(),Bitmap.Config.ARGB_8888);
Canvas mCanvas = new Canvas(mAlphaBitmap);
Paint mPaint = new Paint();
mPaint.setColor(Color.BLUE);
//从原位图中提取只包含alpha的位图
Bitmap alphaBitmap = mBitmap.extractAlpha();
//在画布上(mAlphaBitmap)绘制alpha位图
mCanvas.drawBitmap(alphaBitmap, 0, 0, mPaint);
iv.setImageBitmap(mAlphaBitmap);
这个demo的效果就是通过extractAlpha提取只带有alpha值的位图,然后画笔设置蓝色再绘制这个位图,结果就是位图只有alpha值,保留了图形的轮廓,但是里面填充的是蓝色
扩展:通常要给一张图片外面加一个轮廓阴影就用这个提取,然后和原图一起画
//区别demo说明:
//获取一张图片打印值82944、 82944
Bitmap mBitmap=BitmapFactory.decodeResource(getResources(), R.mipmap.ic_); Bitmap
//原图copy一张图片打印值82944 、82944 (说明另外一个问题图片默认是ARGB_8888,)
mBitmap2=mBitmap.copy(Bitmap.Config.ARGB_8888, true);
//reconfigure改变图片像素色彩存储参数,打印值//41472 、82944
mBitmap2.reconfigure(mBitmap2.getWidth(),mBitmap2.getHeight(), Bitmap.Config.RGB_565);
总结:上面的值第一个是getByteCount(),第二个是getAllocationByteCount ()的值
当我们使用reconfigure(..)方法把原图的像素色彩存储改为Bitmap.Config.RGB_565,这样图片的质量降低,大小就会变小,通过组后一组值发现getByteCount()的值变小了,但是另外一个没变。
故:getByteCount()返回的只是当前位图的像素字节数的大小值,这个值会随着图片质量改变而改变,而getAllocationByteCount()是返回图片在内存中分配的大小,无论图片在程序中如何改变他内存占有大小不变。当源位图没经过任何操作如reconfigure(int,
int, Config), setWidth(int), setHeight(int),等2个方法返回的大小始终相等
另1:图片在sdcard上大小可能是200KB,但是加载到程序中后会变成几MB?why?
在程序中位图表示了图像的全像素的数据,这样才可以在屏幕上完全显示。当您将文件保存在磁盘上的信息,这些信息可以通过像JPG或PNG压缩算法压缩,
另2:图片加入到程序时系统会根据当前手机分辨、密度等重新处理图片,这也会导致图片加入到程序变大。(OOM相关 1.3小节)
如果程序不支持不同屏幕密度那么这个值默认是density_default=160?
关于密度对图片的影响和不同的drawable文件夹中图片的自动缩放等在后面扩展说明!
设置、获取像素在某个坐标点的颜色值 pixels构建一个数组来装返回的颜色值,offset取值时从第几个下标开始取、stride:每行高
设置像素的颜色值,参数和上面的getXX方法一直
返回位图行像素值
获取缩放后的位图宽高,缩放是按照密度来计算缩放比
参数讲解: 上面三种类型参数其实只是使用了他里面封装的密度值 如DisplayMetrics metrics
他只是metrics.densityDpi获取封装的密度值 Canvas canvas参数
他只是canvas.mDensity获取里面封装的密度值
这几个方法在源码里面计算很简单,就是通过获取到的密度值,和位图默认密度值相除得到一个缩放比然后位图的宽高乘以这个缩放比就是得到的缩放后宽高
源码如下:(某一个方法的源码其他自己看)
public int getScaledHeight(DisplayMetrics metrics) { //mDensity是位图默认密度,可获取
return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi); //参数目标密度
}
static public int scaleFromDensity(int size, int sdensity, int tdensity) { //DENSITY_NONE=0
if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
return size; }
return ((size * tdensity) + (sdensity >> 1)) / sdensity;
}
这个算算法是 宽* tdensity/mDensity 另外如果获取到的位图密度等于传递进来的密度或者传递的密度为0那么高度还是返回源高度
Bitmap mBitmap=BitmapFactory.decodeResource(getResources(), R.raw.bit);
//获取位图默认密度mBitmap.getDensity()=480
int scaleHeight=mBitmap.getScaledHeight(160) //524 按160密度缩放后高度
int height=mBitmap.getHeight() //1572 源位图高度
对照上面的源码:160/480 *1527=524
某些方法操作位图时(如修改、复制位图)需要知道当前位图是否可变。
通过此方法给位图定义新的宽、高、conifg等参数,获得新的位图,这种方式优点是不会新生成一个位图
此为图的像素是否被预乘 意思就是alpha通道混合到r、g、b各个通道
比如一个颜色50%的半透明红色(128,255,0,0)所述预乘的形式是(128,128,0,0) 未被预乘的位图不能绘制到Canvas
否则会抛出运行时异常
mipmap这个设计到很多其他知识,比如纹理、贴图、渲染 这个大概意思就是减少内存使用,提高gpu渲染速度和我们android
mimap文件同理 总结:虽然bitmap提供了很多方法,但总结下来就几种
1:创建图片,2:修改图片,通过修改图片的像素值、像素色彩值,密度等 2:获取图片的相关参数、如宽、高、密度、像素颜色值相关