Android中 自定义logo二维码绘制(仿微信QQ二维码)

自定义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.效果图:

在这里插入图片描述
项目地址放在GitHub上啦

猜你喜欢

转载自blog.csdn.net/weixin_43409994/article/details/110939854