跳转至

jpeg: NGINX JPEG 过滤模块

安装

您可以在任何基于 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,于 2018 年 9 月 4 日发布。


Nginx 过滤模块,用于通过 libmodjpeg 在 JPEG 上动态添加覆盖层。

使用 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 徽标将应用于左上角。默认情况下,只有小于 10MB 的图像会被过滤器处理。通过按 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)和文件大小为 100MB(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 库,例如,如果它安装在 /usr/local/lib 中,请在配置选项中添加 --with-ld-opt=-L/usr/local/lib

您可能希望使用当前 nginx 构建中使用的其他 ./configure 选项。检查 nginx -V 的输出。

make
make install

如果您将 modjpeg-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 的 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_widthjpeg_filter_max_heightjpeg_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 将通过减少 Y 分量中的 DC 系数 value 来使图像变暗。这仅适用于 YCbCr 颜色空间中的图像。

brighten 将通过增加 Y 分量中的 DC 系数 value 来使图像变亮。这仅适用于 YCbCr 颜色空间中的图像。

tintblue 将通过增加 Cb 分量中的 DC 系数 value 来使图像呈现蓝色。这仅适用于 YCbCr 颜色空间中的图像。

tintyellow 将通过减少 Cb 分量中的 DC 系数 value 来使图像呈现黄色。这仅适用于 YCbCr 颜色空间中的图像。

tintred 将通过增加 Cr 分量中的 DC 系数 value 来使图像呈现红色。这仅适用于 YCbCr 颜色空间中的图像。

tintgreen 将通过减少 Cr 分量中的 DC 系数 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

通过 verticalhorizontal 像素从 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 的路径,则掩码将被忽略。

此指令默认未设置。

所有参数可以包含变量。

如果没有参数包含变量,则在加载配置时加载覆盖层。如果至少一个参数包含变量,则在处理请求时加载覆盖层。处理请求后,覆盖层将被卸载。

仅在 libmodjpeg 编译时支持 PNG 支持的情况下,PNG 文件作为覆盖层才受支持。

jpeg_filter_dropon_memory

语法: jpeg_filter_dropon_memory $image

语法: jpeg_filter_dropon_memory $image $mask

默认: -

上下文: location

对图像应用覆盖层。覆盖层由持有 JPEG 或 PNG 图像字节流的变量 $image 指定,并可选地由持有 JPEG 图像字节流的变量 $mask 指定。如果未提供掩码图像,则图像将不带透明度地应用。如果提供了掩码图像,则仅使用亮度分量。对于掩码,黑色表示完全透明,白色表示完全不透明。介于两者之间的任何值将相应地混合底层图像和覆盖层。如果 $image 是 PNG,则掩码将被忽略。

此指令默认未设置。

所有参数都应为变量。

覆盖层将在处理请求时始终加载。处理请求后,覆盖层将被卸载。

仅在 libmodjpeg 编译时支持 PNG 支持的情况下,PNG 字节流作为覆盖层才受支持。

注意事项

指令 jpeg_filter_effectjpeg_filter_dropon_alignjpeg_filter_dropon_offsetjpeg_filter_dropon 按它们在 nginx 配置文件中出现的顺序应用,即首先应用效果然后添加覆盖层或反之亦然会有所不同。在前一种情况下,覆盖层将不受效果的影响,而在后一种情况下,效果也将应用于覆盖层。

致谢

此模块受到 nginx 图像过滤模块的强烈启发,并参考了 "Emiller’s Guide To Nginx Module Development"nginx 开发指南

GitHub

您可以在 nginx-module-jpeg 的 GitHub 仓库 中找到此模块的其他配置提示和文档。