Código QR personalizado de Android

Android usa zxing para generar códigos QR.

1. Agregue dependencias o elija la versión de zxing usted mismo: Versiones zxing/zxing GitHub

dependencies {
    ...
    implementation 'com.google.zxing:core:3.5.0'
}

2. Genere un código QR común:

  • Generar código QR
  /**
     * 创建二维码位图 (支持自定义配置和自定义样式)
     *
     * @param content          字符串内容
     * @param width            位图宽度,要求>=0(单位:px)
     * @param height           位图高度,要求>=0(单位:px)
     * @param character_set    字符集/字符转码格式 (支持格式:{@link CharacterSetECI })。传null时,zxing源码默认使用 "ISO-8859-1"
     * @param error_correction 容错级别 (支持级别:{@link ErrorCorrectionLevel })。传null时,zxing源码默认使用 "L"
     * @param margin           空白边距 (可修改,要求:整型且>=0), 传null时,zxing源码默认使用"4"。
     * @param color_black      黑色色块的自定义颜色值
     * @param color_white      白色色块的自定义颜色值
     * @return
     */
    @Nullable
    public static Bitmap createQRCodeBitmap(String content, int width, int height,
                                            @Nullable String character_set, @Nullable String error_correction, @Nullable String margin,
                                            @ColorInt int color_black, @ColorInt int color_white) {

        /** 1.参数合法性判断 */
        if (TextUtils.isEmpty(content)) { // 字符串内容判空
            return null;
        }

        if (width < 0 || height < 0) { // 宽和高都需要>=0
            return null;
        }

        try {
            /** 2.设置二维码相关配置,生成BitMatrix(位矩阵)对象 */
            Hashtable<EncodeHintType, String> hints = new Hashtable<>();

            if (!TextUtils.isEmpty(character_set)) {
                hints.put(EncodeHintType.CHARACTER_SET, character_set); // 字符转码格式设置
            }

            if (!TextUtils.isEmpty(error_correction)) {
                hints.put(EncodeHintType.ERROR_CORRECTION, error_correction); // 容错级别设置
            }

            if (!TextUtils.isEmpty(margin)) {
                hints.put(EncodeHintType.MARGIN, margin); // 空白边距设置
            }
//            hints.put(EncodeHintType.QR_VERSION,"4");
            BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);

            /** 3.创建像素数组,并根据BitMatrix(位矩阵)对象为数组元素赋颜色值 */
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * width + x] = color_black; // 黑色色块像素设置
                    } else {
                        pixels[y * width + x] = color_white; // 白色色块像素设置
                    }
                }
            }

            /** 4.创建Bitmap对象,根据像素数组设置Bitmap每个像素点的颜色值,之后返回Bitmap对象 */
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
            return bitmap;
        } catch (WriterException e) {
            e.printStackTrace();
        }

        return null;

    }
  • Agregar logotipo de código QR
   /**
     * 在二维码中间添加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;
        }
        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.restore();
        } catch (Exception e) {
            bitmap = null;
            e.getStackTrace();
        }
        return bitmap;
    }

Sin embargo, durante el uso, a veces necesitamos usar códigos QR circulares o tamaños de puntos de código personalizados.

3. Genera un código QR personalizado

El código bidimensional se divide principalmente en dos partes: el punto de anclaje y el área de contenido; la complejidad del código bidimensional está relacionada con la versión del código bidimensional. Al generar el código bidimensional, si el parámetro EncodeHintType .QR_VERSION no está configurado, zxing se basa en el tamaño de los datos La versión se selecciona automáticamente, cuanto más grandes son los datos, más alta es la versión y más píxeles, el punto de anclaje es un cuadrado de 7x7;

El código QR de la forma personalizada se genera aquí y la biblioteca zxing todavía se usa para obtener los datos de puntos.

 Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);

        QRCode qrCode = Encoder.encode(content, ErrorCorrectionLevel.H, hints);

        ByteMatrix matrix = qrCode.getMatrix();//获取点位数据
        int originalWidth = matrix.getWidth();//获取宽度
        int originalHeight = matrix.getHeight();//获取高度

   

Después de obtener el objeto de matriz, obtenga el tamaño de cada punto de acuerdo con el tamaño y el margen de la imagen requerida, y luego use el objeto de matriz para asignar valores a los elementos de matriz y generar la forma de patrón deseada correspondiente, y dibujarlo.

El código completo es el siguiente:

  • Generar un código QR personalizado
  /**
     * 自定义二维码
     *
     * @param content:二维码内容
     * @param psRandom:生成圆形码点时参与随机半径大小生成
     * @param sizes:二维码尺寸大小
     * @param colors:二维码颜色,第一位为点位颜色,第二位为背景颜色
     * @param padding:边距
     * @param anchortype:定位点类型:0:方形矩形;1:圆点矩形;2:圆形;3.4.5.6:多边形矩形
     * @param contenttype:码点类型:0:方形码点;1:圆形码点;其他为多边形码点
     * @param ratio:定位点的大小比例
     * @param contentratiod:码点的缩放比例
     * @return
     */
    public static Bitmap CreateQRCode(String content, float psRandom, int[] sizes, int[] colors, int padding, int anchortype, int contenttype, float ratio, float contentratiod) throws Exception {
        int outputWidth = sizes[0], outputHeight = sizes[1];
        int qrColor = colors[0], bgColor = colors[1];

        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);
        QRCode qrCode = Encoder.encode(content, ErrorCorrectionLevel.H, hints);

        ByteMatrix matrix = qrCode.getMatrix();
        int originalWidth = matrix.getWidth();//矩阵的列数
        int originalHeight = matrix.getHeight();//矩阵的行数

        outputWidth = Math.max(originalWidth, outputWidth);
        outputHeight = Math.max(originalHeight, outputHeight);

        int originalPadding = Math.min(outputWidth / (originalWidth + 2), outputHeight / (originalHeight + 2));
        padding = Math.max(padding, originalPadding);

        int cellWidth = Math.min((outputWidth - padding * 2) / originalWidth, (outputHeight - padding * 2) / originalHeight);//每一个点位的宽高

        int outputLeft = (outputWidth - cellWidth * originalWidth) / 2;
        int outputTop = (outputHeight - cellWidth * originalHeight) / 2;

        float cellMid = (float) (cellWidth * 1.0 / 2);


        double randomRange = 0.25 * psRandom;

        Paint paint = new Paint();
        paint.setColor(qrColor);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);

        Bitmap bitmap = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888);
        bitmap.eraseColor(bgColor);
        Canvas canvas = new Canvas(bitmap);
        BitMatrix ignoreMatrix = new BitMatrix(originalWidth, originalHeight);
        if (anchortype == 2) {
            drawCircle2( outputWidth, outputHeight, originalWidth, originalHeight, (float) (cellWidth * 1.0 / 2), paint, canvas, qrColor, ignoreMatrix, ratio);
        }



        int cellFour = cellWidth / 4;


        //圆点可调整
        for (int y = 0; y < originalHeight; y++) {
            for (int x = 0; x < originalWidth; x++) {
                float outputY;
                float outputX;
                if (matrix.get(x, y) == 1) {
                    float r;
                    if ((x < 7 && y < 7) || (x >= originalWidth - 7 && y < 7) || (x < 7 && y >= originalHeight - 7)) {//定位点数据
                        drawAnchor2(anchortype, outputTop, outputLeft, cellWidth, paint, canvas, x, y, contentratiod);
                    } else {
                        if (contenttype == 1) {//圆形点位
                            outputY = outputTop + y * cellWidth + cellMid;//画圆点因为是要确定圆心的位置,而不是圆的左边界,所以要多加半径cellMid,来确认圆心
                            outputX = outputLeft + x * cellWidth + cellMid;
                            if (randomRange == 0) {
                                r = cellMid * contentratiod;
                            } else {
                                r = (int) ((1 + (Math.random() - 0.5) * randomRange * 2) * cellMid) * contentratiod;//生成的圆点会有随机的大小之分
                            }
                            canvas.drawCircle(outputX, outputY, r, paint);
                        } else if (contenttype == 0) {//方形点位
                            outputY = outputTop + y * cellWidth + (1.0f - contentratiod) * cellWidth / 2;
                            outputX = outputLeft + x * cellWidth + (1.0f - contentratiod) * cellWidth / 2;
                            canvas.drawRect(outputX, outputY, outputX + cellWidth * contentratiod, outputY + cellWidth * contentratiod, paint);
                        } else {//多边形
                            outputY = outputTop + y * cellWidth + (1.0f - contentratiod) * cellWidth / 2;
                            outputX = outputLeft + x * cellWidth + (1.0f - contentratiod) * cellWidth / 2;
                            double pr = 2 * Math.PI / contenttype;
                            double pr90 = Math.PI / 2;
                            Path path = new Path();
                            double r1;
                            double r2 = pr / 2 - pr90;
                            path.moveTo(outputX + cellMid, outputY);
                            path.lineTo((int) (outputX + cellMid + Math.cos(r2) * cellFour), (int) (outputY + cellMid + Math.sin(r2) * cellFour));
                            for (int indexL = 1; indexL < contenttype; indexL++) {
                                r1 = indexL * pr - pr90;
                                path.lineTo((int) (outputX + cellMid + Math.cos(r1) * cellMid* contentratiod), (int) (outputY + cellMid + Math.sin(r1) * cellMid* contentratiod));
                                r2 = indexL * pr + pr / 2 - pr90;
                                path.lineTo((int) (outputX + cellMid + Math.cos(r2) * cellFour), (int) (outputY + cellMid + Math.sin(r2) * cellFour));
                            }
                            path.close();
                            canvas.drawPath(path, paint);
                        }

                    }
                }
            }
        }

        return bitmap;
    }
  • Dibujo de punto de anclaje circular de código QR
 /*绘制圆形定位点
     * cellMid:一个格子的一半大小
     * */
    private static void drawCircle2( int outputWidth, int outputHeight, int originalWidth, int originalHeight, float cellMid, Paint paint, Canvas canvas, int qrColor, BitMatrix ignoreMatrix, float ratio) {
        float rightWidth = cellMid * 2 * originalWidth;
        float rightHeight = cellMid * 2 * originalHeight;
        float outputLeft = (outputWidth - rightWidth) / 2;
        float outputTop = (outputHeight - rightHeight) / 2;
        float outputRight = outputLeft + rightWidth;
        float outputBottom = outputTop + rightHeight;
        float circleP = 7 * cellMid;//半径,cellMid用的是一个点位的一半大小,定位点占据了7x7的点位,
        float circleSmR = (float) (3 * cellMid * ratio);
        Paint bigCirclePaint = new Paint();
        bigCirclePaint.setColor(qrColor);
        bigCirclePaint.setStyle(Paint.Style.STROKE);
        bigCirclePaint.setAntiAlias(true);


        bigCirclePaint.setStrokeWidth((float) (cellMid * 2 * ratio));
        canvas.drawCircle(outputLeft + circleP, outputTop + circleP, circleSmR, paint);
        canvas.drawCircle(outputRight - circleP, outputTop + circleP, circleSmR, paint);
        canvas.drawCircle(outputLeft + circleP, outputBottom - circleP, circleSmR, paint);
        float circleR = 6 * cellMid;
        canvas.drawCircle(outputLeft + circleP, outputTop + circleP, circleR, bigCirclePaint);
        canvas.drawCircle(outputRight - circleP, outputTop + circleP, circleR, bigCirclePaint);
        canvas.drawCircle(outputLeft + circleP, outputBottom - circleP, circleR, bigCirclePaint);

        ignoreMatrix.setRegion(0, 0, 7, 7);
        ignoreMatrix.setRegion(originalWidth - 7, 0, 7, 7);
        ignoreMatrix.setRegion(0, originalHeight - 7, 7, 7);

    }
  • Dibujo de punto de anclaje cuadrado de código QR
   /*绘制非圆形定位点*/
    private static void drawAnchor2(int anchortype, float outputTop, float outputLeft, int cellWidth, Paint paint, Canvas canvas, int x, int y, float remark3) {
        float outputY = 0;
        float outputX = 0;
        switch (anchortype) {
            case 0://普通矩形
                outputY = outputTop + y * cellWidth + (1.0f - remark3) * cellWidth / 2;
                outputX = outputLeft + x * cellWidth + (1.0f - remark3) * cellWidth / 2;
                canvas.drawRect(outputX, outputY, outputX + cellWidth * remark3, outputY + cellWidth * remark3, paint);
                break;
            case 1://圆形矩形
                outputY = outputTop + y * cellWidth + (float) (cellWidth * 1.0 / 2);
                outputX = outputLeft + x * cellWidth + (float) (cellWidth * 1.0 / 2);
                canvas.drawCircle(outputX, outputY, (float) (cellWidth * remark3 * 1.0 / 2), paint);
                break;
            case 3:
            case 4:
            case 5:
            case 6:
                outputY = outputTop + y * cellWidth;
                outputX = outputLeft + x * cellWidth;
                double pr = 2 * Math.PI / anchortype;
                double pr90 = Math.PI / 2;
                Path path = new Path();
                double r1;
                double r2 = pr / 2 - pr90;
                int cellMid = cellWidth / 2;
                int cellFour = cellWidth / 4;
                path.moveTo(outputX + cellMid, outputY);
                path.lineTo((int) (outputX + cellMid + Math.cos(r2) * cellFour), (int) (outputY + cellMid + Math.sin(r2) * cellFour));
                for (int indexL = 1; indexL < anchortype; indexL++) {
                    r1 = indexL * pr - pr90;
                    path.lineTo((int) (outputX + cellMid + Math.cos(r1) * cellMid), (int) (outputY + cellMid + Math.sin(r1) * cellMid));
                    r2 = indexL * pr + pr / 2 - pr90;
                    path.lineTo((int) (outputX + cellMid + Math.cos(r2) * cellFour), (int) (outputY + cellMid + Math.sin(r2) * cellFour));
                }
                path.close();
                canvas.drawPath(path, paint);
                break;
        }
    }
  •  llamada de método
int[] sizes = new int[]{600, 600};
int[] colors = {Color.BLACK, Color.WHITE};

Bitmap bitmap1 = CreateQRCode("你好123456", 1.0f, sizes, colors,
                    0, 0, 0, 1.0f, 1.0f);
  •  gráficos de tamaño normal

 

  •  Después de reducir el punto de anclaje y el punto de código

        

Nota: Aquí se utilizan principalmente cuadrados, puntos y polígonos, y también se pueden reemplazar con puntos de código como expresiones. Los cambios de tamaño de los puntos aquí se basan en el mismo punto central. Si necesita mostrar el punto de código como la mitad del tamaño normal, por ejemplo, solo Para mostrar la parte izquierda o superior, también puede dibujar el estilo deseado en el método de bucle de la matriz, pero en este caso, debe molestar al jefe de la empresa para volver a compilar el análisis biblioteca.

Supongo que te gusta

Origin blog.csdn.net/QhappyfishQ/article/details/126365364
Recomendado
Clasificación