From 14b07d18386e58cf218b5c880a3a5a301d945766 Mon Sep 17 00:00:00 2001 From: Jonathan Becker <64037729+Jon-Becker@users.noreply.github.com> Date: Mon, 2 May 2022 14:32:22 -0400 Subject: [PATCH] v2.0.0 - Added external configuration file support ( #35 ) - Implemented argparse (BREAKING CHANGE)! --- .gitignore | 1 + README.md | 11 ++++++++ config.json | 35 +++++++++++++++++++++++++ index.py => generate.py | 57 ++++++++++++++++------------------------- lib/__init__.py | 0 lib/util/__init__.py | 0 lib/util/io.py | 10 ++++++++ requirements.txt | 1 + 8 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 config.json rename index.py => generate.py (80%) create mode 100644 lib/__init__.py create mode 100644 lib/util/__init__.py create mode 100644 lib/util/io.py diff --git a/.gitignore b/.gitignore index 6b00d0a..56c6047 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ workspace.code-workspace metadata/*.json images/*.png .ipynb_checkpoints/ +*.pyc diff --git a/README.md b/README.md index 44a0831..a868350 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,17 @@ nft-generator-py is a python based NFT generator which programatically generates unique images using weighted layer files. The program is simple to use, and new layers can be added by adding a new layer object and adding names, weights, and image files to the object. You can [View The Demo](https://jbecker.dev/demos/nft-generator-py) here. +## Usage +As of v2.0.0, nft-generator-py will use the argparse library in order to support external configuration files and won't require users to interact with the python files themselves. + +1. Install requirements: `python3 -m pip install -r requirements.txt` +2. Make a configuration JSON file. See the configuration section below for specifications. +3. Add layer files into the `/images` folder. +4. Run the command `python3 generate.py --amount AMOUNT --config CONFIG` + + where: + 1. `AMOUNT` is the amount of images to generate + 2. `CONFIG` is the path pointing to a `.json` file containing valid program configuration. ## How it works - A call to `generate_unique_images(amount, config)` is made, which is the meat of the application where all the processing happens. diff --git a/config.json b/config.json new file mode 100644 index 0000000..7493bf7 --- /dev/null +++ b/config.json @@ -0,0 +1,35 @@ +{ + "layers": [ + { + "name": "Background", + "values": ["Blue", "Orange", "Purple", "Red", "Yellow"], + "trait_path": "./trait-layers/backgrounds", + "filename": ["blue", "orange", "purple", "red", "yellow"], + "weights": [20,20,20,20,20] + }, + { + "name": "Foreground", + "values": ["Python Logo", "Python Logo 32"], + "trait_path": "./trait-layers/foreground", + "filename": ["logo", "logo"], + "weights": [50, 50] + }, + { + "name": "Branding", + "values": ["A Name", "Another Name"], + "trait_path": "./trait-layers/text", + "filename": ["text", "text"], + "weights": [50, 50] + } + ], + "incompatibilities": [ + { + "layer": "Background", + "value": "Blue", + "incompatible_with": ["Python Logo 2"] + } + ], + "baseURI": ".", + "name": "NFT #", + "description": "This is a description for this NFT series." +} \ No newline at end of file diff --git a/index.py b/generate.py similarity index 80% rename from index.py rename to generate.py index 255d966..8efe2ca 100644 --- a/index.py +++ b/generate.py @@ -1,9 +1,12 @@ from IPython.display import display from PIL import Image +import argparse import random import json import os +from lib.util.io import loadJSON, pathExists + os.system('cls' if os.name=='nt' else 'clear') def create_new_image(all_images, config): @@ -100,41 +103,25 @@ def generate_unique_images(amount, config): with open('./metadata/' + str(item["tokenId"]) + '.json', 'w') as outfile: json.dump(original_json, outfile, indent=4) -generate_unique_images(11, { - "layers": [ - { - "name": "Background", - "values": ["Blue", "Orange", "Purple", "Red", "Yellow"], - "trait_path": "./trait-layers/backgrounds", - "filename": ["blue", "orange", "purple", "red", "yellow"], - "weights": [20,20,20,20,20] - }, - { - "name": "Foreground", - "values": ["Python Logo", "Python Logo 32"], - "trait_path": "./trait-layers/foreground", - "filename": ["logo", "logo"], - "weights": [50, 50] - }, - { - "name": "Branding", - "values": ["A Name", "Another Name"], - "trait_path": "./trait-layers/text", - "filename": ["text", "text"], - "weights": [50, 50] - } - ], - "incompatibilities": [ - { - "layer": "Background", - "value": "Blue", - "incompatible_with": ["Python Logo 2"] - }, # @dev : Blue backgrounds will never have the attribute "Python Logo 2". - ], - "baseURI": ".", - "name": "NFT #", - "description": "This is a description for this NFT series." -}) + #Additional layer objects can be added following the above formats. They will automatically be composed along with the rest of the layers as long as they are the same size as eachother. #Objects are layered starting from 0 and increasing, meaning the front layer will be the last object. (Branding) + + +generator = argparse.ArgumentParser(prog='generate', usage='generate.py [options]') + +generator.add_argument('-n', '--amount', help="Amount to generate") +generator.add_argument('-c', '--config', help="Path to configuration file") + +args = generator.parse_args() + +if args.amount and args.config: + if pathExists(args.config): + generate_unique_images(int(args.amount), loadJSON(args.config)) + else: + print('heimdall: error: Configuration file specified doesn\'t exist.\n') + +else: + print('heimdall: error: Missing a mandatory option (-n or -c). Use -h to show the help menu.\n') +#generate_unique_images(args.amo, ) \ No newline at end of file diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/util/__init__.py b/lib/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/util/io.py b/lib/util/io.py new file mode 100644 index 0000000..90d014b --- /dev/null +++ b/lib/util/io.py @@ -0,0 +1,10 @@ +import os +import json + +def pathExists(dirPath): + return os.path.exists(dirPath) + +def loadJSON(path): + with open(path) as pathFile: + contents = json.loads("".join(pathFile.readlines())) + return contents \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 6307449..d229533 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ ptyprocess==0.7.0 Pygments==2.11.0 traitlets==5.1.1 wcwidth==0.2.5 +argparse==1.4.0