PHP生成NFT图片脚本

wen PHP项目 2

我将为您创建一个完整的PHP脚本,用于批量生成NFT图片,这个脚本会结合多个图层组件(如背景、身体、眼睛、装饰等)来生成独特的NFT图片。

PHP生成NFT图片脚本

完整PHP NFT生成脚本

<?php
/**
 * NFT图片批量生成器
 * 通过组合不同图层生成独特的NFT图片
 */
class NFTGenerator {
    private $layers = [];
    private $outputDir;
    private $width = 1000;
    private $height = 1000;
    private $totalSupply = 100;
    private $rarityLevels = ['common' => 0.6, 'rare' => 0.25, 'epic' => 0.1, 'legendary' => 0.05];
    public function __construct($outputDir = 'nft_output') {
        $this->outputDir = $outputDir;
        if (!file_exists($outputDir)) {
            mkdir($outputDir, 0777, true);
        }
        if (!extension_loaded('gd')) {
            die('需要启用GD库');
        }
    }
    /**
     * 配置图层
     * 
     * 目录结构示例:
     * layers/
     *   background/
     *     红色背景.png
     *     蓝色背景.png
     *   body/
     *     标准身体.png
     *     特殊身体.png
     */
    public function loadLayers($layersDir) {
        $directories = ['background', 'body', 'eyes', 'mouth', 'accessory'];
        foreach ($directories as $dir) {
            $path = $layersDir . '/' . $dir;
            if (is_dir($path)) {
                $files = glob($path . '/*.{png,jpg,jpeg}', GLOB_BRACE);
                if (!empty($files)) {
                    $this->layers[$dir] = [];
                    foreach ($files as $file) {
                        $this->layers[$dir][] = [
                            'path' => $file,
                            'name' => pathinfo($file, PATHINFO_FILENAME),
                            'rarity' => $this->determineRarity($file)
                        ];
                    }
                }
            }
        }
        if (empty($this->layers)) {
            die('没有找到图层文件');
        }
    }
    /**
     * 根据文件名确定稀有度(可通过文件名包含关键字)
     */
    private function determineRarity($file) {
        $filename = strtolower(basename($file));
        if (strpos($filename, 'legendary') !== false) return 'legendary';
        if (strpos($filename, 'epic') !== false) return 'epic';
        if (strpos($filename, 'rare') !== false) return 'rare';
        return 'common';
    }
    /**
     * 生成单个NFT
     */
    public function generateSingle($id) {
        $bg = imagecreatetruecolor($this->width, $this->height);
        // 设置白色背景
        $white = imagecolorallocate($bg, 255, 255, 255);
        imagefill($bg, 0, 0, $white);
        $selectedLayers = [];
        $attributes = [];
        // 后台优先
        if (isset($this->layers['background'])) {
            $layer = $this->selectLayer($this->layers['background']);
            $this->applyLayer($bg, $layer);
            $attributes[] = ['trait_type' => 'Background', 'value' => $layer['name']];
            $selectedLayers[] = $layer;
        }
        // 身体
        if (isset($this->layers['body'])) {
            $layer = $this->selectLayer($this->layers['body']);
            $this->applyLayer($bg, $layer);
            $attributes[] = ['trait_type' => 'Body', 'value' => $layer['name']];
            $selectedLayers[] = $layer;
        }
        // 眼睛
        if (isset($this->layers['eyes'])) {
            $layer = $this->selectLayer($this->layers['eyes']);
            $this->applyLayer($bg, $layer);
            $attributes[] = ['trait_type' => 'Eyes', 'value' => $layer['name']];
            $selectedLayers[] = $layer;
        }
        // 嘴巴
        if (isset($this->layers['mouth'])) {
            $layer = $this->selectLayer($this->layers['mouth']);
            $this->applyLayer($bg, $layer);
            $attributes[] = ['trait_type' => 'Mouth', 'value' => $layer['name']];
            $selectedLayers[] = $layer;
        }
        // 装饰品
        if (isset($this->layers['accessory'])) {
            $layer = $this->selectLayer($this->layers['accessory']);
            $this->applyLayer($bg, $layer);
            $attributes[] = ['trait_type' => 'Accessory', 'value' => $layer['name']];
            $selectedLayers[] = $layer;
        }
        // 计算稀有度
        $rarity = 'common';
        $rarityScore = 1;
        foreach ($selectedLayers as $layer) {
            if ($layer['rarity'] === 'legendary') {
                $rarity = 'legendary';
                $rarityScore *= 0.5;
            } elseif ($layer['rarity'] === 'epic' && $rarity !== 'legendary') {
                $rarity = 'epic';
                $rarityScore *= 0.7;
            } elseif ($layer['rarity'] === 'rare' && $rarity === 'common') {
                $rarity = 'rare';
                $rarityScore *= 0.85;
            }
        }
        // 保存图片
        $filename = $this->outputDir . '/nft_' . $id . '.png';
        imagepng($bg, $filename);
        imagedestroy($bg);
        // 生成元数据
        $metadata = [
            'name' => 'NFT #' . $id,
            'description' => '独特的数字艺术品 NFT #' . $id,
            'image' => $filename,
            'attributes' => $attributes,
            'rarity' => $rarity,
            'rarity_score' => round($rarityScore, 3)
        ];
        // 保存元数据
        file_put_contents($this->outputDir . '/nft_' . $id . '.json', json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
        echo "生成 NFT #{$id} 成功 (稀有度: {$rarity})\n";
        return $metadata;
    }
    /**
     * 选择图层(带稀有度权重)
     */
    private function selectLayer($layers) {
        // 根据稀有度权重选择
        $totalWeight = 0;
        foreach ($layers as $layer) {
            $weight = $this->rarityLevels[$layer['rarity']] ?? 0.1;
            $totalWeight += $weight;
        }
        $random = mt_rand(0, $totalWeight * 100) / 100;
        $cumulativeWeight = 0;
        shuffle($layers); // 随机排序增加多样性
        foreach ($layers as $layer) {
            $weight = $this->rarityLevels[$layer['rarity']] ?? 0.1;
            $cumulativeWeight += $weight;
            if ($random <= $cumulativeWeight) {
                return $layer;
            }
        }
        return $layers[0]; // 默认返回第一个
    }
    /**
     * 应用图层到图像
     */
    private function applyLayer($base, $layer) {
        $overlay = imagecreatefromstring(file_get_contents($layer['path']));
        // 调整大小
        $overlay = $this->resizeImage($overlay, $this->width, $this->height);
        // 合并图像
        imagecopy($base, $overlay, 0, 0, 0, 0, $this->width, $this->height);
        imagedestroy($overlay);
    }
    /**
     * 调整图像大小
     */
    private function resizeImage($image, $width, $height) {
        $newImage = imagecreatetruecolor($width, $height);
        imagealphablending($newImage, true);
        imagesavealpha($newImage, true);
        $srcW = imagesx($image);
        $srcH = imagesy($image);
        imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $srcW, $srcH);
        imagedestroy($image);
        return $newImage;
    }
    /**
     * 批量生成NFT
     */
    public function generateBatch($count) {
        $generated = [];
        $usedCombinations = [];
        echo "开始生成 {$count} 个NFT...\n";
        for ($i = 1; $i <= $count; $i++) {
            // 获取唯一组合
            do {
                $combination = $this->getRandomCombination();
                $hash = md5(implode('|', $combination));
            } while (in_array($hash, $usedCombinations));
            $usedCombinations[] = $hash;
            $this->generateSingle($i);
            $generated[] = $i;
            if ($i % 10 == 0) {
                echo "已完成 {$i}/{$count} 个NFT\n";
            }
        }
        echo "批量生成完成!共生成 " . count($generated) . " 个NFT\n";
    }
    /**
     * 获取随机组合(用于唯一性检查)
     */
    private function getRandomCombination() {
        $combination = [];
        foreach ($this->layers as $layerType => $layers) {
            $combination[] = $this->selectLayer($layers)['name'];
        }
        return $combination;
    }
    /**
     * 生成项目级元数据
     */
    public function generateCollectionMetadata($name, $description) {
        $metadata = [
            'name' => $name,
            'description' => $description,
            'image' => 'https://example.com/logo.png',
            'external_link' => 'https://example.com',
            'seller_fee_basis_points' => 500,
            'fee_recipient' => '0x0000000000000000000000000000000000000000'
        ];
        file_put_contents($this->outputDir . '/collection.json', json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
        echo "项目元数据已生成\n";
    }
    /**
     * 生成统计报告
     */
    public function generateStatistics() {
        $stats = [];
        $jsonFiles = glob($this->outputDir . '/*.json');
        foreach ($jsonFiles as $file) {
            if (basename($file) === 'collection.json') continue;
            $data = json_decode(file_get_contents($file), true);
            if (isset($data['rarity'])) {
                $stats[$data['rarity']] = ($stats[$data['rarity']] ?? 0) + 1;
            }
        }
        echo "\n=== NFT稀有度统计 ===\n";
        foreach ($stats as $rarity => $count) {
            $percentage = round(($count / array_sum($stats)) * 100, 2);
            echo "{$rarity}: {$count}个 ({$percentage}%)\n";
        }
        return $stats;
    }
}
// ==================== 使用示例 ====================
// 初始化生成器
$generator = new NFTGenerator('my_nft_collection');
// 加载图层(请确保图层目录结构正确)
$generator->loadLayers('layers');
// 设置NFT数量
$totalNFTs = 100;
// 批量生成
$generator->generateBatch($totalNFTs);
// 生成项目元数据
$generator->generateCollectionMetadata(
    '我的NFT收藏',
    '这是一个由PHP自动生成的独特NFT收藏系列'
);
// 生成统计报告
$generator->generateStatistics();
echo "\nNFT生成完成!请检查 my_nft_collection 目录\n";
// 可以添加更多的自定义功能
?>

辅助脚本:创建示例图层

创建以下脚本来生成简单的示例图层:

<?php
/**
 * 生成示例NFT图层
 */
class LayerCreator {
    private $layersDir;
    public function __construct() {
        $this->layersDir = __DIR__ . '/layers';
        $this->createDirectories();
    }
    private function createDirectories() {
        $dirs = ['background', 'body', 'eyes', 'mouth', 'accessory'];
        foreach ($dirs as $dir) {
            if (!file_exists($this->layersDir . '/' . $dir)) {
                mkdir($this->layersDir . '/' . $dir, 0777, true);
            }
        }
    }
    public function generateBackgrounds() {
        $colors = [
            'common' => ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'],
            'rare' => ['#FFEAA7', '#DDA0DD', '#98FB98', '#FFDAB9'],
            'epic' => ['#FFB6C1', '#87CEEB', '#DDA0DD', '#FF69B4'],
            'legendary' => ['#FFD700', '#FF1493', '#00CED1', '#8A2BE2']
        ];
        foreach ($colors as $rarity => $palette) {
            foreach ($palette as $i => $color) {
                $img = imagecreatetruecolor(1000, 1000);
                $rgb = $this->hexToRgb($color);
                $bg = imagecolorallocate($img, $rgb[0], $rgb[1], $rgb[2]);
                imagefill($img, 0, 0, $bg);
                // 添加简单的渐变效果
                for ($y = 0; $y < 1000; $y += 10) {
                    $alpha = ($y / 1000) * 127;
                    $gradient = imagecolorallocatealpha($img, 255, 255, 255, $alpha);
                    imageline($img, 0, $y, 1000, $y, $gradient);
                }
                $filename = $this->layersDir . "/background/bg_{$rarity}_{$i}.png";
                imagepng($img, $filename);
                imagedestroy($img);
            }
        }
        echo "生成背景图层完成\n";
    }
    public function generateBodies() {
        $shapes = [
            'circle', 'rounded', 'squared', 'star'
        ];
        foreach ($shapes as $i => $shape) {
            $img = imagecreatetruecolor(1000, 1000);
            imagesavealpha($img, true);
            $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
            imagefill($img, 0, 0, $transparent);
            $color = imagecolorallocate($img, 255, 128, 0);
            switch ($shape) {
                case 'circle':
                    imagefilledellipse($img, 500, 500, 700, 700, $color);
                    break;
                case 'rounded':
                    imagefilledrectangle($img, 300, 300, 700, 700, $color);
                    break;
                case 'squared':
                    imagefilledrectangle($img, 250, 250, 750, 750, $color);
                    break;
                case 'star':
                    $points = $this->getStarPoints(5, 350, 500, 500);
                    imagefilledpolygon($img, $points, 5, $color);
                    break;
            }
            $rarity = $i < 2 ? 'common' : ($i < 3 ? 'rare' : 'epic');
            $filename = $this->layersDir . "/body/body_{$rarity}_{$i}.png";
            imagepng($img, $filename);
            imagedestroy($img);
        }
        echo "生成身体图层完成\n";
    }
    public function generateEyes() {
        $styles = [
            'small', 'large', 'round', 'cat', 'robot', 'sleepy'
        ];
        foreach ($styles as $i => $style) {
            $img = imagecreatetruecolor(1000, 1000);
            imagesavealpha($img, true);
            $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
            imagefill($img, 0, 0, $transparent);
            $eyeColor = imagecolorallocate($img, 50, 50, 50);
            $white = imagecolorallocate($img, 255, 255, 255);
            switch ($style) {
                case 'small':
                    imagefilledellipse($img, 400, 400, 40, 40, $eyeColor);
                    imagefilledellipse($img, 600, 400, 40, 40, $eyeColor);
                    break;
                case 'large':
                    imagefilledellipse($img, 380, 380, 100, 100, $white);
                    imagefilledellipse($img, 620, 380, 100, 100, $white);
                    imagefilledellipse($img, 380, 380, 60, 60, $eyeColor);
                    imagefilledellipse($img, 620, 380, 60, 60, $eyeColor);
                    break;
                case 'robot':
                    imagefilledrectangle($img, 360, 360, 440, 440, $eyeColor);
                    imagefilledrectangle($img, 560, 360, 640, 440, $eyeColor);
                    break;
                default:
                    imagefilledellipse($img, 400, 400, 70, 70, $eyeColor);
                    imagefilledellipse($img, 600, 400, 70, 70, $eyeColor);
            }
            $rarity = $i < 3 ? 'common' : ($i < 5 ? 'rare' : 'legendary');
            $filename = $this->layersDir . "/eyes/eyes_{$rarity}_{$i}.png";
            imagepng($img, $filename);
            imagedestroy($img);
        }
        echo "生成眼睛图层完成\n";
    }
    public function generateMouths() {
        $styles = ['smile', 'grin', 'frown', 'surprised', 'neutral'];
        foreach ($styles as $i => $style) {
            $img = imagecreatetruecolor(1000, 1000);
            imagesavealpha($img, true);
            $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
            imagefill($img, 0, 0, $transparent);
            $mouthColor = imagecolorallocate($img, 150, 50, 50);
            switch ($style) {
                case 'smile':
                    imagearc($img, 500, 600, 200, 100, 0, 180, $mouthColor);
                    break;
                case 'grin':
                    imagefilledellipse($img, 500, 600, 200, 100, $mouthColor);
                    break;
                case 'frown':
                    imagearc($img, 500, 700, 200, 100, 180, 360, $mouthColor);
                    break;
                case 'surprised':
                    imagefilledellipse($img, 500, 650, 50, 80, $mouthColor);
                    break;
                default:
                    imageline($img, 400, 650, 600, 650, $mouthColor);
            }
            $rarity = $i < 3 ? 'common' : ($i < 4 ? 'rare' : 'epic');
            $filename = $this->layersDir . "/mouth/mouth_{$rarity}_{$i}.png";
            imagepng($img, $filename);
            imagedestroy($img);
        }
        echo "生成嘴巴图层完成\n";
    }
    public function generateAccessories() {
        $items = ['crown', 'hat', 'glasses', 'chain', 'hat_rare', 'crown_legendary'];
        foreach ($items as $i => $item) {
            $img = imagecreatetruecolor(1000, 1000);
            imagesavealpha($img, true);
            $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
            imagefill($img, 0, 0, $transparent);
            $color = imagecolorallocate($img, 255, 215, 0);
            switch ($item) {
                case 'crown':
                    imagefilledpolygon($img, [400,300, 450,200, 500,300, 550,200, 600,300], 5, $color);
                    break;
                case 'hat':
                    imagefilledellipse($img, 500, 300, 300, 100, $color);
                    imagefilledrectangle($img, 420, 250, 580, 380, $color);
                    break;
                case 'glasses':
                    imagesetthickness($img, 5);
                    imagearc($img, 400, 400, 100, 100, 0, 360, $color);
                    imagearc($img, 600, 400, 100, 100, 0, 360, $color);
                    break;
                case 'chain':
                    imagesetthickness($img, 10);
                    imageline($img, 400, 700, 600, 700, $color);
                    imagefilledellipse($img, 500, 700, 30, 30, $color);
                    break;
                case 'hat_rare':
                    imagefilledellipse($img, 500, 250, 250, 50, $color);
                    imagefilledrectangle($img, 450, 200, 550, 350, $color);
                    break;
                case 'crown_legendary':
                    $points = [350,300, 400,150, 450,250, 500,100, 550,250, 600,150, 650,300];
                    imagefilledpolygon($img, $points, 7, $color);
                    break;
            }
            $rarity = strpos($item, 'legendary') !== false ? 'legendary' : (strpos($item, 'rare') !== false ? 'rare' : 'common');
            $filename = $this->layersDir . "/accessory/acc_{$rarity}_{$i}.png";
            imagepng($img, $filename);
            imagedestroy($img);
        }
        echo "生成装饰品图层完成\n";
    }
    private function hexToRgb($hex) {
        $hex = str_replace('#', '', $hex);
        return [hexdec(substr($hex, 0, 2)), hexdec(substr($hex, 2, 2)), hexdec(substr($hex, 4, 2))];
    }
    private function getStarPoints($points, $radius, $centerX, $centerY) {
        $coords = [];
        for ($i = 0; $i < $points * 2; $i++) {
            $angle = deg2rad($i * 180 / $points);
            $r = $i % 2 == 0 ? $radius : $radius * 0.4;
            $coords[] = $centerX + $r * cos($angle);
            $coords[] = $centerY + $r * sin($angle);
        }
        return $coords;
    }
    public function generateAll() {
        $this->generateBackgrounds();
        $this->generateBodies();
        $this->generateEyes();
        $this->generateMouths();
        $this->generateAccessories();
        echo "所有示例图层生成完成!\n";
    }
}
// 运行图层生成器
$creator = new LayerCreator();
$creator->generateAll();
?>

使用方法

  1. 准备环境

    # 确保PHP已安装并启用GD库
    php -m | grep gd
  2. 创建目录结构

    project/
    ├── generate_nft.php     # 主生成脚本
    ├── create_layers.php    # 图层生成脚本
    └── layers/              # 图层目录
  3. 运行脚本

    # 1. 先生成示例图层
    php create_layers.php

运行NFT生成器

php generate_nft.php


4. **查看输出**

my_nft_collection/ ├── nft_1.png ├── nft_1.json ├── nft_2.png ├── nft_2.json ├── ... ├── collection.json └── ...


## 高级功能
### 1. 自定义元数据格式
```php
// 添加更多属性
$attributes[] = ['display_type' => 'number', 'trait_type' => 'Level', 'value' => rand(1, 100)];

批量大小控制

// 分批次生成
$generator->generateBatch(200); // 先生成200个
$generator->generateBatch(300); // 再生成300个

集成智能合约

// 可以使用 ethers.js 或 web3.js 与合约交互
$whitelist = ['0x...', '0x...']; // 白名单地址

这个脚本为您提供了一个功能完整的NFT生成系统,您可以根据需要调整图层、添加更多属性、集成区块链功能等,记住要合理管理图层资源,确保每个图层都有足够的多样性!

抱歉,评论功能暂时关闭!