package com.bob.digcsdn.utils;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextUtils;
import android.util.Log;
import com.bob.digcsdn.interfaces.IVerify;
import java.util.Random;
/**
* 具有逻辑算术的验证方法
*/
public class LogicVerify implements IVerify {
int result;
private static final char[] CHARS = {//定义随机字符集
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'零', '一','二', '三', '四', '五', '六', '七', '八', '九'
};
private static final String[] OPERATORS = {//定义随机字符集
"加上","减去","乘以","除以","+","-","×","÷"
};
private static LogicVerify vCode;
public static LogicVerify getInstance() {//单例模式获取验证码对象
if (vCode == null)
vCode = new LogicVerify();
return vCode;
}
// width="60" height="30"
// base_padding_left="5"
// range_padding_left="10"
// base_padding_top="15"
// range_padding_top="10"
// codeLength="4"
// line_number="3"
// font_size="20"
//验证码固定参数,也就是将会用到的几个常量
private static final int DEFAULT_FONT_SIZE = 20;//字体大小
private static final int DEFAULT_LINE_NUMBER = 3;//默认的用于干扰视线直线的条数
private static final int BASE_PADDING_LEFT = 10, RANGE_PADDING_LEFT = 15, BASE_PADDING_TOP = 20, RANGE_PADDING_TOP = 10;
/**
* 上边4个整型数的解释:
* BASE_PADDING_LEFT,BASE_PADDING_TOP 表示每一个将要画出字符坐标计算的基准
* RANGE_PADDING_LEFT,RANGE_PADDING_TOP 表示字符坐标x,y的变化范围
*/
private static final int DEFAULT_WIDTH = 100, DEFAULT_HEIGHT = 30;
//设置位图宽高,具体的宽高取ImageView和BitMap之间较小的一个,
// 即就是宽= min{ImageView.Width,Bitmap.Width},高同理
//注意:当我们需要一个不同尺寸的验证码图片,不仅仅需要修改DEFAULT_WIDTH 和DEFAULT_HEIGHT,为了显示效果
//的最佳化,最好将上述的4个坐标值也调整一下,使得我们的验证码能最恰当地占据整个底板
//将一些常量应用到本类的成员变量上
//activity_settings decided by the layout xml
//canvas width and height
private int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
//random word space and pading_top
private int base_padding_left = BASE_PADDING_LEFT, range_padding_left = RANGE_PADDING_LEFT,
base_padding_top = BASE_PADDING_TOP, range_padding_top = RANGE_PADDING_TOP;
//number of chars, lines; font size
private int line_number = DEFAULT_LINE_NUMBER, font_size = DEFAULT_FONT_SIZE;
//variables
private String code;//存储随机生成的随机码序列
private int padding_left, padding_top;//左边框间距和上边框间距
private Random random = new Random();//随机数生成器
public Bitmap createBitmap() {//得到位图对象
padding_left = 0;//设置位图左内边距离
Bitmap bp = Bitmap.createBitmap(width, height, Config.ARGB_8888);//创建位图
/**
* 位图最后一个设置参数的简介
* A:透明度
* R:红色
* G:绿
* B:蓝
* Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位
* Bitmap.Config ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位
* Bitmap.Config RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
* Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。
* 一般情况下我们都是使用的ARGB_8888,由此可知它是最占内存的,因为一个像素占32位,8位=1字节,所以一个像素占4字节的内存。假设有一张480x800的图片,如果格式为ARGB_8888,那么将会占用1500KB的内存
*/
Canvas c = new Canvas(bp);//以创建好的空位图创建画布
code = createCode();//生成目标字符串
c.drawColor(Color.WHITE);
Paint paint = new Paint();//创建画笔
paint.setTextSize(font_size);//设置画笔的字体大小
for (int i = 0; i < code.length(); i++) {//画每一个字符
randomTextStyle(paint);//随机的画笔风格
randomPadding();//按照约定好的规则生成字符的坐标
c.drawText(code.charAt(i) + "", padding_left, padding_top, paint);//开始以随机的画笔和坐标画每一个字符
}
for (int i = 0; i < line_number; i++) {//画事先设置好数量的几条横线
drawLine(c, paint);
}
c.save(Canvas.ALL_SAVE_FLAG);//保存在画布上的所有操作
c.restore();
return bp;//返回画好的位图
}
private String createCode() {//随机生成随机码
StringBuilder buffer = new StringBuilder();
buffer.append(CHARS[random.nextInt(CHARS.length)]);//获取第一个运算数
buffer.append(OPERATORS[random.nextInt(OPERATORS.length)]);//获取运算符
buffer.append(CHARS[random.nextInt(CHARS.length)]);//获取第二个运算数
buffer.append("=");
return buffer.toString();
}
private void drawLine(Canvas canvas, Paint paint) {//自定义的任意方向画横线的方法
int color = randomColor();
int startX = random.nextInt(width);
int startY = random.nextInt(height);
int stopX = random.nextInt(width);
int stopY = random.nextInt(height);
paint.setStrokeWidth(1);//设置画笔粗细
paint.setColor(color);//颜色
canvas.drawLine(startX, startY, stopX, stopY, paint);
}
private int randomColor() {
return randomColor(1);
}//随机生成颜色
private int randomColor(int rate) {
int red = random.nextInt(256) / rate;
int green = random.nextInt(256) / rate;
int blue = random.nextInt(256) / rate;
return Color.rgb(red, green, blue);
}
private void randomTextStyle(Paint paint) {//随机的字体风格
int color = randomColor();//颜色
paint.setColor(color);
paint.setFakeBoldText(random.nextBoolean()); //粗细;true为粗体,false为非粗体
float skewX = random.nextInt(11) / 10;
skewX = random.nextBoolean() ? skewX : -skewX;
paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
// paint.setUnderlineText(true); //true为下划线,false为非下划线
// paint.setStrikeThruText(true); //true为删除线,false为非删除线
}
/**
* 随机定义每一个字符所绘画的坐标,注意:在这里padding_left是具有叠加效果的,
* 也就是说所画的字符越往后,坐标也就越大,而top永远就是base+range
*/
private void randomPadding() {
padding_left += base_padding_left + random.nextInt(range_padding_left);
padding_top = base_padding_top + random.nextInt(range_padding_top);
}
public boolean checkCode(String input) {//验证码校验
result= 0;
input= input.trim();
if(TextUtils.equals("", input))//空输入判为错
return false;
int arg1= char2Int(code.charAt(0));
String opt= code.substring(1, code.length() - 2);//java区间遵循左闭右开原则,所以length-2取到的是倒数第二个字符
int arg2= char2Int(code.charAt(code.length()-2));
Log.i("result",arg1+" "+arg2);
Log.i("opt",opt);
switch (opt){
case "加上":case "+":
{
result= arg1+arg2;
}break;
case "减去":case "-":
{
result= arg1-arg2;
}break;
case "乘以":case "×":
{
result= arg1*arg2;
}break;
case "除以":case "÷":
{
if (arg2==0)
result= 0;
else result= arg1/arg2;
}
}
if (Integer.parseInt(input)== result)
return true;
return false;
}
private int char2Int(char arg)//利用下标来转换字符
{
for (int i = 0; i < CHARS.length; i++) {
if (CHARS[i]==arg)
if (i>=10)
return i-10;
else return i;
}
return 0;//默认返回0
}
}