Ridimensionamento delle immagini al volo con Nginx e LuaJIT (OpenResty)

È passato un po' di tempo da quando, ispirato da un articolo Ridimensionamento delle immagini al volo è stato configurato il ridimensionamento delle immagini tramite ngx_http_image_filter_module e tutto funzionava come previsto. Ma è sorto un problema quando al manager è servito ricevere immagini con dimensioni esatte per il caricamento su alcuni servizi, poiché erano i loro requisiti tecnici. Ad esempio, se abbiamo un'immagine originale di dimensioni 1200×1200, e durante il ridimensionamento scriviamo qualcosa come ?resize=600×400, otterremo un'immagine proporzionalmente ridotta dal lato più corto, di dimensioni 400×400. Non è possibile ottenere un'immagine con una risoluzione maggiore (upscale). Cioè, ?resize=1500×1500 restituirà la stessa immagine 1200×1200

Un articolo è stato d'aiuto OpenResty: trasformiamo NGINX in un server applicazioni completo per comprendere come funziona Nginx con Lua e la libreria stessa per Lua isage/lua-imagick — binding pure-c di Lua per ImageMagick. Perché è stata scelta questa soluzione invece di, diciamo, qualcosa in python — perché è veloce e comodo. Non dovrete nemmeno creare file, il tutto direttamente nella configurazione di Nginx (non obbligatorio).

Quindi, cosa ci serve

Gli esempi saranno basati su Debian.

Installazione di nginx e nginx-extras

apt-get update
apt-get install nginx-extras

Installazione di LuaJIT

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

Installazione di imagemagick

apt-get -y install imagemagick

e della libreria magickwand ad esso, nel mio caso per la versione 6

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

Compilazione di lua-imagick

Cloniamo il repository (o scarichiamo lo zip e lo estraiamo)

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

Se tutto è andato a buon fine, possiamo configurare Nginx.

Riporterò un esempio di configurazione del backend host, che si occupa effettivamente del ridimensionamento. Viene proxyato dal server front, anch'esso con Nginx, sul quale si esegue la cache per un certo tempo (un giorno) e altre cose.

configurazione backend 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
    }
}

Ciò che era necessario (espansione dell'immagine ai bordi) avviene tramite img:extent() ed è definito tramite il parametro resize con il segno + alla fine.

I seguenti parametri sono disponibili:

  • WxH (Mantieni il rapporto, usa la dimensione maggiore)
  • WxH^ (Mantieni il rapporto, usa la dimensione minore (ritaglia))
  • WxH! (Ignora il rapporto)
  • WxH+ (Mantieni il rapporto, aggiungi bordi laterali)

Tabella riassuntiva dei risultati del ridimensionamento

Parametro uri della richiesta
Dimensione dell'immagine di output

?resize=400×200
200×200

?resize=400×200^
400×400

?resize=400×200!
400×200 (Non proporzionale)

?resize=400×200+
400×200 (Proporzionale)

Ridimensionamento delle immagini al volo con Nginx e LuaJIT (OpenResty)

Risultato

Considerando tutta la potenza e la semplicità di questo approccio, è possibile realizzare cose con logiche piuttosto complesse, come ad esempio aggiungere watermark o implementare l'autenticazione con accesso differenziato. Per scoprire le possibilità dell'API per lavorare con le immagini, è possibile fare riferimento alla documentazione della libreria isage/lua-imagick

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS - ProHoster