Նկարի չափերը և դրանց փոփոխությունները Nginx-ի և LuaJIT-ով (OpenResty)

Նա աստիճանաբար, ոգեշնչված լինելով հոդվածից Նկարի չափերի և դրանց փոփոխությունները կարգավորվեց պատկերների չափերի փոփոխությունը ngx_http_image_filter_module եւ ամեն ինչ գործում էր ինչպես պետք է։ Սակայն մեկ խնդիր առաջացավ, երբ մենեջերին անհրաժեշտ դարձավ ստանալ պատկերներ ճշգրիտ չափերով որոշ սպասարկման համար, քանի որ դրանք տեխնիկական պահանջներ էին։ Օրինակ, եթե մենք ունենք սկզբնական պատկեր, որի չափսը 1200×1200, եւ չափերի փոփոխության ընթացքում մենք գրում ենք ինչ-որ բան նման ?resize=600×400, ապա կունենանք համաչափ փոքրացված պատկերը ամենափոքրը կողմից, որի չափսը 400×400։ Այնպես էլ անհնար է ստանալ պատկերը ավելի բարձր լուծաչափով (upscale)։ Այսինքն, ?resize=1500×1500 կվերադարձնի նույն պատկերը 1200×1200

Օգնության եկավ հոդվածը OpenResty: transforming NGINX into a full-fledged application server նկարի փոփոխման գործընթացում Nginx-ի եւ Lua-ի գործիքների մասին, ինչպես նաեւ Lua-ի հաշվեկշռային գրադարանը isage/lua-imagick — Lua-ի մաքուր կապերը ImageMagick-ի հետ: Ինչո՞ւ այս լուծումը, այլ ոչ թե, ասենք, ինչ-որ բան Python-ում — որովհետեւ սա արագ եւ հարմար է։ Ձեզ նույնիսկ չի անհրաժեշտ ստեղծել որեւէ ֆայլեր, ամեն ինչ ուղիղ Nginx-ի կոնֆիգում (ոչ պարտադիր)։

Ուրեմն, ինչն է մեզ անհրաժեշտ

Օրինակներ կտրվեն Debian-ի հիման վրա։

Նկարագիրն nginx եւ nginx-extras

apt-get update
apt-get install nginx-extras

Նկարագիր LuaJIT-ի համար

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

Նկարագիր imagemagick-ի համար

apt-get -y install imagemagick

եւ գրադարաններ magickwand իր հետ, իմ դեպքում 6-րդ տարբերակի համար

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

lua-imagick-ի կառուցում

Քլոնավորում ենք ռեպոզիտարը (կամ վերցնում սեղմված ֆայլ եւ բացում)

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

Եթե ամեն ինչ հաջողվեց, կարելի է կարգավորել Nginx-ը։

Կբերեմ օրինակ բեկեդի հոսթի կոնֆիգի, որը, իսկապես, զբաղվում է չափերի փոփոխությամբ։ Այն պրոքսի դրվում է դիմային սերվերի կողմից, նույնպես Nginx-ով, որտեղ կատարվում է կեշավորում որոշ ժամանակահատվածով (մեկ օր) եւ այլն։

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

Անկասկած պահանջվողինը (պատկերների մեծացում եզրալիզանում) տեղի է ունենում img:extent() եւ որոշվում է resize ն նշությամբ + ավարտին։

Հասանելի են հետեւյալ պարամետրերը։

  • WxH (Պահպանել համաչափությունը, օգտագործել ավելի մեծ չափը)
  • WxH^ (Պահպանել համաչափությունը, օգտագործել ավելի փոքր չափ (կրոպ))
  • WxH! (Ignored aspect-ratio)
  • WxH+ (Պահպանել համաչափությունը, ավելացնել կողմային սահմաններ)

Խմբագրված աղյուսակ՝ շրջանառությամբ

uri-request-ի պարամետր
Ելքային պատկերի չափը

?resize=400×200
200×200

?resize=400×200^
400×400

?resize=400×200!
400×200 (Ոչ համաչափ)

?resize=400×200+
400×200 (Համաչափ)

Նկարի չափերը և դրանց փոփոխությունները Nginx-ի և LuaJIT-ով (OpenResty)

Եզրակացություն

Երկարության եւ պարզության ողջ ուժով այս մոտեցումը կարող է իրականացնել բավականին բարդ տրամաբանություն, օրինակ՝ ջրվեժներ ավելացնել կամ իրականացնել արգելափակում սահմաններից։ API-ի հնարավորությունները պատկերների հետ աշխատելու համար կարող եք դիմել գրադարանի փաստաթղթին isage/lua-imagick

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster