Bitmap类getPixels和createBitmap方法详解

主要2个方法:

getPixels(int[] pixels , int offset , int stride , int x , int y ,int width , int height)
createBitmap(int[] colors , int offset , int stride , int width , int height , Config config)

加粗了2个方法中比较关键的参数
新建一个bitmap,长宽均为400:

Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
int width = bitmap.getWidth();
int height = bitmap.getHeight();

其中createBitmap()最后一个参数Config.ARGB_8888,表示色彩的存储方式,还有4444,565等,
8888效果最好,但相比其他更占空间。

接下来往bitmap中添加红黄蓝绿4种颜色,看效果:

图1(400*400).png

上面的图片就是由400乘以400个像素点组成,像素点的排列方式,就跟小学作文本一样,可以看做一个二维的坐标系,每个像素点相当于作文本的一个小格子,当颜色去填充像素点,如同写作文,从第一行开始,从左往右,第一行到头了,换第二行,再从左往右...
上面的图怎么画的:
需要用到bitmap.setPixel()方法,上代码,一看就明白。

for (int i = 0; i < width / 2; i++) {
    for (int j = 0; j < height / 2; j++) {//左上块
        bitmap.setPixel(i, j, Color.RED);//红色
    }
    for (int j = height / 2; j < height; j++) {//左下块
         bitmap.setPixel(i, j, Color.BLUE);//蓝色
    }
}

for (int i = width / 2; i < width; i++) {
    for (int j = 0; j < height / 2; j++) {//右上块
        bitmap.setPixel(i, j, Color.YELLOW);//黄色
    }
    for (int j = height / 2; j < height; j++) { //右下块
        bitmap.setPixel(i, j, Color.GREEN);//绿色
     }
}

比如上图右下的绿色块,开始填充的第一个坐标点在二维坐标系中就是(200,200),最后一个坐标点在右下点(400,400),所以宽高的for循环都从200开始,400结束。

直接把bitmap放入imageview,就会显示图1

imageView.setImageBitmap(bitmap);

到此已经可以用setPixel方法往bitmap中添加颜色

接下来用bitmap的width*height,从而得到一个int[]数组,这个数组就是用来装整个bitmap的像素点。

int[] pixels = new int[width * height];
//pixels.length = 160000

现在pixels[]数组有长度,但是并没有给数组赋值,所以数组中每个单位值都为0,可以AS打断点看到,按住alt,单击pixels:

pixels[] 为0的情况.png

这时候就要用到getPixels方法

bitmap.getPixels(pixels,0,width,0,0,width,height);

当代码走过getPixels方法后再断点:

pixels[] 有值.png

已经有值了,在上面说过,像素点的排列方式如同写作文,一行一行,从左往右,可以想象到图一中第一行的前200个像素点为红色,后200个为黄色,那么在pixels[]数组中 0~ 199为红色,200~399 为黄色?查阅数组:

pixels[] 有值200变色.png

确实如此。颜色解释:
red.png

yellow.png

这个时候应该能理解到getPixels的作用:

将一个bitmap所有像素点组成的二维图形(作文本),通过一定的约束条件,转化为int[] 类型的一维数组

通过一定的约束条件,条件就是getPixels的参数,getPixels方法中前3个参数相比后4个参数更难理解,所以先把getPixels方法中后4个参数搞明白

getPixels(int[] pixels , int offset , int stride , int x , int y ,int width , int height)

先遍历数组,把每一个数全部赋值,相当于给了bitmap给了默认的颜色!

for (int i = 0; i < pixels.length; i++) {
    //设置默认值
    pixels[i] = Color.BLACK;
}

若现在截取图1中左上的红色块区域,代码:

bitmap.getPixels(pixels,0,width,    0, 0, width/2, height/2)

红色.jpg

若现在截取图1中右上的黄色块区域,代码:

bitmap.getPixels(pixels,0,width,      width/2, 0, width/2, height/2)
黄色.jpg

若现在截取图1中左下的蓝色块区域,代码:

bitmap.getPixels(pixels,0,width,     0, height/2, width/2, height/2)
蓝色.jpg

若现在截取图1中右下的绿色块区域,代码:

bitmap.getPixels(pixels,0,width,     width/2, height/2, width/2, height/2)
绿色.jpg

从上面四个操作应该能理解getPixels方法后4个参数:x和y表示需要截取图像左上角的点坐标,width和height分别表示需要截取的宽高

接下来说明 offset ,它可以决定截取图的摆放位置,offset = 像素点以上的矩形区域加上像素点所在行的下标。

  • getPixels方法后4个参数在原图上的操作,而offset和stride都表示截取图(新图)的操作.

举个例子:现在要把上图截取的绿色块居中

 bitmap.getPixels(pixels,      width*100+100,      width,  200,  200,  width/2,  height/2);
绿色块居中.jpg
  • offset这里我设置的为 :width * 100+100 ,width * 100(宽*高)等于上图红色块的像素总数,+100就为白色所在行的像素数,如同最开始所说bitmap的排列如同小学作文本,offset就是要算出你前面已经用过的所有格子。

如果不+100的样子:

bitmap.getPixels(pixels,      width*100,  width,  200,  200,  width/2,  height/2);
width*100.jpg

相信这2个例子也能帮你理解offset了。

接下来就轮到stride参数了:读取多少个像素才能换行

场景:现在有一图片(w:400,h:2),需要把这800个像素全部放入一维数组pixels中让新图(w:800,h:1)使用。

//我们先把其他参数固定:
 bitmap.getPixels(pixels, 0, stride, 0, 0,400, 2);

getPixels方法后四个参数固定为x:0,y:0,width:400,height:2 就相当于截取整个原图,offset也等于0,表示新bitmap从(0,0)开始填充

当stride=800时:规定了在原图上读取800个像素才能换行,而原图一行只有400,剩下400没有,又不能换行,只能用0填充(android规定的), 加入到一维数组中:
一维数组:0~800前400为有色,后400值为0,新图用来画第一行的时候,一半有色,一半无色

当stride=400时:规定了在原图上读取400个像素才能换行,原图一行就为400,读取完400换行,不会出现为空的情况,加入到一维数组中:
一维数组组:0~800都为有色的像素点,新图用来画第一行时都为有色。

还是拿绿色块,举2个例子:

  • 第一种当stride=800
bitmap.getPixels(pixels, 0,   800,   200, 200, width / 2, height / 2);
stride=800.jpg

因为绿色块长宽为200,所以当stride=800时,数组中0 ~ 800就出现 0 ~ 199为绿色,200~799为黑色(设置过默认为黑色),把这个数组用到上图400*400的bitmap中时,就会出现第一行取数组 0~399 ,其中 0~199 为绿色, 200~399 为黑色,第二行取数组400~799,全部为黑色。

  • 同理第二种当stride=400
bitmap.getPixels(pixels, 0,   400,   200, 200, width / 2, height / 2);
stride=400.jpg

看完上述解释,理解stride也不难。


现在把createBitmap(int[] colors , int offset , int stride , int width , int height , Config config)方法拉出来,这个方法里面的参数理解就简单了,前3个参数和getPixels方法一样,后3个就没啥说的。

建议如果有截取,拼接图片这种需求,先想好createBitmap方法的参数,也就是新图的设置,比如现在要得到一个长宽都为400的图,那么createBitmap参数中offset 就为0,stride 为宽度400,width 和 height 都为400;再返回去看getPixels方法的参数设置,这样思路更加清晰。

举个例子:取图一这个四色图4份,拼成一个大图

//数组放大4倍
 int[] pixels = new int[width * height * 4];

//只改变了offset参数
 bitmap.getPixels(pixels,  0,                          width * 2, 0, 0, width, height);
 bitmap.getPixels(pixels,  width,                      width * 2, 0, 0, width, height);
 bitmap.getPixels(pixels,  width*2*height,             width * 2, 0, 0, width, height);
 bitmap.getPixels(pixels,  width*2*height+width,       width * 2, 0, 0, width, height);

//新bitmap长宽都是2倍,offset表示从头开始填入像素,stride表示在数组中读取了width*2个像素 才能换一行
 Bitmap bitmap2 = Bitmap.createBitmap(pixels, 0, width*2,  width*2, height * 2, Bitmap.Config.ARGB_8888);
拼接4倍图.jpg

代码中的参数罗列的很清晰了。除此之外一些限制:

getPixels(int[] pixels , int offset , int stride , int x , int y ,int width , int height)

abs(stride) must be >= width,
x + width must be <= bitmap.width()

只要你思路是对的,符合正常人操作,就不会报错。



对于生活理想,应该像宗教徒对待宗教一样充满虔诚与热情!

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

推荐阅读更多精彩内容