图片绘制原理:
1. 绘制背景图 绘制图层 被修改的
2. 修改绘制图层
3. 绘制修改图层
1. 案例1: 微信画板
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/iv"
android:orientation="horizontal" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickBrush"
android:text="刷子" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickRed"
android:text="红色" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickGreen"
android:text="绿色" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="save"
android:text="保存" />
</LinearLayout>
</RelativeLayout>
java 代码实现:
package mk.denganzhi.com.heimaimage;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
public class WeiXingPaintActivity extends AppCompatActivity {
private ImageView iv;
private Canvas canvas;
private Paint paint;
private Bitmap srcBitmap;
private Bitmap copyBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wei_xing_paint);
iv = (ImageView) findViewById(R.id.iv);
// 设置一个灰白色的背景 ,在这个背景资源上作画。
srcBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.background);
// 创建原图的拷贝
// Bitmap.createBitmap(iv.getWidth(),iv.height(),Bitmap.Config.ARG_8888)
// // 1. 绘制背景图(这里是背景图) 绘制图层(这里是图层) 被修改的
copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(),
srcBitmap.getHeight(), srcBitmap.getConfig());
canvas = new Canvas(copyBitmap);
paint = new Paint();
paint.setColor(Color.BLACK);
// 1. 绘制背景图(这里是背景图) 绘制图层 被修改的
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
// canvas.drawLine(10, 10, 80, 80, paint);
iv.setOnTouchListener(new View.OnTouchListener() {
int startX;
int startY;
@Override
public boolean onTouch(View v, MotionEvent event) {
// 获取到触摸事件的类型。
int action = event.getAction();
// 按下,移动,离开
switch (action) {
case MotionEvent.ACTION_DOWN:// 按下
// 记录下手指第一次按下的坐标
startX = (int) event.getX();
startY = (int) event.getY();
System.out.println("按下:" + startX + "," + startY);
break;
case MotionEvent.ACTION_MOVE:// 移动
// 得到移动后的新的坐标
// 2. 修改绘制图层 修copyBitmap 图层上 继续绘制
int newX = (int) event.getX();
int newY = (int) event.getY();
canvas.drawLine(startX, startY, newX, newY, paint);
System.out.println("移动画线:" + startX + "," + startY + "~"
+ newX + "," + newY);
// 获取新的起点坐标
startX = (int) event.getX();
startY = (int) event.getY();
// 3. 绘制修改图层
iv.setImageBitmap(copyBitmap);
// srcBitmap就是背景
// copyBitmap就是图层
break;
case MotionEvent.ACTION_UP:// 离开
break;
}
// True if the listener has consumed the event, false otherwise
// true 代表监听器把事件处理完毕了,false代表没处理完毕
return true;
}
});
// 设置拷贝后的图片
iv.setImageBitmap(copyBitmap);
}
public void clickBrush(View view) {
// 设置画笔的宽度
paint.setStrokeWidth(10);
}
public void clickRed(View view) {
paint.setColor(Color.RED);
}
public void clickGreen(View view) {
paint.setColor(Color.GREEN);
}
public void save(View view){
try {
File file = new File(Environment.getExternalStorageDirectory(),"haha.png");
FileOutputStream stream = new FileOutputStream(file);
copyBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
//欺骗图库应用。模拟一个sd卡挂载的广播消息。
// Intent intent = new Intent();
// intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
// intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
// sendBroadcast(intent);
// 必须要杀死图库,重新扫描爱可以读取sdcard
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "保存失败", 0).show();
}
}
}
上图看效果:
2. 去掉衣服 抽奖挂码原理
实现原理: 在修改的的图层,不断设置透明区域,覆盖图层
xml布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/iv_after"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
<ImageView
android:id="@+id/iv_pre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</FrameLayout>
Java代码实现:
package mk.denganzhi.com.heimaimage;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.PopupWindow;
public class RemoveGrilActivity extends AppCompatActivity {
private ImageView iv_after;
private ImageView iv_before;
private Bitmap aleterBitmap;
private Paint paint;
private Canvas canvas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_remove_gril);
// 这把是背景图
iv_after=(ImageView) findViewById(R.id.iv_after);
// 这个是被修改图
iv_before=(ImageView) findViewById(R.id.iv_pre);
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inSampleSize=1; //缩小一点
// 这里是只读图片
Bitmap after=BitmapFactory.decodeResource(getResources(), R.drawable.after19,opts);
Bitmap before=BitmapFactory.decodeResource(getResources(), R.drawable.background1,opts);
// 这里是可以写的图片,可以修改的,空白的Bitmap
aleterBitmap=Bitmap.createBitmap(before.getWidth(), before.getHeight(), before.getConfig());
canvas=new Canvas(aleterBitmap);
paint=new Paint();
paint.setStrokeWidth(5);
paint.setColor(Color.BLACK);
canvas.drawBitmap(before, new Matrix(), paint);
// 这把是背景图
iv_after.setImageBitmap(after);
// 被修改图
iv_before.setImageBitmap(aleterBitmap);
iv_before.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int newX=(int) event.getX();
int newY=(int) event.getY();
Log.e("denganzhi1","newX:"+newX +" newY:"+ newY);
Log.e("denganzhi1","weidth"+ aleterBitmap.getWidth()+ "height:"+aleterBitmap.getHeight());
for(int i=-20;i<20;i++){
for(int j=-20;j<20;j++){
// 这里 x、y的值不能小于0、大于图片的宽高
// 透明读取不断你覆盖被修改图片
// 实际上点一下是一个圆形实现
int newX1= (i+newX);
int newY1 =(j+newY);
Log.e("denganzhi","x:" +newX1 +" y: "+ newY1);
aleterBitmap.setPixel(newX1, newY1, Color.TRANSPARENT);
}
}
iv_before.setImageBitmap(aleterBitmap);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
});
}
}
图片效果图:
3. 图片合成 通过图层
图片合成模式:
demo 实现xml :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/iv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
Java 代码实现:
package mk.denganzhi.com.heimaimage;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
public class ImageComposeActivity extends AppCompatActivity {
private ImageView iv1;
private ImageView iv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_compose);
iv1=(ImageView) findViewById(R.id.iv1);
iv2=(ImageView) findViewById(R.id.iv2);
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inSampleSize=2;
Bitmap bitmap1=BitmapFactory.decodeResource(getResources(),R.drawable.background1,opts);
Bitmap alertBitmap = Bitmap.createBitmap(bitmap1.getWidth(), bitmap1.getHeight(), bitmap1.getConfig());
Canvas canvas=new Canvas(alertBitmap);
Paint paint=new Paint();
paint.setColor(Color.BLACK);
// 设置图片合成的样式
// api demos-graphics- xfermodes
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DARKEN));
//android.graphics.PorterDuff.Mode.DARKEN:重叠的地方图片颜色变暗了,就是一个水印效果
//android.graphics.PorterDuff.Mode.Lighten:重叠的地方图片颜色变亮了
// 比如大家来找茬外挂,把图片合成,然后显示出来
// 画了第一张图片
canvas.drawBitmap(bitmap1,new Matrix() , paint);
// 画第二张图片
Bitmap bitmap2=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap2, new Matrix(), paint);
iv2.setImageBitmap(alertBitmap);
}
}
效果图:
4 . 矩阵效果实现
布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/iv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Java代码实现:
package mk.denganzhi.com.heimaimage;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
public class MaxtidActivity extends AppCompatActivity {
private ImageView iv1;
private ImageView iv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maxtid);
iv1=(ImageView) findViewById(R.id.iv1);
iv2=(ImageView) findViewById(R.id.iv2);
Bitmap bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
iv1.setImageBitmap(bitmap);
Bitmap alertbitmap=Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
Canvas canvas=new Canvas(alertbitmap);
Paint paint=new Paint();
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
Matrix matrix=new Matrix();
// matrix.setValues(new float[]{
// 0.5f,0,0,
// 0,1,0,
// 0,0,1
// });
// 1.距阵就是一个3*3数组
// x= 0.5f*x + 0*y + 0*z : 缩小0.5f倍
// y= 0*x + 1*y + 0*z
// google 考虑到大多数人已经不认识矩阵了
// matrix.setTranslate(10, 10);// 2.实现平移
//3. 实现镜子效果
// matrix.setScale(-1, 1);
// matrix.postTranslate(bitmap.getWidth(),0);
// 4. 倒影效果
matrix.setScale(1, -1);
matrix.postTranslate(0, bitmap.getHeight()); // 在原来的基础上倒影,然后移动到下面来
// 把bitmap画上去,matir:对画上去的图片的操作 paint:画笔
canvas.drawBitmap(bitmap,matrix , paint);
iv2.setImageBitmap(alertbitmap);
}
}
效果图:
镜子效果 倒影效果
5 . ColorMatrixColorFilter 颜色矩阵 + 图层 实现 修改 色相
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="青---红" />
<SeekBar
android:id="@+id/sb_r"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="256"
android:progress="128" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="紫---绿" />
<SeekBar
android:id="@+id/sb_g"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="256"
android:progress="128" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="黄---蓝" />
<SeekBar
android:id="@+id/sb_b"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="256"
android:progress="128" />
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Java 代码实现:
package mk.denganzhi.com.heimaimage;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
/*
* 更改饱和度:同时更改 RGB的颜色,使用矩阵处理
* 还可以使用android 内置api:
* ColorMatrix cm=new ColorMatrix();
* cm.setSaturation(0.5f);
* paint.setColorFilter(new ColorMatrixColorFilter(cm));
*
*/
public class ColorActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {
private ImageView iv;
private SeekBar sb_r;
private SeekBar sb_g;
private SeekBar sb_b;
private Paint paint;
private Canvas canvas ;
private Bitmap srcBitmap ;
private Bitmap copyBitmap ;
private Button btn1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color);
sb_r = (SeekBar) findViewById(R.id.sb_r);
sb_g = (SeekBar) findViewById(R.id.sb_g);
sb_b = (SeekBar) findViewById(R.id.sb_b);
sb_b.setOnSeekBarChangeListener(this); //设置SeekBar监听器
sb_r.setOnSeekBarChangeListener(this);
sb_g.setOnSeekBarChangeListener(this);
iv = (ImageView) findViewById(R.id.iv);
// 解析文件得到的bitmap 只读的。
srcBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bb );
// srcBitmap.setPixel(5, 5, Color.RED);
// 在内存空间中 创建原图的副本(拷贝)
// 1.创建一张空白的纸 ,材料保证完全一致。
copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(),
srcBitmap.getHeight(), srcBitmap.getConfig());
// 2.临摹作画
// 创建画板 ,参考空白纸张的大小,把画板创建出来。
canvas = new Canvas(copyBitmap);
// 3.作画
// 创建一个画笔
paint = new Paint();
paint.setColor(Color.BLACK);// 设置默认的颜色。
// 作画
// srcBitmap 原图,要临摹的图
// matrix 变化矩阵
// paint 画笔
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
iv.setImageBitmap(copyBitmap);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int seebarid = seekBar.getId();
int value = seekBar.getProgress();
// 这里是一个颜色矩阵
ColorMatrix cm = new ColorMatrix();
float rf = 1.0f;
float gf = 1.0f;
float bf = 1.0f;
// android:max="256"
// New Red Value = 1*128 + 0*128 + 0*128 + 0*0 + 0
// New Blue Value = 0*128 + 1*128 + 0*128 + 0*0 + 0
// New Green Value = 0*128 + 0*128 + 1*128 + 0*0 + 0
// New Alpha Value = 0*128 + 0*128 + 0*128 + 1*0 + 0
paint.setColorFilter(new ColorMatrixColorFilter(cm));
switch (seebarid) {
case R.id.sb_r:
rf = value/128.0f;
break;
case R.id.sb_g:
gf = value/128.0f;
break;
case R.id.sb_b:
bf = value/128.0f;
break;
}
// 这里表示颜色矩阵
// rf=2 表示当前颜色的多少倍数
cm.set(new float[] {
rf, 0, 0, 0, 0,
0, gf, 0, 0, 0,
0, 0, bf, 0, 0,
0, 0, 0, 1, 0
});
paint.setColorFilter(new ColorMatrixColorFilter(cm));
// 重点*** 这个就是图层
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
// iv.setImageBitmap(copyBitmap);
}
}
效果图:
源码下载:https://download.csdn.net/download/dreams_deng/12295489