Ändra storlek på bilder i farten med Nginx och LuaJIT (OpenResty)

Sedan ganska länge, inspirerad av artikeln Bildstorleksändring i farten bildstorlek konfigurerades med ngx_http_image_filter_module och allt fungerade som det skulle. Men ett problem uppstod när chefen behövde ta emot bilder med exakta mått för uppladdning till vissa tjänster, eftersom... dessa var deras tekniska krav. Till exempel om vi har en originalbild av storlek 1200 × 1200, och när vi ändrar storlek skriver vi något i stil med ?ändra storlek=600×400, då får vi en proportionellt reducerad bild längs den minsta kanten, storlek 400 × 400. Det är också omöjligt att få en bild med högre upplösning (uppskala). De där. ?ändra storlek=1500×1500 kommer att returnera samma bild 1200 × 1200

Den här artikeln kom till undsättning OpenResty: gör NGINX till en fullfjädrad applikationsserver för att förstå hur Nginx fungerar med Lua och själva biblioteket för Lua isage/lua-imagegick - Lua pure-c-bindningar till ImageMagick. Varför valdes den här lösningen, och inte, säg, något i python - eftersom det är snabbt och bekvämt. Du behöver inte ens skapa några filer, allt är rätt i Nginx-konfigurationen (valfritt).

Så vad behöver vi

Exempel kommer att ges baserat på Debian.

Installerar nginx och nginx-extras

apt-get update
apt-get install nginx-extras

Installerar LuaJIT

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

Installerar imagemagick

apt-get -y install imagemagick

och bibliotek trollstav till den, i mitt fall för version 6

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

Att bygga lua-image

Vi klonar förvaret (eller tar zip-filen och packar upp den)

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

Om allt gick bra kan du konfigurera Nginx.

Jag kommer att ge ett exempel på konfigurationen av backend-värden, som faktiskt är ansvarig för storleksändring. Den proxias av frontservern, även med Nginx, där cachning sker under en viss tid (dagar) och annat.

nginx backend-konfiguration

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

Det som krävdes (expandera bilden runt kanterna) sker med hjälp av img:extent() och definieras med parametern resize med en skylt + i slutet.

Följande alternativ är tillgängliga:

  • BxH (Behåll bildförhållande, använd högre dimension)
  • BxH^ (Behåll bildförhållande, använd lägre dimension (beskär))
  • BxH! (Ignorera bildförhållande)
  • BxH+ (Behåll bildförhållande, lägg till sidokanter)

Sammanfattningstabell med resize-resultat

Begär uri-parameter
Utdatabildstorlek

?ändra storlek=400×200
200 × 200

?ändra storlek=400×200^
400 × 400

?ändra storlek=400×200!
400×200 (ej proportionell)

?ändra storlek=400×200+
400×200 (Proportionell)

Ändra storlek på bilder i farten med Nginx och LuaJIT (OpenResty)

Totalt

Med tanke på kraften och enkelheten i detta tillvägagångssätt kan du implementera saker med ganska komplex logik, till exempel lägga till vattenstämplar eller implementera auktorisering med begränsad åtkomst. För att ta reda på funktionerna hos API:et för att arbeta med bilder kan du hänvisa till bibliotekets dokumentation isage/lua-imagegick

Källa: will.com

Lägg en kommentar