javascript

Leer código de barras con JavaScript y cámara

En este post te mostraré cómo leer códigos de barras en el navegador web ya sea de una computadora o dispositivo móvil, usando la cámara del teléfono o la cámara web; y el lenguaje nativo JavaScript.

Esto hace que podamos hacer nuestras aplicaciones web todavía más diversas y con más características; en un ejemplo simple se me ocurre escanear el código de barras para un sistema de ventas.

La librería que vamos a usar se llama QuaggaJS y es capaz de leer códigos de barras con formato EAN, CODE 128, CODE 39, EAN 8, UPC-A, UPC-C, I2of5, 2of5, CODE 93 y CODABAR.

Con esto, podremos leer códigos de barras en dispositivos móviles o computadoras en tiempo real.

Limitaciones y requisitos

Así como para tomar fotos de la cámara web usando JavaScript, necesitamos que el sitio tenga HTTPS o esté en localhost.

No hay manera simple de que funcione si no existen esas características. Incluso si estás en una red local y apuntas a tu servidor local, eso no es localhost. Es forzoso que la URL diga localhost o tenga HTTPS.

También se requiere un navegador decente y actualizado, olvídate de Safari o Internet Explorer; utiliza Firefox o Chrome (esto es mi recomendación, pero puedes probar en el navegador de tu preferencia y dejar un comentario).

Por cierto, no se puede leer (al momento de escribir este post) todo tipo de códigos de barras; es decir, se debe configurar antes cuál formato se debe escanear. Aunque leí por ahí que en las últimas versiones esto ya se está agregando.

Dicho todo esto, comencemos.

Primer ejemplo básico

Leyendo código de barras con JavaScript y cámara en navegador web

Comencemos con un ejemplo sencillo. Incluimos el script de Quagga (si usas NPM o similares también es válido) y nuestro script en donde vamos a iniciar el lector:

<!-- Cargamos Quagga y luego nuestro script -->
<script src="https://unpkg.com/quagga@0.12.1/dist/quagga.min.js"></script>
<script src="script.js"></script>

Ahora en nuestro HTML definimos el contenedor que, como lo dije, va a mostrar la vista previa del lector. Por cierto también defino (para el ejemplo) un elemento en donde se colocará el código leído y por lo tanto el código completo queda así:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Leer código de barras con JavaScript by parzibyte</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
  <p id="resultado">Aquí aparecerá el código</p>
  <p>A continuación, el contenedor: </p>
  <div id="contenedor"></div>
  <!-- Cargamos Quagga y luego nuestro script -->
  <script src="https://unpkg.com/quagga@0.12.1/dist/quagga.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>

La parte importante viene a continuación. Iniciamos Quagga indicándole que lea el formato EAN (puede leer los que indiqué al inicio), con una resolución de 1920 x 1080 y que los resultados los coloque en el elemento del DOM que estamos pasándole (obtenido con querySelector):

document.addEventListener("DOMContentLoaded", () => {
 const $resultados = document.querySelector("#resultado");
 Quagga.init({
  inputStream: {
   constraints: {
    width: 1920,
    height: 1080,
   },
   name: "Live",
   type: "LiveStream",
   target: document.querySelector('#contenedor'), // Pasar el elemento del DOM
  },
  decoder: {
   readers: ["ean_reader"]
  }
 }, function (err) {
  if (err) {
   console.log(err);
   return
  }
  console.log("Iniciado correctamente");
  Quagga.start();
 });

 Quagga.onDetected((data) => {
  $resultados.textContent = data.codeResult.code;
  // Imprimimos todo el data para que puedas depurar
  console.log(data);
 });
});

Iniciamos el lector pasándole el modo, y el contenedor en donde debe colocar los resultados. Si no hay problema al iniciarlo (línea 22) entonces comenzamos a leer lo de la cámara y a buscar códigos de barras con Quagga.start().

Proporcionamos el callback a onDetected que se invocará cuando se haya leído un código de barras. El mismo estará en la propiedad codeResult.code del resultado que nos pasa la función.

Justo en la función onDetected ocurre la magia. En mi caso simplemente coloco el código en el párrafo, pero tú puedes colocarlo en un input y enviar un formulario, enviarlo usando AJAX, etcétera.

Para terminar este ejemplo veamos el estilo usado, que si bien no es primordial, es importante:

#contenedor video{
 max-width: 100%;
 width: 100%;
}
#contenedor{
 max-width: 100%;
 position:relative;
}
canvas{
 max-width: 100%;
}
canvas.drawingBuffer{
 position:absolute;
 top:0;
 left:0;
}

El código completo de este ejemplo lo encuentras en GitHub. La demostración la encuentras en este enlace.

Formatos soportados

Anteriormente listé los formatos soportados. Aquí los muestro pero como cadena aceptable para el lector, es decir, si quieres indicar que se lea en el formato, no debes colocar espacios ni mayúsculas, sino algo así:

  • code_128_reader
  • code_39_reader
  • code_39_vin_reader
  • ean_reader
  • ean_extended_reader
  • ean_8_reader
  • upc_reader
  • upc_e_reader
  • codabar_reader
  • i2of5_reader
  • 2of5_reader
  • code_93_reader

En mi ejemplo simplemente utilizo ean_reader, tú puedes utilizar cualquiera de la lista.

Dibujando código leído

El autor de la librería ha proporcionado una manera bastante sencilla pero poderosa de mostrar en qué lugar del canvas se ha detectado el código, dándole una mejor vista al lector de código de barras de JavaScript e indicándole al usuario en dónde se ha detectado el mismo.

En este caso podemos mostrar algunas líneas en el canvas o drawing buffer para indicar en dónde se ha detectado el código; para ello podemos escuchar al evento Quagga.onProcessed que se invocará cada que haya procesado la imagen, con ciertos puntos en donde se ha detectado.

No es necesario implementar nuestro propio método de dibujo, pues el autor ya lo ha hecho en sus ejemplos. Basta con agregar al script anterior lo siguiente:

Quagga.onProcessed(function (result) {
  var drawingCtx = Quagga.canvas.ctx.overlay,
    drawingCanvas = Quagga.canvas.dom.overlay;

  if (result) {
    if (result.boxes) {
      drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
      result.boxes.filter(function (box) {
        return box !== result.box;
      }).forEach(function (box) {
        Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 });
      });
    }

    if (result.box) {
      Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 });
    }

    if (result.codeResult && result.codeResult.code) {
      Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
    }
  }
});

No es necesario modificar más código, pues todo este dibujo se hace en el lienzo que el lector ya coloca sobre el contenedor indicado. Para dejarlo claro, el código completo del script es el siguiente:

document.addEventListener("DOMContentLoaded", () => {
 const $resultados = document.querySelector("#resultado");
 Quagga.init({
  inputStream: {
   constraints: {
    width: 1920,
    height: 1080,
   },
   name: "Live",
   type: "LiveStream",
   target: document.querySelector('#contenedor'), // Pasar el elemento del DOM
  },
  decoder: {
   readers: ["ean_reader"]
  }
 }, function (err) {
  if (err) {
   console.log(err);
   return
  }
  console.log("Iniciado correctamente");
  Quagga.start();
 });

 Quagga.onDetected((data) => {
  $resultados.textContent = data.codeResult.code;
  // Imprimimos todo el data para que puedas depurar
  console.log(data);
 });

 Quagga.onProcessed(function (result) {
  var drawingCtx = Quagga.canvas.ctx.overlay,
   drawingCanvas = Quagga.canvas.dom.overlay;

  if (result) {
   if (result.boxes) {
    drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
    result.boxes.filter(function (box) {
     return box !== result.box;
    }).forEach(function (box) {
     Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 });
    });
   }

   if (result.box) {
    Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 });
   }

   if (result.codeResult && result.codeResult.code) {
    Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
   }
  }
 });
});

Ahora tenemos un dibujo en cada código detectado. Además, si se detecta uno válido o legible, se dibuja una línea roja:

Lectura de Código de barras con dibujo en canvas – JavaScript con QuaggaJs

El código del ejemplo está en mi repositorio de GitHub, y puedes probarlo aquí.

Tercer ejemplo: leer código de barras en ventana separada

Si bien se puede leer el código en una misma ventana, podemos separar lógica y componentes para leer el código de barras en una ventana distinta y así integrar de mejor manera este lector.

Hace un tiempo hice un ejemplo para abrir una ventana nueva con el lector, cuyo funcionamiento era que al leer el código, la ventana se cerraba; y se devolvía el código de barras gracias a la comunicación entre ventanas de JavaScript.

Si quieres verlo, aquí está el código del ejemplo. La verdad es que es un ejemplo no tan general (de hecho fue para un trabajo que hice) y por lo tanto no lo explico aquí, pero si te gusta explorar el código, estás invitado a hacerlo.

Conclusión

Olvidé mencionar que en todos los ejemplos estoy esperando al evento DOMContentLoaded, esto es solo para esperar que el DOM se haya cargado correctamente y digamos que simplemente es una buena práctica, es algo así como el $(document).ready() de jQuery

Por cierto, en los ejemplo estoy detectando códigos de barras en formato EAN, aunque los soportados son los mencionados al inicio.

Te invito a visitar el repositorio de la librería, pues es la principal fuente de documentación. También te dejo algunos enlaces de interés para aprender JavaScript en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.