Skip to content

Commit

Permalink
Merge pull request exiled-apes#109 from HashLips/dev
Browse files Browse the repository at this point in the history
Updated
  • Loading branch information
HashLips authored Oct 15, 2021
2 parents c0e4b7d + ba395a0 commit 1e3fa1a
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 66 deletions.
46 changes: 34 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ You can mix up the `layerConfigurations` order on how the images are saved by se

If you want to have logs to debug and see what is happening when you generate images you can set the variable `debugLogs` in the `config.js` file to true. It is false by default, so you will only see general logs.

If you want to play around with different blending modes, you can add a `blend: MODE.colorBurn` field to the layersOrder object. If you need a layers to have a different opacity then you can add the `opacity: 0.7` field to the layersOrder object as well. Both the `blend: MODE.colorBurn` and `opacity: 0.7` can be addes on the same layer if you want to.
If you want to play around with different blending modes, you can add a `blend: MODE.colorBurn` field to the layersOrder `options` object.

If you need a layers to have a different opacity then you can add the `opacity: 0.7` field to the layersOrder `options` object as well.

To use a different metadata attribute name you can add the `displayName: "Awesome Eye Color"` to the `options` object. All options are optional and can be addes on the same layer if you want to.

Here is an example on how you can play around with both filter fields:

Expand All @@ -118,11 +122,18 @@ const layerConfigurations = [
layersOrder: [
{ name: "Background" },
{ name: "Eyeball" },
{ name: "Eye color", blend: MODE.colorBurn },
{
name: "Eye color",
options: {
blend: MODE.destinationIn,
opcacity: 0.2,
displayName: "Awesome Eye Color",
},
},
{ name: "Iris" },
{ name: "Shine" },
{ name: "Bottom lid", blend: MODE.overlay, opacity: 0.7 },
{ name: "Top lid", opacity: 0.7 },
{ name: "Bottom lid", options: { blend: MODE.overlay, opacity: 0.7 } },
{ name: "Top lid" },
],
},
];
Expand Down Expand Up @@ -214,36 +225,47 @@ That's it, you're done.

## Utils

### Updating baseUri for IPFS
### Updating baseUri for IPFS and description

You might possibly want to update the baseUri after you have ran your collection. To update the baseUri simply run:
You might possibly want to update the baseUri and description after you have ran your collection. To update the baseUri and description simply run:

```sh
node utils/updateBaseUri.js
npm run update_info
```

### Generate a preview image

Create a preview image collage of your collection, run:

```sh
node utils/createPreviewCollage.js
npm run preview
```

### Re-generate the \_metadata.json file
### Generate pixelated images from collection

This util will only work if you have all the individual json files and want to re-generate the \_metadata.json file if you lost it, run:
In order to convert images into pixelated images you would need a list of images that you want to convert. So run the generator first.

Then simply run this command:

```sh
node utils/regenerateMetadata.js
npm run pixelate
```

All your images will be outputted in the `/build/pixel_images` directory.
If you want to change the ratio of the pixelation then you can update the ratio property on the `pixelFormat` object in the `src/config.js` file. The lower the number on the left, the more pixelated the image will be.

```js
const pixelFormat = {
ratio: 5 / 128,
};
```

### Printing rarity data (Experimental feature)

To see the percentages of each attribute across your collection, run:

```sh
node utils/rarityData.js
npm run rarity
```

The output will look something like this:
Expand Down
File renamed without changes.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
},
"scripts": {
"build": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
"generate": "node index.js",
"rarity": "node utils/rarity.js",
"preview": "node utils/preview.js",
"pixelate": "node utils/pixelate.js",
"update_info": "node utils/update_info.js"
},
"author": "Daniel Eugene Botha (HashLips)",
"license": "MIT",
Expand Down
25 changes: 23 additions & 2 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
const path = require("path");
const isLocal = typeof process.pkg === "undefined";
const basePath = isLocal ? process.cwd() : path.dirname(process.execPath);
const { MODE } = require(path.join(basePath, "src/blendMode.js"));
const { MODE } = require(path.join(basePath, "constants/blend_mode.js"));
const description =
"This is the description of your NFT project, remember to replace this";
const baseUri = "ipfs://NewUriToReplace";

const layerConfigurations = [
{
growEditionSizeTo: 10,
growEditionSizeTo: 5,
layersOrder: [
{ name: "Background" },
{ name: "Eyeball" },
Expand All @@ -32,9 +32,28 @@ const format = {
height: 512,
};

const text = {
only: false,
color: "#ffffff",
size: 20,
xGap: 40,
yGap: 40,
align: "left",
baseline: "top",
weight: "regular",
family: "Courier",
spacer: " => ",
};

const pixelFormat = {
ratio: 2 / 128,
};

const background = {
generate: true,
brightness: "80%",
static: false,
default: "#000000",
};

const extraMetadata = {};
Expand Down Expand Up @@ -62,4 +81,6 @@ module.exports = {
shuffleLayerConfigurations,
debugLogs,
extraMetadata,
pixelFormat,
text,
};
64 changes: 49 additions & 15 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const { createCanvas, loadImage } = require(path.join(
));
const buildDir = path.join(basePath, "/build");
const layersDir = path.join(basePath, "/layers");
console.log(path.join(basePath, "/src/config.js"));
const {
format,
baseUri,
Expand All @@ -23,13 +22,14 @@ const {
shuffleLayerConfigurations,
debugLogs,
extraMetadata,
text,
} = require(path.join(basePath, "/src/config.js"));
const canvas = createCanvas(format.width, format.height);
const ctx = canvas.getContext("2d");
var metadataList = [];
var attributesList = [];
var dnaList = new Set();
const DNA_DELIMITER = '-';
const DNA_DELIMITER = "-";

const buildSetup = () => {
if (fs.existsSync(buildDir)) {
Expand Down Expand Up @@ -80,11 +80,19 @@ const getElements = (path) => {
const layersSetup = (layersOrder) => {
const layers = layersOrder.map((layerObj, index) => ({
id: index,
name: layerObj.name,
elements: getElements(`${layersDir}/${layerObj.name}/`),
blendMode:
layerObj["blend"] != undefined ? layerObj["blend"] : "source-over",
opacity: layerObj["opacity"] != undefined ? layerObj["opacity"] : 1,
name:
layerObj.options?.["displayName"] != undefined
? layerObj.options?.["displayName"]
: layerObj.name,
blend:
layerObj.options?.["blend"] != undefined
? layerObj.options?.["blend"]
: "source-over",
opacity:
layerObj.options?.["opacity"] != undefined
? layerObj.options?.["opacity"]
: 1,
}));
return layers;
};
Expand All @@ -103,7 +111,7 @@ const genColor = () => {
};

const drawBackground = () => {
ctx.fillStyle = genColor();
ctx.fillStyle = background.static ? background.default : genColor();
ctx.fillRect(0, 0, format.width, format.height);
};

Expand Down Expand Up @@ -139,29 +147,51 @@ const loadLayerImg = async (_layer) => {
});
};

const drawElement = (_renderObject) => {
const addText = (_sig, x, y, size) => {
ctx.fillStyle = text.color;
ctx.font = `${text.weight} ${size}pt ${text.family}`;
ctx.textBaseline = text.baseline;
ctx.textAlign = text.align;
ctx.fillText(_sig, x, y);
};

const drawElement = (_renderObject, _index, _layersLen) => {
ctx.globalAlpha = _renderObject.layer.opacity;
ctx.globalCompositeOperation = _renderObject.layer.blendMode;
ctx.drawImage(_renderObject.loadedImage, 0, 0, format.width, format.height);
ctx.globalCompositeOperation = _renderObject.layer.blend;
text.only
? addText(
`${_renderObject.layer.name}${text.spacer}${_renderObject.layer.selectedElement.name}`,
text.xGap,
text.yGap * (_index + 1),
text.size
)
: ctx.drawImage(
_renderObject.loadedImage,
0,
0,
format.width,
format.height
);

addAttributes(_renderObject);
};

const constructLayerToDna = (_dna = '', _layers = []) => {
const constructLayerToDna = (_dna = "", _layers = []) => {
let mappedDnaToLayers = _layers.map((layer, index) => {
let selectedElement = layer.elements.find(
(e) => e.id == cleanDna(_dna.split(DNA_DELIMITER)[index])
);
return {
name: layer.name,
blendMode: layer.blendMode,
blend: layer.blend,
opacity: layer.opacity,
selectedElement: selectedElement,
};
});
return mappedDnaToLayers;
};

const isDnaUnique = (_DnaList = new Set(), _dna = '') => {
const isDnaUnique = (_DnaList = new Set(), _dna = "") => {
return !_DnaList.has(_dna);
};

Expand Down Expand Up @@ -258,8 +288,12 @@ const startCreating = async () => {
if (background.generate) {
drawBackground();
}
renderObjectArray.forEach((renderObject) => {
drawElement(renderObject);
renderObjectArray.forEach((renderObject, index) => {
drawElement(
renderObject,
index,
layerConfigurations[layerConfigIndex].layersOrder.length
);
});
debugLogs
? console.log("Editions left to create: ", abstractedIndexes)
Expand Down
84 changes: 84 additions & 0 deletions utils/pixelate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const fs = require("fs");
const path = require("path");
const { createCanvas, loadImage } = require("canvas");
const isLocal = typeof process.pkg === "undefined";
const basePath = isLocal ? process.cwd() : path.dirname(process.execPath);
const buildDir = `${basePath}/build/pixel_images`;
const inputDir = `${basePath}/build/images`;
const { format, pixelFormat } = require(path.join(basePath, "/src/config.js"));
const console = require("console");
const canvas = createCanvas(format.width, format.height);
const ctx = canvas.getContext("2d");

const buildSetup = () => {
if (fs.existsSync(buildDir)) {
fs.rmdirSync(buildDir, { recursive: true });
}
fs.mkdirSync(buildDir);
};

const getImages = (_dir) => {
try {
return fs
.readdirSync(_dir)
.filter((item) => {
let extension = path.extname(`${_dir}${item}`);
if (extension == ".png" || extension == ".jpg") {
return item;
}
})
.map((i) => {
return {
filename: i,
path: `${_dir}/${i}`,
};
});
} catch {
return null;
}
};

const loadImgData = async (_imgObject) => {
return new Promise(async (resolve) => {
const image = await loadImage(`${_imgObject.path}`);
resolve({ imgObject: _imgObject, loadedImage: image });
});
};

const draw = (_imgObject) => {
let size = pixelFormat.ratio;
let w = canvas.width * size;
let h = canvas.height * size;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(_imgObject.loadedImage, 0, 0, w, h);
ctx.drawImage(canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
};

const saveImage = (_loadedImageObject) => {
fs.writeFileSync(
`${buildDir}/${_loadedImageObject.imgObject.filename}`,
canvas.toBuffer("image/png")
);
};

const startCreating = async () => {
const images = getImages(inputDir);
if (images == null) {
console.log("Please generate collection first.");
return;
}
let loadedImageObjects = [];
images.forEach((imgObject) => {
loadedImageObjects.push(loadImgData(imgObject));
});
await Promise.all(loadedImageObjects).then((loadedImageObjectArray) => {
loadedImageObjectArray.forEach((loadedImageObject) => {
draw(loadedImageObject);
saveImage(loadedImageObject);
console.log(`Pixelated image: ${loadedImageObject.imgObject.filename}`);
});
});
};

buildSetup();
startCreating();
File renamed without changes.
Loading

0 comments on commit 1e3fa1a

Please sign in to comment.