一、概述
-
使用
zxing
開源庫- Zxing主要是Google出品的,用于識(shí)別一維碼和二維碼的第三方庫
- 主要類:
-
BitMatrix
位圖矩陣 -
MultiFormatWriter
位圖編寫器 -
MatrixToImageWriter
寫入圖片
-
可以生成、識(shí)別條形碼和二維碼
-
內(nèi)置三種尺寸:
enum Size {SMALL, MIDDLE, BIG}
-
依賴
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.1</version>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.7</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
二、效果圖
三、條形碼
- 將寬度不等的多個(gè)黑條和白條,按照一定的編碼規(guī)則排序,用以表達(dá)一組信息的圖像標(biāo)識(shí)符
- 通常代表一串?dāng)?shù)字 / 字母,每一位有特殊含義
- 一般數(shù)據(jù)容量30個(gè)數(shù)字 / 字母
1、生成簡(jiǎn)單條形碼(無文字)
/**
* 生成簡(jiǎn)單條形碼(無文字)
*
* @param content
* @param width
* @param height
* @return
*/
public static BufferedImage create(String content, int width, int height) {
// 定義位圖矩陣BitMatrix
BitMatrix matrix = null;
try {
// 定義二維碼參數(shù)
Map<EncodeHintType, Object> hints = new HashMap<>(3);
// 設(shè)置編碼
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 設(shè)置容錯(cuò)等級(jí)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 設(shè)置邊距,默認(rèn)為5
hints.put(EncodeHintType.MARGIN, 3);
// 使用code_128格式進(jìn)行編碼生成條形碼
MultiFormatWriter writer = new MultiFormatWriter();
matrix = writer.encode(content, BarcodeFormat.CODE_128, width, height, hints);
} catch (WriterException e) {
e.printStackTrace();
//throw new RuntimeException("條形碼內(nèi)容寫入失敗");
}
return MatrixToImageWriter.toBufferedImage(matrix);
}
2、生成條形碼(含文字)
- 生成條形碼(含文字)
/**
* 生成條形碼(含文字)
* ****************************************************
* ----------------------------------------------
* | 2023-06-10 10:55 |
* | |
* | 商品名稱 /超出不顯示/ |
* | |
* | | || ||| | || |||| | | | ||| | | || |
* | | || ||| | || |||| | | | ||| | | || |
* | | || ||| | || |||| | | | ||| | | || |
* | | || ||| | || |||| | | | ||| | | || |
* | 13800000000 |
* ----------------------------------------------
* ===================================================
* 1、日期:頂部右側(cè)
* 2、商品名稱:居中
* 3、條形碼:商品名稱下方,且居中
* 4、條碼內(nèi)容:條形碼下方,且居中
* *****************************************************
*
* @param codeImage 條形碼圖片
* @param bottomStr 底部文字
* @param titleStr 標(biāo)題文字
* @param topRightStr 右上角文字
* @param pictureWidth 圖片寬度
* @param pictureHeight 圖片高度
* @param margin 邊距
* @param fontSize 字體大小
* @return 條形碼圖片
*/
private static BufferedImage createWithWords(
BufferedImage codeImage,
String bottomStr,
String titleStr,
String topRightStr,
int pictureWidth,
int pictureHeight,
int margin,
int fontSize) {
BufferedImage picImage = new BufferedImage(pictureWidth, pictureHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = picImage.createGraphics();
// 抗鋸齒
setGraphics2D(g2d);
// 設(shè)置白色
setColorWhite(g2d, picImage.getWidth(), picImage.getHeight());
// 條形碼默認(rèn)居中顯示
int codeStartX = (pictureWidth - codeImage.getWidth()) / 2;
int codeStartY = (pictureHeight - codeImage.getHeight()) / 2 + 2 * margin;
// 畫條形碼到新的面板
g2d.drawImage(codeImage, codeStartX, codeStartY, codeImage.getWidth(), codeImage.getHeight(), null);
// 給條碼上下各畫一條線
// 設(shè)置顏色
g2d.setColor(Color.LIGHT_GRAY);
int y1 = 2 * margin + codeImage.getHeight();
int y2 = 2 * margin + 2 * codeImage.getHeight();
g2d.drawLine(0, y1, pictureWidth, y1);
g2d.drawLine(0, y2, pictureWidth, y2);
// 畫文字到新的面板
g2d.setColor(Color.BLACK);
// 字體、字型、字號(hào)
g2d.setFont(new Font("微軟雅黑", Font.PLAIN, fontSize));
// 文字與條形碼之間的間隔
int wordAndCodeSpacing = 3;
// 底部文字(居中)
if (StringUtils.isNotEmpty(bottomStr)) {
// 文字長(zhǎng)度
int strWidth = g2d.getFontMetrics().stringWidth(bottomStr);
// 文字X軸開始坐標(biāo)
int strStartX = (pictureWidth - strWidth) / 2;
if (strStartX < margin) {
strStartX = margin;
}
// 文字Y軸開始坐標(biāo)
int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing;
// 畫文字
g2d.drawString(bottomStr, strStartX, strStartY);
}
// 右上角文字
if (StringUtils.isNotEmpty(topRightStr)) {
// 文字長(zhǎng)度
int strWidth = g2d.getFontMetrics().stringWidth(topRightStr);
// 文字X軸開始坐標(biāo)
int strStartX = pictureWidth - strWidth - margin;
// 文字Y軸開始坐標(biāo)
int strStartY = margin + fontSize;
// 畫文字
g2d.drawString(topRightStr, strStartX, strStartY);
}
// 標(biāo)題文字(居中)
if (StringUtils.isNotEmpty(titleStr)) {
if (titleStr.length() > 11) {
titleStr = titleStr.substring(0, 11);
}
// 字體、字型、字號(hào)
int fs = (int) Math.ceil(fontSize * 1.5);
g2d.setFont(new Font("微軟雅黑", Font.PLAIN, fs));
// 文字長(zhǎng)度
int strWidth = g2d.getFontMetrics().stringWidth(titleStr);
// 文字X軸開始坐標(biāo)
int strStartX = (pictureWidth - strWidth) / 2;
if (strStartX < margin) {
strStartX = margin;
}
// 文字Y軸開始坐標(biāo)
int strStartY = codeStartY - margin;
// 畫文字
g2d.drawString(titleStr, strStartX, strStartY);
}
g2d.dispose();
picImage.flush();
return picImage;
}
- 設(shè)置 Graphics2D 屬性 (抗鋸齒)
/**
* 設(shè)置 Graphics2D 屬性 (抗鋸齒)
*
* @param g2d Graphics2D提供對(duì)幾何形狀、坐標(biāo)轉(zhuǎn)換、顏色管理和文本布局更為復(fù)雜的控制
*/
private static void setGraphics2D(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
g2d.setStroke(s);
}
- 設(shè)置背景為白色
/**
* 設(shè)置背景為白色
*
* @param g2d Graphics2D提供對(duì)幾何形狀、坐標(biāo)轉(zhuǎn)換、顏色管理和文本布局更為復(fù)雜的控制
*/
private static void setColorWhite(Graphics2D g2d, int width, int height) {
g2d.setColor(Color.WHITE);
// 填充整個(gè)屏幕
g2d.fillRect(0, 0, width, height);
// 設(shè)置筆刷
g2d.setColor(Color.BLACK);
}
- 創(chuàng)建小號(hào)條形碼(250x150)
/**
* 創(chuàng)建小號(hào)條形碼(250x150)
*
* @param code
* @param name
* @return
*/
private static BufferedImage createSmallWithWords(@NonNull String code, @NonNull String name) {
// 條形碼底部?jī)?nèi)容
String bottomStr = code;
// 條形碼左上角內(nèi)容
//String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
String topLeftStr = name;
// 條形碼右上角內(nèi)容
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String topRightStr = dtf.format(LocalDateTime.now());
// 生成條形碼
BufferedImage barCodeImage = create(bottomStr, 250, 50);
return createWithWords(
barCodeImage,
bottomStr,
topLeftStr,
topRightStr,
250,
150,
10,
14);
}
- 創(chuàng)建中號(hào)條形碼(350x210)
/**
* 創(chuàng)建中號(hào)條形碼(350x210)
*
* @param code
* @param name
* @return
*/
private static BufferedImage createMiddleWithWords(@NonNull String code, @NonNull String name) {
// 條形碼底部?jī)?nèi)容
String bottomStr = code;
// 條形碼左上角內(nèi)容
//String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
String topLeftStr = name;
// 條形碼右上角內(nèi)容
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String topRightStr = dtf.format(LocalDateTime.now());
// 生成條形碼
BufferedImage barCodeImage = create(bottomStr, 350, 70);
return createWithWords(
barCodeImage,
bottomStr,
topLeftStr,
topRightStr,
350,
210,
14,
20);
}
- 創(chuàng)建大號(hào)條形碼(500x300)
/**
* 創(chuàng)建大號(hào)條形碼(500x300)
*
* @param code
* @param name
* @return
*/
private static BufferedImage createBigWithWords(@NonNull String code, @NonNull String name) {
// 條形碼底部?jī)?nèi)容
String bottomStr = code;
// 條形碼左上角內(nèi)容
//String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
String topLeftStr = name;
// 條形碼右上角內(nèi)容
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String topRightStr = dtf.format(LocalDateTime.now());
// 生成條形碼
BufferedImage barCodeImage = create(bottomStr, 500, 100);
return createWithWords(
barCodeImage,
bottomStr,
topLeftStr,
topRightStr,
500,
300,
20,
28);
}
- 創(chuàng)建內(nèi)置尺寸(小/中/大)條形碼
/**
* 生成條形碼(帶文字)
*
* @param code 編碼內(nèi)容
* @param name 名稱
* @param size 規(guī)格:小中大
* @return
*/
public static BufferedImage createWithWords(
@NonNull String code,
@NonNull String name,
@NonNull Size size
) {
switch (size) {
case SMALL:
return createSmallWithWords(code, name);
case MIDDLE:
return createMiddleWithWords(code, name);
case BIG:
default:
return createBigWithWords(code, name);
}
}
四、二維碼
- 用某種特定幾何圖形按一定規(guī)律在平面(二維方向上)分布的黑白相間的圖形記錄數(shù)據(jù)符號(hào)信息
- 比一維條形碼能存儲(chǔ)更多信息,表示更多數(shù)據(jù)類型
- 能夠存儲(chǔ)數(shù)字 / 字母 / 漢字 / 圖片等信息
- 可存儲(chǔ)幾百到幾十KB字符
1、生成指定尺寸二維碼
/**
* 生成二維碼(正方形)
* @param content
* @param sideLength 邊長(zhǎng)(px)
* @return
*/
public static BufferedImage create(String content, int sideLength) {
BitMatrix matrix = null;
// 定義二維碼參數(shù)
Map<EncodeHintType, Object> hints = new HashMap<>(3);
// 設(shè)置編碼
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 設(shè)置容錯(cuò)等級(jí)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 設(shè)置邊距,默認(rèn)為5
hints.put(EncodeHintType.MARGIN, 3);
try {
matrix = new MultiFormatWriter()
.encode(content, BarcodeFormat.QR_CODE, sideLength, sideLength, hints);
} catch (Exception e) {
e.printStackTrace();
//throw new RuntimeException("條形碼內(nèi)容寫入失敗");
}
return MatrixToImageWriter.toBufferedImage(matrix);
}
2、生成內(nèi)置尺寸(小/中/大)二維碼
小號(hào):250px;中號(hào):350px;大號(hào):500px;文章來源:http://www.zghlxwxcb.cn/news/detail-478075.html
public static BufferedImage create(String content, Size size) {
switch (size) {
case SMALL:
return create(content, 250);
case MIDDLE:
return create(content, 350);
case BIG:
default:
return create(content, 500);
}
}
五、保存
- 存入文件
/**
* 存入文件
*
* @param barCodeImage
* @return 文件名
*/
public static String toFile(BufferedImage barCodeImage) {
String fileName = getFileName();
boolean isWrite = false;
try {
FileOutputStream outputStream = new FileOutputStream(new File(getImageDir(), fileName));
isWrite = ImageIO.write(barCodeImage, "png", outputStream);
} catch (IOException e) {
e.printStackTrace();
}
if (isWrite) {
return fileName;
}
return "";
}
- 存放目錄
/**
* 得到圖片存放目錄
* 類路徑下的image文件夾
*
* @return
*/
private static String getImageDir() {
String imageDir = "";
Resource resource = new ClassPathResource("");
try {
String _dir = resource.getFile().getAbsolutePath();
File file = new File(_dir, "image");
if (!file.exists()) {
file.mkdirs();
}
imageDir = file.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
return imageDir;
}
- 文件名
/**
* 生成文件名
* 當(dāng)前時(shí)間戳 + 兩位隨機(jī)數(shù)
*
* @return
*/
private static String getFileName() {
// 當(dāng)前時(shí)間戳
long second = Instant.now().getEpochSecond();
// 兩位隨機(jī)數(shù)
ThreadLocalRandom r = ThreadLocalRandom.current();
int rand = r.nextInt(10, 99);
return new StringBuffer().append(second).append(rand).append(".png").toString();
}
六、識(shí)別
/**
* 識(shí)別圖形碼(條形碼/二維碼)
* ***********************************************
* ------ 條形碼 ----------------------------------
* 可以識(shí)別內(nèi)容:手機(jī)號(hào)、純數(shù)字、字母數(shù)字、網(wǎng)址(中大號(hào))
* 識(shí)別不了小號(hào)(250x150)含文字的網(wǎng)址條形碼
* 存儲(chǔ)網(wǎng)址時(shí)用二維碼,不要使用條形碼
* ***********************************************
* ------ 二維碼 ----------------------------------
* 比條形碼有優(yōu)勢(shì);能識(shí)別三種尺寸的網(wǎng)址二維碼
* ***********************************************
*
* @param imageCode 圖形碼文件
* @return void
*/
public static String scan(File imageCode) {
String text = "";
try {
BufferedImage image = ImageIO.read(imageCode);
if (image == null) {
return text;
}
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Map<DecodeHintType, Object> hints = new HashMap<>(3);
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
Result result = new MultiFormatReader().decode(bitmap, hints);
text = result.getText();
} catch (Exception e) {
e.printStackTrace();
System.out.println("無法識(shí)別");
}
return text;
}
public static String scan(String fileName) {
return scan(new File(getImageDir(), fileName));
}
public static String scan(String fileName, String fileParent) {
return scan(new File(fileParent, fileName));
}
七、測(cè)試類
package com.tuwer.util;
/**
* <p>描述...</p>
*
* @author 土味兒
* @version 1.0
* @Date 2023/6/10
*/
public class ImageCodeTest {
public static void main(String[] args) {
cr();
//sc();
}
/**
* 創(chuàng)建
*/
private static void cr() {
//String code = "13800000000";
String code = "1667320863285510145";
//String code = "abcdefg123456789012";
//String code = "http://www.baidu.com";
String title = "商品名稱(超出不顯示)";
System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.BarCode.createWithWords(code, title, ImageCodeUtil.Size.SMALL)));
System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.BarCode.createWithWords(code, title, ImageCodeUtil.Size.MIDDLE)));
System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.BarCode.createWithWords(code, title, ImageCodeUtil.Size.BIG)));
//System.out.println(toFile(QrCode.create(code, 500)));
//System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.QrCode.create(code, ImageCodeUtil.Size.SMALL)));
//System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.QrCode.create(code, ImageCodeUtil.Size.MIDDLE)));
//System.out.println(ImageCodeUtil.toFile(ImageCodeUtil.QrCode.create(code, ImageCodeUtil.Size.BIG)));
}
/**
* 識(shí)別
*/
private static void sc() {
// 掃描
// 13800000000
//String[] fs = {"168636218096.png", "168636218180.png", "168636218127.png"};
// 1667320863285510145
//String[] fs = {"168636260651.png", "168636260766.png", "168636260794.png"};
// abcdefg123456789012
//String[] fs = {"168636320566.png", "168636320750.png", "168636320743.png"};
// http://www.baidu.com
String[] fs = {"168636738387.png", "168636738545.png", "168636738539.png"};
for (String f : fs) {
System.out.println("-----------------");
System.out.println(ImageCodeUtil.scan(f));
}
}
}
八、完整源碼
package com.tuwer.util;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.lang.NonNull;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/**
* <p>圖形碼工具類</p>
*
* @author 土味兒
* @version 1.0
* @Date 2023/6/9
*/
public class ImageCodeUtil {
/**
* 尺寸
*/
enum Size {SMALL, MIDDLE, BIG}
// ====================== 條形碼內(nèi)部類 ========================
/**
* 條形碼
*/
public static class BarCode {
/**
* 生成簡(jiǎn)單條形碼(無文字)
*
* @param content
* @param width
* @param height
* @return
*/
public static BufferedImage create(String content, int width, int height) {
// 定義位圖矩陣BitMatrix
BitMatrix matrix = null;
try {
// 定義二維碼參數(shù)
Map<EncodeHintType, Object> hints = new HashMap<>(3);
// 設(shè)置編碼
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 設(shè)置容錯(cuò)等級(jí)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 設(shè)置邊距,默認(rèn)為5
hints.put(EncodeHintType.MARGIN, 3);
// 使用code_128格式進(jìn)行編碼生成條形碼
MultiFormatWriter writer = new MultiFormatWriter();
matrix = writer.encode(content, BarcodeFormat.CODE_128, width, height, hints);
} catch (WriterException e) {
e.printStackTrace();
//throw new RuntimeException("條形碼內(nèi)容寫入失敗");
}
return MatrixToImageWriter.toBufferedImage(matrix);
}
/**
* 生成條形碼(含文字)
* ****************************************************
* ----------------------------------------------
* | 2023-06-10 10:55 |
* | |
* | 商品名稱 /超出不顯示/ |
* | |
* | | || ||| | || |||| | | | ||| | | || |
* | | || ||| | || |||| | | | ||| | | || |
* | | || ||| | || |||| | | | ||| | | || |
* | | || ||| | || |||| | | | ||| | | || |
* | 13800000000 |
* ----------------------------------------------
* ===================================================
* 1、日期:頂部右側(cè)
* 2、商品名稱:居中
* 3、條形碼:商品名稱下方,且居中
* 4、條碼內(nèi)容:條形碼下方,且居中
* *****************************************************
*
* @param codeImage 條形碼圖片
* @param bottomStr 底部文字
* @param titleStr 標(biāo)題文字
* @param topRightStr 右上角文字
* @param pictureWidth 圖片寬度
* @param pictureHeight 圖片高度
* @param margin 邊距
* @param fontSize 字體大小
* @return 條形碼圖片
*/
private static BufferedImage createWithWords(
BufferedImage codeImage,
String bottomStr,
String titleStr,
String topRightStr,
int pictureWidth,
int pictureHeight,
int margin,
int fontSize) {
BufferedImage picImage = new BufferedImage(pictureWidth, pictureHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = picImage.createGraphics();
// 抗鋸齒
setGraphics2D(g2d);
// 設(shè)置白色
setColorWhite(g2d, picImage.getWidth(), picImage.getHeight());
// 條形碼默認(rèn)居中顯示
int codeStartX = (pictureWidth - codeImage.getWidth()) / 2;
int codeStartY = (pictureHeight - codeImage.getHeight()) / 2 + 2 * margin;
// 畫條形碼到新的面板
g2d.drawImage(codeImage, codeStartX, codeStartY, codeImage.getWidth(), codeImage.getHeight(), null);
// 給條碼上下各畫一條線
// 設(shè)置顏色
g2d.setColor(Color.LIGHT_GRAY);
int y1 = 2 * margin + codeImage.getHeight();
int y2 = 2 * margin + 2 * codeImage.getHeight();
g2d.drawLine(0, y1, pictureWidth, y1);
g2d.drawLine(0, y2, pictureWidth, y2);
// 畫文字到新的面板
g2d.setColor(Color.BLACK);
// 字體、字型、字號(hào)
g2d.setFont(new Font("微軟雅黑", Font.PLAIN, fontSize));
// 文字與條形碼之間的間隔
int wordAndCodeSpacing = 3;
// 底部文字(居中)
if (StringUtils.isNotEmpty(bottomStr)) {
// 文字長(zhǎng)度
int strWidth = g2d.getFontMetrics().stringWidth(bottomStr);
// 文字X軸開始坐標(biāo)
int strStartX = (pictureWidth - strWidth) / 2;
if (strStartX < margin) {
strStartX = margin;
}
// 文字Y軸開始坐標(biāo)
int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing;
// 畫文字
g2d.drawString(bottomStr, strStartX, strStartY);
}
// 右上角文字
if (StringUtils.isNotEmpty(topRightStr)) {
// 文字長(zhǎng)度
int strWidth = g2d.getFontMetrics().stringWidth(topRightStr);
// 文字X軸開始坐標(biāo)
int strStartX = pictureWidth - strWidth - margin;
// 文字Y軸開始坐標(biāo)
int strStartY = margin + fontSize;
// 畫文字
g2d.drawString(topRightStr, strStartX, strStartY);
}
// 標(biāo)題文字(居中)
if (StringUtils.isNotEmpty(titleStr)) {
// 字體、字型、字號(hào)
int fs = (int) Math.ceil(fontSize * 1.5);
g2d.setFont(new Font("微軟雅黑", Font.PLAIN, fs));
// 文字長(zhǎng)度
int strWidth = g2d.getFontMetrics().stringWidth(titleStr);
// 文字X軸開始坐標(biāo)
int strStartX = (pictureWidth - strWidth) / 2;
if (strStartX < margin) {
strStartX = margin;
}
// 文字Y軸開始坐標(biāo)
int strStartY = codeStartY - margin;
// 畫文字
g2d.drawString(titleStr, strStartX, strStartY);
}
g2d.dispose();
picImage.flush();
return picImage;
}
/**
* 設(shè)置 Graphics2D 屬性 (抗鋸齒)
*
* @param g2d Graphics2D提供對(duì)幾何形狀、坐標(biāo)轉(zhuǎn)換、顏色管理和文本布局更為復(fù)雜的控制
*/
private static void setGraphics2D(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
g2d.setStroke(s);
}
/**
* 設(shè)置背景為白色
*
* @param g2d Graphics2D提供對(duì)幾何形狀、坐標(biāo)轉(zhuǎn)換、顏色管理和文本布局更為復(fù)雜的控制
*/
private static void setColorWhite(Graphics2D g2d, int width, int height) {
g2d.setColor(Color.WHITE);
// 填充整個(gè)屏幕
g2d.fillRect(0, 0, width, height);
// 設(shè)置筆刷
g2d.setColor(Color.BLACK);
}
/**
* 創(chuàng)建小號(hào)條形碼(250x150)
*
* @param code
* @param name
* @return
*/
private static BufferedImage createSmallWithWords(@NonNull String code, @NonNull String name) {
// 條形碼底部?jī)?nèi)容
String bottomStr = code;
// 條形碼左上角內(nèi)容
//String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
String topLeftStr = name;
// 條形碼右上角內(nèi)容
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String topRightStr = dtf.format(LocalDateTime.now());
// 生成條形碼
BufferedImage barCodeImage = create(bottomStr, 250, 50);
return createWithWords(
barCodeImage,
bottomStr,
topLeftStr,
topRightStr,
250,
150,
10,
14);
}
/**
* 創(chuàng)建中號(hào)條形碼(350x210)
*
* @param code
* @param name
* @return
*/
private static BufferedImage createMiddleWithWords(@NonNull String code, @NonNull String name) {
// 條形碼底部?jī)?nèi)容
String bottomStr = code;
// 條形碼左上角內(nèi)容
//String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
String topLeftStr = name;
// 條形碼右上角內(nèi)容
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String topRightStr = dtf.format(LocalDateTime.now());
// 生成條形碼
BufferedImage barCodeImage = create(bottomStr, 350, 70);
return createWithWords(
barCodeImage,
bottomStr,
topLeftStr,
topRightStr,
350,
210,
14,
20);
}
/**
* 創(chuàng)建大號(hào)條形碼(500x300)
*
* @param code
* @param name
* @return
*/
private static BufferedImage createBigWithWords(@NonNull String code, @NonNull String name) {
// 條形碼底部?jī)?nèi)容
String bottomStr = code;
// 條形碼左上角內(nèi)容
//String topLeftStr = name.length() < 11 ? name : name.substring(0, 11);
String topLeftStr = name;
// 條形碼右上角內(nèi)容
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String topRightStr = dtf.format(LocalDateTime.now());
// 生成條形碼
BufferedImage barCodeImage = create(bottomStr, 500, 100);
return createWithWords(
barCodeImage,
bottomStr,
topLeftStr,
topRightStr,
500,
300,
20,
28);
}
/**
* 生成條形碼(帶文字)
*
* @param code 編碼內(nèi)容
* @param name 名稱
* @param size 規(guī)格:小中大
* @return
*/
public static BufferedImage createWithWords(
@NonNull String code,
@NonNull String name,
@NonNull Size size
) {
switch (size) {
case SMALL:
return createSmallWithWords(code, name);
case MIDDLE:
return createMiddleWithWords(code, name);
case BIG:
default:
return createBigWithWords(code, name);
}
}
}
// ====================== 二維碼內(nèi)部類 ========================
/**
* 二維碼
*/
public static class QrCode {
/**
* 生成二維碼(正方形)
*
* @param content
* @param sideLength 邊長(zhǎng)(px)
* @return
*/
public static BufferedImage create(String content, int sideLength) {
BitMatrix matrix = null;
// 定義二維碼參數(shù)
Map<EncodeHintType, Object> hints = new HashMap<>(3);
// 設(shè)置編碼
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 設(shè)置容錯(cuò)等級(jí)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 設(shè)置邊距,默認(rèn)為5
hints.put(EncodeHintType.MARGIN, 3);
try {
matrix = new MultiFormatWriter()
.encode(content, BarcodeFormat.QR_CODE, sideLength, sideLength, hints);
} catch (Exception e) {
e.printStackTrace();
//throw new RuntimeException("條形碼內(nèi)容寫入失敗");
}
return MatrixToImageWriter.toBufferedImage(matrix);
}
public static BufferedImage create(String content, Size size) {
switch (size) {
case SMALL:
return create(content, 250);
case MIDDLE:
return create(content, 350);
case BIG:
default:
return create(content, 500);
}
}
}
// ======================== 存入文件 =========================
/**
* 存入文件
*
* @param barCodeImage
* @return 文件名
*/
public static String toFile(BufferedImage barCodeImage) {
String fileName = getFileName();
boolean isWrite = false;
try {
FileOutputStream outputStream = new FileOutputStream(new File(getImageDir(), fileName));
isWrite = ImageIO.write(barCodeImage, "png", outputStream);
} catch (IOException e) {
e.printStackTrace();
}
if (isWrite) {
return fileName;
}
return "";
}
/**
* 得到圖片存放目錄
* 類路徑下的image文件夾
*
* @return
*/
private static String getImageDir() {
String imageDir = "";
Resource resource = new ClassPathResource("");
try {
String _dir = resource.getFile().getAbsolutePath();
File file = new File(_dir, "image");
if (!file.exists()) {
file.mkdirs();
}
imageDir = file.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
return imageDir;
}
/**
* 生成文件名
* 當(dāng)前時(shí)間戳 + 兩位隨機(jī)數(shù)
*
* @return
*/
private static String getFileName() {
// 當(dāng)前時(shí)間戳
long second = Instant.now().getEpochSecond();
// 兩位隨機(jī)數(shù)
ThreadLocalRandom r = ThreadLocalRandom.current();
int rand = r.nextInt(10, 99);
return new StringBuffer().append(second).append(rand).append(".png").toString();
}
// ======================= 識(shí)別圖形碼 ========================
/**
* 識(shí)別圖形碼(條形碼/二維碼)
* ***********************************************
* ------ 條形碼 ----------------------------------
* 可以識(shí)別內(nèi)容:手機(jī)號(hào)、純數(shù)字、字母數(shù)字、網(wǎng)址(中大號(hào))
* 識(shí)別不了小號(hào)(250x150)含文字的網(wǎng)址條形碼
* 存儲(chǔ)網(wǎng)址時(shí)用二維碼,不要使用條形碼
* ***********************************************
* ------ 二維碼 ----------------------------------
* 比條形碼有優(yōu)勢(shì);能識(shí)別三種尺寸的網(wǎng)址二維碼
* ***********************************************
*
* @param imageCode 圖形碼文件
* @return void
*/
public static String scan(File imageCode) {
String text = "";
try {
BufferedImage image = ImageIO.read(imageCode);
if (image == null) {
return text;
}
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Map<DecodeHintType, Object> hints = new HashMap<>(3);
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
Result result = new MultiFormatReader().decode(bitmap, hints);
text = result.getText();
} catch (Exception e) {
e.printStackTrace();
System.out.println("無法識(shí)別");
}
return text;
}
public static String scan(String fileName) {
return scan(new File(getImageDir(), fileName));
}
public static String scan(String fileName, String fileParent) {
return scan(new File(fileParent, fileName));
}
}
參考自:Java生成讀取條形碼及二維碼文章來源地址http://www.zghlxwxcb.cn/news/detail-478075.html
到了這里,關(guān)于java生成、識(shí)別條形碼和二維碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!