Desde hace bastante tiempo, inspirado por un artículo se configuró el redimensionamiento de imágenes usando y todo funcionaba como se esperaba. Pero surgió un problema cuando el gerente necesitaba obtener imágenes con dimensiones exactas para cargar en ciertos servicios, ya que eran sus requisitos técnicos. Por ejemplo, si tenemos un original de imagen de tamaño 1200×1200, y al redimensionar especificamos algo como ?resize=600×400, obtendremos una imagen proporcionalmente reducida por el lado más pequeño, de tamaño 400×400. También es imposible obtener una imagen con una mayor resolución (upscale). Es decir, ?resize=1500×1500 devolverá la misma imagen 1200×1200
Un artículo llegó a ayudar para entender cómo trabaja Nginx con Lua y la propia biblioteca para Lua — bindings de Lua en C puro para ImageMagick. ¿Por qué se eligió tal solución en lugar de, digamos, algo en Python? Porque es rápido y conveniente. Incluso no necesitarás crear ningún archivo, todo irá directamente en la configuración de Nginx (no es obligatorio).
Así que, ¿qué necesitaremos?
Los ejemplos se darán sobre la base de Debian.
Instalación de nginx y nginx-extras
apt-get update
apt-get install nginx-extrasInstalación de LuaJIT
apt-get -y install lua5.1 luajit-5.1 libluajit-5.1-devInstalación de imagemagick
apt-get -y install imagemagicky la biblioteca magickwand asociada, en mi caso para la versión 6
apt-cache search libmagickwand
apt-get -y install libmagickwand-6.q16-3 libmagickwand-6.q16-devCompilación de lua-imagick
Clonamos el repositorio (o simplemente descargamos el zip y lo descomprimimos)
cd ~
git clone https://github.com/isage/lua-imagick.git
cd lua-imagick
mkdir build
cd build
cmake ..
make
make installSi todo ha ido bien, se puede configurar Nginx.
Aquí un ejemplo de la configuración del backend del host, que de hecho se encarga del redimensionamiento. Se proxiea a través del servidor frontal también con Nginx, donde se realiza la caché por un tiempo (un día) y otras cosas.
configuración de backend 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
}
}
Lo que se necesitaba (ampliar la imagen por los bordes) se realiza con img:extent() y se determina a través del parámetro resize con un signo + al final.
Los siguientes parámetros están disponibles:
- WxH (Mantener la relación de aspecto, usar dimensión superior)
- WxH^ (Mantener la relación de aspecto, usar dimensión inferior (recortar))
- WxH! (Ignorar la relación de aspecto)
- WxH+ (Mantener la relación de aspecto, agregar bordes laterales)
Tabla resumen con los resultados del redimensionamiento
Parámetro uri de la solicitud
Tamaño de la imagen salida
?resize=400×200
200×200
?resize=400×200^
400×400
?resize=400×200!
400×200 (No proporcional)
?resize=400×200+
400×200 (Proporcional)

Summary
Dada toda la potencia y simplicidad de este enfoque, se pueden implementar cosas con una lógica bastante compleja, como agregar marcas de agua o implementar una autorización con control de acceso. Para conocer las capacidades de la API para trabajar con imágenes, se puede consultar la documentación de la biblioteca
Fuente: habr.com
