原文地址: JavaFx 生成二維碼工具類封裝 - Stars-One的雜貨小窩 之前星之音樂下載器有需要生成二維碼功能,當時用的是一個開源庫來實現的,但是沒過多久,發現那個庫依賴太多,有個http-client的依賴,把軟體都搞大了一倍,而且有時候開發的時候下載依賴還報錯,就想換個方案 於是在網上 ...
原文地址: 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()
}
}
提問之前,請先看提問須知 點擊右側圖標發起提問 或者加入QQ群一起學習 TornadoFx學習交流群:1071184701