Аватары без искажений

Уже поднималась тема про искажения в аватарах, возникающие, если исходная картинка не квадратная. Что-то мне это сильно не нравилось, и решил я это исправить.

Ниже даю решение, как создавать квадратные аватары из неквадратных картинок.
«Оквадрачивание» возможно по одному из трех алгоритмов (на выбор):

1) Пропорциональное уменьшение картинки по бОльшей стороне и вписывание ее квадрат. На выходе имеем квадратную аватару, но само изображение уменьшается пропорционально и не искажается.

2) Пропорциональное уменьшение по максимальной стороне.

3) Пропорциональное уменьшение по минимальной стороне.

4) Уменьшение с обрезкой: сначала выполняется п.2, а потом выполняется обрезка: если W>H, то обрезка по бокам, если W<H, то обрезка снизу.

Теперь сам код. Чтобы не ломать файл с системными функциями, создаем в папке include свой файл, в котором прописываем такую функцию:


<?php

define('IMG_RESIZE_FIT', 0); // вписывание в квадрат (уменьшение по максимальной стороне)
define('IMG_RESIZE_MAX', 1); // уменьшение по максимальной стороне
define('IMG_RESIZE_MIN', 2); // уменьшение по минимальной стороне
define('IMG_RESIZE_CROP', 3); // обрезка исходной картинки: 
                              // если W>H, то обрезка по бокам, если W<H, то снизу

function func_img_avatar($sFileSrc, $sDirDest, $sFileDest, $iWidthMax, $iHeightMax, 
                         $iWidthDest=null, $iHeightDest=null, $iResizeMode=0) {
  if (!($aSize=getimagesize($sFileSrc))) {		
    return false;
  }	
  $img_src=false;
  switch ($aSize['mime']) {
    case 'image/png':
      $img_src=imagecreatefrompng($sFileSrc);
      $sFileDest.='.png';
      break;
    case 'image/gif':
      $img_src=imagecreatefromgif($sFileSrc);
      $sFileDest.='.gif';
      break;
    case 'image/jpeg':
      $img_src=imagecreatefromjpeg($sFileSrc);
      $sFileDest.='.jpg';
      break;
    default:
      return false;
      break;
  }
  if (!$img_src) {		
    return false;
  }
  if (($aSize[0]>$iWidthMax) or ($aSize[1]>$iHeightMax)) {
    return false;
  }

  if ($iWidthDest) {$iScaleW=$iWidthDest/$aSize[0];} else {$iScaleW=1;}
  if ($iHeightDest) {$iScaleH=$iHeightDest/$aSize[1];} else {$iScaleH=1;}

  if ($iResizeMode==IMG_RESIZE_MAX) {
    $iSizeRelation=(($iScaleW<$iScaleH)?$iScaleW:$iScaleH);
    $iWidthNew=round($aSize[0]*$iSizeRelation);
    $iHeightNew=round($aSize[1]*$iSizeRelation);
  
    $iSizeW=$iWidthNew;
    $iSizeH=$iHeightNew;
    $iDestX=0;
    $iDestY=0;
  } elseif ($iResizeMode==IMG_RESIZE_MIN) {
    $iSizeRelation=(($iScaleW>$iScaleH)?$iScaleW:$iScaleH);
    $iWidthNew=round($aSize[0]*$iSizeRelation);
    $iHeightNew=round($aSize[1]*$iSizeRelation);
  
    $iSizeW=$iWidthNew;
    $iSizeH=$iHeightNew;
    $iDestX=0;
    $iDestY=0;
  } elseif ($iResizeMode==IMG_RESIZE_CROP) {
    $iSizeRelation=(($iScaleW>$iScaleH)?$iScaleW:$iScaleH);
    $iWidthNew=round($aSize[0]*$iSizeRelation);
    $iHeightNew=round($aSize[1]*$iSizeRelation);
  
    $iSizeH=$iSizeW=(($iWidthNew<$iHeightNew)?$iWidthNew:$iHeightNew);
    $iDestX=round(($iSizeW-$iWidthNew)/2);
    $iDestY=0;
  } else {
    $iSizeRelation=(($iScaleW<$iScaleH)?$iScaleW:$iScaleH);
    $iWidthNew=round($aSize[0]*$iSizeRelation);
    $iHeightNew=round($aSize[1]*$iSizeRelation);
  
    $iSizeH=$iSizeW=(($iWidthNew>$iHeightNew)?$iWidthNew:$iHeightNew);
    $iDestX=round(($iSizeW-$iWidthNew)/2);
    $iDestY=round(($iSizeH-$iHeightNew)/2);
  }

  $sFileFullPath=DIR_SERVER_ROOT.'/'.$sDirDest.'/'.$sFileDest;
  @func_mkdir(DIR_SERVER_ROOT,$sDirDest);
  if ($iWidthDest and $iWidthDest!=$aSize[0]) {
    $img_dest=imagecreatetruecolor($iSizeW,$iSizeH);		
    imagesavealpha($img_dest,true);
    imagealphablending($img_dest,false);
    if (imagecopyresampled($img_dest, $img_src, $iDestX, $iDestY, 0, 0, 
                           $iWidthNew, $iHeightNew, $aSize[0], $aSize[1])) {
      imagedestroy($img_src);
      switch ($aSize['mime']) {
        case 'image/png':
          if (imagepng($img_dest,$sFileFullPath)) {
            chmod($sFileFullPath,0666);
          }
          break;
        case 'image/gif':
          if (imagegif($img_dest,$sFileFullPath)) {
            chmod($sFileFullPath,0666);
          }
          break;
        case 'image/jpeg':
          if (imagejpeg($img_dest,$sFileFullPath)) {
            chmod($sFileFullPath,0666);
          }
          break;
        }
      imagedestroy($img_dest);
      return $sFileDest;
    }
  } else {
    if (copy($sFileSrc,$sFileFullPath)) {
      return $sFileDest;
    }
  }
  return false;
}
?>


В файле ActionSettings.class.php в методе protected function EventProfile() вызовы функций func_img_resize при загрузке аватар меняем на func_img_avatar.

Все!

UPD Внимание! Уже залитые аватары никуда не денутся и автоматически не изменятся! Их можно исправить только повторной заливкой!

44 комментария

avatar
Забыл добавить: режим сжатия надо выбрать самому и указать при вызове ф-ции (последний параметр). В идеале, конечно, было б хорошо, если б, юзер при загрузке в интерактиве выбирал. Но с этим чуть дольше повозиться надо, может, и сделаю потом.
avatar
День добрый!
Подскажите пожалуйста работает ли эта метода для 0.31 версии?
avatar
Не вижу причин, почему она не должна работать
avatar
Что бы не плодить новых постов по данной теме отпишу здесь:
решал ли кто-либо вопрос с аватарами, поблема в том, что при масштабировании картинки дико искажаются.
avatar
А топик почитать не пробовал?
avatar
может я чего то не понимаю, но насколько можно уловить из этого фрагмента
Ниже даю решение, как создавать квадратные аватары из неквадратных картинок.
«Оквадрачивание» возможно по одному из трех алгоритмов (на выбор):

речь идет про работу с неквадратными картинками, я же говорю про кривое масштабирвание и квадратных аватаров тоже
avatar
Не замечал, что квадратные картинки криво масштабируются
Они делаются неквадратными?
avatar
Кажется, я понял о чем речь. Из загружаемой картинки создается четыре аватары — 24х24, 48х48, 64х64, 100х100. Если размер загружаемой картинки меньше, чем 100х100, то она будет растягиваться. И тут уже ничего не поделаешь, потому что при растягивании искажения, как правило, заметней, чем при сжатии. Поэтому рекомендуется загружать аватару размером не менее 100х100
avatar
Отлично. Переносите в Tips&Tricks, когда сможете.
Карму уже когда-то плюсовал — больше не могу.
avatar
Прибавил вам карму слегка ;-)
Этот топик надо в Tips&Tricks :-)
avatar
Только код под кат спрячьте :)
avatar
Что-то и после установки у меня аватары корявые
avatar
Те, которые уже были — они останутся корявые и никуда не денутся. Процесс трансформации ведь в процессе заливки на сайт происходит
avatar
Я о другом. Удаляю аватар. Сохраняю. Загружаю новый. И снова искаженный. Может я что-то с настройками не понял?
avatar
Хм, не знаю. У меня работает без проблем.
Еще рах кратко порядок действий:
1. В папке include создаем файл, скажем, my_function.php с функцией func_img_avatar, которая описана выше.
2. В файле ActionSettings.class.php в методе protected function EventProfile() вызовы функций func_img_resize меняем на func_img_avatar.

Больше ничего настраивать не надо, все должно работать
avatar
Сделал всё. И поменял func_img_resize на func_img_avatar. Всё работает, аватар грузит и уменьшает, но непропорционально как и было.
avatar
Тогда не понимаю. А проверял — при удалении действительно файлы с аватарой удаляются из папки? При загрузке — действительно пишутся файлы? Пробовал вновь созданные аватары скачать и посмотреть — с искажениями? Выводятся те файлы, что нужно? Может, в путях что-то не то?
avatar
Все отлично. Само заработало :-) Может где-то в кэше сидело. Спасибо.
avatar
Здравствуйте! Всё делаю, как советуете, но получаю вот что:

www.avtoturistu.ru/uploads/problem.JPG

Что не так делаю? Спасибо!
avatar
Такое впечатление, что файл с доп. функцией не оформлен, как пхп-скрипт
avatar
Ну я просто в папке includes рядышком с functions.php создал blablabla.php По крайней мере, я понял, что надо делать так… Прав ли я?
avatar
А с php вообще хоть чуть-чуть знакомы? Надеюсь, знаете, что php-скрипты должны заключаться в теги <?php и ?>. На всякий случай уточню: первый тег должен быть в самом начале файла, а второй — в самом конце.
avatar
Почему–то мне кажется, что следующим будет вопрос с ошибкой парсера аля
unexpected '{'
На всякий случай скажу, что чтобы этого не было, нужно в указанном коде перед func_img_avatar вставить function, т.е. должно получиться вот так
function func_img_avatar

avadim, может быть проще исправить пост, чтобы не было таких вопросов? Сразу указать что нужно вставить в новый файл и все — новичкам будет проще :)
avatar
Дельный совет, сделал.
Вот теперь кусок кода, как есть, можно вставлять в файл
avatar
Благодарю! С php знаком примерно также, как с балетом)))
avatar
Спасибо, всё работает на ура!!!
залил аватарку формата *.gif (не анимация) на локалхост — получил чёрные полоски справа и слева :(, первоначальный размер аватары был 82х100

С наилучшими пожеланиями
avatar
define('IMG_RESIZE_FIT', 0); // вписывание в квадрат (уменьшение по максимальной стороне)
define('IMG_RESIZE_MAX', 1); // уменьшение по максимальной стороне
define('IMG_RESIZE_MIN', 2); // уменьшение по минимальной стороне
define('IMG_RESIZE_CROP', 3); // обрезка исходной картинки: 
                              // если W>H, то обрезка по бокам, если W<H, то снизу

function func_img_avatar($sFileSrc, $sDirDest, $sFileDest, $iWidthMax, $iHeightMax, 
                         $iWidthDest=null, $iHeightDest=null, $iResizeMode=0)

Играешь с последним параметром $iResizeMode. Можно прямо в описание функции воткнуть, напр., так:
function func_img_avatar(..., $iResizeMode=1)
Будет пропорциональное уменьшение по максимальной стороне.
avatar
avadim, да спасибо, поставил 1 — всё заработало как надо!

спасибо, фокусник :)
avatar
Подскажите, пожалуйста, а как сделать чтобы это работало на другие размеры изображения?
  • qoox
  • 0
avatar
На какие «на другие»? Нужный размер передается в аргументах функции. Какой задан, такой и делается.
avatar
Просто попытался применить этот метод к «Делаем превьюшку к топику» (http://livestreet.ru/blog/tips_and_tricks/747.html), но т.к. я не программист, делал это наугад. Вроде получается, но картинка уменьшается до 200х200.
Поэтому и возник такой вопрос.
avatar
Так я же говорю: если используется функция, приведенная выше, то изображение уменьшается до размеров, которые передаются в параметрах. Если не знаете, что такое «функция», «параметры», как они передаются и т.д., то сюда: livestreet.ru/blog/1939.html
avatar
Я понял, но передается размер 300х200, а он режет, в зависимости от размеров, загружаемого изображения. Но минимум 300х225
avatar
спасибо. вроде работает )
avatar
А вот и замечание, причем существенное.
Сейчас почти нет времени расписать нормально, НО!
Рассмотрим все 4 варианта уменьшения изображений:
1. после ресайза она станет квадратной, да только с черными полосами по бокам (если начальное изображение было не квадратным)
2,3. изображение уменьшается, но не становится квадратным — все аватары будут разными по ширине.
4. из всего загруженного изображения вырезается средняя часть размера 100 на 100 и потом она ресайзится.

На данный момент лучший вариант — п.4 — получается квадрат без каких либо черных полос по-бокам. Но!

п.4. так же не до конца верен, потому как если взять картинку 200х600, на который я в полный рост, то после ресайза на аватаре будет область промежности, что конечно удручает.

Есть выход! Какой?
avatar
последние 2 абзаца не читайте — хрень написал.
п.4 — самый приемлемый
avatar
Вы под п.4 вы имеете ввиду — define('IMG_RESIZE_CROP', 3);?
Я код не разбирал, но на деле получилась не средняя облвсть, а кроп сверху:
1) Ресайз по ширине до 100px,
2) Кроп сверху вниз на 100px.
Там обычно лицо.

Автору спасибо.
avatar
да. последний.
мне кажется там рес до 100, а потом вырез середины, а не сверху.
автору, бесспорно, спасибо
avatar
конечно есть выход. по пункту 2 и 3, заключить все аватарки в квадратный блок и выровнять по центру… помоему это очевидное решение. а вот упихивать всё в квадрат — это совершенно невменяемо и глупо, а если я на фотке к верху ногами, зачем мне на обрезанной фотографии мои пятки?
avatar
>а вот упихивать всё в квадрат…
Ответ прост и банален — верстка практически всех шаблонов предусматривает квадратные аватары. А писать софт, который будет автоматом распознавать на фотке лицо и именно его вырезать для аватары, это отдельная задача для системы программного распознавания образов. :)
avatar
поэтому я двумя руками и ногой за второй и третий варианты. а добавить лишний блок с выравниванием по центру… ну не знаю, дело 35 секунд мне и часа, тому кто не знаком с хтмл вообще
avatar
кстати у себя на проекте, я вообще аватары отключил =) нафига они нужны?
avatar
Я, народ, где видимо ошибся.
Почему у меня высокие картинки ресайзятся до 100*100 (метод IMG_RESIZE_CROP), а широкие до 67*67?
Входными параметрами я говорю сделать рес. до 100*100 в любом случае.
avatar
Помогите пожалуйста!!!
livestreet.ru/blog/16608.html
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.