28 December 2012

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

PHP
Sandbox


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

Основной принцип — генерируем примитивами 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);
}



Остальные части лица (кроме волос и аксессуаров) рисуются аналогичным образом. Получается красиво, но есть большой и жирный минус — это очень затратно даже если оптимизировать. А накладывать друг на друга готовые паттерны может и лучше, но скучно и однообразно. Засим откланиваюсь, с наступающим и спасибо за рыбу.
Tags:PHPimages
Hubs: PHP
+30
13.3k 109
Comments 21