2021年5月27日 星期四

Android 簡單利用 ZXing 產生 QR code, 並將它解碼

 1.用 AndroidStudio 產生樣板程式, 將 ZXing 程式庫加入 build.gradle, 並按下同步鈕,像這樣:
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.5.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    implementation 'com.google.zxing:core:3.4.1'
}

2. 修改 activity_main.xml 內容,加入 ImageView 及 Button 像這樣:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        tools:ignore="MissingConstraints" />
    <Button
        android:id="@+id/bgButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="left|center_vertical"
        android:textAllCaps="false"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/sample_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> 

3.修改主程式 MainActivity.kt , 像這樣:

package com.example.zxex1
import android.content.pm.ActivityInfo
import android.graphics.*
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
class MainActivity : AppCompatActivity() {
    private val qrBitmap = {text: String, square: Int ->
        val intArray = IntArray(square * square)
        try {//產生 QR code
            val bCode = MultiFormatWriter().encode(text,
                BarcodeFormat.QR_CODE,
                square,
                square,
                mapOf(EncodeHintType.CHARACTER_SET to "UTF8")
            )
            var k = 0
            for (row in 0 until square) {
                for (col in 0 until square) {
                    if (! bCode[row, col]) intArray[k + col] = Color.WHITE
                }
                k += square // next row
            }
        } catch (e:IllegalArgumentException) {  }
        Bitmap.createBitmap(intArray,
            square,
            square,
            Bitmap.Config.ARGB_8888
        )
    }
    private val painter = Paint() .apply {
        textAlign   = Paint.Align.CENTER
        style       = Paint.Style.STROKE
        color       = Color.RED
        textSize    = 24f
        strokeWidth = 4f
        isAntiAlias = true
    }
    private val shrinkSize = 640
    private val bgGround = Bitmap.createBitmap (
            shrinkSize,
            shrinkSize,
            Bitmap.Config.ARGB_8888
        )  .apply {            
            val centerX= width.toFloat() / 2
            val centerY= height.toFloat() / 2
            val left = centerX / 2     - 4// = 1 unit = 1/4
            val top  = centerY / 2     - 4// = 1 unit = 1/4
            val right= centerX * 3 / 2 + 4// = 3 unit = 3/4
            val down = centerY * 3 / 2 + 4// = 3 unit = 3/4
            Canvas(this).drawRect(left, top, right, down, painter)
        }
    private lateinit var bgButton:Button
    private lateinit var bgImageView:ImageView
    private fun testQRcode(code: String = "中文也可以") {
        try {
            val sqrSize= shrinkSize/2
            val sRGB = IntArray(sqrSize * sqrSize)
            val qrCode = qrBitmap(code, sqrSize) .apply { // 正方形
                getPixels(sRGB, 0, sqrSize, 0, 0, sqrSize, sqrSize)
            }// 解析 QR code
            MultiFormatReader()
                .decode (BinaryBitmap (HybridBinarizer (RGBLuminanceSource (
                    sqrSize, sqrSize, sRGB
                )))) .text ?. also { qrText -> // 成功解出文字
                Bitmap.createBitmap(bgGround) .apply {
                    val x = width.toFloat()/4
                    val y = height.toFloat()/4
                    Canvas(this).drawBitmap(qrCode, x, y, painter)
                    bgImageView.setImageBitmap(this)// 顯示合成照
                }
                bgButton.apply {
                    setTextColor(Color.GREEN)
                    text = qrText
                }
            }            
        } catch (e: Exception) {// QR code not found exception
            bgImageView.setImageBitmap(bgGround)
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        if (savedInstanceState == null) {
            findViewById<TextView>(R.id.sample_text).text = "Hello"
            bgImageView = findViewById<ImageView>(R.id.imageView)
            bgButton = findViewById<Button>(R.id.bgButton).apply{
                background = GradientDrawable() .apply {
                    cornerRadius = 24f
                    setColor(Color.GREEN)
                }
                isAllCaps = false
                textSize = 24f
                val scanHint= "掃描 QR code"
                var id = 0
                text = scanHint
                setTextColor(Color.RED)
                setOnClickListener { _->
                    text = scanHint
                    setTextColor(Color.RED)
                    testQRcode("數字(${id ++})")
                }
            }
        }
        testQRcode()
    }
    override fun onResume(){ super.onResume()  }
    override fun onPause() {  super.onPause() }
}

4. 編譯並上傳到手機上執行看看

沒有留言:

張貼留言

使用 pcie 轉接器連接 nvme SSD

之前 AM4 主機板使用 pcie ssd, 但主機板故障了沒辦法上網, 只好翻出以前買的 FM2 舊主機板, 想辦法讓老主機復活, 但舊主機板沒有 nvme 的界面, 因此上網買了 pcie 轉接器用來連接 nvme ssd, 遺憾的是 grub2 bootloader 無法識...