php生成赛博像素风头像

效果图:

代码实现:

php 复制代码
class ImageIdenticon
{
    public static function generateBase64Avatar(string $address, int $size = 64, int $grid = 8): string
    {
        if (!extension_loaded('gd')) {
            throw new \RuntimeException('GD 扩展未启用');
        }

        $address = trim($address) ?: 'default';

        $hash = hash('sha256', $address);

        $img = imagecreatetruecolor($size, $size);

        // 关键:不要透明通道,避免任何"透明合成黑边"
        imagesavealpha($img, false);
        imagealphablending($img, true);

        // 赛博霓虹统一调色板:主/辅/高亮/背景(深色)
        $palettes = [
            [[165, 90, 255], [0, 255, 240], [255, 230, 90], [18, 20, 40]],
            [[90, 170, 255], [175, 80, 255], [150, 255, 90], [10, 16, 34]],
            [[140, 255, 90], [0, 255, 220], [255, 120, 255], [10, 24, 20]],
            [[255, 90, 210], [90, 170, 255], [255, 230, 90], [22, 10, 30]],
            [[0, 255, 240], [150, 255, 90], [175, 80, 255], [6, 26, 28]],
            [[255, 230, 90], [255, 90, 210], [0, 255, 240], [8, 12, 24]],
        ];

        $paletteIndex = self::stableIndex('palette:' . $address, count($palettes));
        $p            = $palettes[$paletteIndex];

        $colA   = imagecolorallocate($img, $p[0][0], $p[0][1], $p[0][2]); // 主色
        $colB   = imagecolorallocate($img, $p[1][0], $p[1][1], $p[1][2]); // 辅色
        $colC   = imagecolorallocate($img, $p[2][0], $p[2][1], $p[2][2]); // 高亮
        $colBG  = imagecolorallocate($img, $p[3][0], $p[3][1], $p[3][2]); // 背景深色
        $colEye = imagecolorallocate($img, 6, 6, 10);                     // 五官近黑

        // 整张图先铺满背景色(彻底杜绝透明导致的黑边)
        imagefilledrectangle($img, 0, 0, $size, $size, $colBG);

        $grid = max(6, $grid);

        $cell = (int)floor($size / $grid);
        if ($cell < 1) $cell = 1;

        $drawSize = $cell * $grid;
        $offset   = (int)floor(($size - $drawSize) / 2);

        // 1) 底纹
        $full = self::buildCyberCircuitPattern($address, $hash, $grid);

        // 2) 脸型模板
        $mask = self::buildStyleMask($address, $grid);

        // 3) 覆盖合成
        for ($y = 0; $y < $grid; $y++) {
            for ($x = 0; $x < $grid; $x++) {
                if (($mask[$y][$x] ?? 0) !== 0) {
                    $full[$y][$x] = $mask[$y][$x];
                }
            }
        }

        // 4) 只在圆内绘制像素(圆外保持背景色 colBG)
        $r     = $size / 2;
        $cxPix = $size / 2;
        $cyPix = $size / 2;

        // 边缘厚度:1=最外一圈像素块。用于"去暗/去黑",避免看起来像描边
        $edgeThickness = 1;

        for ($y = 0; $y < $grid; $y++) {
            for ($x = 0; $x < $grid; $x++) {

                $x1 = $offset + $x * $cell;
                $y1 = $offset + $y * $cell;
                $x2 = $x1 + $cell - 1;
                $y2 = $y1 + $cell - 1;

                // 格子中心点
                $px = $x1 + $cell / 2;
                $py = $y1 + $cell / 2;

                $dx = $px - $cxPix;
                $dy = $py - $cyPix;
                $d2 = ($dx * $dx + $dy * $dy);

                // 圆外不画(保持 colBG)
                if ($d2 > ($r * $r)) {
                    continue;
                }

                $v = $full[$y][$x] ?? 5;

                // 边缘"去暗/去黑":避免圆边缘出现深色圈感
                $dist     = sqrt($d2);
                $nearEdge = (($r - $dist) <= ($edgeThickness * $cell));

                if ($nearEdge) {
                    // 最激进:边缘永远不允许 v=4(黑五官) 和 v=5(深背景)
                    if ($v === 4) $v = 3;   // 黑 -> 高亮
                    if ($v === 5) $v = 2;   // 深背景 -> 辅色
                }

                if ($v === 4) $color = $colEye;
                elseif ($v === 3) $color = $colC;
                elseif ($v === 2) $color = $colB;
                elseif ($v === 1) $color = $colA;
                else $color = $colBG;

                imagefilledrectangle($img, $x1, $y1, $x2, $y2, $color);
            }
        }

        ob_start();
        imagepng($img);
        $png = ob_get_clean();
        imagedestroy($img);

        return base64_encode($png);
    }


    private static function stableIndex(string $key, int $mod): int
    {
        $n = sprintf('%u', crc32($key));
        return $n % $mod;
    }

    /**
     * 赛博电路板底纹:返回值 1主 2辅 3高亮 5背景
     * 核心:对称 + 线路条纹 + 接点高亮
     */
    private static function buildCyberCircuitPattern(string $address, string $hash, int $grid): array
    {
        $m = array_fill(0, $grid, array_fill(0, $grid, 5));

        $seedA = self::stableIndex('lineA:' . $address, 1000);
        $seedB = self::stableIndex('lineB:' . $address, 1000);

        // 1) 深色背景基底 + 少量"噪点电流"
        for ($y = 0; $y < $grid; $y++) {
            for ($x = 0; $x < $grid; $x++) {
                $n = hexdec($hash[($x + $y * $grid) % strlen($hash)]) % 100;
                // 背景为主:70%,主色/辅色做电流:25%,高亮接点:5%
                if ($n < 5) $m[$y][$x] = 3;
                elseif ($n < 18) $m[$y][$x] = 2;
                elseif ($n < 30) $m[$y][$x] = 1;
                else $m[$y][$x] = 5;
            }
        }

        // 2) 画"电路线条"(横竖两组),用主/辅色
        $row1 = ($seedA % ($grid - 2)) + 1;
        $row2 = ($seedB % ($grid - 2)) + 1;
        $col1 = (self::stableIndex('col1:' . $address, $grid - 2)) + 1;
        $col2 = (self::stableIndex('col2:' . $address, $grid - 2)) + 1;

        for ($x = 0; $x < $grid; $x++) {
            $m[$row1][$x] = 1;
            if ($grid >= 8) $m[$row2][$x] = 2;
        }
        for ($y = 0; $y < $grid; $y++) {
            $m[$y][$col1] = 2;
            if ($grid >= 8) $m[$y][$col2] = 1;
        }

        // 3) 线路"接点"高亮(交叉点 + 随机点)
        $m[$row1][$col1] = 3;
        if ($grid >= 8) {
            $m[$row2][$col2] = 3;
            $m[$row1][$col2] = 3;
            $m[$row2][$col1] = 3;
        }

        // 4) 对称(让头像更像 identicon 且更统一)
        $half = (int)ceil($grid / 2);
        for ($y = 0; $y < $grid; $y++) {
            for ($x = 0; $x < $half; $x++) {
                $m[$y][$grid - 1 - $x] = $m[$y][$x];
            }
        }

        return $m;
    }

    private static function buildStyleMask(string $address, int $grid): array
    {
        // 统一赛博风:robot / monster / cat / dog / frog / alien
        $styles = ['robot', 'monster', 'cat', 'dog', 'frog', 'alien'];
        $idx    = self::stableIndex('style:' . $address, count($styles));
        $style  = $styles[$idx];

        switch ($style) {
            case 'monster':
                return self::buildMonsterFaceMask($address, $grid);
            case 'cat':
                return self::buildCatFaceMask($address, $grid);
            case 'dog':
                return self::buildDogFaceMask($address, $grid);
            case 'frog':
                return self::buildFrogFaceMask($address, $grid);
            case 'alien':
                return self::buildAlienFaceMask($address, $grid);
            default:
                return self::buildRobotFaceMask($address, $grid);
        }
    }

    // -------------------- 模板:全部"酷感"统一:更硬朗的线条/眼睛/表情 --------------------

    private static function buildMonsterFaceMask(string $address, int $grid): array
    {
        $mask   = array_fill(0, $grid, array_fill(0, $grid, 0));
        $cx     = (int)floor(($grid - 1) / 2);
        $cy     = (int)floor(($grid - 1) / 2);
        $left   = 1;
        $right  = $grid - 2;
        $top    = 1;
        $bottom = $grid - 2;

        for ($y = $top; $y <= $bottom; $y++) {
            for ($x = $left; $x <= $right; $x++) $mask[$y][$x] = 1;
        }

        // 角:高亮
        if ($top - 1 >= 0) {
            $mask[$top - 1][max(0, $left + 1)]          = 3;
            $mask[$top - 1][min($grid - 1, $right - 1)] = 3;
        }

        // 眼:三眼更"异形"
        $eyeY     = max($top + 2, $cy - 1);
        $threeEye = self::stableIndex('eye:' . $address, 2) === 1;
        if ($threeEye) $mask[$eyeY][$cx] = 4;
        $mask[$eyeY][max($left + 1, $cx - 2)]  = 4;
        $mask[$eyeY][min($right - 1, $cx + 2)] = 4;

        // 大嘴 + 獠牙
        $mouthY = min($bottom - 1, $cy + 2);
        for ($x = $cx - 2; $x <= $cx + 2; $x++) if ($x > $left && $x < $right) $mask[$mouthY][$x] = 4;
        if ($mouthY + 1 <= $bottom) {
            $mask[$mouthY + 1][$cx - 1] = 2;
            $mask[$mouthY + 1][$cx + 1] = 2;
        }

        // 颧骨阴影
        $mask[$cy][max($left + 1, $cx - 3)]  = 2;
        $mask[$cy][min($right - 1, $cx + 3)] = 2;

        return $mask;
    }

    private static function buildCatFaceMask(string $address, int $grid): array
    {
        $mask   = array_fill(0, $grid, array_fill(0, $grid, 0));
        $cx     = (int)floor(($grid - 1) / 2);
        $cy     = (int)floor(($grid - 1) / 2);
        $left   = 1;
        $right  = $grid - 2;
        $top    = 1;
        $bottom = $grid - 2;

        // 脸
        for ($y = $top + 1; $y <= $bottom; $y++) {
            for ($x = $left + 1; $x <= $right - 1; $x++) $mask[$y][$x] = 1;
        }

        // 耳朵(高亮更赛博)
        $mask[$top][$left + 1]      = 3;
        $mask[$top + 1][$left + 2]  = 2;
        $mask[$top][$right - 1]     = 3;
        $mask[$top + 1][$right - 2] = 2;

        // 眼(冷酷)
        $eyeY                                  = max($top + 2, $cy - 1);
        $mask[$eyeY][max($left + 1, $cx - 2)]  = 4;
        $mask[$eyeY][min($right - 1, $cx + 2)] = 4;

        // 鼻/嘴
        $noseY = $cy + 1;
        if ($noseY < $grid) $mask[$noseY][$cx] = 3;
        $mouthY = $cy + 2;
        if ($mouthY < $grid) {
            if ($cx - 1 >= 0) $mask[$mouthY][$cx - 1] = 4;
            if ($cx + 1 < $grid) $mask[$mouthY][$cx + 1] = 4;
        }

        return $mask;
    }

    private static function buildDogFaceMask(string $address, int $grid): array
    {
        $mask   = array_fill(0, $grid, array_fill(0, $grid, 0));
        $cx     = (int)floor(($grid - 1) / 2);
        $cy     = (int)floor(($grid - 1) / 2);
        $left   = 1;
        $right  = $grid - 2;
        $top    = 1;
        $bottom = $grid - 2;

        for ($y = $top + 1; $y <= $bottom; $y++) {
            for ($x = $left; $x <= $right; $x++) $mask[$y][$x] = 1;
        }

        // 立耳(更酷)为主,偶尔垂耳
        $ear = self::stableIndex('ear:' . $address, 4);
        if ($ear !== 0) {
            $mask[$top][$left + 1]      = 3;
            $mask[$top][$right - 1]     = 3;
            $mask[$top + 1][$left + 2]  = 2;
            $mask[$top + 1][$right - 2] = 2;
        } else {
            $mask[$top + 1][$left]  = 2;
            $mask[$top + 2][$left]  = 2;
            $mask[$top + 1][$right] = 2;
            $mask[$top + 2][$right] = 2;
        }

        // 眉骨
        $browY                                  = max($top + 2, $cy - 2);
        $mask[$browY][max($left + 1, $cx - 2)]  = 2;
        $mask[$browY][min($right - 1, $cx + 2)] = 2;

        // 眼
        $eyeY                                  = max($top + 3, $cy - 1);
        $mask[$eyeY][max($left + 1, $cx - 2)]  = 4;
        $mask[$eyeY][min($right - 1, $cx + 2)] = 4;

        // 鼻/嘴(更硬)
        $noseY             = min($bottom - 2, $cy + 1);
        $mask[$noseY][$cx] = 4;
        if ($cx - 1 >= 0) $mask[$noseY][$cx - 1] = 4;
        if ($cx + 1 < $grid) $mask[$noseY][$cx + 1] = 4;

        $mouthY             = min($bottom - 1, $cy + 2);
        $mask[$mouthY][$cx] = 4;

        return $mask;
    }

    private static function buildFrogFaceMask(string $address, int $grid): array
    {
        $mask   = array_fill(0, $grid, array_fill(0, $grid, 0));
        $cx     = (int)floor(($grid - 1) / 2);
        $cy     = (int)floor(($grid - 1) / 2);
        $left   = 1;
        $right  = $grid - 2;
        $top    = 1;
        $bottom = $grid - 2;

        for ($y = $top + 1; $y <= $bottom; $y++) {
            for ($x = $left; $x <= $right; $x++) $mask[$y][$x] = 1;
        }

        // 护目镜带
        $eyeY = max($top + 2, $cy - 1);
        for ($x = $left + 1; $x <= $right - 1; $x++) $mask[$eyeY][$x] = 2;

        // 眼点
        $mask[$eyeY][max($left + 1, $cx - 2)]  = 4;
        $mask[$eyeY][min($right - 1, $cx + 2)] = 4;

        // 宽嘴
        $mouthY = min($bottom - 1, $cy + 2);
        for ($x = $cx - 3; $x <= $cx + 3; $x++) if ($x > $left && $x < $right) $mask[$mouthY][$x] = 4;

        // 额头霓虹点
        if ($top + 1 < $grid) {
            $mask[$top + 1][$cx] = 3;
            if ($cx - 2 >= 0) $mask[$top + 1][$cx - 2] = 3;
            if ($cx + 2 < $grid) $mask[$top + 1][$cx + 2] = 3;
        }

        return $mask;
    }

    private static function buildAlienFaceMask(string $address, int $grid): array
    {
        $mask   = array_fill(0, $grid, array_fill(0, $grid, 0));
        $cx     = (int)floor(($grid - 1) / 2);
        $cy     = (int)floor(($grid - 1) / 2);
        $left   = 1;
        $right  = $grid - 2;
        $top    = 1;
        $bottom = $grid - 2;

        // 梯形头(更"异形")
        for ($y = $top; $y <= $bottom; $y++) {
            $shrink = (int)max(0, floor(($y - $top) / 2));
            $l      = min($right, $left + $shrink);
            $r      = max($left, $right - $shrink);
            for ($x = $l; $x <= $r; $x++) $mask[$y][$x] = 1;
        }

        // 大眼(2x2)
        $eyeY = max($top + 2, $cy - 1);
        $lx   = max($left + 1, $cx - 2);
        $rx   = min($right - 1, $cx + 2);

        $mask[$eyeY][$lx]         = 4;
        $mask[$eyeY][$lx + 1]     = 4;
        $mask[$eyeY + 1][$lx]     = 4;
        $mask[$eyeY + 1][$lx + 1] = 4;

        $mask[$eyeY][$rx - 1]     = 4;
        $mask[$eyeY][$rx]         = 4;
        $mask[$eyeY + 1][$rx - 1] = 4;
        $mask[$eyeY + 1][$rx]     = 4;

        // 冷嘴
        $mouthY             = min($bottom - 1, $cy + 2);
        $mask[$mouthY][$cx] = 4;
        if ($cx - 1 >= 0) $mask[$mouthY][$cx - 1] = 4;
        if ($cx + 1 < $grid) $mask[$mouthY][$cx + 1] = 4;

        // 光环/天线
        if ($top - 1 >= 0) {
            $mask[$top - 1][$cx] = 3;
            if ($cx - 2 >= 0) $mask[$top - 1][$cx - 2] = 3;
            if ($cx + 2 < $grid) $mask[$top - 1][$cx + 2] = 3;
        }

        // 颧骨阴影
        $cheekY                                  = $cy;
        $mask[$cheekY][max($left + 1, $cx - 3)]  = 2;
        $mask[$cheekY][min($right - 1, $cx + 3)] = 2;

        return $mask;
    }

    private static function buildRobotFaceMask(string $address, int $grid): array
    {
        $mask   = array_fill(0, $grid, array_fill(0, $grid, 0));
        $cx     = (int)floor(($grid - 1) / 2);
        $cy     = (int)floor(($grid - 1) / 2);
        $left   = 1;
        $right  = $grid - 2;
        $top    = 1;
        $bottom = $grid - 2;

        // 硬朗外壳
        for ($y = $top; $y <= $bottom; $y++) {
            for ($x = $left; $x <= $right; $x++) $mask[$y][$x] = 1;
        }
        for ($x = $left; $x <= $right; $x++) {
            $mask[$top][$x]    = 2;
            $mask[$bottom][$x] = 2;
        }
        for ($y = $top; $y <= $bottom; $y++) {
            $mask[$y][$left]  = 2;
            $mask[$y][$right] = 2;
        }

        // 眼:更"激光"
        $eyeY                                  = max($top + 2, $cy - 1);
        $mask[$eyeY][max($left + 1, $cx - 2)]  = 4;
        $mask[$eyeY][min($right - 1, $cx + 2)] = 4;

        // 眉:更凶
        $browY = $eyeY - 1;
        if ($browY >= 0) {
            $mask[$browY][max($left + 1, $cx - 2)]  = 2;
            $mask[$browY][min($right - 1, $cx + 2)] = 2;
        }

        // 嘴:短、冷
        $mouthY             = min($bottom - 1, $cy + 2);
        $mask[$mouthY][$cx] = 4;
        if ($cx - 1 >= 0) $mask[$mouthY][$cx - 1] = 4;
        if ($cx + 1 < $grid) $mask[$mouthY][$cx + 1] = 4;

        // 天线:霓虹高亮
        $ant = self::stableIndex('ant:' . $address, 3);
        if ($top - 1 >= 0) {
            if ($ant === 0) $mask[$top - 1][$cx] = 3;
            if ($ant === 1) {
                if ($cx - 1 >= 0) $mask[$top - 1][$cx - 1] = 3;
                if ($cx + 1 < $grid) $mask[$top - 1][$cx + 1] = 3;
            }
            if ($ant === 2) {
                if ($cx - 2 >= 0) $mask[$top - 1][$cx - 2] = 3;
                if ($cx + 2 < $grid) $mask[$top - 1][$cx + 2] = 3;
            }
        }

        return $mask;
    }
}
php 复制代码
$imageBase64 = ImageIdenticon::generateBase64Avatar($address);

我这里生成的是base64数据,如果是pc或者app做渲染只需要拼接前缀就行:

php 复制代码
$img = 'data:image/png;base64,' . $imageBase64
相关推荐
短剑重铸之日2 小时前
《深入解析JVM》第五章:JDK 8之后版本的优化与JDK 25前瞻
java·开发语言·jvm·后端
love530love2 小时前
【探讨】“父级/基环境损坏,子环境全部失效”,如何避免 .venv 受父级 Python 损坏影响?
java·开发语言·人工智能·windows·python·编程·ai编程
shbelec2 小时前
实邦电子在电子产品开发方面有哪些优势与特色?
开发语言
阿里嘎多学长3 小时前
2025-12-31 GitHub 热点项目精选
开发语言·程序员·github·代码托管
无限进步_3 小时前
【C语言】循环队列的两种实现:数组与链表的对比分析
c语言·开发语言·数据结构·c++·leetcode·链表·visual studio
蓝眸少年CY3 小时前
测试Java性能
java·开发语言·python
何包蛋H3 小时前
数据结构深度解析:Java Map 家族完全指南
java·开发语言·数据结构
秃了也弱了。3 小时前
python监听文件变化:Watchdog库
开发语言·python
一路往蓝-Anbo3 小时前
C语言从句柄到对象 (五) —— 虚函数表 (V-Table) 与 RAM 的救赎
c语言·开发语言·stm32·单片机·物联网