Создавайте тысячи уникальных изображений для своей коллекции NFT слой за слоем вместе с метаданными с помощью Python.

Когда я писал первую статью, я как раз изучал процесс генерации изображений NFT. Когда я узнал больше, я понял, что речь идет не только о создании изображений, но и о создании метаданных, а также о хранении изображений в облаке. Вы можете рассматривать эту статью как улучшенную версию первой статьи. Кроме того, написав эту статью и узнав больше, я пошел дальше и создал небольшой веб-сайт, используя ту же концепцию, чтобы пользователи могли создавать свои коллекции. На данный момент я ограничил его до 1000 изображений, но надеюсь продолжить работу над ним, если будет достаточно посещений. Пожалуйста, сделайте проверку!

Этот код имеет некоторые улучшения по сравнению с предыдущим. Основные из них следующие:

  • Пользователь может добавить столько слоев, сколько захочет, единственное, что ему нужно указать в коде, это название слоев.
  • Количество вариантов в каждом слое не обязательно должно быть одинаковым, код просто загрузит список файлов в каждой папке, представляющей слой, использующий их.
  • Код также создает файл .json, содержащий метаданные созданного изображения.

Еще раз, я не профессиональный программист, и мой код, вероятно, не будет лучшим способом выполнить задачу, но, эй, он работает!

Структура каталогов:

На следующем изображении показана структура каталогов:

Корневая папка содержит вложенные папки, каждая из которых представляет слой. Каждая вложенная папка, представляющая слой, должна быть пронумерована в той последовательности, в которой слои должны быть выбраны и объединены. Таким образом, самый нижний слой изображения, являющийся фоном, будет называться «1», следующий слой — «2» и так далее. В изображении с 5 слоями фон будет равен 1, а самый верхний слой — 5.

Каждая вложенная папка слоя содержит файлы изображений, представляющие каждую вариацию этого слоя. Их не нужно нумеровать, так как наш обновленный код загружает имена файлов. Однако вы должны дать каждому файлу соответствующее имя, так как это имя будет использоваться в метаданных созданного файла изображения.

Хранение изображений в облаке:

Все изображения в вашей коллекции NFT должны где-то храниться. Вы можете хранить его где угодно, но имейте в виду, что вы должны убедиться, что это надежное хранилище, чтобы ваши изображения были доступны в любое время. Популярный вариант — Пината. Pinata хранит ваши данные в одноранговой файловой системе, известной как Межпланетная файловая система. Пиньята довольно проста. Вы можете зарегистрироваться для бесплатного хранения до 1 ГБ. После входа в систему загрузите папку. Подойдет любая папка с тестовым файлом. На этом этапе нужно получить URL-адрес, который можно использовать в файле метаданных. После того, как вы загрузили папку, вернитесь на домашнюю страницу, вы увидите там имя папки. Рядом с ним вы увидите его CID, представляющий собой длинную последовательность букв и цифр. Скопируйте это и сохраните в месте, к которому вы можете легко получить доступ, так как оно понадобится нам для нашего кода.

Настройка параметров:

Определим некоторые параметры.

#Name of your  project, using test for now.
project = ‘test’
#The CID of the folder on Pinata.
url = ‘QtgdsX3fsfT45fsggrd’
#The local folder which will have the layers' subfolders.
folder = ‘layers’
#The number of images you want to generate.
count = ‘100’
#List containing the names of the layers, in the sequence you want
#the layers to be picked by the code and merged.
layers_names = [“background”, “face”, “shirt”, “accessory”]

Общее количество изображений, которые могут быть сгенерированы, можно рассчитать, умножив количество файлов в подпапках каждого слоя. Допустим, у нас есть 4 слоя, и каждый слой имеет 4 варианта, представленных файлами, общее количество возможных уникальных изображений будет:

4x4x4x4=256

Добавление большего количества слоев увеличит количество в геометрической прогрессии. Однако для тестирования вы можете не захотеть генерировать столько изображений, так как это займет много времени, поэтому можно установить значение 100 или даже 10.

Импорт необходимых библиотек:

import random
import os
from itertools import product
from PIL import Image

Генерация всех возможных комбинаций файлов вариантов:

Теперь мы загрузим список файлов в каждой подпапке в нашей папке, указанной параметром папки. Затем мы объединим их во всех возможных комбинациях, чтобы создать список кортежей, каждый кортеж содержит возможную комбинацию вариации каждого слоя. Это можно сделать одной строкой кода.

combinations = list(product(*[os.listdir(f'{folder}/{x}') for x in os.listdir(folder)]))

Каждый элемент в этом списке представляет возможную комбинацию вариаций в каждом слое. Мы будем использовать его для загрузки файлов на основе их имен файлов и их объединения. Если вы не хотите идти до конца и ограничили количество изображений меньшим числом, может быть хорошей идеей перетасовать этот список.

random.shuffle(combinations)

Создание изображений и метаданных:

Следующий код перебирает каждую комбинацию в списке комбинаций, загружает изображение из каждой папки слоев и объединяет их в одно изображение, затем сохраняет его, а также создает метаданные для этого изображения и сохраняет их.

c=0
metadata={}
for combination in combinations:
    if c != count:
        if len(combination)>2:
            comp = image.alpha_composite(image.open(f'{folder}/1/{combination[1]}').convert('RGBA'),
                                         image.open(f'{folder}/2/{combination[2]}').convert('RGBA'))
            n=3
            for item in combination[2:]:
                if combination.index(item)!=-1:
                    comp = Image.alpha_composite(comp,
                                         image.open(f'{folder}/{n}/{item}').convert('RGBA'))
                    n+=1
        rgb_im = comp.convert('RGB')
        file_name = str(combinations.index(combination)) + ".png"
        rgb_im.save("./images/" + file_name)
        metadata['image']=f'{image_url}/{file_name}'
        metadata['tokenId']=str(combinations.index(combination))
        metadata['name']=project+' '+str(combinations.index(combination))
        metadata['attributes']=[]
        for item in layers_names:
            metadata['attributes'].append({item:combination[layers_names.index(item)][:-4]})
        with open(f"./metadata/{str(combinations.index(combination))}.json", "w") as outfile:
            json.dump(metadata, outfile, indent=4)
        c+=1
    else:
        break

Переменная «c» ведет подсчет количества сгенерированных файлов и обновляется в конце каждой итерации. Для каждого элемента в списке «комбинации» код сначала проверяет значение «c», если оно не равно переменной «count», то продолжит работу, иначе цикл прервется.

Для первых двух слоев мне пришлось жестко закодировать их пути, я уверен, что есть лучший способ сделать это, но я не мог его понять. Помимо первых двух слоев, другие слои загружаются один за другим и объединяются с ранее объединенными слоями.

Индекс каждого элемента в списке «комбинаций» используется в качестве имени файла как для файла изображения, так и для файла json. Нам нужен список «layers_names» для метаданных. Каждый элемент в этом списке представляет атрибут изображения, значением которого является имя файла, представляющего этот вариант в соответствующем слое. Поэтому каждая вариация в папке каждого слоя должна называться соответствующим образом, поскольку она будет включена в метаданные. Изображения сохраняются в папке «images», а файлы метаданных сохраняются в папке «metadata».

Код, скорее всего, не будет отображаться с соответствующим отступом, поэтому не стесняйтесь проверить Блокнот Jupyter. Как уже говорилось ранее, мой код может быть детским, но я здесь, чтобы учиться, и ваши отзывы, безусловно, помогут мне стать лучше. Спасибо, что дочитали до этого места! По ходу работы над своим проектом я буду делиться тем, что узнаю.

Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.