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 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。