Pular para conteúdo

jpeg: Módulo de filtro JPEG do NGINX

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e 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

Ative o módulo adicionando o seguinte no início de /etc/nginx/nginx.conf:

load_module modules/ngx_http_jpeg_filter_module.so;

Este documento descreve o nginx-module-jpeg v1.0.1 lançado em 04 de setembro de 2018.


Módulo de filtro Nginx para adicionar sobreposições em JPEGs em tempo real com libmodjpeg.

Com libmodjpeg, você pode sobrepor uma imagem (mascarada) em um JPEG existente da forma mais sem perdas possível. As alterações no JPEG ocorrem apenas onde a imagem sobreposta é aplicada. Todas as modificações acontecem no domínio DCT, assim o JPEG é decodificado e codificado sem perdas.

Usos Típicos

Este módulo de filtro pode adicionar sobreposições (por exemplo, um logotipo, marca d'água visual) em JPEGs quando são solicitados.

Algumas ideias:

  • Considere que você é um fotógrafo e tem uma galeria de imagens em seu site. Sem codificar seu logotipo (marca, marca d'água, ...) diretamente nessas imagens, você pode aplicá-lo no momento em que a imagem é solicitada. Sempre que você atualizar seu logotipo, basta atualizar a configuração do nginx e está feito. Não há necessidade de reprocessar todas as suas imagens.
  • Você tem uma loja online com milhares de imagens de produtos. Com apenas a configuração do nginx, você pode adicionar seu logotipo a todas as imagens dos produtos. Você não precisa processar todas as imagens dos produtos.
  • Você tem um serviço pago. Adicione uma marca d'água a todas as imagens se o usuário não estiver inscrito. Se o usuário estiver inscrito, não aplique a marca d'água ou coloque apenas um pequeno logotipo nas imagens sem tocar nas imagens originais.
  • Em seu site, usuários registrados podem enviar imagens. Adicione o avatar do usuário à imagem que enviou a imagem sem processá-la após o upload. Se o usuário mudar seu avatar, todas as suas imagens terão automaticamente o novo avatar.

Experimente

Para experimentar este módulo de filtro, puxe a imagem do docker

docker pull ioppermann/modjpeg-nginx:latest

O contêiner docker expõe a porta TCP 80 e espera um diretório com imagens montado em /images, por exemplo:

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

Agora você pode navegar até http://localhost:8080/ e clicar nas imagens listadas. O logotipo do modjpeg será aplicado no canto superior esquerdo. Por padrão, apenas imagens que são menores que 10MB são processadas pelo filtro. Pare o contêiner pressionando Ctrl-c.

O filtro pode ser controlado por estas variáveis de ambiente:

Nome Padrão Descrição
MJ_GRACEFUL on Veja jpeg_filter_graceful
MJ_BUFFER 10M Veja jpeg_filter_buffer
MJ_MAX_PIXEL 0 Veja jpeg_filter_max_pixel
MJ_DROPON_ALIGN "top left" Veja jpeg_filter_dropon_align
MJ_DROPON_OFFSET "0 0" Veja jpeg_filter_dropon_offset
MJ_DROPON_FILE "/usr/local/nginx/conf/dropon.png" Veja jpeg_filter_dropon_file

O seguinte exemplo permitirá imagens com até 150 megapixels (MJ_MAX_PIXEL) e 100MB de tamanho de arquivo (MJ_BUFFER). O logotipo será colocado no canto inferior direito (MJ_DROPON_ALIGN) com um deslocamento de -15px horizontal e 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 mudar o logotipo, você pode montar um volume adicional ou colocá-lo no diretório que você já montou, por exemplo:

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

Baixar 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, ou ...

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

... configurar como módulo dinâmico (a partir do nginx 1.9.11)

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

Se a biblioteca libmodjpeg não for encontrada, adicione por exemplo '--with-ld-opt=-L/usr/local/lib' às

opções de configuração se ela foi instalada em /usr/local/lib

Você pode querer usar as outras opções './configure' que são usadas

na sua construção atual do nginx. Verifique a saída de 'nginx -V'.

make make install

Se você configurou o modjpeg-nginx como um módulo dinâmico, você deve carregar o módulo no início da configuração

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

Sinopse

   ...

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

      # limitar tamanhos de imagem a 9 megapixels
      jpeg_filter_max_pixel 9000000;

      # limitar o tamanho do arquivo de imagem a 5 megabytes
      jpeg_filter_buffer 5M;

      # entregar as imagens não modificadas se um dos limites se aplicar
      jpeg_filter_graceful on;

      # pixelar a imagem
      jpeg_filter_effect pixelate;

      # adicionar um logotipo mascarado no canto inferior direito
      # com uma distância de 10 pixels da borda
      jpeg_filter_dropon_align bottom right;
      jpeg_filter_dropon_offset -10 -10;
      jpeg_filter_dropon_file /path/to/logo.jpg /path/to/mask.jpg;
   }

   ...

Ou use-o com OpenResty's ngx_http_lua_module e um logotipo 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 tamanhos de imagem a 9 megapixels
      jpeg_filter_max_pixel 9000000;

      # limitar o tamanho do arquivo de imagem a 5 megabytes
      jpeg_filter_buffer 5M;

      # entregar as imagens não modificadas se um dos limites se aplicar
      jpeg_filter_graceful on;

      # pixelar a imagem
      jpeg_filter_effect pixelate;

      # adicionar um logotipo em uma posição aleatória
      jpeg_filter_dropon_align $valign $halign;
      jpeg_filter_dropon_file /path/to/logo.png;
   }

   ...

Ou gere um logotipo com 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, "Hello 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 tamanhos de imagem a 9 megapixels
           jpeg_filter_max_pixel 9000000;

           # limitar o tamanho do arquivo de imagem a 5 megabytes
           jpeg_filter_buffer 5M;

           # entregar as imagens não modificadas se um dos limites se aplicar
           jpeg_filter_graceful on;

           # pixelar a imagem
           jpeg_filter_effect pixelate;

           # adicionar um logotipo gerado no canto inferior direito
           # com uma distância de 10 pixels da borda
           jpeg_filter_dropon_align bottom right;
           jpeg_filter_dropon_offset -10 -10;
           jpeg_filter_dropon_memory $logobytestream;
      }
      ...
   }
   ...
}

Diretivas

jpeg_filter

Sintaxe: jpeg_filter on | off

Padrão: jpeg_filter off

Contexto: location

Habilita o módulo de filtro jpeg.

Esta diretiva está desativada por padrão.

jpeg_filter_max_pixel

Sintaxe: jpeg_filter_max_pixel pixel

Padrão: 0

Contexto: http, server, location

Número máximo de pixels na imagem para operar. Se a imagem tiver mais pixels (largura * altura) do que pixel, o filtro jpeg retornará um "415 Unsupported Media Type". Defina jpeg_filter_graceful como on para entregar a imagem inalterada. Defina o número máximo de pixels como 0 para ignorar as dimensões da imagem.

Esta diretiva está definida como 0 por padrão.

jpeg_filter_buffer

Sintaxe: jpeg_filter_buffer size

Padrão: 2M

Contexto: http, server, location

O tamanho máximo do arquivo da imagem para operar. Se o tamanho do arquivo for maior que size, o filtro jpeg retornará um "415 Unsupported Media Type". Defina jpeg_filter_graceful como on para entregar a imagem inalterada.

Esta diretiva está definida como 2 megabytes por padrão.

jpeg_filter_optimize

Sintaxe: jpeg_filter_optimize on | off

Padrão: off

Contexto: http, server, location

Ao entregar, otimize as tabelas de Huffman da imagem.

Esta diretiva está desativada por padrão.

jpeg_filter_progressive

Sintaxe: jpeg_filter_progressive on | off

Padrão: off

Contexto: http, server, location

Ao entregar, habilite a codificação progressiva da imagem.

Esta diretiva está desativada por padrão.

jpeg_filter_arithmetric

Sintaxe: jpeg_filter_arithmetric on | off

Padrão: off

Contexto: http, server, location

Ao entregar, habilite a codificação aritmética da imagem. Isso substituirá a diretiva jpeg_filter_optimize. A codificação aritmética geralmente não é suportada pelos navegadores.

Esta diretiva está desativada por padrão.

jpeg_filter_graceful

Sintaxe: jpeg_filter_graceful on | off

Padrão: off

Contexto: http, server, location

Permite entregar a imagem inalterada caso as diretivas jpeg_filter_max_width, jpeg_filter_max_height ou jpeg_filter_buffer retornem um erro "415 Unsupported Media Type".

Esta diretiva está desativada por padrão.

jpeg_filter_effect

Sintaxe: jpeg_filter_effect grayscale | pixelate

Sintaxe: jpeg_filter_effect darken | brighten value

Sintaxe: jpeg_filter_effect tintblue | tintyellow | tintred | tintgreen value

Padrão: -

Contexto: location

Aplique um efeito à imagem.

grayscale removerá todos os componentes de cor da imagem. Isso se aplica apenas a imagens no espaço de cor YCbCr.

pixelate pixelará a imagem em blocos de 8x8 pixels definindo os coeficientes AC em todos os componentes como 0.

darken escurecerá a imagem diminuindo os coeficientes DC no componente Y por value. Isso se aplica apenas a imagens no espaço de cor YCbCr.

brighten clareará a imagem aumentando os coeficientes DC no componente Y por value. Isso se aplica apenas a imagens no espaço de cor YCbCr.

tintblue tintará a imagem de azul aumentando os coeficientes DC no componente Cb por value. Isso se aplica apenas a imagens no espaço de cor YCbCr.

tintyellow tintará a imagem de azul diminuindo os coeficientes DC no componente Cb por value. Isso se aplica apenas a imagens no espaço de cor YCbCr.

tintred tintará a imagem de vermelho aumentando os coeficientes DC no componente Cr por value. Isso se aplica apenas a imagens no espaço de cor YCbCr.

tintgreen tintará a imagem de verde diminuindo os coeficientes DC no componente Cr por value. Isso se aplica apenas a imagens no espaço de cor YCbCr.

Esta diretiva não está definida por padrão.

Todos os parâmetros podem conter variáveis.

jpeg_filter_dropon_align

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

Padrão: center center

Contexto: location

Alinhe a sobreposição na imagem. Use a diretiva jpeg_filter_dropon_offset para deslocar a sobreposição do alinhamento.

Esta diretiva deve ser definida antes de jpeg_filter_dropon para ter efeito sobre a sobreposição.

Esta diretiva aplicará a sobreposição no centro da imagem por padrão.

Todos os parâmetros podem conter variáveis.

jpeg_filter_dropon_offset

Sintaxe: jpeg_filter_dropon_offset vertical horizontal

Padrão: 0 0

Contexto: location

Desloque a sobreposição por vertical e horizontal pixels a partir do alinhamento dado pela diretiva jpeg_filter_dropon_align. Use um valor negativo para mover a sobreposição para cima ou para a esquerda e um valor positivo para mover a sobreposição para baixo ou para a direita.

Esta diretiva deve ser definida antes de jpeg_filter_dropon para ter efeito sobre a sobreposição.

Esta diretiva não aplicará um deslocamento por padrão.

Todos os parâmetros podem conter variáveis.

jpeg_filter_dropon_file

Sintaxe: jpeg_filter_dropon_file image

Sintaxe: jpeg_filter_dropon_file image mask

Padrão: -

Contexto: location

Aplique uma sobreposição à imagem. A sobreposição é dada por um caminho para uma imagem JPEG ou PNG para image e, opcionalmente, um caminho para uma imagem JPEG para mask. Se nenhuma imagem de máscara for fornecida, a imagem será aplicada sem translucidez. Se uma imagem de máscara for fornecida, apenas o componente de luminância será usado. Para a máscara, preto significa totalmente translúcido e branco significa totalmente opaco. Quaisquer valores intermediários misturarão a imagem subjacente e a sobreposição de acordo. Se image for um caminho para um PNG, a máscara será ignorada.

Esta diretiva não está definida por padrão.

Todos os parâmetros podem conter variáveis.

Se nenhum dos parâmetros contiver variáveis, a sobreposição é carregada durante o carregamento da configuração. Se pelo menos um parâmetro contiver variáveis, a sobreposição será carregada durante o processamento da solicitação. Após o processamento da solicitação, a sobreposição será descarregada.

Arquivos PNG como sobreposição são suportados apenas se o libmodjpeg foi compilado com suporte a PNG.

jpeg_filter_dropon_memory

Sintaxe: jpeg_filter_dropon_memory $image

Sintaxe: jpeg_filter_dropon_memory $image $mask

Padrão: -

Contexto: location

Aplique uma sobreposição à imagem. A sobreposição é dada por uma variável que contém um fluxo de bytes de imagem JPEG ou PNG para $image e, opcionalmente, uma variável para um fluxo de bytes de imagem JPEG para $mask. Se nenhuma imagem de máscara for fornecida, a imagem será aplicada sem translucidez. Se uma imagem de máscara for fornecida, apenas o componente de luminância será usado. Para a máscara, preto significa totalmente translúcido e branco significa totalmente opaco. Quaisquer valores intermediários misturarão a imagem subjacente e a sobreposição de acordo. Se $image for um PNG, a máscara será ignorada.

Esta diretiva não está definida por padrão.

Todos os parâmetros devem ser variáveis.

A sobreposição sempre será carregada durante o processamento da solicitação. Após o processamento da solicitação, a sobreposição será descarregada.

Fluxos de bytes PNG como sobreposição são suportados apenas se o libmodjpeg foi compilado com suporte a PNG.

Notas

As diretivas jpeg_filter_effect, jpeg_filter_dropon_align, jpeg_filter_dropon_offset e jpeg_filter_dropon são aplicadas na ordem em que aparecem no arquivo de configuração do nginx, ou seja, faz diferença se você aplica primeiro um efeito e depois adiciona uma sobreposição ou vice-versa. No primeiro caso, a sobreposição não será afetada pelo efeito e, no segundo caso, o efeito também será aplicado à sobreposição.

Agradecimentos

Este módulo é fortemente inspirado no módulo de filtro de imagem do nginx com insights de "Emiller’s Guide To Nginx Module Development" e do guia de desenvolvimento do nginx.

GitHub

Você pode encontrar dicas de configuração adicionais e documentação para este módulo no repositório do GitHub para nginx-module-jpeg.