Zmień rozmiar obrazów w locie za pomocą Nginx i LuaJIT (OpenResty)

Od dłuższego czasu inspirowany artykułem Zmiana rozmiaru obrazu w locie zmiana rozmiaru obrazu została skonfigurowana przy użyciu ngx_http_image_filter_module i wszystko działało jak należy. Pojawił się jednak problem, gdy menedżer musiał otrzymać obrazy o dokładnych wymiarach w celu przesłania ich do niektórych usług, ponieważ... takie były ich wymagania techniczne. Na przykład, jeśli mamy oryginalny obraz o rozmiarze 1200 × 1200, a przy zmianie rozmiaru piszemy coś takiego ?zmienić rozmiar=600×400, wówczas otrzymujemy proporcjonalnie zmniejszony obraz wzdłuż najmniejszej krawędzi, rozmiaru 400 × 400. Niemożliwe jest także uzyskanie obrazu o wyższej rozdzielczości (upscale). Te. ?zmienić rozmiar=1500×1500 zwróci ten sam obraz 1200 × 1200

Ten artykuł przyszedł na ratunek OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji aby zrozumieć, jak Nginx współpracuje z Lua i samą biblioteką dla Lua isage/lua-imagick - Powiązania Lua pure-c z ImageMagick. Dlaczego wybrano właśnie to rozwiązanie, a nie powiedzmy coś w Pythonie - bo jest szybkie i wygodne. Nie musisz nawet tworzyć żadnych plików, wszystko jest w porządku w konfiguracji Nginx (opcjonalnie).

Czego więc potrzebujemy

Przykłady zostaną podane w oparciu o Debiana.

Instalowanie nginx i dodatków nginx

apt-get update
apt-get install nginx-extras

Instalowanie LuaJIT

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

Instalowanie imagemagicka

apt-get -y install imagemagick

i biblioteki magiczna różdżka do tego, w moim przypadku do wersji 6

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

Budowanie lua-imagick

Klonujemy repozytorium (lub bierzemy zip i rozpakowujemy)

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

Jeśli wszystko poszło dobrze, możesz skonfigurować Nginx.

Podam przykład konfiguracji hosta backendowego, który tak naprawdę odpowiada za zmianę rozmiaru. Jest proxy przez serwer frontowy, również z Nginxem, gdzie buforowanie odbywa się przez określony czas (dni) i inne rzeczy.

konfiguracja zaplecza nginx

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

To, co było wymagane (rozszerzanie obrazu wokół krawędzi), dzieje się za pomocą img:extent() i jest definiowany za pomocą parametru resize podpisany + na końcu.

Dostępne są następujące opcje:

  • SxW (Zachowaj proporcje, użyj większego wymiaru)
  • SxW^ (Zachowaj proporcje, użyj mniejszego wymiaru (przytnij))
  • szer. x wys.! (Zignoruj ​​proporcje)
  • SxW+ (Zachowaj proporcje, dodaj boczne krawędzie)

Tabela podsumowująca z wynikami zmiany rozmiaru

Żądanie parametru uri
Rozmiar obrazu wyjściowego

?zmienić rozmiar=400×200
200 × 200

?zmienić rozmiar=400×200^
400 × 400

?zmienić rozmiar=400×200!
400×200 (nieproporcjonalne)

?zmienić rozmiar=400×200+
400×200 (proporcjonalne)

Zmień rozmiar obrazów w locie za pomocą Nginx i LuaJIT (OpenResty)

Łączny

Biorąc pod uwagę siłę i prostotę tego podejścia, możesz wdrażać rzeczy o dość złożonej logice, na przykład dodając znaki wodne lub wdrażając autoryzację z ograniczonym dostępem. Aby poznać możliwości API do pracy z obrazami, możesz zapoznać się z dokumentacją biblioteki isage/lua-imagick

Źródło: www.habr.com

Dodaj komentarz