Как стать автором
Обновить

MagickWand — тени и скругленные углы

Время на прочтение 4 мин
Количество просмотров 1.4K
Навеяно топиком хабраюзера apelsyn Фотошопим на PHP
Я взялся за написание движка для сервиса открыток — для знакомых, бесплатно. Такая работа хороша тем, что можно ставить эксперименты и в процессе что-то новое и интересное узнавать — благо никто не может торопить и напоминать о сроках.
В этой работе впервые мне пришлось столкнутся с интерфейсом к ImageMagick под названием MagickWand
Как делать превьюшки я разобрался быстро, несмотря на то, что документация, мягко говоря, очень лаконичная. Так же практически не вызвало вопросов добавление надписей и фонов к картинке.
Но душа хотела прекрасного.
В частности, закругленных уголочков и теней под превьюшками.
Я знал, что таки вещи делать можно, но вся загвоздка в том, что в упомянутом посте все делалось с помощью Imagick, а у меня-то уже стояла MagickWand! Гугл, хабр и тематические блоги ничего не дали, поэтому пришлось изобретать велосипед самостоятельно.
После некоторых проблем, непродолжительного битья головой о стену и экспериментов с режимами наложения изображений в MagickWand родилось .

<?php
$img = '../images/card1.jpg'; //исходный файл
$card=NewMagickWand();
MagickReadImage($card, $img); //создаем ресурс MagickWand
$card = MagickTransformImage($card, NULL, 'x190'); //делаем превьюшку

// Круглые уголочки

$pr_width = MagickGetImageWidth($card); //взяли ширину
$pr_height = MagickGetImageHeight($card); //взяли высоту

$black=NewPixelWand();
PixelSetColor($black, "#000000"); // новый PixelWand ресурс - черный цвет. Понадобится для закрашивания прямоугольника со скругленными уголочками

$rounded=NewDrawingWand(); // создаем ресурс для прямоугольника с круглыми уголками
DrawSetFillColor($rounded, $black); // заливка
DrawSetFillAlpha($rounded, 1); //Альфа-канал (прозрачность), 0 - полностью прозрачный, 1 - полностью непрозрачный
DrawRoundRectangle($rounded, 3, 3, $pr_width-6, $pr_height-6, 15, 15); //рисуем прямоугольник

$border=NewMagickWand(); // новый ресурс, белая картинка размером ровно с превьюшку
MagickNewImage($border, $pr_width, $pr_height, "#ffffff"); //создали картинку
MagickSetImageFormat($border, 'png'); //задали формат

MagickDrawImage($border, $rounded); //нарисовали на картинке прямоугольник с круглыми уголками

// ---------- здесь начинается магия режимов наложения ---------------- //
MagickCompositeImage($card, $border, MW_BlendCompositeOp, 0, 0); //наложили наш белый прямоугольник с нарисованным в нем черным с закругленными углами на исходную картинку, Режим наложения - MW_BlendCompositeOp (это важно)
// ------------ ----------------- ----------------- ----------------- ---------------- //
//рамка на картинку
$border_c=NewPixelWand(); // ресурс для цвета рамки
PixelSetColor($border_c,"#eeeeee"); // задаем будущий цвет

$rounded_b=NewDrawingWand(); // ресурс для рамки
DrawSetStrokeColor($rounded_b, $border_c); // задаем цвет рамки
DrawSetStrokeWidth($rounded_b, 1); // ширина рамки
DrawSetFillOpacity($rounded_b, 0); // Прозрачность фона, в данном случае - полностью прозрачный
DrawRoundRectangle($rounded_b, 3, 3, $pr_width-6, $pr_height-6, 15, 15); // Создаем прямоугольник - рамку
MagickDrawImage($card, $rounded_b); рисуем на картинке нашу рамку

/* Дальше делаем тень */

// Тень
$sh_border=NewMagickWand(); // снова новый ресурс
MagickNewImage($sh_border, $pr_width, $pr_height, "#ffffff"); // белый прямоугольник размером с превьюшку
MagickSetImageFormat($sh_border, 'png');

$sh_color=NewPixelWand(); // ресурс для цвета тени
PixelSetColor($sh_color, "#aaaaaa"); // цвет - серый

$sh_rounded=NewDrawingWand(); // ресурс для прямоугольника со скругленными глами, который потом будет тенью
DrawSetFillColor($sh_rounded, $sh_color); // задали цвет
DrawSetFillAlpha($sh_rounded, 1); // прозрачности - нет
DrawRoundRectangle($sh_rounded, 6, 6, $pr_width-3, $pr_height-3, 15, 15); // нарисовали прямоугольник (обратите внимание на координаты - прямоугольник сдвинут относительно рисунка)

MagickDrawImage($sh_border, $sh_rounded); // наложили прямоугольник на фон
MagickBlurImage($sh_border, 3, 3); // blur (размытие) - чтоб тень была похожа на тень

$sh_fill_color=NewPixelWand(); // ресурс для белого цвета - закрашивать ненужный кусок тени
PixelSetColor($sh_fill_color, "#ffffff"); // задали цвет

$rounded_fill=NewDrawingWand(); // прямоугольник для наложения на тень - отсечь лишнее
DrawSetFillColor($rounded_fill, $sh_fill_color); // задали белый цвет
DrawSetFillAlpha($rounded_fill, 1); // непрозрачный
DrawRoundRectangle($rounded_fill, 3, 3, $pr_width-6, $pr_height-6, 15, 15); // создали прямоугольник - в данном случае на том же месте, что и исходная картинка
MagickDrawImage($sh_border, $rounded_fill); // нарисовали прямоугольник на картинке

MagickCompositeImage($sh_border, $card, MW_MultiplyCompositeOp, 0, 0); // накладываем получившуюся тень на картинку, режим наложения - MW_MultiplyCompositeOp.

header('Content-type: image/jpeg'); // задали контент-тайп

MagickEchoImageBlob($sh_border); // вывели рисунок в браузер

?>

Описание алгоритма действий

Для создания скругленных уголочков мы рисуем прямоугольник размером с нашу картинку (белый), а на нем — несколько меньший прямоугольник со скругленными углами (черный). Получившуюся констркцию склеиваем с исходной картинкой, но с режимом наложения, который отсекает детали изображения, находящиеся под белым цветом и оставляет то, что под черным. Остается та же прямоугольная картинка, но уже с белой рамкой со скругленными уголочками. Потом на картинку рисуем рамку, которая повторяет исходный прямоугольник со скругленными углами.

Для тени точно так же рисуем белую рамку с черным скругленным прямоугольником внутри, который немного сдвинут относительно исходной картинки (той, от которой будет падать тень). Потом белым прямоугольником повторяем исходную картинку. Таким образом, у нас на белом прямоугольнике остается только тот кусочек тени, который нам нужен. Приклеиваем его поверх исходной картинки.

В итоге получаем нечто такое:
image
В дальнейшем я планирую из этого кода сделать функцию, которой можно будет скармливать любые картинки с заданным размером превьюшки, а она будет отдавать же превьюшку с закругленными уголками и тенью. В рамках этого проекта пока такая функция не нужна.
Теги:
Хабы:
+8
Комментарии 8
Комментарии Комментарии 8

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн