Revisado: Códigos QR con Filemaker. Parte II: Tamaño de impresión

En la anterior entrada hemos visto cómo sacar por pantalla unos QR bien hermosos y más bonitos que un San Luis, ahora toca que impresos queden igual de majos. Vamos a ver cómo imprimir códigos QR con FileMaker al tamaño deseado con total definición.

Advertencia inicial: Es necesario disponer de la versión 19 (o superior) de FileMaker

Resolución

Para empezar, conviene aclarar algo sobre la resolución y luego lo veremos todo mucho más claro… se diría que con mejor resolución.

La pantalla

Las imágenes que vemos en pantalla van a tener una relación directa con la resolución de nuestro monitor, así de simple. Si tenemos una imagen que mide 800 píxeles de ancho y 400 de alto, si la vemos en un monitor que esté configurado a 800×600 ocupará todo el ancho de pantalla, pero si la vemos en un monitor HD que esté configurado a 1920×1080 la imagen ocupará poco más de una quinta parte del ancho, un 21% aprox. Y no hay más. La imagen tiene unos determinados píxeles y nuestro monitor tiene una resolución de pantalla de unos determinados píxeles. Es como hacer coincidir dos rejillas y no entra en juego ningún otro parámetro.

El papel

Aquí entra en juego otro factor, la resolución de la imagen, que se expresa en ppp o dpi (puntos por pulgada o dots per inch). Simplemente es un dato que va a determinar a qué tamaño se imprime la imagen pero que, por supuesto, afectará a su calidad impresa.

A una resolución de 300 ppp las imágenes impresas se ven correctas. La mayoría de las impresoras domésticas, láser o de chorro de tinta, son capaces de alcanzar y superar esa resolución.

Así pues, una imagen de 300 px de ancho, a una resolución de 300 ppp, ocupará impresa una pulgada de ancho, es decir, 25,4 mm.

Vamos a verlo con un ejemplo. Retomamos la primera imagen del ejemplo de la anterior entrada, el QR que habíamos generado con el script en el navegador. Recordamos que es una imagen que habíamos dicho que debía de medir 200×200 px. Lo vemos:

Aquí vemos que la imagen mide 200×200 px y también que se ha generado con una resolución de 300 ppp. Si le preguntamos al GIMP por el tamaño de impresión:

Observamos que ocupará en el papel 16,93 mm.

Es una simple regla de tres: si 300 puntos ocupan 25,4 mm, pues 200 ocuparán… 200*25,4/300=16,9333

Por supuesto, esta resolución de impresión es la que determina la calidad final de la imagen impresa. Si tenemos una foto muy pequeña, de unos pocos píxeles, de un adorable gatito jugando con su ovillo de lana y, para hacerla más grande impresa, ampliamos su tamaño de impresión reduciendo la resolución, los ppp, pues el resultado final será un auténtico churro.

Esto puede estar bien para cartelería, esos anuncios gigantescos que vemos desde el coche desde varios metros de distancia. Si nos acercamos a dos palmos de los mismos, en la mayoría de los casos veremos unos puntacos bien hermosos. Tendrán una resolución de muy pocos ppp, pero es que no necesitan más ya que son imágenes que vamos a ver desde una considerable distancia.

Por el contrario, si estamos preparando un archivo para un trabajo de offset, para generar unos fotolitos o un CtP, necesitaremos una resolución mayor a esos 300 ppp para que el resultado final sea perfecto.

Hay bastantes páginas que tratan sobre este tema, pero he visto dos bastante ilustrativas e interesantes:

https://www.pixelandnet.com/resolucion-300-ppp-minima-para-impresion-y-72-pantalla-si-o-no.html

https://www.xatakafoto.com/tutoriales/mito-72-dpi-como-ajustar-resolucion

Así pues, ya sabemos que la resolución en ppp o dpi de una imagen no tiene ninguna importancia para las imágenes en pantalla pero que va a ser la que determine su tamaño impreso. Ya veis, tanta parrafada para esto. Así que, después de toda esta literatura, vamos a meternos en harina.

Calculando el tamaño de impresión

Hemos dicho antes que si cogemos la foto de un gatico y le bajamos la resolución para ampliar el tamaño, en vez de imprimir un gato íbamos a imprimir un churro, peeero… nosotros aquí contamos con una ventaja: nuestras imágenes son códigos QR, esto es, unas imágenes formadas por unos “puntacos cuadraos” que nos da exactamente igual si salen más grandes o más pequeños, siempre serán «puntacos cuadraos». La resolución nos la trae al pairo. Y os aseguro que esto es una gran ventaja.

Por ejemplo:

Aquí tenemos un QR de 200×200:

Si le echamos un ojo con el GIMP:

Vemos que está a 300 ppp de resolución y que nos va a ocupar impreso menos de 17 mm, 16,93 para ser exactos. Probamos a imprimir un PDF:

Este es el tamaño que ocupará en la página. Y si ahora comprobamos el tamaño con Acrobat:

Exactamente lo que nos decía GIMP. Y con una resolución perfecta.

Vamos a quitarle ahora resolución. Queremos imprimirlo a 12 cm, o lo que es lo mismo, 120 mm:

La resolución es tan solo de 42 ppp. Esto es lo que ocupa ahora el QR en la página:

Y si comprobamos con Acrobat:

Creo que por una centésima de milímetro lo podemos dar por bueno, pero lo mejor es que, como veis, la calidad sigue siendo perfecta. Alguna ventaja teníamos que tener con los QR.

Vale, pues ya hemos visto que modificando los ppp del QR podemos configurar a qué tamaño queremos que se nos impriman, ahora bien ¿qué se supone que tenemos que hacer cada vez que tengamos que imprimir un QR, pasarlos por el GIMP? Pues no.

Resulta que con kjua podemos generar archivos PNG y estos archivos almacenan fragmentos, “chunk”, con determinada información. Uno de ellos es “pHYs”: Physical Pixel Dimensions. Bajo esta etiqueta se almacena, entre otras cosas, la resolución de impresión. Veamos lo que aparece aquí:

http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html

Y nos ayudamos del traductor de San Google:

4.2.4.2. pHYs Dimensiones físicas de píxeles

El fragmento pHYs especifica el tamaño de píxel o la relación de aspecto previstos para la visualización de la imagen. Contiene:

Píxeles por unidad, eje X: 4 bytes (entero sin signo)
Píxeles por unidad, eje Y: 4 bytes (entero sin signo)
Especificador de unidad: 1 byte

Los siguientes valores se definen para el especificador de unidad:

0: la unidad es desconocida
1: la unidad es el metro

Cuando el especificador de la unidad es 0, el fragmento pHYs define solo la relación de aspecto de píxeles; el tamaño real de los píxeles permanece sin especificar.

Nota de conversión: una pulgada equivale exactamente a 0,0254 metros.

Si este fragmento auxiliar no está presente, se supone que los píxeles son cuadrados y se desconoce el tamaño físico de cada píxel.

Si está presente, este fragmento debe preceder al primer fragmento de IDAT .

Consulte Recomendaciones para decodificadores: dimensiones de píxeles .

Pues ya está, solucionado: todo lo que tenemos que hacer es insertar o reescribir ese apartado de la cabecera con la información de los ppp que queramos y arreando…. Vale, dicho así suena fácil, pero menos mal que hay buenas gentes que desarrollan librerías y las publican, que si no…

Una de esas personas es Michael Borcherds, “Murkle”: https://github.com/murkle que tiene en GitHub la librería “rewrite-png-pHYs-chuk”

https://github.com/murkle/rewrite-png-pHYs-chunk

Si echamos un vistazo al readme.md la verdad es que lo hace bastante fácil, gracias a su librería, claro:

Usage

data = rewrite_pHYs_chunk(data, ppmX, ppmY);

Toma el archivo de imagen en bruto «data» como un Uint8Array, y devuelve el archivo de imágenes en bruto «data» como Uint8Array con el fragmento Phys añadido o reescrito con ppmX, ppmY (píxeles por metro):

Pues mira, aún encima trabajo que nos ahorra que no tenemos que andar con pulgadas, sino que nos las vemos con nuestro amado sistema métrico decimal.

Hala pues, vamos a ver cómo funciona este invento. Echamos un vistazo a su archivo test.html:

https://github.com/murkle/rewrite-png-pHYs-chunk/blob/master/test.html

Limpiamos un poco de comentarios y vemos lo que hace:

En él podemos ver que prepara un canvas y mete allí una imagen, la pasa a Uint8Array, luego hace una conversión de los dpi deseados a píxeles por metro, reescribe el fragmento pHYs y muestra la imagen, todo ello mientras por consola nos va mostrando los datos de lo que va haciendo. Coser y cantar (moral que no nos falte).

Pero en nuestro caso aún es más sencillo porque con kjua vamos a fijar la opción render a canvas y toda la primera parte del ejemplo de test.html nos la podremos saltar, algo es algo. Vamos a probar.

Probamos primero en el navegador y luego ya nos meteremos con FileMaker, así que preparamos un html que es una modificación del que ya teníamos. La diferencia es que vamos a declarar al principio las variables con los datos de las opciones que necesitamos: versión, size, tamaño que queremos imprimir, texto a generar en el QR y nivel de corrección.

Necesitaremos también descargarnos el script rewrite-png-pHYs-chunk de:

https://github.com/murkle/rewrite-png-pHYs-chunk

En este caso está en el raíz (de hecho no hay carpetas) y se llama “index.js”, aunque aconsejo cambiarle el nombre a “rewritejs.js” o el nombre que prefiráis, pero algo más descriptivo que “index”.

Ponemos nuestro kjua.min.js y el renombrado rewritejs.js en la misma carpeta que el siguiente html que para la ocasión, de momento, comentamos para que se vea más claro… algo más claro.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
    <script type='text/javascript' src='kjua.min.js'></script>
    <script type='text/javascript' src='rewritejs.js'></script>
  </head>
  <body>
    <script>

      // Ponemos todos los valores en variables, versiónqr (versión), tamanoqr (tamaño, que habrá de corresponder con un múltiplo de la matriz de la versión), impresion (en milímetros), texto (la cadena a generar en QR) y nivel de corrección. Luego todos estos valores se pueden meter, si se desea, en campos de FileMaker para hacer pruebas sin tener que modificar el campo de cálculo.

      var versionqr = 6;
      var tamanoqr = 164;
      var impresion = 60;
      var texto = 'https://wampirius.com';
      var correccion = 'M';

      // Generamos el QR con kjua en la variable imagenqr, igual que en los ejemplos anteriores
      var imagenqr = kjua({
          render: 'canvas',
          crisp: true,
          minVersion: versionqr,
          size: tamanoqr,
          ratio: null,
          ecLevel: correccion,
          quiet:0,
          text: texto
          });

      // Pero ahora no hace falta dibujar el QR obtenido, sólo necesitamos la variable imagenqr
      //document.querySelector('body').appendChild(imagenqr);

      // Procedemos como en el ejemplo test.html de
      // https://github.com/murkle/rewrite-png-pHYs-chunk
      var pngHeader = 'data:image/png;base64,';
      var base64 = imagenqr.toDataURL().substr(pngHeader.length);

      var img = new Image();

      var binary_string = window.atob(base64);
      var len = binary_string.length;
      var bytes = new Uint8Array(len);
      for (var i = 0; i < len; i++) {
          bytes[i] = binary_string.charCodeAt(i);
      }

      // Pero a diferencia del ejemplo no vamos a usar el tamaño en pulgadas, lo tenemos ya en la variable en milímetros, así que los cálculos cambian, más fáciles:
      var ppm = Math.round(1000 * tamanoqr / impresion );
      bytes = rewrite_pHYs_chunk(bytes, ppm, ppm);

      var b64encoded = btoa(String.fromCharCode.apply(null, bytes));
      img.src = pngHeader + b64encoded;

      // Y ahora sí, dibujamos el QR en pantalla y si nos lo descargamos podremos comprobar que la resolución está a la medida definida en milímetros
      document.querySelector('body').appendChild(img);

    </script>
</body>
</html>

Poco miedo que hay mucho comentario, luego se queda en nada.

Bien, pues en el html anterior lo que hemos dicho es que genere un QR de la dirección de este blog en una versión 6, size 164 y un tamaño de impresión de 60 mm. Si lo ejecutamos en el navegador, obtenemos un QR que si lo analizamos con el GIMP:

Vemos que tiene un tamaño de 60,01 mm y a una resolución ridícula de 2,73 píxeles por milímetro. Vemos que GIMP ya no nos da la medida en píxeles por pulgada al haber reescrito el fragmento de esa información.

Y ahora, si imprimimos dicho QR en un PDF y lo comprobamos:

Vemos que el tamaño es el deseado, y el indicado por GIMP. Pero además, vemos que la nitidez es perfecta. Ventajas de estar trabajando con puntacos cuadraos.

No obstante queda un tema en el aire ¿qué size debemos poner? Está claro que un múltiplo de la matriz de la versión, pero ¿qué múltiplo?

Bueno, luego veremos que la variación sobre el resultado final es escasa. Dejaremos una variable para indicar el número de píxeles en función de la exactitud que queramos en el resultado impreso: a más píxeles más posibilidades de encajarlos en la medida que se indique, pero para un trabajo normal en A4 las diferencias van a ser mínimas.

En la siguiente imagen vemos que si aumentamos el tamaño a 246 píxeles ahora sí que anchura y altura se adaptan perfectamente.

Eso sí, a más píxeles, más «peso» del archivo y realmente los píxeles nos dan igual, ya que sólo buscamos un número que permita una impresión más o menos exacta en tamaño. Si nuestros requerimientos permiten una determinada holgura, el número de píxeles no será tan crítico.

Ahora bien ¿vamos a tener que poner la versión y calcular el size tirando de tabla, dividiendo el tamaño y luego multiplicando? Pues no, la verdad es que ya sólo de pensarlo da una pereza horrible. Vamos a intentar hacer nuestro propio script para que directamente haga esos cálculos y nosotros sólo pondremos el tamaño al que queremos la impresión y, por supuesto, lo que queremos que contenga el QR. Al lío:

Automatizando versión y size

Recordamos que la versión del QR va a depender de lo que queramos codificar y del nivel de corrección.

En esta página: https://www.thonky.com/qr-code-tutorial/character-capacities tenemos una tabla que podemos trasladar a una hoja de cálculo para ayudarnos a hacer los arrays que vamos a necesitar.

Vamos a usar sólo los valores de la columna Byte, ya que supongo que los QR que vamos a generar contienen direcciones web y ni Numeric ni Alphanumeric soportan minúsculas, y del alfabeto japonés no creo que necesitemos tampoco nada.

Desde la versión 1 hasta la versión 40 el número indicado en la columna Byte hace referencia al número de caracteres que puede ser codificado en cada versión según el nivel de corrección. Por ejemplo, una cadena de 41 caracteres con un nivel M necesitará una versión 3, ya que esta versión admite un máximo de 42 caracteres con el nivel M, pero si subiéramos el nivel de corrección a Q, vemos que ya necesitamos una versión 4.

Bueno, pues lo que vamos a hacer es prepararnos cuatro arrays con los cuarenta valores para cada uno de los niveles de corrección y prepararemos una función que hará lo siguiente:

      • Calcularemos la longitud de la cadena a codificar en el QR
      • Con un switch case usaremos un array u otro en función del nivel de corrección.
      • Luego, con un for vamos comparando la longitud de la cadena con el número máximo de caracteres que puede soportar cada nivel para seleccionar el más bajo posible. Así obtendremos la versión.
      • A continuación, sabiendo el nivel, calcularemos la matriz. Si nos fijamos en uno de los links mencionados en la entrada anterior, la matriz para el nivel 1 es de 21×21 y luego va aumentando de 4 en 4: 25 para el 2, 29 para el 3, etc.
http://hm2.heubach-media.de/projektis/hmReports/6_0/Documentation/CONTENT/EN00002273.HTM
      • Por último, calcularemos un multiplicador para el tamaño siguiendo el criterio comentado unas líneas antes: redondeando hacia el valor que tenga la variable «pixeles», que como hemos comentado, vamos a poner en 300. Y así, con dicho multiplicador, obtendremos el tamaño en píxeles.

Si nos fijamos, lo que estamos haciendo con este multiplicador es algo «parecido» a lo que hace la opción «crisp» del script kjua, solo que nosotros vamos a generar «el QR más aproximado en píxeles al tamaño asignado a la variable, bien por exceso o por defecto y sin dejar márgenes en blanco». Aunque suene que hace algo parecido, realmente es bastante diferente.

Y el script nos queda así:

function vtqr(){
    var longitud = texto.length; //Longitud de la cadena a generar QR
    switch (correccion) {
        // Según el nivel de corrección, el array 'arrayversion' almacenará unos valores u otros
        // Dado que el primer índice de un array es 0, añadimos al principio un valor, para que el índice 1 coincida con la versión 1 de QR y hacer más sencilla la comparación
        case 'L': var arrayversion = [0,17,32,53,78,106,134,154,192,230,271,321,367,425,458,520,586,644,718,792,858,929,1003,1091,1171,1273,1367,1465,1528,1628,1732,1840,1952,2068,2188,2303,2431,2563,2699,2809,2953];
            break;
        case 'M': var arrayversion = [0,14,26,42,62,84,106,122,152,180,213,251,287,331,362,412,450,504,560,624,666,711,779,857,911,997,1059,1125,1190,1264,1370,1452,1538,1628,1722,1809,1911,1989,2099,2213,2331];
            break;
        case 'Q': var arrayversion = [0,11,20,32,46,60,74,86,108,130,151,177,203,241,258,292,322,364,394,442,482,509,565,611,661,715,751,805,868,908,982,1030,1112,1168,1228,1283,1351,1423,1499,1579,1663];
            break;
        case 'H': var arrayversion = [0,7,14,24,34,44,58,64,84,98,119,137,155,177,194,220,250,280,310,338,382,403,439,461,511,535,593,625,658,698,742,790,842,898,958,983,1051,1093,1139,1219,1273];
            break;
        default : // Reservado para implementar control de errores
    }
    // Vamos comparando la longitud del texto a codificar con los valores del array y en el momento en que sea menor obtendremos la versión del QR necesaria, que coincidirá con el índice del array
    for (let i = 1; i <= 40; i++){
        if (longitud <= arrayversion[i]){
            versionqr = i;
            break;
        }
    }
    // Calculamos el tamaño de la matriz, que son 21 para la versión 1 y luego se va incrementando de 4 en 4.
    var matriz = (versionqr - 1) * 4 + 21;
    // Calculamos un multiplicador de la matriz para obtener un tamaño en torno a los píxeles establecidos en la variable 'pixeles'
    var multiplicador = Math.round(pixeles/matriz);
    // Comprobamos que el multiplicador no sea cero y de serlo lo ponemos a 1
    if (multiplicador == 0 ) {
        multiplicador = 1;
    }
    // Calculamos el tamaño de nuestro QR
    tamanoqr = matriz * multiplicador;
}

 

Me ha dado por bautizar al script como versionytamano.js y lo dejaré al final para descargar. Quien quiera probar puede hacer copy&paste del código o descargarlo del link del final de la entrada.

Y ahora, vamos a modificar un poquito nuestro html anterior para usar este script y que haga los cálculos de versión y tamaño él solo. Los cambios que vamos a hacer son:

      1. Añadir al principio el script versionytamano.js, el primero en la cabecera del html
      2. Colocar las tres variables que hemos de rellenar: tamaño de impresión, texto, nivel de corrección y pixeles
      3. Declarar las variables versionqr y tamanoqr que ha de calcular el script
      4. Llamar a la función que hemos creado.

Y listo, así se nos queda:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
    <script type='text/javascript' src='versionytamano.js'></script>
    <script type='text/javascript' src='kjua.min.js'></script>
    <script type='text/javascript' src='rewritejs.js'></script>
  </head>
  <body>
    <script>

      // Indicamos el tamaño de impresión en milímetros, el texto para generar el QR y el nivel de corrección: L, M, Q o H
      var impresion = 38;
      var texto = 'https://wampirius.com';
      var correccion = 'M';
      var pixeles = 300;

      // Declaramos las variables globales versionqr y tamanoqr que calcularemos con nuestro script
      var versionqr;
      var tamanoqr;

      // LLamamos a la función vtqr de nuestro script para obtener la versión y el tamaño
      vtqr();

      // Generamos el QR con kjua en la variable imagenqr, igual que en los ejemplos anteriores
      var imagenqr = kjua({
          render: 'canvas',
          crisp: true,
          minVersion: versionqr,
          size: tamanoqr,
          ratio: null,
          ecLevel: correccion,
          quiet:0,
          text: texto
          });

      // Procedemos como en el ejemplo test.html de
      // https://github.com/murkle/rewrite-png-pHYs-chunk
      var pngHeader = 'data:image/png;base64,';
      var base64 = imagenqr.toDataURL().substr(pngHeader.length);

      var img = new Image();

      var binary_string = window.atob(base64);
      var len = binary_string.length;
      var bytes = new Uint8Array(len);
      for (var i = 0; i < len; i++) {
          bytes[i] = binary_string.charCodeAt(i);
      }

      // Pero a diferencia del ejemplo no vamos a usar el tamaño en pulgadas, lo tenemos ya en la variable en milímetros, así que los cálculos cambian, más fáciles:
      var ppm = Math.round(1000 * tamanoqr / impresion );
      bytes = rewrite_pHYs_chunk(bytes, ppm, ppm);

      var b64encoded = btoa(String.fromCharCode.apply(null, bytes));
      img.src = pngHeader + b64encoded;

      // Y ahora sí, dibujamos el QR en pantalla y si nos lo descargamos podremos comprobar que la resolución está a la medida definida en milímetros
      document.querySelector('body').appendChild(img);

    </script>
</body>
</html>

Sigue estando todo comentado por si alguien quiere hacer copy&paste y probarlo (recomendado), pero os garantizo que funciona, así que toca pasar todo esto al FileMaker. Este archivo lo dejaré también al final de la entrada.

Imprimir QR al tamaño deseado con FileMaker (¡Por fin…!)

Y después de tanta literatura teórico práctica, toca meter esto en el FileMaker y ver si de verdad funciona, pero ya os avanzo que sí, que esta historia va a tener un final feliz y vamos a poder imprimir códigos QR con FileMaker al tamaño deseado con total definición.

Para meter todo lo anterior en el FileMaker vamos a tener que crear algunos campos más que los que teníamos en la anterior entrada. Además, meteremos el QR en un campo contenedor para imprimirlo desde ese campo, no desde el visualizador web que podremos ocultar y sólo lo usaremos para ejecutar el código JavaScript. Bueno, vamos a verlo sobre la marcha que será mejor.

Campos

Por supuesto podéis bautizar los campos como mejor os plazca, los nombres son orientativos y por seguir el ejemplo (Aviso: los nombres de los campos no contienen acentos)

Crearemos tres campos de texto globales para albergar los scripts:

      • kjuamin
      • rewrite
      • versionytamano

Para poder hacer las pruebas con total comodidad, las variables del tamaño de impresión y del tamaño en píxeles las vamos a meter también en dos campos numéricos, estos campos los haremos también globales para que conserven los ajustes a cada registro que vayamos creando.

      • milimetros
      • pixeles

Para introducir el texto a codificar, un campo de texto con validación «no vacío».

      • contenido

Y ahora vamos por orden:

Un campo de cálculo con resultado texto que generará el código QR en el visualizador web. En él meteremos, modificado, el último código que hemos visto en HTML.

      • qrcalculo

Un campo de texto, que recibirá desde un guion el QR en Base64

      • qr64

Un campo de cálculo con resultado contenedor que contendrá el código QR listo para imprimir generado del campo anterior

      • qrprintcontenedor

Y todos ellos lucen así:

Vamos viendo cada uno:

Los campos globales tienen que tener activada la siguiente casilla en opciones:

Para el campo «Contenido», en validación desmarcamos «Permitir al usuario…» y marcamos «No vacío».

Y ahora viene lo bueno:

Campo qrcalculo: ha de contener, como hemos dicho, el código en HTML ligeramente modificado para integrar los campos de las dimensiones del QR y para pasar la variable al guión. Este es el código que ha de contener:

"<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
    <script>" & versionytamano & "</script>
    <script>" & kjuamin & "</script>
    <script>" & rewrite & "</script>
  </head>
  <body>
  <script>
      var impresion = " & milimetros & ";
      var texto = '" & contenido & "';
      var correccion = 'M';
      var pixeles = " & pixeles & ";
      var versionqr;
      var tamanoqr;
      vtqr();
      var imagenqr = kjua({
      render: 'canvas',
      crisp: true,
      minVersion: versionqr,
      size: tamanoqr,
      ratio: null,
      ecLevel: correccion,
      quiet:0,
      text: texto
      });
      var pngHeader = 'data:image/png;base64,';
      var base64 = imagenqr.toDataURL().substr(pngHeader.length);
      var img = new Image();
      var binary_string = window.atob(base64);
      var len = binary_string.length;
      var bytes = new Uint8Array(len);
      for (var i = 0; i < len; i++) {
          bytes[i] = binary_string.charCodeAt(i);
      }
      var ppm = Math.round(1000 * tamanoqr / impresion );
      bytes = rewrite_pHYs_chunk(bytes, ppm, ppm);
      var b64encoded = btoa(String.fromCharCode.apply(null, bytes));
      img.src = pngHeader + b64encoded;
      document.querySelector('body').appendChild(img);
      FileMaker.PerformScriptWithOption ( 'qrprint', b64encoded, '0' );
  </script>
</body>
</html>"

Os sugiero el copy&paste, pero si lo hacéis a mano poned atención a las comillas dobles y simples.

Si lo comparáis con el HTML veréis que es igual pero añadiendo lo indicado.

No obstante, hay que presta atención a la última línea del script:

FileMaker.PerformScriptWithOption ( ‘qrprint’, b64encoded, ‘0’ );

Con esta línea lo que estamos haciendo es pasar el valor de la variable b64encoded que tenemos un par de líneas más arriba al guion qrprint que vamos a crear a continuación.

El porqué y cómo de este paso de variables está explicado en la entrada del CRC-8:

CRC-8 con FileMaker 19 y JavaScript

Por supuesto, todo eso ha de procesarse en un visualizador web que habremos de crear en una presentación. Dicho visualizador hay que configurarlo de la siguiente manera:

Seleccionamos dirección web personalizada, indicamos el campo de cálculo que acabamos de preparar y marcamos la última casilla para permitir a JavaScript ejecutar guiones de FileMaker.

Guion para generar la imagen a imprimir

Bien, si habéis echado un ojo a la entrada del CRC-8, es tan fácil como crear un guion, que aquí hemos llamado qrprint, con el siguiente contenido:

Con esto lo que estamos haciendo es copiar el contenido de la variable JavaScript que contiene el código QR en formato Base64 al campo de texto qr64. Ahora lo que toca es generar ese QR en un campo contenedor con un campo de cálculo, vemos que abajo está configurado «El resultado del cálculo es Contenedor»:

Y que el cálculo a realizar es tan sencillo como colocar:

Base64Decode ( qr64 ; "qr.png" )

Este campo de cálculo lo que hace es tomar la cadena en Base64 del campo qr64, asignarle el nombre, qr.png y el resultado del cálculo vemos que ha de ponerse a Contenedor.

Y ya lo tenemos. Sólo nos queda pegar los scripts en los campos de texto globales.

Con fines didácticos, vamos a preparar una presentación con todos los campos a cascoporro, algo así:

Vamos a visualizar, creamos un registro y metemos en los campos versionytamano, kjuamin y rewrite el contenido de los scripts antes mencionados. Estos campos ya no habrá que tocarlos.

Y ya está todo listo para probar:

¡Perfecto! Vemos que funciona. Hemos puesto una dirección web «al azar» en el campo contenido y le hemos dicho que queremos un png de 35 mm de lado y de unos 300 px. Podemos ver que se ha formado la imagen en el visualizador web, que se ha pasado el contenido de la variable al campo qr64 y que, lo que más nos interesa, el contenedor muestra un QR.

Vale, pues limpiamos la presentación o nos creamos otra dejando sólo las imágenes y los campos que tenemos que rellenar y hacemos un par de pruebas.

En la primera vamos a imprimir a PDF con los ajustes siguientes: 35 mm de tamaño y 300 px La pantalla del FileMaker muestra esto:

Imprimimos a PDF y cambiamos el ajuste de los píxeles y ponemos «1» Esto nos generará un QR al menor tamaño posible:

Fijaos que en el visualizador web el tamaño ha cambiado de forma llamativa, sin embargo en el contenedor el tamaño es el mismo. Ahora bien, seguro que alguno está diciendo que se ve fatal en el contenedor, pues sí, en efecto se ve fatal, pero vamos a imprimir un PDF y veréis qué sorpresa.

De momento comparamos los tamaños que nos han salido en ambas hojas. No os fijéis en la calidad, son PDF en A4 reducidos bastante sólo para ver que el tamaño del QR impreso en el contenedor es, a simple vista, muy similar:

Y ahora sí, abrimos con Acrobat y comprobamos calidad y tamaño:

Este es el primero, el que hemos configurado con 300 px. Vemos que el tamaño es «casi» el solicitado de 35 mm, se nos va 8 centésimas partes de milímetro. La calidad podemos ver que también es buena, la imagen, como puede verse en la parte superior, está ampliada un 175%

Y este es el segundo, el que parecía que se veía borroso pero que podéis ver que la calidad es perfecta y también lo estamos viendo aumentado en un 175%. Únicamente, que como la imagen tiene muchos menos pixeles a distribuir, pues la medida no es tan exacta, en este caso se nos va de casi 3 décimas de milímetro. Obviamente este error es casi despreciable y para trabajos normales podríamos trabajar con resoluciones muy pequeñas sin mayores problemas.

Y para finalizar, pues vamos a sacar por impresora ambos PDF  a ver si en el papel y con la regla en la mano las cosas son como parecen:

Y ahí los tenemos, justo lo que andábamos buscando.

Si ponemos uno sobre otro:

Vemos que la diferencia es casi inapreciable al ojo, si acaso, se aprecia más mi «pulso de relojero» a la hora de cuadrar ambos papeles y sacar la foto y las limitaciones de la modesta cámara de mi móvil, pero en cuanto a la calidad del QR no parece que haya nada que objetar.

Como últimos ajustes, será necesario conservar el visualizador web en la presentación con la que vayamos a trabajar para que procese el JS, pero nada nos impide ocultarlo dándole unas dimensiones de 1 x 1 px:

Y adaptar el tamaño del contenedor al tamaño del QR:

Y eso ha sido todo. Una vez que se sabe cómo funcionan los QR y se dispone de los scripts es pan comido. Hemos visto que podemos ajustar perfectamente el tamaño tanto en pantalla con los svg o impresos con los png como acabamos de ver, teniendo en ambos casos una calidad perfecta.

A continuación, dejo para su descarga un zip que contiene:

      • El script en JS que hemos creado para el campo versionytamano, tanto con comentarios como sin ellos para que ocupe menos.
      • El archivo WampiQRv2.html para hacer pruebas con el navegador.
      • El archivo QR_Wampirius_v2.fmp12 que he usado para esta entrada y del que están sacadas las capturas (recordad que requiere FileMaker 19).
      • El script kjua.js
      • El script rewritejs.js (rewrite-png-pHYs-chuk)

Descarga: Archivos QR FileMaker v.2

Recordando que los scripts kjua y rewrite-png-pHYs-chunk, que nosotros hemos rebautizado como rewritejs.js se los debemos a sus autores: Lars Jung y Michael Borcherds respectivamente y a la generosidad que han tenido al ponerlos a disposición de todo el mundo en GitHub

Y esto es todo. Con esto podemos dar por finalizado el tema de los QR en FileMaker, aunque doy por supuesto que hay cosillas que se pueden mejorar o hacer de otras formas más eficientes, así que cualquier idea, comentario o sugerencia será bienvenida.

¡Hasta la próxima entrada! (A ver qué fruta toca…)

Nota: La imagen de cabecera es una adaptación de una fotografía libre de derechos de Birgit Böllinger «bboellinger» disponible en Pixabay

Deja una respuesta

No está permitida la inserción de ningún dato de carácter personal (mail, tef...). Cualquier comentario que los contenga será editado o eliminado.

Por favor, si dejas un comentario pon cualquier nombre para poderme dirigir a ti pero que no te identifique

El comentario es totalmente anónimo. No se almacena la IP