@runejs/filestore
Version:
Tools for managing the RuneJS filestore.
202 lines (201 loc) • 6.92 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FontStore = exports.Font = exports.fontNames = exports.FontName = void 0;
const common_1 = require("@runejs/common");
const canvas_1 = require("canvas");
const sprite_store_1 = require("./sprite-store");
/**
* A list of game font file names.
*/
var FontName;
(function (FontName) {
FontName["p11_full"] = "p11_full";
FontName["p12_full"] = "p12_full";
FontName["b12_full"] = "b12_full";
FontName["q8_full"] = "q8_full";
// Lunar alphabets only work with capital letters from A-Z
FontName["lunar_alphabet"] = "lunar_alphabet";
FontName["lunar_alphabet_lrg"] = "lunar_alphabet_lrg";
})(FontName || (exports.FontName = FontName = {}));
exports.fontNames = [
FontName.p11_full,
FontName.p12_full,
FontName.b12_full,
FontName.q8_full,
FontName.lunar_alphabet,
FontName.lunar_alphabet_lrg,
];
class Font {
name;
spriteStore;
/**
* The `SpritePack` containing this `Font`'s various character glypth.
*/
spritePack;
constructor(name, spriteStore) {
this.name = name;
this.spriteStore = spriteStore;
this.spritePack = this.spriteStore.getSpritePack(this.name);
this.spritePack?.decode();
}
/**
* Draws the given string and returns it as a base64 encoded PNG image string.
* @param string The string to draw.
* @param textColor The color to draw the text in.
* @returns A base64 encoded PNG image.
*/
drawString(string, textColor = 0xffffff) {
const stringWidth = this.getStringWidth(string);
const stringHeight = this.getStringHeight(string);
const characters = string.split('');
const canvas = (0, canvas_1.createCanvas)(stringWidth, stringHeight);
const context = canvas.getContext('2d');
let x = 0;
for (const char of characters) {
const charPixels = this.getCharPixels(char, textColor);
const charWidth = this.getCharWidth(char);
const charHeight = this.getCharHeight(char);
const charSprite = this.getSprite(char);
const imageData = (0, canvas_1.createImageData)(charPixels, charWidth, charHeight);
const y = charSprite.offsetY;
context.putImageData(imageData, x, y);
x += charSprite.width;
}
return canvas.toDataURL('image/png');
}
/**
* Fetches all of the pixels of a character glyph in `Uint8ClampedArray` rgba pixel format.
* @param char The character or character code to get the pixels of.
* @param color The color to set the character's pixels to. Defaults to white.
*/
getCharPixels(char, color = 0xffffff) {
const sprite = this.getSprite(char);
if (!sprite) {
return null;
}
const pixels = sprite.getPixels();
for (let x = 0; x < sprite.width; x++) {
for (let y = 0; y < sprite.height; y++) {
const i = (sprite.width * y + x) << 2;
if (pixels[i] !== 0) {
const [r, g, b] = (0, sprite_store_1.toRgb)(color);
pixels[i] = r;
pixels[i + 1] = g;
pixels[i + 2] = b;
pixels[i + 3] = 255;
}
else {
pixels[i] = 0;
pixels[i + 1] = 0;
pixels[i + 2] = 0;
pixels[i + 3] = 0;
}
}
}
return pixels;
}
/**
* Finds and returns the height of the the specified string.
* @param string The string to find the height of.
*/
getStringHeight(string) {
// We set the default font height to uppercase A for reference
let height = this.getCharHeight('A');
if (height === 0) {
throw new Error("Default height couldn't be defined!");
}
for (const char of string.split('')) {
const sprite = this.getSprite(char);
if (!sprite) {
continue;
}
// Character is above the standard line of text, for example ' characters
if (sprite.offsetY < 0) {
height = height + Math.abs(sprite.offsetY);
continue;
}
// Add the offset to the char height to check for overflowing characters like g, y, j, etc
const charHeight = sprite.height + sprite.offsetY;
height = Math.max(height, charHeight);
}
return height;
}
/**
* Calculates the total width of all character glyphs within the specified string.
* @param string The string to find the width of.
*/
getStringWidth(string) {
const widths = string
.split('')
.map((stringChar) => this.getCharWidth(stringChar));
return widths.reduce((a, b) => a + b, 0);
}
/**
* Gets the glyph height for the specified character or character code.
* @param char The character or character code to get the height of.
*/
getCharHeight(char) {
return this.getSprite(char)?.height || 0;
}
/**
* Gets the glyph width for the specified character or character code.
* @param char The character or character code to get the width of.
*/
getCharWidth(char) {
return this.getSprite(char)?.width || 0;
}
/**
* Gets the `Sprite` for the specified character or character code.
* @param char The character or character code to get the sprite glyph for.
*/
getSprite(inputChar) {
let char = inputChar;
if (typeof char === 'string') {
char = char.charCodeAt(0);
}
try {
return this.spritePack.sprites[char] || null;
}
catch (error) {
common_1.logger.error(`Error loading glyph ${char}`, error);
return null;
}
}
}
exports.Font = Font;
/**
* Contains information and tools for the game's fonts.
*/
class FontStore {
filestore;
/**
* A map of loaded game fonts by name.
*/
fonts;
constructor(filestore) {
this.filestore = filestore;
this.fonts = new Map();
}
/**
* Load the list of registered game fonts and their associated Sprite Packs.
*/
loadFonts() {
for (const fontName of exports.fontNames) {
this.fonts.set(fontName, new Font(fontName, this.filestore.spriteStore));
}
return this;
}
/**
* Fetches a font by its file name
*/
getFontByName(fontName) {
return this.fonts.get(fontName);
}
/**
* Fetches a font by its ID
*/
getFontById(spriteId) {
return Array.from(this.fonts.values()).find((e) => e.spritePack.packId === spriteId);
}
}
exports.FontStore = FontStore;