Skip to content

Commit

Permalink
Adding Weighted Image Randomizer feature
Browse files Browse the repository at this point in the history
  • Loading branch information
ptedeschi committed Sep 15, 2021
1 parent a36c310 commit c2d7b7e
Show file tree
Hide file tree
Showing 23 changed files with 149 additions and 32 deletions.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,25 @@ There are many amazing projects that help in creating generative art, but they a
That's why we created the NFT<area>.net project.
An application developed with .NET Core to generate NFT's through a graphical interface. Simple as that, in the best Grab & Go style.

# Features

- Multiple layers
- Metadata generation (Individual and Merged)
- Weighted Image Randomizer
- No coding skills required

# How to start
Download the most recent release version [here](https://github.com/ptedeschi/NFT.net/releases) and execute it.
> Despite the fact that it was thought to work cross-platform, the WinForms application in .NET Core seems to rely solely on Windows at the moment. If there is interest from the community, we can consider alternative solutions to allow use on other platforms.
> You may need to install .NET Runtime. If necessary, you can find it [here](https://dotnet.microsoft.com/download/dotnet/5.0/runtime?initial-os=windows)
> The release already includes the .NET Runtime but if needed, you can find it [here](https://dotnet.microsoft.com/download/dotnet/5.0/runtime?initial-os=windows)
# How it works
Once you run the tool, you will need to select the folder where the NFT layers are located. Next, you will need to provide the output folder where the generated images and metadata will be saved.

After that, you can press the Generate button or you can customize some settings such as the Collection Size, Initial numbers, filename prefix etc.

![enter image description here](https://i.postimg.cc/qMVNBVPN/screenshot.png)
![enter image description here](https://user-images.githubusercontent.com/6684508/133380651-e08d5972-9897-4095-9d0d-e8da84164b8d.PNG)

The most important idea here is to make sure you are using the tool, respecting some rules for the layer and elements:

Expand All @@ -41,7 +48,24 @@ For example:
#### Layer elements (*trait values*)
All images used to create the NFT MUST have the same dimensions (width and height). Subfolders are not supported.

> There is no strict rule for naming layer elements, but this name will be used to populate Metadata *attribute* values
If you want to add weighting ability to your images, you can do so by adding weight as a suffix to the image filename.

Imagine the scenario where you have a hat layer and support 5 different hat colors.
This is how you can weigh them:

- hat_red+1.png
- hat_orange+3.png
- hat_yellow+3.png
- hat_green+4.png
- hat_blue+4.png

By using the plus sign (+) and a number, you are telling NFT<area>.net the chances to choose images.

In this case, red has 20% (1/5).
Orange and yellow have 60% (3/5).
And green and blue have 80% (4/5).

> If no weight is defined in the suffix, the total number of files present in the layers folder will be used as weight so that in the end the result is 100%
# Projects
- [Il Pinguino](https://opensea.io/collection/ilpinguino)
Expand Down
21 changes: 21 additions & 0 deletions dependencies/Weighted Randomizer/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2013 Daniel "BlueRaja" Pflughoeft

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
3 changes: 3 additions & 0 deletions dependencies/Weighted Randomizer/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This library was developed by BlueRaja.
The original code can be found here https://github.com/BlueRaja/Weighted-Item-Randomizer-for-C-Sharp.
As there is a bug in the officially distributed NuGet package, it was necessary to compile this library manually and reference the generated dll.
Binary file not shown.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
1 change: 1 addition & 0 deletions src/NFT.net/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Tedeschi.NFT
public static class Constants
{
public const char LayerNamingDelimiter = '-';
public const char WeightDelimiter = '+';
public const int MaxDuplicateDnaRetries = 100;

public static class About
Expand Down
10 changes: 5 additions & 5 deletions src/NFT.net/Helper/CollectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Tedeschi.NFT.Helper

public class CollectionHelper
{
public static void Create(string layersFolder, string outputFolder, int metadataType, string metadataProjectName, string metadataImageBaseUri, int collectionSize, int collectionInitialNumber, string collectionFilenamePrefix)
public static void Create(string layersFolder, string outputFolder, int metadataType, string metadataDescription, string metadataImageBaseUri, int collectionSize, int collectionInitialNumber, string collectionImagePrefix)
{
var layers = LayerHelper.Load(layersFolder);

Expand All @@ -27,18 +27,18 @@ public static void Create(string layersFolder, string outputFolder, int metadata
var filename = $"{collectionNumber}{Constants.FileExtension.Png}";
var filenameWithoutExtension = $"{collectionNumber}";

if (!string.IsNullOrWhiteSpace(collectionFilenamePrefix))
if (!string.IsNullOrWhiteSpace(collectionImagePrefix))
{
filename = $"{collectionFilenamePrefix}{collectionNumber}{Constants.FileExtension.Png}";
filenameWithoutExtension = $"{collectionFilenamePrefix}{collectionNumber}";
filename = $"{collectionImagePrefix}{collectionNumber}{Constants.FileExtension.Png}";
filenameWithoutExtension = $"{collectionImagePrefix}{collectionNumber}";
}

var metadata = new Metadata
{
Id = collectionNumber,
Dna = item.Dna,
Name = filenameWithoutExtension,
Description = metadataProjectName,
Description = metadataDescription,
Image = $"{metadataImageBaseUri}/{System.Uri.EscapeDataString(filename)}",
Attributes = item.Attributes.Select(i => new Attribute { Layer = i.Layer, Value = i.Value }).ToList(),
};
Expand Down
4 changes: 1 addition & 3 deletions src/NFT.net/Helper/GeneratorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace Tedeschi.NFT.Helper

public class GeneratorHelper
{
private static readonly Random Random = new Random();

public static List<ImageDescriptor> Create(List<Layer> layers, int collectionSize)
{
var images = new List<ImageDescriptor>();
Expand Down Expand Up @@ -60,7 +58,7 @@ private static ImageDescriptor UniqueImage(List<Layer> layers)

foreach (var layer in layers)
{
var index = Random.Next(0, layer.Elements.Count);
var index = layer.Randomizer.NextWithReplacement();

var attribute = new ImageAttribute
{
Expand Down
17 changes: 17 additions & 0 deletions src/NFT.net/Helper/LayerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Tedeschi.NFT.Helper
using Tedeschi.NFT.Exception;
using Tedeschi.NFT.Model;
using Tedeschi.NFT.Util;
using Weighted_Randomizer;

public class LayerHelper
{
Expand All @@ -19,6 +20,7 @@ public static List<Layer> Load(string path)

for (var i = 0; i < folders.Length; i++)
{
var randomizer = new DynamicWeightedRandomizer<int>();
var folder = folders[i];
var folderName = Path.GetFileName(folder);

Expand All @@ -36,15 +38,29 @@ public static List<Layer> Load(string path)
{
var file = files[j];
var filename = Path.GetFileNameWithoutExtension(file);

// If the filename has Weight information, extract it.
// Otherwise use Weight as the number of files present to represent 100%.
var weight = files.Length;

if (StringUtil.HasWeight(filename, Constants.WeightDelimiter))
{
weight = StringUtil.GetWeight(filename, Constants.WeightDelimiter);
filename = StringUtil.GetNameWithoutWeight(filename, Constants.WeightDelimiter);
}

var convertedCaseFilename = StringUtil.ToTitleCase(filename);

var element = new Element
{
Id = j,
Name = convertedCaseFilename,
Path = file,
Weight = weight,
};

randomizer.Add(element.Id, element.Weight);

elements.Add(element);
}

Expand All @@ -62,6 +78,7 @@ public static List<Layer> Load(string path)
Id = i,
Name = convertedCaseFolderName,
Elements = elements,
Randomizer = randomizer,
};

layers.Add(layer);
Expand Down
2 changes: 2 additions & 0 deletions src/NFT.net/Model/Element.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ public class Element
public string Name { get; set; }

public string Path { get; set; }

public int Weight { get; set; }
}
}
3 changes: 3 additions & 0 deletions src/NFT.net/Model/Layer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Tedeschi.NFT.Model
{
using System.Collections.Generic;
using Weighted_Randomizer;

public class Layer
{
Expand All @@ -13,5 +14,7 @@ public class Layer
public string Name { get; set; }

public List<Element> Elements { get; set; }

public IWeightedRandomizer<int> Randomizer { get; set; }
}
}
10 changes: 8 additions & 2 deletions src/NFT.net/NFT.net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RunTimeIdentifiers>win10-x64;osx.10.12-x64</RunTimeIdentifiers>
<RunTimeIdentifiers>win10-x64</RunTimeIdentifiers>
<UseWindowsForms>true</UseWindowsForms>
<RootNamespace>Tedeschi.NFT</RootNamespace>
<AssemblyName>NFT.net</AssemblyName>
<Version>0.0.9</Version>
<Version>1.0.0</Version>
<Authors>Tedeschi</Authors>
</PropertyGroup>

Expand All @@ -20,6 +20,12 @@
<AdditionalFiles Include="stylecop.json" />
</ItemGroup>

<ItemGroup>
<Reference Include="Weighted Randomizer Net Standard">
<HintPath>..\..\dependencies\Weighted Randomizer\Weighted Randomizer Net Standard.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup>
<Compile Update="Resources\Resource.Designer.cs">
<DesignTime>True</DesignTime>
Expand Down
40 changes: 40 additions & 0 deletions src/NFT.net/Util/StringUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,45 @@ public static string GetName(string file, char delimiter)

return file.Substring(index + 1);
}

public static bool HasWeight(string filename, char delimiter)
{
try
{
var index = filename.LastIndexOf(delimiter);
var weight = filename.Substring(index + 1);

int.Parse(weight);

return true;
}
catch
{
return false;
}
}

public static string GetNameWithoutWeight(string filename, char delimiter)
{
try
{
var index = filename.LastIndexOf(delimiter);
var nameWithoutWeight = filename.Substring(0, index);

return nameWithoutWeight;
}
catch
{
return filename;
}
}

public static int GetWeight(string filename, char delimiter)
{
var index = filename.LastIndexOf(delimiter);
var weight = filename.Substring(index + 1);

return int.Parse(weight);
}
}
}
28 changes: 14 additions & 14 deletions src/NFT.net/View/MainForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c2d7b7e

Please sign in to comment.