使用Zxing生成具有自定义点形状的QR码 [英] Generate QR codes with custom dot shapes using zxing
问题描述
我正在编写一个应用程序,以生成具有自定义点形状的QR码.使用zxing做到这一点的最佳方法是什么?
到目前为止,我已经研究了源代码,并且看到数据位写在
public static void main(String [] args){尝试 {generateQRCodeImage("https://www.google.com",300、300,"./MyQRCode.png");} catch(Exception e){e.printStackTrace();}}私人静态void generateQRCodeImage(String text,int width,int height,String filePath)抛出WriterException,IOException {最终Map< EncodeHintType,Object>encodingHints = new HashMap<>();encodingHints.put(EncodeHintType.CHARACTER_SET,"UTF-8");QRCode代码= Encoder.encode(text,ErrorCorrectionLevel.H,encodingHints);BufferedImage image = renderQRImage(code,width,height,4);尝试(FileOutputStream流=新的FileOutputStream(filePath)){stream.write(bufferedImageToBytes(image));}}私有静态BufferedImage renderQRImage(QRCode代码,int宽度,int高度,int quietZone){BufferedImage图片=新的BufferedImage(宽度,高度,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,宽度,高度);graphics.setColor(Color.black);ByteMatrix输入= code.getMatrix();如果(输入==空){抛出新的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);整数倍= Math.min(outputWidth/qrWidth,outputHeight/qrHeight);int leftPadding =(outputWidth-(inputWidth *倍数))/2;int topPadding =(outputHeight-(inputHeight *倍数))/2;最终int FINDER_PATTERN_SIZE = 7;最终浮动CIRCLE_SCALE_DOWN_FACTOR = 21f/30f;int circleSize =(int)(多个* CIRCLE_SCALE_DOWN_FACTOR);for(int inputY = 0,outputY = topPadding; inputY< inputHeight; inputY ++,outputY + =多个){for(int inputX = 0,outputX = leftPadding; inputX< inputWidth; inputX ++,outputX + =多个){如果(input.get(inputX,inputY)== 1){如果(!(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 =多个* 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);返回图像;}private static void drawFinderPatternCircleStyle(Graphics2D graphics,int x,int y,int circleDiameter){最终int WHITE_CIRCLE_DIAMETER = circleDiameter * 5/7;final int WHITE_CIRCLE_OFFSET = circleDiameter/7;最终int MIDDLE_DOT_DIAMETER = circleDiameter * 3/7;最终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>
I'm writing an application to generate QR codes with custom dot shapes. What's the best way to do this using zxing?
So far, I've dug through the source code and I see that the data bits are written in com.google.zxing.qrcode.encoder.MatrixUtil.embedDataBits(). I think I could add some code on to the end of this function which would allow me to mask the dots but I'm not sure how to do this in Java. I can't extend the class because it's declared as final. Would it be a good idea and if so how would I extend this method in that way?
The other option I've been looking at involves post-processing the image produced by QRCode but this is really complex I think as I'd have to find a way to discern the dots from the positioning squares.
Is there a better way to do what I'm looking to do? Is there another QR code library besides zxing which can do what I'm looking to do out of the box?
P.S. I want to note that this is not a duplicate of this question although the keywords are similar.
The following java code uses zxing to make a QR-code image with circular dots and a circular finder pattern (custom rendering style). This can be adapted to other custom render styles.
I use the Encoder class directly and bypass QRCodeWriter and MatrixToImageWriter to gain enough control to alter the rendering. To alter the finder pattern, I use the fact that the finder pattern is always 7 dots wide/tall. Otherwise I would have to create a custom version of MatrixUtil (and perhaps Encoder).
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:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.0</version>
</dependency>
这篇关于使用Zxing生成具有自定义点形状的QR码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!