Bitmap像素是否可以更改
在前面一节中,我们详细介绍了两种创建Bitmap的方式,一种是使用BitmapFactory,一种是使用Bitmap静态方法,但这里我有一个需求,假如我有一张图片,绿色的颜色非常丰富,但绿色很暗,这个时候我想要修改该图片每个像素中的绿色值,用这两种方式创建的Bitmap都能直接修改吗?
答案是否定的,所有使用 BitmapFactory创建的Bitmap都是不可更改其像素值的,只有通过Bitmap以下几种函数创建的Bitmap才能完成如上需求,代码如下:
#只有这三个方法生成的Bitmap可以进行像素更改操作 copy(Bitmap.Config config,boolean isMutable) createBitmap(int width,int height,Bitmap.Config config) createScaledBitmap(Bitmap src,int dstWidth,int dstHeight,boolean filter)
不过我们这里需要注意的一点是,使用createScaledBitmap创建Bitmap时,如果源图像的宽高与生成图像的宽高一致,那么会直接返回源图像,不会生成新的图像,如果源图像不可更改,那么新图像也不可更改,如果源图像可以更改,那么新图像也可以更改。
Copy()函数
今天我们的实现主要用的就是Copy()函数,所以我们需要重点来讲解以下,这个函数,我们先来看看这个函数的定义:
copy(Bitmap.Config config,boolean isMutable)
Config config:像素在内存中的存储格式,取值有ARGB_8888等四个值,不知道的可以返回小编上一篇的博文。
boolean isMutable:新创建的Bitmap是否可以更改其中的像素。
该函数的意思时根据源图像创建一个副本,但可以指定副本的像素存储格式,同时可以自己定义是否可以更改其像素值。
setPixel(),getPixel()
因为要更改某图片的像素值,所以必须要用到这两个设置,和获取像素值的函数,他们的定义如下:
public void setPixel(int x,int y,int color) public void getPixel(int x,int y)
很明显,x,y是获取某图片像素点的坐标值,color是需要设置该像素值为哪个颜色,下面我们来看一张图片,如下图所示:
我们可以看到这张图片的绿色草坪,颜色有点偏暗,所以我们接下来需要通过上面讲解的所有函数,把图片的绿色变得更亮。
让图片变得更鲜艳
首先我们需要定义两个ImageView,方便后续进行对比,一个直接显示源图像,一个后续进行设置,XML代码如下:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/dog"/> <ImageView android:id="@+id/imageview" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
定义好之后,我们直接在主Activity中获取到id为imageview的控件,然后首先使用copy()函数进行复制一张可以编辑像素的Bitmap,代码如下:
this.imageView=(ImageView) findViewById(R.id.imageview);//获取控件 Bitmap srcBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.dog);//获取源图片,srcBitmap不可编辑像素 Bitmap dstBitmap=srcBitmap.copy(Bitmap.Config.ARGB_8888,true);copy后设置true,dstBitmap就是可以设置像素的Bitmap
这里我们获取到了可编辑Bitmap后,下面直接遍历该bitmap每个像素值,然后获取到颜色值,进行对比,在调升我们每个像素的绿色比重,代码如下:
for(int h=0;h<srcBitmap.getHeight();h++){// 行 for(int w=0;w<srcBitmap.getWidth();w++){//列 int pixel=srcBitmap.getPixel(w,h);//获取该点像素值 int red= Color.red(pixel);//获取该点像素值的红色值 int alpha= Color.alpha(pixel);//获取该点像素值的透明值 int green= Color.green(pixel);//获取该点像素值的蓝色值 int blue= Color.blue(pixel);//获取该点像素值的绿色值 if(green<200){//当绿色小于200,最高255 green+=50;//加50 } dstBitmap.setPixel(w,h,Color.argb(alpha,red,green,blue));//然后修改该dstBitmap该点像素值 } } this.imageView.setImageBitmap(dstBitmap);//设置到iamgeview控件中
这里的代码很好理解,就是遍历获取每个像素值,然后获取该像素值的红,蓝,绿以及透明度的值,当绿色值小于200的时候,更改绿色值,然后设置到可以更改颜色的dstBitmap中。
备注:这里有一点需要主要,为什么需要判断小于200才能加50呢?我们都知道ARGB_8888颜色值的最大值是255,假如现在有个颜色值是250,你不小心也加了50,那么就是300,那么程序会设置300吗?不会,那么程序会自动向下取整吗?也不会,颜色值计算是取余的,也就是说,假如你更改了某个颜色值为300,那么它只会设置成45,并不会设置成你希望的255。
这里你也可以通过遍历判断所有像素点哪个颜色值更高,然后统计分别自加计算红绿蓝最高的数值各有多少,然后再遍历一次单独给最高最多的颜色设置值,以达到让某图片最多的颜色更鲜艳的目的。
给图片添加水印
下面我们来实现大多数APP经常使用到的功能给图片添加水印,其实代码很简单,我们来看看这段代码:
/*** * 添加水印 * @param srcBitmap源图像 * @param watermark水印图像 * @return */ private Bitmap createWaterMarkBitmap(Bitmap srcBitmap, Bitmap watermark){ if(srcBitmap==null){ return null; } int srcWidth=srcBitmap.getWidth();//获取源图像的宽 int srcHeight=srcBitmap.getHeight();//获取源图像的高 int waterWidth=watermark.getWidth();//获取水印图像的宽 int waterHeight=watermark.getHeight();//获取水印图像的高 Bitmap bitmap=Bitmap.createBitmap(srcWidth,srcHeight,Bitmap.Config.ARGB_8888);//创建一个空白位图 Canvas canvas=new Canvas(bitmap);//根据位图创建画布 canvas.drawBitmap(srcBitmap,0,0,null);//先画出源图像 canvas.drawBitmap(watermark,srcWidth-waterWidth+5,srcHeight-waterHeight+5,null);//然后在画水印图像 return bitmap;//返回水印图片 }
代码注释已经非常详细了,这里就是简单的叠加绘制流程,创建一个空白位图,先画源图像,再在右下角画水印图像即可,详细的计算看下图就明白了:
接着我们还需要创建一个ImageView放置水印图像,这里的XML代码就不写了,和上面差不多,除了Id不同之外,其他的设置调用代码如下:
this.imageView2=(ImageView)findViewById(R.id.imageview2); this.imageView2.setImageBitmap(createWaterMarkBitmap(dstBitmap,BitmapFactory.decodeResource(getResources(),R.drawable.water)));
这样我们就实现了给图片添加水印的效果,实现的效果如下图所示:
本文的实现代码以及上篇文章的实现代码Github下载地址:点击下载