Перейти к содержанию

jpeg: Модуль фильтра JPEG для NGINX

Установка

Вы можете установить этот модуль в любой дистрибутив на базе RHEL, включая, но не ограничиваясь:

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

Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:

load_module modules/ngx_http_jpeg_filter_module.so;

Этот документ описывает nginx-module-jpeg v1.0.1, выпущенный 4 сентября 2018 года.


Модуль фильтра Nginx для добавления наложений на JPEG в реальном времени с помощью libmodjpeg.

С помощью libmodjpeg вы можете наложить (замаскированное) изображение на существующий JPEG с минимальными потерями. Изменения в JPEG происходят только там, где применяется наложенное изображение. Все модификации происходят в области DCT, таким образом JPEG декодируется и кодируется без потерь.

Типичные применения

Этот модуль фильтра может добавлять наложения (например, логотип, визуальный водяной знак) на JPEG, когда они запрашиваются.

Несколько идей:

  • Представьте, что вы фотограф и у вас есть галерея изображений на вашем сайте. Без жесткой кодировки вашего логотипа (бренда, водяного знака и т. д.) в эти изображения вы можете применить его в момент запроса изображения. Когда вы обновляете свой логотип, просто обновите конфигурацию nginx, и это сделано. Нет необходимости повторно обрабатывать все ваши изображения.
  • У вас есть интернет-магазин с тысячами изображений продуктов. Просто настроив nginx, вы можете добавить свой логотип ко всем изображениям продуктов. Вам не нужно обрабатывать все изображения продуктов.
  • У вас есть платный сервис. Добавьте водяной знак ко всем изображениям, если пользователь не подписан. Если пользователь подписан, не применяйте водяной знак или просто добавьте небольшой логотип на изображения, не затрагивая оригинальные изображения.
  • На вашем сайте зарегистрированные пользователи могут загружать изображения. Добавьте аватар пользователя к изображению, которое загрузил пользователь, без обработки после загрузки. Если пользователь изменит свой аватар, все его изображения автоматически получат новый аватар.

Попробуйте

Чтобы попробовать этот модуль фильтра, загрузите образ docker

docker pull ioppermann/modjpeg-nginx:latest

Контейнер docker открывает TCP-порт 80 и ожидает, что директория с изображениями будет смонтирована на /images, например:

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

Теперь вы можете перейти по адресу http://localhost:8080/ и кликнуть на перечисленные изображения. Логотип modjpeg будет применен в верхнем левом углу. По умолчанию фильтр обрабатывает только изображения размером менее 10 МБ. Остановите контейнер, нажав Ctrl-c.

Фильтр можно контролировать с помощью следующих переменных окружения:

Имя По умолчанию Описание
MJ_GRACEFUL on См. jpeg_filter_graceful
MJ_BUFFER 10M См. jpeg_filter_buffer
MJ_MAX_PIXEL 0 См. jpeg_filter_max_pixel
MJ_DROPON_ALIGN "top left" См. jpeg_filter_dropon_align
MJ_DROPON_OFFSET "0 0" См. jpeg_filter_dropon_offset
MJ_DROPON_FILE "/usr/local/nginx/conf/dropon.png" См. jpeg_filter_dropon_file

Следующий пример позволит обрабатывать изображения с максимальным разрешением до 150 мегапикселей (MJ_MAX_PIXEL) и размером файла до 100 МБ (MJ_BUFFER). Логотип будет размещен в нижнем правом углу (MJ_DROPON_ALIGN) с смещением -15 пикселей по горизонтали и вертикали (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

Чтобы изменить логотип, вы можете смонтировать дополнительный том или поместить его в директорию, которую вы уже монтируете, например:

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

Клонируйте и установите libmodjpeg

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

Клонируйте modjpeg-nginx

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

Скачайте и установите 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

Настройте как статический модуль, или ...

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

... настройте как динамический модуль (начиная с nginx 1.9.11)

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

Если библиотека libmodjpeg не найдена, добавьте, например, '--with-ld-opt=-L/usr/local/lib' в

параметры конфигурации, если она была установлена в /usr/local/lib

Возможно, вам также стоит использовать другие параметры './configure', которые используются

в вашей текущей сборке nginx. Проверьте вывод 'nginx -V'.

make make install

Если вы настроили modjpeg-nginx как динамический модуль, вам нужно загрузить модуль в начале конфигурации

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

Синопсис

   ...

   location /gallery {
      # включить модуль фильтра jpeg
      jpeg_filter on;

      # ограничить размеры изображений до 9 мегапикселей
      jpeg_filter_max_pixel 9000000;

      # ограничить размер файла изображения до 5 мегабайт
      jpeg_filter_buffer 5M;

      # доставлять изображения без изменений, если одно из ограничений применимо
      jpeg_filter_graceful on;

      # пикселизировать изображение
      jpeg_filter_effect pixelate;

      # добавить замаскированный логотип в нижнем правом углу
      # с расстоянием 10 пикселей от края
      jpeg_filter_dropon_align bottom right;
      jpeg_filter_dropon_offset -10 -10;
      jpeg_filter_dropon_file /path/to/logo.jpg /path/to/mask.jpg;
   }

   ...

Или используйте его с OpenResty's ngx_http_lua_module и логотипом 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)]
      }

      # включить модуль фильтра jpeg
      jpeg_filter on;

      # ограничить размеры изображений до 9 мегапикселей
      jpeg_filter_max_pixel 9000000;

      # ограничить размер файла изображения до 5 мегабайт
      jpeg_filter_buffer 5M;

      # доставлять изображения без изменений, если одно из ограничений применимо
      jpeg_filter_graceful on;

      # пикселизировать изображение
      jpeg_filter_effect pixelate;

      # добавить логотип в случайном положении
      jpeg_filter_dropon_align $valign $halign;
      jpeg_filter_dropon_file /path/to/logo.png;
   }

   ...

Или сгенерируйте логотип с помощью 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)
           }

       # включить модуль фильтра jpeg
       jpeg_filter on;

           # ограничить размеры изображений до 9 мегапикселей
           jpeg_filter_max_pixel 9000000;

           # ограничить размер файла изображения до 5 мегабайт
           jpeg_filter_buffer 5M;

           # доставлять изображения без изменений, если одно из ограничений применимо
           jpeg_filter_graceful on;

           # пикселизировать изображение
           jpeg_filter_effect pixelate;

           # добавить сгенерированный логотип в нижнем правом углу
           # с расстоянием 10 пикселей от края
           jpeg_filter_dropon_align bottom right;
           jpeg_filter_dropon_offset -10 -10;
           jpeg_filter_dropon_memory $logobytestream;
      }
      ...
   }
   ...
}

Директивы

jpeg_filter

Синтаксис: jpeg_filter on | off

По умолчанию: jpeg_filter off

Контекст: location

Включите модуль фильтра jpeg.

Эта директива по умолчанию отключена.

jpeg_filter_max_pixel

Синтаксис: jpeg_filter_max_pixel pixel

По умолчанию: 0

Контекст: http, server, location

Максимальное количество пикселей в изображении, с которым можно работать. Если изображение имеет больше пикселей (ширина * высота), чем pixel, фильтр jpeg вернет "415 Unsupported Media Type". Установите jpeg_filter_graceful в on, чтобы доставить изображение без изменений. Установите максимальное количество пикселей в 0, чтобы игнорировать размеры изображения.

Эта директива по умолчанию установлена в 0.

jpeg_filter_buffer

Синтаксис: jpeg_filter_buffer size

По умолчанию: 2M

Контекст: http, server, location

Максимальный размер файла изображения, с которым можно работать. Если размер файла больше, чем size, фильтр jpeg вернет "415 Unsupported Media Type". Установите jpeg_filter_graceful в on, чтобы доставить изображение без изменений.

Эта директива по умолчанию установлена в 2 мегабайта.

jpeg_filter_optimize

Синтаксис: jpeg_filter_optimize on | off

По умолчанию: off

Контекст: http, server, location

При доставке оптимизируйте таблицы Хаффмана изображения.

Эта директива по умолчанию отключена.

jpeg_filter_progressive

Синтаксис: jpeg_filter_progressive on | off

По умолчанию: off

Контекст: http, server, location

При доставке включите прогрессивное кодирование изображения.

Эта директива по умолчанию отключена.

jpeg_filter_arithmetric

Синтаксис: jpeg_filter_arithmetric on | off

По умолчанию: off

Контекст: http, server, location

При доставке включите арифметическое кодирование изображения. Это переопределит директиву jpeg_filter_optimize. Арифметическое кодирование обычно не поддерживается браузерами.

Эта директива по умолчанию отключена.

jpeg_filter_graceful

Синтаксис: jpeg_filter_graceful on | off

По умолчанию: off

Контекст: http, server, location

Позволяет доставлять неизмененное изображение в случае, если директивы jpeg_filter_max_width, jpeg_filter_max_height или jpeg_filter_buffer вернут ошибку "415 Unsupported Media Type".

Эта директива по умолчанию отключена.

jpeg_filter_effect

Синтаксис: jpeg_filter_effect grayscale | pixelate

Синтаксис: jpeg_filter_effect darken | brighten value

Синтаксис: jpeg_filter_effect tintblue | tintyellow | tintred | tintgreen value

По умолчанию: -

Контекст: location

Примените эффект к изображению.

grayscale удалит все цветовые компоненты из изображения. Это применяется только к изображениям в цветовой модели YCbCr.

pixelate пикселизирует изображение в блоках 8x8 пикселей, устанавливая коэффициенты AC во всех компонентах в 0.

darken затемняет изображение, уменьшая коэффициенты DC в компоненте Y на value. Это применяется только к изображениям в цветовой модели YCbCr.

brighten осветляет изображение, увеличивая коэффициенты DC в компоненте Y на value. Это применяется только к изображениям в цветовой модели YCbCr.

tintblue придает изображению синий оттенок, увеличивая коэффициенты DC в компоненте Cb на value. Это применяется только к изображениям в цветовой модели YCbCr.

tintyellow придает изображению желтый оттенок, уменьшая коэффициенты DC в компоненте Cb на value. Это применяется только к изображениям в цветовой модели YCbCr.

tintred придает изображению красный оттенок, увеличивая коэффициенты DC в компоненте Cr на value. Это применяется только к изображениям в цветовой модели YCbCr.

tintgreen придает изображению зеленый оттенок, уменьшая коэффициенты DC в компоненте Cr на value. Это применяется только к изображениям в цветовой модели YCbCr.

Эта директива по умолчанию не установлена.

Все параметры могут содержать переменные.

jpeg_filter_dropon_align

Синтаксис: jpeg_filter_dropon_align [top | center | bottom] [left | center | right]

По умолчанию: center center

Контекст: location

Выравнивание наложения на изображении. Используйте директиву jpeg_filter_dropon_offset, чтобы сместить наложение от выравнивания.

Эта директива должна быть установлена перед jpeg_filter_dropon, чтобы оказать влияние на наложение.

Эта директива по умолчанию применяет наложение в центре изображения.

Все параметры могут содержать переменные.

jpeg_filter_dropon_offset

Синтаксис: jpeg_filter_dropon_offset vertical horizontal

По умолчанию: 0 0

Контекст: location

Сместите наложение на vertical и horizontal пикселей от выравнивания, заданного директивой jpeg_filter_dropon_align. Используйте отрицательное значение, чтобы переместить наложение вверх или влево, и положительное значение, чтобы переместить наложение вниз или вправо.

Эта директива должна быть установлена перед jpeg_filter_dropon, чтобы оказать влияние на наложение.

Эта директива по умолчанию не применяет смещение.

Все параметры могут содержать переменные.

jpeg_filter_dropon_file

Синтаксис: jpeg_filter_dropon_file image

Синтаксис: jpeg_filter_dropon_file image mask

По умолчанию: -

Контекст: location

Примените наложение к изображению. Наложение задается путем указания пути к изображению JPEG или PNG для image и, при необходимости, пути к изображению JPEG для mask. Если маска не предоставлена, изображение будет применено без прозрачности. Если маска предоставлена, будет использоваться только компонент яркости. Для маски черный цвет означает полную прозрачность, а белый цвет — полную непрозрачность. Любые значения между ними будут смешивать подлежащее изображение и наложение соответственно. Если image — это путь к PNG, маска будет проигнорирована.

Эта директива по умолчанию не установлена.

Все параметры могут содержать переменные.

Если ни один из параметров не содержит переменных, наложение загружается во время загрузки конфигурации. Если хотя бы один параметр содержит переменные, наложение будет загружено во время обработки запроса. После обработки запроса наложение будет выгружено.

PNG-файлы в качестве наложения поддерживаются только в том случае, если libmodjpeg был скомпилирован с поддержкой PNG.

jpeg_filter_dropon_memory

Синтаксис: jpeg_filter_dropon_memory $image

Синтаксис: jpeg_filter_dropon_memory $image $mask

По умолчанию: -

Контекст: location

Примените наложение к изображению. Наложение задается переменной, содержащей поток байтов изображения JPEG или PNG для $image и, при необходимости, переменной для потока байтов изображения JPEG для $mask. Если маска не предоставлена, изображение будет применено без прозрачности. Если маска предоставлена, будет использоваться только компонент яркости. Для маски черный цвет означает полную прозрачность, а белый цвет — полную непрозрачность. Любые значения между ними будут смешивать подлежащее изображение и наложение соответственно. Если $image — это PNG, маска будет проигнорирована.

Эта директива по умолчанию не установлена.

Все параметры должны быть переменными.

Наложение всегда будет загружено во время обработки запроса. После обработки запроса наложение будет выгружено.

Потоки байтов PNG в качестве наложения поддерживаются только в том случае, если libmodjpeg был скомпилирован с поддержкой PNG.

Заметки

Директивы jpeg_filter_effect, jpeg_filter_dropon_align, jpeg_filter_dropon_offset и jpeg_filter_dropon применяются в порядке их появления в конфигурационном файле nginx, т.е. имеет значение, примените ли сначала эффект, а затем добавьте наложение, или наоборот. В первом случае наложение не будет затронуто эффектом, а во втором случае эффект также будет применен к наложению.

Благодарности

Этот модуль сильно вдохновлен модулем фильтра изображений nginx с идей из "Emiller’s Guide To Nginx Module Development" и руководством по разработке nginx.

GitHub

Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-jpeg.