如何使用Zxing和Android CameraX解码条形码和QR码

时间:2019-09-26 09:00:39

标签: android kotlin zxing android-camerax

我如何集成ZXing库以使其与新的Android Jetpack CameraX一起使用?

我知道我必须构建一个ImageAnalyzer,并在其中使用 ZXing 解码 QR代码 条形码

1 个答案:

答案 0 :(得分:0)

在我为此而建立的ImageAnalyzer下方:

class ZxingQrCodeAnalyzer(
    private val onQrCodesDetected: (qrCode: Result) -> Unit
) : ImageAnalysis.Analyzer {

  companion object {
    val reader = MultiFormatReader()
  }

  /*
      https://developer.android.com/training/camerax/configuration

      Default resolution: The default target resolution setting is 640x480.

      Adjusting both target resolution and corresponding aspect ratio will result
      in a best-supported resolution under 1080p (max analysis resolution).
  */
  override fun analyze(imageProxy: ImageProxy, rotationDegrees: Int) {
    // okay - manage rotation, not needed for QRCode decoding [-;
    // okay - manage it for barcode scanning instead!!!
    try {
      imageProxy.image?.let {
        // ImageProxy uses an ImageReader under the hood:
        // https://developer.android.com/reference/androidx/camera/core/ImageProxy.html
        // That has a default format of YUV_420_888 if not changed.
        // https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888
        // https://developer.android.com/reference/android/media/ImageReader.html
        if ((it.format == ImageFormat.YUV_420_888
            || it.format == ImageFormat.YUV_422_888
            || it.format == ImageFormat.YUV_444_888)
            && it.planes.size == 3) {
          val buffer = it.planes[0].buffer // We get the luminance plane only, since we
          // want to binarize it and we don't wanna take color into consideration.
          val bytes = ByteArray(buffer.capacity())
          buffer.get(bytes)
          // Create a LuminanceSource.
          val rotatedImage = RotatedImage(bytes, imageProxy.width, imageProxy.height)

          rotateImageArray(rotatedImage, rotationDegrees)

          val source = PlanarYUVLuminanceSource(rotatedImage.byteArray,
              rotatedImage.width,
              rotatedImage.height,
              0,
              0,
              rotatedImage.width,
              rotatedImage.height,
              false)

          // Create a Binarizer
          val binarizer = HybridBinarizer(source)
          // Create a BinaryBitmap.
          val binaryBitmap = BinaryBitmap(binarizer)
          // Try decoding...
          val result: Result
          try {
            result = reader.decode(binaryBitmap)
            onQrCodesDetected(result)
          } catch (e: NotFoundException) {
            e.printStackTrace()
          }
        } else {
          // Manage other image formats
          // TODO - https://developer.android.com/reference/android/media/Image.html
        }
      }
    } catch (ise: IllegalStateException) {
      ise.printStackTrace()
    }
  }

  // 90, 180. 270 rotation
  private fun rotateImageArray(imageToRotate: RotatedImage, rotationDegrees: Int) {
    if (rotationDegrees == 0) return // no rotation
    if (rotationDegrees % 90 != 0) return // only 90 degree times rotations

    val width = imageToRotate.width
    val height = imageToRotate.height

    val rotatedData = ByteArray(imageToRotate.byteArray.size)
    for (y in 0 until height) { // we scan the array by rows
      for (x in 0 until width) {
        when (rotationDegrees) {
          90 -> rotatedData[x * height + height - y - 1] =
              imageToRotate.byteArray[x + y * width] // Fill from top-right toward left (CW)
          180 -> rotatedData[width * (height - y - 1) + width - x - 1] =
              imageToRotate.byteArray[x + y * width] // Fill from bottom-right toward up (CW)
          270 -> rotatedData[y + x * height] =
                            imageToRotate.byteArray[y * width + width - x - 1] // The opposite (CCW) of 90 degrees
        }
      }
    }

    imageToRotate.byteArray = rotatedData

    if (rotationDegrees != 180) {
      imageToRotate.height = width
      imageToRotate.width = height
    }
  }
}

private data class RotatedImage(var byteArray: ByteArray, var width: Int, var height: Int)