From 5f897021e575b34dabbfa0341dd80c68ca9db5b1 Mon Sep 17 00:00:00 2001 From: hashlips Date: Sun, 24 Oct 2021 12:30:09 +0200 Subject: [PATCH] Added gif export --- README.md | 15 +++++++++++++++ modules/HashlipsGiffer.js | 38 ++++++++++++++++++++++++++++++++++++++ package-lock.json | 7 ++++++- package.json | 3 ++- src/config.js | 10 +++++++++- src/main.js | 27 +++++++++++++++++++++++++++ yarn.lock | 5 +++++ 7 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 modules/HashlipsGiffer.js diff --git a/README.md b/README.md index 0bee7278a..ca7aece86 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,21 @@ const pixelFormat = { }; ``` +### Generate pixelated images from collection + +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. + +Setting the `repeat: -1` will produce a one time render and `repeat: 0` will loop forever. + +```js +const gif = { + export: true, + repeat: 0, + quality: 100, + delay: 500, +}; +``` + ### Printing rarity data (Experimental feature) To see the percentages of each attribute across your collection, run: diff --git a/modules/HashlipsGiffer.js b/modules/HashlipsGiffer.js new file mode 100644 index 000000000..c7b477edd --- /dev/null +++ b/modules/HashlipsGiffer.js @@ -0,0 +1,38 @@ +const GifEncoder = require("gif-encoder-2"); +const { writeFile } = require("fs"); + +class HashLipsGiffer { + constructor(_canvas, _ctx, _fileName, _repeat, _quality, _delay) { + this.canvas = _canvas; + this.ctx = _ctx; + this.fileName = _fileName; + this.repeat = _repeat; + this.quality = _quality; + this.delay = _delay; + this.initGifEncoder(); + } + + initGifEncoder = () => { + this.gifEncoder = new GifEncoder(this.canvas.width, this.canvas.height); + this.gifEncoder.setQuality(this.quality); + this.gifEncoder.setRepeat(this.repeat); + this.gifEncoder.setDelay(this.delay); + }; + + start = () => { + this.gifEncoder.start(); + }; + + add = () => { + this.gifEncoder.addFrame(this.ctx); + }; + + stop = () => { + this.gifEncoder.finish(); + const buffer = this.gifEncoder.out.getData(); + writeFile(this.fileName, buffer, (error) => {}); + console.log(`Created gif at ${this.fileName}`); + }; +} + +module.exports = HashLipsGiffer; diff --git a/package-lock.json b/package-lock.json index 4ba89076f..9226f9839 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "hashlips_art_engine", - "version": "1.0.5", + "version": "1.0.9", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -165,6 +165,11 @@ "wide-align": "^1.1.0" } }, + "gif-encoder-2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/gif-encoder-2/-/gif-encoder-2-1.0.5.tgz", + "integrity": "sha512-fsRAKbZuUoZ7FYGjpFElmflTkKwsn/CzAmL/xDl4558aTAgysIDCUF6AXWO8dmai/ApfZACbPVAM+vPezJXlFg==" + }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", diff --git a/package.json b/package.json index f436ee5fc..aa9ef47bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hashlips_art_engine", - "version": "1.0.5", + "version": "1.0.9", "description": "HashLips Art Engine is a tool used to create multiple different instances of artworks based on provided layers.", "main": "index.js", "bin": "index.js", @@ -23,6 +23,7 @@ "license": "MIT", "dependencies": { "canvas": "^2.8.0", + "gif-encoder-2": "^1.0.5", "sha1": "^1.1.1" } } diff --git a/src/config.js b/src/config.js index a024e40c8..55dde0c3f 100644 --- a/src/config.js +++ b/src/config.js @@ -14,7 +14,7 @@ const description = "Remember to replace this description"; const baseUri = "ipfs://NewUriToReplace"; const solanaMetadata = { - symbol: "NOC", + symbol: "YC", seller_fee_basis_points: 1000, // Define how much % you want from secondary market sales 1000 = 10% external_url: "https://www.youtube.com/c/hashlipsnft", creators: [ @@ -50,6 +50,13 @@ const format = { height: 512, }; +const gif = { + export: false, + repeat: 0, + quality: 100, + delay: 500, +}; + const text = { only: false, color: "#ffffff", @@ -104,4 +111,5 @@ module.exports = { namePrefix, network, solanaMetadata, + gif, }; diff --git a/src/main.js b/src/main.js index f5718f6d2..989c82ab2 100644 --- a/src/main.js +++ b/src/main.js @@ -27,6 +27,7 @@ const { namePrefix, network, solanaMetadata, + gif, } = require(path.join(basePath, "/src/config.js")); const canvas = createCanvas(format.width, format.height); const ctx = canvas.getContext("2d"); @@ -34,6 +35,12 @@ var metadataList = []; var attributesList = []; var dnaList = new Set(); const DNA_DELIMITER = "-"; +const HashlipsGiffer = require(path.join( + basePath, + "/modules/HashlipsGiffer.js" +)); + +let hashlipsGiffer = null; const buildSetup = () => { if (fs.existsSync(buildDir)) { @@ -42,6 +49,9 @@ const buildSetup = () => { fs.mkdirSync(buildDir); fs.mkdirSync(path.join(buildDir, "/json")); fs.mkdirSync(path.join(buildDir, "/images")); + if (gif.export) { + fs.mkdirSync(path.join(buildDir, "/gifs")); + } }; const getRarityWeight = (_str) => { @@ -315,6 +325,17 @@ const startCreating = async () => { await Promise.all(loadedElements).then((renderObjectArray) => { debugLogs ? console.log("Clearing canvas") : null; ctx.clearRect(0, 0, format.width, format.height); + if (gif.export) { + hashlipsGiffer = new HashlipsGiffer( + canvas, + ctx, + `${buildDir}/gifs/${abstractedIndexes[0]}.gif`, + gif.repeat, + gif.quality, + gif.delay + ); + hashlipsGiffer.start(); + } if (background.generate) { drawBackground(); } @@ -324,7 +345,13 @@ const startCreating = async () => { index, layerConfigurations[layerConfigIndex].layersOrder.length ); + if (gif.export) { + hashlipsGiffer.add(); + } }); + if (gif.export) { + hashlipsGiffer.stop(); + } debugLogs ? console.log("Editions left to create: ", abstractedIndexes) : null; diff --git a/yarn.lock b/yarn.lock index 772257763..91a88a2bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -159,6 +159,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gif-encoder-2@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/gif-encoder-2/-/gif-encoder-2-1.0.5.tgz#872ae04d8028de4a3417646ceb80dda88d6247b9" + integrity sha512-fsRAKbZuUoZ7FYGjpFElmflTkKwsn/CzAmL/xDl4558aTAgysIDCUF6AXWO8dmai/ApfZACbPVAM+vPezJXlFg== + glob@^7.1.3: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"