前言:
眼前兄弟们对“js随机生成id”大体比较珍视,朋友们都想要剖析一些“js随机生成id”的相关资讯。那么小编在网上搜集了一些对于“js随机生成id””的相关文章,希望你们能喜欢,姐妹们快快来学习一下吧!文章简介:使用 Node.js 的 JIMP 图形处理库,通过混合图层的方式随机产生 NFT 图片和 metadata(元数据)。
在本教程中,我们将学习如何随机生成符合 OpenSea 标准的带有 metadata 的 NFT 图片(本教程也可以适用于Solana 和其它链,只需要 metadata 满足各链的要求即可)。学习本教程后能够批量获取可以直接上传到 Ethereum 或 Polygon 链的 NFT 图片。
在动手之前需要一些额外的准备工作。我们需要绘制不同图层的插画:眼睛、嘴巴、鼻子,以及我们想要包含在 NFT 图片的不同特征图片。
重要提示:同一图层的图片应具有相同的尺寸,代码会将具有透明背景的图层进行叠加,这样就不用花精力去对齐图片了,所有图层的 PNG 文件都要和背景图片尺寸相同。
下面是我们将要构建的NFT图片示例,包含正确的图层排序,错误示例(尺寸不同),以及 27 个由代码生成的NFT图片。示例图片是我用 iPad Pro 和 Procreate APP 绘制的(我是开发人员,不是设计师,画得不好但是可以说明问题):
我们将具有同一特征的图层按照如下顺序排列,每个特征都单独导出:
1- Background2- Body3- Outfit4- Head5- Nose6- Mouth7- Eyes8- Sunglasses9- Headwear
编写 Node.js 脚本
现在我们有了要在 NFT 生成器中使用的特征图片,接下来进行编码工作。本教程假设你已经安装了 Node.js 和 NPM,并且熟悉创建 NPM 项目的基础知识。(本教程示例代码和图片可以从获取)
新建文件夹并运行 npm init(默认回车即可),然后将 Traits 文件夹复制进来。现在我们将安装我们将要使用的库:fs(文件系统)、Jimp(图像处理)、dotenv(存储 pinata认证信息)和 Pinata SDK(将生成的图片上传到 IPFS )。安装依赖库:
npm i jimp fs @pinata/sdk
接着创建脚本入口文件index.js,我们通过 while 循环100次来生成100张不同的NFT图片。maxSupply可以修改成任意数字,但要保证特征图片足够多以避免重复(或自行修改代码防止创建具有重复 metadata 的图片)。代码如下:
const initial = async () => { var _thisIndex = 1; const _maxSupply = 100; while(_thisIndex <= _maxSupply) { try{ console.log('Generating NFT '+_thisIndex); _thisIndex++; }catch(e){ console.error('Error while generating NFT '+_thisIndex) console.log(e); _thisIndex = _maxSupply + 1; } }}initial();
下面要编写 generator.js 文件用来处理生成规则,以保证基础代码和生成规则的解耦。generator.js 将使用特征文件来产生常见、不常见、稀有和传奇四种稀有度的变化。
我们首先在index.js的同一文件夹中创建 traits.js 文件,其中包含生成眼睛、嘴巴、头部等的方法。我们将使用 Math.random 函数并返回一个字符串。
从背景样式开始,我选择岩浆和森林背景为普通,山脉和流水为罕见,城市和雪山为稀有,银河为传奇。
我们使用的特征文件名称格式为 CATEGORY_NAME(分类_名称)。例如,流水的背景文件名为 Background_Aqua。使用同一个命名格式不仅是为了更好地管理,而且可以节省很多代码。
我还通过以下方式设置稀有度范围的常数:
const COMMON_MAX_RARITY = 50; //Starts from 1const UNCOMMON_MAX_RARITY = 75;const RARE_MAX_RARITY = 95;const LEGENDARY_MAX_RARITY = 100;const randomElement = (list) => { const _random = Math.floor(Math.random() * list.length); return list[_random];}const getBackground = () => { const _random = Math.floor(Math.random() * LEGENDARY_MAX_RARITY);if(_random < COMMON_MAX_RARITY) { return randomElement([ 'Lava', 'Forest' ]); }else if(_random < UNCOMMON_MAX_RARITY) { return randomElement([ 'Mountain', 'Aqua' ]); }else if(_random < RARE_MAX_RARITY) { return randomElement([ 'Psycho', 'Snow' ]); }else if(_random < LEGENDARY_MAX_RARITY) { return randomElement([ 'Galaxy' ]); }}module.exports = { getBackground}
现在我们再添加其余的特征。对于身体和头部,我们使用相同的函数:getBodyAndHead。这是因为我们希望身体和头部匹配,外星人的头匹配外星人的身体,僵尸的头匹配僵尸的身体,等等。
现在我们已经准备好 traits.js 文件,接下来编写 generator.js 文件,我们将使用它来实际生成图像和 metadata。由于我们将使用 IPFS 保存图片,需要用到 Pinata 来帮助我们上传图片到 IPFS。
打开 Pinata 网站: 并创建一个帐户。注册很简单,中间需要验证下电子邮件。
注意:免费 Pinata 账户的上传限制为 1GB,超过需要支付费用。
登录后,你将在屏幕右上角看到一个菜单。选择 API Keys选项。
创建一个具有 Admin 权限的 API Key,设置名称并保存 API Key和API Secret,我们将在 Node.js 脚本上使用。
创建一个包含以下内容的 .env 文件,通过 dotenv 来保护我们的认证信息:
PINATA_KEY=PINATA_API_SECRET=
接着回到 generator.js 文件,导入依赖的库并使用刚刚生成的密钥来配置 Pinata。然后还需要引用我们的项目文件夹(参见下面的 _path 变量):
require('dotenv').config();const Jimp = require('jimp');const fs = require('fs');const pinataSDK = require('@pinata/sdk');const pinata = pinataSDK(process.env.PINATA_KEY, process.env.PINATA_API_SECRET);const Traits = require('./traits');const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms));}const build = async(index, onComplete) => { const _path = '/Users/jcmacur/Documents/Projects/nftgenerator/'; onComplete();}module.exports = { build}
在继续之前,还要修改一下 index.js 文件,使得它能在每次循环时调用 Generator 生成图片。 将 index.js 内容替换为以下内容:
const Generator = require('./generator')const initial = async () => { var _thisIndex = 1; const _maxSupply = 100; while(_thisIndex <= _maxSupply) { try{ console.log('Generating NFT '+_thisIndex); await Generator.build(_thisIndex, () => { _thisIndex++; }) }catch(e){ console.error('Error while generating NFT '+_thisIndex) console.log(e); _thisIndex = _maxSupply + 1; } }}initial();
现在可以开始测试脚本了 ,执行:
node index.js
如果一切顺利,应该会看到以下输出。
在我们继续之前先快速解释一下 metadata 到底是什么,以及我们怎样以正确的方式构建它。
在以太坊上,NFT 智能合约使用 URL 来同步 token。 因此 ID为 1 的 token 将通过 baseUrl(通常是你上传的 IPFS 文件夹)+ ID 拼接成的 url 来获取对应的 metadata。
例如,如果 metadata 文件夹上传到“”,则 ID 为 1 的 NFT 将是“”。
每个 metadata 都是一个 JSON 格式的文件,没有扩展名,从 1 到 maxSupply 命名。 你也可以在 OpenSea 文档站点上阅读完整的规范,我们将使用以下结构作为例子:
{"image":"IPFS URL","name":"NFT #0","traits": [ {"trait_type":"Trait 1","value":"Blue"}, {"trait_type":"Trait 2","value":"Red"}, {"trait_type":"Trait 3","value":"Green"}, ]}
现在让我们再继续 generator.js 文件。首先解释一下代码逻辑:
按顺序加载几种图层。每次加载时会随机变化,Jimp 会将图片特征信息添加到 metadata 数组中,并将其重叠到上一层(背景图层除外)。将图像保存在自动创建的 Output/images 文件夹中。在下一个动作之前等待 20 毫秒,确保图像被保存到硬盘。创建一个只读的图像流并将图片上传到 IPFS,不用担心,使用 Pinata SDK 只需要2行代码即可。最后,保存一个没有扩展名的文件(例如,是“1”而不是“1.json”),其中包含 NFT 的名称、IPFS 图片的 URL 和特征描述。
将我们的构建方法替换为以下代码并运行。由于要循环生成 100 个 NFT 图片,可能需要几分钟时间。我们可以先测试只生成背景,确保它正常工作:
const build = async(index, onComplete) => { const _path = '/Users/jcmacur/Documents/Projects/nftgenerator/'; var _traits = [];const background = Traits.getBackground(); const backgroundJimp = await Jimp.read(_path+'/Traits/Background/Background_'+background+'.png'); _traits.push({ 'trait_type': 'Background', 'value': background });var _composedImage = backgroundJimp;await _composedImage.write('Output/images/'+index+'.png'); await sleep(20); //We give some time for the image to be actually saved in our files const _readableStream = await fs.createReadStream(_path + '/Output/images/'+index+'.png'); const _ipfs = await pinata.pinFileToIPFS(_readableStream);await fs.writeFileSync('Output/'+index, JSON.stringify({ "name": "My NFT #"+index, "traits": _traits, "image": ";+_ipfs.IpfsHash }))onComplete();}
执行 node index.js 测试一下,应该会看到以下内容:
现在我们可以添加其余的特征,按照头部、衣服和身体。。。的顺序开始,这样才能保证显示正常。 继续在 var _composedImage = backgroundJimp; 下面添加代码:
const bodyAndHead = Traits.getBodyAndHead(); const bodyJimp = await Jimp.read(_path+'/Traits/Body/Body_'+bodyAndHead+'.png'); _traits.push({ 'trait_type': 'Body', 'value': bodyAndHead });_composedImage.blit(bodyJimp, 0, 0);const outfit = Traits.getOutfit(); const outfitJimp = await Jimp.read(_path+'/Traits/Outfit/Outfit_'+outfit+'.png'); _traits.push({ 'trait_type': 'Outfit', 'value': outfit });_composedImage.blit(outfitJimp, 0, 0);const headJimp = await Jimp.read(_path+'/Traits/Head/Head_'+bodyAndHead+'.png'); _traits.push({ 'trait_type': 'Head', 'value': bodyAndHead });_composedImage.blit(headJimp, 0, 0);
再次运行脚本,我们将看到 2 个随机的人物图片!
我们现在可以按照顺序继续添加所有其余的特征到 _composedImage.blit(headJimp, 0, 0);这行代码之后 :
const nose = Traits.getNose(); const noseJimp = await Jimp.read(_path+'/Traits/Nose/Nose_'+nose+'.png'); _traits.push({ 'trait_type': 'Nose', 'value': nose });_composedImage.blit(noseJimp, 0, 0);const mouth = Traits.getMouth(); const mouthJimp = await Jimp.read(_path+'/Traits/Mouth/Mouth_'+mouth+'.png'); _traits.push({ 'trait_type': 'Mouth', 'value': mouth });_composedImage.blit(mouthJimp, 0, 0);const eyes = Traits.getEyes(); const eyesJimp = await Jimp.read(_path+'/Traits/Eyes/Eyes_'+eyes+'.png'); _traits.push({ 'trait_type': 'Eyes', 'value': eyes });_composedImage.blit(eyesJimp, 0, 0);const sunglasses = Traits.getSunglasses(); const sunglassesJimp = await Jimp.read(_path+'/Traits/Sunglasses/Sunglasses_'+sunglasses+'.png'); _traits.push({ 'trait_type': 'Sunglasses', 'value': sunglasses });_composedImage.blit(sunglassesJimp, 0, 0);const headwear = Traits.getHeadwear(); const headwearJimp = await Jimp.read(_path+'/Traits/Headwear/Headwear_'+headwear+'.png'); _traits.push({ 'trait_type': 'Headwear', 'value': headwear });_composedImage.blit(headwearJimp, 0, 0);
代码完成!再次运行 node index.js ,生成新的随机 NFT 图片:
总结
后续还有一些工作。创建了所有 NFT图片后,还需要将 IPFS 文件夹链接到智能合约上。所以我们需要上传图片文件夹并获取对应的 URL。
首先,我们将所有没有扩展名的文件移动到一个单独的文件夹(图像文件夹不是必需的,因为 IPFS 刷新可能需要一些时间,为了能快速看到生成的结果才创建,并且上传这些图片可能会占用 Pinata 的很多空间)。一旦我们有了包含所有 metadata 的文件夹,让我们打开 并转到上传文件夹。选择我们的文件夹,为其命名,然后上传:
上传后,可以能够看到 IPFS 哈希:
你的 metadata 文件夹 URL 是 CID/。所以,一个索引为 5 的 NFT,url 是 CID/5,并且你可以打开该 URL(将 CID 替换为你的)来自己测试。
本教程的示例代码和图片可以由此下载:。
原文地址:
标签: #js随机生成id #js随机图片 #js中怎么随机产生图片