UNPKG

@runejs/filestore

Version:

Tools for managing the RuneJS filestore.

202 lines (201 loc) 6.92 kB
"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;