1.屏幕的尺寸信息
屏幕大小:寸,屏幕对角线的长度
分辨率:手机屏幕像素点的个数,720*1280.
PPI:每英寸像素又被称为DPI。他是由对角线的像素点除以屏幕的大小的得到的。
独立像素密度:dp,同样像素大小的长度在不同密度的屏幕上显示长度不同。
2.2D绘图基础
系统通过canvas对象提供绘图方法,像画圆,画线,画矩形等等。。。设置paint笔的的一些参数。具体画法可以自己百度查一下。
3.Android XML绘图
XML在安卓中可不仅仅是一个布局文件,配置列表,也可以变成一张画一幅图。
在xml中使用bitmap;
在xml中使用shape:是xml绘图的精华所在功能十分强大。整个shape的可用参数自己去网上百度,印象更深。画好了可以当作一个空间的背景啊,或者用作src啊,等等。
在xml中使用layer图层:通过layer,layer-list可以很方便的饿实现图层效果,图片会依次叠加。
在xml中使用selector:这一方法可以帮助开发者迅速制作view的触摸反馈,像是一个按钮你点击一下背景就变色的效果等等,都可以。
4.安卓绘图技巧
默认的坐标零点位于屏幕的左上角,向下作为y轴方向,向右作为x轴方向。
下面是一个如何画表盘的例子。
先画外面的圈,也就是原盘。其实就是画一个圆。很简单吧
然后就要考虑画刻度线,这个还是比较麻烦的,这个时候就需要动脑子怎么才能简单的画出刻度线。就是从0点刻度线画起,画刻度线就是canvas画直线的方法,每画好一个就将对画布进行旋转15度,然后再画。旋转就是canvas.ratate();
最后就是画指针,为了方便画指针,而不要繁琐的计算指针的坐标结果,所以就需要用到canvas的translate方法,移动坐标的原点位置,然后再进行画。这样就会比较简单。具体代码如下。
public class Clock extends View { private int mHeight, mWidth; public Clock(Context context) { super(context); } public Clock(Context context, AttributeSet attrs) { super(context, attrs); } public Clock(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { // 获取宽高参数 mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); // 画外圆 Paint paintCircle = new Paint(); paintCircle.setStyle(Paint.Style.STROKE); paintCircle.setAntiAlias(true); paintCircle.setStrokeWidth(5); canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, paintCircle); // 画刻度 Paint painDegree = new Paint(); paintCircle.setStrokeWidth(3); for (int i = 0; i < 24; i++) { // 区分整点与非整点 if (i == 0 || i == 6 || i == 12 || i == 18) { painDegree.setStrokeWidth(5); painDegree.setTextSize(30); canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 60, painDegree); String degree = String.valueOf(i); canvas.drawText(degree, mWidth / 2 - painDegree.measureText(degree) / 2, mHeight / 2 - mWidth / 2 + 90, painDegree); } else { painDegree.setStrokeWidth(3); painDegree.setTextSize(15); canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 30, painDegree); String degree = String.valueOf(i); canvas.drawText(degree, mWidth / 2 - painDegree.measureText(degree) / 2, mHeight / 2 - mWidth / 2 + 60, painDegree); } // 通过旋转画布简化坐标运算 canvas.rotate(15, mWidth / 2, mHeight / 2); } // 画圆心 Paint paintPointer = new Paint(); paintPointer.setStrokeWidth(30); canvas.drawPoint(mWidth / 2, mHeight / 2, paintPointer); // 画指针 Paint paintHour = new Paint(); paintHour.setStrokeWidth(20); Paint paintMinute = new Paint(); paintMinute.setStrokeWidth(10); canvas.save(); canvas.translate(mWidth / 2, mHeight / 2); canvas.drawLine(0, 0, 100, 100, paintHour); canvas.drawLine(0, 0, 100, 200, paintMinute); canvas.restore(); } }
还有就是我们常常会遇到图形的叠加,在安卓中我们也叫layer图层。通过canvas的setLayer,setLayerAlpha方法将一个图层入栈,然后就在这个图层画另外的东西,最后canvas的restore方法,则会把图像绘制到上层的canvas上。下面有个小事例,大家可供参考。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyLayer(this)); } public class MyLayer extends View { private Paint mPaint; private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG; public MyLayer(Context context) { super(context); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); mPaint.setColor(Color.BLUE); canvas.drawCircle(150, 150, 100, mPaint); canvas.saveLayerAlpha(0, 0, 400, 400,0, LAYER_FLAGS); mPaint.setColor(Color.RED); canvas.drawCircle(200, 200, 100, mPaint); canvas.restore(); } } }5.安卓图像处理之色彩特效处理
改变色光属性:图像的色调,饱和度,亮度这三个属性在图像处理中的使用非常之多。因此在安卓中,系统封装了一个类--ColorMatrix,也就是我们所知的颜色矩阵,通过这个我们就能快速方便的通过改变矩阵值来处理颜色效果。
‘色调:这个类提供了setRotate(int axis,float degree)来帮助我们设置颜色的色调,第一个参数系统分别使用012来代表red,green,blue三种颜色的处理,第二个参数就是需要处理的值。
‘饱和度:setSaturation方法来设置颜色的饱和度的值,当饱和度为0时,图像就会变成灰度图像了
‘亮度:setScale(lum,lum,lum,1);当三原色以相同的比例混合时,就会显示出白色系统也正是使用这个原理来改变一个图像的亮度,当亮度为0 的时候,图像就会变成全黑了。
除了上述单独使用上面的三种方式来进行颜色效果的处理之外,安卓系统还封装了矩阵的乘法运算,它提供postConcat()方法将矩阵的作用效果混合,从而叠加这些处理效果。
这所有的colormatrix到最后在一起都要放在paint的setColorFilter方法中,然后放入canvas的draw方法里面,下面代码有体现出来注意观察。
具体可以看如下事例代码:
下面是一个帮助类,里面封装了一些方法;
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; } }
public class PrimaryColor extends Activity implements SeekBar.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.primary_color); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test3); 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) { } }
6.安卓颜色矩阵-colormatrix
通过改变矩阵的值来调整图像色彩。
public class ColorMatrix extends Activity { private ImageView mImageView; private GridLayout mGroup; private Bitmap bitmap; private int mEtWidth, mEtHeight; private EditText[] mEts = new EditText[20]; private float[] mColorMatrix = new float[20]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.color_matrix); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1); mImageView = (ImageView) findViewById(R.id.imageview); mGroup = (GridLayout) findViewById(R.id.group); mImageView.setImageBitmap(bitmap); mGroup.post(new Runnable() { @Override public void run() { // 获取宽高信息 mEtWidth = mGroup.getWidth() / 5; mEtHeight = mGroup.getHeight() / 4; addEts(); initMatrix(); } }); } // 获取矩阵值 private void getMatrix() { for (int i = 0; i < 20; i++) { mColorMatrix[i] = Float.valueOf( mEts[i].getText().toString()); } } // 将矩阵值设置到图像 private void setImageMatrix() { Bitmap bmp = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); android.graphics.ColorMatrix colorMatrix = new android.graphics.ColorMatrix(); colorMatrix.set(mColorMatrix); Canvas canvas = new Canvas(bmp); Paint paint = new Paint(); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(bitmap, 0, 0, paint); mImageView.setImageBitmap(bmp); } // 作用矩阵效果 public void btnChange(View view) { getMatrix(); setImageMatrix(); } // 重置矩阵效果 public void btnReset(View view) { initMatrix(); getMatrix(); setImageMatrix(); } // 添加EditText private void addEts() { for (int i = 0; i < 20; i++) { EditText editText = new EditText(ColorMatrix.this); mEts[i] = editText; mGroup.addView(editText, mEtWidth, mEtHeight); } } // 初始化颜色矩阵为初始状态 private void initMatrix() { for (int i = 0; i < 20; i++) { if (i % 6 == 0) { mEts[i].setText(String.valueOf(1)); } else { mEts[i].setText(String.valueOf(0)); } } } }调整过后的数组值直接在colormatrix的set里面设置进去。
7.像素点分析
作为更加精确的图像处理方式,可以通过改变每个像素点的argb值,达到处理一张图像效果的目的。
具体步骤请见上述的帮助类里。有很多效果的照片算法,请查阅相关资料。