Dynamické zmenšovanie obrázkov pomocou Nginx a LuaJIT (OpenResty)

Už je to dávno, inšpirovaný článkom Dynamické zmenšovanie obrázkov bolo nastavené zmenšovanie obrázkov pomocou ngx_http_image_filter_module a všetko fungovalo ako má. Ale objavil sa jeden problém, keď potreboval manažér dostávať obrázky s presnými rozmermi na nahrávanie na niektoré služby, pretože to boli ich technické požiadavky. Napríklad, ak máme originál obrázka s rozmerom 1200×1200, a pri zmenšovaní napíšeme niečo ako ?resize=600×400, dostaneme proporčne zmenšený obrázok po najmenšej hrane, s rozmerom 400×400. Rovnako nie je možné získať obrázok s väčším rozlíšením (upscale). To znamená, že ?resize=1500×1500 vráti rovnaký obrázok 1200×1200

Na pomoc prišiel článok OpenResty: premeníme NGINX na plnohodnotný aplikačný server na pochopenie toho, ako Nginx pracuje s Lua a samotná knižnica pre Lua isage/lua-imagick — Lua čisté C previazané na ImageMagick. Prečo bolo zvolené takéto riešenie, a nie napríklad niečo na pythone — pretože je to rýchle a pohodlné. Nepotrebujete ani vytvárať žiadne súbory, všetko je priamo v konfigurácii Nginx (nie je to povinné).

Takže, čo budeme potrebovať

Príklady budú uvedené na základe Debianu.

Inštalácia nginx a nginx-extras

apt-get update
apt-get install nginx-extras

Inštalácia LuaJIT

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

Inštalácia imagemagick

apt-get -y install imagemagick

a knižnice magickwand k nemu, v mojom prípade pre 6 verziu

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

Zostavenie lua-imagick

Skopírujeme repozitár (alebo stiahneme zip a rozbalíme ho)

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

Ak všetko prebehlo úspešne, môžeme konfigurovať Nginx.

Uvediem príklad configu backend hosta, ktorý sa zaoberá zmenšovaním. Je proxyingovaný frontend serverom taktiež s Nginx, na ktorom prebieha caching na určité časové obdobie (deň) a iné veci.

nginx backend config

# 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
    }
}

To, čo bolo požadované (rozšírenie obrázka po okrajoch) sa deje pomocou img:extent() a určuje sa pomocou parametra resize so znamienkom + na konci.

K dispozícii sú nasledovné parametre:

  • WxH (Udržiavať pomer strán, použiť vyššiu dimenziu)
  • WxH^ (Udržiavať pomer strán, použiť nižšiu dimenziu (ořezanie))
  • WxH! (Ignorovať pomer strán)
  • WxH+ (Udržiavať pomer strán, pridať bočné okraje)

Zhrnutie tabuľky s výsledkami zmenšovania

Parametr uri požiadavky
Veľkosť výstupného obrázka

?resize=400×200
200×200

?resize=400×200^
400×400

?resize=400×200!
400×200 (Neporprocionálne)

?resize=400×200+
400×200 (Proporčne)

Dynamické zmenšovanie obrázkov pomocou Nginx a LuaJIT (OpenResty)

Záver

Vzhľadom na všetku moc a jednoduchú aplikáciu tohto prístupu je možné realizovať veci s dosť zložitou logikou, napríklad pridávať vodotlače alebo implementovať autorizáciu s obmedzeným prístupom. Ak chcete zistiť možnosti API pre prácu s obrázkami, môžete sa odvolať na dokumentáciu knižnice. isage/lua-imagick

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster