服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - android实现图片橡皮擦和快速染色功能

android实现图片橡皮擦和快速染色功能

2022-09-03 15:03爱折腾的猫 Android

这篇文章主要为大家详细介绍了android实现图片橡皮擦和快速染色功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文为大家分享了android实现图片橡皮擦和快速染色的具体代码,供大家参考,具体内容如下

源码地址:eraselmg

1.染色

     关于染色部分,可以分别设置调整画笔的大小和画笔的透明度,画笔已经设置了模糊效果。画笔的特效可以调整下面一行代码:

android实现图片橡皮擦和快速染色功能

2.橡皮擦

  橡皮擦的实现用了两个canvas,一个临时的,一个是作用在imagetouchview上显示的,代码里面有注释,这里不再详细介绍。

3.功能展示:

原图:

android实现图片橡皮擦和快速染色功能

画笔设置界面:

android实现图片橡皮擦和快速染色功能

(1)画笔大小为32,透明度为255(不透明)。如下图:

android实现图片橡皮擦和快速染色功能

(2)画笔大小为32,透明度为10,如下图:

android实现图片橡皮擦和快速染色功能

融合的效果跟画笔的透明度有关系,也跟背景图片的相应区域颜色有关,所以透明度的值自行调整得出满意效果。

(3)擦除

擦除前图像:

android实现图片橡皮擦和快速染色功能

部分擦除后:

android实现图片橡皮擦和快速染色功能

4.bitmap处理相关的类bitmaputils:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package com.jiangjie.utils;
 
import java.io.bytearrayoutputstream;
import java.io.file;
import java.io.filenotfoundexception;
import java.io.fileoutputstream;
import java.io.ioexception;
import android.content.context;
import android.content.res.resources;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.rect;
import android.graphics.bitmap.config;
public class bitmaputils {
 
 
 /**
  * 缩放图片
  */
 public static void bitmapscale(bitmap basebitmap, paint paint, float x, float y) {
  // 因为要将图片放大,所以要根据放大的尺寸重新创建bitmap
  bitmap scalebitmap = bitmap.createbitmap(
    (int) (basebitmap.getwidth() * x),
    (int) (basebitmap.getheight() * y), basebitmap.getconfig());
  canvas canvas = new canvas(scalebitmap);
  // 初始化matrix对象
  matrix matrix = new matrix();
  // 根据传入的参数设置缩放比例
  matrix.setscale(x, y);
  // 根据缩放比例,把图片draw到canvas上
  canvas.drawbitmap(basebitmap, matrix,paint);
 }
 
 /**
  * 图片旋转
  */
 public static void bitmaprotate(bitmap basebitmap, paint paint,float degrees) {
  // 创建一个和原图一样大小的图片
  bitmap afterbitmap = bitmap.createbitmap(basebitmap.getwidth(),
    basebitmap.getheight(), basebitmap.getconfig());
  canvas canvas = new canvas(afterbitmap);
  matrix matrix = new matrix();
  // 根据原图的中心位置旋转
  matrix.setrotate(degrees, basebitmap.getwidth() / 2,
    basebitmap.getheight() / 2);
  canvas.drawbitmap(basebitmap, matrix, paint);
 }
 
 /**
  * 图片移动
  */
 public static void bitmaptranslate(bitmap basebitmap, paint paint, float dx, float dy) {
  // 需要根据移动的距离来创建图片的拷贝图大小
  bitmap afterbitmap = bitmap.createbitmap(
    (int) (basebitmap.getwidth() + dx),
    (int) (basebitmap.getheight() + dy), basebitmap.getconfig());
  canvas canvas = new canvas(afterbitmap);
  matrix matrix = new matrix();
  // 设置移动的距离
  matrix.settranslate(dx, dy);
  canvas.drawbitmap(basebitmap, matrix, paint);
 }
 
 /**
  * 倾斜图片
  */
 public static void bitmapskew(bitmap basebitmap, paint paint, float dx, float dy) {
  // 根据图片的倾斜比例,计算变换后图片的大小,
  bitmap afterbitmap = bitmap.createbitmap(basebitmap.getwidth()
    + (int) (basebitmap.getwidth() * dx), basebitmap.getheight()
    + (int) (basebitmap.getheight() * dy), basebitmap.getconfig());
  canvas canvas = new canvas(afterbitmap);
  matrix matrix = new matrix();
  // 设置图片倾斜的比例
  matrix.setskew(dx, dy);
  canvas.drawbitmap(basebitmap, matrix, paint);
 }
 
 public static bitmap decodefromresource(context context, int id) {
  resources res = context.getresources();
  bitmap bitmap = bitmapfactory.decoderesource(res,id).copy(bitmap.config.argb_8888, true);
  return bitmap;
 }
 
 /**
  * 保存图片到sd卡
  */
 public static void savetosdcard(string path, bitmap bitmap) {
 if (null != bitmap && null != path && !path.equalsignorecase("")) {
 try {
 file file = new file(path);
 fileoutputstream outputstream = null;
 //创建文件,并写入内容
 outputstream = new fileoutputstream(new file(path), true);
 bitmap.compress(bitmap.compressformat.png, 30, outputstream);
 outputstream.flush();
 outputstream.close();
 } catch (filenotfoundexception e) {
 e.printstacktrace();
 } catch (ioexception e) {
 e.printstacktrace();
 }
 
 }
 }
 
 /**
  * 复制bitmap
  */
 public static bitmap duplicatebitmap(bitmap bmpsrc, int width, int height) {
 if (null == bmpsrc) {
 return null;
 }
 
 int bmpsrcwidth = bmpsrc.getwidth();
 int bmpsrcheight = bmpsrc.getheight();
 
 bitmap bmpdest = bitmap.createbitmap(width, height, config.argb_8888);
 if (null != bmpdest) {
 canvas canvas = new canvas(bmpdest);
 rect viewrect = new rect();
 final rect rect = new rect(0, 0, bmpsrcwidth, bmpsrcheight);
 if (bmpsrcwidth <= width && bmpsrcheight <= height) {
 viewrect.set(rect);
 } else if (bmpsrcheight > height && bmpsrcwidth <= width) {
 viewrect.set(0, 0, bmpsrcwidth, height);
 } else if (bmpsrcheight <= height && bmpsrcwidth > width) {
 viewrect.set(0, 0, width, bmpsrcwidth);
 } else if (bmpsrcheight > height && bmpsrcwidth > width) {
 viewrect.set(0, 0, width, height);
 }
 canvas.drawbitmap(bmpsrc, rect, viewrect, null);
 }
 
 return bmpdest;
 }
 
 /**
  * 复制bitmap
  */
 public static bitmap duplicatebitmap(bitmap bmpsrc) {
 if (null == bmpsrc) {
 return null;
 }
 
 int bmpsrcwidth = bmpsrc.getwidth();
 int bmpsrcheight = bmpsrc.getheight();
 
 bitmap bmpdest = bitmap.createbitmap(bmpsrcwidth, bmpsrcheight,
 config.argb_8888);
 if (null != bmpdest) {
 canvas canvas = new canvas(bmpdest);
 final rect rect = new rect(0, 0, bmpsrcwidth, bmpsrcheight);
 
 canvas.drawbitmap(bmpsrc, rect, rect, null);
 }
 
 return bmpdest;
 }
 
 /**
  * bitmap转字节码
  */
 public static byte[] bitamptobytearray(bitmap bitmap) {
 byte[] array = null;
 try {
 if (null != bitmap) {
 bytearrayoutputstream os = new bytearrayoutputstream();
 bitmap.compress(bitmap.compressformat.png, 100, os);
 array = os.tobytearray();
 os.close();
 }
 } catch (ioexception e) {
 e.printstacktrace();
 }
 
 return array;
 }
 
 /**
  * 字节码转bitmap
  */
 public static bitmap bytearraytobitmap(byte[] array) {
 if (null == array) {
 return null;
 }
 
 return bitmapfactory.decodebytearray(array, 0, array.length);
 }
 
}

5.图像旋转,缩放,橡皮擦和染色功能如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
package com.jiangjie.ps;
 
import com.jiangjie.utils.paintconstants;
 
import android.content.context;
import android.graphics.bitmap;
import android.graphics.bitmap.config;
import android.graphics.blurmaskfilter;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.path;
import android.graphics.pointf;
import android.graphics.porterduff.mode;
import android.graphics.porterduffxfermode;
import android.graphics.rectf;
import android.graphics.drawable.bitmapdrawable;
import android.util.attributeset;
import android.util.displaymetrics;
import android.util.floatmath;
import android.util.log;
import android.view.motionevent;
import android.view.view;
import android.widget.imageview;
 
public class imagetouchview extends imageview{
 public matrix matrix = new matrix();
 
 matrix savedmatrix = new matrix();
 /** 屏幕的分辨率*/
 private displaymetrics dm;
 /** 当前模式*/
 int mode = paintconstants.mode.none;
 
 /** 存储float类型的x,y值,就是你点下的坐标的x和y*/
 pointf prev = new pointf();
 pointf curposition = new pointf();
 pointf mid = new pointf();
 float dist = 1f;
 
 float oldrotation = 0;
 float olddistx = 1f;
 float olddisty = 1f;
 
 /**位图对象*/
 private bitmap bitmap = null;
 private paint paint;
 private context context;
 
 private path path;
 private path temppath;
 //定义一个内存中的图片,该图片将作为缓冲区
 bitmap cachebitmap = null;
 
 //定义cachebitmap上的canvas对象
 canvas cachecanvas = null;
 private paint cachepaint = null;
 
 private string tag = "app";
 
 int x = 0;
 int y = 0;
 
 
 public imagetouchview(context context) {
 super(context);
 }
 
 public imagetouchview(context context, attributeset attrs) {
 super(context, attrs);
 this.context = context;
 log.i(tag, "imagetouchview(context context, attributeset attrs)=>");
 
 setupview();
 }
 
 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);
 
 if(mode == paintconstants.mode.coloring){
 canvas.drawpath(temppath, paint);
 }
 
 }
 
 public void setupview(){
 
 //获取屏幕分辨率,需要根据分辨率来使用图片居中
 dm = getcontext().getresources().getdisplaymetrics();
 //根据myimageview来获取bitmap对象
 bitmapdrawable bd = (bitmapdrawable)this.getdrawable();
 if(bd != null){
 bitmap = bd.getbitmap();
 // bitmap = setbitmapalpha(bitmap, 100);
 center(true, true);
 }
 setcoverbitmap(bitmap);
 this.setimagematrix(matrix);
 
 this.setontouchlistener(new ontouchlistener() {
 @override
 public boolean ontouch(view v, motionevent event) {
 matrix matrixtemp = new matrix();
 matrixtemp.set(matrix);
 //view的触摸坐标的转换
 matrixtemp.invert(matrixtemp);
 log.i(tag, "touch screen.");
 
 switch (event.getaction() & motionevent.action_mask) {
 // 主点按下
 case motionevent.action_down:
  savedmatrix.set(matrix);
  prev.set(event.getx(), event.gety());
 
  float[] pointprevinit = new float[]{prev.x, prev.y};
  matrixtemp.mappoints(pointprevinit);
  path.moveto(pointprevinit[0], pointprevinit[1]);
  temppath.moveto(event.getx(), event.gety());
 
  mode = paintconstants.mode.drag;
  log.i(tag, "action_down=>.");
  break;
  // 副点按下
 case motionevent.action_pointer_down:
  dist = spacing(event);
  oldrotation = rotation(event);
  olddistx = spacingx(event);
  olddisty = spacingy(event);
  // 如果连续两点距离大于10,则判定为多点模式
  if (spacing(event) > 10f) {
  savedmatrix.set(matrix);
  midpoint(mid, event);
  mode = paintconstants.mode.zoom;
  }
  break;
 case motionevent.action_up:
  log.i(tag, "action_up=>.");
  if(mode == paintconstants.mode.coloring){
  cachepaint.setcolor(paintconstants.pen_color);
  cachepaint.setstrokewidth(paintconstants.pen_size);
  cachepaint.setalpha(paintconstants.transparent);
  cachepaint.setmaskfilter(new blurmaskfilter(5, paintconstants.blur_type));
  
  cachecanvas.drawpath(path, cachepaint);
  path.reset();
  temppath.reset();
  }
  break;
 
 case motionevent.action_pointer_up:
  mode = paintconstants.mode.none;
  break;
 
 case motionevent.action_move:
  if(!paintconstants.selector.keep_image){
  if (mode == paintconstants.mode.drag) {
  matrix.set(savedmatrix);
  matrix.posttranslate(event.getx() - prev.x, event.gety() - prev.y);
  } else if (mode == paintconstants.mode.zoom) {
  float rotation = (rotation(event) - oldrotation)/2;
  float newdistx = spacingx(event);
  float newdisty = spacingy(event);
  float scalex = newdistx-olddistx;
  float scaley = newdisty-olddisty;
 
  float newdist = spacing(event);
  if (newdist > 10f) {
  matrix.set(savedmatrix);
  float tscale = newdist / dist;
  tscale = tscale>1?1+((tscale-1)/2):1-(1-tscale)/2;
  if(paintconstants.selector.keep_scale){
   matrix.postscale(tscale, tscale, mid.x, mid.y);// 縮放
  }else{
   if(math.abs(scalex)>=math.abs(scaley)){
   matrix.postscale(tscale, 1, mid.x, mid.y);// 縮放
   }else{
   matrix.postscale(1, tscale, mid.x, mid.y);// 縮放
   }
  }
  if(paintconstants.selector.hair_rurn)
   matrix.postrotate(rotation, mid.x, mid.y);// 旋轉
  }
  }
  }else{
  float[] pointprev = new float[]{prev.x, prev.y};
  float[] pointstop= new float[]{event.getx(), event.gety()};
 
 
  //view的触摸坐标的转换
  matrixtemp.mappoints(pointprev);
  matrixtemp.mappoints(pointstop);
 
  if(paintconstants.selector.coloring){
  //染色功能
  mode = paintconstants.mode.coloring;
  paint.reset();
  paint = new paint(paint.dither_flag);
  paint.setcolor(color.red);
  //设置画笔风格
  paint.setstyle(paint.style.stroke);
  paint.setstrokewidth(1);
  //反锯齿
  paint.setantialias(true);
  paint.setdither(true);
  paint.setcolor(paintconstants.pen_color);
  paint.setstrokewidth(paintconstants.pen_size);
 
  path.quadto(pointprev[0],pointprev[1],pointstop[0],pointstop[1]);
  temppath.quadto(prev.x, prev.y,event.getx(), event.gety());
  
  // 更新开始点的位置
  prev.set(event.getx(), event.gety());
 
  imagetouchview.this.setimagebitmap(cachebitmap);
 
  }else if(paintconstants.selector.erase){
  //橡皮擦功能
 
  mode = paintconstants.mode.erase;
 
  paint.reset();
  paint.setcolor(color.transparent);
  paint.setantialias(false);
  paint.setstyle(paint.style.stroke);
  paint.setstrokewidth(16);
  paint.setstrokejoin(paint.join.round);
  paint.setstrokecap(paint.cap.round);
  paint.setalpha(0);
  paint.setxfermode(new porterduffxfermode(mode.dst_in));
  paint.setstrokewidth(paintconstants.erase_size);
 
  prev.set(event.getx(), event.gety());
  
  cachecanvas.drawline(pointprev[0],pointprev[1],pointstop[0],pointstop[1], paint);
  imagetouchview.this.setimagebitmap(cachebitmap);
  }
  }
 }
 imagetouchview.this.setimagematrix(matrix);
 invalidate();
 
 return true;
 }
 });
 }
 
 /**
 * 横向、纵向居中
 */
 protected void center(boolean horizontal, boolean vertical) {
 rectf rect = new rectf(0, 0, bitmap.getwidth(), bitmap.getheight());
 
 float height = rect.height();
 float width = rect.width();
 
 float deltax = 0, deltay = 0;
 
 if (vertical) {
 // 图片小于屏幕大小,则居中显示。大于屏幕,上方留空则往上移,下方留空则往下移
 int screenheight = dm.heightpixels;
 if (height < screenheight) {
 deltay = (screenheight - height) / 2 - rect.top;
 } else if (rect.top > 0) {
 deltay = -rect.top;
 } else if (rect.bottom < screenheight) {
 deltay = this.getheight() - rect.bottom;
 }
 }
 
 if (horizontal) {
 int screenwidth = dm.widthpixels;
 if (width < screenwidth) {
 deltax = (screenwidth - width) / 2 - rect.left;
 } else if (rect.left > 0) {
 deltax = -rect.left;
 } else if (rect.right < screenwidth) {
 deltax = screenwidth - rect.right;
 }
 }
 matrix.posttranslate(deltax, deltay);
 }
 
 private float spacingx(motionevent event) {
 float x = event.getx(0) - event.getx(1);
 return x;
 }
 private float spacingy(motionevent event) {
 float y = event.gety(0) - event.gety(1);
 return y;
 
 // 取旋转角度
 private float rotation(motionevent event) {
 double delta_x = (event.getx(0) - event.getx(1));
 double delta_y = (event.gety(0) - event.gety(1));
 double radians = math.atan2(delta_y, delta_x);
 return (float) math.todegrees(radians);
 }
 
 /**
 * 两点的距离
 */
 private float spacing(motionevent event) {
 float x = event.getx(0) - event.getx(1);
 float y = event.gety(0) - event.gety(1);
 return floatmath.sqrt(x * x + y * y);
 }
 
 /**
 * 两点的中点
 */
 private void midpoint(pointf point, motionevent event) {
 float x = event.getx(0) + event.getx(1);
 float y = event.gety(0) + event.gety(1);
 point.set(x / 2, y / 2);
 }
 
 
 /**
 *
 * @param bm
 * @note set cover bitmap , which overlay on background.
 */
 private void setcoverbitmap(bitmap bitmap) {
 // setting paint
 paint = new paint();
 
 cachebitmap = bitmap.createbitmap(bitmap.getwidth(), bitmap.getheight(), config.argb_8888);
 cachecanvas = new canvas();
 cachecanvas.setbitmap(cachebitmap);
 cachecanvas.drawbitmap( bitmap, 0, 0, null);
 
 path = new path();
 temppath = new path();
 
 //设置画笔的颜色
 cachepaint = new paint();
 //设置画笔风格
 cachepaint.setstyle(paint.style.stroke);
 //反锯齿
 cachepaint.setantialias(true);
 cachepaint.setstrokejoin(paint.join.round);
 cachepaint.setstrokecap(paint.cap.round);
 cachepaint.setxfermode(new porterduffxfermode(mode.src_atop));
 //设置画笔模糊效果
 cachepaint.setmaskfilter(new blurmaskfilter(5, paintconstants.blur_type));
 
 }
 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/guang09080908/article/details/41408077

延伸 · 阅读

精彩推荐
  • AndroidAndroid完全退出应用程序的方法

    Android完全退出应用程序的方法

    这篇文章主要介绍了Android完全退出应用程序的方法,实例分析了Android退出应用程序的相关方法与实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    Ruthless12002021-03-31
  • Android在Android中动态添加Panel框架的实现代码

    在Android中动态添加Panel框架的实现代码

    项目经常会有这种需求,就是想动态的在某个界面上添加一个Panel。比如,有一个按钮,点击后会显示下拉菜单式的界面。这种需求,就属于动态添加一个...

    Android开发网12512021-01-14
  • AndroidAndroid 异步加载图片的实例代码

    Android 异步加载图片的实例代码

    异步加载图片主要是利用多线程进行下载、图片弱引用缓存和Handler操作UI进行实现的。...

    Android开发网9742021-01-16
  • AndroidAndroid数据存储之SQLite使用

    Android数据存储之SQLite使用

    SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎。它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行...

    Android开发网12062021-05-06
  • AndroidAndroid相机启动加速详解

    Android相机启动加速详解

    本篇文章给大家详细分析了Android实现相机启动加速的相关知识点内容以及实例代码,有兴趣的朋友参考下。...

    take_it6572022-03-08
  • Android浅谈Android系统的基本体系结构与内存管理优化

    浅谈Android系统的基本体系结构与内存管理优化

    这篇文章主要介绍了Android系统的基本体系结构与内存管理优化,非常简洁明了地总结了系统服务及垃圾回收等安卓的一些主要特性,需要的朋友可以参考下...

    iam_wingjay7872021-05-28
  • Androidandroid 屏幕亮度调节方法详解

    android 屏幕亮度调节方法详解

    分析一下自动调节屏幕亮度手机随着光线的强度自我调节,也就是在亮的光线下屏幕自动亮一些,暗的时候就自动调暗一些,本文将详细介绍android 屏幕亮...

    Android开发网3362020-12-19
  • AndroidAndroid自定义view实现水波进度条控件

    Android自定义view实现水波进度条控件

    这篇文章主要为大家详细介绍了Android自定义view实现水波进度条控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    yhongm11812022-02-21