Bitmap的创建使用( 一)

bitmap位图类

bitmap位图是一种基于rgb颜色编码的点阵图形,由像素组成(一个一个小方块排列组成)**

  • Bitmap.CompressFormat 枚举类有三个值,指定位图可以被压缩成什么格式

JPEG:不能保存透明背景(缺少Alpha通道)?有损压缩故图片大小比较小
PNG:能保存透明背景,无损压缩,图片质量好,但是比较大
WEBP:好像是谷歌推出的一种图片格式,压缩率高
注意:WEBP支持不好(略),在android有时候我们做圆角头像如果用到了jpeg的图片你会发现图片后面有黑色背景,这就是因为jpeg不支持透明的原因。

  • Bitmap.Config 枚举类4个值,描述像素是如何存储的色彩,不同值会影响图片质量

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

  • compress(Bitmap.CompressFormat format, int quality, OutputStreamstream) 压 缩图片方法解决OOM的一大途径
//如果format参数是Bitmap.CompressFormat.PNG,那么quality随便设置多少压缩是无效
public void setCompress(Bitmap bitmap){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    }
  • copy(Bitmap.Config config, boolean isMutable) 从源位图赋值一个新的位图
  isMutable:true表示赋值出来的新位图的像素点是可以本修改的
  Bitmap bitmap2=BitmapFactory.decodeResource(getResources(), R.raw.bit);
  Bitmap newB1=bitmap2.copy(Bitmap.Config.RGB_565, false);
  • copyPixelsFromBuffer(Buffer src)、copyPixelsToBuffer(Buffer dst)
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);

创建位图的方法 9种

系统提供了不同方式来创建位图,但是常用的就几个

  • createBitmap(Bitmap src)

从源位图src中创建一个新位图,宽高密度都一样

  • createBitmap(int width, int height, Bitmap.Config config)
创建一个空位图,就是说这个位图创建出来里面的像素点没有色彩
  //获取一张已有的位图   
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);//成功显示
  • createBitmap(Bitmap source, int x, int y, int width, int height)

(x,y)定义截取原点的坐标,就是从source位图的那个点开始截取默认是0,0 截取的宽width和高height

  • createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

从目标bitmap中截取一段点集返回一个不可改变的bitmap,截取的范围由Matrix
m来 决定,返回 的bitmap和目标有相同的density,x,y,width,height分别为目标的起点 和宽高,filter表示目标 是否需要过滤,只有在Matrix包含更多信息的时候才会用到。

  • createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)

把src位图缩放到指定的dstWidth、dstHeight,缩放位图到指定宽高 可以看下源码就是计算缩放比然后用矩阵来缩放

  • createBitmap(int[] colors, int width, int height, Bitmap.Configconfig)

图片宽高就是像素,像素包含色彩,这里就是自己定义若干colors来组成图

  • createBitmap(int[] colors, int offset, int stride, int width, int height, Bitmap.Config config)

返回一个不可改变的bitmap,里边的点的值有colors数组一一对应的设定,offset表示colors数组中的颜色值是从哪个下标开始,stride表示colors数组中每一行有多少个颜色值,该值必须大于width。当width,height没有大于0,或者数组的长度小于bitmap的点的数量时就会抛出异常。

  • createBitmap(DisplayMetrics display, int width, int height,Bitmap.Config config)
  • createBitmap(DisplayMetrics display, int[] colors, int width, intheight, Bitmap.Config config)
  • createBitmap(DisplayMetrics display, int[] colors, int offset, intstride, int width, int height, Bitmap.Config config)

下面三个同上,display参数只是包含了当前显示其他信息如密度等……….

  • eraseColor (int c)

将指定颜色填满到bitmap中,当该bitmap不可改变时将会抛出异常

  • Bitmap extractAlpha () 提取指定位图的alpha值
  • Bitmap extractAlpha (Paint paint, int[] offsetXY)按照offsetXY偏移去绘制
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值,保留了图形的轮廓,但是里面填充的是蓝色
扩展:通常要给一张图片外面加一个轮廓阴影就用这个提取,然后和原图一起画

  • getAllocationByteCount ()、getByteCount () 返回bitmap大小
  • getAllocationByteCount :返回用于存储该位图的内存大小(byte)
  • getByteCount :返回存储该位图的像素字节数(getRowBytes() * getHeight())
 //区别demo说明:
//获取一张图片打印值8294482944
Bitmap mBitmap=BitmapFactory.decodeResource(getResources(), R.mipmap.ic_); Bitmap   
//原图copy一张图片打印值8294482944 (说明另外一个问题图片默认是ARGB_8888,)
mBitmap2=mBitmap.copy(Bitmap.Config.ARGB_8888, true); 
//reconfigure改变图片像素色彩存储参数,打印值//4147282944
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小节)

  • public int getDensity () 返回位图密度
  • setDensity(int density) 设置位图密度

如果程序不支持不同屏幕密度那么这个值默认是density_default=160?
关于密度对图片的影响和不同的drawable文件夹中图片的自动缩放等在后面扩展说明!

  • getGenerationId () 返回位图是否被更改(修改)的标志
  • int getHeight () 、getWidth()返回位图高\宽(位图的像素高\宽)
  • setHeight(int height)、setWidth(int width 设置位图宽高
  • byte[] getNinePatchChunk () 点9图片相关
  • getPixel (int x, int y) 获取图像在xy坐标的颜色值,可转成16进制即可使用该颜色
  • getPixels (int[] pixels, int offset, int stride, int x, int y, intwidth, int height)同上

设置、获取像素在某个坐标点的颜色值 pixels构建一个数组来装返回的颜色值,offset取值时从第几个下标开始取、stride:每行高

  • setPixel(int x, int y, int color)
  • setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)

设置像素的颜色值,参数和上面的getXX方法一直

  • getRowBytes()

返回位图行像素值

  • public int getScaledHeight (DisplayMetrics metrics)
  • public int getScaledHeight (int targetDensity)
  • public int getScaledHeight (Canvas canvas)
  • public int getScaledWidth (int targetDensity)
  • public int getScaledWidth (DisplayMetrics metrics)
  • public int getScaledWidth (Canvas canvas)

获取缩放后的位图宽高,缩放是按照密度来计算缩放比

参数讲解: 上面三种类型参数其实只是使用了他里面封装的密度值 如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)  //524160密度缩放后高度
int height=mBitmap.getHeight() //1572  源位图高度
对照上面的源码:160/480 *1527=524
  • boolean hasAlpha() 返回true表示当前位图是包含alpha通道的
  • setHasAlpha(boolean hasAlpha) 如果位图不包含alpha通道,此方法忽略
  • final boolean isMutable() 表示位图是否可变

某些方法操作位图时(如修改、复制位图)需要知道当前位图是否可变。

  • boolean isRecycled() 判断位图是否被回收了(true :回收了)
  • public void recycle() 回收一个位图
  • reconfigure(int width, int height, Bitmap.Config config)

通过此方法给位图定义新的宽、高、conifg等参数,获得新的位图,这种方式优点是不会新生成一个位图

  • boolean sameAs(Bitmap other) 比较2个位图是否一样
  • isPremultiplied()、setPremultiplied(boolean)

此为图的像素是否被预乘 意思就是alpha通道混合到r、g、b各个通道
比如一个颜色50%的半透明红色(128,255,0,0)所述预乘的形式是(128,128,0,0) 未被预乘的位图不能绘制到Canvas
否则会抛出运行时异常

  • prepareToDraw()
  • hasMipMap()、setHasMipMap(boolean)

mipmap这个设计到很多其他知识,比如纹理、贴图、渲染 这个大概意思就是减少内存使用,提高gpu渲染速度和我们android
mimap文件同理 总结:虽然bitmap提供了很多方法,但总结下来就几种
1:创建图片,2:修改图片,通过修改图片的像素值、像素色彩值,密度等 2:获取图片的相关参数、如宽、高、密度、像素颜色值相关

你可能感兴趣的:(Android)