UNPKG

chess-image-generator

Version:

Generate images based on various forms of chess notation.

177 lines (156 loc) 4.47 kB
const { createCanvas, loadImage, } = require('canvas'); const Frame = require('canvas-to-buffer'); const { Chess } = require('chess.js'); const fs = require('fs'); const path = require('path'); const { cols, white, black, defaultSize, defaultLight, defaultDark, deafultStyle, filePaths, } = require('./config/index'); /** * Object constructor, initializes options. * @param {object} options Optional options * @param {number} size Pixel length of desired image * @param {string} light Color of light squares * @param {string} dark Color of dark squares * @param {style} style Desired style of pieces */ function ChessImageGenerator(options = {}) { this.chess = new Chess(); this.size = options.size || defaultSize; this.light = options.light || defaultLight; this.dark = options.dark || defaultDark; this.style = options.style || deafultStyle; this.ready = false; } ChessImageGenerator.prototype = { /** * Loads PGN into chess.js object. * @param {string} pgn Chess game PGN */ async loadPGN(pgn) { if (!this.chess.load_pgn(pgn)) { throw new Error('PGN could not be read successfully'); } else { this.ready = true; } }, /** * Loads FEN into chess.js object * @param {string} fen Chess position FEN */ async loadFEN(fen) { if (!this.chess.load(fen)) { throw new Error('FEN could not be read successfully'); } else { this.ready = true; } }, /** * Loads position array into chess.js object * @param {Array<string>} array Chess position array */ loadArray(array) { this.chess.clear(); for (let i = 0; i < array.length; i += 1) { for (let j = 0; j < array[i].length; j += 1) { if (array[i][j] !== '' && black.includes(array[i][j].toLowerCase())) { this.chess.put( { type: array[i][j].toLowerCase(), color: white.includes(array[i][j]) ? 'w' : 'b', }, (cols[j] + (8 - i)), ); } } } this.ready = true; }, /** * Generates buffer image based on position * @returns {Buffer} Image buffer */ async generateBuffer() { if (!this.ready) { throw new Error('Load a position first'); } const canvas = createCanvas(this.size, this.size); const ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.rect( 0, 0, this.size, this.size, ); ctx.fillStyle = this.light; ctx.fill(); for (let i = 0; i < 8; i += 1) { for (let j = 0; j < 8; j += 1) { if ((i + j) % 2 === 0) { ctx.beginPath(); ctx.rect( ((this.size / 8) * ((7-j)+1)) - (this.size / 8), ((this.size / 8) * (i)) , (this.size / 8) , (this.size / 8) ); ctx.fillStyle = this.dark; ctx.fill(); } const piece = this.chess.get(cols[7 - j] + ((7 - i) + 1)); if (piece && piece.type !== '' && black.includes(piece.type.toLowerCase())) { const image = `resources/${this.style}/${filePaths[`${piece.color}${piece.type}`]}.png`; const imageFile = await loadImage(path.join(__dirname, image)); await ctx.drawImage( imageFile, ((this.size / 8) * ((7-j)+1)) - (this.size / 8), ((this.size / 8) * (i)) , (this.size / 8) , (this.size / 8) ); } } } const frame = new Frame(canvas, { image: { types: [ 'png', ], }, }); return frame.toBuffer(); }, /** * Generates PNG image based on position * @param {string} pngPath File name */ async generatePNG(pngPath) { if (!this.ready) { throw new Error('Load a position first'); } const buffer = await this.generateBuffer(); fs.open(pngPath, 'w', (err, fd) => { if (err) { throw new Error(`could not open file: ${err}`); } fs.write(fd, buffer, 0, buffer.length, null, (writeError) => { if (writeError) { throw new Error(`error writing file: ${writeError}`); } fs.close(fd, () => pngPath); }); }); }, }; module.exports = ChessImageGenerator;