Генерация аватарок средствами PHP, глаза



Как и перед авторами недавнего топика, передо мной возник вопрос генерации дефолтных аватаров. Тут же вспомнил о «фрактальных» аватарах.

Основной принцип — генерируем примитивами 1/4 изображения и дублируем с поворотом на 90°. Пробовал сделать свой вариант:


Сорцы
<?php

$w=150;
$h=150;

$cols=4;

$im = imageCreate($w,$h);

$del=1.5;
$mw = $w/$del; $mh = $h/$del;

$c = imageColorAllocate($im, 245, 245, 245);
imagefilledrectangle($im, 0, 0, $w, $h, $c);

$c = array(rand(0,200),rand(0,200),rand(0,200));
for($zz=0;$zz<5;$zz++)
{
$im = createPolgon($im, $w, $h, $mw, $mh,5, $c, 75);
}

header('Content-type: image/jpg');
imagepng($im);
imagedestroy($im);

function createPolgon($image, $width, $height, $mwidth, $mheight, $count, $color, $merge)
{
$img = imageCreate($width,$height);
$c = imageColorAllocate($img, 245, 245, 245);
imagefilledrectangle($img, 0, 0, $width, $height, $c);

for($i=0;$i<$count;$i++)
{
$c = imageColorAllocate($image,$color[0],$color[1],$color[2]);
$cnt=3;
$values=array(rand(0,$mwidth), rand(0,$mheight),rand(0,$mwidth), rand(0,$mheight),rand(0,$mwidth), rand(0,$mheight));
imagefilledpolygon($image, $values, $cnt, $c);
}

$rotate = imagerotate($image, 90, 0);
imagecopymerge($image, $rotate, 0, 0, 0, 0, $width, $height, 50);

$rotate = imagerotate($image, 180, 0);
imagecopymerge($image, $rotate, 0, 0, 0, 0, $width, $height, 50);

imagecopymerge($img, $image, 0, 0, 0, 0, $width, $height, $merge);

return $img;
}



Как и любой дизайнер, «поиграл цветами и формами», но все было не то. Тогда и родилась идея сделать случайно генерируемые лица. Подумывал даже об ан$%е, но вовремя отдумал. В планах была только генерация лиц в стиле «мульт» — с разноцветными глазами, волосами и карикатурными чертами, а после задумался и об аксессуарах — очки, румяна, веснушки и т.д…
На скорую руку набросал мордочки,


и принялся за различные части лица. Начнем с глаз.
Базовая форма для глаза — капля.



В общем-то, эта форма является базовой для многих частей аватарки — ноздри, губы и т.д. Получить ее довольно просто — из параболы. Точнее — из четырех:



Исходный код для половины параболы фиксированного размера
/*
$width, $height - высота, ширина поработы
$quality - обратное качеству
*/
$color = imageColorAllocate($image,45,45,45)
$points = array();
    for($x=0; $x<=$width/2; $x+=$quality)
    {
        $y=($x*$x) / (($width)*($width)) * $height;
        array_push($points, $x, $y);
    }
 imagefilledpolygon($image, $points, count($points)/2, $color);


А imagefilledpolygon заполняет многоугольник выбранным цветом в контуре, заданным массивом точек в декартовой системе координат. Подробнее о рисовании средствами PHP можно почитать здесь.
Делаем тонкую обводку глаза черным цветом. imagepolygon — как раз подходит — обвод многоугольника без заливки.

Обводка, тень от века, тени, белОк.


Зрачок и блики рисуем с помощью imagefilledellipse.

Зрачок, блики.


Кастомизация глаз происхоит с помощью rand

raw source
<?php
/*
Не для слабонервных. Давно бросил пхп, но иногда балуюсь. Данный код - сырое превью.
Новичкам  - лучше вообще не смотреть.
*/
$Width=500;
$Height=300;
$img =  imageCreate($Width,$Height);
$r = rand(5,200);$g = rand(5,200);$b = rand(5,200);
$c = imageColorAllocate($img, 255,255,255);
imagefilledrectangle($img, 0, 0, $Width, $Height, $c);
//-------------------го дотан------------------------//
$w = rand(100,150);
$h = rand(100,100);

$zsize=rand(20,50);

$max = rand(2,7)/10;
$max2= 0.5;

$zxr = rand(-$w/5,$w/5);
$zyr = rand(-$h/5,$h/5);

$zform = rand(3,8)/10;

$mejg = rand($w/2,$w);

$zc = imageColorAllocate($img,rand(5,150),rand(5,150),rand(5,150));
$ec = imageColorAllocate($img,$r,$g,$b);

$ebc = imageColorAllocate($img,rand(235,255),rand(235,255),rand(230,255));

$eform = rand(90,100)/100;
$eform2 = rand(70,100)/100;

$rznglaz = rand(80,120)/100;
$rznglaz2 = rand(80,120)/100;

$smeshx = (500 - ($w*2+$mejg))/2;

DrawEye($img, $smeshx+0,0, $w*$rznglaz,$h ,$ec, $ebc, $eform, $eform2, $zxr, $zyr, $zc, $max, $max2, $zform, $zsize);
if(rand(0,5)==0) $zc = imageColorAllocate($img,rand(5,150),rand(5,150),rand(5,150));
DrawEye($img, $smeshx+$w + $mejg, 0, $w*$rznglaz2, $h, $ec, $ebc, $eform, $eform2, $zxr, $zyr, $zc, 1-$max, $max2, $zform, $zsize);

//imageellipse ( $img , 100 , 100 ,100 , 100 , imageColorAllocate($img,45,45,45) );
//imagefilledellipse ( $img , 200 , 200 ,100 , 100 , imageColorAllocate($img,45,45,45) );
//-----------------и пили симфоню уже-----------------------//
header('Content-type: image/png');
imagepng($img);
imagedestroy($img);
//-------------------------------------------------------//
function DrawEye($image, $xx, $yy, $w, $h, $ec, $ebc, $eform, $eform2, $zxr,$zyr, $zc, $max, $max2, $zform, $zsize)
{
    /*
    if($w<$h)
    $zsize =  $w/3;
    else
    $zsize =  $h/3;
*/
    DrawEyePoligon($image,$xx-5,95-5,$w+10,$h+10, imageColorAllocate($image,5,5,5), 1, $max, $max2, 0);

    DrawEyePoligon($image,$xx,95,$w,$h, imageColorAllocate($image,5,5,5), 1, $max, $max2, 1);

    DrawEyePoligon($image,$xx,100,$w,$h*$eform, $ec, 1, $max, $max2, 1);
    DrawEyePoligon($image,$xx+10,100+$zform*10,$w-20,$h*$eform2, $ebc, 1, $max2,$max2, 1);

    DrawEyePoligon($image,$xx+10,100+$zform*10,$w-20,$h*$eform2, $ebc, 1, $max2,$max2, 1);

    imagefilledellipse ( $image, $xx+$w/2+$zxr,140+$zyr, $zsize, $zsize, $zc);
    imagefilledellipse ( $image, $xx+$w/2+$zxr,140+$zyr, $zsize * $zform, $zsize*(1-$zform), imageColorAllocate($image,5,5,5));
    imagefilledellipse ( $image, $xx+$w/2+$zxr+10,140+$zyr-10, $zsize * 0.5, $zsize*0.5, imageColorAllocate($image,255,255,255));
}
//-------------------------------------------------------//
function DrawEyePoligon($image, $xx, $yy, $width, $height, $color, $quality, $max, $max2, $fill)
{
    $height/=2;

    if($quality>$width/2)
        $quality=$width/2;

    $points = array();

    for($i=0; $i<=$width; $i+=$quality)
    {
        $x = $i-$width;
        $y=($x*$x) / (($width)*($width)) * $height;
        array_push($points, $i*$max, $y);
    }

    for($i=0; $i<=$width; $i+=$quality)
    {
        $x = $i;
        $y=($x*$x) / (($width)*($width)) * $height;
        //$y=(($width*$width)-($x*$x)) / (($width)*($width)) * $height;
        array_push($points, $i*(1-$max)+($width*$max), $y);
    }

    for($i=0; $i<=$width; $i+=$quality)
    {
        $x = $i-$width;
        $y=-($x*$x) / (($width)*($width)) * $height;
        array_push($points, $i*$max2, 2*$height+$y);
    }

    for($i=0; $i<=$width; $i+=$quality)
    {
        $x = $i;
        $y=-($x*$x) / (($width)*($width)) * $height;
        //$y=(($width*$width)-($x*$x)) / (($width)*($width)) * $height;
        array_push($points, $i*(1-$max2)+($width*$max2), 2*$height+$y);
    }

    DrawPoligon($image, $xx, $yy, $points, $color, $fill);
}
//-------------------------------------------------------//
function DrawPoligon($image, $x, $y, $points, $color, $fill)
{
    for($i=0; $i<count($points); $i+=2)
    {
        $points[$i]+=$x;
        $points[$i+1]+=$y;
    }

    if($fill)
        imagefilledpolygon($image, $points, count($points)/2, $color);
    else
        imagepolygon($image, $points, count($points)/2, $color);
}



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

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 21

    +7
    Подумывал даже об ан$%е, но вовремя отдумал.

    А можете просвятить, что это значит?
      +12
      японская мультипликация
        +16
        Блин я уж грешным делом подумал что под закорючками «ал» или «ус» и тоже не мог понять причем оно здесь
        • НЛО прилетело и опубликовало эту надпись здесь
            +2
            Ага. Некоторые знают, что правильно пишется «онанизм», а некоторые не знают. :)
            • НЛО прилетело и опубликовало эту надпись здесь
        +14
        Думаю все зависит от того, что скрывается за "$".
        //самому стыдно за свою распущенность, но японская мультипликация последнее, что пришло в голову.
          +1
          На Хабрахабре нет мата и того самого слова на «А»?
          +1
          Что за рыбка? ;)
          image
            +5
            Это, видимо, отсыл к «Автостопом по галактике»
            0
            Идея то что надо!
              +3
              Возможно менее затратно будет брать одну каплевидную форму и рандомно плющить или растягивать её, чтобы получать разную форму глаз. Библиотека ImageMagick это умеет вроде.

              UPD: Еще можно заранее нагенерить 100500 разных глаз, а юзеру отдавать глаза из заранее сгенеренного массива картинок.
                0
                Качество будет хуже. Например, толщина границ — разной.
                  0
                  А если SVG?
                    0
                    Если SVG, то можно сразу так, без IMagick
                0
                Запустил, очень понравилось, и не так уж затратно в плане ресурсов. Можно генерить как дефолтный аватар при регистрации.
                А будут ещё статьи по генерации аватарок, остальные элементы мордочки? Можно ваш код использовать в коммерческом проекте?
                  +1
                  Скорее всего будут, но уже в следующем году.
                  Можно использовать в коммерческом проекте.
                    0
                    Спасибо, в любом случае если буду использовать, то добавлю в код комментарий:
                    // Written by eximap from habrahabr.ru
                  0
                  Просто оставлю это здесь www.php.net/mt_rand
                    0
                    А еще можно *для снижения затрат* не использовать генераторы случайных чисел, а по какому-то алгоритму добывать разные параметры, скажем, из id пользователя.
                    0
                    Спасибо за идею :)

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

                    Самое читаемое