For a long time, inspired by the article image resizing was configured with and everything worked as it should. But there was one problem when the manager needed to get images with exact dimensions for uploading to some services, because. those were their specifications. For example, if we have an original image of size 1200 × 1200, and when resizing we write something like ?resize=600×400, then we get a proportionally reduced image along the smallest edge, size 400 × 400. It is also impossible to get an image with a higher resolution (upscale). Those. ?resize=1500×1500 will return all the same image 1200 × 1200
Article came to the rescue to understand how Nginx works with Lua and the library itself for Lua - Lua pure-c bindings to ImageMagick. Why such a solution was chosen, and not, say, something in python - because it is fast and convenient. You don't even need to create any files, everything is right in the Nginx config (optional).
So, what do we need
The examples will be based on Debian.
Installing nginx and nginx-extras
apt-get update
apt-get install nginx-extrasInstalling LuaJIT
apt-get -y install lua5.1 luajit-5.1 libluajit-5.1-devInstalling imagemagick
apt-get -y install imagemagickand libraries magickwand to it, in my case for version 6
apt-cache search libmagickwand
apt-get -y install libmagickwand-6.q16-3 libmagickwand-6.q16-devBuilding lua-imagick
Clone the repository (well, or take the zip and unpack it)
cd ~
git clone https://github.com/isage/lua-imagick.git
cd lua-imagick
mkdir build
cd build
cmake ..
make
make installIf everything went well, you can configure Nginx.
I will give an example of the backend host config, which, in fact, is engaged in resizing. It is proxied by the front server in the same way as with Nginx, on which caching takes place for a certain time (day), etc. things.
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
}
}
What was required (expanding the image at the edges) is done with img:extent() and is determined using the parameter resize with sign + at the end.
The following options are available:
- 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)
Pivot table with resize results
Request uri parameter
Output image size
?resize=400×200
200 × 200
?resize=400×200^
400 × 400
?resize=400×200!
400×200 (Not proportional)
?resize=400×200+
400×200 (Proportional)

Сonclusion
Given the power and simplicity of this approach, you can implement things with rather complex logic, for example, add watermarks or implement authorization with limited access. In order to learn about the capabilities of the API for working with images, you can refer to the library documentation.
Source: habr.com
