Barcode Detection API - Parte 2

Usando a câmera para detectar código

Desta vez usaremos TypeScript e para que isso seja feito sem alertas de erro no código, precisaremos que a API esteja devidamente tipada, porém, não temos disponível no arquivo lib.dom.ts do TypeScript. Eu mesmo escrevi um seguindo a especificação, vai servir por enquanto.

barcode.d.ts

Crie um arquivo barcode.d.ts com o conteúdo a seguir.

interface BarcodeDetector {
  new (barcodeDetectorOptions?: BarcodeDetectorOptions): BarcodeDetector;

  static getSupportedFormats(): Promise<BarcodeFormat[]>;

  detect(image: ImageBitmapSource): Promise<DetectedBarcode[]>;
}

declare var BarcodeDetector: {
  prototype: BarcodeDetector;
  new (barcodeDetectorOptions?: BarcodeDetectorOptions): BarcodeDetector;
};

interface BarcodeDetectorOptions {
  formats: BarcodeFormat;
}

interface Point2D {
  x: number
  y: number
}

interface DetectedBarcode {
  boundingBox: DOMRectReadOnly;
  rawValue: string;
  format: BarcodeFormat;
  cornerPoints: Point2D[];
}

type BarcodeFormat =
  | "aztec"
  | "code_128"
  | "code_39"
  | "code_93"
  | "codabar"
  | "data_matrix"
  | "ean_13"
  | "ean_8"
  | "itf"
  | "pdf417"
  | "qr_code"
  | "unknown"
  | "upc_a"
  | "upc_e";

Agora sim, partimos para implementação.

Basicamente o que precisamos fazer é:

  1. Capturar o stream de vídeo do dispositivo

  2. Desenhar o video em um elemento canvas

  3. Executar o método de detecção no canvas

  4. Se houver resultados, desenhar no canvas

Vamos lá!

main.ts

const stream$ = navigator.mediaDevices.getUserMedia({
  video: {facingMode: 'environment'},
})

const detector = new BarcodeDetector()

const value = new Text()
const h1 = document.createElement('h1')
h1.append(value)

const video = document.createElement('video')
video.autoplay = true

const canvas = document.createElement('canvas')
canvas.width = 640
canvas.height = 480

document.body.append(canvas, h1)

const context = canvas.getContext('2d')
if (!context) throw `context error`

Vamos separar a função draw

draw.ts

export function draw(
  context: CanvasRenderingContext2D,
  paths: Point2D[],
  color = 'lime',
  width = 3
) {
  const [topLeft, topRight, bottomRight, bottomLeft] = paths
  context.strokeStyle = color
  context.lineWidth = width

  context.beginPath()
  context.moveTo(topLeft.x, topLeft.y)
  context.lineTo(topRight.x, topRight.y)
  context.lineTo(bottomRight.x, bottomRight.y)
  context.lineTo(bottomLeft.x, bottomLeft.y)
  context.closePath()
  context.stroke()
}

De volta ao main.ts, vamos finalizar!

// ...

stream$.then((stream) => {
  video.srcObject = stream
  video.ontimeupdate = async () => {
    context.drawImage(video, 0, 0, 640, 480)

    const result = await detector.detect(canvas)

    if (result.length > 0) {
      for (const detected of result) {
        draw(context, detected.cornerPoints)
        value.textContent = detected.rawValue
      }
    }
  }
})

E então, o que achou? Espero que tenha gostado!

Abraço

Last updated