Pull to refresh

Наложение текста и картинок на изображение с помощью библиотек MagickWand и GD

Reading time 5 min
Views 20K
MagickWand — одна из библиотек, осуществляющих доступ к пакету программ ImageMagic, для работы с изображениями в PHP. Рассмотрим особенности наложения текста и графики в ней. Говорят, что ImageMagic очень быстрый и дает результат лучшего качества (но не так распространен как GD). За одно проверим это.

Общий код скрипта будет таким:

$new_image = NewMagickWand(); //Создаем экземпляр MagickWand
MagickReadImage($new_image, 'image.png'); //Загружаем в него исходное изображение

$w = MagickGetImageWidth($new_image); //Узнаем его размеры
$h = MagickGetImageHeight($new_image);

/* --- Обработка изображения ---  */

MagickSetImageFormat($new_image, 'jpeg');
MagickWriteImage($new_image, 'newimage.jpeg'); //Сохраняем результат
//
		
ClearMagickWand($new_image); //Удаляем и выгружаем полученное изображение из памяти
DestroyMagickWand($new_image);


Теперь рассмотрим подробнее код обработки изображения. Для примера, наложим текстовый копирайт на фотографию. Это можно сделать несколькими способами:

1. Наложим заранее подготовленное полупрозрачное изображение копирайта с помощью MagickCompositeImage

$watermark = NewMagickWand();		
MagickReadImage($watermark, 'copyright.png'); //Загружаем изображение копирайта
		
$wc = MagickGetImageWidth($watermark);
$hc = MagickGetImageHeight($watermark);
MagickCompositeImage($new_image, $watermark, MW_OverCompositeOp, $w-$wc, $h-$hc); //Накладываем копирайт на исходное изображение

ClearMagickWand($watermark); //Удаляем и выгружаем копирайт из памяти
DestroyMagickWand($watermark);


2. Наложим заранее подготовленное полупрозрачное изображение копирайта с помощью DrawComposite

$watermark = NewMagickWand();		
MagickReadImage($watermark, 'copyright.png');

$watermark_drawing = NewDrawingWand(); //Создаем экземпляр DrawingWand для рисунков
DrawSetGravity($watermark_drawing, MW_SouthEastGravity); //Устанавливаем его расположение в правом нижнем углу
DrawComposite($watermark_drawing, MW_OverCompositeOp, 0, 0, 0, 0, $watermark); //Загружаем в него копирайт
MagickDrawImage($new_image, $watermark_drawing); //Объединяем рисунок с исходным изображением

ClearMagickWand($watermark);
DestroyMagickWand($watermark);
ClearDrawingWand($watermark_drawing);
DestroyDrawingWand($watermark_drawing);

В результате этих двух способов получилось следующее:

image

Время выполнения схоже. В первом случае скачет от 20 до 400мс. Возьмем абстрактное среднее значение 200мс. Во втором случае практически не зависит от величины изображения и других факторов и составило 160мс.

3. Сгенерируем текст копирайта и наложим с помощью MagickAnnotateImage

//Настраиваем текстовое поле	
$watermark_drawing = NewDrawingWand();
DrawSetFont($watermark_drawing, 'copyright.ttf');
DrawSetFontSize($watermark_drawing, 12);
DrawSetGravity($watermark_drawing, MW_NorthWestGravity);

//Задаем его цвет
$pixel_wand = NewPixelWand();
PixelSetColor($pixel_wand, 'black');
PixelSetOpacity($pixel_wand, 0.6);
DrawSetFillColor($watermark_drawing, $pixel_wand);

//Создаем и размещаем на исходном изображении текстовую строку
MagickAnnotateImage($new_image, $watermark_drawing, $w-15, $h-8, -90,' Копирайт');

ClearDrawingWand($watermark_drawing);
DestroyDrawingWand($watermark_drawing);


4. Тоже самое, но с помощью DrawAnnotation

$watermark_drawing = NewDrawingWand();
DrawSetFont($watermark_drawing, 'copyright.ttf');
DrawSetFontSize($watermark_drawing, 12);
DrawSetGravity($watermark_drawing, MW_NorthWestGravity);
DrawRotate($watermark_drawing, -90);

$pixel_wand = NewPixelWand();
PixelSetColor($pixel_wand, 'black');
PixelSetOpacity($pixel_wand, 0.6);
DrawSetFillColor($watermark_drawing, $pixel_wand);
DrawAnnotation($watermark_drawing, 8-$h, $w-15, ' Копирайт'); //Определяем размещение и текст строки.
//Обратите внимание, что после поворота на 90° координаты смещения так же «перевернулись», в отличие от предыдущего варианта

MagickDrawImage($new_image, $watermark_drawing);

ClearDrawingWand($watermark_drawing);
DestroyDrawingWand($watermark_drawing);

В результате этих двух способов получилось следующее:

image

Надпись немного четче, но это скорее свидетельствует, о том, что фотошоп слишком размыл текст в файле-исходнике для первых способов.

По скорости способы идентичны. Время сильно скачет. Для мелких изображений составляет 20мс и доходит до 300мс в 2560×1600. Возьмем среднее значение 150. Опять же абстрактно.

Вывод: Для вставки копирайта с помощью MagickWand лучше всего подойдет способ с DrawComposite. Он универсален (можно вставлять не только текст) и работает предсказуемое время. Исходное изображение для него можно подготовить 3 или 4 способом.

GD Graphics Library с большой вероятностью стоит на любом сервере. В ней то же самое можно сделать так:

list($w, $h) = getimagesize('image.png'); //Узнаем размер исходного изображения
$new_image = imagecreatefrompng('image.png'); //Загружаем исходное изображение

/* --- Обработка изображения ---  */
		
imagejpeg($new_image, 'newimage.jpeg') //Сохраняем
imagedestroy($new_image);


1. С помощью подготовленного изображения

list($cw, $ch) = getimagesize('copyright.png');
$watermark = imagecreatefrompng('copyright.png');

imagecopy($new_image, $watermark, $w-$cw, $h-$ch, 0, 0, $cw, $ch); //Накладываем копирайт
imagedestroy($watermark); //Очищаем память


image

2. Генерация текста средствами GD

$color = imagecolorallocatealpha($new_image, 0, 0, 0, 60); //Устанавливаем черный цвет с прозрачностью 60%
imagettftext($new_image, 10, 90, $w-7, $h-12, $color, 'copyright.ttf', ' Копирайт'); //Создаем текстовую строку и размещаем на исходном изображении


image

Время работы в первом случае составило от 0,2 до 0,7 мс в зависимости от размера изображения, во втором — на 30% дольше.

Признаться, сам удивился, когда увидел, что GD работает чуть ли не в 1000 раз быстрее. Правда, замерял именно алгоритм обработки изображения, без открытий, сохранений и конвертаций в другой формат. Так же не учитывал объем занимаемой памяти, поэтому данные мало подходят для практического применения. Замер производительности целых функций с разными типами файлов показал, что на мелких файлах GD работает до 10 раз быстрее. Наиболее распространенные размеры (3–8 мегапикселей) библиотеки обрабатывают с одинаковой скоростью (справедливо только для моего хостинга). MagickWand (ImageMagic) любят за лучшее качество масштабирования. Опять же это справедливо только для сложных фотографий. Четкие контуры MW слишком размывает

image image

Интересно, что вес такого png-изображения (справа) получился 1,2 КБ против 6 КБ у GD. А все от того, что GD не догадался поменять палитру на 8-битную.

Так что проверяйте скорость на своем хостинге (я тестировал на МакХосте), выбирайте качество исходя из ваших нужд и после этого отдавайте предпочтение той или иной библиотеке, а лучше подкиньте монетку ;-)

Бонус
Немного о настройках качества

В MagickWand настройки качества задаются перед сохранением

MagickSetImageCompressionQuality($new_image, $quality);
MagickSetImageFormat($new_image, 'jpeg');
MagickWriteImage($new_image, 'newimage.jpeg'); //Сохраняем результат

Здесь $quality степнь сжатия от 0–100 для jpeg и 0–80 для png. На gif не влияет.
для jpeg:
0, null — сжатие по умолчанию ~85
1..100 — градация от ужасного качества до идеального

для png, т. к. это формат без потери качества, влияет только на вес картинки и, соответственно, время ее обработки сервером:
0, null — сжатие по умолчанию самое высокое (в этом случае вес картинки минимален)
1­­..80 — градация от низкой до высокой степени сжатия (но наибольшее сжатие при 0)

Еще в MagickWand можно указать вид компрессии, но в случае с jpeg, png, gif он ни на что не влияет.
MagickSetImageCompression($image, MW_JPEGCompression);

В GD качество настраивается в сохраняющих функциях

imagejpeg($new_image, 'newimage.jpeg', $quality)
imagepng($new_image, 'newimage.png', $quality)
imagegif($new_image, 'newimage.gif') //gif так же обделили

Здесь $quality степнь сжатия от 0–100 для jpeg и 0–9 для png.
Для jpeg:
null — сжатие по умолчанию 75
0..100 — градация от ужасного качества до идеального. Практически совпадает с MagickWand

для png:
null — сжатие по умолчанию 0 (плохое сжатие)
0­­..9 — градация от низкой до высокой степени сжатия. При значение 9 вес картинки получается примерно такой как при 0 в MagickWand
Tags:
Hubs:
-1
Comments 16
Comments Comments 16

Articles