αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†αžšαžΌαž”αž—αžΆαž–αž—αŸ’αž›αžΆαž˜αŸ—αžŠαŸ„αž™αž”αŸ’αžšαžΎ Nginx αž“αž·αž„ LuaJIT (OpenResty)

αž˜αž½αž™αžšαž™αŸˆαž“αŸαŸ‡ αž”αŸ†αž•αž»αžŸαž‚αŸ†αž“αž·αžαžŠαŸ„αž™αž’αžαŸ’αžαž”αž‘ αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†αžšαžΌαž”αž—αžΆαž–αž—αŸ’αž›αžΆαž˜αŸ— αž€αžΆαžšαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†αžšαžΌαž”αž—αžΆαž–αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžŠαŸ„αž™αž”αŸ’αžšαžΎ ngx_http_image_filter_module αž αžΎαž™αž’αŸ’αžœαžΈαŸ—αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŠαžΌαž…αžŠαŸ‚αž›αžœαžΆαž‚αž½αžšαžαŸ‚αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž”αž‰αŸ’αž αžΆαž˜αž½αž™αž”αžΆαž“αž€αžΎαžαž‘αžΎαž„αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž’αŸ’αž“αž€αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαž‘αž‘αž½αž›αžšαžΌαž”αž—αžΆαž–αžŠαŸ‚αž›αž˜αžΆαž“αžœαž·αž˜αžΆαžαŸ’αžšαž–αž·αžαž”αŸ’αžšαžΆαž€αžŠαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αž„αŸ’αž αŸ„αŸ‡αž‘αŸ…αž€αžΆαž“αŸ‹αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž˜αž½αž™αž…αŸ†αž“αž½αž“ αžŠαŸ„αž™αžŸαžΆαžšαžαŸ‚... αž‘αžΆαŸ†αž„αž“αŸαŸ‡αž‚αžΊαž‡αžΆαžαž˜αŸ’αžšαžΌαžœαž€αžΆαžšαž”αž…αŸ’αž…αŸαž€αž‘αŸαžŸαžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸαŸ” αž§αž‘αžΆαž αžšαžŽαŸαž”αŸ’αžšαžŸαž·αž“αž”αžΎαž™αžΎαž„αž˜αžΆαž“αžšαžΌαž”αž—αžΆαž–αžŠαžΎαž˜αž“αŸƒαž‘αŸ†αž αŸ† 1200 Γ— 1200αž αžΎαž™αž“αŸ…αž–αŸαž›αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†αž™αžΎαž„αžŸαžšαžŸαŸαžšαž’αŸ’αžœαžΈαž˜αž½αž™αžŠαžΌαž…αž‡αžΆ ?resize=600Γ—400αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“αžšαžΌαž”αž—αžΆαž–αž€αžΆαžαŸ‹αž”αž“αŸ’αžαž™αžŸαž˜αžΆαž˜αžΆαžαŸ’αžšαžαžΆαž˜αž‚αŸ‚αž˜αžαžΌαž…αž”αŸ†αž•αž»αž αž‘αŸ†αž αŸ† 400 Γ— 400. αžœαžΆαž€αŸαž˜αž·αž“αž’αžΆαž…αž‘αŸ…αžšαž½αž…αž‘αŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαž‘αž‘αž½αž›αž”αžΆαž“αžšαžΌαž”αž—αžΆαž–αžŠαŸ‚αž›αž˜αžΆαž“αž‚αž»αžŽαž—αžΆαž–αž”αž„αŸ’αž αžΆαž‰αžαŸ’αž–αžŸαŸ‹ (αž’αŸ†αž‡αžΆαž„)αŸ” αž‘αžΆαŸ†αž„αž“αŸ„αŸ‡αŸ” ?resize=1500Γ—1500 αž“αžΉαž„αžαŸ’αžšαž‘αž”αŸ‹αžšαžΌαž”αž—αžΆαž–αžŠαžŠαŸ‚αž› 1200 Γ— 1200

αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡αž”αžΆαž“αž˜αž€αž‡αž½αž™αžŸαž„αŸ’αž‚αŸ’αžšαŸ„αŸ‡ OpenRestyαŸ– αž”αŸ’αžšαŸ‚αž€αŸ’αž›αžΆαž™ NGINX αž‘αŸ…αž‡αžΆαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž–αŸαž‰αž›αŸαž‰ αžŠαžΎαž˜αŸ’αž”αžΈαž™αž›αŸ‹αž–αžΈαžšαž”αŸ€αž”αžŠαŸ‚αž› Nginx αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™ Lua αž“αž·αž„αž”αžŽαŸ’αžŽαžΆαž›αŸαž™αžαŸ’αž›αž½αž“αž―αž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ Lua isage/lua-imagick - Lua pure-c αž…αž„αž—αŸ’αž‡αžΆαž”αŸ‹αž‡αžΆαž˜αž½αž™ ImageMagick αŸ” αž αŸαžαž»αž’αŸ’αžœαžΈαž”αžΆαž“αž‡αžΆαžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸ αž“αž·αž„αž˜αž·αž“αž“αž·αž™αžΆαž™αžαžΆαž’αŸ’αžœαžΈαž˜αž½αž™αž“αŸ…αž€αŸ’αž“αž»αž„ python αž–αŸ’αžšαŸ„αŸ‡αžœαžΆαž›αžΏαž“ αž“αž·αž„αž„αžΆαž™αžŸαŸ’αžšαž½αž›αŸ” αž’αŸ’αž“αž€αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž”αž„αŸ’αž€αžΎαžαž―αž€αžŸαžΆαžšαžŽαžΆαž˜αž½αž™αž‘αŸ αž’αŸ’αžœαžΈαž‚αŸ’αžšαž”αŸ‹αž™αŸ‰αžΆαž„αž‚αžΊαžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ Nginx (αžŸαŸ’αžšαŸαž…αž…αž·αžαŸ’αž)αŸ”

αžŠαžΌαž…αŸ’αž“αŸαŸ‡αžαžΎαž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαž’αŸ’αžœαžΈαžαŸ’αž›αŸ‡

αž§αž‘αžΆαž αžšαžŽαŸαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αžαž›αŸ‹αž±αŸ’αž™αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎ Debian αŸ”

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ nginx αž“αž·αž„ nginx-extras

apt-get update
apt-get install nginx-extras

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ LuaJIT

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

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ imagemagick

apt-get -y install imagemagick

αž“αž·αž„αž”αžŽαŸ’αžŽαžΆαž›αŸαž™ αžœαŸαž‘αž˜αž“αŸ’αž αž‘αŸ…αžœαžΆ αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αŸ†αžŽαŸ‚ 6

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

αž€αžΆαžšαž€αžŸαžΆαž„ lua-imagick

αž™αžΎαž„αž€αŸ’αž›αžΌαž“αžƒαŸ’αž›αžΆαŸ†αž„ (αž¬αž™αž€ zip αž αžΎαž™αžŸαŸ’αžšαžΆαž™αžœαžΆ)

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

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αžœαžΈαŸ—αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž›αŸ’αž’ αž’αŸ’αž“αž€αž’αžΆαž…αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ Nginx αŸ”

αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž•αŸ’αžαž›αŸ‹αž§αž‘αžΆαž αžšαžŽαŸαž“αŸƒ config αž“αŸƒ backend host αžŠαŸ‚αž›αžαžΆαž˜αž–αž·αžαž‘αŸ…αž‚αžΊαž‘αž‘αž½αž›αžαž»αžŸαžαŸ’αžšαžΌαžœαž…αŸ†αž–αŸ„αŸ‡αž€αžΆαžšαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†αŸ” αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΌαž€αžŸαŸŠαžΈαžŠαŸ„αž™αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαžαžΆαž„αž˜αž»αž αž€αŸαžŠαžΌαž…αž‡αžΆ Nginx αž•αž„αžŠαŸ‚αžš αžŠαŸ‚αž›αžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αž„αžΆαžαŸ‹αž€αžΎαžαž‘αžΎαž„αž€αŸ’αž“αž»αž„αžšαž™αŸˆαž–αŸαž›αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αž˜αž½αž™ (αžαŸ’αž„αŸƒ) αž“αž·αž„αž’αŸ’αžœαžΈαŸ—αž•αŸ’αžŸαŸαž„αž‘αŸ€αžαŸ”

αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž•αŸ’αž“αŸ‚αž€αžαžΆαž„αž€αŸ’αžšαŸ„αž™ 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
    }
}

αž’αŸ’αžœαžΈαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αžΆαž˜αž‘αžΆαžš (αž–αž„αŸ’αžšαžΈαž€αžšαžΌαž”αž—αžΆαž–αž‡αž»αŸ†αžœαž·αž‰αž‚αŸ‚αž˜) αž€αžΎαžαž‘αžΎαž„αžŠαŸ„αž™αž”αŸ’αžšαžΎ img:extent() αž“αž·αž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžŠαŸ„αž™αž”αŸ’αžšαžΎαž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžš resize αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžŸαž‰αŸ’αž‰αžΆαž˜αž½αž™αŸ” + αž“αŸ…β€‹αž…αž»αž„β€‹αž”αž‰αŸ’αž…αž”αŸ‹αŸ”

αž‡αž˜αŸ’αžšαžΎαžŸαžαžΆαž„αž€αŸ’αžšαŸ„αž˜αž’αžΆαž…αž”αŸ’αžšαžΎαž”αžΆαž“αŸ–

  • WxH (αžšαž€αŸ’αžŸαžΆαžŸαž˜αžΆαž˜αžΆαžαŸ’αžšαž‘αž·αžŠαŸ’αž‹αž—αžΆαž– αž”αŸ’αžšαžΎαžœαž·αž˜αžΆαžαŸ’αžšαžαŸ’αž–αžŸαŸ‹αž‡αžΆαž„)
  • WxH^ (αžšαž€αŸ’αžŸαžΆαžŸαž˜αžΆαž˜αžΆαžαŸ’αžš αž”αŸ’αžšαžΎαžœαž·αž˜αžΆαžαŸ’αžšαž‘αžΆαž” (αž…αŸ’αžšαžΉαž”))
  • WxH! (αž˜αž·αž“αž’αžΎαž–αžΎαžŸαž˜αžΆαž˜αžΆαžαŸ’αžš)
  • WxH+ (αžšαž€αŸ’αžŸαžΆαžŸαž˜αžΆαž˜αžΆαžαŸ’αžšαž‘αž·αžŠαŸ’αž‹αž—αžΆαž– αž”αž“αŸ’αžαŸ‚αž˜αžŸαŸŠαž»αž˜αž…αŸ†αž αŸ€αž„)

αžαžΆαžšαžΆαž„αžŸαž„αŸ’αžαŸαž”αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž›αž‘αŸ’αž’αž•αž›αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†

αžŸαŸ’αž“αžΎαžŸαž»αŸ†αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžš
αž”αž‰αŸ’αž…αŸαž‰αž‘αŸ†αž αŸ†αžšαžΌαž”αž—αžΆαž–

?resize=400Γ—200
200 Γ— 200

?resize=400Γ—200^
400 Γ— 400

?resize=400Γ—200!
400 Γ— 200 (αž˜αž·αž“αžŸαž˜αžΆαž˜αžΆαžαŸ’αžš)

?resize=400Γ—200+
400 Γ— 200 (αžŸαž˜αžΆαž˜αžΆαžαŸ’αžš)

αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž‘αŸ†αž αŸ†αžšαžΌαž”αž—αžΆαž–αž—αŸ’αž›αžΆαž˜αŸ—αžŠαŸ„αž™αž”αŸ’αžšαžΎ Nginx αž“αž·αž„ LuaJIT (OpenResty)

αž›αž‘αŸ’αž’αž•αž›

αžŠαŸ„αž™αž–αž·αž…αžΆαžšαžŽαžΆαž›αžΎαžαžΆαž˜αž–αž› αž“αž·αž„αž—αžΆαž–αžŸαžΆαž˜αž‰αŸ’αž‰αž“αŸƒαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαž“αŸαŸ‡ αž’αŸ’αž“αž€αž’αžΆαž…αž’αž“αž»αžœαžαŸ’αžαž’αŸ’αžœαžΈαŸ—αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžαž€αŸ’αž€αžœαž·αž‡αŸ’αž‡αžΆαžŠαŸαžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰ αž§αž‘αžΆαž αžšαžŽαŸ αž€αžΆαžšαž”αž“αŸ’αžαŸ‚αž˜αž€αžΆαžšαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž‘αžΉαž€ αž¬αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž€αžΆαžšαž’αž“αž»αž‰αŸ’αž‰αžΆαžαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž…αžΌαž›αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž˜αžΆαž“αž€αŸ†αžŽαžαŸ‹αŸ” αžŠαžΎαž˜αŸ’αž”αžΈαžŸαŸ’αžœαŸ‚αž„αž™αž›αŸ‹αž–αžΈαžŸαž˜αžαŸ’αžαž—αžΆαž–αžšαž”αžŸαŸ‹ API αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αžšαžΌαž”αž—αžΆαž– αž’αŸ’αž“αž€αž’αžΆαž…αž™αŸ„αž„αž‘αŸ…αž―αž€αžŸαžΆαžšαž”αžŽαŸ’αžŽαžΆαž›αŸαž™ isage/lua-imagick

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹