(资料图片)
原文地址: JavaFx 生成二维码工具类封装 - Stars-One的杂货小窝
之前星之音乐下载器有需要生成二维码功能,当时用的是一个开源库来实现的,但是没过多久,发现那个库依赖太多,有个http-client的依赖,把软件都搞大了一倍,而且有时候开发的时候下载依赖还报错,就想换个方案
于是在网上找了下解决方案,最终只需要依赖两个zxing的两个依赖即可实现功能
本文基于TornadoFx框架进行编写,封装工具代码是kotlin版本,工具类已经封装在common-controls库中
工具支持带logo图标,带底部文本的二维码生成
代码封装1.引入依赖 com.google.zxing core 3.5.0 com.google.zxing javase 3.5.0 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() 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() }} 关键词: