Android绘图(二)
2015-12-29 18:44
615 查看
(《群英传》)整理笔记:
图像处理之色彩特效处理:
(这一块不太懂,先记录下一个例子)
程序运行后可拖动三个属性条实时改变图像。
(留待以后学习)
【色彩矩阵、颜色矩阵ColorMatrix、常用图像颜色矩阵处理效果(灰度、图像反转、怀旧、去色、高饱和度)、像素点、常用像素点处理效果(底片、老照片、浮雕)】
图像处理之图形特效处理
图像的变形处理包含四类基本变换
Translate:平移变换
Rotate:旋转变换
Scale:缩放变换
Skew:错切变换
像素块分析
drawBitmapMeshh():将图像分成了一个个小块,然后通过改变每一个图像块来修改整个图像。基本上可以实现所有的图像特效。
canvas.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
Bitmap:将要扭曲的图像;meshWidth:需要的横向网格数目;meshHeight:需要的纵向网格数目;verts:网格交叉点坐标数组;vertOffset:verts数组中开始跳过的(x, y)坐标对的数目。
示例:旗帜飞扬
核心思想:让图片中每个交织点的横坐标较之前坐标不断变化
Android图像处理值画笔特效处理:
各种各样的画笔:记号笔、毛笔、蜡笔等。
1、PorterDuffXfermode:
PorterDuffXfermode设置的是两个图层交际区域的显示方式,dst是先画的图形,而src是后画的图形,通过控制遮罩层的图形,来控制下面被这招图形的显示效果,最常用的就是通过DST_IN、SRC_IN模式来实现将一个矩形图片变成圆角图片或者圆形图片的效果。
2、Shader
着色器、渲染器。用来实现一系列的渐变、渲染效果。
Android中的Shader包括以下几种:
(1)BitmapShader位图:产生的是一个图像,作用是通过Paint对画布进行指定Bitmap的填充。填充的模式:CLAMP拉伸;REPEAT重复;MIRROR镜像。
(2)LinearGradient线性;
(3)RadialGradient光束;
(4)SweepGradient梯度;
(5)ComposeShader混合。
但是这些渐变效果不会直接使用在程序里,通常情况下把这种渐变效果作为一个遮罩层来使用。
图像处理之色彩特效处理:
(这一块不太懂,先记录下一个例子)
package com.android.utils; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; /** * 设置图像矩阵的代码 * @author Administrator * */ public class ImageHelper { public static Bitmap handleImageEffect(Bitmap bm, float hue, float saturation, float lum) { Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bmp); Paint paint = new Paint(); ColorMatrix hueMatrix = new ColorMatrix(); hueMatrix.setRotate(0, hue); hueMatrix.setRotate(1, hue); hueMatrix.setRotate(2, hue); ColorMatrix saturationMatrix = new ColorMatrix(); saturationMatrix.setSaturation(saturation); ColorMatrix lumMatrix = new ColorMatrix(); lumMatrix.setScale(lum, lum, lum, 1); ColorMatrix imageMatrix = new ColorMatrix(); imageMatrix.postConcat(hueMatrix); imageMatrix.postConcat(saturationMatrix); imageMatrix.postConcat(lumMatrix); paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix)); canvas.drawBitmap(bm, 0, 0, paint); return bmp; } public static Bitmap handleImageNegative(Bitmap bm) { int width = bm.getWidth(); int height = bm.getHeight(); int color; int r, g, b, a; Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); int[] oldPx = new int[width * height]; int[] newPx = new int[width * height]; bm.getPixels(oldPx, 0, width, 0, 0, width, height); for (int i = 0; i < width * height; i++) { color = oldPx[i]; r = Color.red(color); g = Color.green(color); b = Color.blue(color); a = Color.alpha(color); r = 255 - r; g = 255 - g; b = 255 - b; if (r > 255) { r = 255; } else if (r < 0) { r = 0; } if (g > 255) { g = 255; } else if (g < 0) { g = 0; } if (b > 255) { b = 255; } else if (b < 0) { b = 0; } newPx[i] = Color.argb(a, r, g, b); } bmp.setPixels(newPx, 0, width, 0, 0, width, height); return bmp; } public static Bitmap handleImagePixelsOldPhoto(Bitmap bm) { Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888); int width = bm.getWidth(); int height = bm.getHeight(); int color = 0; int r, g, b, a, r1, g1, b1; int[] oldPx = new int[width * height]; int[] newPx = new int[width * height]; bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height); for (int i = 0; i < width * height; i++) { color = oldPx[i]; a = Color.alpha(color); r = Color.red(color); g = Color.green(color); b = Color.blue(color); r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b); g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b); b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b); if (r1 > 255) { r1 = 255; } if (g1 > 255) { g1 = 255; } if (b1 > 255) { b1 = 255; } newPx[i] = Color.argb(a, r1, g1, b1); } bmp.setPixels(newPx, 0, width, 0, 0, width, height); return bmp; } public static Bitmap handleImagePixelsRelief(Bitmap bm) { Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888); int width = bm.getWidth(); int height = bm.getHeight(); int color = 0, colorBefore = 0; int a, r, g, b; int r1, g1, b1; int[] oldPx = new int[width * height]; int[] newPx = new int[width * height]; bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height); for (int i = 1; i < width * height; i++) { colorBefore = oldPx[i - 1]; a = Color.alpha(colorBefore); r = Color.red(colorBefore); g = Color.green(colorBefore); b = Color.blue(colorBefore); color = oldPx[i]; r1 = Color.red(color); g1 = Color.green(color); b1 = Color.blue(color); r = (r - r1 + 127); g = (g - g1 + 127); b = (b - b1 + 127); if (r > 255) { r = 255; } if (g > 255) { g = 255; } if (b > 255) { b = 255; } newPx[i] = Color.argb(a, r, g, b); } bmp.setPixels(newPx, 0, width, 0, 0, width, height); return bmp; } }
import com.android.utils.ImageHelper; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; /** * 色调、饱和度、亮度调整图片 * @author Administrator * */ public class MyView3 extends Activity implements OnSeekBarChangeListener{ private static int MAX_VALUE = 255; private static int MID_VALUE = 127; private ImageView mImageView; private SeekBar mSeekbarhue, mSeekbarSaturation, mSeekbarLum; private float mHue, mStauration, mLum; private Bitmap bitmap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_view3); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qie); mImageView = (ImageView) findViewById(R.id.imageview); mSeekbarhue = (SeekBar) findViewById(R.id.seekbarHue); mSeekbarSaturation = (SeekBar) findViewById(R.id.seekbarSaturation); mSeekbarLum = (SeekBar) findViewById(R.id.seekbatLum); mSeekbarhue.setOnSeekBarChangeListener(this); mSeekbarSaturation.setOnSeekBarChangeListener(this); mSeekbarLum.setOnSeekBarChangeListener(this); mSeekbarhue.setMax(MAX_VALUE); mSeekbarSaturation.setMax(MAX_VALUE); mSeekbarLum.setMax(MAX_VALUE); mSeekbarhue.setProgress(MID_VALUE); mSeekbarSaturation.setProgress(MID_VALUE); mSeekbarLum.setProgress(MID_VALUE); mImageView.setImageBitmap(bitmap); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { switch (seekBar.getId()) { case R.id.seekbarHue: mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180; break; case R.id.seekbarSaturation: mStauration = progress * 1.0F / MID_VALUE; break; case R.id.seekbatLum: mLum = progress * 1.0F / MID_VALUE; break; } mImageView.setImageBitmap(ImageHelper.handleImageEffect( bitmap, mHue, mStauration, mLum)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }
程序运行后可拖动三个属性条实时改变图像。
(留待以后学习)
【色彩矩阵、颜色矩阵ColorMatrix、常用图像颜色矩阵处理效果(灰度、图像反转、怀旧、去色、高饱和度)、像素点、常用像素点处理效果(底片、老照片、浮雕)】
图像处理之图形特效处理
图像的变形处理包含四类基本变换
Translate:平移变换
Rotate:旋转变换
Scale:缩放变换
Skew:错切变换
像素块分析
drawBitmapMeshh():将图像分成了一个个小块,然后通过改变每一个图像块来修改整个图像。基本上可以实现所有的图像特效。
canvas.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
Bitmap:将要扭曲的图像;meshWidth:需要的横向网格数目;meshHeight:需要的纵向网格数目;verts:网格交叉点坐标数组;vertOffset:verts数组中开始跳过的(x, y)坐标对的数目。
示例:旗帜飞扬
核心思想:让图片中每个交织点的横坐标较之前坐标不断变化
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; public class DrawBitmapMesh extends View { private final int WIDTH = 200; private final int HEIGHT = 200; private int COUNT = (WIDTH + 1) * (HEIGHT + 1); private float[] verts = new float[COUNT * 2]; private float[] orig = new float[COUNT * 2]; private Bitmap bitmap; private float A; private float k = 1; public DrawBitmapMesh(Context context) { super(context); initView(context); } public DrawBitmapMesh(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public DrawBitmapMesh(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { setFocusable(true); // 第一步:获取交叉点的坐标,保存在orig数组中 bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.test); float bitmapWidth = bitmap.getWidth(); float bitmapHeight = bitmap.getHeight(); // 通过循环遍历所有的交叉线,并按比例获取其坐标 int index = 0; for (int y = 0; y <= HEIGHT; y++) { float fy = bitmapHeight * y / HEIGHT; for (int x = 0; x <= WIDTH; x++) { float fx = bitmapWidth * x / WIDTH; orig[index * 2 + 0] = verts[index * 2 + 0] = fx; // 为了避免扭曲后被屏幕遮挡,人为将坐标+100为了让图像下移 orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 100; index += 1; } } A = 50; } @Override protected void onDraw(Canvas canvas) { flagWave(); // 第四步:将处理后的图像绘制出来。每次绘制的时候通过改变相位来改变偏移量,从而造成动态的效果 k += 0.1F; canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts, 0, null, 0, null); invalidate(); } // 第二步:改变交叉点的纵坐标的值,使用sin x 来改变交叉点纵坐标的值,保存到vert数组中 private void flagWave() { for (int j = 0; j <= HEIGHT; j++) { for (int i = 0; i <= WIDTH; i++) { verts[(j * (WIDTH + 1) + i) * 2 + 0] += 0; // 第三步:让图像动起来。利用函数的周期性 float offsetY = (float) Math.sin((float) i / WIDTH * 2 * Math.PI + Math.PI * k); verts[(j * (WIDTH + 1) + i) * 2 + 1] = orig[(j * WIDTH + i) * 2 + 1] + offsetY * A; } } } }
Android图像处理值画笔特效处理:
各种各样的画笔:记号笔、毛笔、蜡笔等。
1、PorterDuffXfermode:
PorterDuffXfermode设置的是两个图层交际区域的显示方式,dst是先画的图形,而src是后画的图形,通过控制遮罩层的图形,来控制下面被这招图形的显示效果,最常用的就是通过DST_IN、SRC_IN模式来实现将一个矩形图片变成圆角图片或者圆形图片的效果。
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * 刮刮卡效果 * * @author Administrator * */ public class ProterDuffXfermode extends View { private Bitmap mBgBitmap, mFgBitmap; private Paint mPaint; private Canvas mCanvas; private Path mPath; public ProterDuffXfermode(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * 第一步:做一些初始化工作。例如准备好图片,设置好Paint的一些属性 */ private void init() { mPaint = new Paint(); // 将画笔的透明度置为0,这样才能显示出擦除的效果 mPaint.setAlpha(0); // 第三步:使用DST_IN模式 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); mPaint.setStyle(Paint.Style.STROKE); // 让笔触和连接处更加圆滑一点Paint.Join.ROUND,Paint.Cap.ROUND mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeWidth(60); mPaint.setStrokeCap(Paint.Cap.ROUND); mPath = new Path(); mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qie); mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(), mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mFgBitmap); mCanvas.drawColor(Color.GRAY); } // 第二步:获取用户手指滑动所产生的路径,使用Path保存用户手指划过的路径(贝塞尔曲线会有更好的显示效果) @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPath.reset(); mPath.moveTo(event.getX(), event.getY()); break; case MotionEvent.ACTION_MOVE: mPath.lineTo(event.getX(), event.getY()); break; } mCanvas.drawPath(mPath, mPaint); invalidate(); return true; } @Override protected void onDraw(Canvas canvas) { // 第四步:将路径绘制到前面覆盖的图层上面即可 canvas.drawBitmap(mBgBitmap, 0, 0, null); canvas.drawBitmap(mFgBitmap, 0, 0, null); } }
2、Shader
着色器、渲染器。用来实现一系列的渐变、渲染效果。
Android中的Shader包括以下几种:
(1)BitmapShader位图:产生的是一个图像,作用是通过Paint对画布进行指定Bitmap的填充。填充的模式:CLAMP拉伸;REPEAT重复;MIRROR镜像。
(2)LinearGradient线性;
(3)RadialGradient光束;
(4)SweepGradient梯度;
(5)ComposeShader混合。
// 用一张图片创建了一支具有图像填充功能的画笔,并使用这支画笔绘制了一个圆形。 mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); mPaint = new Paint(); mPaint.setShader(mBitmapShader); canvas.drawCircle(250, 250, 200, mPaint);
// LinearGradient的使用:只需要指定渐变起始的颜色就可以了。 mPaint = new Paint(); mPaint.setShader(new LinearGradient(0, 0, 200, 200, Color.BLUE, Color.YELLOW, Shader.TileMode.REPEAT)); canvas.drawRect(0,0,800,800,mPaint);
但是这些渐变效果不会直接使用在程序里,通常情况下把这种渐变效果作为一个遮罩层来使用。
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; public class DaoYing extends View { private Bitmap mSrcBitmap, mRefBitmap; private Paint mPaint; private PorterDuffXfermode mXfermode; public DaoYing(Context context) { super(context); initRes(context); } public DaoYing(Context context, AttributeSet attrs) { super(context, attrs); initRes(context); } public DaoYing(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initRes(context); } /** * 第一步:把原图复制一份并进行翻转 * * @param context */ private void initRes(Context context) { mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qie); Matrix matrix = new Matrix(); // 使用matrix.setScale(1F, -1F)方法来实现图片的垂直翻转。水平翻转同理 matrix.setScale(1F, -1F); mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight(), matrix, true); mPaint = new Paint(); mPaint.setShader(new LinearGradient(0, mSrcBitmap.getHeight(), 0, mSrcBitmap.getHeight() + mSrcBitmap.getHeight() / 4, 0XDD000000, 0X10000000, Shader.TileMode.CLAMP)); mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); } @Override protected void onDraw(Canvas canvas) { // 第二步:绘制两张图片即原图和倒影图 canvas.drawColor(Color.BLACK); canvas.drawBitmap(mSrcBitmap, 0, 0, null); canvas.drawBitmap(mRefBitmap, 0, mSrcBitmap.getHeight(), null); mPaint.setXfermode(mXfermode); // 第三步:绘制渐变效果矩形,并通过Mode.DST_IN模式绘制到倒影图上,形成一个具有过度效果的渐变层 canvas.drawRect(0, mSrcBitmap.getHeight(), mRefBitmap.getWidth(), mSrcBitmap.getHeight() * 2, mPaint); mPaint.setXfermode(null); } }
相关文章推荐
- 19.Android之文件存储方法学习
- AndroidStudio开发环境搭建
- Android 之 注解
- Android自定义组合控件
- android适配的努力
- [android问题]小记碰到的问题
- Android 输入法键盘和activity页面遮挡问题解决
- [android项目]开发过程中需要时刻注意的
- Android图片压缩批量上传
- Android版添加phonegap--Native Api插件教程
- Android设置背景色为透明
- android 开源图表库MPChart最简单使用方法--折线图
- android 开源图表库MPChart最简单使用方法示例教程Demo--折线图 柱状图
- Android之JAVASe基础篇-面向对象-高级部分(四)
- Android状态栏兼容4.4.4与5.0,Android5.0状态栏由半透明设置为全透明
- android跳转手机百度高德腾讯谷歌地图、地图传坐标、坐标偏移、base64解码相关
- border-radius在Android下的几个BUG
- android进度记录
- android Graphics( 五):drawText()详解
- Android:ListView底部footview无法显示问题解决