说起滤镜,是图像处理中常用的工具,它将原图赋予各种效果,像是在原图是蒙上了一层有效果的镜子。虽然最终的效果是这样,但是在移动的设备上,其原理不可能是放两张图。而是对原图的每一个点的ARGB进行变换。所以在写代码之前,我们需要了解,图像的ARGB是如何进行变换的。Android中可以通过颜色矩阵(ColorMatrix类)进行颜色变换。
通过上面的计算方式一目了然了。图片本身的每个点的颜色是C矩阵,我们的滤镜矩阵则是A矩阵,最后经过滤镜处理得到的图上的每个点是R矩阵。
在此,列一个将图片滤为黑白的为例
Paint paint = new Paint(); ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.set(new float[] { 0.3f, 0.59f, 0.11f, 0, 0, 0.3f, 0.59f, 0.11f, 0, 0, 0.3f, 0.59f, 0.11f, 0, 0, 0, 0, 0, 1, 0 }); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
经这样的矩阵变换后,新的图片RGB三个值是相等的,大小只取决于0.3*R+0.59*G+0.11*B的值。这样图片就变成了黑白的。
在自己学习的demo中,我用了一个SurfaceView来显示处理后的图片。
public class FilterSurfaceView extends SurfaceView { SurfaceHolder surfaceHolder; boolean backThreadLock = true; boolean threadIsRunning = true; String pathStr; public FilterSurfaceView(Context context) { super(context); init(); } public FilterSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public FilterSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init(){ surfaceHolder = this.getHolder(); surfaceHolder.addCallback(callback); } // 将pathStr目录下的指定文件进行滤镜处理,并显示处理后的bitmap private class FiltBitmapTask extends AsyncTask<Void , Integer , Bitmap>{ @Override protected Bitmap doInBackground(Void... params) { // 用于关闭线程 while (threadIsRunning){ if (!backThreadLock && pathStr != null && !TextUtils.isEmpty(pathStr)){ Canvas cv = null; Bitmap bitmap = BitmapFactory.decodeFile(pathStr); try { synchronized (surfaceHolder){ cv = surfaceHolder.lockCanvas(); Paint paint = new Paint(); ColorMatrix colorMatrix = new ColorMatrix(); // 黑白滤镜矩阵 colorMatrix.set(new float[] { 0.3f, 0.59f, 0.11f, 0, 0, 0.3f, 0.59f, 0.11f, 0, 0, 0.3f, 0.59f, 0.11f, 0, 0, 0, 0, 0, 1, 0 }); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); // 图简单只取了屏幕宽高 RectF rectF = new RectF(0 , 0 , ScreenHelper.getInstance().getScreenWidth() , ScreenHelper.getInstance().getScreenHeight()); cv.drawBitmap(bitmap, null, rectF, paint); surfaceHolder.unlockCanvasAndPost(cv); } }catch (Exception e){ }finally { backThreadLock = true; if (!bitmap.isRecycled()){ bitmap.recycle(); bitmap = null; } } } return null; } return null; } } public void setPathStr(String pathStr){ this.pathStr = pathStr; } SurfaceHolder.Callback callback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { FiltBitmapTask filtBitmapTask = new FiltBitmapTask(); filtBitmapTask.execute(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { threadIsRunning = false; } }; public void refresh(){ backThreadLock = false; } }
Done