Cambiar el tamaño de las imágenes sobre la marcha usando Nginx y LuaJIT (OpenResty)

Desde hace bastante tiempo, inspirado en el artículo Cambiar el tamaño de las imágenes sobre la marcha, se configuró el cambio de tamaño de la imagen con ngx_http_image_filter_module y todo funcionó como debería. Pero hubo un problema cuando el administrador necesitaba obtener imágenes con tamaños exactos para cargarlas en algunos servicios, porque Estos eran sus requisitos técnicos. Por ejemplo, si tenemos una imagen original de tamaño 1200x1200 , y al cambiar el tamaño escribimos algo como ? Cambiar tamaño = 600x400 , obtendremos una imagen reducida proporcionalmente en el borde más pequeño, tamaño 400x400 . También es imposible obtener una imagen con una resolución más alta (escala superior). Aquellos. ? resize = 1500x1500 devolverá la misma imagen1200x1200


Un artículo de OpenResty vino al rescate: convertimos NGINX en un servidor de aplicaciones completo para comprender cómo funciona Nginx con Lua y la biblioteca para Lua isage / lua-imagick en sí misma : enlaces de Lua pure-c a ImageMagick. Por qué se eligió esa solución, y no, digamos, algo en Python, porque es rápida y conveniente. Ni siquiera necesita crear ningún archivo, todo está en la configuración de Nginx (opcional).


Entonces, qué necesitamos


Se darán ejemplos basados ​​en Debian.


Instalar nginx y nginx-extras


apt-get update
apt-get install nginx-extras

Instalar LuaJIT


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

Instalar imagemagick


apt-get -y install imagemagick

y las bibliotecas magickwand , en mi caso para la versión 6


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

Lua-imagick build


Clonamos el repositorio (bueno, o tomamos el zip y lo desempaquetamos)


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

Si todo salió bien, puede configurar Nginx.


backend , , , . Nginx, () . .


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

, ( ) img:extent() resize + .


:


  • WxH (Keep aspect-ratio, use higher dimension)
  • WxH^ (Keep aspect-ratio, use lower dimension (crop))
  • WxH! (Ignore aspect-ratio)
  • WxH+ (Keep aspect-ratio, add side borders)


uri
?resize=400x200200x200
?resize=400x200^400x400
?resize=400x200!400x200 ( )
?resize=400x200+400x200 ()



Dado el poder y la simplicidad de este enfoque, puede implementar cosas con una lógica bastante complicada, por ejemplo, agregar watermark'i o implementar autorización con acceso limitado. Para conocer las capacidades de la API para trabajar con imágenes, puede consultar la documentación de la biblioteca isage / lua-imagick


All Articles