81 lines
2.3 KiB
JavaScript
81 lines
2.3 KiB
JavaScript
const fs = require('fs');
|
|
|
|
const encode = require('png-chunks-encode');
|
|
const extract = require('png-chunks-extract');
|
|
const PNGtext = require('png-chunk-text');
|
|
|
|
/**
|
|
* Writes Character metadata to a PNG image buffer.
|
|
* @param {Buffer} image PNG image buffer
|
|
* @param {string} data Character data to write
|
|
* @returns {Buffer} PNG image buffer with metadata
|
|
*/
|
|
const write = (image, data) => {
|
|
const chunks = extract(image);
|
|
const tEXtChunks = chunks.filter(chunk => chunk.name === 'tEXt');
|
|
|
|
// Remove all existing tEXt chunks
|
|
for (let tEXtChunk of tEXtChunks) {
|
|
chunks.splice(chunks.indexOf(tEXtChunk), 1);
|
|
}
|
|
// Add new chunks before the IEND chunk
|
|
const base64EncodedData = Buffer.from(data, 'utf8').toString('base64');
|
|
chunks.splice(-1, 0, PNGtext.encode('chara', base64EncodedData));
|
|
const newBuffer = Buffer.from(encode(chunks));
|
|
return newBuffer;
|
|
};
|
|
|
|
/**
|
|
* Reads Character metadata from a PNG image buffer.
|
|
* @param {Buffer} image PNG image buffer
|
|
* @returns {string} Character data
|
|
*/
|
|
const read = (image) => {
|
|
const chunks = extract(image);
|
|
|
|
const textChunks = chunks.filter(function (chunk) {
|
|
return chunk.name === 'tEXt';
|
|
}).map(function (chunk) {
|
|
return PNGtext.decode(chunk.data);
|
|
});
|
|
|
|
if (textChunks.length === 0) {
|
|
console.error('PNG metadata does not contain any text chunks.');
|
|
throw new Error('No PNG metadata.');
|
|
}
|
|
|
|
let index = textChunks.findIndex((chunk) => chunk.keyword.toLowerCase() == 'chara');
|
|
|
|
if (index === -1) {
|
|
console.error('PNG metadata does not contain any character data.');
|
|
throw new Error('No PNG metadata.');
|
|
}
|
|
|
|
return Buffer.from(textChunks[index].text, 'base64').toString('utf8');
|
|
};
|
|
|
|
/**
|
|
* Parses a card image and returns the character metadata.
|
|
* @param {string} cardUrl Path to the card image
|
|
* @param {string} format File format
|
|
* @returns {string} Character data
|
|
*/
|
|
const parse = (cardUrl, format) => {
|
|
let fileFormat = format === undefined ? 'png' : format;
|
|
|
|
switch (fileFormat) {
|
|
case 'png': {
|
|
const buffer = fs.readFileSync(cardUrl);
|
|
return read(buffer);
|
|
}
|
|
}
|
|
|
|
throw new Error('Unsupported format');
|
|
};
|
|
|
|
module.exports = {
|
|
parse,
|
|
write,
|
|
read,
|
|
};
|