¿Leer QR con versiones anteriores a FileMaker 19? Sí, pero…

A partir de la versión 19.3.1 FileMaker introduce cambios importantes en el motor del visualizador web. Es preciso tener esto en cuenta a la hora de tratar con scripts de JavaScript

Conforme estaba preparando la entrada anterior, leer un código QR con FileMaker en una imagen de un campo contenedor, me iba haciendo la pregunta del encabezado. Sabía que tal como estaba preparado el archivo de FM no iba a ser posible, al menos la forma de pasar el valor de la variable de JS a FM era exclusiva de FM19, pero ¿se podría hacer?

Como ya llevaba un razonable estrujamiento de meninges, decidí aparcar la pregunta para otra ocasión y no demorar más la publicación de una entrada que, pese a que seguro que se puede hacer mejor, funcionaba y daba respuesta a una cuestión planteada. Ya nos divertiremos con eso en otra ocasión.

Pero la verdad es que servidor necesita de bien poco para meterse a chapotear en un charco, y ha bastado con recibir una consulta idéntica a la pregunta de inicio para intentar responderla y responderme. Así que, allá vamos:

Incompatibilidad de caracteres

Aún tengo instalado el FM18, y tal como intuía, el fichero de la entrada anterior carga perfectamente en él, pero el JS no funciona.

Sospechaba que el visualizador web de FM18, o mejor dicho de FM<19, no era capaz de procesar correctamente el JS incluido en el archivo, y por ahí van los tiros:

https://community.claris.com/en/s/article/Claris-FileMaker-Pro-19-3-1-Release-Notes

Las pruebas de la entrada anterior están hechas con el FM19 debidamente actualizado, concretamente muestra que estoy usando la versión 19.4.2.204 en Windows 10

En el enlace de Claris que precede a estas líneas podemos ver que las versiones anteriores a la 19.3.1 utilizan el motor de Internet Explorer. Pues bien, si resulta que el JavaScript que usamos utiliza el estándar ES6, lo más normal hoy, no funcionará con estas versiones de FileMaker:

https://www.w3schools.com/js/js_es6.asp

En este enlace anterior podemos ver que JS ES6 no está soportado por ninguna versión de Internet Exploter, ¡uy, perdón! “Explorer”.

JS ES5 Sí

https://www.w3schools.com/js/js_es5.asp

Con el estándar anterior de JS no debería haber problemas. En la tabla de compatibilidad vemos que aparece esta vez IE 9.0

Así que, llegados a este punto, habría dos opciones: o arremangarnos y reescribir el código JS utilizado, y sinceramente, antes me decantaría por uno de los doce trabajillos de Hércules, o buscar otra librería en JavaScript que se llevara bien con estas versiones de FileMaker, en la grata compañía del perro de Hades.

LazarSoft/jsqrcode

Una de las que tenía echado ya el ojo de antemano es esta:

https://github.com/LazarSoft/jsqrcode

Y había llegado a ella a través de este enlace:

https://ourcodeworld.com/articles/read/271/how-to-decode-a-qr-code-from-an-image-with-javascript

Ahí se explica muy claramente cómo leer un QR de una imagen con cuatro líneas de código y las librerías existentes en el enlace anterior de GitHub, además, pasando la imagen como una cadena en base64, justo lo que necesitamos.

Si no me decanté en un primer momento por esta serie de scripts es porque tienen ya una cierta antigüedad y en el apartado de cuestiones se presentan algunos problemas que no han sido resueltos. Sin embargo, tras probar alguna otra librería, esta es la única que he podido y sabido hacer funcionar en FM18

A mogollón

Para hacer funcionar esto en nuestro FM necesitaríamos crear 17 campos de texto globales, meter en ellos el contenido de cada uno de los scripts y cargarlos en el orden indicado:

Esto, aparte de ser una paliza, apareja que como cometamos el más mínimo error no nos va a funcionar, así que decidí simplificar las cosas, gracias a esta estupenda página:

https://www.toptal.com/developers/javascript-minifier/

Lo que he hecho ha sido copiar el código de cada uno de los scripts, “minificarlo” y después juntarlo todo en un único archivo JS en el orden indicado. El resultado se puede descargar del siguiente link:

qrall.zip

El archivo contiene el script qrall.js que es el que se ha creado según lo comentado. También contiene las fuentes y un html para comprobar el funcionamiento y que vamos a ver a continuación.

ourcodeworld.com

Comenzamos echando un vistazo al código que aparece en la mencionada web, la que nos ha puesto sobre la pista y que, recordamos, está aquí:

https://ourcodeworld.com/articles/read/271/how-to-decode-a-qr-code-from-an-image-with-javascript

El código funciona perfectamente y vemos que es muy simple: carga los scripts, pasa los datos de la imagen del QR en base64 y luego hay una función para decodificar el contenido de la imagen que se activa pulsando un botón.

Para nuestros propósitos, ese botón nos estorba bastante, así que vamos a simplificar todavía más este código y vamos a hacer que funcione directamente al cargar la página, ya que nosotros no colocaremos los datos de la imagen en el código sino que los leeremos de un campo, o de dos esta vez, pero para probar, y ver que funciona el script que hemos preparado, vamos a seguir poniendo todo en el código:

Parece largo, pero si le quitamos los comentarios y el código de la imagen se queda en nada. Vemos que los cambios que hemos realizado son la fusión de todos los scripts en uno solo y que hemos modificado un poquito la función que ahora se lanza al acabar de cargar la página.

Este html está incluido en el zip, se llama «prueba.html» y funciona perfectamente. Se puede probar, que para eso está. Al ejecutarlo mostrará en pantalla «https://wampirius.com». Y, por si alguien piensa que hay truco, en el mismo archivo está comentada una página donde se puede copiar el contenido de la variable, pegarlo y mostrará el QR utilizado.

Bien, pues con esto ya funcionando, podemos ir preparando el campo de cálculo del archivo FileMaker que vamos a crear.

Bueno, aquí lo suyo sería preparar primero el FileMaker y luego preparar el contenido del campo de cálculo para el visualizador, pero ya que estamos con el código, por seguir este orden, vamos a centrarnos en el código apuntando los nombres que deberemos dar a los campos.

Hay una cosa que difiere de la anterior entrada, que aquí sí que hay que poner el tipo de imagen que estamos pasando, lo podemos ver que se indica al principio del contenido de la variable «imageURI». Vamos, por tanto, a necesitar un campo en FileMaker que nos devuelva el tipo de imagen, a ese campo lo llamaremos tipoimagen. Nos ocuparemos de él cuando creemos el archivo FM.

El resto de la variable imageURI lo compone el código en base64, así que eso vendrá de un campo que llamaremos qrbase64.

Por último, necesitaremos un campo de texto con almacenamiento global para contener el script en JS. A ese campo lo llamaremos como al script: qrall.

Y con estos datos ya podemos adaptar nuestro «prueba.html» a lo que será el contenido del campo de cálculo que servirá para mostrarse en el visualizador web:

Luego lo pondremos en formato copy&paste, de momento es sólo para hacernos una idea.

FileMaker

Sencillito, lo suficiente para probar.

Cinco campos:

    • qrall: De texto con almacenamiento global para meter el script. Tendremos que copiar a este campo el texto del script qrall.js que se encuentra en el zip que se puede descargar un poco más arriba.
    • qr: Contenedor donde arrastraremos las imágenes.
    • qrbase64: De cálculo con resultado texto.
    • tipoimagen: De cálculo con resultado texto para extraer la extensión de la imagen.
    • resuelve: De cálculo con resultado texto  que generará el código que habrá de interpretar el visualizador.

Contenido de los campos de cálculo

qrbase64: Este ya es conocido de entradas anteriores, el contenido del mismo es el siguiente:

Base64EncodeRFC ( 4848 ; qr )

tipoimagen: Es curioso, GetContainerAttribute puede darnos un montón de cosas… menos la extensión, manda narices. Bueno, pues la forma de sacarla por la que he optado es la siguiente: obtenemos el nombre completo del archivo del contenedor, sustituimos los puntos que pueda haber por espacios para, digamos, convertir el nombre en una frase y de dicha frase nos quedamos con la palabra de la derecha.

RightWords ( Substitute ( GetContainerAttribute ( qr ; "filename" ) ; "." ; " " ) ; 1 )

resuelve: Es el campo que ya hemos visto antes. El código para copiar y pegar es el siguiente:

"<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
<script>" & qrall & "</script>
</head>
<body>
<script>
var imageURI = 'data:image/" & tipoimagen & ";base64," & qrbase64 & "'; 
window.onload = function() {
qrcode.decode(imageURI);
qrcode.callback = function(decodedInformation){
var resultado = decodedInformation;
document.write(resultado);
};
}
</script>
</body>
</html>"

Visualizador web

Ya sólo queda, en presentación, instalar el visualizador web indicándole una dirección web personalizada, para la cual seleccionaremos el campo resuelve:

Y listo para su uso:

Dejo aquí el ejemplo por si alguien se lo quiere descargar:

QR_FM18

Resumiendo

Sí que es posible leer QR con versiones anteriores a FM19, pero el motor que usa el visualizador hace que no pueda entender expresiones del último estándar de JS, que ojo, no es que sea de anteayer, salió en junio de 2015.

Y repito, que los scripts que he usado aquí no son precisamente los mejores. Hay QR que no pueden leer, bien por tamaño, por densidad, por tipo… Por lo que estos scripts no deberían usarse para ningún desarrollo serio, sino exclusivamente como un punto de partida y experimentación.

Esto es sólo un ejemplo de que con FM < 19.3.1 sí que se pueden leer QR, aunque con ciertas limitaciones.

Hasta la próxima!

La imagen de portada está realizada a partir de una fotografía de Mabel Amber en Pixabay

Leer un código QR con FileMaker en una imagen de un campo contenedor

En esta entrada vamos a ver cómo leer el código QR de una imagen en JPG de un campo contenedor de FileMaker 19, pasando el resultado a un campo de texto.

Aquí estamos otra vez con más FileMaker y más JavaScript: ¡Más Melocotones!

Vaya por delante lo que ya he comentado en alguna ocasión, que no soy ningún experto. Ni soy experto en FileMaker ni lo soy en JavaScript. Aviso esto porque esta entrada, aunque funciona, me sigue quedando la impresión de que se podría hacer lo mismo pero mejor y de una forma más directa… o no, luego me explico… o no.

Bueno, al tajo. Resulta que en la entrada “Generar códigos QR con FileMaker”, Marcos planteó la siguiente cuestión:

¿Es posible realizar el proceso inverso? me explico:
La idea es (hablando de Filemaker) leer o escanear el código siendo este una imagen insertada en un campo contenedor y obtener el resultado en un campo de texto.

Y me picó la curiosidad.

Comencé a buscar en el bendito GitHub algún desarrollo en JavaScript para leer códigos QR. Hay unos cuantos y al final me decanté por este porque está bastante actualizado y muy bien currado:

https://github.com/mebjas/html5-qrcode

Que además también tiene una entrada en su blog:

https://blog.minhazav.dev/HTML5-QR-Code-scanning-support-for-local-file-and-default-camera/

Estuve haciendo unas cuantas pruebas intentando leer el código directamente de la imagen, y aunque con los ejemplos en HTML funcionaba, usando un input, si intentaba prescindir de ese input y/o hacer eso mismo en FileMaker, cargar la imagen directamente a una función, no conseguía ningún resultado positivo. Algo no estaba haciendo correctamente, pero no sabía el qué.

El caso es que me cansé de probar y decidí cambiar de estrategia: ¿Y si pasaba la imagen a base64 e intentaba leer el QR así? Era dar un rodeo, pero si funcionaba…

Obviamente eso suponía buscar otra librería, así que me lancé a ello, pero mira tú por dónde, encuentro esta página que dice que hace eso con la misma que estoy usando, aunque modificándola ligeramente:

https://sandi-fajariadi.medium.com/detect-qr-code-from-an-image-using-javascript-ba30b0aa7d59

¡Y funciona, vaya si funciona!

Sandi Fajariadi muestra en su página un código que nosotros vamos también a modificar otro poquito. Para empezar, él extrae el tipo de fichero de la cadena en base64 y luego elimina la cabecera. Nosotros, en FileMaker, generamos la cadena en base64 sin la cabecera y vamos a asumir que usamos siempre ficheros en JPG. Teniendo esto, si queremos usar otro tipo de ficheros sería fácil adaptar el código si es que hiciera falta.

Al lío.

Lo primero que haremos será descargarnos el script en JS. Si vamos al apartado “minified”:

https://github.com/mebjas/html5-qrcode/tree/master/minified

Encontramos esta advertencia:

If you are not using any loader, you can get the latest UMD javascript code in production from https://unpkg.com/html5-qrcode

Así que nos lo bajamos del mencionado enlace.

A continuación, vamos a realizarle la modificación indicada por Sandi Fajariadi:

Tan simple como con un editor de texto buscar la cadena de arriba y sustituirla por la de abajo. Y con esto ya tenemos el script listo para nuestros propósitos.

Vamos a probar: Crearemos en FileMaker un fichero sencillo con los siguientes campos:

    • qrcode: que contendrá el script que acabamos de bajar y preparar. Será un campo de texto con almacenamiento global
    • imagen: un campo contenedor donde meteremos los QR
    • base64: un campo de cálculo con resultado texto que codificará en Base64 la imagen del contenedor
    • resuelve: un campo de cálculo, con resultado texto, que será el que genere la web que procesará el visualizador.
    • resultado: un campo de texto donde pegaremos el resultado de “leer” el QR

También crearemos un guion para pasar el valor de la variable al campo de texto que bautizaremos como «resultprint«.

Y así, sabiendo todos estos datos, podemos ir preparando el cálculo para el campo “resuelve”, que quedará así:

¡Que no cunda el pánico! Más adelante, cuando hagamos la prueba con el FileMaker lo ponemos para copiar y pegar. De momento es sólo para echarle un vistazo.

Las únicas diferencias con el código de Fajariadi es que prescindimos de leer y eliminar la cabecera, de mostrar los errores (si los hubiera) por consola, ya que eso no nos es útil en FM, y que el resultado lo metemos en la última función en una variable que es la que pasaremos  al guion con PerformScripWithOption

Código de la web de Sandi Fajariadi mostrando las zonas donde hemos realizado los cambios.

Preparando el FileMaker

Como hemos comentado antes, vamos a crear un ficherito sencillo con los mencionados campos:

Poca complicación, como puede verse. Lo único el contenido de los campos de cálculo. Para el «base64» la fórmula será la siguiente:

Base64EncodeRFC ( 4648 ; imagen)

Más información:

https://help.claris.com/es/pro-help/content/base64encoderfc.html

El contenido del campo de cálculo «resuelve«, listo para copiar y pegar, es este:

"<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
<script>" & qrcode & "</script>
</head>
<body>
<div id='reader'></div>
<script>
var base64image = '" & base64 & "';
var resultado;
function base64ImageToBlob(str) {
var type = 'jpg';
var b64 = str;
var imageContent = atob(b64);
var buffer = new ArrayBuffer(imageContent.length);
var view = new Uint8Array(buffer);
for(var n = 0; n < imageContent.length; n++) {
view[n] = imageContent.charCodeAt(n);
}
var blob = new Blob([buffer], { type: type });
return blob;
}
function getQRCode(imageBase64) { 
var imageBlob = base64ImageToBlob(imageBase64);
const html5QrCode = new Html5Qrcode('reader');
html5QrCode.scanFile(imageBlob, false)
.then(qrCodeMessage => {
setQRCode(qrCodeMessage);
}); 
}
function setQRCode(QRCode) {
resultado = QRCode;
FileMaker.PerformScriptWithOption ( 'resultprint', resultado, '0' );
}
getQRCode(base64image);
</script>
</body>
</html>"

Una pequeña actualización:

He estado haciendo unas pruebas y fruto de ellas ha sido someter a dieta al campo anterior, eliminando casi todas las funciones y simplificándolo, el resultado es el siguiente, que hace exactamente lo mismo pero con menos líneas:

"<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
<script>" & qrcode & "</script>
</head>
<body>
<div id='reader'></div>
<script>
var b64 = '" & base64 & "';
var type = 'jpg';
var imageContent = atob(b64);
var buffer = new ArrayBuffer(imageContent.length);
var view = new Uint8Array(buffer);
for(var n = 0; n < imageContent.length; n++) {
view[n] = imageContent.charCodeAt(n);
}
var imageBlob = new Blob([buffer], { type: type });
const html5QrCode = new Html5Qrcode('reader');
html5QrCode.scanFile(imageBlob, false).then(function(qrCodeMessage){
var resultado = qrCodeMessage;
FileMaker.PerformScriptWithOption ( 'resultprint', resultado, '0' );
});
</script>
</body>
</html>"

Y falta el script de JS que habrá que incluir en el campo qrcode en el que, además de la modificación de Fajariadi hemos eliminado la primera línea con el comentario relativo a la licencia, que me fastidia, pero en ocasiones he tenido problemas con JavaScript en FileMaker si llevaba comentarios, espacios, etc. No obstante, la primera línea eliminada es esta:

/*! For license information please see html5-qrcode.min.js.LICENSE.txt */

Y el script lo paso a este archivo de texto para poder descargarlo, abrir con cualquier editor de texto y directamente copiar y pegar en el campo de texto:

html5-qrcode.min-MODIFICADO.txt

Por supuesto, ahora tenemos que ir a «presentación» y crear un visualizador web para que procese todo:

Ampliamos las opciones, para refrescar la memoria, ya que en alguna entrada anterior las hemos colocado igual:

Aquí el visualizador web es enorme, pero no lo necesitamos ver para nada, aunque tiene que estar. Recordad que una opción, cutre pero efectiva, es darle una dimensión de un pixel y colocarlo donde no moleste.

Vamos ahora, por último, con el guion que necesitamos para que tome el valor de la variable de JavaScript y lo coloque en el campo de texto, obteniendo en claro el contenido del QR que es lo que hemos venido a buscar:

Como ya vimos en entradas anteriores, un par de líneas: En la primera establecemos una variable, le decimos que tome el valor de ScriptParameter y en la segunda establecemos un campo, el de texto, y que coloque el valor de la variable.

Probando

Y llega el momento de saber si todo esto funciona (Atención, spoiler: ¡Funciona! 😀 )

Apañamos un poco la presentación, ponemos el visualizador a la derecha, ordenamos un poquito los campos y a ver qué pasa. No hace falta tampoco tener los campos visibles, esto es sólo para probar.

Vamos a una de las entradas que tenemos por melocotones y hacemos una captura de un QR y lo guardamos como JPG, por ejemplo este:

El contenido del mismo es «Lo que quieras poner»

Ahora, creamos nuestro primer registro y arrastramos el fichero hasta el campo contenedor, a ver qué pasa:

Y ahí lo tenemos.

Vamos a probar con otro y se lo vamos a complicar algo. Capturamos el QR que tenemos aquí: https://www.wampirius.com/revisado-codigos-qr-con-filemaker-parte-ii-tamano-de-impresion/ y no nos molestamos ni en quitar las flechas y, ojo a esto, la captura es en png y se la colocamos tal cual en ese formato:

¡Fantástico! el desarrollo de Minhaz es una auténtica joya. Ha leído el QR sin importarle la «basurilla» añadida. Además, lo curioso ha sido que lo que hemos arrastrado a FileMaker ha sido un archivo en PNG, y al script le estamos diciendo que es un JPG (ver línea 13). Teóricamente esto «no» debería haber funcionado, pero lo ha hecho, y ahora mismo no sé si es por cómo está programada la librería o por cómo almacena FileMaker las imágenes. En cualquier caso esto ha sido una prueba y no conviene fiarse de que vaya a funcionar sea cual sea el formato. En caso de querer usar más de un formato, lo suyo sería averiguar el tipo de formato y meterlo en la variable.

Una vuelta de tuerca más y acabamos ¿Y si lo giramos un poco, no 90 o 180 grados, sólo un poco…?

Me reafirmo en lo dicho: esta librería es una auténtica joya. Tengo que probar el resto de formatos que soporta, pero es extraordinaria.

Edito: Como me han pedido el archivo fmp12 por mail, dejo aquí una versión del mismo, un pelín diferente a la de los ejemplos anteriores, que muestra también el contenido del QR en el campo contenedor. Es una sobre la que he estado haciendo pruebas para una entrada posterior. Funciona perfectamente en versiones de FileMaker 19.3.1 y posteriores:

leerqr_FM19

Gracias a Minhaz por este pedazo de trabajo y gracias también a Sandi Fajariadi por su aportación sobre Base64 y su ajuste sobre el script de Minhaz. Gracias a estos dos genios ha sido posible el desarrollo de esta entrada. Es todo el mérito suyo, un servidor no ha hecho sino juntar las piezas.

¡Hasta la próxima fruta (u hortaliza, u lo que sea…)!

Nota: La imagen de cabecera está sacada de Pixabay y su autor es Xavier Turpain (xat-ch)