Breyttu stærð mynda á flugi með Nginx og LuaJIT (OpenResty)

Í nokkuð langan tíma núna, innblásin af greininni Breyta stærð mynda á flugu myndastærð var stillt með ngx_http_image_filter_module og allt virkaði eins og það átti að gera. En eitt vandamál kom upp þegar stjórnandinn þurfti að fá myndir með nákvæmum stærðum til að hlaða upp á einhverja þjónustu, vegna þess að... þetta voru tæknilegar kröfur þeirra. Til dæmis, ef við höfum upprunalega mynd af stærð 1200 × 1200, og þegar stærð er breytt skrifum við eitthvað eins og ?size=600×400, þá fáum við hlutfallslega minnkaða mynd meðfram minnstu brúninni, stærð 400 × 400. Það er líka ómögulegt að fá mynd með hærri upplausn (uppskala). Þeir. ?size=1500×1500 mun skila sömu mynd 1200 × 1200

Þessi grein kom til bjargar OpenResty: að breyta NGINX í fullgildan forritaþjón til að skilja hvernig Nginx vinnur með Lua og bókasafnið sjálft fyrir Lua isage/lua-imagegick - Lua pure-c bindingar við ImageMagick. Hvers vegna var þessi lausn valin, en ekki, segjum, eitthvað í python - vegna þess að hún er fljótleg og þægileg. Þú þarft ekki einu sinni að búa til neinar skrár, allt er rétt í Nginx stillingunni (valfrjálst).

Svo hvað þurfum við

Dæmi verða gefin út frá Debian.

Að setja upp nginx og nginx-aukahluti

apt-get update
apt-get install nginx-extras

Að setja upp LuaJIT

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

Að setja upp imagemagick

apt-get -y install imagemagick

og bókasöfn töfrasproti við það, í mínu tilfelli fyrir útgáfu 6

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

Að byggja lua-imagegick

Við klónum geymsluna (eða tökum zip-ið og tökum það upp)

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

Ef allt gekk vel geturðu stillt Nginx.

Ég mun gefa dæmi um stillingar bakendshýsilsins, sem í raun ber ábyrgð á stærðarbreytingum. Það er umboð af framþjóninum, einnig með Nginx, þar sem skyndiminni á sér stað í ákveðinn tíma (daga) og annað.

nginx bakenda stillingar

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

Það sem þurfti (stækka myndina um brúnirnar) gerist með því að nota img:extent() og er skilgreint með færibreytunni resize með skilti + í lokin.

Eftirfarandi valkostir eru í boði:

  • BxH (Haltu stærðarhlutfalli, notaðu hærri vídd)
  • BxH^ (Haltu hlutfalli, notaðu lægri vídd (skera))
  • BxH! (Hunsa hliðarhlutföll)
  • BxH+ (Haltu stærðarhlutfalli, bættu við hliðarmörkum)

Yfirlitstafla með niðurstöðum til að breyta stærð

Biðja um uri færibreytu
Úttaksmyndastærð

?size=400×200
200 × 200

?size=400×200^
400 × 400

?stærð=400×200!
400×200 (ekki í réttu hlutfalli)

?size=400×200+
400×200 (í hlutfalli)

Breyttu stærð mynda á flugi með Nginx og LuaJIT (OpenResty)

Samtals

Miðað við kraftinn og einfaldleika þessarar aðferðar geturðu útfært hluti með nokkuð flókinni rökfræði, til dæmis að bæta við vatnsmerkjum eða innleiða heimild með takmarkaðan aðgang. Til þess að komast að getu API til að vinna með myndir geturðu vísað í skjöl bókasafnsins isage/lua-imagegick

Heimild: www.habr.com

Bæta við athugasemd