Android 使用ZXing生成带logo的二维码

2020-09-25 11:25:40 浏览数 (3)

Android 使用ZXing生成带logo的二维码

有一段时间没有写博客了,都快忘记怎么写了,最近在赶公司的项目,接近尾声了,写点有意思的东西,好了,进入正题。。。

老规矩,从头开始啊,新建一个名为QGCodeDemo的项目

运行效果如下:

然后这里我们会使用一个框架,二维码框架ZXing 划重点,首先我们在app下的build.gradle下添加依赖

代码语言:javascript复制
//二维码
    api 'com.journeyapps:zxing-android-embedded:3.6.0'

添加之后记得 Sync Now 一下,这个通常出现在AS的右上角,现在框架已经添加进来了,然后就是简单的一个布局,一个按钮,一个居中显示图片

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lanjing.qgcodedemo.MainActivity">

    <ImageView
        android:id="@ id/code"
        android:layout_centerInParent="true"
        android:layout_width="300dp"
        android:layout_height="300dp" />

    <Button
        android:id="@ id/showBtn"
        android:text="SHOW CODE"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

可以看到布局非常简单,然后在MainActivity中进行初始化控件。

代码语言:javascript复制
package com.lanjing.qgcodedemo;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private ImageView codeImageView;
    private Button showBtn;

    //创建两个Bitmap,一个放二维码,一个放logo
    Bitmap codeBmp, logoBmp;
    private String url;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        showBtn.setOnClickListener(this);
        //给图片添加长按点击事件
        codeImageView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                /*
                * 给button添加长按事件,触发时调用openCode()方法打开二维码,如果是文本则显示文本,是可访问地址,则会弹出提示问你是否继续访问
                * */
                openCode();
                return true;
            }
        });
    }

    //初始化控件
    private void initView() {
        codeImageView = (ImageView) findViewById(R.id.code);
        showBtn = (Button) findViewById(R.id.showBtn);
    }


    @Override
    public void onClick(View v) {

        /*
        * 按钮点击显示二维码
        * */
        //加一个测试地址,之后我们的二维码就是用这个地址来生成。扫描后直接进入百度,这个地址也可以用于动态,或者是你从服务器中得到的地址
        url = "https://www.baidu.com";
        //这里的logo是系统自带的,通过BitmapFactory加载进来
        logoBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.demo);
        //通过ZXing框架将地址和logo图片加到里面,生成二维码之后赋值给codeBmp;
        codeBmp = ZXingUtilsTest.createQRImage(this, url, logoBmp);
        //最后将得到的codeBmp设置为ImageView的ImageBitmap这样图片就会显示出来了
        codeImageView.setImageBitmap(codeBmp);
    }
    

    private void openCode() {//这个方法其实和我们之前的页面跳转比较像  intent携带信息访问权限,这时活动产生一个新的任务,然后开始执行这个任务
        Intent intent = new Intent(Intent.ACTION_VIEW,
                (Uri.parse(url))
        ).addCategory(Intent.CATEGORY_BROWSABLE)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

}

应该是一目了然吧,接下来就需要用到ZXing框架的东西了,首先这是一个比较早的框架了,很多人进行了多次重写与封装,里面内容会很多,但不一定适用于现在的你,所以也重写一下这个。

代码语言:javascript复制
package com.lanjing.qgcodedemo;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2019/4/3 0001.
 */

public class ZXingUtilsTest {
    /**
     * 生成二维码Bitmap
     *
     * @param context   文本内容
     * @param logoBm    二维码中心的Logo图标(可以为null)
     * @return 合成后的bitmap
     */
    public static Bitmap createQRImage(Context context, String data, Bitmap logoBm) {

        try {

            if (data == null || "".equals(data)) {
                return null;
            }

            int widthPix = ((Activity) context).getWindowManager().getDefaultDisplay()
                    .getWidth();
            widthPix = widthPix / 5 * 3;
            int heightPix = widthPix;

            //配置参数
            Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            //容错级别
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            //设置空白边距的宽度
            hints.put(EncodeHintType.MARGIN, 3); //default is 4


            // 图像数据转换,使用了矩阵转换
            BitMatrix bitMatrix = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, widthPix, heightPix, hints);
            int[] pixels = new int[widthPix * heightPix];
            // 下面这里按照二维码的算法,逐个生成二维码的图片,
            // 两个for循环是图片横列扫描的结果
            for (int y = 0; y < heightPix; y  ) {
                for (int x = 0; x < widthPix; x  ) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * widthPix   x] = 0xff000000;
                    } else {
                        pixels[y * widthPix   x] = 0xffffffff;
                    }
                }
            }

            // 生成二维码图片的格式,使用ARGB_8888
            Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);

            if (logoBm != null) {
                bitmap = addLogo(bitmap, logoBm);
            }

            return bitmap;
            //必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
            //return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 在二维码中间添加Logo图案
     */
    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;
    }
}

这个就是一个重写的工具类,可以复制过去直接用。里面也有相关的注释,我就不做过多解释了

GitHub地址

1 人点赞