imgproxy

پردازش تصاویر با Imgproxy

(Imgproxy one-click app)

Imgproxy یک ابزار پردازش تصویر توسعه داده شده با زبان Go است که می‌توانیم آن را جایگزینی مدرن‌ و حتی بسیار کاربردی‌تر برای ImageMagick و یا GraphicsMagick بدانیم زیرا قابلیت‌های مختلفی مانند تغییر اندازه‌ی تصاویر را به‌صورت remote برای ما فراهم کرده است.

فهرست عناوین:

🚀 راه‌اندازی Imgproxy

در صورتی که تمایلی به خواندن آموزش متنی ندارید می‌توانید ویدیوی آموزشی زیر ‌را مشاهده کنید.

برای راه‌اندازی برنامه‌ی آماده Imgproxy باید در بخش برنامه‌های کنسول لیارا بر روی دکمه‌ی ایجاد برنامه کلیک کرده و در صفحه‌ی باز شده وارد بخش برنامه‌های آماده شوید. سپس برنامه‌ی Imgproxy را انتخاب و یک شناسه‌ی یکتا برای برنامه‌ی خود درنظر بگیرید، همچنین پلن مورد نظر خود را انتخاب کنید و در آخر بر روی دکمه‌ی ایجاد برنامه کلیک کنید.

استفاده از Imgproxy بر روی فضای ذخیره‌سازی ابری لیارا

برای استفاده از Imgproxy بر روی عکس‌های ذخیره‌شده در فضای ذخیره‌سازی ابری لیارا نیاز به انجام هیچ‌کار خاصی نیست؛ فقط کافیست تا آدرس دائمی (یا موقت) عکس ذخیره شده را در انتهای URL پیکربندی شده Imgproxy قرار دهید؛ به عنوان مثال، فرض کنید که این URL برابر با مقدار زیر است:

https://imgproxy-app.liara.run/_/resize:fill:300:400:0/gravity:sm/plain/

حال، فرض کنیم که URL عکس ذخیره‌شده در لیارا نیز، برابر با مقدار زیر است:

https://bucket.storage.iran.liara.space/liara-poster.png

اکنون، برای اعمال Imgproxy بر روی عکس مد نظر خود، کافیست تا URL پیکربندی شده Imgproxy را قبل از URL عکس مدنظر خود قرار دهید:

https://imgproxy-app.liara.run/_/resize:fill:300:400:0/gravity:sm/plain/https://bucket.storage.iran.liara.space/liara-poster.png

بدین نحو، تمامی تغییرات اعمال می‌شوند و شما می‌توانید با استفاده از URL فوق، به عکس نهایی خود دسترسی داشته باشید. قطعه کد زیر، نمونه‌ای از استفاده imgproxy بر روی باکت لیارا در فریم‌ورک Flask است:

from flask import Flask, request, render_template, redirect, url_for
import boto3
import uuid
from dotenv import load_dotenv
import os

app = Flask(__name__)

# Load environment variables from .env file
load_dotenv()

LIARA_ENDPOINT    = os.getenv("LIARA_ENDPOINT")
LIARA_BUCKET_NAME = os.getenv("LIARA_BUCKET_NAME")
LIARA_ACCESS_KEY  = os.getenv("LIARA_ACCESS_KEY")
LIARA_SECRET_KEY  = os.getenv("LIARA_SECRET_KEY")
IMGPROXY_URL      = os.getenv("IMGPROXY_URL") 

img_proxy_conf = {
    "signature": "_",
    "options": "resize:fill:300:400:0",
    "gravity": "gravity:sm",
}

imgproxy_conf = f'{img_proxy_conf["signature"]}/{img_proxy_conf["options"]}/{img_proxy_conf["gravity"]}/plain'

s3 = boto3.client('s3',
                  endpoint_url=LIARA_ENDPOINT,
                  aws_access_key_id=LIARA_ACCESS_KEY,
                  aws_secret_access_key=LIARA_SECRET_KEY)

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files['file']
        if file:
            # Generate a unique filename using UUID
            filename = str(uuid.uuid4()) + '.' + file.filename.rsplit('.', 1)[1]
            
            # Save file to S3
            s3.upload_fileobj(file, LIARA_BUCKET_NAME, filename)
            
            # Generate the URL for the uploaded file
            url = f"{LIARA_ENDPOINT}/{LIARA_BUCKET_NAME}/{filename}"
            
            # Redirect to images page
            return redirect(url_for('images'))
    return render_template('index.html')

@app.route('/images')
def images():
    # List all objects in the bucket
    response = s3.list_objects_v2(Bucket=LIARA_BUCKET_NAME)
    images = []
    for obj in response.get('Contents', []):
        images.append(f"{IMGPROXY_URL}{imgproxy_conf}/{LIARA_ENDPOINT}/{LIARA_BUCKET_NAME}/{obj['Key']}")
    return render_template('images.html', images=images)

if __name__ == '__main__':
    app.run(debug=True)
سورس کامل قطعه کد فوق در گیت‌هاب لیارا موجود است که می‌توانید از آن استفاده کنید.

برای کسب اطلاعات بیشتر و اعمال دیگر تغییرات می‌توانید مستندات پیکربندی Imgproxy را مطالعه کنید.

استفاده از Imgproxy در برنامه‌های Django

برای استفاده از Imgproxy در برنامه‌های Django، نیاز به نصب ماژول و یا کتابخانه خاصی نیست! در ادامه، یک مثال از نحوه استفاده Imgproxy آمده است:

در ابتدا، کافیست تا متغیرهای ENDPOINT و IMGPROXY_URL را به شکل زیر به فایل settings.py اضافه کنید:

import os
ENDPOINT     = os.getenv("ENDPOINT", 'http://127.0.0.1:8000')
IMGPROXY_URL = os.getenv("IMGPROXY_URL", "")
دقت داشته باشید که مقدار ENDPOINT را حتماً با http یا https وارد کنید و همچنین مقدار IMGPROXY_URL باید برابر با آدرس کامل برنامه Imgproxy باشد.

برای مثال، اگر که از فایل .env استفاده می‌کنید، مقادیر دو متغیر فوق را باید همانند مقادیر زیر وارد کنید:

ENDPOINT=https://django-app-test.liara.run
IMGPROXY_URL=https://imgproxy-app.liara.run

اکنون می‌توانید از Imgproxy در برنامه خود استفاده کنید؛ برای مثال، قطعه کد زیر در فایل models.py به کار رفته است:

from django.db import models
from django.conf import settings

img_proxy_conf = {
    "signature": "_",
    "options": "resize:fill:300:400:0",
    "gravity": "gravity:sm",}

class Image(models.Model):
    title = models.CharField(max_length=100)
    image = models.ImageField(upload_to='')
    full_path = models.CharField(max_length=255)
    final_result = models.CharField(max_length=255)

    def save(self, *args, **kwargs):
        if self.image:
            self.full_path = f"{settings.ENDPOINT}{self.image.url}"
            if settings.IMGPROXY_URL != "":
                self.final_result = (
                    f"{settings.IMGPROXY_URL}/{img_proxy_conf['signature']}/"
                    f"{img_proxy_conf['options']}/{img_proxy_conf['gravity']}/plain/"
                    f"{self.full_path}")
            else:
                self.final_result = self.image.url
        super().save(*args, **kwargs)
سورس کامل قطعه کد فوق در گیت‌هاب لیارا موجود است که می‌توانید از آن استفاده کنید.

در نظر داشته باشید که کد فوق، یک مثال از کاربرد Imgproxy است و شما می‌توانید فیلد option درون دیکشنری img_proxy_conf موجود در کد فوق را با توجه به نیاز خود تغییر دهید.

استفاده از Imgproxy در برنامه‌های Laravel

برای استفاده از Imgproxy در ابتدا بایستی متغیرهای محیطی زیر را به فایل .env یا بخش متغیرهای محیطی برنامه خود اضافه کنید:

ENDPOINT_URL=your-host-address 
IMGPROXY_URL=your-imgproxy-address
دقت داشته باشید که مقدار ENDPOINT را حتماً با http یا https وارد کنید و همچنین مقدار IMGPROXY_URL باید برابر با آدرس کامل برنامه Imgproxy باشد.

قطعه کد زیر یک مثال برای مقدار این متغیرهای محیطی است:

ENDPOINT_URL=https://laravel-app.liara.run
IMGPROXY_URL=https://imgproxy-app.liara.run

اکنون کافیست تا در دایرکتوری config یک فایل به نام custom.php ایجاد کنید و قطعه کد زیر را درون آن قرار دهید:

<?php

return [
    'img_proxy_conf' => [
        'signature' => '_',
        'options' => 'resize:fill:300:400:0',
        'gravity' => 'gravity:sm',
    ],
];

دقت داشته باشید که مقادیر درون img_proxy_conf برای مثال آورده شده‌اند و شما می‌توانید مقادیر آن را متناسب با نیازهای خود تغییر دهید.

اکنون، می‌توانید از imgproxy در برنامه خود استفاده کنید؛ قطعه کد زیر، مثالی از استفاده imgproxy در کنترلر برنامه laravel است:

<?php

namespace AppHttpControllers;

use IlluminateHttpRequest;
use AppModelsPhoto;
use IlluminateSupportFacadesStorage;

class PhotoController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'photo' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
        ]);

        $imgProxyConf = config('custom.img_proxy_conf');
        $options = $imgProxyConf['options'];
        $gravity = $imgProxyConf['gravity'];
        $signature = $imgProxyConf['signature'];


        $phototemp = $request->file('photo')->store('public/photos');
        $photoPath_ = env('ENDPOINT_URL') . Storage::url($phototemp);
        $photoPath = env('IMGPROXY_URL') . '/' . $signature . '/' . $options . '/' . $gravity . '/plain/' . $photoPath_;


        Photo::create([
            'path' => $photoPath,
        ]);

        return redirect()->route('photo.index');
    }
    
    public function index()
    {
        $photos = Photo::all();
        return view('photos.index', compact('photos'));
    }
}
سورس کامل قطعه کد فوق در گیت‌هاب لیارا موجود است که می‌توانید از آن استفاده کنید.

استفاده از Imgproxy در برنامه‌های NodeJS

برای استفاده از Imgproxy باید همانند دو پلتفرم دیگر، متغیرهای محیطی زیر را به فایل .env یا بخش متغیرهای محیطی برنامه خود اضافه کنید:

ENDPOINT_URL=https://laravel-app.liara.run
IMGPROXY_URL=https://imgproxy-app.liara.run
در نظر داشته باشید که مقدار متغیرهای محیطی فوق، فرضی هستند و باید آن‌ها را با مقادیر خود، جایگزین کنید.

اکنون می‌توانید تنظیمات مربوط به Imgproxy را در برنامه خود وارد کنید:

const ENDPOINT_URL = process.env.ENDPOINT_URL;
const IMGPROXY_URL = process.env.IMGPROXY_URL;

const img_proxy_conf = {
    "signature": "_",
    "options": "resize:fill:300:400:0",
    "gravity": "gravity:sm"
};

const imgproxy_conf = `${IMGPROXY_URL}/${img_proxy_conf.signature}/${img_proxy_conf.options}/${img_proxy_conf.gravity}/plain/`;

دقت داشته باشید که مقادیر درون img_proxy_conf برای مثال آورده شده‌اند و شما می‌توانید مقادیر آن را متناسب با نیازهای خود تغییر دهید.

در نهایت، می‌توانید با استفاده از قطعه کد زیر، از imgproxy در برنامه خود استفاده کنید:

app.get('/images', (req, res) => {
    fs.readdir('./public/uploads', (err, files) => {
        if (err) {
            console.error('Error reading directory:', err);
            res.status(500).send('Internal Server Error');
            return;
        }

        const imageFiles = files.filter(file => {
            const extname = path.extname(file);
            return ['.jpg', '.jpeg', '.png', '.gif'].includes(extname.toLowerCase());
        });

        const processedImages = imageFiles.map(image => {
            const temp = `${ENDPOINT_URL}/public/uploads/${image}`;
            return `${imgproxy_conf}${temp}`;
        });

        processedImages.forEach(image => {
            console.log(image);
        });

        res.render('images', { images: processedImages });
    });
});
سورس کامل قطعه کد فوق در گیت‌هاب لیارا موجود است که می‌توانید از آن استفاده کنید.

🎯 توضیحات و نکات تکمیلی

اضافه کردن URL signature

بسیار توصیه می‌شود که در حالت Production با اجرای دستور زیر، یک hex-encoded key و یک hex-encoded salt ایجاد کرده و هر دوی این مقدارها را کپی کنید:

echo $(xxd -g 2 -l 64 -p /dev/random | tr -d '\n')

سپس وارد تب برنامه‌ها شده و برنامه‌ی Imgproxy خود را انتخاب کنید. اکنون باید مقادیر کپی شده را در بخش تنظیمات متغیرها در فیلد Value متغیرهای IMGPROXY_KEY و IMGPROXY_SALT قرار دهید و درنهایت بر روی دکمه‌ی ثبت تغییرات کلیک کنید.

محدود کردن دسترسی به Imgproxy با تنظیم IMGPROXY_SECRET

برای محدود کردن دسترسی به برنامه‌ی Imgproxy می‌توانید secret مورد نظر خود را در فیلد Value متغیر IMGPROXY_SECRET وارد کرده و درنهایت بر روی دکمه‌ی ثبت تغییرات کلیک کنید.

توجه داشته باشید که پس از تنظیم IMGPROXY_SECRET بایستی هدرAuthorization: Bearer %secret% را به درخواست‌های HTTP خود اضافه کنید.

تغییر نسخه‌ی برنامه مستقر شده

برخی مواقع لازم شده که نسخه برنامه‌ی آماده‌ای که مستقر کردیم رو تغییر بدیم. برای مثال، نسخه جدیدی از آن برنامه منتشر شده و ما می‌خواهیم از آن استفاده بکنیم. نکته‌ای که باید قبل تغییر نسخه برنامه‌مان در نظر داشته باشیم، این است که آن نسخه با لیارا سازگاری داشته باشد و در صورتی که لازم باشد از دیسک‌ها برای مواردی همچون تغییرات در برنامه یا نگهداری اطلاعات‌مان استفاده بکنیم. یا حتی لازم باشد یک سری متغیر‌هایی در برنامه‌مان تنظیم کنیم. در اینجا شما می‌تونید یک نمونه ساده از تغییر نسخه را مشاهده کنید. برای شروع لازم هست ابتدا در سیستم لوکال فایلی تحت عنوان liara.jsonایجاد کنید و مقادیر زیر رو در اون قرار بدید:

{
    "image": "darthsim/imgproxy:<your-version>",
    "port": 80,
    "app": "<your-app-name>"
}

در اینجا مقدار app، برابر هست با نام برنامه‌ای که در لیارا ایجاد کردید و مقدار image، برابر هست نام image برنامه‌تان. در قسمت port، پورتی که برنامه‌تان بر روی آن اجرا می‌شود. در نهایت با liara-cli و سپس دستور زیر برنامه‌تان مستقر کنید:

liara deploy
;