Bildgröße zur Laufzeit mit Nginx und LuaJIT (OpenResty) ändern

Es ist schon eine Weile her, dass ich von einem Artikel inspiriert wurde Bildgröße zur Laufzeit ändern das Resizing von Bildern mithilfe von ngx_http_image_filter_module und alles funktionierte wie es sollte. Doch es gab ein Problem, als der Manager Bilder mit genauen Abmessungen benötigte, um sie auf bestimmten Diensten hochzuladen, da dies ihre technischen Anforderungen waren. Zum Beispiel, wenn wir ein Originalbild mit der Größe haben 1200×1200, und beim Resizing wir etwas wie ?resize=600×400angeben, erhalten wir ein proportional verkleinertes Bild an der kleinsten Kante mit der Größe von 400×400. Es ist auch unmöglich, ein Bild mit höherer Auflösung zu erhalten (Upscale). Das heißt, ?resize=1500×1500 wird das gleiche Bild zurückgeben 1200×1200

Ein Artikel kam zur Rettung OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln um zu verstehen, wie Nginx mit Lua arbeitet und die Bibliothek selbst für Lua isage/lua-imagick — Lua Pure-C-Bindings zu ImageMagick. Warum wurde diese Lösung gewählt und nicht zum Beispiel etwas in Python? Weil es schnell und bequem ist. Sie müssen nicht einmal irgendwelche Dateien erstellen, alles erfolgt direkt in der Nginx-Konfiguration (nicht zwingend).

Also, was brauchen wir

Die Beispiele werden auf Grundlage von Debian gegeben.

Installation von nginx und nginx-extras

apt-get update
apt-get install nginx-extras

Installation von LuaJIT

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

Installation von imagemagick

apt-get -y install imagemagick

und der Bibliothek magickwand dazu, in meinem Fall für Version 6

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

Komplilierung von lua-imagick

Wir klonen das Repository (oder holen das Zip und entpacken es)

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

Wenn alles erfolgreich war, können wir Nginx konfigurieren.

Ich werde ein Beispiel für die Konfiguration des Backend-Hosts anführen, der das Resizing tatsächlich vornimmt. Er wird ebenfalls von einem Front-Server mit Nginx weitergeleitet, wo eine Cachebildung für eine gewisse Zeit (24 Stunden) usw. stattfindet.

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

Das, was benötigt wurde (Erweiterung des Bildes an den Rändern), erfolgt durch img:extent() und wird durch den Parameter resize mit dem Zeichen + am Ende bestimmt.

Folgende Parameter sind verfügbar:

  • WxH (Seitenverhältnis beibehalten, größere Dimension verwenden)
  • WxH^ (Seitenverhältnis beibehalten, kleinere Dimension verwenden (croppen))
  • WxH! (Seitenverhältnis ignorieren)
  • WxH+ (Seitenverhältnis beibehalten, seitliche Ränder hinzufügen)

Zusammenfassungstabelle mit den Ergebnissen des Resizings

Parameter der URI-Anfrage
Größe des Ausgangsbildes

?resize=400×200
200×200

?resize=400×200^
400×400

?resize=400×200!
400×200 (Nicht proportional)

?resize=400×200+
400×200 (Proportional)

Bildgröße zur Laufzeit mit Nginx und LuaJIT (OpenResty) ändern

Fazit

Angesichts der gesamten Kraft und Einfachheit eines solchen Ansatzes lassen sich relativ komplexe Logik implementieren, zum Beispiel Wasserzeichen hinzufügen oder eine Authentifizierung mit eingeschränktem Zugriff realisieren. Um die Möglichkeiten der API zur Bildbearbeitung zu erkunden, kann man die Dokumentation der Bibliothek konsultieren. isage/lua-imagick

Quelle: habr.com

60GB SSD 8Gb DDR4