引入依赖
Gradle
implementation 'com.google.zxing:core:3.4.1'
Maven
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>示例代码
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import java.awt.geom.AffineTransform
import java.awt.image.BufferedImage
object QrUtil {
private val mfw = MultiFormatWriter()
private val encodeHints = object : HashMap<EncodeHintType, Any>() {
init {
put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H)
put(EncodeHintType.CHARACTER_SET, Charsets.UTF_8)
put(EncodeHintType.MARGIN, 1)
}
}
private val decodeHints = object : HashMap<DecodeHintType, Any>() {
init {
put(DecodeHintType.CHARACTER_SET, Charsets.UTF_8)
//优化精度
put(DecodeHintType.TRY_HARDER, true)
//复杂模式,开启PURE_BARCODE模式
put(DecodeHintType.PURE_BARCODE, true)
}
}
/**
* 生成二维码
*
* 若宽/高小于生成的二维码的最小宽度则会忽略此宽/高度, 否则会生成此宽/高度的二维码图片
*
* @param content 正文
* @param width 目标图片宽度
* @param height 目标图片高度
* @param color1 二维码颜色
* @param color2 二维码背景
* @return 二维码图片
*/
@Throws(WriterException::class)
fun getQrImage(
content: String,
width: Int,
height: Int,
color1: Int,
color2: Int,
): BufferedImage {
val bitMatrix = mfw.encode(content, BarcodeFormat.QR_CODE, width, height, encodeHints)
val w = bitMatrix.width
val h = bitMatrix.height
val image = BufferedImage(w, h, 1)
for (x in 0 until w) for (y in 0 until h) image.setRGB(x, y, if (bitMatrix[x, y]) color1 else color2)
return image
}
/**
* 识别二维码
*
* @param image 要识别的图片
* @return 识别的结果
*/
@Throws(NotFoundException::class)
fun decode(image: BufferedImage): String {
val source = BufferedImageLuminanceSource(image)
val bitmap = BinaryBitmap(HybridBinarizer(source))
return MultiFormatReader().decode(bitmap, decodeHints).text
}
class BufferedImageLuminanceSource(
image: BufferedImage,
left: Int = 0,
top: Int = 0,
width: Int = image.width,
height: Int = image.height,
) :
LuminanceSource(width, height) {
private val image: BufferedImage
private val left: Int
private val top: Int
override fun getRow(y: Int, rowBytes: ByteArray): ByteArray {
var row = rowBytes
require(!(y < 0 || y >= height)) { "Requested row is outside the image: $y" }
if (row.size < width) row = ByteArray(width)
image.raster.getDataElements(left, top + y, width, 1, row)
return row
}
override fun getMatrix(): ByteArray {
val width = width
val height = height
val area = width * height
val matrix = ByteArray(area)
image.raster.getDataElements(left, top, width, height, matrix)
return matrix
}
override fun isCropSupported() = true
override fun crop(left: Int, top: Int, width: Int, height: Int) =
BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height)
override fun isRotateSupported() = true
override fun rotateCounterClockwise(): LuminanceSource {
val sourceWidth = image.width
val sourceHeight = image.height
val transform = AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth.toDouble())
val rotatedImage = BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY)
val g = rotatedImage.createGraphics()
g.drawImage(image, transform, null)
g.dispose()
val width = width
return BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), height, width)
}
init {
val sourceWidth = image.width
val sourceHeight = image.height
require(!(left + width > sourceWidth || top + height > sourceHeight)) { "Crop rectangle does not fit within image data." }
for (y in top until top + height) {
for (x in left until left + width) {
if (image.getRGB(x, y) and -0x1000000 == 0) {
image.setRGB(x, y, -0x1) // = white
}
}
}
this.image = BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY)
this.image.graphics.drawImage(image, 0, 0, null)
this.left = left
this.top = top
}
}
}