Foto: Phil Roeder
Uso del módulo Image‑Filter y del atributo srcset para redimensionar imágenes al vuelo
El diseño web adaptable se ha convertido en la norma para los sitios y las aplicaciones web modernos, ya que ofrece una experiencia coherente en una amplia variedad de dispositivos y, al mismo tiempo, optimiza la visualización para cada uno de ellos. Sin embargo, los dispositivos modernos no solo varían en cuanto al tamaño de la pantalla, sino también en la densidad de píxeles. La etiqueta HTML5 img ofrece una serie de funciones que permiten al navegador seleccionar el recurso más adecuado si el servidor proporciona varias versiones. Si el sitio web ofrece varios tamaños distintos de una misma imagen, el navegador puede elegir el que mejor se adapte a su entorno actual.
Por tanto, las imágenes adaptables permiten que el navegador web genere una representación que se ajuste fielmente a la intención del diseñador. Esto mejora la experiencia del usuario, pero también supone una carga adicional para los equipos de desarrollo y operaciones, que ahora deben crear e implementar numerosas variantes de los recursos de imagen, además de la imagen predeterminada.
En esta entrada del blog mostramos cómo utilizar el módulo Image‑Filter para NGINX y NGINX Plus con el fin de ofrecer imágenes adaptables sin la complicación de crear y gestionar infinidad de variantes de recursos de imagen. En su lugar, podemos implementar una única versión «de origen» de cada imagen, que NGINX o NGINX Plus redimensiona sobre la marcha. La información de esta entrada se aplica tanto a NGINX Open Source como a NGINX Plus (excepto las instrucciones específicas de Instalación del módulo Image‑Filter); para abreviar, utilizamos NGINX Plus en toda la entrada.
El atributo srcset Attribute
La principal herramienta para ofrecer imágenes adaptables es el atributo srcset de la etiqueta img de HTML5. Podemos utilizarlo para especificar distintas variantes de un recurso de imagen para diferentes densidades de píxeles y tamaños del área de visualización. Área de visualización es un término genérico que designa el espacio de visualización disponible para el navegador web, ya sea en una ventana de un ordenador de escritorio o en una aplicación a pantalla completa de un dispositivo móvil.
En el siguiente ejemplo, el atributo src define una imagen predeterminada para los navegadores que no admiten el atributo srcset attribute y el atributo srcset especifica dos variantes: una para pantallas con una densidad de píxeles estándar (1x) y otra para pantallas con el doble de densidad de píxeles, como las pantallas Retina™ de Apple y algunos monitores 4K (2x).
<img src="/images/mylogo-default.png" srcset="/images/mylogo-density1.png 1x, /images/mylogo-density2.png 2x">El siguiente ejemplo, más sofisticado, define varias variantes de un recurso de imagen que se mostrarán en función del ancho del área de visualización. El atributo sizes especifica que el navegador renderiza una imagen en la mitad del área de visualización si esta tiene un ancho superior a 10em y, de lo contrario, utiliza toda el área de visualización. El navegador determina cuánto espacio hay disponible para la imagen y selecciona la variante del recurso de imagen que mejor se ajusta al espacio disponible; normalmente, «redondea hacia arriba» hasta el siguiente ancho (sufijo w) y cambia internamente el tamaño de la imagen para que ocupe exactamente el espacio disponible.
<img src="/images/racecar-default.jpg" sizes="(min-width: 10em) 50vw, 100vw"
srcset="/images/racecar-100px.jpg 100w, /images/racecar-225px.jpg 225w, /images/racecar-450px.jpg 450w, /images/racecar-675px.jpg 675w">Este enfoque para ofrecer imágenes adaptables mediante la especificación de diversas variantes de recursos de imagen es fácil de programar y muy eficaz. Sin embargo, plantea dificultades a la hora de crear y gestionar las propias variantes. Es necesario redimensionar muchas imágenes durante la preproducción y alojar un número mucho mayor de archivos en el servidor. Ajustar el número y el tamaño óptimos de cada variante puede llevar mucho tiempo, lo que a su vez dificulta comprobar que todas las variantes de los recursos de imagen sean accesibles.
Para obtener más información sobre el atributo srcset y otras técnicas para crear imágenes adaptables, consulta esta excelente entrada de blog.
Instalación del módulo de filtrado de imágenes
El procedimiento para obtener el módulo Image‑Filter difiere entre NGINX Plus y NGINX.
Instalación del módulo Image‑Filter para NGINX Plus
El módulo Image‑Filter está disponible como módulo dinámico gratuito para los suscriptores de NGINX Plus.
- Obtenga el módulo instalándolo desde el repositorio de NGINX Plus. Para sistemas Ubuntu y Debian:
$ sudo apt-get install nginx-plus-module-image-filter- Para sistemas RedHat, CentOS y Oracle Linux:
$ sudo yum install nginx-plus-module-image-filter- Habilite el módulo incluyendo una directiva
load_modulepara él en el contexto de nivel superior («main») del archivo de configuración nginx.conf (es decir, no en los contextoshttpnistream).
load_module modules/ngx_http_image_filter_module.so;- Recargue NGINX Plus para cargar el módulo Image‑Filter en la instancia en ejecución.
$ sudo nginx -s reload>Instalación del módulo de filtrado de imágenes para NGINX Open Source
La forma más sencilla de instalar el módulo Image‑Filter es obtenerlo del repositorio oficial de NGINX. Siga estas instrucciones para configurar el sistema de modo que pueda acceder al repositorio oficial de NGINX y, a continuación, instálelo con el gestor de paquetes de su sistema operativo.
Para sistemas Ubuntu y Debian:
$ sudo apt-get install nginx-module-image-filterPara sistemas Red Hat, CentOS y Oracle Linux:
$ sudo yum install nginx-module-image-filterUna vez instalado, siga los pasos 2 y 3 de «Instalación del módulo de filtrado de imágenes para NGINX Plus» para configurar NGINX y volver a cargar la configuración.
También es posible compilar el módulo Image‑Filter a partir del código fuente y cargarlo como módulo compilado estáticamente o como módulo dinámico. Para obtener más información, consulte la Guía de administración de NGINX Plus.
Adaptación del tamaño de la imagen a la densidad de píxeles
Con el módulo Image‑Filter, podemos crear e implementar una única versión «de origen» de cada imagen y hacer que NGINX Plus cambie su tamaño sobre la marcha para ofrecer cualquier variante de tamaño que solicite el navegador. Podemos ajustar con precisión las páginas web y las imágenes adaptables íntegramente desde el código fuente HTML, sin tener que cambiar manualmente el tamaño de las imágenes ni implementarlas en nuestro servidor web.
En este archivo HTML de ejemplo, definimos cuatro variantes de imagen para dispositivos con distintas densidades de píxeles.
<!DOCTYPE html><html>
<head>
<title>Responsive Logo</title>
</head>
<body>
<h2>Logo selection based on pixel density</h2>
<img src="/img400/mylogo.png"
srcset="/img400/mylogo.png 1x, /img800/mylogo.png 2x, /img1200/mylogo.png 3x, /img1600/mylogo.png 4x">
</body>
</html>Los directorios /img400, /img800, /img1200 y /img1600 no existen realmente. En su lugar, la siguiente configuración de NGINX Plus identifica las solicitudes de recursos cuyo prefijo es /img y las transforma en solicitudes para cambiar el tamaño de la imagen del nombre de archivo original (por ejemplo, mylogo.png en el HTML anterior).
server { listen 80;
root /var/www/public_html;
location ~ ^/img([0-9]+)(?:/(.*))?$ {
alias /var/www/source_images/$2;
image_filter_buffer 10M;
image_filter resize $1 -;
}
}El bloque server define cómo gestiona NGINX Plus las solicitudes HTTP entrantes. La directiva listen indica a NGINX Plus que escuche en el puerto 80, el puerto predeterminado para el tráfico HTTP. La directiva root especifica la ubicación de este sitio web en el disco. En este sencillo ejemplo, utilizamos un sitio web estático alojado en NGINX Plus, aunque también es habitual que NGINX Plus actúe como proxy inverso para contenido dinámico o como conector de aplicaciones, como FastCGI. Todos estos casos de uso pueden aprovechar el módulo Image‑Filter tal como se describe aquí, implementando las imágenes de origen en el servidor NGINX Plus.
El bloque location utiliza una expresión regular para identificar las solicitudes de recursos almacenados en cualquier directorio cuyo nombre comience por /img seguido de uno o varios dígitos. Los dígitos se capturan en la variable $1 y el nombre de archivo que aparece a continuación se captura en la variable $2. A continuación, utilizamos la directiva alias para atender esta solicitud desde el directorio del disco que contiene nuestras imágenes de origen. Tenga en cuenta que este directorio no se encuentra en la ruta root, por lo que los clientes no pueden solicitar directamente las imágenes de origen.
Dado que es probable que nuestras imágenes de origen sean muy grandes, quizá de miles de píxeles de ancho, debemos asegurarnos de que el módulo Image‑Filter asigne suficiente memoria para cargarlas y cambiar su tamaño. En este ejemplo, utilizamos la directiva image_filter_buffer para admitir archivos de imagen de hasta 10 MB.
Por último, la directiva image_filter indica al módulo Image‑Filter que cambie el tamaño de la imagen de origen al ancho obtenido del sufijo del nombre del directorio /img. El guion (‑) indica a NGINX Plus que mantenga la relación de aspecto de la imagen de origen.
Consideraciones para el uso en producción
La configuración descrita en Adaptación del tamaño de la imagen a la densidad de píxeles puede proporcionar una imagen en cualquier variante de tamaño en función del nombre del directorio utilizado para solicitarla. Sin embargo, en un entorno de producción no queremos esperar a que el servidor web cambie el tamaño de las imágenes con cada solicitud. Esto perjudica la latencia general y también puede suponer una sobrecarga considerable de la CPU.
La solución más eficaz consiste en almacenar en caché las variantes redimensionadas de nuestras imágenes, de modo que las solicitudes posteriores de cada variante se atiendan desde la caché, sin pasar por el módulo Image‑Filter. Podemos conseguirlo mediante la configuración de NGINX Plus, definiendo un servidor virtual independiente que se encargue de redimensionar las imágenes y redirigiendo las solicitudes a este mediante proxy únicamente si el tamaño de imagen solicitado aún no está en la caché. A esto lo denominamos «servidor de imágenes adaptables».
Figura 1. Configuración de producción de un servidor de imágenes adaptables con el almacenamiento en caché habilitado en el servidor web frontend
También debemos tener en cuenta las implicaciones de seguridad de permitir que solicitudes arbitrarias realicen operaciones de redimensionamiento de imágenes. Tener configurado el almacenamiento en caché no sirve de nada si un atacante realiza rápidamente solicitudes de variantes únicas de recursos de imagen, como /img1001/mylogo.png, /img1002/mylogo.png, /img1003/mylogo.png, etc. Incluso con un volumen de solicitudes relativamente bajo, estos ataques pueden provocar una denegación de servicio (DoS) debido al uso excesivo de la CPU. Para evitarlo, aplicamos un límite de solicitudes al servidor de imágenes adaptables, pero no al servidor frontend que contiene las variantes almacenadas en caché. La siguiente configuración amplía la configuración de Adaptación del tamaño de la imagen a la densidad de píxeles mediante la aplicación de almacenamiento en caché y límites de solicitudes al módulo Image-Filter.
proxy_cache_path /var/www/imgcache levels=1 keys_zone=resized:1m max_size=256m;
server {
listen 80;
root /var/www/public_html;
location ~ ^/img([0-9]+)(?:/(.*))?$ {
proxy_pass http://127.0.0.1:9001;
proxy_cache resized;
proxy_cache_valid 180m;
}
}
limit_req_zone "1" zone=2persec:32k rate=2r/s;
server {
listen 9001;
allow 127.0.0.1;
deny all;
limit_req zone=2persec burst=10;
location ~ ^/img([0-9]+)(?:/(.*))?$ {
alias /var/www/source_images/$2;
image_filter_buffer 10M;
image_filter resize $1 -;
}
}Empezamos definiendo la ubicación de nuestras imágenes almacenadas en caché mediante la directiva proxy_cache_path. El parámetro keys_zone define una zona de memoria compartida para el índice de la caché (denominada resized) y le asigna 1 MB, suficiente para unas 8.000 imágenes redimensionadas. El parámetro max_size define el punto a partir del cual NGINX Plus empieza a eliminar de la caché las imágenes solicitadas con menor frecuencia recientemente para dejar espacio a nuevos elementos almacenados en caché.
La directiva location del servidor web frontend (el que escucha en el puerto 80) utiliza la directiva proxy_pass para enviar las solicitudes cuyo prefijo es /img al servidor de imágenes adaptables alojado internamente (127.0.0.1:9001). La directiva proxy_cache habilita el almacenamiento en caché para esta ubicación especificando el nombre de la caché (resized) que se utilizará para almacenar las respuestas del servidor de imágenes adaptables. La directiva proxy_cache_valid garantiza que las imágenes redimensionadas se conserven en la caché durante al menos 180 minutos (a menos que la caché haya superado el valor de max_size y se encuentren entre las solicitadas menos recientemente) y que no se almacenen en caché las respuestas erróneas del servidor de imágenes adaptables.
Para obtener una descripción detallada del almacenamiento en caché, consulte Guía sobre el almacenamiento en caché con NGINX y NGINX Plus.
Antes de definir el propio servidor de imágenes adaptables, especificamos un límite de solicitudes mediante la directiva limit_req_zone. La directiva no aplica por sí misma ningún límite, sino que define un límite de dos solicitudes por segundo que después se aplica al servidor de imágenes adaptables incluyendo la directiva limit_req en su bloque server (consulte el párrafo siguiente). Normalmente, un límite de solicitudes se asocia a un atributo de la solicitud, pero en este caso especificamos el valor de clave estático "1" para que el límite se aplique a todos los solicitantes. Establecemos el tamaño de la zona de memoria compartida en el valor mínimo posible, 3 KB, porque nuestra clave tiene una cardinalidad fija de uno.
El bloque server del servidor de imágenes adaptables escucha en el puerto 9001. Incluimos las directivas allow y deny para especificar que solo localhost (el servidor web frontend) puede conectarse al servidor de imágenes adaptables. A continuación, aplicamos el límite de solicitudes definido anteriormente mediante la directiva limit_req; el parámetro burst permite 10 solicitudes simultáneas antes de aplicar el límite. Una vez que el límite entra en vigor, las solicitudes excedentes se retrasan hasta que puedan procesarse dentro del límite.
El bloque location es idéntico al de Adaptación del tamaño de la imagen a la densidad de píxeles, pero ahora solo se utiliza cuando la imagen solicitada no está en la caché y no se ha superado el límite de solicitudes.
En esta configuración básica, una única instancia de NGINX Plus actúa tanto como servidor web frontend como servidor de imágenes adaptables. El procesamiento de imágenes puede requerir una gran cantidad de recursos computacionales, lo que puede generar cargas de trabajo extremadamente elevadas y exponer NGINX Plus a ataques de denegación de servicio (DoS). Para evitar que el servidor web frontend no pueda aceptar nuevas solicitudes de inmediato porque todos los procesos de trabajo estén ocupados con solicitudes de redimensionamiento de imágenes, recomendamos ejecutar una instancia independiente de NGINX Plus dedicada al procesamiento de imágenes. De este modo, los procesos de trabajo del servidor web frontend quedan aislados de los que realizan el procesamiento de imágenes. Para ejecutar una instancia independiente de NGINX Plus en el mismo host, especifique un archivo de configuración diferente en la línea de comandos:
$ sudo nginx -c /etc/nginx/resize-server.confImágenes adaptables en acción
La forma más eficaz de ver las imágenes adaptables en acción es observar cómo un navegador decide qué variante de imagen de srcset utilizar a medida que cambia el tamaño del área de visualización. Este es el código fuente HTML de una galería de imágenes sencilla. Ten en cuenta que, a efectos de demostración, las variantes de tamaño son ligeramente diferentes para cada imagen, lo que crea muchos «puntos de ruptura» posibles en los que el navegador puede elegir una variante distinta.
<!DOCTYPE html>
<html>
<head>
<title>Responsive Image Gallery</title>
</head>
<body>
<h2>Responsive Image Gallery</h2>
<img src="/img100/1-dominos.jpg" sizes="(min-width: 20em) 40vw, 100vw"
srcset="/img110/1-dominos.jpg 110w, /img210/1-dominos.jpg 210w, /img310/1-dominos.jpg 310w, /img410/1-dominos.jpg 410w, /img510/1-dominos.jpg 510w, /img610/1-dominos.jpg 610w">
<img src="/img100/2-sign.jpg" sizes="(min-width: 20em) 40vw, 100vw"
srcset="/img120/2-sign.jpg 120w, /img220/2-sign.jpg 220w, /img330/2-sign.jpg 330w, /img420/2-sign.jpg 420w, /img520/2-sign.jpg 520w, /img620/2-sign.jpg 620w">
<img src="/img100/3-thruppence.jpg" sizes="(min-width: 20em) 40vw, 100vw"
srcset="/img130/3-thruppence.jpg 130w, /img230/3-thruppence.jpg 230w, /img330/3-thruppence.jpg 330w, /img440/3-thruppence.jpg 440w, /img550/3-thruppence.jpg 550w, /img660/3-thruppence.jpg 660w">
<img src="/img100/4-aces.jpg" sizes="(min-width: 20em) 40vw, 100vw"
srcset="/img140/4-aces.jpg 140w, /img240/4-aces.jpg 240w, /img340/4-aces.jpg 340w, /img440/4-aces.jpg 440w, /img540/4-aces.jpg 540w, /img640/4-aces.jpg 640w">
</body>
</html>Las capturas de pantalla que aparecen a continuación muestran el contenido de esta página web en un navegador Chrome con el Inspector abierto en la pestaña Red. La columna Nombre muestra la ruta de cada variante de imagen solicitada al servidor, lo que nos permite ver el tamaño elegido sin tener que consultar los registros del servidor web.
Con el área de visualización estrecha de la Figura 2, el navegador ha elegido imágenes de entre 220 y 310 píxeles de ancho (los sufijos numéricos de los nombres de los directorios /img de la columna «Nombre» se encuentran dentro de ese intervalo).
Figura 2. Galería de imágenes adaptable cuando el área de visualización es estrecha
Cuando ampliamos la ventana del navegador en la Figura 3, el navegador elige imágenes de entre 440 y 540 píxeles de ancho (las cuatro últimas imágenes de la lista). El valor de estas imágenes en la columna Iniciador es Otro.
Figura 3. Galería de imágenes adaptable cuando la ventana gráfica es más ancha
Conclusión
Con NGINX Plus y el módulo Image‑Filter, podemos ofrecer el tamaño de imagen óptimo para las condiciones actuales del navegador. Y podemos hacerlo sin tener que redimensionar las imágenes antes de la producción, procesarlas por lotes ni gestionar cientos de variantes de recursos de imagen en el disco. Una forma más en la que NGINX Plus le ayuda a ofrecer aplicaciones de forma impecable.
Pruebe usted mismo las imágenes adaptables con NGINX Plus: comience hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre sus casos de uso.
Sobre el autor

Artículos relacionados del blog
Únete a F5 NGINX en AppWorld 2024
Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.
Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.
Exposición de APIs en Kubernetes
La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».
NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.
Presentamos NGINX Plus R22
NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.
Presentamos NGINX Plus R17
NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.