原文地址: JavaFx 生成二维码工具类封装 - Stars-One的杂货小窝
之前星之音乐下载器有需要生成二维码功能,当时用的是一个开源库来实现的,但是没过多久,发现那个库依赖太多,有个http-client的依赖,把软件都搞大了一倍,而且有时候开发的时候下载依赖还报错,就想换个方案
于是在网上找了下解决方案,最终只需要依赖两个zxing的两个依赖即可实现功能
本文基于TornadoFx框架进行编写,封装工具代码是kotlin版本,工具类已经封装在common-controls库中
工具支持带logo图标,带底部文本的二维码生成
代码封装
1.引入依赖
- <dependency>
- <groupId>com.google.zxing</groupId>
- <artifactId>core</artifactId>
- <version>3.5.0</version>
- </dependency>
- <dependency>
- <groupId>com.google.zxing</groupId>
- <artifactId>javase</artifactId>
- <version>3.5.0</version>
- </dependency>
复制代码 2.使用
由于工具代码过多不便阅读,就先讲些使用,工具代码就放下面了
比较核心的就两个方法,如下面代码所示,其他的方法是带Swing关键字,就是生成Swing包中的Image对象
getQRcodeFxImg()方法就是直接生成Fx的Image对象,可以JavaFx中直接使用- /**
- * 初始化设置
- *
- * @param qrcodeSize 二维码尺寸,默认为320(即320*320)
- * @param logoSize logo图标尺寸,默认为80(即80*80)
- * @param bottomTextSize 底部文字大小,默认20px
- * @param qrcodeType 二维码图片格式,默认为png
- */
- fun initConfig(qrcodeSize: Int = 320, logoSize: Int = 80, bottomTextSize: Int = 20, qrcodeType: String = "PNG")
- /**
- * 生成二维码图片
- *
- * @param data 二维码文本内容
- * @param logoPath 图标图片的路径
- * @param bottomText 底部文字
- * @return fx的img对象
- */
- fun getQRcodeFxImg(data: String?, logoPath: String?=null, bottomText: String?=null): WritableImage
复制代码 使用的话也比较简单:- //得到的swing的image对象
- val buImg = QRCodeUtil.getQRcodeFxImg("这是测试文本")
- val buImg1 = QRCodeUtil.getQRcodeFxImg("这是测试文本", null, "底部文字")
- val buImg2 = QRCodeUtil.getQRcodeFxImg("这是测试文本", "/x5.jpg", "底部文字")
- val list = listOf(buImg, buImg1, buImg2)
- hbox(20.0) {
- list.forEach {
- imageview(it) {
- fitWidth = 200.0
- fitHeight = 200.0
- }
- }
- }
复制代码 3.工具库代码
- /**
- * 二维码生成工具类
- * Created by stars-one
- */
- object QRCodeUtil {
- private var QRCODE_SIZE = 320 // 二维码尺寸,宽度和高度均是320
- private var LOGO_SIZE = 80 // 二维码里logo的尺寸,宽高一致 80*80
- private var BOTTOM_TEXT_SIZE = 20 // 底部文本的文字大小
- private var FORMAT_TYPE = "PNG" // 二维码图片类型
- /**
- * 初始化设置
- *
- * @param qrcodeSize 二维码尺寸,默认为320(即320*320)
- * @param logoSize logo图标尺寸,默认为80(即80*80)
- * @param bottomTextSize 底部文字大小,默认20px
- * @param qrcodeType 二维码图片格式,默认为png
- */
- fun initConfig(qrcodeSize: Int = 320, logoSize: Int = 80, bottomTextSize: Int = 20, qrcodeType: String = "PNG") {
- QRCODE_SIZE = qrcodeSize
- LOGO_SIZE = logoSize
- BOTTOM_TEXT_SIZE = bottomTextSize
- FORMAT_TYPE = qrcodeType
- }
- /**
- * 生成二维码图片
- *
- * @param data 二维码文本内容
- * @param logoPath 图标图片的路径
- * @param bottomText 底部文字
- * @return
- */
- fun getQRcodeFxImg(data: String?, logoPath: String?=null, bottomText: String?=null): WritableImage {
- val resources = ResourceLookup(this)
- val url = if (logoPath == null) {
- null
- } else {
- resources.url(logoPath)
- }
- val swingImg = getQRCodeSwingImg(data, url, bottomText)
- return SwingFXUtils.toFXImage(swingImg,null)
- }
- /**
- * 默认需要logo,无底部文字
- * 返回 BufferedImage 可以使用ImageIO.write(BufferedImage, "png", outputStream);输出
- *
- * @param dataStr
- * @return 返回 BufferedImage 可以使用ImageIO.write(BufferedImage, "png", outputStream);输出
- */
- @Throws(Exception::class)
- fun getQRCodeSwingImg(dataStr: String?): BufferedImage {
- return getQRCodeSwingImg(dataStr, null, null)
- }
- /**
- * 默认需要logo,无底部文字
- *
- * @param dataStr
- * @return 返回字节数组
- */
- @Throws(Exception::class)
- fun getQRCodeByte(dataStr: String?): ByteArray {
- val bufferedImage = getQRCodeSwingImg(dataStr, null, null)
- val outputStream = ByteArrayOutputStream()
- ImageIO.write(bufferedImage, FORMAT_TYPE, outputStream)
- return outputStream.toByteArray()
- }
- /**
- * 默认需要logo,包含底部文字 文字为空则不显示文字
- * 返回 BufferedImage 可以使用ImageIO.write(BufferedImage, "png", outputStream);输出
- *
- * @param dataStr
- * @return
- */
- @Throws(Exception::class)
- fun getQRCodeSwingImg(dataStr: String?, bottomText: String?): BufferedImage {
- return getQRCodeSwingImg(dataStr, null, bottomText)
- }
- /**
- * 默认需要logo,包含底部文字 文字为空则不显示文字
- *
- * @param dataStr
- * @return 返回字节数组
- */
- @Throws(Exception::class)
- fun getQRCodeByte(dataStr: String?, bottomText: String?): ByteArray {
- val bufferedImage = getQRCodeSwingImg(dataStr, null, bottomText)
- val outputStream = ByteArrayOutputStream()
- ImageIO.write(bufferedImage, FORMAT_TYPE, outputStream)
- return outputStream.toByteArray()
- }
- /**
- * 获取二维码图片
- *
- * @param dataStr 二维码内容
- * @param needLogo 是否需要添加logo
- * @param bottomText 底部文字 为空则不显示
- * @return
- */
- @Throws(Exception::class)
- fun getQRCodeSwingImg(dataStr: String?, url: URL?, bottomText: String?): BufferedImage {
- if (dataStr == null) {
- throw RuntimeException("未包含任何信息")
- }
- val hints = HashMap<EncodeHintType, Any?>()
- hints[EncodeHintType.CHARACTER_SET] = "utf-8" //定义内容字符集的编码
- hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L //定义纠错等级
- hints[EncodeHintType.MARGIN] = 1
- val qrCodeWriter = QRCodeWriter()
- val bitMatrix = qrCodeWriter.encode(dataStr, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints)
- val width = bitMatrix.width
- val height = bitMatrix.height
- var tempHeight = height
- if (StringUtils.isNotBlank(bottomText)) {
- tempHeight = tempHeight + 12
- }
- val image = BufferedImage(width, tempHeight, BufferedImage.TYPE_INT_RGB)
- for (x in 0 until width) {
- for (y in 0 until height) {
- image.setRGB(x, y, if (bitMatrix[x, y]) -0x1000000 else -0x1)
- }
- }
- // 判断是否添加logo
- if (url != null) {
- insertLogoImage(image, url)
- }
- // 判断是否添加底部文字
- if (StringUtils.isNotBlank(bottomText)) {
- addFontImage(image, bottomText)
- }
- return image
- }
- /**
- * 插入logo图片
- *
- * @param source 二维码图片
- * @throws Exception
- */
- @Throws(Exception::class)
- private fun insertLogoImage(source: BufferedImage, url: URL) {
- var src: Image = ImageIO.read(url)
- val width = LOGO_SIZE
- val height = LOGO_SIZE
- val image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH)
- val tag = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
- val g = tag.graphics
- g.drawImage(image, 0, 0, null) // 绘制缩小后的图
- g.dispose()
- src = image
- // 插入LOGO
- val graph = source.createGraphics()
- val x = (QRCODE_SIZE - width) / 2
- val y = (QRCODE_SIZE - height) / 2
- graph.drawImage(src, x, y, width, height, null)
- val shape: Shape = RoundRectangle2D.Float(x.toFloat(), y.toFloat(), width.toFloat(), width.toFloat(), 6f, 6f)
- graph.stroke = BasicStroke(3f)
- graph.draw(shape)
- graph.dispose()
- }
- private fun addFontImage(source: BufferedImage, declareText: String?) {
- //生成image
- val defineWidth = QRCODE_SIZE
- val defineHeight = 20
- val textImage = BufferedImage(defineWidth, defineHeight, BufferedImage.TYPE_INT_RGB)
- val g2 = textImage.graphics as Graphics2D
- //开启文字抗锯齿
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
- g2.background = Color.WHITE
- g2.clearRect(0, 0, defineWidth, defineHeight)
- g2.paint = Color.BLACK
- val context = g2.fontRenderContext
- //部署linux需要注意 linux无此字体会显示方块
- val font = Font("宋体", Font.BOLD, BOTTOM_TEXT_SIZE)
- g2.font = font
- val lineMetrics = font.getLineMetrics(declareText, context)
- val fontMetrics: FontMetrics = FontDesignMetrics.getMetrics(font)
- val offset = ((defineWidth - fontMetrics.stringWidth(declareText)) / 2).toFloat()
- val y = (defineHeight + lineMetrics.ascent - lineMetrics.descent - lineMetrics.leading) / 2
- g2.drawString(declareText, offset.toInt(), y.toInt())
- val graph = source.createGraphics()
- //开启文字抗锯齿
- graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
- //添加image
- val width = textImage.getWidth(null)
- val height = textImage.getHeight(null)
- val src: Image = textImage
- graph.drawImage(src, 0, QRCODE_SIZE - 8, width, height, Color.WHITE, null)
- graph.dispose()
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |