Echtzeit-Bildgrößenänderung mit Nginx und LuaJIT (OpenResty)

Es ist schon eine Weile her, inspiriert von einem Artikel Echtzeit-Bildgrößenänderung. wurde das Resizing von Bildern mit Hilfe von ngx_http_image_filter_module und alles funktionierte wie geplant. Doch es trat ein Problem auf, als der Manager Bilder mit genauen Abmessungen für das Hochladen auf bestimmte Dienste benötigte, da dies deren technische Anforderungen waren. Zum Beispiel, wenn wir das Originalbild mit der Größe 1200×1200, und beim Resizing geben wir etwas wie ?resize=600×400ein, erhalten wir ein proportional verkleinertes Bild an der kleinsten Kante mit der Größe 400×400. Es ist auch nicht möglich, ein Bild mit höherer Auflösung (Upscale) zu erhalten. Das heißt, ?resize=1500×1500 gibt nur das gleiche Bild zurück 1200×1200

Ein Artikel kam zur Hilfe OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln um zu verstehen, wie Nginx mit Lua funktioniert und die Bibliothek für Lua isage/lua-imagick — Lua pure-c Bindings für ImageMagick. Warum wurde diese Lösung gewählt und nicht, sagen wir, etwas in Python — weil es schnell und praktisch ist. Sie müssen nicht einmal irgendwelche Dateien erstellen, alles direkt in der Nginx-Konfiguration (optional).

Also, was brauchen wir

Beispiele werden auf Basis 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 die Bibliothek magickwand darum, in meinem Fall für Version 6

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

Build lua-imagick

Wir klonen das Repository (oder wir laden das Zip herunter 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, kann Nginx konfiguriert werden.

Ich gebe ein Beispiel für die Konfiguration des Backend-Hosts, der sich um das Resizing kümmert. Er wird vom Frontserver ebenfalls mit Nginx proxied, wobei für eine bestimmte Zeit (einen Tag) und andere Dinge Caching erfolgt.

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), geschieht durch img:extent() und wird durch den Parameter resize mit dem Vorzeichen + am Ende definiert.

Die folgenden Parameter sind verfügbar:

  • WxH (Seitenverhältnis beibehalten, höhere Dimension verwenden)
  • WxH^ (Seitenverhältnis beibehalten, niedrigere Dimension verwenden (zuschneiden))
  • WxH! (Seitenverhältnis ignorieren)
  • WxH+ (Seitenverhältnis beibehalten, Seiteneinfassungen hinzufügen)

Zusammenfassungstabelle mit den Ergebnissen des Resizings

Parameter uri der 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)

Echtzeit-Bildgrößenänderung mit Nginx und LuaJIT (OpenResty)

Zusammenfassung

Angesichts der gesamten Leistungsfähigkeit und Einfachheit eines solchen Ansatzes können recht komplexe Logiken realisiert werden, zum Beispiel das Hinzufügen von Wasserzeichen oder die Implementierung von Berechtigungen für den Zugriff. Um die API-Möglichkeiten zur Arbeit mit Bildern zu erfahren, kann auf die Dokumentation der Bibliothek verwiesen werden. isage/lua-imagick

Quelle: habr.com

Erwerben Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster