Redimensione imagens rapidamente usando Nginx e LuaJIT (OpenResty)

Já faz algum tempo, inspirado no artigo Redimensione imagens instantaneamente o redimensionamento da imagem foi configurado usando ngx_http_image_filter_module e tudo funcionou como deveria. Mas surgiu um problema quando o gestor precisava receber imagens com dimensões exatas para upload em alguns serviços, porque... esses eram seus requisitos técnicos. Por exemplo, se tivermos uma imagem original de tamanho 1200 × 1200, e ao redimensionar escrevemos algo como ?redimensionar=600×400, então obtemos uma imagem proporcionalmente reduzida ao longo da menor borda, tamanho 400 × 400. Também é impossível obter uma imagem com resolução superior (upscale). Aqueles. ?redimensionar=1500×1500 retornará a mesma imagem 1200 × 1200

Este artigo veio para o resgate OpenResty: transformando o NGINX em um servidor de aplicativos completo entender como o Nginx funciona com Lua e a própria biblioteca para Lua isage/lua-imagick - Ligações Lua pure-c ao ImageMagick. Por que essa solução foi escolhida e não, digamos, algo em python - porque é rápida e conveniente. Você nem precisa criar nenhum arquivo, está tudo certo na configuração do Nginx (opcional).

Então, o que precisamos

Os exemplos serão fornecidos com base em Debian.

Instalando nginx e nginx-extras

apt-get update
apt-get install nginx-extras

Instalando LuaJIT

apt-get -y install lua5.1 luajit-5.1 libluajit-5.1-dev

Instalando o imagemagick

apt-get -y install imagemagick

e bibliotecas varinha mágica para isso, no meu caso para a versão 6

apt-cache search libmagickwand
apt-get -y install libmagickwand-6.q16-3 libmagickwand-6.q16-dev

Construindo lua-imagick

Clonamos o repositório (ou pegamos o zip e descompactamos)

cd ~
git clone https://github.com/isage/lua-imagick.git
cd lua-imagick
mkdir build
cd build
cmake ..
make
make install

Se tudo correr bem, você pode configurar o Nginx.

Darei um exemplo da configuração do host backend, que, na verdade, é responsável pelo redimensionamento. É proxy pelo servidor frontal, também com Nginx, onde o cache ocorre por um determinado período de tempo (dias) e outras coisas.

configuração de back-end do nginx

# Backend image server
server {
    listen       8082;
    listen [::]:8082;
    set $files_root /var/www/example.lh/frontend/web;
    root $files_root;
    access_log off;
    expires 1d;

    location /files {
        # дефолтные значения ресайза
        set $w 700;
        set $h 700;
        set $q 89;

        #1-89 allowed
        if ($arg_q ~ "^([1-9]|[1-8][0-9])$") {
            set $q $arg_q;
        }

        if ($arg_resize ~ "([d-]+)x([d+!^]+)") {  
            set $w $1;
            set $h $2;
            rewrite  ^(.*)$   /resize/$w/$h/$q$uri     last;
        }

        rewrite  ^(.*)$   /resize/$w/$h/$q$uri     last;
    }

    location ~* ^/resize/([d]+)/([d+!^]+)/([d]+)/files/(.+)$ {
        default_type 'text/plain';

        set $w $1;
        set $h $2;
        set $q $3;
        set $fname $4;

        # Есть возможность вынести весь Lua код в отдельный файл
        # content_by_lua_file /var/www/some.lua;
        # lua_code_cache off; #dev
        content_by_lua '
        local magick = require "imagick"
        local img = magick.open(ngx.var.files_root .. "/files/" .. ngx.var.fname)
        if not img then ngx.exit(ngx.HTTP_NOT_FOUND) end
        img:set_gravity(magick.gravity["CenterGravity"])

        if string.match(ngx.var.h, "%d+%+") then
            local h = string.gsub(ngx.var.h, "(%+)", "")
            resize = ngx.var.w .. "x" .. h
            -- для png с альфа каналом
            img:set_bg_color(img:has_alphachannel() and "none" or img:get_bg_color())
            img:smart_resize(resize)
            img:extent(ngx.var.w, h)
        else
                img:smart_resize(ngx.var.w .. "x" .. ngx.var.h)
        end

        if ngx.var.arg_q then img:set_quality(ngx.var.q) end

        ngx.say(img:blob())
        ';
    }
}

# Upstream
upstream imageserver {
    server localhost:8082;
}

server {
    listen 80;
    server_name examaple.lh;

    # отправляем все jpg и png картинки на imageserver
    location ~* ^/files/.+.(jpg|png) {
        proxy_buffers 8 2m;
        proxy_buffer_size 10m;
        proxy_busy_buffers_size 10m;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass     http://imageserver;  # Backend image server
    }
}

O que era necessário (expandir a imagem nas bordas) acontece usando img:extent() e é definido usando o parâmetro resize assinado + no final.

As seguintes opções estão disponíveis:

  • LxA (manter a proporção, usar dimensão superior)
  • LxA^ (manter a proporção, usar dimensão inferior (corte))
  • LxA! (Ignorar proporção de aspecto)
  • LxA+ (manter a proporção, adicionar bordas laterais)

Tabela de resumo com resultados de redimensionamento

Solicitar parâmetro uri
Tamanho da imagem de saída

?redimensionar=400×200
200 × 200

?redimensionar=400×200^
400 × 400

?redimensionar=400×200!
400×200 (não proporcional)

?redimensionar=400×200+
400×200 (proporcional)

Redimensione imagens rapidamente usando Nginx e LuaJIT (OpenResty)

Total

Considerando o poder e a simplicidade desta abordagem, você pode implementar coisas com uma lógica bastante complexa, por exemplo, adicionando marcas d'água ou implementando autorização com acesso limitado. Para descobrir os recursos da API para trabalhar com imagens, você pode consultar a documentação da biblioteca isage/lua-imagick

Fonte: habr.com

Compre hospedagem confiável para sites com proteção DDoS, servidores VPS VDS 🔥 Compre hospedagem de sites confiável com proteção contra DDoS, servidores VPS/VDS | ProHoster