• JavaFx 生成二维码工具类封装


    本文为作者原创,允许转载,不过请在文章开头明显处注明链接和出处!!! 谢谢配合~
    作者:stars-one
    链接:https://www.cnblogs.com/stars-one/p/17359473.html

    本篇大约有6601个字,阅读预计需要8.25分钟


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

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

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

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

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

    代码封装

    1.引入依赖

    <dependency>
        <groupId>com.google.zxinggroupId>
        <artifactId>coreartifactId>
        <version>3.5.0version>
    dependency>
    <dependency>
        <groupId>com.google.zxinggroupId>
        <artifactId>javaseartifactId>
        <version>3.5.0version>
    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()
            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()
        }
    }
    
  • 相关阅读:
    [需求管理-8]:需求分析 - 商业价值评判和确认
    kafka发送消息分区选择策略详解
    如何查看微信小程序服务器域名并且修改
    【浅学Java】Bean的作用域和生命周期
    单元测试实战(三)JPA 的测试
    Linux笔试面试题
    PDF怎么编辑修改文字?
    KY90 简单密码
    【JavaEE初阶】多线程 _ 基础篇 _ 线程的概念和创建
    【在clion中配置使用和调试ros工程】
  • 原文地址:https://www.cnblogs.com/stars-one/p/17359473.html