自定义Logo二维码绘制(追加上一篇简单二维码绘制)
简单绘制二维码地址:
Android 实现简单绘制二维码(包含带LOGO的二维码的绘制)
1.实现思路
2.实现(新增拍照以及相册上传logo以及分享和保存二维码)
参数说明:
//拍照
public static final int TAKE_PHOTO = 1;
//从相册选择图片
public static final int CHOOSE_PHOTO = 2;
//二维码宽度
public static final int QR_CODE_WIDTH = 500;
//logo的尺寸不能高于二维码的20%.大于可能会导致二维码失效
public static final int LOGO_WIDTH_MAX = QR_CODE_WIDTH / 5;
//logo的尺寸不能小于二维码的10%,否则不搭
public static final int LOGO_WIDTH_MIN = QR_CODE_WIDTH / 10;
//定义黑色
private static final int BLACK = 0xFF000000;
//定义白色
private static final int WHITE = 0xFFFFFFFF;
//生成的二维码
private Bitmap genBitMap;
//绘制的logo二维码
private Bitmap logoBitMap;
//图片地址
private Uri imageUri;
1)、拍照上传
private void takePhoto() {
// 创建File对象,用于存储拍照后的图片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT < 24) { //SDK版本小于24 使用Uri解析
imageUri = Uri.fromFile(outputImage);
} else {
imageUri = FileProvider.getUriForFile(LogoQRCode.this, "fatcats.top.qrcodedemo.fileprovider", outputImage);
}
// 启动相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
补充FileProvider:
在app开发过程中需要用到FileProvider的主要有
1.1、相机拍照以及图片裁剪
1.2、调用系统应用安装器安装apk(应用升级)
1.3、基本配置使用方法:在以前使用的是v4的包下的FileProvider,到现在可以使用androidx包下的FileProvider(androidx.core.content.FileProvider)
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
说明:
authorities:标识,在当前系统内必须是唯一值,一般用包名。
exported:表示该 FileProvider 是否需要公开出去。
granUriPermissions:是否允许授权文件的临时访问权限。(这里是给出了权限)
1.4.xml文件配置:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--path设为空值表示将整个sd卡共享-->
<external-path
name="external_storage"
path="" />
</paths>
补充说明:xml中标签的配置可以参考FileProvider源码中的标签说明
public class FileProvider extends ContentProvider {
private static final String[] COLUMNS = {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE };
private static final String
META_DATA_FILE_PROVIDER_PATHS = "android.support.FILE_PROVIDER_PATHS";
private static final String TAG_ROOT_PATH = "root-path";
private static final String TAG_FILES_PATH = "files-path";
private static final String TAG_CACHE_PATH = "cache-path";
private static final String TAG_EXTERNAL = "external-path";
private static final String TAG_EXTERNAL_FILES = "external-files-path";
private static final String TAG_EXTERNAL_CACHE = "external-cache-path";
private static final String TAG_EXTERNAL_MEDIA = "external-media-path";
...
2)、从相册选择
private void choosePhotoFromAlbum() {
if (ContextCompat.checkSelfPermission(LogoQRCode.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(LogoQRCode.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
openAlbum();
}
}
2.1、打开相册
private void openAlbum() {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO);
}
2.2、返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
logoBitMap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
// 将拍摄的照片显示出来
logoImg.setImageBitmap(logoBitMap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case CHOOSE_PHOTO:
if (resultCode == RESULT_OK) {
// 判断手机系统版本号
if (Build.VERSION.SDK_INT >= 19) {
// 4.4及以上系统使用这个方法处理图片
handleImageOnKitKat(data);
} else {
// 4.4以下系统使用这个方法处理图片
handleImageBeforeKitKat(data);
}
}
break;
default:
break;
}
}
2.3、sdk4.4以上处理图片方法
@SuppressLint("NewApi")
private void handleImageOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
Log.d("TAG", "handleImageOnKitKat: uri is " + uri);
if (DocumentsContract.isDocumentUri(this, uri)) {
// 如果是document类型的Uri,则通过document id处理
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1]; // 解析出数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// 如果是content类型的Uri,则使用普通方式处理
imagePath = getImagePath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
// 如果是file类型的Uri,直接获取图片路径即可
imagePath = uri.getPath();
}
displayImage(imagePath); // 根据图片路径显示图片
}
2.4 SDK4.4以下处理图片方式
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
2.5 展示图片
private void displayImage(String imagePath) {
if (imagePath != null) {
Toast.makeText(this, "成功", Toast.LENGTH_SHORT).show();
logoBitMap = BitmapFactory.decodeFile(imagePath);
// 显示图片
Bitmap bitmap = createBitmap(((BitmapDrawable) getDrawable(R.drawable.bg)).getBitmap(), logoBitMap);
logoImg.setImageBitmap(bitmap);
} else {
Toast.makeText(this, "获取图片失败", Toast.LENGTH_SHORT).show();
}
}
补充:createBitmap(Bitmap bgBitmap , Bitmap logoBitmap)方法在上文中有提到,小编在不在此再多叙述啦
3)、储存图片
3.1 储存图片处理
private void saveImg(Bitmap bitmap){
String fileName = "qr_"+System.currentTimeMillis() + ".jpg"; //图片保存名称格式
boolean isSaveSuccess = ImgStoreUtils.saveImageToGallery(LogoQRCode.this, bitmap,fileName);
if (isSaveSuccess) {
Toast.makeText(LogoQRCode.this, "图片已保存至本地", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(LogoQRCode.this, "保存图片失败,请稍后重试", Toast.LENGTH_SHORT).show();
}
}
图片保存工具:ImgStoreUtils
public static boolean saveImageToGallery(Context context, Bitmap qrBitmap, String fileName) {
// 保存图片至指定路径
String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "qrcode";
File appDir = new File(storePath);
if (!appDir.exists()) {
appDir.mkdir();
}
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
//通过io流的方式来压缩保存图片(80代表压缩20%)
boolean isSuccess = qrBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
fos.flush();
fos.close();
Uri uri = Uri.fromFile(file);
//发送广播通知系统图库刷新数据
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
if (isSuccess) {
return true;
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
4)、分享图片
private void shareImg(Bitmap bitmap){
Uri uri = Uri.parse(MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, null,null));
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("image/*");//设置分享内容的类型
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent = Intent.createChooser(intent, "分享");
startActivity(intent);
}
5.效果图: