Add express server, cleanup
This commit is contained in:
parent
4a155c1059
commit
077273c3c3
8 changed files with 2034 additions and 230 deletions
BIN
SourceSansPro-Regular.ttf
Normal file
BIN
SourceSansPro-Regular.ttf
Normal file
Binary file not shown.
BIN
SourceSansPro-SemiBold.ttf
Normal file
BIN
SourceSansPro-SemiBold.ttf
Normal file
Binary file not shown.
BIN
chara_n.png
Normal file
BIN
chara_n.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
280
create-card.js
Normal file
280
create-card.js
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
const fetch = require("node-fetch");
|
||||||
|
const fs = require("fs");
|
||||||
|
const { createCanvas, loadImage, registerFont } = require("canvas");
|
||||||
|
|
||||||
|
registerFont('SourceSansPro-Regular.ttf', { family: 'Source Sans Pro', style: 'Regular' });
|
||||||
|
registerFont('SourceSansPro-SemiBold.ttf', { family: 'Source Sans Pro', style: 'SemiBold' });
|
||||||
|
|
||||||
|
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 "Source Sans Pro"';
|
||||||
|
const med = '30px "Source Sans Pro"';
|
||||||
|
const smed = '25px "Source Sans Pro"';
|
||||||
|
const large = '45px "Source Sans Pro SemiBold"';
|
||||||
|
|
||||||
|
const jobsRowStart = 495;
|
||||||
|
const jobsRowTextSize = 30;
|
||||||
|
const jobsRowTextSpacer = jobsRowTextSize * 2;
|
||||||
|
|
||||||
|
const fcCrestCol = 345;
|
||||||
|
|
||||||
|
class CardCreator {
|
||||||
|
async init() {
|
||||||
|
this.bgImage = await loadImage("./chara_n.png");
|
||||||
|
|
||||||
|
this.imgAlchemist = await loadImage("./cj/1/alchemist.png");
|
||||||
|
this.imgArmorer = await loadImage("./cj/1/armorer.png");
|
||||||
|
this.imgBlacksmith = await loadImage("./cj/1/blacksmith.png");
|
||||||
|
this.imgCarpenter = await loadImage("./cj/1/carpenter.png");
|
||||||
|
this.imgCulinarian = await loadImage("./cj/1/culinarian.png");
|
||||||
|
this.imgGoldsmith = await loadImage("./cj/1/goldsmith.png");
|
||||||
|
this.imgLeatherworker = await loadImage("./cj/1/leatherworker.png");
|
||||||
|
this.imgWeaver = await loadImage("./cj/1/weaver.png");
|
||||||
|
|
||||||
|
this.imgBotanist = await loadImage("./cj/1/botanist.png");
|
||||||
|
this.imgFisher = await loadImage("./cj/1/fisher.png");
|
||||||
|
this.imgMiner = await loadImage("./cj/1/miner.png");
|
||||||
|
|
||||||
|
this.imgPaladin = await loadImage("./cj/1/paladin.png");
|
||||||
|
this.imgWarrior = await loadImage("./cj/1/warrior.png");
|
||||||
|
this.imgDarkKnight = await loadImage("./cj/1/darkknight.png");
|
||||||
|
this.imgGunbreaker = await loadImage("./cj/1/gunbreaker.png");
|
||||||
|
|
||||||
|
this.imgWhitemage = await loadImage("./cj/1/whitemage.png");
|
||||||
|
this.imgScholar = await loadImage("./cj/1/scholar.png");
|
||||||
|
this.imgAstrologian = await loadImage("./cj/1/astrologian.png");
|
||||||
|
|
||||||
|
this.imgBard = await loadImage("./cj/1/bard.png");
|
||||||
|
this.imgMachinist = await loadImage("./cj/1/machinist.png");
|
||||||
|
this.imgDancer = await loadImage("./cj/1/dancer.png");
|
||||||
|
|
||||||
|
this.imgDragoon = await loadImage("./cj/1/dragoon.png");
|
||||||
|
this.imgMonk = await loadImage("./cj/1/monk.png");
|
||||||
|
this.imgNinja = await loadImage("./cj/1/ninja.png");
|
||||||
|
this.imgSamurai = await loadImage("./cj/1/samurai.png");
|
||||||
|
|
||||||
|
this.imgBlackmage = await loadImage("./cj/1/blackmage.png");
|
||||||
|
this.imgSummoner = await loadImage("./cj/1/summoner.png");
|
||||||
|
this.imgRedmage = await loadImage("./cj/1/redmage.png");
|
||||||
|
|
||||||
|
this.imgBluemage = await loadImage('./cj/1/bluemage.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
async createCard(charaId) {
|
||||||
|
var response = await fetch(`https://xivapi.com/character/${charaId}?extended=1&data=FC`);
|
||||||
|
var data = await response.json();
|
||||||
|
|
||||||
|
const canvas = createCanvas(890, 600);
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
var portrait = await loadImage(data.Character.Portrait);
|
||||||
|
|
||||||
|
ctx.drawImage(this.bgImage, 441, 0, 900, 600);
|
||||||
|
|
||||||
|
ctx.drawImage(portrait, 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 = smed;
|
||||||
|
ctx.textAlign = "left";
|
||||||
|
ctx.fillText(`${data.Character.Race.Name}, ${data.Character.Tribe.Name}`, 480, 230);
|
||||||
|
|
||||||
|
ctx.fillText(data.Character.GuardianDeity.Name, 480, 280);
|
||||||
|
var measure = ctx.measureText(data.Character.GuardianDeity.Name);
|
||||||
|
var deityIcon = await loadImage('https://xivapi.com/' + data.Character.GuardianDeity.Icon);
|
||||||
|
ctx.drawImage(deityIcon, 480 + measure.width + 20, 252, 28, 28);
|
||||||
|
|
||||||
|
if (data.Character.GrandCompany.Company != null) {
|
||||||
|
ctx.fillText(data.Character.GrandCompany.Company.Name, 480, 330);
|
||||||
|
|
||||||
|
var measure = ctx.measureText(data.Character.GrandCompany.Company.Name);
|
||||||
|
var gcRankIcon = await loadImage('https://xivapi.com/' + data.Character.GrandCompany.Rank.Icon);
|
||||||
|
ctx.drawImage(gcRankIcon, 480 + measure.width + 20, 300, 40, 40);
|
||||||
|
}
|
||||||
|
if (data.Character.FreeCompanyName != null) {
|
||||||
|
var measure = ctx.measureText(data.Character.FreeCompanyName);
|
||||||
|
|
||||||
|
var crestLayer2 = await loadImage(data.FreeCompany.Crest[0]);
|
||||||
|
ctx.drawImage(crestLayer2, 480 + measure.width + 20, fcCrestCol, 38, 38);
|
||||||
|
|
||||||
|
var crestLayer1 = await loadImage(data.FreeCompany.Crest[1]);
|
||||||
|
ctx.drawImage(crestLayer1, 480 + measure.width + 20, fcCrestCol, 38, 38);
|
||||||
|
|
||||||
|
var crestLayer0 = await loadImage(data.FreeCompany.Crest[2]);
|
||||||
|
ctx.drawImage(crestLayer0, 480 + measure.width + 20, fcCrestCol, 38, 38);
|
||||||
|
|
||||||
|
ctx.fillText(data.Character.FreeCompanyName, 480, 380);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Why are there so many fucking jobs in this game?
|
||||||
|
// Crafting
|
||||||
|
ctx.font = small;
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
|
||||||
|
var cJobsRowX = jobsRowStart;
|
||||||
|
ctx.drawImage(this.imgAlchemist, 480, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[24].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgArmorer, 510, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[20].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgBlacksmith, 540, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[19].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgCarpenter, 570, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[18].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgCulinarian, 600, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[25].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgGoldsmith, 630, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[21].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgLeatherworker, 660, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[22].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgWeaver, 690, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[23].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSpacer;
|
||||||
|
|
||||||
|
// Gathering
|
||||||
|
ctx.drawImage(this.imgBotanist, 750, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[27].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgFisher, 780, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[28].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgMiner, 810, 520, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[26].Level, cJobsRowX, 565);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
// Tanks
|
||||||
|
cJobsRowX = jobsRowStart;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgPaladin, 480, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[0].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgWarrior, 510, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[1].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgDarkKnight, 540, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[2].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgGunbreaker, 570, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[3].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSpacer;
|
||||||
|
|
||||||
|
// Healers
|
||||||
|
ctx.drawImage(this.imgWhitemage, 630, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[8].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgScholar, 660, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[9].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgAstrologian, 690, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[10].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSpacer;
|
||||||
|
|
||||||
|
// DPS
|
||||||
|
// Ranged
|
||||||
|
ctx.drawImage(this.imgBard, 750, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[11].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgMachinist, 780, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[12].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgDancer, 810, 415, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[13].Level, cJobsRowX, 460);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
// Melee
|
||||||
|
cJobsRowX = jobsRowStart;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgDragoon, 480, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[5].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgMonk, 510, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[4].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgNinja, 540, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[6].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgSamurai, 570, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[7].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSpacer;
|
||||||
|
|
||||||
|
// Caster
|
||||||
|
ctx.drawImage(this.imgBlackmage, 630, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[14].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgSummoner, 660, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[15].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
ctx.drawImage(this.imgRedmage, 690, 465, 30, 30);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[16].Level, cJobsRowX, 515);
|
||||||
|
cJobsRowX += jobsRowTextSize;
|
||||||
|
|
||||||
|
// Limited
|
||||||
|
ctx.drawImage(this.imgBluemage, 780, 465, 33, 33);
|
||||||
|
ctx.fillText(data.Character.ClassJobs[17].Level, 796, 515);
|
||||||
|
|
||||||
|
return canvas.toBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.CardCreator = CardCreator;
|
262
index.js
262
index.js
|
@ -1,238 +1,50 @@
|
||||||
const fetch = require("node-fetch");
|
const fetch = require("node-fetch");
|
||||||
const fs = require("fs");
|
const express = require('express');
|
||||||
const { createCanvas, loadImage } = require("canvas");
|
const app = express();
|
||||||
const args = process.argv.slice(2);
|
const port = 80;
|
||||||
|
|
||||||
const canvas = createCanvas(900, 600);
|
const { CardCreator } = require('./create-card');
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
|
|
||||||
const primary = "rgba(178, 214, 249, 1)";
|
const creator = new CardCreator();
|
||||||
const white = "rgba(255, 255, 255,1)";
|
creator.init();
|
||||||
const black = "rgba(0,0,0,0.5)";
|
|
||||||
const small = "18px Sans";
|
|
||||||
const med = "30px Sans";
|
|
||||||
const large = "40px Sans";
|
|
||||||
|
|
||||||
let charaID = "13821878";
|
app.get('/characters/id/:charaId', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const png = await creator.createCard(req.params.charaId);
|
||||||
|
|
||||||
function createCard(charaID, callback) {
|
res.writeHead(200, {
|
||||||
let chara = "";
|
'Content-Type': 'image/png',
|
||||||
fetch(`https://xivapi.com/character/${charaID}?extended=1&data=FC`)
|
'Content-Length': png.length
|
||||||
.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) => {
|
res.end(png, 'binary');
|
||||||
ctx.drawImage(image, 0, 0, 441, 600);
|
}catch(error){
|
||||||
ctx.strokeStyle = white;
|
res.send(error);
|
||||||
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);
|
|
||||||
}
|
app.get('/characters/name/:world/:charName', async (req, res) => {
|
||||||
ctx.fillStyle = white;
|
var response = await fetch(`https://xivapi.com/character/search?name=${req.params.charName}&server=${req.params.world}`);
|
||||||
ctx.font = large;
|
var data = await response.json();
|
||||||
ctx.textAlign = "center";
|
|
||||||
// Chara Name
|
if (data.Results[0] === undefined)
|
||||||
if (data.Character.Title.Name == null || data.Character.Title.Name == "") {
|
{
|
||||||
ctx.fillText(data.Character.Name, 665, 70);
|
res.status(404).send("Character not found.");
|
||||||
} else {
|
return;
|
||||||
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?
|
try {
|
||||||
// Crafting
|
const png = await creator.createCard(data.Results[0].ID);
|
||||||
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) => {
|
res.writeHead(200, {
|
||||||
ctx.drawImage(image, 510, 520, 30, 30);
|
'Content-Type': 'image/png',
|
||||||
});
|
'Content-Length': png.length
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
res.end(png, 'binary');
|
||||||
|
}catch(error){
|
||||||
|
res.send(error);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
exports.createCard = createCard;
|
app.listen(port, () => {
|
||||||
|
console.log(`Listening at http://localhost:${port}`)
|
||||||
|
})
|
1711
package-lock.json
generated
Normal file
1711
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas": "^2.6.1",
|
"canvas": "^2.6.1",
|
||||||
|
"express": "^4.17.1",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"nodemon": "^2.0.7"
|
"nodemon": "^2.0.7"
|
||||||
}
|
}
|
||||||
|
|
2
test.js
2
test.js
|
@ -1,5 +1,5 @@
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const createCard = require("./index").createCard;
|
const createCard = require("./create-card").createCard;
|
||||||
|
|
||||||
createCard("9575452", (png) => {
|
createCard("9575452", (png) => {
|
||||||
const data = png.replace(/^data:image\/\w+;base64,/, "");
|
const data = png.replace(/^data:image\/\w+;base64,/, "");
|
||||||
|
|
Loading…
Reference in a new issue