Java 使用zxing生成具有自定义点形状的二维码

Java 使用zxing生成具有自定义点形状的二维码,java,qr-code,zxing,Java,Qr Code,Zxing,我正在编写一个应用程序来生成带有自定义点形状的二维码。使用zxing的最佳方法是什么 到目前为止,我已经翻遍了源代码,我看到数据位是用代码写的。我想我可以在这个函数的末尾添加一些代码,这将允许我屏蔽这些点,但我不知道如何在Java中做到这一点。我无法扩展该类,因为它已声明为final。这是一个好主意吗?如果是,我将如何以这种方式扩展此方法 我一直在考虑的另一个选择是对QRCode生成的图像进行后处理,但我认为这真的很复杂,因为我必须找到一种从定位方块中辨别点的方法 有没有更好的方法来做我想做的事

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

到目前为止,我已经翻遍了源代码,我看到数据位是用代码写的。我想我可以在这个函数的末尾添加一些代码,这将允许我屏蔽这些点,但我不知道如何在Java中做到这一点。我无法扩展该类,因为它已声明为final。这是一个好主意吗?如果是,我将如何以这种方式扩展此方法

我一直在考虑的另一个选择是对QRCode生成的图像进行后处理,但我认为这真的很复杂,因为我必须找到一种从定位方块中辨别点的方法

有没有更好的方法来做我想做的事情?除了zxing,还有没有其他二维码库可以做我想做的事情


另外,我想指出的是,尽管关键字相似,但这并不是的重复。

我最终选择了zxing,并使用它将其包含在Maven中。我实现了RGB掩蔽功能,并将圆和轮廓正方形绘制为点形状。以下是存储库:

以下java代码使用zxing制作带有圆点和圆形查找器图案的QR码图像(自定义渲染样式)。这可以调整为其他自定义渲染样式

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

生成的二维码图像示例:

publicstaticvoidmain(字符串[]args){
试一试{
生成QRCodeImage(“https://www.google.com“,300300,”./MyQRCode.png”);
}捕获(例外e){
e、 printStackTrace();
}
}
私有静态void generateQRCodeImage(字符串文本、整数宽度、整数高度、字符串文件路径)引发WriterException、IOException{
final Map encodinghits=new HashMap();
编码提示.put(EncodeHintType.CHARACTER_集,“UTF-8”);
QRCode code=Encoder.encode(文本,ErrorCorrectionLevel.H,编码提示);
BuffereImage=renderQRImage(代码、宽度、高度,4);
try(FileOutputStream=newfileoutputstream(filePath)){
stream.write(bufferedImageToBytes(image));
}
}
专用静态缓冲区映像renderQRImage(QRCode代码、int-width、int-height、int-quietZone){
BuffereImage=新的BuffereImage(宽度、高度、BuffereImage.TYPE_INT_ARGB);
Graphics2D graphics=image.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY\u抗锯齿,RenderingHints.VALUE\u抗锯齿开);
图形.背景(颜色.白色);
图形.clearRect(0,0,宽度,高度);
图形.设置颜色(颜色.黑色);
ByteMatrix输入=code.getMatrix();
如果(输入==null){
抛出新的非法状态异常();
}
int inputWidth=input.getWidth();
int inputhweight=input.getHeight();
int qrWidth=输入宽度+(quietZone*2);
int qrHeight=inputHeight+(静音*2);
int outputWidth=Math.max(宽度,qrWidth);
int outputhweight=数学最大值(高度,qrHeight);
整数倍数=数学最小值(outputWidth/qrWidth,outputhweight/qrHeight);
int-leftPadding=(outputWidth-(inputWidth*multiple))/2;
int-topPadding=(输出权限-(输入权限*多个))/2;
最终int FINDER_PATTERN_SIZE=7;
最终浮动圆\比例\下降\系数=21f/30f;
int circleSize=(int)(多个*圆的比例因子);
for(int-inputY=0,outputY=topPadding;inputYif(!(inputX看起来是一个很好的实现。
drawFinderPatternCircleStyle
来自哪里?@jcassee也可以使用.fillOval函数。但是使用它三次(两个黑色椭圆,中间一个白色)。您需要坚持的是,它们的直径与7x5x3x3有关。对不起,添加了drawFinderPatternCircleStyle。@jCassee“BuffereImage”和“Graphics2D”所需的实现是什么类?实际上它无法解析。@RamkeshYadav这些都是java系统类。
导入java.awt.Graphics2D;
导入java.awt.image.BufferedImage;
你能给我发一些代码参考,让我更好地理解定制二维码吗?@RamkeshYadav 4年后,我认为另一个答案可能更好:你没有很高兴看到你的建议,如果你不能回复我,我会按照上面提到的链接。
    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);
    }
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.4.0</version>
    </dependency>