1.粒子效果的核心有三个点:收集粒子、更改粒子、显示粒子
2.Bitmap的能够获取像素,从而获得每一个像素的颜色值
3.能够经过粒子拼合一张图片,并对粒子操做完成不少意想不到的效果
4.本项目源码见文尾捷文规范
第一条,文件为BitmapSplitView.java
java
1.什么是Bitmap像素级的操做:git
相信你们都知道一张jpg或png放大后会是一个个小格子,称为一个像素(px),并且一个小格子是一种颜色
也就是一张jpg或png图片就是不少颜色的合集,而这些合集信息都被封装到了Bitmap类中
你可使用Bitmap获取任意像素点,并修改它,对与某像素点而言,颜色信息是其主要的部分github
像素.png算法
2.获取第一个像素canvas
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.iv_200x200); int color_0_0 = bitmap.getPixel(0, 0);//获取第1行,第1个像素颜色
使用该颜色画一个圆测试一下:数组
第一点.png微信
3.获取全部点像素颜色值dom
这里i表明列数,j表明行数,mColArr[i][j]表明是一个图片第i列,第j行的像素颜色值ide
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.iv_200x200); mColArr = new int[bitmap.getWidth()][bitmap.getHeight()]; for (int i = 0; i < bitmap.getWidth(); i++) { for (int j = 0; j < bitmap.getHeight(); j++) { mColArr[i][j] = bitmap.getPixel(i, j); } }
1.首先看一下如何建立一个Bitmap对象函数
新建一个
2*2的ARGB_8888
图片:颜色分别是黑(0,0)、红(1,0)、白(0,1)、蓝(1,1)
Bitmap bitmap = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); bitmap.setPixel(0, 0, Color.BLACK); bitmap.setPixel(1, 0, Color.RED); bitmap.setPixel(0, 1, Color.WHITE); bitmap.setPixel(1, 1, Color.BLUE);
2.保存bitmap成为图片到本地
保存bitmap就是压缩到一个输出流里,写成文件
输出结果.png
/** * 保存bitmap到本地 * * @param path 路径 * @param mBitmap 图片 * @return 路径 */ public static String saveBitmap(String path, Bitmap mBitmap) { File filePic = FileHelper.get().createFile(path + ".png"); try { FileOutputStream fos = new FileOutputStream(filePic); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); return null; } return filePic.getAbsolutePath(); }
3.bitmap.getPixel到底说了什么?
int pixel_0_0 = bitmap.getPixel(0, 0); int pixel_1_0 = bitmap.getPixel(1, 0); int pixel_0_1 = bitmap.getPixel(0, 1); int pixel_1_1 = bitmap.getPixel(1, 1); 黑:pixel_0_0:-16777216 红:pixel_1_0:-65536 白:pixel_0_1:-1 蓝:pixel_1_1:-16776961
都是负数,感受不怎么好懂:其实那就是颜色值
Color类中有几个方法能够方便获取argb分别对应的值,下面测试一下你就明白了
其实就是将int进行了位运算,分离出argb四个通道的值
printColor("pixel_0_0", pixel_0_0);//黑:a:255, r:0, g:0, b:0 printColor("pixel_1_0", pixel_1_0);//红:a:255, r:255, g:0, b:0 printColor("pixel_0_1", pixel_0_1);//白:a:255, r:255, g:255, b:255 printColor("pixel_1_1", pixel_1_1);//蓝:a:255, r:0, g:0, b:255 /** * 将颜色从int 拆分红argb,并打印出来 * @param msg * @param color */ private void printColor(String msg, int color) { int a = Color.alpha(color); int r = Color.red(color); int g = Color.green(color); int b = Color.blue(color); L.d(msg + "----a:" + a + ", r:" + r + ", g:" + g + ", b:" + b + L.l()); }
既然像素颜色信息拿到手了,不就等于天下我有了吗?
1.bitmap复刻的粒子载体
public class Ball implements Cloneable { public float aX;//加速度 public float aY;//加速度Y public float vX;//速度X public float vY;//速度Y public float x;//点位X public float y;//点位Y public int color;//颜色 public float r;//半径 public long born;//诞生时间 public Ball clone() { Ball clone = null; try { clone = (Ball) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }
2.初始化粒子:
坐标分析.png
private int d = 50;//复刻的像素边长 private List<Ball> mBalls = new ArrayList<>();//粒子集合
/** * 根像素初始化粒子 * @param bitmap * @return */ private List<Ball> initBall(Bitmap bitmap) { for (int i = 0; i < bitmap.getHeight(); i++) { for (int j = 0; j < bitmap.getWidth(); j++) { Ball ball = new Ball(); ball.x = i * d + d / 2; ball.y = j * d + d / 2; ball.color = bitmap.getPixel(i, j); mBalls.add(ball); } } return mBalls; }
3.正方形粒子的绘制(原图复刻):
原图复刻.png
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mCoo.x, mCoo.y); for (Ball ball : mBalls) { mPaint.setColor(ball.color); canvas.drawRect( ball.x - d / 2, ball.y - d / 2, ball.x + d / 2, ball.y + d / 2, mPaint); } canvas.restore(); HelpDraw.draw(canvas, mGridPicture, mCooPicture); }
4.复刻其余图片资源文件
只要是bitmap就好了,咱们能够decode图片变成Bitmap
注意:此处只是演示,画一张bitmap仍是用原生的好,像素级的粒子化由它的优点,好比运动
//加载图片数组 mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.iv_200x200); initBall(mBitmap);
原图复刻图片资源.png
5.圆形复刻
这里的4中的图片已经不是bitmap了,而是由一个个小正方形堆积成的东西,这些小正方形拥有本身的颜色
然而咱们能够利用它实现一些好玩的东西,好比不画正方形,画个圆怎么样?
如今你明白像素级操做什么了吧。也许你会感叹,还能怎么玩,先把下巴收回去,后面还有更惊叹的呢。
圆形复刻图片资源.png
for (Ball ball : mBalls) { mPaint.setColor(ball.color); canvas.drawCircle(ball.x, ball.y, d/2, mPaint); }
6.其余形状复刻
你能够用任意的图形更换粒子单元,或者各类形状的粒子混合适用,全凭你的操做
像素单元都在你的手上了,还有什么不能作。
五角星复刻图片资源.png
for (int i = 0; i < mBalls.size(); i++) { canvas.save(); int line = i % mBitmap.getHeight(); int row = i / mBitmap.getWidth(); canvas.translate(row * 2 * d, line * 2 * d); mPaint.setColor(mBalls.get(i).color); canvas.drawPath(CommonPath.nStarPath(5, d, d / 2), mPaint); canvas.restore(); }
在Color篇中详细介绍了使用
ColorFilter
和ColorMatrix
改变图片颜色
这里既然拿到了小球颜色,那么统一改变一下小球的颜色则何如?
注:如下属于改变颜色的旁门左道,主要为了演示。正规仍是用ColorFilter
和ColorMatrix
吧
颜色处理.png
1.下面是图片黑白化的算法
之前在JavaScript用过,在Python用过,如今终于用到java上了,难免感慨,语言无界限,真理永恒
因此你们最好收集一下相关的真理
,无论什么时候都不会过期,也不会错误,就像1+1=2
/** * 根像素初始化粒子 * * @param bitmap * @return */ private List<Ball> initBall(Bitmap bitmap) { for (int i = 0; i < bitmap.getHeight(); i++) { for (int j = 0; j < bitmap.getWidth(); j++) { Ball ball = new Ball(); ball.x = i * d + d / 2; ball.y = j * d + d / 2; //获取像素点的a、r、g、b int color_i_j = bitmap.getPixel(i, j); int a = Color.alpha(color_i_j); int r = Color.red(color_i_j); int g = Color.green(color_i_j); int b = Color.blue(color_i_j); ball.color = blackAndWhite(a, r, g, b); mBalls.add(ball); } } return mBalls; } /** * 配凑黑白颜色 */ private int blackAndWhite(int a, int r, int g, int b) { //拼凑出新的颜色 int grey = (int) (r * 0.3 + g * 0.59 + b * 0.11); if (grey > 255 / 2) { grey = 255; } else { grey = 0; } return Color.argb(a, grey, grey, grey); }
2.灰色处理函数
/** * 配凑灰颜色 */ private int grey(int a, int r, int g, int b) { //拼凑出新的颜色 int grey = (int) (r * 0.3 + g * 0.59 + b * 0.11); return Color.argb(a, grey, grey, grey); }
3.颜色反转
//颜色反转 private int reverse(int a, int r, int g, int b) { //拼凑出新的颜色 return Color.argb(a, 255-r, 255-g, 255-b); }
到了最重要的地方了,让小球动起来的核心分析见Android原生绘图之让你了解View的运动:
重力扩散.gif
1.将一个图片粒子化的方法
这里速度x方向是正负等几率随机数值,因此粒子会呈现左右运动趋势
有必定的y方向速度,但加速度aY向下,致使粒子向下运动,综合效果就是两边四散加坠落
要改变粒子的运动方式,只要改变粒子的这些参数就好了。
/** * 根像素初始化粒子 * * @param bitmap * @return */ private void initBall(Bitmap bitmap) { for (int i = 0; i < bitmap.getHeight(); i++) { for (int j = 0; j < bitmap.getWidth(); j++) { Ball ball = new Ball();//产生粒子---每一个粒子拥有随机的一些属性信息 ball.x = i * d + d / 2; ball.y = j * d + d / 2; ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); ball.vY = rangeInt(-15, 35); ball.aY = 0.98f; ball.color = bitmap.getPixel(i, j); ball.born = System.currentTimeMillis(); mBalls.add(ball); } } }
2.更新小球
/** * 更新小球 */ private void updateBall() { for (int i = 0; i < mBalls.size(); i++) { Ball ball = mBalls.get(i); if (System.currentTimeMillis() - mRunTime > 2000) { mBalls.remove(i); } ball.x += ball.vX; ball.y += ball.vY; ball.vY += ball.aY; ball.vX += ball.aX; } }
3.初始化时间流:ValueAnimator
//初始化时间流ValueAnimator mAnimator = ValueAnimator.ofFloat(0, 1); mAnimator.setRepeatCount(-1); mAnimator.setDuration(2000); mAnimator.setInterpolator(new LinearInterpolator()); mAnimator.addUpdateListener(animation -> { updateBall();//更新小球位置 invalidate(); });
4.点击开启ValueAnimator
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mRunTime = System.currentTimeMillis();//记录点击时间 mAnimator.start(); break; } return true; }
好了,本篇就到这里,你是否是更清楚Bitmap是什么了?
但愿本文能够给你一点灵感,你能作出更酷炫的东西。
1.本文成长记录及勘误表
项目源码 | 日期 | 备注 |
---|---|---|
V0.1--github | 2018-11-17 | Android粒子篇之Bitmap像素级操做 |
2.更多关于我
笔名 | 微信 | 爱好 | |
---|---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 | 语言 |
个人github | 个人简书 | 个人掘金 | 我的网站 |
做者:张风捷特烈 连接:https://www.jianshu.com/p/12184d861646 來源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。