使用zxing生成具有自定义点形状的QR码

时间:2016-02-15 21:34:34

标签: java qr-code zxing

我正在编写一个应用程序来生成具有自定义点形状的QR码。使用zxing的最佳方法是什么?

到目前为止,我已经挖掘了源代码,我发现数据位是用com.google.zxing.qrcode.encoder.MatrixUtil.embedDataBits()编写的。我想我可以在这个函数的末尾添加一些代码,这将允许我掩盖点,但我不知道如何在Java中这样做。我无法扩展课程,因为它被宣布为最终课程。这是一个好主意,如果是这样,我将如何以这种方式扩展这种方法?

我一直关注的另一个选项涉及对QRCode生成的图像进行后期处理,但这非常复杂,我认为我必须找到一种方法来识别定位方块中的点。

有没有更好的方法来做我想做的事情?除了zxing之外还有另一个二维码库可以做我想要开箱即用的东西吗?

P.S。我想请注意,这不是this question的重复,尽管关键字类似。

2 个答案:

答案 0 :(得分:4)

以下Java代码使用zxing制作带有圆形点和圆形finder模式(自定义渲染样式)的QR代码图像。可以适应其他自定义渲染样式。

我直接使用Encoder类,并绕过QRCodeWriter和MatrixToImageWriter获得足够的控制权来更改呈现。要更改取景器图案,我使用以下事实:取景器图案始终为7点宽/高。否则,我将不得不创建MatrixUtil(可能还有Encoder)的自定义版本。

生成的QR码示例图像:

Example QR Code Image Generated

    public static void main(String[] args) {
        try {
            generateQRCodeImage("https://www.google.com", 300, 300, "./MyQRCode.png");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void generateQRCodeImage(String text, int width, int height, String filePath) throws WriterException, IOException {
        final Map<EncodeHintType, Object> encodingHints = new HashMap<>();
        encodingHints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        QRCode code = Encoder.encode(text, ErrorCorrectionLevel.H, encodingHints);
        BufferedImage image = renderQRImage(code, width, height, 4);
        
        try (FileOutputStream stream = new FileOutputStream(filePath)) {
            stream.write(bufferedImageToBytes(image));
        }
    }

    private static BufferedImage renderQRImage(QRCode code, int width, int height, int quietZone) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = image.createGraphics();

        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics.setBackground(Color.white);
        graphics.clearRect(0, 0, width, height);
        graphics.setColor(Color.black);

        ByteMatrix input = code.getMatrix();
        if (input == null) {
            throw new IllegalStateException();
        }
        int inputWidth = input.getWidth();
        int inputHeight = input.getHeight();
        int qrWidth = inputWidth + (quietZone * 2);
        int qrHeight = inputHeight + (quietZone * 2);
        int outputWidth = Math.max(width, qrWidth);
        int outputHeight = Math.max(height, qrHeight);

        int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);
        int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
        int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
        final int FINDER_PATTERN_SIZE = 7;
        final float CIRCLE_SCALE_DOWN_FACTOR = 21f/30f;
        int circleSize = (int) (multiple * CIRCLE_SCALE_DOWN_FACTOR);

        for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
            for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
                if (input.get(inputX, inputY) == 1) {
                    if (!(inputX <= FINDER_PATTERN_SIZE && inputY <= FINDER_PATTERN_SIZE ||
                          inputX >= inputWidth - FINDER_PATTERN_SIZE && inputY <= FINDER_PATTERN_SIZE ||
                          inputX <= FINDER_PATTERN_SIZE && inputY >= inputHeight - FINDER_PATTERN_SIZE)) {
                        graphics.fillOval(outputX, outputY, circleSize, circleSize);
                    }
                }
            }
        }

        int circleDiameter = multiple * FINDER_PATTERN_SIZE;
        drawFinderPatternCircleStyle(graphics, leftPadding, topPadding, circleDiameter);
        drawFinderPatternCircleStyle(graphics, leftPadding + (inputWidth - FINDER_PATTERN_SIZE) * multiple, topPadding, circleDiameter);
        drawFinderPatternCircleStyle(graphics, leftPadding, topPadding + (inputHeight - FINDER_PATTERN_SIZE) * multiple, circleDiameter);

        return image;
    }

    private static void drawFinderPatternCircleStyle(Graphics2D graphics, int x, int y, int circleDiameter) {
        final int WHITE_CIRCLE_DIAMETER = circleDiameter*5/7;
        final int WHITE_CIRCLE_OFFSET = circleDiameter/7;
        final int MIDDLE_DOT_DIAMETER = circleDiameter*3/7;
        final int MIDDLE_DOT_OFFSET = circleDiameter*2/7;

        graphics.setColor(Color.black);
        graphics.fillOval(x, y, circleDiameter, circleDiameter);
        graphics.setColor(Color.white);
        graphics.fillOval(x + WHITE_CIRCLE_OFFSET, y + WHITE_CIRCLE_OFFSET, WHITE_CIRCLE_DIAMETER, WHITE_CIRCLE_DIAMETER);
        graphics.setColor(Color.black);
        graphics.fillOval(x + MIDDLE_DOT_OFFSET, y + MIDDLE_DOT_OFFSET, MIDDLE_DOT_DIAMETER, MIDDLE_DOT_DIAMETER);
    }

Maven依赖项:

    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.4.0</version>
    </dependency>

答案 1 :(得分:0)

我最终请求zxing并使用JitPack将其包含在Maven中。我实现了RGB蒙版的功能,并绘制了圆形和轮廓方块作为点形状。这是存储库:https://github.com/flotwig/zxing