最近遇上了扫描条码的需求,在查找材料过程中不是那么地顺畅,做个笔记,记录下这两篇文章,前人栽树后人乘凉。
Andorid依据ZXing完成二维码生成&扫描
Android依据MLKit完成条形码扫码
本篇文章Demo下载
ZXing介绍
说到二维码,许多的材料都会说到ZXing,详细见ZXing,这是一个用Java言语完成的1D/2D 条形码图像处理库。触及专业知识不多做介绍,这篇文章只讲运用。
二维码生成
引入ZXing中心库:
implementation 'com.google.zxing:core:3.5.1'
创立二维码位图,写了一个东西类,能够直接运用:
object QrCodeUtil {
/**
* 创立二维码位图 (支撑自定义装备和自定义款式)
* @param content 字符串内容
* @param width 位图宽度,要求>=0(单位:px)
* @param height 位图高度,要求>=0(单位:px)
* @param character_set 字符集/字符转码格局 (支撑格局:{@link CharacterSetECI })。传null时,zxing源码默许运用 "ISO-8859-1"
* @param error_correction 容错等级 (支撑等级:{@link ErrorCorrectionLevel })。传null时,zxing源码默许运用 "L"
* @param margin 空白边距 (可修正,要求:整型且>=0), 传null时,zxing源码默许运用"4"。
* @param color_black 黑色色块的自定义色彩值
* @param color_white 白色色块的自定义色彩值
* @return
*/
fun createQRCodeBitmap(
content: String,
width: Int,
height: Int,
character_set: String = "UTF-8",
error_correction: String = "H",
margin: String = "1",
@ColorInt color_black: Int = Color.BLACK,
@ColorInt color_white: Int = Color.WHITE,
): Bitmap? {
/** 1.参数合法性判别 */
if (width < 0 || height < 0) { // 宽和高都需要>=0
return null
}
try {
/** 2.设置二维码相关装备,生成BitMatrix(位矩阵)目标 */
val hints: Hashtable<EncodeHintType, String> = Hashtable()
if (character_set.isNotEmpty()) {
hints[EncodeHintType.CHARACTER_SET] = character_set // 字符转码格局设置
}
if (error_correction.isNotEmpty()) {
hints[EncodeHintType.ERROR_CORRECTION] = error_correction // 容错等级设置
}
if (margin.isNotEmpty()) {
hints[EncodeHintType.MARGIN] = margin // 空白边距设置
}
val bitMatrix =
QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
/** 3.创立像素数组,并依据BitMatrix(位矩阵)目标为数组元素赋色彩值 */
val pixels = IntArray(width * height)
for (y in 0 until height) {
for (x in 0 until width) {
if (bitMatrix[x, y]) {
pixels[y * width + x] = color_black // 黑色色块像素设置
} else {
pixels[y * width + x] = color_white // 白色色块像素设置
}
}
}
/** 4.创立Bitmap目标,依据像素数组设置Bitmap每个像素点的色彩值,之后回来Bitmap目标 */
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
return bitmap
} catch (e: WriterException) {
e.printStackTrace()
}
return null
}
}
运用到了ZXing中心功用的便是这句 QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints), 传入内容、款式、宽高以及装备。
在装备EncodeHintType.CHARACTER_SET字符格局时,咱们运用了”UTF-8″,这是为了兼容中文,ZXing源码默许运用的是”ISO-8859-1″,而”ISO-8859-1″自身是不支撑中文的。
看一下运用作用:
val imageView = findViewById<ImageView>(R.id.iv)
val bitmap = createQRCodeBitmap("你好,初次见面,请多指教!", 480, 480)
imageView.setImageBitmap(bitmap)
生成带logo小图的二维码
许多时候见到的二维码中心都会带有一个logo小图,咱们也来完成一下这样子的作用。
其实便是把两个bitmap绘制在一块,在原有的办法上补充即可,增加两个参数:
object QrCodeUtil {
/**
* 创立二维码位图 (支撑自定义装备和自定义款式)
* @param content 字符串内容
* @param width 位图宽度,要求>=0(单位:px)
* @param height 位图高度,要求>=0(单位:px)
* @param character_set 字符集/字符转码格局 (支撑格局:{@link CharacterSetECI })。传null时,zxing源码默许运用 "ISO-8859-1"
* @param error_correction 容错等级 (支撑等级:{@link ErrorCorrectionLevel })。传null时,zxing源码默许运用 "L"
* @param margin 空白边距 (可修正,要求:整型且>=0), 传null时,zxing源码默许运用"4"。
* @param color_black 黑色色块的自定义色彩值
* @param color_white 白色色块的自定义色彩值
* @param logoBitmap logo小图片
* @param logoPercent logo小图片在二维码图片中的占比大小,规模[0F,1F],超出规模->默许运用0.2F。
* @return
*/
fun createQRCodeBitmap(
content: String,
width: Int,
height: Int,
character_set: String = "UTF-8",
error_correction: String = "H",
margin: String = "1",
@ColorInt color_black: Int = Color.BLACK,
@ColorInt color_white: Int = Color.WHITE,
logoBitmap: Bitmap? = null,
logoPercent: Float = 0f
): Bitmap? {
/** 1.参数合法性判别 */
if (width < 0 || height < 0) { // 宽和高都需要>=0
return null
}
try {
/** 2.设置二维码相关装备,生成BitMatrix(位矩阵)目标 */
val hints: Hashtable<EncodeHintType, String> = Hashtable()
if (character_set.isNotEmpty()) {
hints[EncodeHintType.CHARACTER_SET] = character_set // 字符转码格局设置
}
if (error_correction.isNotEmpty()) {
hints[EncodeHintType.ERROR_CORRECTION] = error_correction // 容错等级设置
}
if (margin.isNotEmpty()) {
hints[EncodeHintType.MARGIN] = margin // 空白边距设置
}
val bitMatrix =
QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
/** 3.创立像素数组,并依据BitMatrix(位矩阵)目标为数组元素赋色彩值 */
val pixels = IntArray(width * height)
for (y in 0 until height) {
for (x in 0 until width) {
if (bitMatrix[x, y]) {
pixels[y * width + x] = color_black // 黑色色块像素设置
} else {
pixels[y * width + x] = color_white // 白色色块像素设置
}
}
}
/** 4.创立Bitmap目标,依据像素数组设置Bitmap每个像素点的色彩值,之后回来Bitmap目标 */
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
/** 5.为二维码增加logo小图标 */
if (logoBitmap != null) {
return addLogo(bitmap, logoBitmap, logoPercent)
}
return bitmap
} catch (e: WriterException) {
e.printStackTrace()
}
return null
}
private fun addLogo(srcBitmap: Bitmap?, logoBitmap: Bitmap?, logoPercent: Float): Bitmap? {
/** 1.参数合法性判别 */
if (srcBitmap == null || logoBitmap == null) {
return null
}
var percent = logoPercent
if (logoPercent < 0F || logoPercent > 1F) {
percent = 0.2F
}
/** 2. 获取原图片和Logo图片各自的宽、高值 */
val srcWidth = srcBitmap.width
val srcHeight = srcBitmap.height
val logoWidth = logoBitmap.width
val logoHeight = logoBitmap.height
/** 3. 计算画布缩放的宽高比 */
val scaleWidth = srcWidth * percent / logoWidth
val scaleHeight = srcHeight * percent / logoHeight
/** 4. 运用Canvas绘制,合成图片 */
val bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.drawBitmap(srcBitmap, 0f, 0f, null)
canvas.scale(scaleWidth, scaleHeight, (srcWidth / 2).toFloat(), (srcHeight / 2).toFloat())
canvas.drawBitmap(logoBitmap, srcWidth * 1f / 2 - logoWidth / 2, srcHeight * 1f / 2 - logoHeight / 2, null)
return bitmap
}
}
看一下运用作用:
val imageViewLogo = findViewById<ImageView>(R.id.iv_logo)
val logo = BitmapFactory.decodeResource(resources, R.drawable.cat)
val bitmapLogo = createQRCodeBitmap(
content = "你好,初次见面,请多指教!",
width = 480,
height = 480,
logoBitmap = logo,
logoPercent = 0.3f
)
imageViewLogo.setImageBitmap(bitmapLogo)
二维码扫描
凭借开源库ZXing Android Embedded完成二维码扫描。
ZXing Android Embedded是用于Android的条形码扫描库,运用ZXing进行解码。
更多的运用能够下载源码工程跑下样例检查,包括设置前后摄像头、设置扫描超时时间等,该篇文章就只介绍最基本的二维码扫描运用。
引入库:
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
运用相机扫描二维码
跳转到扫描页面后会自动开端扫描,扫描到结果后会将结果回来,onActivityResult废弃之后,运用Activity Result API获取页面回传数据,不了解Activity Result API的能够检查这篇文章Android Activity Result API运用
private val barcodeLauncher = registerForActivityResult(
ScanContract()
) { result: ScanIntentResult ->
if (result.contents == null) {
val originalIntent = result.originalIntent
if (originalIntent == null) {
Toast.makeText(this@MainActivity, "Cancelled", Toast.LENGTH_LONG).show()
} else if (originalIntent.hasExtra(Intents.Scan.MISSING_CAMERA_PERMISSION)) {
Toast.makeText(this@MainActivity, "Cancelled due to missing camera permission", Toast.LENGTH_LONG)
.show()
}
} else {
Toast.makeText(this@MainActivity, "Scanned: " + result.contents, Toast.LENGTH_LONG).show()
}
}
findViewById<Button>(R.id.bt).setOnClickListener {
barcodeLauncher.launch(ScanOptions())
}
这是运用默许的扫描页面,运用办法很简单,可是更多的情况下,咱们都需要自定义扫描页面款式。
自定义CustomScannerActivity,发动扫描时设置CaptureActivity即可:
findViewById<Button>(R.id.bt2).setOnClickListener {
val options = ScanOptions().setOrientationLocked(false).setCaptureActivity(
CustomScannerActivity::class.java
)
barcodeLauncher.launch(options)
}
详细的在自定义扫描页面中如何装备扫描view,能够参阅本篇文章Demo下载或许ZXing Android Embedded源码工程,里边有样例能够参阅,本篇文章也是参阅的里边的样例。
从相册中辨认二维码图片
在样例中并没有找到从相册中辨认二维码图片的办法,最终在issue中发现有说到同样的问题以及回答。
打开相册获取图片:
private fun openGallery() {
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT
openGalleryRequest.launch(Intent.createChooser(intent, "辨认相册二维码图片"))
}
private val openGalleryRequest =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
it.data?.data?.let { uri -> handleImage(uri) }
}
}
解析图片二维码:
private fun handleImage(uri: Uri) {
try {
val image = MediaStore.Images.Media.getBitmap(this.contentResolver, uri)
val intArray = IntArray(image.width * image.height)
image.getPixels(intArray, 0, image.width, 0, 0, image.width, image.height)
val source = RGBLuminanceSource(image.width, image.height, intArray)
val reader = MixedDecoder(MultiFormatReader())
var result = reader.decode(source)
if (result == null) {
result = reader.decode(source)
}
Toast.makeText(this@MainActivity, "Scanned: ${result?.text}", Toast.LENGTH_LONG).show()
} catch (e: Exception) {
e.printStackTrace()
}
}
上述办法从相册中辨认二维码图片,发现存在辨认失利的问题,尤其是产品条形码,运用相机扫描产品条形码是能够正常扫描辨认出来的,可是将产品条形码拍照保存进相册,运用从相册中辨认二维码图片办法,却呈现辨认失利的情况。
为此,又去查找了其他的材料,见下一篇文章Android依据MLKit完成条形码扫码
参阅文档:
www.jianshu.com/p/b275e818d…
www.jianshu.com/p/c75f16de1…
www.jianshu.com/p/b85812b6f…
github.com/journeyapps…