我们先写一个小的图片选择程序
原理:利用内置的Gallery程序选择图像
下面我们就实现利用一个系统意图去调用系统的Gallery选着一张图片并显示,完整代码如下:
activity代码
<span style="font-size:14px;">package com.example.innergalleryselectphoto;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener{
private static final int REQUEST_CODE=0;
private Button selectBtn;
private ImageView showIv;
private ImageView drawShowIv;
private int screenWidth;//屏幕宽
private int screenHeight;//屏幕高
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
selectBtn=(Button) findViewById(R.id.select);
showIv=(ImageView) findViewById(R.id.show);
drawShowIv=(ImageView) findViewById(R.id.drawShow);
selectBtn.setOnClickListener(this);
//获取屏幕宽度,高度
screenWidth=getWindowManager().getDefaultDisplay().getWidth();
screenHeight=getWindowManager().getDefaultDisplay().getHeight();
}
@Override
public void onClick(View v) {
/*
* 通过Intent.ACTION_PICK动作,通知Android,我们想要选着一块数据
* 第二个参数是要从中获取数据的URI(这里从MediaStore中获取)
* 该意图会启动Gallery应用程序
*/
Intent intent=new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE);
}
/**
* 当在用户选择图片之后,activity将调用onActivityResult方法,并返回图片的URI
* 由于图片较大会消耗内存,我们这里将图片进行了压缩
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==REQUEST_CODE&&resultCode==RESULT_OK&&data!=null){
//获取返回的URI数据
Uri uri=data.getData();
//解析图片并实现压缩
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
try {
BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
//获取图片的宽高
int imgWidth=options.outWidth;
int imgHeight=options.outHeight;
//获取压缩比率
int radio=imgWidth/screenWidth>imgHeight/screenHeight?imgWidth/screenWidth:imgHeight/screenHeight;
options.inSampleSize=radio;
options.inJustDecodeBounds=false;
Bitmap bitmap=BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
//显示图片
showIv.setImageBitmap(bitmap);
//下面我们将得到的图片复制一份
//先创建一个空的bitmap对象,并将属性和原图片配置成一样
Bitmap copyBitmap=Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
//创建画布,包含空白bitmap对象
Canvas canvas=new Canvas(copyBitmap);
//创建画笔
Paint paint=new Paint();
//在空白位图上绘制选择的图片进行复制
canvas.drawBitmap(bitmap, 0, 0, paint);
//将绘制后的图片显示出来
drawShowIv.setImageBitmap(copyBitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
</span>
<span style="font-size:14px;">布局代码</span>
<span style="font-size:14px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选着图片" />
<ImageView
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
</LinearLayout></span>
有时候我们需要将一张图片变成两张一样的图片(复制),那我们该如何实现呢?
实现原理:先获得原图片参数信息,根据原图创建一个空白图片,将空白图片传入画布,创建画笔,在画布上面绘制一张原图
代码如下:
<span style="font-size:14px;"> //下面我们将得到的图片复制一份
//先创建一个空的bitmap对象,并将属性和原图片配置成一样
Bitmap copyBitmap=Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
//创建画布,包含空白bitmap对象
Canvas canvas=new Canvas(copyBitmap);
//创建画笔
Paint paint=new Paint();
//在空白位图上绘制选择的图片进行复制
canvas.drawBitmap(bitmap, 0, 0, paint);
//将绘制后的图片显示出来
drawShowIv.setImageBitmap(copyBitmap);</span>
下面我们来探讨基本的图像缩放和旋转
首先我们的了解一个类Matrix(矩阵)
当在现有位图对象上绘制或从别的位图上创建某个位图对象时使用该类。我们可以在空间上对图像进行旋转,剪切,缩放,移动
Matrix类中主要以9个数字的数组来对图像进行修改绘制,Matrix类中的每个数字都将应用于图像上每个点的3个坐标之一
例如:
1 0 0
0 1 0
0 0 1
第一行(1,0,0)指定源图像的x坐标根据以下公式进行转化:x=1*x+0*y+0*z,第一行总会影响到x坐标,但可以操作原图像的x,y,z坐标
第二行(0,1,0) 指定源图像的y坐标根据以下公式进行转化:y=0*x+1*y+0*z
第二行(0,0,1) 指定源图像的y坐标根据以下公式进行转化:z=0*x+0*y+1*z
以上矩阵不会对图像进行修改,所有内容都将按照原图显示
那么我们具体怎么使用Matrix类呢?
首先我们的创建Matrix对象,然后根据setValues方法设置矩阵值
<span style="font-size:14px;"> //创建矩阵
Matrix matrix=new Matrix();
//设置值
matrix.setValues(new float[]{
1,0,0,
0,1,0,
0,0,1
});
//创建一个空的位图对象
Bitmap kongBitmap=Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
Paint paint=new Paint();
Canvas canvas=new Canvas(kongBitmap);
//画图
canvas.drawBitmap(bitmap, matrix, paint);</span>
例如:
0.5 0 0
0 1 0
0 0 1
以上将在x轴上压缩50%
1 0.5 0
0 1 0
0 0 1
如果改变矩阵,使x坐标也受原图像的y坐标影响,则修改第一行的第二个数字,则从图片左上角开始延伸到右下角每个像素的x值随着y值增加而增加,如果为负值将随y值得增加而减小。这些矩阵通过修改这9个数字将图片千变万化,但手动处理是相当麻烦的,这里Matrix类给我们提供了,一些常用的方法Matrix类的方法
1.旋转
setRotate()方法中传入一个浮点数表示要旋转的角度,正数顺时针旋转,负数逆时针旋转,默认点为图片的左上角
matrix.setRotate(15);
更改旋转点
matrix.setRotate(15,width/2,height/2);
2.缩放
setScale()方法用于缩放
matrix.setScale(1.5f,1f);
第一个参数代表x轴上的缩放比例,第二个参数代表y轴上的缩放比例
3.平移
setTranslate(1.5f,-10)//在x轴和y轴上简单的移动图像
第一个参数:x轴上移动的数量;第二个参数:在y轴上移动的数量
x轴上正数表示右移,负数表示左移;y轴上正数表示下移,负数表示上移
4.上面的一些方法可以整合到一起,让他们按顺序对图片进行操作
例如:matrix.setScale(1.5f,2f);//先缩放
matrix.postRotate(1.5f,2f);//再旋转
//产生镜像
matrix.setScale(-1,1);//-1向左绘制图片
matrix.postTranslate(getWidth,0);//再向右平移
//翻转图片matrix.setScale(1,-1);//-1向上绘制图片
matrix.postTranslate(0,getWidth);//再向下平移
以上我们绘制的图像会出现被截断的现象,那我们怎样设计才能得到完整图片呢?
当我们上面都是先创建一个空白图像,再通过画布画笔在空白图像上绘制新图像,这样做不能更改位图对象,想改变位图,需重建
这里我们需要用到Bitmap类中的createBitmap方法绘制图片
Bitmap kongBitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
第一个参数:指的是原图片
第二、三、四、五参数:原图片的x、y、宽度和高度
第六个参数:Matrix对象
第七个参数:布尔值,表示是否在图像上应用过滤器
下面我们学习图像处理(处理像素自身颜色值的变化,改变对比度、亮度、色调等)
ColorMatrix类(和Matrix用法一样)
它是一个数字数组长度为20的浮点数组,可以对像素进行操作。它的操作颜色值-红(R)、绿(G)、蓝(B)、透明度(alpha)
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
第一行对红色像素进行操作,第二行对绿色像素进行操作,第三行对蓝色像素进行操作,第四行对透明度进行操作
在每一行中,第一个数字与红色像素相关,第二个数字与绿色像素相关,第三个数字与蓝色像素相关,第四个数字与透明度相关,最后一个数字不会和任何值相乘
例如:现在有一个颜色值,红色为128,蓝色为128,绿色为128,alpha为0(不透明)公式如下
新的红色值:1*128+0*128+0*128+0*0+0
新的蓝色值:0*128+1*128+0*128+0*0+0
新的绿色值:0*128+0*128+1*128+0*0+0
新的Alpha值:0*128+0*128+0*128+1*0+0
所有的值都保持不变
将原图像红色值增加2倍
2 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
增加原图片的颜色强度,将影响到图像的亮度和对比度
2,0,0,0,0
0,2,0,0,0
0,0,2,0,0
0,0,0,1,0
如果只想增加对比度而不增加亮度,那么必须降低亮度来补偿在颜色强度方面的增加
调整亮度时,只改变矩阵最后一列的值会更加简单
降低亮度
1,0,0,0,-25
0,1,0,0,-25
0,0,1,0,-25
0,0,0,1,0
每个颜色值强度加倍亮度减少,影响对比度为不影响亮度
2,0,0,0,-25,
0,2,0,0,-25,
0,0,2,0,-25,
0,0,0,2,0
改变饱和度
这里ColorMatrix类中提供了setSaturation方法来改变饱和度,方法中参数大于1则增加饱和度,范围为0-1之间的数字会减少饱和度,为0时将产生一幅灰度图像
ColorMatrix cm=new ColorMatrix();
cm.setSatutation(0.5f);
paint.setColorFilter(new ColorMatrixColorFilter(cm));
1.首先得创建一个颜色矩阵对象ColorMatrix
2.构建一个ColorMatrixColorFilter对象构造方法中传入ColorMatrix对象
3.给Paint对象设置过滤器,通过ColorMatrix对象改变绘制内容
代码如下:将原图的红色值增加到2倍
<span style="font-size:14px;"> Paint paint=new Paint();
ColorMatrix colorMatrix=new ColorMatrix();
colorMatrix.set(new float[]{
2,0,0,0,0,
0,1,0,0,0,
0,0,1,0,0,
0,0,0,1,0});
ColorMatrixColorFilter colorFilter=new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(colorFilter); </span>
图像的合成
合成是将两幅图片放在一起,我们会同时看到两幅图像的特征。在Android SDK中,可以通过首先在Canvas对象绘制一个位图对象,然后在相同的Canvas对象上绘制第二个位图对象来实现合成,在绘制第二幅图像时,需要在Paint对象上指定一个过渡模式(Xfermode)
过渡模式的基类为Xfermode,PorterDuffXfermode类详细介绍了一系列不同的规则,用于彼此重叠的绘制图像。这些规则定义了哪些图像的哪些部分将出现在结果输出中。
在Android的PorterDuff.Mode类中定义了以下规则
1.android.graphics.PorterDuff.Mode.SRC
只绘制原图片,在当前情况下它是正在应用此规则的Paint对象
2.android.graphics.PorterDuff.Mode.DST
只显示目标图像,即已在画布上的初始图像
3.android.graphics.PorterDuff.Mode.DST_OVER
在原图像的顶部绘制目标图像
4.android.graphics.PorterDuff.Mode.DST_IN
在原图像和目标图像相交的地方绘制目标图像
5.android.graphics.PorterDuff.Mode.DST_OUT
在原图像和目标图像不相交的地方绘制目标图像
6.android.graphics.PorterDuff.Mode.DST_ATOP
在目标图像与原图像相交的地方绘制目标图像,其他地方绘制原图像
7.android.graphics.PorterDuff.Mode.SRC_OVER
在目标图像的顶部绘制原图像
8.android.graphics.PorterDuff.Mode.SRC_IN
在目标图像和原图像相交的地方绘制原图像
9.android.graphics.PorterDuff.Mode.SRC_OUT
在目标图像和原图像不相交的地方绘制原图像
10.android.graphics.PorterDuff.Mode.SRC_ATOP
在原图像与目标图像相交的地方绘制原图像,在其他地方绘制目标图像
11.android.graphics.PorterDuff.Mode.XOR
在原图像和目标图像重叠之外的任何地方绘制它们。重叠的位置不进行内容绘制
12.android.graphics.PorterDuff.Mode.LIGHTEN
获得每个位置上两幅图像中最亮的像素并显示
13.android.graphics.PorterDuff.Mode.DARKEN
获得每个位置上两幅图像中最暗的像素并显示
14.android.graphics.PorterDuff.Mode.MULTIPLY
在每个位置的两个像素相乘,除以255,然后使用该值创建一个新的像素进行显示。颜色=顶部颜色*底部颜色/255
15.android.graphics.PorterDuff.Mode.SCREEN
反转每个颜色,执行相同的操作(将他们相乘并除以255),然后再次反转。颜色=255-(((255-顶部颜色)*(255-底部颜色))/255)
用法举例:
<span style="font-size:14px;"><span> </span>//创建一个空白图片
Bitmap kongBitmap=Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig());
Canvas canvas=new Canvas(kongBitmap);
Paint paint=new Paint();
canvas.drawBitmap(bmp1, 0,0,paint);</span>
<span style="font-size:14px;"><span> </span>//设置画笔的过度模式
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(bmp2, 0, 0, paint);
combineImageIv.setImageBitmap(kongBitmap);</span>