Add files via upload
BIN
chara.png
Normal file
After Width: | Height: | Size: 421 KiB |
BIN
cj/1/alchemist.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
cj/1/arcanist.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
cj/1/archer.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
cj/1/armorer.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
cj/1/astrologian.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
cj/1/bard.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
cj/1/blackmage.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
cj/1/blacksmith.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
cj/1/bluemage.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
cj/1/botanist.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
cj/1/carpenter.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
cj/1/conjurer.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
cj/1/culinarian.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
cj/1/dancer.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
cj/1/darkknight.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
cj/1/dragoon.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
cj/1/fisher.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
cj/1/gladiator.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
cj/1/goldsmith.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
cj/1/gunbreaker.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
cj/1/lancer.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
cj/1/leatherworker.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
cj/1/machinist.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
cj/1/marauder.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
cj/1/miner.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
cj/1/monk.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
cj/1/ninja.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
cj/1/paladin.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
cj/1/pugilist.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
cj/1/redmage.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
cj/1/rogue.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
cj/1/samurai.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
cj/1/scholar.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
cj/1/summoner.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
cj/1/thaumaturge.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
cj/1/warrior.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
cj/1/weaver.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
cj/1/whitemage.png
Normal file
After Width: | Height: | Size: 17 KiB |
238
index.js
Normal file
|
@ -0,0 +1,238 @@
|
|||
const fetch = require("node-fetch");
|
||||
const fs = require("fs");
|
||||
const { createCanvas, loadImage } = require("canvas");
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const canvas = createCanvas(900, 600);
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const primary = "rgba(178, 214, 249, 1)";
|
||||
const white = "rgba(255, 255, 255,1)";
|
||||
const black = "rgba(0,0,0,0.5)";
|
||||
const small = "18px Sans";
|
||||
const med = "30px Sans";
|
||||
const large = "40px Sans";
|
||||
|
||||
let charaID = "13821878";
|
||||
|
||||
function createCard(charaID, callback) {
|
||||
let chara = "";
|
||||
fetch(`https://xivapi.com/character/${charaID}?extended=1&data=FC`)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
ctx.clearRect(0, 0, 900, 600);
|
||||
loadImage("./chara.png").then((image) => {
|
||||
ctx.drawImage(image, 0, 0, 900, 600);
|
||||
});
|
||||
loadImage(data.Character.Portrait).then((image) => {
|
||||
ctx.drawImage(image, 0, 0, 441, 600);
|
||||
ctx.strokeStyle = white;
|
||||
ctx.fillStyle = black;
|
||||
ctx.beginPath();
|
||||
ctx.fillRect(464, 7, 400, 100);
|
||||
ctx.fillRect(464, 120, 400, 50);
|
||||
ctx.fillRect(464, 185, 400, 205);
|
||||
ctx.fillRect(464, 405, 400, 175);
|
||||
ctx.stroke();
|
||||
ctx.textAlign = "center";
|
||||
ctx.font = med;
|
||||
ctx.fillStyle = primary;
|
||||
ctx.fillText(data.Character.Title.Name, 665, 45);
|
||||
ctx.font = med;
|
||||
ctx.fillText(`${data.Character.Server} (${data.Character.DC})`, 665, 155);
|
||||
// Race, Clan, Guardian, GC, FC Titles
|
||||
ctx.font = small;
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText("Race & Clan", 480, 205);
|
||||
ctx.fillText("Guardian", 480, 255);
|
||||
if (data.Character.GrandCompany.Company != null) {
|
||||
ctx.fillText("Grand Company", 480, 305);
|
||||
}
|
||||
if (data.Character.FreeCompanyName != null) {
|
||||
ctx.fillText("Free Company", 480, 355);
|
||||
}
|
||||
ctx.fillStyle = white;
|
||||
ctx.font = large;
|
||||
ctx.textAlign = "center";
|
||||
// Chara Name
|
||||
if (data.Character.Title.Name == null || data.Character.Title.Name == "") {
|
||||
ctx.fillText(data.Character.Name, 665, 70);
|
||||
} else {
|
||||
ctx.fillText(data.Character.Name, 665, 90);
|
||||
}
|
||||
// Race, Clan, Guardian, GC, FC Info
|
||||
ctx.font = "25px Sans";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(`${data.Character.Race.Name}, ${data.Character.Tribe.Name}`, 480, 230);
|
||||
ctx.fillText(data.Character.GuardianDeity.Name, 480, 280);
|
||||
if (data.Character.GrandCompany.Company != null) {
|
||||
ctx.fillText(data.Character.GrandCompany.Company.Name, 480, 330);
|
||||
}
|
||||
if (data.Character.FreeCompanyName != null) {
|
||||
ctx.fillText(data.Character.FreeCompanyName, 480, 380);
|
||||
}
|
||||
|
||||
// Why are there so many fucking jobs in this game?
|
||||
// Crafting
|
||||
ctx.font = "18px Sans";
|
||||
loadImage("./cj/1/alchemist.png").then((image) => {
|
||||
ctx.drawImage(image, 480, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[24].Level, 486, 565);
|
||||
|
||||
loadImage("./cj/1/armorer.png").then((image) => {
|
||||
ctx.drawImage(image, 510, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[20].Level, 516, 565);
|
||||
|
||||
loadImage("./cj/1/blacksmith.png").then((image) => {
|
||||
ctx.drawImage(image, 540, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[19].Level, 546, 565);
|
||||
|
||||
loadImage("./cj/1/carpenter.png").then((image) => {
|
||||
ctx.drawImage(image, 570, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[18].Level, 576, 565);
|
||||
|
||||
loadImage("./cj/1/culinarian.png").then((image) => {
|
||||
ctx.drawImage(image, 600, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[25].Level, 606, 565);
|
||||
|
||||
loadImage("./cj/1/goldsmith.png").then((image) => {
|
||||
ctx.drawImage(image, 630, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[21].Level, 636, 565);
|
||||
|
||||
loadImage("./cj/1/leatherworker.png").then((image) => {
|
||||
ctx.drawImage(image, 660, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[22].Level, 666, 565);
|
||||
|
||||
loadImage("./cj/1/weaver.png").then((image) => {
|
||||
ctx.drawImage(image, 690, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[23].Level, 696, 565);
|
||||
|
||||
// Gathering
|
||||
loadImage("./cj/1/botanist.png").then((image) => {
|
||||
ctx.drawImage(image, 750, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[27].Level, 756, 565);
|
||||
|
||||
loadImage("./cj/1/fisher.png").then((image) => {
|
||||
ctx.drawImage(image, 780, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[28].Level, 786, 565);
|
||||
|
||||
loadImage("./cj/1/miner.png").then((image) => {
|
||||
ctx.drawImage(image, 810, 520, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[26].Level, 816, 565);
|
||||
|
||||
// Tanks
|
||||
loadImage("./cj/1/paladin.png").then((image) => {
|
||||
ctx.drawImage(image, 480, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[0].Level, 486, 460);
|
||||
|
||||
loadImage("./cj/1/warrior.png").then((image) => {
|
||||
ctx.drawImage(image, 510, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[1].Level, 516, 460);
|
||||
|
||||
loadImage("./cj/1/darkknight.png").then((image) => {
|
||||
ctx.drawImage(image, 540, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[2].Level, 546, 460);
|
||||
|
||||
loadImage("./cj/1/gunbreaker.png").then((image) => {
|
||||
ctx.drawImage(image, 570, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[3].Level, 576, 460);
|
||||
|
||||
// Healers
|
||||
loadImage("./cj/1/whitemage.png").then((image) => {
|
||||
ctx.drawImage(image, 630, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[8].Level, 636, 460);
|
||||
|
||||
loadImage("./cj/1/scholar.png").then((image) => {
|
||||
ctx.drawImage(image, 660, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[9].Level, 666, 460);
|
||||
|
||||
loadImage("./cj/1/astrologian.png").then((image) => {
|
||||
ctx.drawImage(image, 690, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[10].Level, 696, 460);
|
||||
|
||||
// DPS
|
||||
// Ranged
|
||||
loadImage("./cj/1/bard.png").then((image) => {
|
||||
ctx.drawImage(image, 750, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[11].Level, 756, 460);
|
||||
|
||||
loadImage("./cj/1/machinist.png").then((image) => {
|
||||
ctx.drawImage(image, 780, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[12].Level, 786, 460);
|
||||
|
||||
loadImage("./cj/1/dancer.png").then((image) => {
|
||||
ctx.drawImage(image, 810, 415, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[13].Level, 816, 460);
|
||||
|
||||
// Melee
|
||||
loadImage("./cj/1/dragoon.png").then((image) => {
|
||||
ctx.drawImage(image, 480, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[5].Level, 486, 515);
|
||||
|
||||
loadImage("./cj/1/monk.png").then((image) => {
|
||||
ctx.drawImage(image, 510, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[4].Level, 516, 515);
|
||||
|
||||
loadImage("./cj/1/ninja.png").then((image) => {
|
||||
ctx.drawImage(image, 540, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[6].Level, 546, 515);
|
||||
|
||||
loadImage("./cj/1/samurai.png").then((image) => {
|
||||
ctx.drawImage(image, 570, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[7].Level, 576, 515);
|
||||
|
||||
// Caster
|
||||
loadImage("./cj/1/blackmage.png").then((image) => {
|
||||
ctx.drawImage(image, 630, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[14].Level, 636, 515);
|
||||
|
||||
loadImage("./cj/1/summoner.png").then((image) => {
|
||||
ctx.drawImage(image, 660, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[15].Level, 666, 515);
|
||||
|
||||
loadImage("./cj/1/redmage.png").then((image) => {
|
||||
ctx.drawImage(image, 690, 465, 30, 30);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[16].Level, 696, 515);
|
||||
|
||||
// Limited
|
||||
loadImage("./cj/1/bluemage.png").then((image) => {
|
||||
ctx.drawImage(image, 780, 465, 33, 33);
|
||||
});
|
||||
ctx.fillText(data.Character.ClassJobs[17].Level, 786, 515);
|
||||
|
||||
const png = canvas.toDataURL();
|
||||
|
||||
callback(png);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exports.createCard = createCard;
|
15
package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "shit",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"dev": "nodemon index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"canvas": "^2.6.1",
|
||||
"node-fetch": "^2.6.1",
|
||||
"nodemon": "^2.0.7"
|
||||
}
|
||||
}
|
2
readme.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# XIV Character Cards
|
||||
|
18
test.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const fs = require("fs");
|
||||
const createCard = require("./index").createCard;
|
||||
|
||||
createCard("9575452", (png) => {
|
||||
const data = png.replace(/^data:image\/\w+;base64,/, "");
|
||||
const buf = Buffer.from(data, "base64");
|
||||
fs.writeFile('test.png', buf, (err) => {
|
||||
console.log(err)
|
||||
})
|
||||
});
|
||||
|
||||
createCard("13821878", (png) => {
|
||||
const data = png.replace(/^data:image\/\w+;base64,/, "");
|
||||
const buf = Buffer.from(data, "base64");
|
||||
fs.writeFile('image.png', buf, (err) => {
|
||||
console.log(err)
|
||||
})
|
||||
});
|