先看图说话:
1.二维码生成:
public void generateQRcode() throws FileNotFoundException {
String mLink = text.getText().toString();
if (mLink.length()==0)
{
mLink=text.getHint().toString();
}
Log.v("MainActivity","mLink:" + mLink);
//generateCode(mLink);
//生成图片二维码
boolean success = false;
success = createQRImage(mLink, qrImgImageView);
if (success) {
isQrImgShow = true;
Toast.makeText(getBaseContext(), "二维码成功生成,请长按识别", Toast.LENGTH_SHORT).show();
}
//设置图片长按识别
readImagePicture(qrImgImageView);
}
/*
* 生成二维码
*/
//要转换的地址或字符串,可以是中文
public boolean createQRImage(String url, final ImageView qrImgImageView) throws FileNotFoundException {
int QR_WIDTH = 300;
int QR_HEIGHT = 300;
try {
//判断URL合法性
if (url == null || "".equals(url) || url.length() < 1) {
return false;
}
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);
int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
//下面这里按照二维码的算法,逐个生成二维码的图片,
//两个for循环是图片横列扫描的结果
for (int y = 0; y < QR_HEIGHT; y++) {
for (int x = 0; x < QR_WIDTH; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * QR_WIDTH + x] = 0xff000000;
} else {
pixels[y * QR_WIDTH + x] = 0xffffffff;
}
}
}
//生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
if (checkBox.isChecked()) {
//获取要设置的logo的bitmap
ImageView imageView_logo = new ImageView(this);
imageView_logo.setImageResource(R.drawable.ic_launcher);
Bitmap obmp = ((BitmapDrawable) (imageView_logo).getDrawable()).getBitmap();
int width = obmp.getWidth();
int height = obmp.getHeight();
int[] data = new int[width * height];
obmp.getPixels(data, 0, width, 0, 0, width, height);
if (obmp != null) {
bitmap = addLogo(bitmap, obmp);
}
}
boolean b_need_save_first = false;
if (!b_need_save_first) {
qrImgImageView.setImageBitmap(bitmap);
} else {
if (bitmap != null) {
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
final String filePath = getFileRoot(getBaseContext()) + File.separator
+ "qr_" + System.currentTimeMillis() + ".jpg";
final boolean success = bitmap.compress(Bitmap.CompressFormat.JPEG, 30, new FileOutputStream(filePath));
//二维码图片较大时,生成图片、保存文件的时间可能较长,因此放在新线程中
new Thread(new Runnable() {
@Override
public void run() {
if (success) {
//显示到一个ImageView上面
runOnUiThread(new Runnable() {
@Override
public void run() {
qrImgImageView.setImageBitmap(BitmapFactory.decodeFile(filePath));
}
});
}
}
}).start();
}
}
return true;
} catch (WriterException e) {
e.printStackTrace();
}
return false;
}
//文件存储根目录
private String getFileRoot(Context context) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File external = context.getExternalFilesDir(null);
if (external != null) {
return external.getAbsolutePath();
}
}
return context.getFilesDir().getAbsolutePath();
}
2.生成的二维码中间添加logo
(这个添加了logo的二维码只有超链接可以识别)
/**
* 在二维码中间添加Logo图案
*/
@SuppressWarnings("deprecation")
private static Bitmap addLogo(Bitmap src, Bitmap logo) {
if (src == null) {
return null;
}
if (logo == null) {
return src;
}
//获取图片的宽高
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int logoWidth = logo.getWidth();
int logoHeight = logo.getHeight();
if (srcWidth == 0 || srcHeight == 0) {
return null;
}
if (logoWidth == 0 || logoHeight == 0) {
return src;
}
//logo大小为二维码整体大小的1/5
float scaleFactor = srcWidth * 1.0f / 5 / logoWidth;
Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
try {
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(src, 0, 0, null);
canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2);
canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
} catch (Exception e) {
bitmap = null;
e.getStackTrace();
}
return bitmap;
}
3.是否添加logo通过一个checkbox 来获取状态,并在生成的过程中判断这个checkbox状态
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == checkBox) { //自动登陆选框发生改变时
if (isChecked) {
checkBox.setChecked(true);
}
}
}
if (checkBox.isChecked()) {
//获取要设置的logo的bitmap
ImageView imageView_logo = new ImageView(this);
imageView_logo.setImageResource(R.drawable.ic_launcher);
Bitmap obmp = ((BitmapDrawable) (imageView_logo).getDrawable()).getBitmap();
int width = obmp.getWidth();
int height = obmp.getHeight();
int[] data = new int[width * height];
obmp.getPixels(data, 0, width, 0, 0, width, height);
if (obmp != null) {
bitmap = addLogo(bitmap, obmp);
}
}
4.长按二维码图片选择识别或者保存到手机相册:
/*
* 长按图片解析二维码
*/
private void readImagePicture(final ImageView imageView) {
// TODO Auto-generated method stub
//长按,通过zxing读取图片,判断是否有二维码
imageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View viewm) {
Bitmap obmp = ((BitmapDrawable) (imageView).getDrawable()).getBitmap();
recogQRcode(obmp);
return false;
}
});
}
//识别二维码的函数
public void recogQRcode(Bitmap obmp){
int width = obmp.getWidth();
int height = obmp.getHeight();
int[] data = new int[width * height];
obmp.getPixels(data, 0, width, 0, 0, width, height);
RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
Result re = null;
try {
re = reader.decode(bitmap1);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
if (re == null) {
showAlert(obmp);
} else {
showSelectAlert(obmp, re);
}
}
private void showAlert(final Bitmap bitmap) {
Toast.makeText(MainActivity.this,"添加了logo,无法识别",Toast.LENGTH_SHORT).show();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("保存图片")
.setCancelable(false);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterfacem, int i) {
saveImageToGallery(bitmap);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterfacem, int i) {
}
});
builder.show();
}
protected void saveImageToGallery(Bitmap bitmap) {
// 首先保存图片
String path = Environment.getExternalStorageDirectory()+"/QRcodeImage/";
File fileDir;
/**
* 文件目录如果不存在,则创建
*/
fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
String bitName = System.currentTimeMillis()+".JPG";
String filePath =Environment.getExternalStorageDirectory().getPath()+"/DCIM/Camera/"+ bitName;
Log.e(Debug.filename(new Exception()), Debug.funAndLine(new Exception())+filePath);
File file=new File(filePath);
if(file.exists()){
file.delete();
}
FileOutputStream out;
try{
out = new FileOutputStream(file);
// 格式为 JPEG,照相机拍出的图片为JPEG格式的,PNG格式的不能显示在相册中
if(bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out))
{
out.flush();
out.close();
// 插入图库
MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), bitName, null);
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
// 发送广播,通知刷新图库的显示
this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + filePath)));
Toast.makeText(getBaseContext(), "图片保存成功", Toast.LENGTH_SHORT).show();
System.out.println("图片保存成功");
}
private void showSelectAlert(final Bitmap bitmap,final Result re) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("请选择");
String str[] = {"保存图片", "识别二维码"};
builder.setItems(str, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterfacem, int i) {
switch (i) {
case 0: {
saveImageToGallery(bitmap);
}
break;
case 1: {
//Toast出内容
Toast.makeText(MainActivity.this,re.getText(),Toast.LENGTH_SHORT).show();
scanResult.setText("识别结果:"+re);
//利用正则表达式判断内容是否是URL,是的话则打开网页
String regex = "(((https|http)?://)?([a-z0-9]+[.])|(www.))"
+ "\\w+[.|\\/]([a-z0-9]{0,})?[[.]([a-z0-9]{0,})]+((/[\\S&&[^,;\u4E00-\u9FA5]]+)+)?([.][a-z0-9]{0,}+|/?)";//设置正则表达式
Pattern pat = Pattern.compile(regex.trim());//比对
Matcher mat = pat.matcher(re.getText().trim());
if (mat.matches()){
Uri uri = Uri.parse(re.getText());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);//打开浏览器
startActivity(intent);
}
}
break;
}
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterfacem, int i) {
}
});
builder.show();
}
生成的效果图:
5.扫描二维码:
这部分采用了第三方的识别库:https://blog.csdn.net/ky1996/article/details/79502358
我是添加到了自己的工程中。上面说的方法很好,这里就不贴了,只说下要注意的地方:
1) 在manifest 添加权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--获取sd卡写的权限,用于文件上传和下载-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许读取手机状态 用于创建BmobInstallation-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
2) 在main Activity中获取权限:
/**
* 动态获取权限,Android 6.0 新特性,一些保护权限,除了要在AndroidManifest中声明权限,还要使用如下代码动态获取
*/
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 101;
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,
Manifest.permission.VIBRATE
};
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
return;
}
}
}
下面是效果图:
从相册获取的gif图
下面是整个demo的下载链接https://download.csdn.net/download/linzihahaha/10777476