Saltar a contenido

jpeg: Módulo de filtro JPEG de NGINX

Instalación

Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:

  • RedHat Enterprise Linux 7, 8, 9 y 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 y Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-jpeg
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-jpeg

Habilita el módulo añadiendo lo siguiente al principio de /etc/nginx/nginx.conf:

load_module modules/ngx_http_jpeg_filter_module.so;

Este documento describe nginx-module-jpeg v1.0.1 lanzado el 04 de septiembre de 2018.


Módulo de filtro Nginx para añadir superposiciones en JPEGs al vuelo con libmodjpeg.

Con libmodjpeg puedes superponer una imagen (enmascarada) sobre un JPEG existente de la manera más sin pérdida posible. Los cambios en el JPEG solo ocurren donde se aplica la imagen superpuesta. Todas las modificaciones suceden en el dominio DCT, por lo que el JPEG se decodifica y codifica sin pérdidas.

Usos Típicos

Este módulo de filtro puede añadir superposiciones (por ejemplo, un logo, marca visual) en JPEGs cuando son solicitados.

Algunas ideas:

  • Considera que eres un fotógrafo y tienes una galería de imágenes en tu sitio web. Sin codificar tu logo (marca, marca de agua, ...) en estas imágenes, puedes aplicarlo en el momento en que se solicita la imagen. Siempre que actualices tu logo, solo actualiza la configuración de nginx y listo. No es necesario reprocesar todas tus imágenes.
  • Tienes una tienda en línea con miles de imágenes de productos. Con solo configurar nginx puedes añadir tu logo a todas las imágenes de productos. No tienes que procesar todas las imágenes de productos.
  • Tienes un servicio de pago. Añade una marca de agua a todas las imágenes si el usuario no está suscrito. Si el usuario está suscrito, no apliques la marca de agua o coloca solo un pequeño logo en las imágenes sin tocar las imágenes originales.
  • En tu sitio web, los usuarios registrados pueden subir imágenes. Añade el avatar del usuario a la imagen que subió sin procesarla después de la carga. Si el usuario cambia su avatar, todas sus imágenes tendrán automáticamente el nuevo avatar.

Pruébalo

Para probar este módulo de filtro, descarga la imagen de docker

docker pull ioppermann/modjpeg-nginx:latest

El contenedor de docker expone el puerto TCP 80 y espera un directorio con imágenes montado en /images, por ejemplo:

docker run -it --rm --name=modjpeg-nginx \
   --mount type=bind,src=$PWD/images,dst=/images,readonly \
   -p 8080:80 \
   ioppermann/modjpeg-nginx:latest

Ahora puedes navegar a http://localhost:8080/ y hacer clic en las imágenes listadas. El logo de modjpeg se aplicará en la esquina superior izquierda. Por defecto, solo se procesan imágenes que son más pequeñas que 10MB. Detén el contenedor presionando Ctrl-c.

El filtro puede ser controlado por estas variables de entorno:

Nombre Predeterminado Descripción
MJ_GRACEFUL on Ver jpeg_filter_graceful
MJ_BUFFER 10M Ver jpeg_filter_buffer
MJ_MAX_PIXEL 0 Ver jpeg_filter_max_pixel
MJ_DROPON_ALIGN "top left" Ver jpeg_filter_dropon_align
MJ_DROPON_OFFSET "0 0" Ver jpeg_filter_dropon_offset
MJ_DROPON_FILE "/usr/local/nginx/conf/dropon.png" Ver jpeg_filter_dropon_file

El siguiente ejemplo permitirá imágenes de hasta 150 megapíxeles (MJ_MAX_PIXEL) y 100MB en tamaño de archivo (MJ_BUFFER). El logo se colocará en la esquina inferior derecha (MJ_DROPON_ALIGN) con un desplazamiento de -15px horizontal y verticalmente (MJ_DROPON_OFFSET).

docker run -it --rm --name=modjpeg-nginx \
   --mount type=bind,src=$PWD/images,dst=/images,readonly \
   -p 8080:80 \
   -e MJ_MAX_PIXEL=150000000 \
   -e MJ_BUFFER=100M \
   -e MJ_DROPON_ALIGN="bottom right" \
   -e MJ_DROPON_OFFSET="-15 -15" \
   ioppermann/modjpeg-nginx:latest

Para cambiar el logo, puedes montar un volumen adicional o ponerlo en el directorio que ya montas, por ejemplo:

docker run -it --rm --name=modjpeg-nginx \
   --mount type=bind,src=$PWD/images,dst=/images,readonly \
   -p 8080:80 \
   -e MJ_DROPON_FILE="/images/logo.png" \
   ioppermann/modjpeg-nginx:latest

Clonar e instalar libmodjpeg

git clone https://github.com/ioppermann/libmodjpeg.git cd libmodjpeg cmake . make make install cd ..

Clonar modjpeg-nginx

git clone https://github.com/ioppermann/modjpeg-nginx.git

Descargar e instalar nginx

wget 'http://nginx.org/download/nginx-1.15.1.tar.gz' tar -xvzf nginx-1.15.1.tar.gz cd nginx-1.15.1

Configurar como módulo estático, o ...

./configure --add_module=../modjpeg-nginx

... configurar como módulo dinámico (a partir de nginx 1.9.11)

./configure --add_dynamic_module=../modjpeg-nginx

Si la biblioteca libmodjpeg no se encuentra, añade por ejemplo '--with-ld-opt=-L/usr/local/lib' a

las opciones de configuración si fue instalada en /usr/local/lib

Puede que desees usar las otras opciones de './configure' que se utilizan

en tu compilación actual de nginx. Revisa la salida de 'nginx -V'.

make make install

Si configuraste modjpeg-nginx como módulo dinámico, debes cargar el módulo al principio de la configuración

```nginx
...
load_module modules/ngx_http_jpeg_filter_module.so;
...

Sinopsis

   ...

   location /gallery {
      # habilitar módulo de filtro jpeg
      jpeg_filter on;

      # limitar tamaños de imagen a 9 megapíxeles
      jpeg_filter_max_pixel 9000000;

      # limitar tamaño de archivo de imagen a 5 megabytes
      jpeg_filter_buffer 5M;

      # entregar las imágenes sin modificar si se aplica uno de los límites
      jpeg_filter_graceful on;

      # pixelar la imagen
      jpeg_filter_effect pixelate;

      # añadir un logo enmascarado en la esquina inferior derecha
      # con una distancia de 10 píxeles desde el borde
      jpeg_filter_dropon_align bottom right;
      jpeg_filter_dropon_offset -10 -10;
      jpeg_filter_dropon_file /path/to/logo.jpg /path/to/mask.jpg;
   }

   ...

O úsalo con OpenResty's ngx_http_lua_module y un logo PNG:

   ...

   location /gallery {
      set_by_lua_block $valign {
         local a = { 'top', 'center', 'bottom' }
         return a[math.random(#a)]
      }

      set_by_lua_block $halign {
         local a = { 'left', 'center', 'right' }
         return a[math.random(#a)]
      }

      # habilitar módulo de filtro jpeg
      jpeg_filter on;

      # limitar tamaños de imagen a 9 megapíxeles
      jpeg_filter_max_pixel 9000000;

      # limitar tamaño de archivo de imagen a 5 megabytes
      jpeg_filter_buffer 5M;

      # entregar las imágenes sin modificar si se aplica uno de los límites
      jpeg_filter_graceful on;

      # pixelar la imagen
      jpeg_filter_effect pixelate;

      # añadir un logo en una posición aleatoria
      jpeg_filter_dropon_align $valign $halign;
      jpeg_filter_dropon_file /path/to/logo.png;
   }

   ...

O genera un logo con Lua-GD:

http {
   ...
   ...
   server {
      ...
      location /gallery {
           set_by_lua_block $logobytestream {
              local gd = require "gd"

              local im = gd.create(210, 70)
              local white = im:colorAllocate(255, 255, 255)
              local black = im:colorAllocate(0, 0, 0)
              im:filledRectangle(0, 0, 140, 80, white)
              im:string(gd.FONT_LARGE, 10, 10, "Hola modjpeg", black)
              im:string(gd.FONT_LARGE, 10, 40, os.date("%c"), black);
              return im:jpegStr(85)
           }

       # habilitar módulo de filtro jpeg
       jpeg_filter on;

           # limitar tamaños de imagen a 9 megapíxeles
           jpeg_filter_max_pixel 9000000;

           # limitar tamaño de archivo de imagen a 5 megabytes
           jpeg_filter_buffer 5M;

           # entregar las imágenes sin modificar si se aplica uno de los límites
           jpeg_filter_graceful on;

           # pixelar la imagen
           jpeg_filter_effect pixelate;

           # añadir un logo generado en la esquina inferior derecha
           # con una distancia de 10 píxeles desde el borde
           jpeg_filter_dropon_align bottom right;
           jpeg_filter_dropon_offset -10 -10;
           jpeg_filter_dropon_memory $logobytestream;
      }
      ...
   }
   ...
}

Directivas

jpeg_filter

Sintaxis: jpeg_filter on | off

Predeterminado: jpeg_filter off

Contexto: location

Habilita el módulo de filtro jpeg.

Esta directiva está desactivada por defecto.

jpeg_filter_max_pixel

Sintaxis: jpeg_filter_max_pixel pixel

Predeterminado: 0

Contexto: http, server, location

Número máximo de píxeles en la imagen para operar. Si la imagen tiene más píxeles (ancho * alto) que pixel, el filtro jpeg devolverá un "415 Unsupported Media Type". Establece jpeg_filter_graceful en on para entregar la imagen sin cambios. Establece el máximo de píxeles en 0 para ignorar las dimensiones de la imagen.

Esta directiva está establecida en 0 por defecto.

jpeg_filter_buffer

Sintaxis: jpeg_filter_buffer size

Predeterminado: 2M

Contexto: http, server, location

El tamaño máximo del archivo de la imagen para operar. Si el tamaño del archivo es mayor que size, el filtro jpeg devolverá un "415 Unsupported Media Type". Establece jpeg_filter_graceful en on para entregar la imagen sin cambios.

Esta directiva está establecida en 2 megabytes por defecto.

jpeg_filter_optimize

Sintaxis: jpeg_filter_optimize on | off

Predeterminado: off

Contexto: http, server, location

Al entregar, optimiza las tablas de Huffman de la imagen.

Esta directiva está desactivada por defecto.

jpeg_filter_progressive

Sintaxis: jpeg_filter_progressive on | off

Predeterminado: off

Contexto: http, server, location

Al entregar, habilita la codificación progresiva de la imagen.

Esta directiva está desactivada por defecto.

jpeg_filter_arithmetric

Sintaxis: jpeg_filter_arithmetric on | off

Predeterminado: off

Contexto: http, server, location

Al entregar, habilita la codificación aritmética de la imagen. Esto anulará la directiva jpeg_filter_optimize. La codificación aritmética generalmente no es compatible con los navegadores.

Esta directiva está desactivada por defecto.

jpeg_filter_graceful

Sintaxis: jpeg_filter_graceful on | off

Predeterminado: off

Contexto: http, server, location

Permite entregar la imagen sin cambios en caso de que las directivas jpeg_filter_max_width, jpeg_filter_max_height o jpeg_filter_buffer devuelvan un error "415 Unsupported Media Type".

Esta directiva está desactivada por defecto.

jpeg_filter_effect

Sintaxis: jpeg_filter_effect grayscale | pixelate

Sintaxis: jpeg_filter_effect darken | brighten value

Sintaxis: jpeg_filter_effect tintblue | tintyellow | tintred | tintgreen value

Predeterminado: -

Contexto: location

Aplica un efecto a la imagen.

grayscale eliminará todos los componentes de color de la imagen. Esto solo se aplica a imágenes en el espacio de color YCbCr.

pixelate pixelará la imagen en bloques de 8x8 píxeles al establecer los coeficientes AC en todos los componentes a 0.

darken oscurecerá la imagen disminuyendo los coeficientes DC en el componente Y por value. Esto solo se aplica a imágenes en el espacio de color YCbCr.

brighten aclarará la imagen aumentando los coeficientes DC en el componente Y por value. Esto solo se aplica a imágenes en el espacio de color YCbCr.

tintblue teñirá la imagen de azul aumentando los coeficientes DC en el componente Cb por value. Esto solo se aplica a imágenes en el espacio de color YCbCr.

tintyellow teñirá la imagen de azul disminuyendo los coeficientes DC en el componente Cb por value. Esto solo se aplica a imágenes en el espacio de color YCbCr.

tintred teñirá la imagen de rojo aumentando los coeficientes DC en el componente Cr por value. Esto solo se aplica a imágenes en el espacio de color YCbCr.

tintgreen teñirá la imagen de verde disminuyendo los coeficientes DC en el componente Cr por value. Esto solo se aplica a imágenes en el espacio de color YCbCr.

Esta directiva no está establecida por defecto.

Todos los parámetros pueden contener variables.

jpeg_filter_dropon_align

Sintaxis: jpeg_filter_dropon_align [top | center | bottom] [left | center | right]

Predeterminado: center center

Contexto: location

Alinea la superposición en la imagen. Usa la directiva jpeg_filter_dropon_offset para desplazar la superposición desde la alineación.

Esta directiva debe establecerse antes de jpeg_filter_dropon para tener efecto en la superposición.

Esta directiva aplicará la superposición en el centro de la imagen por defecto.

Todos los parámetros pueden contener variables.

jpeg_filter_dropon_offset

Sintaxis: jpeg_filter_dropon_offset vertical horizontal

Predeterminado: 0 0

Contexto: location

Desplaza la superposición por vertical y horizontal píxeles desde la alineación dada con la directiva jpeg_filter_dropon_align. Usa un valor negativo para mover la superposición hacia arriba o a la izquierda y un valor positivo para mover la superposición hacia abajo o a la derecha.

Esta directiva debe establecerse antes de jpeg_filter_dropon para tener efecto en la superposición.

Esta directiva no aplicará un desplazamiento por defecto.

Todos los parámetros pueden contener variables.

jpeg_filter_dropon_file

Sintaxis: jpeg_filter_dropon_file image

Sintaxis: jpeg_filter_dropon_file image mask

Predeterminado: -

Contexto: location

Aplica una superposición a la imagen. La superposición se da mediante una ruta a una imagen JPEG o PNG para image y opcionalmente una ruta a una imagen JPEG para mask. Si no se proporciona una imagen de máscara, la imagen se aplicará sin translucidez. Si se proporciona una imagen de máscara, solo se utilizará el componente de luminancia. Para la máscara, el negro significa totalmente translúcido y el blanco significa totalmente opaco. Cualquier valor intermedio mezclará la imagen subyacente y la superposición en consecuencia. Si image es una ruta a un PNG, la máscara será ignorada.

Esta directiva no está establecida por defecto.

Todos los parámetros pueden contener variables.

Si ninguno de los parámetros contiene variables, la superposición se carga durante la carga de la configuración. Si al menos un parámetro contiene variables, la superposición se cargará durante el procesamiento de la solicitud. Después de procesar la solicitud, la superposición se descargará.

Los archivos PNG como superposición son compatibles solo si libmodjpeg ha sido compilado con soporte para PNG.

jpeg_filter_dropon_memory

Sintaxis: jpeg_filter_dropon_memory $image

Sintaxis: jpeg_filter_dropon_memory $image $mask

Predeterminado: -

Contexto: location

Aplica una superposición a la imagen. La superposición se da mediante una variable que contiene un flujo de bytes de imagen JPEG o PNG para $image y opcionalmente una variable para un flujo de bytes de imagen JPEG para $mask. Si no se proporciona una imagen de máscara, la imagen se aplicará sin translucidez. Si se proporciona una imagen de máscara, solo se utilizará el componente de luminancia. Para la máscara, el negro significa totalmente translúcido y el blanco significa totalmente opaco. Cualquier valor intermedio mezclará la imagen subyacente y la superposición en consecuencia. Si $image es un PNG, la máscara será ignorada.

Esta directiva no está establecida por defecto.

Todos los parámetros se espera que sean variables.

La superposición siempre se cargará durante el procesamiento de la solicitud. Después de procesar la solicitud, la superposición se descargará.

Los flujos de bytes PNG como superposición son compatibles solo si libmodjpeg ha sido compilado con soporte para PNG.

Notas

Las directivas jpeg_filter_effect, jpeg_filter_dropon_align, jpeg_filter_dropon_offset, y jpeg_filter_dropon se aplican en el orden en que aparecen en el archivo de configuración de nginx, es decir, hace una diferencia si primero aplicas un efecto y luego añades una superposición o viceversa. En el primer caso, la superposición no será afectada por el efecto y en el segundo caso el efecto también se aplicará a la superposición.

Reconocimientos

Este módulo está fuertemente inspirado en el módulo de filtro de imagen de nginx con perspectivas de "Guía de Emiller para el Desarrollo de Módulos Nginx" y la guía de desarrollo de nginx.

GitHub

Puedes encontrar consejos adicionales de configuración y documentación para este módulo en el repositorio de GitHub para nginx-module-jpeg.