ResizeImageGet и простой водяной знак налету

  • ResizeImageGet и простой водяной знак налету

    Антон Долганин 9 Августа 2016 16:45 23619
    Сегодня поговорим о том как проще всего воткнуть водяной знак на картинки в Битрикс. Например, на все изображения каталога.

    Полной автоматики получить не удалось, хотя есть зацепки, но об этом ниже.

    Итак, за основу я взял метод ResizeImageGet. Почему? Потому что именно он делает копию картинки, а не воздействует на оригинал. И именно он внутри себя обращается к методу CFile::ResizeImageFile, который уже может наложить водяной знак.

    Для начала создаем класс с одним статическим методом:
    class CFileWater extends CAllFile
    {
       public static $watermark = array(
                   'position' => 'mc',//допустимые http://prntscr.com/c3hc9i
                   'type' => 'file',
                   'size' => 'real',
                   'alpha_level' => 100,//прозрачность
                   'file' => '/upload/watermark.png',
                ); 
    }


    Параметр fill может быть равен resize, тогда размер ватемарка расчитывается на основании значения coefficient
    $wmWidth = round($Params["width"] * $Params["coefficient"]);
    $wmHeight = round($Params["height"] * $Params["coefficient"]);


    иначе, значение может быть repeat, тогда размер не меняется и производится заполнение всего изображения ватемарком

    Собственно, это и будет ваш класс для применения вотермарка. В нем указаны настройки, которыми можно крутить для знака.

    Затем идем в /bitrix/modules/main/classes/general/file.php и находим там метод ResizeImageGet. Копируем его как есть и вставляем в ваш метод. Я намеренно не прикладываю здесь готовых файлов, потому что данный метод может довольно часто меняться, и через пару версий уже быть совершенно иным.

    Вставили метод, теперь работаем с ВАШИМ классом, в ядре ничего не меняем. Сразу скажу,  что вы можете менять его как угодно, какие угодно параметры добавлять, но я шел по пути минимального вмешательства.

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

    Screenshot_3.png

    Затем находим еще блок кода непосредственно перед ресайзом копии.

    Screenshot_5.png

    И туда сверху вставляем данные пару строк:
    $arWatermark = self::$watermark;
    $arWatermark['file'] = $_SERVER['DOCUMENT_ROOT'].$arWatermark['file']; 


    А где вторым прямоугольником отмечено, мы заменяем array() на ваш новый массив. Это и есть применение вотермарка и собственно все танцы с бубном ради него.  И вот теперь об автоматике. Если вы взглянете в коде еще выше, то увидите там обработку события OnBeforeResizeImage. И вот его можно научить принимать переменные по ссылке, и дополнить его передачей параметра вотермарка. Тогда все это можно было бы менять в обработчике. Очень маленькая мелочь, и я надеюсь ее Битрикс сделает рано или поздно.

    По сути все, теперь как применять. Ну во-первых, если у вас уже используется ResizeImageGet, вы можете просто заменить в коде вызов CFile::ResizeImageGet на CFileWater::ResizeImageGet и все будет работать.

    Теперь о том, почему я настройки знака вынес в отдельную переменную. А чтобы для разных вариантов подбрасывать разные водяные знаки.
    Например:
    CFileWater::$watermark['position'] = 'br';
    CFileWater::$watermark['file'] = CFileWater::$watermark['file_small'];
    $arOfferPicture = CFileWater::ResizeImageGet($iOfferPicture,
       array('width' => 250, 'height' => 250),
       BX_RESIZE_IMAGE_PROPORTIONAL_ALT);
     


    Вот и все!
Иван
11 Августа 2016 12:31
Хороший метод, получается CFileWater::ResizeImageGet нужно применять в template.php секции товаров и в карточке товара?  
Антон Долганин
11 Августа 2016 13:09
Проще всего да - по факту вывода в шаблоне. Но никто не мешает там в result_modifer перенести, или в свой компонент.
Иван
12 Августа 2016 7:06
спасибо! Все получилось , запилить )
Игорь
18 Августа 2016 10:50
Спасибо, интересно!
У меня правда первая мысль была обратиться к одному из обработчиков OnAfterResizeImage/OnBeforeResizeImage, но нужно проверить. Не рассматривали этот подход? Почему отказались? Из-за лишней операции перезаписи или эти события не сработают при нормальных размерах картинки, т.е. без фактического ресайза?
Антон Долганин
18 Августа 2016 11:05
А я про это упомянул - начиная со слов "И вот теперь об автоматике". Пока не хватает данных для обработчика.
Олег
27 Августа 2016 0:13
Антон, извините за оффтоп, а как вы вставки кода оформляете, как доработли битриксовый визивиг?
Антон Долганин
27 Августа 2016 5:13
Олег, речь про тег CODE? Библиотека highlight.js, в футере страницы ее подключение видно. Ее же юзает Битрикс в своих онлайн-курсах.
Олег
27 Августа 2016 12:46
Да-да, но я про визивиг, вы кнопку свою в визивиг добавляли? Там же <pre><code class="php"> вставлять надо или вроде такого...
Или всё в режиме html пишете? :)
Антон Долганин
27 Августа 2016 19:32
А это просто в шаблоне реплейсом заменяется CODE на нужные теги, и все.
Редактор не трогал. Сапожник без сапог :)
Евгений
21 Сентября 2016 11:55
При таком подходе (если применять наложение ко всем изображениям элемента) в том случае, когда в инфоблоке 20 тыс. элементов и у каждого по 10 фото, вашему жесткому диску я не сильно позавидую...

Ресайзить и наносить ватермарки надо только в момент создания элементов, а не потом, при выводе на странице. Мы так делали — заливали номенклатуру товаров из 1С, а потом ресайзили "налету", как результат  50Гиговая папка с сайтом...  
Антон Долганин
21 Сентября 2016 13:12
Мы так делали
Я вот не понял - вы себя этим сео то ли подняли, то ли оскорбили :)

Ресайзить и наносить ватермарки надо только в момент создания элементов
И так вы убьете оригинал картинки.
Евгений
21 Сентября 2016 14:53
А так вы сначала набьете папки сайта оригиналами картинок, а потом еще и сресайзенными и заватермарченными копиями.  

Модераторы 1С еще имеют обыкновение добавлять к товарам фото по несколько Мб каждая и все это с импортом вы предлагаете влить на сайт?

Дело Ваше, но я бы так не делал) А ссылка, чтобы не представляться (и в то же время может кому то будет интересно, кто у Долганина в посте "умничает")
Антон Долганин
21 Сентября 2016 14:58
Не, зерно правды в ваших словах есть, просто большинству сайтов не надо париться с дублями картинок - их не так много.
Для большого проекта ваш путь вернее само собой. Только я оригиналы все равно сохранял бы, хотя бы постингов на какой-нить свой фтп, пусть лежат.

А в целом я вообще против водяных знаков.
Юрий
5 Октября 2016 13:00
Тут по сути вопрос стоит "нужно ли вам сохранять оригиналы изображений?", отресайзенные до веб-размеров, много гигабайт не займу (иначе просто жаль посетителей).
Кому нужно (например чтобы спустя время без перезаливки всего - под ретину подстроиться) - то вариант с сохранением оригиналов - очень даже очень. Да и об импорте тут речи нет.
Марк
9 Марта 2017 23:32
Годный вариант.
Ребята не понятно к чему пристали в комментариях - вам показали способ, как решить конкретную задачу. Это же не руководство, как надо делать на любом проекте. Хотите храните оригиналы, хотите не храните. Все просто :)
Леонид
7 Сентября 2017 16:46
Никак не пойму, чем стандартный вотермарк не угодил? Только если на момент публикации статьи его не было, хотя, насколько я помню, это не так.
И зачем комментировать строки, если при наличии фильтра(а вотермарка, как раз оно и есть) он всё равно его применит?
Антон Долганин
7 Сентября 2017 17:26
Леонид, ключевое - "на лету", то есть оригинал не страдает, и не надо перегенерировать каталог. Если какой-то такой же штатный функционал есть (я не  про сам вотермарк), то раньше его точно не было.
Леонид
7 Сентября 2017 18:02
Вотермарки вроде появились в ResizeImageGet ещё в 11 версии битрикса. (да что там, вы сами используете этот функционал, учитывая копирование практически без изменений этого самого метода)
И ваш код:
CFileWater::$watermark['position'] = 'br';
CFileWater::$watermark['file'] = CFileWater::$watermark['file_small'];
$arOfferPicture = CFileWater::ResizeImageGet($iOfferPicture,   array('width' => 250, 'height' => 250),   BX_RESIZE_IMAGE_PROPORTIONAL_ALT);

Можно было бы заменить на:
$watermark = array(
   array(
               'position' => 'br',
               'type' => 'file',
               'size' => 'real',
               'alpha_level' => 100,
               'file' => '/upload/watermark.png',
   )
); 
$arOfferPicture = CFile::ResizeImageGet($iOfferPicture,   array('width' => 250, 'height' => 250),   BX_RESIZE_IMAGE_PROPORTIONAL_ALT, false, $watermark);

Да, вызов получается подлиннее. Зато не надо создавать свой класс, не надо ничего копировать из ядра. И всё так же работает "на лету", оригинал не страдает.
К сожалению, не могу проверить было ли всё так, на момент написания статьи, самая старая версия битрикса у меня на руках 14.5, от 6.12.16. А там уже всё работает, как и сейчас. А именно вот так:

if(is_array($arFilters))
 {
    foreach($arFilters as $arFilter)
    $bNeedCreatePicture |= CFile::ApplyImageFilter($picture, $arFilter, $bHasAlpha);
}
if(is_array($arWaterMark))
{
   $arWaterMark["name"] = "watermark";
   $bNeedCreatePicture |= CFile::ApplyImageFilter($picture, $arWaterMark, $bHasAlpha);
}
Что значит, нет никакой разницы, добавлять вотермарку через $arFilters в ResizeImageGet или через $arWatermark в ResizeImageFile.
ааааа
14 Января 2020 9:05
Аааааа такое адище расказано
я почти уверен что даже в битриксе есть правильные пути, этот путь вообще на уровне "я закончил универ, я прафесианальный кодир"
Антон Долганин
14 Января 2020 11:29
я почти уверен что даже в битриксе есть правильные пути
Так может быть сначала убедитесь? А пока вы рассуждаете на уровне поступающих в прафесианальную шарагу.
BXwork
16 Января 2020 16:30
Может пойдешь работать в Битрикс и реализуешь правильные пути?!  (которых на данный момент нет)