Створення зображень у хмарі: Використання Sharp та Node-Canvas у Docker-контейнері

pic

Логотип Sharp & логотип Docker & Canvas

У цій статті я покажу, як використовувати пакети sharp та node-canvas для генерації зображень всередині контейнера Docker.

Будь ласка, перегляньте супутній репозиторій на GitHub (посилання тут) для повністю працюючого прикладу проекту. Почнемо!

TL;DR

Нижче наведено Dockerfile, використаний у цьому проекті:

УВАГА: У цьому проекті я використовую TypeScript, тому для запуску потрібно використовувати команду npm run build.

FROM node:20-alpine  

RUN apk add  
 librsvg-dev \  
 pixman-dev \  
 freetype-dev \  
 fontconfig \  
 ttf-dejavu \  
 ttf-freefont  

WORKDIR /app  

COPY package*.json ./  

RUN npm install --build-from-source  

COPY . .  

RUN npm run build  

CMD ["node", "dist/app.js"]

Запуск проекту

Нещодавно я хотів створити сервер, який генеруватиме зображення за допомогою npm пакетів sharp та node-canvas. Однак я стикнувся з труднощами під час контейнеризації проекту з різних причин.

Нижче наведено огляд прикладу проекту (посилання тут) та інструкції, як ви можете запустити його самостійно!

Сервіс для створення зображень

Спочатку ми коротко розглянемо функцію, що використовується для генерації та, за бажанням, збереження зображення. Вона використовує комбінацію пакетів sharp та node-canvas.

УВАГА: функцію createImage() можна знайти у файлі src/services/image.service.ts.

import { createCanvas } from "canvas";  
import path from "path";  
import sharp from "sharp";  
import fs from "fs";  

const WIDTH = 1080;  
const HEIGHT = 1080;  
const FONT_LARGE = "bold 88px Arial";  
const FONT_MEDIUM = "semi-bold 68px Arial";  
const BACKGROUND_COLOR = "black";  
const TEXT_COLOR = "white";  

/**  
 * Функція для створення зображення  
 * @param title - заголовок зображення  
 * @param subtitle - підзаголовок зображення  
 * @param options {  
 * @param create_file - булеве значення, яке визначає, чи потрібно створювати файл;  
 * @param file_name - ім'я файлу, що буде створене;  
 * }  
 */  

export const createImage = async (  
 title: string,  
 subtitle: string,  
 options?: {  
 file_name?: string;  
 create_file?: boolean;  
 },  
) => {  
 const canvas = createCanvas(WIDTH, HEIGHT);  
 const ctx = canvas.getContext("2d");  

 // --- ФОН ---  
 ctx.fillStyle = BACKGROUND_COLOR;  
 ctx.fillRect(0, 0, WIDTH, HEIGHT);  

 // --- ТЕКСТ ЗАГОЛОВКА ---  
 const TITLE_Y_POSITION = 200;  
 ctx.fillStyle = TEXT_COLOR;  
 ctx.textAlign = "center";  
 ctx.font = FONT_LARGE;  
 ctx.fillText(title, WIDTH / 2, TITLE_Y_POSITION);  

 // --- ТЕКСТ ПІДЗАГОЛОВКА ---  
 const SUBTITLE_Y_POSITION = 350;  
 ctx.font = FONT_MEDIUM;  
 ctx.fillText(subtitle, WIDTH / 2, SUBTITLE_Y_POSITION);  

 // --- КОНВЕРТАЦІЯ У PNG ---  
 const FINAL_IMAGE_BUFFER = canvas.toBuffer("image/png");  
 const CONNECTIONS_IMAGE = await sharp(FINAL_IMAGE_BUFFER).toBuffer();  

 // --- ЗБЕРЕЖЕННЯ У ФАЙЛ ---  
 if (options?.create_file) {  
 const OUTPUT_DIR = path.join(__dirname, "../output");  
 if (!fs.existsSync(OUTPUT_DIR)) {  
 fs.mkdirSync(OUTPUT_DIR, { recursive: true });  
 }  

 const OUTPUT_PATH = path.join(  
 OUTPUT_DIR,  
 options?.file_name ?? "test-image.png",  
 );  

 fs.writeFileSync(OUTPUT_PATH, CONNECTIONS_IMAGE);  
 console.log(`Зображення збережене за адресою ${OUTPUT_PATH}`);  
 }  

 return CONNECTIONS_IMAGE;  
};

Наведений код показує, як працює функція:

  1. Створює полотно (1080 x 1080).
  2. Малює заголовок та підзаголовок на зображенні.
  3. Конвертує в PNG за допомогою canvas.toBuffer("image/png").
  4. За бажанням зберігає зображення в папку /output.
    5.
    Повертає Image Buffer для подальшої обробки без збереження на диску.

Запуск та тестування проекту локально (без Docker)

Будь ласка, слідуйте інструкціям в README на GitHub, щоб клонувати репозиторій та встановити залежності для проекту локально!

Далі, запустіть команду npm run dev
Це створить зображення в папці /output

pic

Зображення, створене за допомогою коду

Запуск та тестування проекту локально в Docker

Будь ласка, слідуйте інструкціям в README на GitHub, щоб клонувати репозиторій та встановити залежності для проекту локально!

Створіть Docker-образ:

docker build -t node-sharp-canvas-image .

Запустіть Docker-образ у контейнері:
УВАГА:
Це створить ID контейнера, який буде використовуватись пізніше.

docker run -d --name node-sharp-canvas-container node-sharp-canvas-image

Перевірка Docker-контейнера:
Тепер, коли контейнер працює, ми можемо перевірити папку /output, щоб переконатися, що зображення було створене.

docker exec  ls /app/src/output  

# --- Виведення: ---  
# .gitkeep  
# image-created-using-sharp-and-canvas.png

Висновки

Ось і все! Тепер ви можете генерувати зображення в середовищі Node.js всередині Docker-контейнера!

Підтримка

Якщо це було корисно, будь ласка, розгляньте можливість підтримати мене тут.

Перекладено з: Crafting Images in the Cloud: Using Sharp and Node-Canvas Inside a Docker Container

Leave a Reply

Your email address will not be published. Required fields are marked *