Redimensionarea imaginilor în timp real cu ajutorul Nginx și LuaJIT (OpenResty)

De ceva timp, inspirat de un articol Redimensionarea imaginilor în timp real a fost configurată redimensionarea imaginilor folosind ngx_http_image_filter_module și totul a funcționat așa cum trebuie. Dar a apărut o problemă, când managerul a avut nevoie să obțină imagini cu dimensiuni precise pentru încărcare pe unele servicii, deoarece acestea erau cerințele lor tehnice. De exemplu, dacă avem un original al imaginii cu dimensiunea 1200×1200, iar la redimensionare specificăm ceva de genul ?resize=600×400, atunci vom obține o imagine redusă proporțional la cea mai mică dimensiune, având dimensiunea 400×400. De asemenea, nu este posibil să obținem o imagine cu o rezoluție mai mare (upscale). Adică, ?resize=1500×1500 va returna exact aceeași imagine 1200×1200

În ajutor a venit articolul OpenResty: turning NGINX into a full-fledged application server pentru a înțelege cum funcționează Nginx cu Lua și biblioteca în sine pentru Lua isage/lua-imagick — binding-uri pure-c Lua pentru ImageMagick. De ce a fost aleasă această soluție, și nu, să spunem, ceva pe Python — pentru că este rapid și convenabil. Nici nu va trebui să creați fișier, totul se face direct în configurația Nginx (nu este obligatoriu).

Așadar, ce ne va trebui

Exemplele vor fi prezentate pornind de la Debian.

Instalarea nginx și nginx-extras

apt-get update
apt-get install nginx-extras

Instalarea LuaJIT

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

Instalarea imagemagick

apt-get -y install imagemagick

și bibliotecile magickwand pentru acesta, în cazul meu pentru versiunea 6

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

Compilarea lua-imagick

Clonăm repository-ul (sau luăm zip-ul și-l dezarhivăm)

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

Dacă totul a decurs bine, putem configura Nginx.

Voi prezenta un exemplu de configurație a backend-ului hostului, care se ocupă propriu-zis de redimensionare. Este proxy-izat de serverul frontal folosind de asemenea Nginx, pe care se face caching pentru o anumită perioadă (24 de ore) și alte lucruri.

configurația 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
    }
}

Ceea ce era necesar (extinderea imaginii pe marginile) se realizează cu ajutorul img:extent() și este definit cu ajutorul parametrului resize cu semnul + la final.

Următoarele parametrii sunt disponibili:

  • WxH (Menține raportul de aspect, utilizând dimensiunea mai mare)
  • WxH^ (Menține raportul de aspect, utilizând dimensiunea mai mică (cropează))
  • WxH! (Ignoră raportul de aspect)
  • WxH+ (Menține raportul de aspect, adaugă margini laterale)

Tabel rezumat cu rezultatele redimensionării

Parametrul uri al solicitării
Dimensiunea imaginii de ieșire

?resize=400×200
200×200

?resize=400×200^
400×400

?resize=400×200!
400×200 (Nu proporțional)

?resize=400×200+
400×200 (Proporțional)

Redimensionarea imaginilor în timp real cu ajutorul Nginx și LuaJIT (OpenResty)

Rezultatul

Având în vedere toată puterea și simplitatea acestui mod de abordare, se pot implementa lucruri cu o logică destul de complexă, cum ar fi adăugarea de watermark-uri sau implementarea unei autorizări cu acces restricționat. Pentru a afla posibilitățile API-ului pentru lucrul cu imagini, se poate consulta documentația bibliotecii. isage/lua-imagick

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster