Skip to content

Commit dddf5b4

Browse files
authored
Merge pull request #284 from HashLips/dev
Update
2 parents f04b036 + 41709e0 commit dddf5b4

5 files changed

Lines changed: 203 additions & 17 deletions

File tree

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v16.13.0

README.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ const pixelFormat = {
266266
};
267267
```
268268

269-
### Generate pixelated images from collection
269+
### Generate GIF images from collection
270270

271271
In order to export gifs based on the layers created, you just need to set the export on the `gif` object in the `src/config.js` file to `true`. You can also play around with the `repeat`, `quality` and the `delay` of the exported gif.
272272

@@ -292,15 +292,22 @@ npm run rarity
292292
The output will look something like this:
293293

294294
```sh
295-
Trait type: Bottom lid
296-
{ trait: 'High', chance: '20', occurrence: '15% out of 100%' }
297-
{ trait: 'Low', chance: '40', occurrence: '40% out of 100%' }
298-
{ trait: 'Middle', chance: '40', occurrence: '45% out of 100%' }
299-
300-
Trait type: Iris
301-
{ trait: 'Large', chance: '20', occurrence: '15% out of 100%' }
302-
{ trait: 'Medium', chance: '20', occurrence: '15% out of 100%' }
303-
{ trait: 'Small', chance: '60', occurrence: '70% out of 100%' }
295+
Trait type: Top lid
296+
{
297+
trait: 'High',
298+
chance: '30',
299+
occurrence: '3 in 20 editions (15.00 %)'
300+
}
301+
{
302+
trait: 'Low',
303+
chance: '20',
304+
occurrence: '3 in 20 editions (15.00 %)'
305+
}
306+
{
307+
trait: 'Middle',
308+
chance: '50',
309+
occurrence: '14 in 20 editions (70.00 %)'
310+
}
304311
```
305312

306313
Hope you create some awesome artworks with this code 👄

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"preview": "node utils/preview.js",
1919
"pixelate": "node utils/pixelate.js",
2020
"update_info": "node utils/update_info.js",
21-
"preview_gif": "node utils/preview_gif.js"
21+
"preview_gif": "node utils/preview_gif.js",
22+
"generate_metadata": "node utils/generate_metadata.js"
2223
},
2324
"author": "Daniel Eugene Botha (HashLips)",
2425
"license": "MIT",

utils/generate_metadata.js

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
const fs = require("fs");
2+
const path = require("path");
3+
const { createCanvas, loadImage } = require("canvas");
4+
const basePath = process.cwd();
5+
const buildDir = `${basePath}/build/json`;
6+
const inputDir = `${basePath}/build/images`;
7+
const {
8+
format,
9+
namePrefix,
10+
description,
11+
baseUri,
12+
} = require(`${basePath}/src/config.js`);
13+
const console = require("console");
14+
const canvas = createCanvas(format.width, format.height);
15+
const ctx = canvas.getContext("2d");
16+
const metadataList = [];
17+
18+
const buildSetup = () => {
19+
if (fs.existsSync(buildDir)) {
20+
fs.rmdirSync(buildDir, { recursive: true });
21+
}
22+
fs.mkdirSync(buildDir);
23+
};
24+
25+
const getImages = (_dir) => {
26+
try {
27+
return fs
28+
.readdirSync(_dir)
29+
.filter((item) => {
30+
let extension = path.extname(`${_dir}${item}`);
31+
if (extension == ".png" || extension == ".jpg") {
32+
return item;
33+
}
34+
})
35+
.map((i) => {
36+
return {
37+
filename: i,
38+
path: `${_dir}/${i}`,
39+
};
40+
});
41+
} catch {
42+
return null;
43+
}
44+
};
45+
46+
const loadImgData = async (_imgObject) => {
47+
return new Promise(async (resolve) => {
48+
const image = await loadImage(`${_imgObject.path}`);
49+
resolve({ imgObject: _imgObject, loadedImage: image });
50+
});
51+
};
52+
53+
const draw = (_imgObject) => {
54+
let w = canvas.width;
55+
let h = canvas.height;
56+
ctx.drawImage(_imgObject.loadedImage, 0, 0, w, h);
57+
};
58+
59+
const addRarity = () => {
60+
let w = canvas.width;
61+
let h = canvas.height;
62+
let i = -4;
63+
let count = 0;
64+
let imgdata = ctx.getImageData(0, 0, w, h);
65+
let rgb = imgdata.data;
66+
let newRgb = { r: 0, g: 0, b: 0 };
67+
const tolerance = 15;
68+
const rareColorBase = "NOT a Hot Dog";
69+
const rareColor = [
70+
{ name: "Hot Dog", rgb: { r: 192, g: 158, b: 131 } },
71+
{ name: "Hot Dog", rgb: { r: 128, g: 134, b: 90 } },
72+
{ name: "Hot Dog", rgb: { r: 113, g: 65, b: 179 } },
73+
{ name: "Hot Dog", rgb: { r: 162, g: 108, b: 67 } },
74+
];
75+
76+
while ((i += 10 * 4) < rgb.length) {
77+
++count;
78+
newRgb.r += rgb[i];
79+
newRgb.g += rgb[i + 1];
80+
newRgb.b += rgb[i + 2];
81+
}
82+
83+
newRgb.r = ~~(newRgb.r / count);
84+
newRgb.g = ~~(newRgb.g / count);
85+
newRgb.b = ~~(newRgb.b / count);
86+
87+
let rarity = rareColorBase;
88+
89+
rareColor.forEach((color) => {
90+
if (isNeighborColor(newRgb, color.rgb, tolerance)) {
91+
rarity = color.name;
92+
}
93+
});
94+
95+
console.log(newRgb);
96+
console.log(rarity);
97+
98+
return [
99+
{
100+
trait_type: "average color",
101+
value: `rgb(${newRgb.r},${newRgb.g},${newRgb.b})`,
102+
},
103+
{
104+
trait_type: "What is this?",
105+
value: rarity,
106+
},
107+
{
108+
trait_type: "date",
109+
value: randomIntFromInterval(1500, 1900),
110+
},
111+
];
112+
};
113+
114+
randomIntFromInterval = (min, max) => {
115+
return Math.floor(Math.random() * (max - min + 1) + min);
116+
};
117+
118+
isNeighborColor = (color1, color2, tolerance) => {
119+
return (
120+
Math.abs(color1.r - color2.r) <= tolerance &&
121+
Math.abs(color1.g - color2.g) <= tolerance &&
122+
Math.abs(color1.b - color2.b) <= tolerance
123+
);
124+
};
125+
126+
const saveMetadata = (_loadedImageObject) => {
127+
let shortName = _loadedImageObject.imgObject.filename.replace(
128+
/\.[^/.]+$/,
129+
""
130+
);
131+
132+
let tempAttributes = [];
133+
tempAttributes.push(addRarity());
134+
135+
let tempMetadata = {
136+
name: `${namePrefix} #${shortName}`,
137+
description: description,
138+
image: `${baseUri}/${shortName}.png`,
139+
edition: Number(shortName),
140+
attributes: tempAttributes,
141+
compiler: "HashLips Art Engine",
142+
};
143+
fs.writeFileSync(
144+
`${buildDir}/${shortName}.json`,
145+
JSON.stringify(tempMetadata, null, 2)
146+
);
147+
metadataList.push(tempMetadata);
148+
};
149+
150+
const writeMetaData = (_data) => {
151+
fs.writeFileSync(`${buildDir}/_metadata.json`, _data);
152+
};
153+
154+
const startCreating = async () => {
155+
const images = getImages(inputDir);
156+
if (images == null) {
157+
console.log("Please generate collection first.");
158+
return;
159+
}
160+
let loadedImageObjects = [];
161+
images.forEach((imgObject) => {
162+
loadedImageObjects.push(loadImgData(imgObject));
163+
});
164+
await Promise.all(loadedImageObjects).then((loadedImageObjectArray) => {
165+
loadedImageObjectArray.forEach((loadedImageObject) => {
166+
draw(loadedImageObject);
167+
saveMetadata(loadedImageObject);
168+
console.log(
169+
`Created metadata for image: ${loadedImageObject.imgObject.filename}`
170+
);
171+
});
172+
});
173+
writeMetaData(JSON.stringify(metadataList, null, 2));
174+
};
175+
176+
buildSetup();
177+
startCreating();

utils/rarity.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ layerConfigurations.forEach((config) => {
2525
// just get name and weight for each element
2626
let rarityDataElement = {
2727
trait: element.name,
28-
chance: element.weight.toFixed(0),
28+
weight: element.weight.toFixed(0),
2929
occurrence: 0, // initialize at 0
3030
};
3131
elementsForLayer.push(rarityDataElement);
@@ -59,16 +59,16 @@ data.forEach((element) => {
5959
});
6060
});
6161

62-
// convert occurrences to percentages
62+
// convert occurrences to occurence string
6363
for (var layer in rarityData) {
6464
for (var attribute in rarityData[layer]) {
65-
// convert to percentage
66-
rarityData[layer][attribute].occurrence =
67-
(rarityData[layer][attribute].occurrence / editionSize) * 100;
65+
// get chance
66+
let chance =
67+
((rarityData[layer][attribute].occurrence / editionSize) * 100).toFixed(2);
6868

6969
// show two decimal places in percent
7070
rarityData[layer][attribute].occurrence =
71-
rarityData[layer][attribute].occurrence.toFixed(0) + "% out of 100%";
71+
`${rarityData[layer][attribute].occurrence} in ${editionSize} editions (${chance} %)`;
7272
}
7373
}
7474

0 commit comments

Comments
 (0)