| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- package com.railway.common.utils;
- import com.google.zxing.BarcodeFormat;
- import com.google.zxing.BinaryBitmap;
- import com.google.zxing.DecodeHintType;
- import com.google.zxing.EncodeHintType;
- import com.google.zxing.MultiFormatReader;
- import com.google.zxing.MultiFormatWriter;
- import com.google.zxing.Result;
- import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
- import com.google.zxing.common.BitMatrix;
- import com.google.zxing.common.HybridBinarizer;
- import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
- import java.awt.BasicStroke;
- import java.awt.Color;
- import java.awt.Font;
- import java.awt.FontMetrics;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.Image;
- import java.awt.RenderingHints;
- import java.awt.Shape;
- import java.awt.font.FontRenderContext;
- import java.awt.font.LineMetrics;
- import java.awt.geom.RoundRectangle2D;
- import java.awt.image.BufferedImage;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.OutputStream;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.Hashtable;
- import java.util.List;
- import javax.imageio.ImageIO;
- import lombok.extern.slf4j.Slf4j;
- import sun.font.FontDesignMetrics;
- import sun.misc.BASE64Encoder;
- /**
- * @author ZhaoMn
- */
- @Slf4j
- public class QrCodeUtil {
- private static final String CHARSET = "utf-8";
- private static final String FORMAT_NAME = "JPG";
- /** 二维码尺寸 */
- private static final int QRCODE_SIZE = 300;
- /** LOGO宽度 */
- private static final int WIDTH = 60;
- /** LOGO高度 */
- private static final int HEIGHT = 60;
- /** 字体大小 */
- private static final int FONT_SIZE = 18;
- /** 字体高度 */
- private static final int FONT_HEIGHT = 30;
- private static BufferedImage createImage(String content, List<String> bottomDes, String imgPath,
- boolean needCompress) throws Exception {
- Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
- hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
- hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
- hints.put(EncodeHintType.MARGIN, 1);
- BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE,
- QRCODE_SIZE, QRCODE_SIZE, hints);
- int width = bitMatrix.getWidth();
- int height = bitMatrix.getHeight();
- int tempHeight = height;
- boolean needDescription = (null != bottomDes && bottomDes.size() > 0);
- if (needDescription) {
- tempHeight += (FONT_HEIGHT * bottomDes.size());
- }
- BufferedImage image = new BufferedImage(width, tempHeight, BufferedImage.TYPE_INT_RGB);
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; y++) {
- image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
- }
- }
- // 插入图片
- if (imgPath != null && !"".equals(imgPath)) {
- insertImage(image, imgPath, needCompress);
- }
- //添加底部文字
- if (needDescription) {
- addFontImage(image, bottomDes);
- }
- return image;
- }
- private static BufferedImage createImage(String content, String bottomDes, String imgPath,
- boolean needCompress) throws Exception {
- return createImage(content, Collections.singletonList(bottomDes), imgPath, needCompress);
- }
- /**
- * 添加 底部图片文字
- *
- * @param source 图片源
- * @param declareText 文字本文
- */
- private static void addFontImage(BufferedImage source, List<String> declareText) {
- Graphics2D graph = source.createGraphics();
- //开启文字抗锯齿
- graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- for(int i = 0; i < declareText.size(); i ++){
- String declare = declareText.get(i);
- BufferedImage textImage = strToImage(declare);
- int width = textImage.getWidth(null);
- int height = textImage.getHeight(null);
- int y = QRCODE_SIZE + (declareText.size() * 20) - ((declareText.size() - i - 1) * FONT_HEIGHT);
- graph.drawImage(textImage, 0, y, width, height, null);
- }
- graph.dispose();
- }
- public static void main(String[] args) {
- try {
- String qcode = "LKDSLSFD2412341234";
- String toolName = "名称";
- List<String> bottomDes = Arrays.asList("长春西高铁综合车间", "存放处",
- toolName + " - " + "2314321412");
- encode(qcode, bottomDes, "D:/" + DateUtils.dateTimeNow() + ".jpg");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private static BufferedImage strToImage(String str) {
- BufferedImage textImage = new BufferedImage(QRCODE_SIZE, FONT_HEIGHT, BufferedImage.TYPE_INT_RGB);
- Graphics2D g2 = (Graphics2D) textImage.getGraphics();
- //开启文字抗锯齿
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- g2.setBackground(Color.WHITE);
- g2.clearRect(0, 0, QRCODE_SIZE, FONT_HEIGHT);
- g2.setPaint(Color.BLACK);
- FontRenderContext context = g2.getFontRenderContext();
- Font font = new Font("宋体", Font.BOLD, FONT_SIZE);
- g2.setFont(font);
- LineMetrics lineMetrics = font.getLineMetrics(str, context);
- FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
- float offset = ((float) QRCODE_SIZE - fontMetrics.stringWidth(str)) / 2;
- float y =
- (FONT_HEIGHT + lineMetrics.getAscent() - lineMetrics.getDescent() - lineMetrics.getLeading())
- / 2;
- g2.drawString(str, (int) offset, (int) y);
- return textImage;
- }
- private static void insertImage(BufferedImage source, String imgPath, boolean needCompress)
- throws Exception {
- File file = new File(imgPath);
- if (!file.exists()) {
- System.err.println("" + imgPath + " 该文件不存在!");
- return;
- }
- Image src = ImageIO.read(new File(imgPath));
- int width = src.getWidth(null);
- int height = src.getHeight(null);
- // 压缩LOGO
- if (needCompress) {
- if (width > WIDTH) {
- width = WIDTH;
- }
- if (height > HEIGHT) {
- height = HEIGHT;
- }
- Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
- BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics g = tag.getGraphics();
- // 绘制缩小后的图
- g.drawImage(image, 0, 0, null);
- g.dispose();
- src = image;
- }
- // 插入LOGO
- Graphics2D graph = source.createGraphics();
- int x = (QRCODE_SIZE - width) / 2;
- int y = (QRCODE_SIZE - height) / 2;
- graph.drawImage(src, x, y, width, height, null);
- Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
- graph.setStroke(new BasicStroke(3f));
- graph.draw(shape);
- graph.dispose();
- }
- public static void encode(String content, String bottomDes, String imgPath, String destPath,
- boolean needCompress) throws Exception {
- BufferedImage image = createImage(content, bottomDes, imgPath, needCompress);
- mkdirs(destPath);
- ImageIO.write(image, FORMAT_NAME, new File(destPath));
- }
- /**
- * 获取二维码base64数据,转回图片时前面加上 data:image/png;base64,
- */
- public static String encodeStr(String content, List<String> bottomDes) throws Exception {
- BufferedImage image = createImage(content, bottomDes, null, false);
- //io流
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- //写入流中
- ImageIO.write(image, FORMAT_NAME, baos);
- //转换成字节
- byte[] bytes = baos.toByteArray();
- BASE64Encoder encoder = new BASE64Encoder();
- //转换成base64串
- String jpgBase64 = encoder.encodeBuffer(bytes).trim();
- //删除 \r\n
- jpgBase64 = jpgBase64.replaceAll("\n", "").replaceAll("\r", "");
- return jpgBase64;
- }
- public static BufferedImage encode(String content, String bottomDes, String imgPath,
- boolean needCompress) throws Exception {
- return createImage(content, bottomDes, imgPath, needCompress);
- }
- public static void mkdirs(String destPath) throws Exception {
- File file = new File(destPath);
- // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
- if (!file.exists() && !file.isDirectory()) {
- if(!file.mkdirs()){
- throw new Exception(destPath + ", 创建失败");
- }
- }
- }
- public static void encode(String content, List<String> bottomDes, String destPath)
- throws Exception {
- BufferedImage image = createImage(content, bottomDes, destPath, false);
- mkdirs(destPath);
- ImageIO.write(image, FORMAT_NAME, new File(destPath));
- }
- public static void encode(String content, String bottomDes, String imgPath, String destPath)
- throws Exception {
- encode(content, bottomDes, imgPath, destPath, false);
- }
- public static void encode(String content, String bottomDes, String destPath) throws Exception {
- encode(content, bottomDes, null, destPath, false);
- }
- public static void encode(String content, String bottomDes, String imgPath, OutputStream output,
- boolean needCompress) throws Exception {
- BufferedImage image = createImage(content, bottomDes, imgPath, needCompress);
- ImageIO.write(image, FORMAT_NAME, output);
- }
- public static void encode(String content, String bottomDes, OutputStream output)
- throws Exception {
- encode(content, bottomDes, null, output, false);
- }
- public static String decode(File file) throws Exception {
- BufferedImage image;
- image = ImageIO.read(file);
- if (image == null) {
- return null;
- }
- BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
- BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
- Result result;
- Hashtable<DecodeHintType, Object> hints = new Hashtable<>();
- hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
- result = new MultiFormatReader().decode(bitmap, hints);
- return result.getText();
- }
- public static String decode(String path) throws Exception {
- return decode(new File(path));
- }
- }
|