Серверная обработка изображений через ImageMagick
ImageMagick — стандарт де-факто для серверной обработки изображений. Поддерживает 200+ форматов, сложные трансформации и работает через CLI или библиотеки (Wand для Python, Imagick для PHP, imagemagick для Node.js). Используется там, где Sharp не справляется: PDF-конвертация, PSD, сложные цветовые профили, векторная растеризация.
Установка
# Ubuntu/Debian
apt install imagemagick libmagickwand-dev
# Alpine (Docker)
apk add imagemagick
# macOS
brew install imagemagick
# Проверить поддерживаемые форматы
convert -list format | grep -E 'WEBP|AVIF|PDF'
Python: Wand (биндинг к MagickWand)
pip install Wand
from wand.image import Image
from wand.color import Color
import io
def process_image(input_path: str, output_dir: str, filename: str):
with Image(filename=input_path) as img:
# Auto-orient по EXIF
img.auto_orient()
# Нормализовать в RGB (PDF/CMYK → sRGB)
if img.colorspace == 'cmyk':
img.transform_colorspace('srgb')
# Убрать прозрачность перед JPEG
if img.alpha_channel and filename.endswith('.jpg'):
img.background_color = Color('white')
img.alpha_channel = 'remove'
# Генерация вариантов
sizes = {
'thumb': (150, 150, 'cover'),
'medium': (800, 600, 'inside'),
'large': (1920, 1080, 'inside'),
}
results = {}
for name, (w, h, fit) in sizes.items():
with img.clone() as variant:
if fit == 'cover':
# Resize + crop по центру
variant.transform(resize=f'{w}x{h}^')
variant.gravity = 'center'
variant.extent(w, h)
else:
variant.transform(resize=f'{w}x{h}>')
variant.strip() # удалить метаданные
variant.compression_quality = 85
out_path = f"{output_dir}/{name}.webp"
variant.format = 'webp'
variant.save(filename=out_path)
results[name] = out_path
return results
PHP: Imagick
<?php
class ImageProcessor
{
public function process(string $inputPath, string $outputDir): array
{
$imagick = new Imagick($inputPath);
// Auto-orient и нормализация
$imagick->autoOrient();
// Для многостраничных файлов (PDF, GIF) — взять первый кадр
$imagick = $imagick->coalesceImages()->current();
// CMYK → sRGB
if ($imagick->getColorspace() === Imagick::COLORSPACE_CMYK) {
$imagick->transformImageColorspace(Imagick::COLORSPACE_SRGB);
}
$sizes = [
'thumb' => [150, 150, Imagick::GRAVITY_CENTER],
'medium' => [800, 600, null],
'large' => [1920, 1080, null],
];
$results = [];
foreach ($sizes as $name => [$w, $h, $gravity]) {
$variant = clone $imagick;
if ($gravity) {
// Thumbnail с обрезкой по центру
$variant->cropThumbnailImage($w, $h);
} else {
$variant->thumbnailImage($w, $h, true); // fit inside
}
$variant->stripImage(); // убрать EXIF
$variant->setImageFormat('webp');
$variant->setImageCompressionQuality(82);
$outPath = "{$outputDir}/{$name}.webp";
$variant->writeImage($outPath);
$results[$name] = $outPath;
$variant->destroy();
}
$imagick->destroy();
return $results;
}
}
PDF и PSD конвертация
Уникальная возможность ImageMagick — конвертация PDF страниц в изображения:
from wand.image import Image
def pdf_to_images(pdf_path: str, output_dir: str, dpi: int = 150):
"""Конвертировать PDF в JPG превью страниц"""
with Image(filename=pdf_path, resolution=dpi) as pdf:
images = pdf.sequence
for i, page in enumerate(images):
with Image(page) as img:
img.format = 'jpeg'
img.compression_quality = 85
# Белый фон (PDF может быть прозрачным)
img.background_color = Color('white')
img.alpha_channel = 'flatten'
img.save(filename=f"{output_dir}/page_{i+1:04d}.jpg")
return len(images)
# PSD → PNG слоёв
with Image(filename='design.psd') as psd:
for i, layer in enumerate(psd.sequence):
with Image(layer) as l:
l.format = 'png'
l.save(filename=f"layer_{i}.png")
Настройка политики безопасности
ImageMagick по умолчанию имеет жёсткие ограничения в /etc/ImageMagick-6/policy.xml. PDF-конвертация часто заблокирована:
<!-- /etc/ImageMagick-6/policy.xml -->
<policymap>
<!-- Ограничения ресурсов -->
<policy domain="resource" name="memory" value="512MiB"/>
<policy domain="resource" name="map" value="1GiB"/>
<policy domain="resource" name="width" value="16KP"/>
<policy domain="resource" name="height" value="16KP"/>
<policy domain="resource" name="area" value="128MP"/>
<policy domain="resource" name="disk" value="2GiB"/>
<policy domain="resource" name="time" value="120"/>
<!-- Разрешить PDF (по умолчанию заблокирован для безопасности) -->
<policy domain="coder" rights="read|write" pattern="PDF"/>
<policy domain="coder" rights="read|write" pattern="LABEL"/>
<!-- Запретить опасные форматы -->
<policy domain="coder" rights="none" pattern="MVG"/>
<policy domain="coder" rights="none" pattern="MSL"/>
<policy domain="delegate" rights="none" pattern="URL"/>
</policymap>
CLI: пакетная обработка
# Конвертация директории в WebP
for f in /uploads/raw/*.jpg; do
convert "$f" \
-auto-orient \
-strip \
-resize '1920x1080>' \
-quality 82 \
"${f%.jpg}.webp"
done
# Параллельная обработка через GNU Parallel
find /uploads/raw -name '*.jpg' | \
parallel -j4 convert {} \
-auto-orient -strip \
-resize '800x600>' \
-quality 82 \
{.}.webp
# Добавить watermark
convert input.jpg \
\( watermark.png -resize 200x -alpha on -evaluate multiply 0.7 \) \
-gravity SouthEast -composite \
output.jpg
Когда выбирать ImageMagick вместо Sharp
| Задача | Sharp | ImageMagick |
|---|---|---|
| JPEG/WebP/AVIF обработка | Лучше (быстрее в 3–5×) | Да |
| PDF → изображение | Нет | Да |
| PSD слои | Нет | Да |
| CMYK → RGB | Нет | Да |
| 200+ форматов | Нет | Да |
| SVG растеризация | Частично | Да |
| Потребление памяти | Низкое | Высокое |
Срок выполнения
Настройка серверной обработки через ImageMagick/Wand с поддержкой PDF и нестандартных форматов — 1–2 рабочих дня.







