全网最好看的自定义渐变二维码

老规矩,先上效果图:

全网最好看的自定义渐变二维码

说到二维码,对于开发人员来说那这张图片就在熟悉不过了

全网最好看的自定义渐变二维码

什么?不熟悉?那好吧,我来讲一下吧…(了解二维码原理的大佬请略过…)

基础知识

首先,我们先说一下二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21的矩阵,Version 2是 25 x 25的矩阵,Version 3是29的尺寸,每增加一个version,就会增加4的尺寸,公式是:(V-1)*4 + 21(V是版本号) 最高Version 40,(40-1)*4+21 = 177,所以最高是177 x 177 的正方形。

那么,二维码上面那些图案又代表什么呢?

请接着看~(标黄的地方大家自己对应上图看)

定位图案

  • Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。
  • Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。
    Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。

功能性数据

  • Format Information存在于所有的尺寸中,用于存放一些格式化数据的。
  • Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。

数据码和纠错码

除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。

关于数据编码我这里就不讲了,一个字,麻烦,我们还是来说说怎么写出好看的二维码吧~结果请看下回分晓…哈哈,言归正传,代码还有30秒到达战场!

画二维码图

Position Detection Pattern
首先,先把Position Detection图案画在三个角上。(无论Version如何,这个图案的尺寸就是这么大
全网最好看的自定义渐变二维码
Alignment Pattern
然后,再把Alignment图案画上(无论Version如何,这个图案的尺寸就是这么大
全网最好看的自定义渐变二维码
Timing Pattern
接下来是Timing Pattern的线(这个不用多说了)
全网最好看的自定义渐变二维码

Format Information
再接下来是Formation Information,下图中的蓝色部分。
全网最好看的自定义渐变二维码
Format Information是一个15个bits的信息,每一个bit的位置如下图所示:(注意图中的Dark Module,那是永远出现的)
全网最好看的自定义渐变二维码
最后就是错误码和掩码了,这个比较简单,就不说了。

好了,说了这么多,那么show your code,不对,是my code…

public class QRCodeUtil {
    private static final byte BYTE_EPT = 0;
    private static final byte BYTE_DTA = 1;
    private static final byte BYTE_POS = 2;
    private static final byte BYTE_AGN = 3;
    private static final byte BYTE_TMG = 4;
    private static final byte BYTE_PTC = 5;
    private static final float DEFAULT_DTA_DOT_SCALE = 0.3F;
    private static final float DEFAULT_LOGO_SCALE = 0.2F;
    private static final int DEFAULT_SIZE = 800;
    private static final int DEFAULT_MARGIN = 20;
    private static final int DEFAULT_LOGO_MARGIN = 10;
    private static final int DEFAULT_LOGO_RADIUS = 8;
    private static final int DEFAULT_BINARIZING_THRESHOLD = 128;
    private float mAgnX;
    private float mAgnY;
    private float mPosX;
    private float mPosY;

    private Bitmap create(String contents, int size, int margin, float dataDotScale, int colorDark, int colorLight, int startColor, int endColor, Bitmap backgroundImage, boolean whiteMargin, boolean autoColor, boolean binarize, int binarizeThreshold, boolean roundedDataDots, Bitmap logoImage, int logoMargin, int logoCornerRadius, float logoScale) throws IllegalArgumentException {
        if (contents == null) {
            throw (new IllegalArgumentException("Error: contents is empty. (contents.isEmpty())"));
        } else {
            CharSequence var17 = (CharSequence) contents;
            if (var17.length() == 0) {
                throw (new IllegalArgumentException("Error: contents is empty. (contents.isEmpty())"));
            } else if (size < 0) {
                throw (new IllegalArgumentException("Error: a negative size is given. (size < 0)"));
            } else if (margin < 0) {
                throw (new IllegalArgumentException("Error: a negative margin is given. (margin < 0)"));
            } else if (size - 2 * margin <= 0) {
                throw (new IllegalArgumentException("Error: there is no space left for the QRCode. (size - 2 * margin <= 0)"));
            } else {
                ByteMatrix byteMatrix = this.getBitMatrix(contents);
                int var10000 = size - 2 * margin;
                if (var10000 < byteMatrix.getWidth()) {
                    throw (new IllegalArgumentException("Error: there is no space left for the QRCode. (size - 2 * margin < " + byteMatrix.getWidth() + ")"));
                } else if (dataDotScale >= (float) 0 && dataDotScale <= (float) 1) {
                    return this.render(byteMatrix, size - 2 * margin, margin, dataDotScale, colorDark, colorLight, startColor, endColor, backgroundImage, whiteMargin, autoColor, binarize, binarizeThreshold, roundedDataDots, logoImage, logoMargin, logoCornerRadius, logoScale);
                } else {
                    throw (new IllegalArgumentException("Error: an illegal data dot scale is given. (dataDotScale < 0 || dataDotScale > 1)"));
                }
            }
        }
    }

    private final Bitmap render(ByteMatrix byteMatrix, int innerRenderedSize, int margin, float dataDotScale, int colorDark, int colorLight, int startColor, int endColor, Bitmap backgroundImage, boolean whiteMargin, boolean autoColor, boolean binarize, int binarizeThreshold, boolean roundedDataDots, Bitmap logoImage, int logoMargin, int logoCornerRadius, float logoScale) {
        int nCount = byteMatrix.getWidth();
        float nWidth = (float) innerRenderedSize / (float) nCount;
        float nHeight = (float) innerRenderedSize / (float) nCount;
        Bitmap backgroundImageScaled = Bitmap.createBitmap(innerRenderedSize + (whiteMargin ? 0 : margin * 2), innerRenderedSize + (whiteMargin ? 0 : margin * 2), Config.ARGB_8888);
        if (backgroundImage != null) {
            this.scaleBitmap(backgroundImage, backgroundImageScaled);
        }

        Bitmap renderedBitmap = Bitmap.createBitmap(innerRenderedSize + margin * 2, innerRenderedSize + margin * 2, Config.ARGB_8888);
        if (autoColor && backgroundImage != null) {
            colorDark = this.getDominantColor(backgroundImage);
        }

        int binThreshold = DEFAULT_BINARIZING_THRESHOLD;
        if (binarize) {
            if (binarizeThreshold > 0 && binarizeThreshold < 255) {
                binThreshold = binarizeThreshold;
            }

            colorDark = Color.BLACK;
            colorLight = Color.WHITE;
            if (backgroundImage != null) {
                this.binarize(backgroundImageScaled, binThreshold);
            }
        }

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        Paint paintDark = new Paint();
        paintDark.setColor(colorDark);
        paintDark.setAntiAlias(true);
        paintDark.setStyle(Style.FILL);
        Paint paintLight = new Paint();
        paintLight.setColor(colorLight);
        paintLight.setAntiAlias(true);
        paintLight.setStyle(Style.FILL);
        Paint paintProtector = new Paint();
        paintProtector.setColor(Color.argb(120, 255, 255, 255));
        paintProtector.setAntiAlias(true);
        paintProtector.setStyle(Style.FILL);
        Canvas canvas = new Canvas(renderedBitmap);
        canvas.drawColor(-1);
        canvas.drawBitmap(backgroundImageScaled, (float) (whiteMargin ? margin : 0), (float) (whiteMargin ? margin : 0), paint);
        int row = 0;
        int var34 = byteMatrix.getHeight() - 1;
        ArgbEvaluator argbEvaluator = new ArgbEvaluator();
        if (row <= var34) {
            while (true) {
                int col = 0;
                int var36 = byteMatrix.getWidth() - 1;
                if (col <= var36) {
                    while (true) {
                        byte var37 = byteMatrix.get(col, row);

                        int COLOR_MIDDLE = (int) argbEvaluator.evaluate(0.5f, UIUtils.getColor(startColor), UIUtils.getColor(endColor));

                        int COLOR_S1 = (int) argbEvaluator.evaluate(row / (float) var34, COLOR_MIDDLE, UIUtils.getColor(endColor));

                        int COLOR_S2 = (int) argbEvaluator.evaluate(row / (float) var34, UIUtils.getColor(startColor), COLOR_MIDDLE);

                        int COLOR = (int) argbEvaluator.evaluate(col / (float) var36, COLOR_S1,COLOR_S2);

                        paintDark.setColor(COLOR);

                        if (var37 == BYTE_AGN) {
                            float agnX = (float) margin + (float) col * nWidth;
                            float agnY = (float) margin + (float) row * nHeight;

                            if (agnX - mAgnX > 5 * nWidth || agnY - mAgnY > 5 * nHeight || (col * nWidth == 0 && row * nHeight == 0)) {
                                canvas.drawCircle((float) margin + (float) col * nWidth + 2.5f * nWidth,
                                        (float) margin + (float) row * nHeight + 2.5f * nHeight,
                                        nWidth / 2, paintDark);

                                paintDark.setStrokeWidth(nWidth);
                                paintDark.setStyle(Paint.Style.STROKE);

                                canvas.drawCircle((float) margin + (float) col * nWidth + 2.5f * nWidth,
                                        (float) margin + (float) row * nHeight + 2.5f * nHeight,
                                        (4 * nWidth) / 2, paintDark);

                                mAgnX = (float) margin + (float) col * nWidth;
                                mAgnY = (float) margin + (float) row * nHeight;
                            }
                        } else if (var37 == BYTE_POS) {
                            float posX = (float) margin + (float) col * nWidth;
                            float posY = (float) margin + (float) row * nHeight;

                            if (posX - mPosX > 7 * nWidth || posY - mPosY > 7 * nHeight || (col * nWidth == 0 && row * nHeight == 0)) {
                                canvas.drawCircle((float) margin + (float) col * nWidth + 3.5f * nWidth,
                                        (float) margin + (float) row * nHeight + 3.5f * nHeight,
                                        (3 * nWidth) / 2, paintDark);

                                paintDark.setStrokeWidth(nWidth);
                                paintDark.setStyle(Paint.Style.STROKE);

                                canvas.drawCircle((float) margin + (float) col * nWidth + 3.5f * nWidth,
                                        (float) margin + (float) row * nHeight + 3.5f * nHeight,
                                        (6 * nWidth) / 2, paintDark);

                                mPosX = (float) margin + (float) col * nWidth;
                                mPosY = (float) margin + (float) row * nHeight;
                            }
                        } else if (var37 == BYTE_DTA) {
                            if (roundedDataDots) {
                                paintDark.setStyle(Style.FILL);
                                canvas.drawCircle((float) margin + ((float) col + 0.5F) * nWidth,
                                        (float) margin + ((float) row + 0.5F) * nHeight,
                                        dataDotScale * nHeight * 0.5F, paintDark);
                            } else {
                                paintDark.setStyle(Style.FILL);
                                canvas.drawRect((float) margin + ((float) col + 0.5F * ((float) 1 - dataDotScale)) * nWidth,
                                        (float) margin + ((float) row + 0.5F * ((float) 1 - dataDotScale)) * nHeight,
                                        (float) margin + ((float) col + 0.5F * ((float) 1 + dataDotScale)) * nWidth,
                                        (float) margin + ((float) row + 0.5F * ((float) 1 + dataDotScale)) * nHeight, paintDark);
                            }
                        } else if (var37 == BYTE_EPT) {
                            if (roundedDataDots) {
                                canvas.drawCircle((float) margin + ((float) col + 0.5F) * nWidth,
                                        (float) margin + ((float) row + 0.5F) * nHeight,
                                        dataDotScale * nHeight * 0.5F, paintLight);
                            } else {
                                canvas.drawRect((float) margin + ((float) col + 0.5F * ((float) 1 - dataDotScale)) * nWidth,
                                        (float) margin + ((float) row + 0.5F * ((float) 1 - dataDotScale)) * nHeight,
                                        (float) margin + ((float) col + 0.5F * ((float) 1 + dataDotScale)) * nWidth,
                                        (float) margin + ((float) row + 0.5F * ((float) 1 + dataDotScale)) * nHeight, paintLight);
                            }
                        }

                        if (col == var36) {
                            break;
                        }

                        ++col;
                    }
                }

                if (row == var34) {
                    break;
                }

                ++row;
            }
        }

        if (logoImage != null) {
            if (logoScale <= (float) 0 || logoScale >= (float) 1) {
                logoScale = DEFAULT_LOGO_SCALE;
            }

            if (logoMargin < 0 || logoMargin * 2 >= innerRenderedSize) {
                logoMargin = DEFAULT_LOGO_MARGIN;
            }

            row = (int) ((float) innerRenderedSize * logoScale);
            if (logoCornerRadius < 0) {
                logoCornerRadius = 0;
            }

            if (logoCornerRadius * 2 > row) {
                logoCornerRadius = (int) ((double) row * 0.5D);
            }

            Bitmap logoScaled = Bitmap.createScaledBitmap(logoImage, row, row, true);
            Bitmap logoOpt = Bitmap.createBitmap(logoScaled.getWidth(), logoScaled.getHeight(), Config.ARGB_8888);
            Canvas logoCanvas = new Canvas(logoOpt);
            Rect logoRect = new Rect(0, 0, logoScaled.getWidth(), logoScaled.getHeight());
            RectF logoRectF = new RectF(logoRect);
            Paint logoPaint = new Paint();
            logoPaint.setAntiAlias(true);
            logoCanvas.drawARGB(0, 0, 0, 0);
            logoCanvas.drawRoundRect(logoRectF, (float) logoCornerRadius, (float) logoCornerRadius, logoPaint);
            logoPaint.setXfermode((Xfermode) (new PorterDuffXfermode(Mode.SRC_IN)));
            logoCanvas.drawBitmap(logoScaled, logoRect, logoRect, logoPaint);


            logoPaint.setStyle(Style.STROKE);
            LinearGradient gradient = new LinearGradient(byteMatrix.getWidth() / 2 + 100,
                    byteMatrix.getHeight() / 2 - 100,
                    byteMatrix.getWidth() / 2 - 100,
                    byteMatrix.getHeight() / 2 + 100,
                    UIUtils.getColor(startColor),
                    UIUtils.getColor(endColor),
                    Shader.TileMode.MIRROR);
            logoPaint.setShader(gradient);
            logoPaint.setStrokeWidth((float) logoMargin);
            logoCanvas.drawRoundRect(logoRectF, (float) logoCornerRadius, (float) logoCornerRadius, logoPaint);
            if (binarize) {
                this.binarize(logoOpt, binThreshold);
            }

            canvas.drawBitmap(logoOpt, (float) ((int) (0.5D * (double) (renderedBitmap.getWidth() - logoOpt.getWidth()))), (float) ((int) (0.5D * (double) (renderedBitmap.getHeight() - logoOpt.getHeight()))), paint);
        }

        return renderedBitmap;
    }

    private final ByteMatrix getBitMatrix(String contents) {
        try {
            QRCode qrCode = this.getProtoQRCode(contents, ErrorCorrectionLevel.H);
            int[] agnCenter = qrCode.getVersion().getAlignmentPatternCenters();
            ByteMatrix byteMatrix = qrCode.getMatrix();
            int matSize = byteMatrix.getWidth();
            int row = 0;
            int var7 = matSize - 1;
            if (row <= var7) {
                while (true) {
                    int col = 0;
                    int var9 = matSize - 1;
                    if (col <= var9) {
                        while (true) {
                            if (this.isTypeAGN(col, row, agnCenter, true)) {
                                if (byteMatrix.get(col, row) != BYTE_EPT) {
                                    byteMatrix.set(col, row, BYTE_AGN);
                                } else {
                                    byteMatrix.set(col, row, BYTE_PTC);
                                }
                            } else if (this.isTypePOS(col, row, matSize, true)) {
                                if (byteMatrix.get(col, row) != BYTE_EPT) {
                                    byteMatrix.set(col, row, BYTE_POS);
                                } else {
                                    byteMatrix.set(col, row, BYTE_PTC);
                                }
                            } else if (this.isTypeTMG(col, row, matSize)) {
                                if (byteMatrix.get(col, row) != BYTE_EPT) {
                                    byteMatrix.set(col, row, BYTE_TMG);
                                } else {
                                    byteMatrix.set(col, row, BYTE_PTC);
                                }
                            }

                            if (this.isTypePOS(col, row, matSize, false) && byteMatrix.get(col, row) == BYTE_EPT) {
                                byteMatrix.set(col, row, BYTE_PTC);
                            }

                            if (col == var9) {
                                break;
                            }

                            ++col;
                        }
                    }

                    if (row == var7) {
                        break;
                    }

                    ++row;
                }
            }

            return byteMatrix;
        } catch (WriterException var10) {
            var10.printStackTrace();
            return null;
        }
    }

    private final QRCode getProtoQRCode(String contents, ErrorCorrectionLevel errorCorrectionLevel) throws WriterException {
        CharSequence var3 = (CharSequence) contents;
        if (var3.length() == 0) {
            throw (new IllegalArgumentException("Found empty contents"));
        } else {
            Hashtable hintMap = new Hashtable();
            hintMap.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hintMap.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel);
            QRCode var10000 = Encoder.encode(contents, errorCorrectionLevel, (Map) hintMap);
            return var10000;
        }
    }

    private final boolean isTypeAGN(int x, int y, int[] agnCenter, boolean edgeOnly) {
        if (agnCenter.length == 0) {
            return false;
        } else {
            int edgeCenter = agnCenter[agnCenter.length - 1];

            for (int var7 = 0; var7 < agnCenter.length; ++var7) {
                int agnY = agnCenter[var7];

                for (int var9 = 0; var9 < agnCenter.length; ++var9) {
                    int agnX = agnCenter[var9];
                    if ((!edgeOnly || agnX == 6 || agnY == 6 || agnX == edgeCenter || agnY == edgeCenter) && (agnX != 6 || agnY != 6) && (agnX != 6 || agnY != edgeCenter) && (agnY != 6 || agnX != edgeCenter) && x >= agnX - 2 && x <= agnX + 2 && y >= agnY - 2 && y <= agnY + 2) {
                        return true;
                    }
                }
            }

            return false;
        }
    }

    private boolean isTypePOS(int x, int y, int size, boolean inner) {
        return inner ? x < 7 && (y < 7 || y >= size - 7) || x >= size - 7 && y < 7 : x <= 7 && (y <= 7 || y >= size - 8) || x >= size - 8 && y <= 7;
    }

    private boolean isTypeTMG(int x, int y, int size) {
        return y == 6 && x >= 8 && x < size - 8 || x == 6 && y >= 8 && y < size - 8;
    }

    private void scaleBitmap(Bitmap src, Bitmap dst) {
        Paint cPaint = new Paint();
        cPaint.setAntiAlias(true);
        cPaint.setDither(true);
        cPaint.setFilterBitmap(true);
        float ratioX = (float) dst.getWidth() / (float) src.getWidth();
        float ratioY = (float) dst.getHeight() / (float) src.getHeight();
        float middleX = (float) dst.getWidth() * 0.5F;
        float middleY = (float) dst.getHeight() * 0.5F;
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
        Canvas canvas = new Canvas(dst);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(src, middleX - (float) (src.getWidth() / 2), middleY - (float) (src.getHeight() / 2), cPaint);
    }

    private int getDominantColor(Bitmap bitmap) {
        Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, 8, 8, true);
        int red = 0;
        int green = 0;
        int blue = 0;
        int c = 0;
        int y = 0;
        int var11 = newBitmap.getHeight() - 1;
        if (y <= var11) {
            while (true) {
                int x = 0;
                int var13 = newBitmap.getHeight() - 1;
                if (x <= var13) {
                    while (true) {
                        int color = newBitmap.getPixel(x, y);
                        int r = color >> 16 & 255;
                        int g = color >> 8 & 255;
                        int b = color & 255;
                        if (r <= 200 && g <= 200 && b <= 200) {
                            red += r;
                            green += g;
                            blue += b;
                            ++c;
                        }

                        if (x == var13) {
                            break;
                        }

                        ++x;
                    }
                }

                if (y == var11) {
                    break;
                }

                ++y;
            }
        }

        newBitmap.recycle();
        red = Math.max(0, Math.min(255, red / c));
        green = Math.max(0, Math.min(255, green / c));
        blue = Math.max(0, Math.min(255, blue / c));
        return Color.BLACK | red << 16 | green << 8 | blue;
    }

    private void binarize(Bitmap bitmap, int threshold) {
        int y = 0;
        int var7 = bitmap.getHeight() - 1;
        if (y <= var7) {
            while (true) {
                int x = 0;
                int var9 = bitmap.getHeight() - 1;
                if (x <= var9) {
                    while (true) {
                        int color = bitmap.getPixel(x, y);
                        int r = color >> 16 & 255;
                        int g = color >> 8 & 255;
                        int b = color & 255;
                        float sum = 0.3F * (float) r + 0.59F * (float) g + 0.11F * (float) b;
                        bitmap.setPixel(x, y, sum > (float) threshold ? Color.WHITE : Color.BLACK);
                        if (x == var9) {
                            break;
                        }

                        ++x;
                    }
                }

                if (y == var7) {
                    break;
                }

                ++y;
            }
        }

    }

    // $FF: synthetic method
    public static int getDEFAULT_SIZE() {
        return DEFAULT_SIZE;
    }

    // $FF: synthetic method
    public static int getDEFAULT_MARGIN() {
        return DEFAULT_MARGIN;
    }

    // $FF: synthetic method
    public static float getDEFAULT_DTA_DOT_SCALE() {
        return DEFAULT_DTA_DOT_SCALE;
    }

    // $FF: synthetic method
    public static int getDEFAULT_BINARIZING_THRESHOLD() {
        return DEFAULT_BINARIZING_THRESHOLD;
    }

    // $FF: synthetic method
    public static int getDEFAULT_LOGO_MARGIN() {
        return DEFAULT_LOGO_MARGIN;
    }

    // $FF: synthetic method
    public static int getDEFAULT_LOGO_RADIUS() {
        return DEFAULT_LOGO_RADIUS;
    }

    // $FF: synthetic method
    public static float getDEFAULT_LOGO_SCALE() {
        return DEFAULT_LOGO_SCALE;
    }


    public static class Renderer {
        private String contents;
        private int size;
        private int margin;
        private float dataDotScale;
        private int colorDark;
        private int colorLight;
        private Bitmap backgroundImage;
        private boolean whiteMargin;
        private boolean autoColor;
        private boolean binarize;
        private int binarizeThreshold;
        private boolean roundedDataDots;
        private Bitmap logoImage;
        private int logoMargin;
        private int logoCornerRadius;
        private float logoScale;
        private int startColor;
        private int endColor;

        public QRCodeUtil.Renderer autoColor(boolean autoColor) {
            this.autoColor = autoColor;
            return this;
        }

        public QRCodeUtil.Renderer background(@Nullable Bitmap backgroundImage) {
            this.backgroundImage = backgroundImage;
            return this;
        }

        public final QRCodeUtil.Renderer binarize(boolean binarize) {
            this.binarize = binarize;
            return this;
        }

        public final QRCodeUtil.Renderer binarizeThreshold(int binarizeThreshold) {
            this.binarizeThreshold = binarizeThreshold;
            return this;
        }

        public final QRCodeUtil.Renderer colorDark(int colorDark) {
            this.colorDark = colorDark;
            return this;
        }

        public final QRCodeUtil.Renderer colorLight(int colorLight) {
            this.colorLight = colorLight;
            return this;
        }

        public final QRCodeUtil.Renderer startColor(int startColor) {
            this.startColor = startColor;
            return this;
        }

        public final QRCodeUtil.Renderer endColor(int endColor) {
            this.endColor = endColor;
            return this;
        }

        public final QRCodeUtil.Renderer contents(@Nullable String contents) {
            this.contents = contents;
            return this;
        }

        public final QRCodeUtil.Renderer dotScale(float dataDotScale) {
            this.dataDotScale = dataDotScale;
            return this;
        }

        public final QRCodeUtil.Renderer logoRadius(int logoCornerRadius) {
            this.logoCornerRadius = logoCornerRadius;
            return this;
        }

        public final QRCodeUtil.Renderer logo(@Nullable Bitmap logoImage) {
            this.logoImage = logoImage;
            return this;
        }

        public final QRCodeUtil.Renderer logoMargin(int logoMargin) {
            this.logoMargin = logoMargin;
            return this;
        }

        public final QRCodeUtil.Renderer logoScale(float logoScale) {
            this.logoScale = logoScale;
            return this;
        }

        public final QRCodeUtil.Renderer margin(int margin) {
            this.margin = margin;
            return this;
        }

        public final QRCodeUtil.Renderer roundedDots(boolean roundedDataDots) {
            this.roundedDataDots = roundedDataDots;
            return this;
        }

        public final QRCodeUtil.Renderer size(int size) {
            this.size = size;
            return this;
        }

        public final QRCodeUtil.Renderer whiteMargin(boolean whiteMargin) {
            this.whiteMargin = whiteMargin;
            return this;
        }

        public final void renderAsync(@Nullable final QRCodeUtil.Callback callback) throws IllegalArgumentException {
            (new Thread() {
                public void run() {
                    super.run();

                    QRCodeUtil.Callback var10000;
                    try {
                        Bitmap bitmap = new QRCodeUtil().create(Renderer.this.contents, Renderer.this.size, Renderer.this.margin, Renderer.this.dataDotScale, Renderer.this.colorDark, Renderer.this.colorLight, Renderer.this.startColor, Renderer.this.endColor, Renderer.this.backgroundImage, Renderer.this.whiteMargin, Renderer.this.autoColor, Renderer.this.binarize, Renderer.this.binarizeThreshold, Renderer.this.roundedDataDots, Renderer.this.logoImage, Renderer.this.logoMargin, Renderer.this.logoCornerRadius, Renderer.this.logoScale);
                        var10000 = callback;
                        if (callback != null) {
                            var10000.onRendered(Renderer.this, bitmap);
                        }
                    } catch (Exception var2) {
                        var10000 = callback;
                        if (callback != null) {
                            var10000.onError(Renderer.this, var2);
                        }
                    }

                }
            }).start();
        }

        public Renderer() {
            this.size = QRCodeUtil.getDEFAULT_SIZE();
            this.margin = QRCodeUtil.getDEFAULT_MARGIN();
            this.dataDotScale = QRCodeUtil.getDEFAULT_DTA_DOT_SCALE();
            this.colorDark = Color.BLACK;
            this.colorLight = Color.WHITE;
            this.colorDark = Color.BLACK;
            this.whiteMargin = true;
            this.autoColor = true;
            this.binarize = false;
            this.binarizeThreshold = QRCodeUtil.getDEFAULT_BINARIZING_THRESHOLD();
            this.roundedDataDots = false;
            this.logoMargin = QRCodeUtil.getDEFAULT_LOGO_MARGIN();
            this.logoCornerRadius = QRCodeUtil.getDEFAULT_LOGO_RADIUS();
            this.logoScale = QRCodeUtil.getDEFAULT_LOGO_SCALE();
        }
    }

    public interface Callback {
        void onRendered(QRCodeUtil.Renderer var1, Bitmap var2);

        void onError(QRCodeUtil.Renderer var1, Exception var2);
    }
}

链式使用:

new QRCodeUtil.Renderer()
                .contents(qrCodeBean.getUrl()) //二维码的url
                .size(UIUtils.dip2px(140)) // 二维码大小
                .dotScale(1.0f) //掩码点大小
                .margin(UIUtils.dip2px(6)) 
                .startColor() //渐变色起始颜色
                .endColor() //渐变色结束颜色
                .roundedDots(true) 
                .logo(resource) //中间logo图片
                .logoMargin(20)
                .logoRadius(150)
                .logoScale(0.4f)
                .renderAsync(new QRCodeUtil.Callback() {
                    @Override
                    public void onRendered(QRCodeUtil.Renderer renderer, Bitmap bitmap) {
                    }

                    @Override
                    public void onError(QRCodeUtil.Renderer renderer, Exception e) {
                    }
                });

如果觉得对你有帮助的话就点个赞吧~