引入依赖
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 } } }