Генератор композитных изображений

Категория: Решение задач | Скилл: php | Дата: 09.03.2020

Задача

В примере, файл изображения (sample.jpg) и его название файла (sample) были вставлены в изображение

На работе попросили обработать (в графическом редакторе) около 100 фотографии моделей для производства следующим образом:

  • создать белый фон (как выяснилось позже 1500х1000 пикселей)
  • в нижнюю часть поместить файл изображения модели (оставив вверху место для текста)
  • поместить текст из имени файла вверх изображения
Естественно такая рутинная работа меня не радовала, и вспомнив свой прошлый опыт работы с библиотекой gd на php я решил написать скрипт, который сделает все сам ;)

В итоге появился репозиторий https://github.com/Byurrer/gen-composite-image размером около 200 строк кода :)

Решение

Скрипт имеет настройки для кастомизации данных и комментарии, там все просто.

При запуске скрипт:

  • сканирует текущую директорию на наличие в ней файлов с нужным расширением (jpg),
  • создает изображение помещая в него:
    • файл изображения модели (с масштабированием)
    • текст из имени файла
  • сохраняет итоговое изображение (имя и расширение как у исходного файла) в директорию с аналогичным именем текущей директории добавляя постфикс _2
В ходе разработки были интересные моменты, но наибольшую ценность представляют функции ContainText и CreateImg.

Умещение текста в ограниченную область

ContainText умещает текст в ограниченную область при помощи разбиения текста на строки и уменьшения размера шрифта.

В примере ниже бесконечный цикл, который проверяет помещается ли текст в указанные размеры, если нет тогда размер шрифта уменьшается, проводится повторная аналогичная проверка (на текущей итерации), и если опять нет тогда текст разбивается на строки. Если на следующей итерации текст будет умещен в пределы, тогда цикл будет завершен:

//! вместить текст sText размером iSize (может уменьшаться функцией) в размер iWidth и iHeight
function ContainText($sText, $iWidth, $iHeight, &$iSize, $sFont)
{
	$aText = explode(" ", $sText);
	$sStr = $sText;
  
  while(1)
  {
    $aBox = imagettfbbox($iSize, 0, $sFont, $sStr);

    if($aBox[2] > $iWidth || $aBox[3] > $iHeight)
    {
      $iSize *= FONT_SCALE;

      $aBox = imagettfbbox($iSize, 0, $sFont, $sStr);

      if($aBox[2] > $iWidth || $aBox[3] > $iHeight)
      {
        $sStr = "";
        $sStr2 = "";
        foreach($aText as $sWord)
        {
          $sStr2 = $sStr2.' '.$sWord;
          $aBox = imagettfbbox($iSize, 0, $sFont, $sStr2);
          
          if($aBox[2] > $iWidth)
          {
            $sStr .= "\n".$sWord;
            $sStr2 = $sStr;
          }
          else
            $sStr = $sStr2;
        }
      }
    }
    else
      break;
  }

  return $sStr;
}

Расчет коэффициента масштабирования

CreateImg создает композитное изображение, но самое интересное здесь - расчет коэффициента масштабирования вставляемого изображения. На это ушло много времени, но разбор на логические составляющие помог все упростить. Как оказалось все просто:

  • сначала необходимо вычислить коэффициенты разницы размеров:
$iWdiff = $vSizeSrc[0] / IMG_WIDTH;
$iHdiff = $vSizeSrc[1] / $sHeight2;

  • затем определить наибольший коэффициент разницы и вычислить итоговый коэффициент масштабирования вставляемого изображения:
if($iWdiff > $iHdiff)
  $fCoef = IMG_WIDTH / $vSizeSrc[0];
else if($iHdiff > $iWdiff)
  $fCoef = $sHeight2 / $vSizeSrc[1];

Результат

На разработку, тест и отладку скрипта (а так же на оформление репозитория), ушло в общей сложности 2 часа. Скрипт обрабатывает каждое изображение в пределах секунды.

На решение задачи ручной обработкой изображений потребовалось бы примерно столько же времени. Однако, теперь процесс автоматизирован и в следующий раз на решение задачи потребуется в несклько раз меньше времени :)
Я Виталий, ник в сети Byurrer.
Увлекаюсь программированием, веду интересные проекты, пишу здесь об интересующих меня вещах: о работе, проектах, увлечениях и проффесиональном развитии.
Мое резюме

Проекты
SkyXEngine, PHP-API, S4G
Категории
В разработке :)
Популярное
В разработке :)