原文地址: JavaFx 生成二维码工具类封装 - Stars-One的杂货小窝

之前星之音乐下载器有需要生成二维码功能,当时用的是一个开源库来实现的,但是没过多久,发现那个库依赖太多,有个http-client的依赖,把软件都搞大了一倍,而且有时候开发的时候下载依赖还报错,就想换个方案

于是在网上找了下解决方案,最终只需要依赖两个zxing的两个依赖即可实现功能

本文基于TornadoFx框架进行编写,封装工具代码是kotlin版本,工具类已经封装在common-controls库中

工具支持带logo图标,带底部文本的二维码生成

代码封装

1.引入依赖

  1. <dependency>
  2. <groupId>com.google.zxing</groupId>
  3. <artifactId>core</artifactId>
  4. <version>3.5.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.google.zxing</groupId>
  8. <artifactId>javase</artifactId>
  9. <version>3.5.0</version>
  10. </dependency>

2.使用

由于工具代码过多不便阅读,就先讲些使用,工具代码就放下面了

比较核心的就两个方法,如下面代码所示,其他的方法是带Swing关键字,就是生成Swing包中的Image对象

getQRcodeFxImg()方法就是直接生成Fx的Image对象,可以JavaFx中直接使用

  1. /**
  2. * 初始化设置
  3. *
  4. * @param qrcodeSize 二维码尺寸,默认为320(即320*320)
  5. * @param logoSize logo图标尺寸,默认为80(即80*80)
  6. * @param bottomTextSize 底部文字大小,默认20px
  7. * @param qrcodeType 二维码图片格式,默认为png
  8. */
  9. fun initConfig(qrcodeSize: Int = 320, logoSize: Int = 80, bottomTextSize: Int = 20, qrcodeType: String = "PNG")
  10. /**
  11. * 生成二维码图片
  12. *
  13. * @param data 二维码文本内容
  14. * @param logoPath 图标图片的路径
  15. * @param bottomText 底部文字
  16. * @return fx的img对象
  17. */
  18. fun getQRcodeFxImg(data: String?, logoPath: String?=null, bottomText: String?=null): WritableImage

使用的话也比较简单:

  1. //得到的swing的image对象
  2. val buImg = QRCodeUtil.getQRcodeFxImg("这是测试文本")
  3. val buImg1 = QRCodeUtil.getQRcodeFxImg("这是测试文本", null, "底部文字")
  4. val buImg2 = QRCodeUtil.getQRcodeFxImg("这是测试文本", "/x5.jpg", "底部文字")
  5. val list = listOf(buImg, buImg1, buImg2)
  6. hbox(20.0) {
  7. list.forEach {
  8. imageview(it) {
  9. fitWidth = 200.0
  10. fitHeight = 200.0
  11. }
  12. }
  13. }

3.工具库代码

  1. /**
  2. * 二维码生成工具类
  3. * Created by stars-one
  4. */
  5. object QRCodeUtil {
  6. private var QRCODE_SIZE = 320 // 二维码尺寸,宽度和高度均是320
  7. private var LOGO_SIZE = 80 // 二维码里logo的尺寸,宽高一致 80*80
  8. private var BOTTOM_TEXT_SIZE = 20 // 底部文本的文字大小
  9. private var FORMAT_TYPE = "PNG" // 二维码图片类型
  10. /**
  11. * 初始化设置
  12. *
  13. * @param qrcodeSize 二维码尺寸,默认为320(即320*320)
  14. * @param logoSize logo图标尺寸,默认为80(即80*80)
  15. * @param bottomTextSize 底部文字大小,默认20px
  16. * @param qrcodeType 二维码图片格式,默认为png
  17. */
  18. fun initConfig(qrcodeSize: Int = 320, logoSize: Int = 80, bottomTextSize: Int = 20, qrcodeType: String = "PNG") {
  19. QRCODE_SIZE = qrcodeSize
  20. LOGO_SIZE = logoSize
  21. BOTTOM_TEXT_SIZE = bottomTextSize
  22. FORMAT_TYPE = qrcodeType
  23. }
  24. /**
  25. * 生成二维码图片
  26. *
  27. * @param data 二维码文本内容
  28. * @param logoPath 图标图片的路径
  29. * @param bottomText 底部文字
  30. * @return
  31. */
  32. fun getQRcodeFxImg(data: String?, logoPath: String?=null, bottomText: String?=null): WritableImage {
  33. val resources = ResourceLookup(this)
  34. val url = if (logoPath == null) {
  35. null
  36. } else {
  37. resources.url(logoPath)
  38. }
  39. val swingImg = getQRCodeSwingImg(data, url, bottomText)
  40. return SwingFXUtils.toFXImage(swingImg,null)
  41. }
  42. /**
  43. * 默认需要logo,无底部文字
  44. * 返回 BufferedImage 可以使用ImageIO.write(BufferedImage, "png", outputStream);输出
  45. *
  46. * @param dataStr
  47. * @return 返回 BufferedImage 可以使用ImageIO.write(BufferedImage, "png", outputStream);输出
  48. */
  49. @Throws(Exception::class)
  50. fun getQRCodeSwingImg(dataStr: String?): BufferedImage {
  51. return getQRCodeSwingImg(dataStr, null, null)
  52. }
  53. /**
  54. * 默认需要logo,无底部文字
  55. *
  56. * @param dataStr
  57. * @return 返回字节数组
  58. */
  59. @Throws(Exception::class)
  60. fun getQRCodeByte(dataStr: String?): ByteArray {
  61. val bufferedImage = getQRCodeSwingImg(dataStr, null, null)
  62. val outputStream = ByteArrayOutputStream()
  63. ImageIO.write(bufferedImage, FORMAT_TYPE, outputStream)
  64. return outputStream.toByteArray()
  65. }
  66. /**
  67. * 默认需要logo,包含底部文字 文字为空则不显示文字
  68. * 返回 BufferedImage 可以使用ImageIO.write(BufferedImage, "png", outputStream);输出
  69. *
  70. * @param dataStr
  71. * @return
  72. */
  73. @Throws(Exception::class)
  74. fun getQRCodeSwingImg(dataStr: String?, bottomText: String?): BufferedImage {
  75. return getQRCodeSwingImg(dataStr, null, bottomText)
  76. }
  77. /**
  78. * 默认需要logo,包含底部文字 文字为空则不显示文字
  79. *
  80. * @param dataStr
  81. * @return 返回字节数组
  82. */
  83. @Throws(Exception::class)
  84. fun getQRCodeByte(dataStr: String?, bottomText: String?): ByteArray {
  85. val bufferedImage = getQRCodeSwingImg(dataStr, null, bottomText)
  86. val outputStream = ByteArrayOutputStream()
  87. ImageIO.write(bufferedImage, FORMAT_TYPE, outputStream)
  88. return outputStream.toByteArray()
  89. }
  90. /**
  91. * 获取二维码图片
  92. *
  93. * @param dataStr 二维码内容
  94. * @param needLogo 是否需要添加logo
  95. * @param bottomText 底部文字 为空则不显示
  96. * @return
  97. */
  98. @Throws(Exception::class)
  99. fun getQRCodeSwingImg(dataStr: String?, url: URL?, bottomText: String?): BufferedImage {
  100. if (dataStr == null) {
  101. throw RuntimeException("未包含任何信息")
  102. }
  103. val hints = HashMap<EncodeHintType, Any?>()
  104. hints[EncodeHintType.CHARACTER_SET] = "utf-8" //定义内容字符集的编码
  105. hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L //定义纠错等级
  106. hints[EncodeHintType.MARGIN] = 1
  107. val qrCodeWriter = QRCodeWriter()
  108. val bitMatrix = qrCodeWriter.encode(dataStr, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints)
  109. val width = bitMatrix.width
  110. val height = bitMatrix.height
  111. var tempHeight = height
  112. if (StringUtils.isNotBlank(bottomText)) {
  113. tempHeight = tempHeight + 12
  114. }
  115. val image = BufferedImage(width, tempHeight, BufferedImage.TYPE_INT_RGB)
  116. for (x in 0 until width) {
  117. for (y in 0 until height) {
  118. image.setRGB(x, y, if (bitMatrix[x, y]) -0x1000000 else -0x1)
  119. }
  120. }
  121. // 判断是否添加logo
  122. if (url != null) {
  123. insertLogoImage(image, url)
  124. }
  125. // 判断是否添加底部文字
  126. if (StringUtils.isNotBlank(bottomText)) {
  127. addFontImage(image, bottomText)
  128. }
  129. return image
  130. }
  131. /**
  132. * 插入logo图片
  133. *
  134. * @param source 二维码图片
  135. * @throws Exception
  136. */
  137. @Throws(Exception::class)
  138. private fun insertLogoImage(source: BufferedImage, url: URL) {
  139. var src: Image = ImageIO.read(url)
  140. val width = LOGO_SIZE
  141. val height = LOGO_SIZE
  142. val image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH)
  143. val tag = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
  144. val g = tag.graphics
  145. g.drawImage(image, 0, 0, null) // 绘制缩小后的图
  146. g.dispose()
  147. src = image
  148. // 插入LOGO
  149. val graph = source.createGraphics()
  150. val x = (QRCODE_SIZE - width) / 2
  151. val y = (QRCODE_SIZE - height) / 2
  152. graph.drawImage(src, x, y, width, height, null)
  153. val shape: Shape = RoundRectangle2D.Float(x.toFloat(), y.toFloat(), width.toFloat(), width.toFloat(), 6f, 6f)
  154. graph.stroke = BasicStroke(3f)
  155. graph.draw(shape)
  156. graph.dispose()
  157. }
  158. private fun addFontImage(source: BufferedImage, declareText: String?) {
  159. //生成image
  160. val defineWidth = QRCODE_SIZE
  161. val defineHeight = 20
  162. val textImage = BufferedImage(defineWidth, defineHeight, BufferedImage.TYPE_INT_RGB)
  163. val g2 = textImage.graphics as Graphics2D
  164. //开启文字抗锯齿
  165. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
  166. g2.background = Color.WHITE
  167. g2.clearRect(0, 0, defineWidth, defineHeight)
  168. g2.paint = Color.BLACK
  169. val context = g2.fontRenderContext
  170. //部署linux需要注意 linux无此字体会显示方块
  171. val font = Font("宋体", Font.BOLD, BOTTOM_TEXT_SIZE)
  172. g2.font = font
  173. val lineMetrics = font.getLineMetrics(declareText, context)
  174. val fontMetrics: FontMetrics = FontDesignMetrics.getMetrics(font)
  175. val offset = ((defineWidth - fontMetrics.stringWidth(declareText)) / 2).toFloat()
  176. val y = (defineHeight + lineMetrics.ascent - lineMetrics.descent - lineMetrics.leading) / 2
  177. g2.drawString(declareText, offset.toInt(), y.toInt())
  178. val graph = source.createGraphics()
  179. //开启文字抗锯齿
  180. graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
  181. //添加image
  182. val width = textImage.getWidth(null)
  183. val height = textImage.getHeight(null)
  184. val src: Image = textImage
  185. graph.drawImage(src, 0, QRCODE_SIZE - 8, width, height, Color.WHITE, null)
  186. graph.dispose()
  187. }
  188. }

JavaFx 生成二维码工具类封装的更多相关文章

  1. iOS开发——生成二维码——工具类

    啥也不说,直接上源码,拷过去就能用.生成二维码的工具类使用方法在ProduceQRCode.h里有示例说明 分别将下面的ProduceQRCode.h和ProduceQRCode.m对应的代码考到自己 ...

  2. java生成二维码工具类

    package com.runtime.extend.utils.CodeCreate; import com.google.zxing.*;import com.google.zxing.commo ...

  3. Java使用Zxing生成、解析二维码工具类

    Zxing是Google提供的关于条码(一维码.二维码)的解析工具,提供了二维码的生成与解析的方法. 1.二维码的生成 (1).将Zxing-core.jar 包加入到classpath下. (2). ...

  4. 二维码工具类 - QrcodeUtils.java

    二维码工具类,提供多种生成二维码.解析二维码的方法,包括中间logo的二维码等方法. 源码如下:(点击下载 - QrcodeUtils.java.MatrixToImageWriterEx.java. ...

  5. java二维码工具类,中间带LOGO的,很强大

    jar包下载maven 配置: Xml代码 收藏代码 <dependency> <groupId>com.google.zxing</groupId> <ar ...

  6. java 生成微信的二维码 工具类

    package com.app.wii.util; import java.io.File;import java.io.FileInputStream;import java.io.FileOutp ...

  7. java 生成二维码工具

    二维码生成 Gitee:https://gitee.com/search?utf8=%E2%9C%93&search=qrext4j&group_id=&project_id= ...

  8. iOS开发——扫描二维码——工具类

    (代码已测试好,空闲时间更新……)

  9. 利用Spring Boot+zxing,生成二维码还能这么简单

    在网站开发中,经常会遇到要生成二维码的情况,比如要使用微信支付.网页登录等,本文分享一个Spring Boot生成二维码的例子,这里用到了google的zxing工具类. 本文目录 一.二维码简介二. ...

  10. 使用google zxing生成二维码图片

    生成二维码工具类: 1 import java.awt.geom.AffineTransform; 2 import java.awt.image.AffineTransformOp; 3 impor ...

随机推荐

  1. MySQL代替in之临时表

    如果我们正常的使用IN去查询 SELECT * FROM a JOIN b ON a.id = b.id WHERE b.tag_id IN (1,2,3,4,5,6) 这种因为in里面的参数是连续的 ...

  2. jxg项目Day4-数据库和mybatis的连接映射

    配置:yml配置文件中配置数据库的参数,还有映射的参数 1.建实体类User,属性与数据库表对应 2.Mapper包下建UserMapper,继承BaseMapper<User> 3.Se ...

  3. Fiddler之常用的操作

    Fiddler操作 一.首次安装 1.设置https Tools → Options → https 第一次选择安装证书,如图 2.无法正常显示https请求 重置所有证书,重置后会重新提示安装证书, ...

  4. 自定义DOM事件函数封装

    非原生DOM触发,个性化定制的自定义事件. currentTarget(DOM对象):要触发事件的元素节点. type(字符串):触发的事件类型,例如"keydown". bubb ...

  5. vue自动展示一、二级路由

    在vue项目中使用路由可以很方便的跳转要显示的页面 在初始页面当中,首先要显示的路由怎么实现呢? 只需要在index.js页面中存放路由的children:[...]最后加上 redirect:&qu ...

  6. 在app中如何使weib-view不铺满全屏,自适应页面

    // #ifdef APP-PLUS //自建webview var currentWebview = this.$scope.$getAppWebview(); var height = this. ...

  7. 10. XrmToolBox

    XrmToolBox是一个连接到MicrosoftDataverse的Windows应用程序,可以为任何在MicrosoftDataverse上构建的产品提供了简化定制.配置和操作任务的工具,包括Dy ...

  8. 基于element-ui进行二次封装的表格组件

    <!-- * @description 表格组件 * @fileName TableList.vue * @authorQ * @date 2021/05/15 15:13:45 --> ...

  9. 一文明白:JavaScript异步编程

    同步和异步 JS是单线程 JavaScript语言的一大特点是单线程,同一时间只能做一件事 (单线程的JS 就是一个傻子,脑子一根筋,做着当前的这件事情,没有完成之前,绝对不会做下一件事情) 当然,这 ...

  10. Python批量采集百度资讯文章,如何自定义采集日期范围

    01 引言 大家好!蜡笔小曦有个朋友是做能源相关工作的,她想要有一个工具以天为单位持续地采集百度资讯中能源相关的文章进行留存和使用. 其中有个需求点是说能够自定义采集的开始日期和结束日期,这样更加灵活 ...