QRCodeUtil.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package com.iotechn.unimall.data.util;
  2. import com.aliyun.oss.OSSClient;
  3. import com.aliyun.oss.model.ObjectMetadata;
  4. import com.aliyun.oss.model.PutObjectRequest;
  5. import com.google.zxing.BarcodeFormat;
  6. import com.google.zxing.EncodeHintType;
  7. import com.google.zxing.client.j2se.MatrixToImageWriter;
  8. import com.google.zxing.common.BitMatrix;
  9. import com.google.zxing.qrcode.QRCodeWriter;
  10. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
  11. import lombok.Getter;
  12. import lombok.SneakyThrows;
  13. import org.apache.http.entity.ContentType;
  14. import org.springframework.beans.factory.InitializingBean;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.beans.factory.annotation.Value;
  17. import org.springframework.core.io.ClassPathResource;
  18. import org.springframework.mock.web.MockMultipartFile;
  19. import org.springframework.stereotype.Component;
  20. import org.springframework.util.StringUtils;
  21. import org.springframework.web.multipart.MultipartFile;
  22. import sun.font.FontDesignMetrics;
  23. import javax.imageio.ImageIO;
  24. import java.awt.*;
  25. import java.awt.font.FontRenderContext;
  26. import java.awt.font.LineMetrics;
  27. import java.awt.geom.RoundRectangle2D;
  28. import java.awt.image.BufferedImage;
  29. import java.io.*;
  30. import java.nio.charset.StandardCharsets;
  31. import java.nio.file.FileSystems;
  32. import java.nio.file.Path;
  33. import java.util.HashMap;
  34. import java.util.Hashtable;
  35. import java.util.Properties;
  36. /**
  37. * @Author:chengchangjiang
  38. * @Description: 二维码Util类
  39. * @Date:Created in 9:38 2021-09-03
  40. */
  41. @Component
  42. public class QRCodeUtil implements InitializingBean {
  43. @Value("${oss.aliyun.oss.basekUrl}")
  44. private String baseUrl;
  45. @Value("${oss.aliyun.oss.bucket}")
  46. private String bucket;
  47. @Autowired
  48. private OSSClient ossClient;
  49. @Value("${oss.aliyun.oss.endpoint}")
  50. private String endpoint;
  51. private String host;
  52. @Override
  53. public void afterPropertiesSet() throws Exception {
  54. host = "http://" + bucket + "." + endpoint;
  55. }
  56. /***
  57. * 生成二维码图片并上传OSS
  58. * @param text 二维码内容
  59. * @param width 宽度
  60. * @param height 高度
  61. * @param type 类型
  62. * @param name 图片名字
  63. * @return
  64. */
  65. public String generateQRCodeImage(String text, int width, int height,String type,String name){
  66. try {
  67. QRCodeWriter qrCodeWriter = new QRCodeWriter();
  68. Hashtable<EncodeHintType, Object> hints = new Hashtable();
  69. hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
  70. BitMatrix bitMatrix = qrCodeWriter.encode(type+"="+text, BarcodeFormat.QR_CODE, width, height,hints);
  71. File file = new File( new String(("templates" + File.separator + name+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
  72. if(!file.exists()){
  73. boolean flag = file.mkdirs();
  74. }
  75. Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());
  76. MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
  77. FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());
  78. MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
  79. String result = upload(multipartFile,name);
  80. file.delete();
  81. return result;
  82. }
  83. catch (Exception e){
  84. System.out.println("二维码异常:"+e.toString());
  85. return "error";
  86. }
  87. }
  88. /**
  89. * 后台通过服务器间接传文件
  90. * @param file
  91. * @return
  92. * @throws IOException
  93. */
  94. public String upload(MultipartFile file, String sendCarNo) throws IOException {
  95. ObjectMetadata objectMetadata = new ObjectMetadata();
  96. objectMetadata.setContentLength(file.getSize());
  97. objectMetadata.setContentType(file.getContentType());
  98. PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, "QRCode/" +sendCarNo+".png", file.getInputStream(), objectMetadata);
  99. ossClient.putObject(putObjectRequest);
  100. return baseUrl + "QRCode/" + sendCarNo+".png";
  101. }
  102. private static final int QRCODE_SIZE = 320; // 二维码尺寸,宽度和高度均是320
  103. private static final String FORMAT_TYPE = "PNG"; // 二维码图片类型
  104. // //1、生成带logo和底部文字得二维码
  105. // @SneakyThrows
  106. // @GetMapping("/getQrCode1")
  107. // public void getQrCode1(HttpServletResponse response) {
  108. // ServletOutputStream os = response.getOutputStream();
  109. // BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test", "底部文字");
  110. // response.setContentType("image/png");
  111. // ImageIO.write(bufferedImage,"png",os);
  112. // }
  113. // //2、生成不带logo和底部文字得二维码
  114. // @SneakyThrows
  115. // @GetMapping("/getQrCode2")
  116. // public void getQrCode2(HttpServletResponse response) {
  117. // ServletOutputStream os = response.getOutputStream();
  118. // BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test", false);
  119. // response.setContentType("image/png");
  120. // ImageIO.write(bufferedImage,"png",os);
  121. // }
  122. // //3、生成默认带logo不带底部文字得二维码
  123. // @SneakyThrows
  124. // @GetMapping("/getQrCode3")
  125. // public void getQrCode3(HttpServletResponse response) {
  126. // ServletOutputStream os = response.getOutputStream();
  127. // BufferedImage bufferedImage = QRCodeUtil.generateQRCodeImage("test");
  128. // response.setContentType("image/png");
  129. // ImageIO.write(bufferedImage,"png",os);
  130. // }
  131. // //3、生成不带logo带底部文字得二维码
  132. // @SneakyThrows
  133. // public getQrCode3(HttpServletResponse response) {
  134. // ServletOutputStream os = response.getOutputStream();
  135. // BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test",false,
  136. // "底部文字");
  137. // response.setContentType("image/png");
  138. // ImageIO.write(bufferedImage,"png",os);
  139. // }
  140. /**
  141. * 获取二维码图片
  142. *
  143. * @param dataStr 二维码内容
  144. * @param needLogo 是否需要添加logo
  145. * @param bottomText 底部文字 为空则不显示
  146. * @return
  147. */
  148. @SneakyThrows
  149. public String getQRCodeImage(String dataStr, boolean needLogo, String bottomText ,String name) {
  150. if (dataStr == null) {
  151. throw new RuntimeException("未包含任何信息");
  152. }
  153. HashMap<EncodeHintType, Object> hints = new HashMap<>();
  154. hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //定义内容字符集的编码
  155. hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); //定义纠错等级
  156. hints.put(EncodeHintType.MARGIN, 1);
  157. QRCodeWriter qrCodeWriter = new QRCodeWriter();
  158. BitMatrix bitMatrix = qrCodeWriter.encode(dataStr, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
  159. int width = bitMatrix.getWidth();
  160. int height = bitMatrix.getHeight();
  161. int tempHeight = height;
  162. if (StringUtils.hasText(bottomText)) {
  163. tempHeight = tempHeight + 12;
  164. }
  165. BufferedImage image = new BufferedImage(width, tempHeight, BufferedImage.TYPE_INT_RGB);
  166. for (int x = 0; x < width; x++) {
  167. for (int y = 0; y < height; y++) {
  168. image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
  169. }
  170. }
  171. // 判断是否添加logo
  172. if (needLogo) {
  173. insertLogoImage(image);
  174. }
  175. // 判断是否添加底部文字
  176. if (StringUtils.hasText(bottomText)) {
  177. addFontImage(image, bottomText);
  178. }
  179. File file = new File( new String(("templates" + File.separator + name+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
  180. if(!file.exists()){
  181. boolean flag = file.mkdirs();
  182. }
  183. Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());
  184. // ByteArrayOutputStream out = new ByteArrayOutputStream();
  185. // ImageIO.write(image,"png",path);
  186. // MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
  187. //创建一个ByteArrayOutputStream
  188. ByteArrayOutputStream os = new ByteArrayOutputStream();
  189. //把BufferedImage写入ByteArrayOutputStream
  190. ImageIO.write(image, "png", os);
  191. //ByteArrayOutputStream转成InputStream
  192. InputStream input = new ByteArrayInputStream(os.toByteArray());
  193. //InputStream转成MultipartFile
  194. MultipartFile multipartFile =new MockMultipartFile("file", "file.jpg", "text/plain", input);
  195. // FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());
  196. // MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
  197. String result = upload(multipartFile,name);
  198. file.delete();
  199. return result;
  200. }
  201. /**
  202. * 插入logo图片
  203. *
  204. * @param source 二维码图片
  205. * @throws Exception
  206. */
  207. private static void insertLogoImage(BufferedImage source) throws Exception {
  208. // 默认logo放于resource/static/image目录下
  209. ClassPathResource classPathResource = new ClassPathResource("static/image/logo.png");
  210. InputStream inputStream = classPathResource.getInputStream();
  211. if (inputStream == null || inputStream.available() == 0) {
  212. return;
  213. }
  214. Image src = ImageIO.read(inputStream);
  215. int width = 30;
  216. int height = 30;
  217. Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
  218. BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  219. Graphics g = tag.getGraphics();
  220. g.drawImage(image, 0, 0, null); // 绘制缩小后的图
  221. g.dispose();
  222. src = image;
  223. // 插入LOGO
  224. Graphics2D graph = source.createGraphics();
  225. int x = (QRCODE_SIZE - width) / 2;
  226. int y = (QRCODE_SIZE - height) / 2;
  227. graph.drawImage(src, x, y, width, height, null);
  228. Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
  229. graph.setStroke(new BasicStroke(3f));
  230. graph.draw(shape);
  231. graph.dispose();
  232. }
  233. private static void addFontImage(BufferedImage source, String declareText) {
  234. //生成image
  235. int defineWidth = QRCODE_SIZE;
  236. int defineHeight = 20;
  237. BufferedImage textImage = new BufferedImage(defineWidth, defineHeight, BufferedImage.TYPE_INT_RGB);
  238. Graphics2D g2 = (Graphics2D) textImage.getGraphics();
  239. //开启文字抗锯齿
  240. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  241. g2.setBackground(Color.WHITE);
  242. g2.clearRect(0, 0, defineWidth, defineHeight);
  243. g2.setPaint(Color.BLACK);
  244. FontRenderContext context = g2.getFontRenderContext();
  245. String font_cn = getChineseFont();
  246. //部署linux需要注意 linux无此字体会显示方块
  247. Font font = new Font("宋体", Font.BOLD, 18);
  248. g2.setFont(font);
  249. LineMetrics lineMetrics = font.getLineMetrics(declareText, context);
  250. FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
  251. float offset = (defineWidth - fontMetrics.stringWidth(declareText)) / 2;
  252. float y = (defineHeight + lineMetrics.getAscent() - lineMetrics.getDescent() - lineMetrics.getLeading()) / 2;
  253. g2.drawString(declareText, (int) offset, (int) y);
  254. Graphics2D graph = source.createGraphics();
  255. //开启文字抗锯齿
  256. graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  257. //添加image
  258. int width = textImage.getWidth(null);
  259. int height = textImage.getHeight(null);
  260. Image src = textImage;
  261. graph.drawImage(src, 0, QRCODE_SIZE - 8, width, height, Color.WHITE, null);
  262. graph.dispose();
  263. }
  264. /**
  265. * 获取中文字体位置
  266. *
  267. * @return
  268. * @author xxj 2017年4月28日
  269. */
  270. private static String getChineseFont() {
  271. //宋体(对应css中的 属性 font-family: SimSun; /*宋体*/)
  272. String font1 = "templates" + File.separator + "msyh.ttc";
  273. // String font1 = "templates" + File.separator + "simsun.ttf";
  274. //判断系统类型,加载字体文件
  275. Properties prop = System.getProperties();
  276. String osName = prop.getProperty("os.name").toLowerCase();
  277. System.out.println(osName);
  278. if (osName.indexOf("linux") > -1) {
  279. font1 = "/usr/share/fonts/chinese/simsun.ttc";
  280. }
  281. else{
  282. font1 = "宋体";
  283. }
  284. return font1;
  285. }
  286. }