引入zxing成熟的二維碼生成接口,生成標準二維碼文件,透過java圖形圖像處理API為二維碼添加相關文字描述,根據需要,可以為合成後的圖片添加相關背景。範例如下圖所示:
1.先拿點位圖來說,產生二維碼圖片核心程式碼如下
/** * 定义二维码的参数 */ HashMap<EncodeHintType, Object> hints = new HashMap(); //指定字符编码为“utf-8” hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //指定二维码的纠错等级为中级 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //设置图片的边距 hints.put(EncodeHintType.MARGIN, 1); /** * 生成二维码 */ try { BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_HEIGHT, hints); Path file = new File(filePath).toPath(); MatrixToImageWriter.writeToPath(bitMatrix, format, file); } catch (Exception e) { log.error("二维码生成出错:/permitDownload: error", e); }
2.為二維碼新增文字
/** * 给二维码下方添加说明文字 * * @param image 原二维码 * @param topText 顶部说明文字 * @param downText 底部说明文字 * @return 带说明文字的二维码 */ private static BufferedImage addNote(BufferedImage image, String topText, String downText) { Image src = image.getScaledInstance(QRCODE_WIDTH, QRCODE_HEIGHT, Image.SCALE_DEFAULT); BufferedImage tag = new BufferedImage(QRCODE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = tag.createGraphics();//设置文字 g2.setColor(Color.BLACK); g2.setBackground(Color.WHITE); g2.clearRect(0,0,QRCODE_WIDTH, IMAGE_HEIGHT); //设置顶部文本并计算坐标 // 保证操作系统包含“宋体”字体,如果没有上传字体至JAVA_HOME/jre/lib/fonts下 FontMetrics fm = getFontByWidth(new Font("宋体", Font.PLAIN, DEFAULT_FONT_SIZE), topText, g2); //文字的宽度 int fontWidth = fm.stringWidth(topText); //文字高度 int fontHeight = fm.getHeight(); /** * 顶部添加文字并居中 */ g2.drawString(topText, (QRCODE_WIDTH - fontWidth) / 2, (TEXT_DEFAULT_HEIGHT - fontHeight) / 2 + fm.getFont().getSize()); /** * 绘制二维码 */ g2.drawImage(src, 0, TEXT_DEFAULT_HEIGHT, null); // 设置底部文字字体并计算坐标 // 保证操作系统包含“宋体”字体,如果没有上传字体至JAVA_HOME/jre/lib/fonts下 fm = getFontByWidth(new Font("宋体", Font.PLAIN, DEFAULT_FONT_SIZE), downText, g2); //文字的宽度 fontWidth = fm.stringWidth(downText); //文字高度 fontHeight = fm.getHeight(); /** * 添加底部文字 */ g2.drawString(downText, (QRCODE_WIDTH - fontWidth) / 2, QRCODE_HEIGHT + TEXT_DEFAULT_HEIGHT+(TEXT_DEFAULT_HEIGHT - fontHeight) / 2 + fm.getFont().getSize()); g2.dispose(); image = tag; image.flush(); return image; }
知識點: 底部文字長度會變,目前設計只放一行文字,所以根據字數多少會動態改變文字大小在一個合理區間(不至於太小無法識別),使用FontMetrics 對象,這個點會對多數同學有幫助
3.動態修改字體及大小
/** * 根据文字长度改变文字大小 * * @param font 默认字体 * @param note 文字内容 * @param g2 图像画布 * @return 处理后的字体封装 */ private static FontMetrics getFontByWidth(Font font, String note, Graphics2D g2) { FontMetrics fm = g2.getFontMetrics(font); int textWidth = fm.stringWidth(note);//文字的宽度 if (textWidth > QRCODE_WIDTH) { int fontSize = (int) ((TEMP_PARAM / textWidth) * font.getSize()); font = new Font(font.getName(), font.getStyle(), fontSize); } g2.setFont(font); return g2.getFontMetrics(font); }
4.最後一步將藍色底圖與二維碼圖片合成,就可以了。
第一步:建立畫布,需要設定畫布的寬、高,單位應該是像素
BufferedImage tag = new BufferedImage(QRCODE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
第二步驟: 在畫布上建立圖形物件Graphics2D,可以根據你對圖像知識點的了解設定如背景、前景、邊框、寬度等資訊
Graphics2D g2 = tag.createGraphics();//设置文字
第三步: 合成圖片,過程中的圖片新增順序、圖片大小、座標位置會影響最終的呈現效果,如果最終效果沒有達到設計需求,調整這三個參數一定會有所幫助
Image src = image.getScaledInstance(QRCODE_WIDTH, QRCODE_HEIGHT, Image.SCALE_DEFAULT); ... /** * 绘制二维码 */ g2.drawImage(src, 0, TEXT_DEFAULT_HEIGHT, null);
第四步: 產生最終的新圖片
/** * 给二维码图片添加背景图片 * * @param qrPic 二维码 * @param backImage 背景图片 */ private static void createNewPng(File qrPic, BufferedImage backImage) { try { if (!qrPic.isFile()) { log.error("二维码临时路径不存在!"); } /** * 读取背景图片,并构建绘图对象--画布 */ Graphics2D g = backImage.createGraphics(); /** * 读取二维码图片 */ BufferedImage qrcodeImage = ImageIO.read(qrPic); //开始绘制图片 g.drawImage(qrcodeImage, 48, 120, qrcodeImage.getWidth(), qrcodeImage.getHeight(), null); g.dispose(); ImageIO.write(backImage, "png", qrPic); } catch (Exception e) { log.error("绘制二维码出错!"); } }
第二張圖片和第一張圖片產生過程相同,只是將文中【2. 為二維碼新增文字】中的順序由上、中、下變為左、右即可
背景圖片像素、大小需要和二維碼匹配,否則會出現二維碼與背景比例嚴重失調或二維碼顯示不完整
二維碼新增文字亂碼開發環境(windows),測試環境(centos 伺服器版)。本機開發測試沒有任何問題,打包部署至伺服器後所有中文字元出現亂碼(各種轉碼,字體設置,調試整了很久),問題仍然沒有任何變化。最終靈光一現懷疑是系統字體問題,查了測試環境(centos)字體資訊確實沒有“宋體”,設定成系統自有或預設的字體,問題還在。最後從(c:\windows\fonts\simsun.ttc)開發系統中copy字體至測試系統(JAVA_HOME/jre/libs/fonts)後重新啟動應用,問題已完美解決。系統安裝部署要準備字體有點麻煩,不知道還有沒有更好的方法,字體有邏輯字體和實體字體,愛、先這樣吧。
背景圖片載入問題項目為springboot項目,背景圖片存放在resources資料夾下,本地開發測試未見異常,打包部署至伺服器後背景圖片無法找到,原始程式碼如下
String backFilePath = "template/down.png"; ClassPathResource resource = new ClassPathResource(backFilePath); File file = resource.getFile();
在網路上找載入圖片的方法都使用過,沒有效果,最後修改為輸入流,圖片合成正常,程式碼如下
/** * 必须通过流方式,否则不同操作系统无法拿到背景图片信息 */ String backFilePath = "template/down.png"; ClassPathResource resource = new ClassPathResource(backFilePath); BufferedImage bi = ImageIO.read(resource.getInputStream());
以上是java zxing怎麼合成複雜二維碼圖片的詳細內容。更多資訊請關注PHP中文網其他相關文章!