mirror of
https://github.com/SwingTheVine/Wplace-BlueMarble.git
synced 2026-03-11 17:15:38 +00:00
Did most new template creation system
This commit is contained in:
parent
d56f952f4b
commit
d1d6ebe7cc
9 changed files with 270 additions and 29 deletions
4
dist/BlueMarble.user.js
vendored
4
dist/BlueMarble.user.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -35,7 +35,7 @@
|
|||
<a href="https://github.com/SwingTheVine/Wplace-BlueMarble/blob/main/LICENSE.txt" target="_blank"><img alt="Software License: MPL-2.0" src="https://img.shields.io/badge/Software_License-MPL--2.0-brightgreen?style=flat"></a>
|
||||
<a href="https://discord.gg/tpeBPy46hf" target="_blank"><img alt="Contact Me" src="https://img.shields.io/badge/Contact_Me-gray?style=flat&logo=Discord&logoColor=white&logoSize=auto&labelColor=cornflowerblue"></a>
|
||||
<a href="" target="_blank"><img alt="WakaTime" src="https://img.shields.io/badge/Coding_Time-59hrs_0mins-blue?style=flat&logo=wakatime&logoColor=black&logoSize=auto&labelColor=white"></a>
|
||||
<a href="" target="_blank"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-354-black?style=flat"></a>
|
||||
<a href="" target="_blank"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-395-black?style=flat"></a>
|
||||
<a href="" target="_blank"><img alt="Total Lines of Code" src="https://tokei.rs/b1/github/SwingTheVine/Wplace-BlueMarble?category=code"></a>
|
||||
<a href="" target="_blank"><img alt="Total Comments" src="https://tokei.rs/b1/github/SwingTheVine/Wplace-BlueMarble?category=comments"></a>
|
||||
<a href="" target="_blank"><img alt="Compression" src="https://img.shields.io/badge/Compression-73.03%25-blue"></a>
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
<h2>Overview</h2>
|
||||
<p>
|
||||
Welcome to Blue Marble! Blue Marble is a userscript for the website <a href="https://wplace.live/" target="_blank">wplace.live</a>.
|
||||
Welcome to Blue Marble! Blue Marble is a userscript for the website <a href="https://wplace.live/" target="_blank">wplace.live</a>. If you like this userscript, please ⭐ the repository!
|
||||
|
||||
<h3>Installation Instructions</h3>
|
||||
<a href="" target="_blank"><img alt="Supported Browsers" src="https://img.shields.io/badge/Browsers-Chrome%20%7C%20Firefox%20%7C%20Safari%20%7C%20IE-orange?style=flat"></a>
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.64.12",
|
||||
"version": "0.65.41",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.64.12",
|
||||
"version": "0.65.41",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"terser": "^5.43.1"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.65.0",
|
||||
"version": "0.65.41",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node build/build.js",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name Blue Marble
|
||||
// @namespace https://github.com/SwingTheVine/
|
||||
// @version 0.65.0
|
||||
// @version 0.65.41
|
||||
// @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA.
|
||||
// @author SwingTheVine
|
||||
// @license MPL-2.0
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
|
||||
import TemplateManager from "./templateManager.js";
|
||||
import { escapeHTML, serverTPtoDisplayTP } from "./utils.js";
|
||||
import { escapeHTML, numberToEncoded, serverTPtoDisplayTP } from "./utils.js";
|
||||
|
||||
export default class ApiManager {
|
||||
|
||||
|
|
@ -62,6 +62,15 @@ export default class ApiManager {
|
|||
}
|
||||
|
||||
const nextLevelPixels = Math.ceil(Math.pow(Math.floor(dataJSON['level']) * Math.pow(30, 0.65), (1/0.65)) - dataJSON['pixelsPainted']); // Calculates pixels to the next level
|
||||
|
||||
console.log(dataJSON['id']);
|
||||
if (!!dataJSON['id'] || dataJSON['id'] === 0) {
|
||||
console.log(numberToEncoded(
|
||||
dataJSON['id'],
|
||||
'!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'
|
||||
));
|
||||
}
|
||||
this.templateManager.userID = dataJSON['id'];
|
||||
|
||||
overlay.updateInnerHTML('bm-user-name', `Username: <b>${escapeHTML(dataJSON['name'])}</b>`); // Updates the text content of the username field
|
||||
overlay.updateInnerHTML('bm-user-droplets', `Droplets: <b>${new Intl.NumberFormat().format(dataJSON['droplets'])}</b>`); // Updates the text content of the droplets field
|
||||
|
|
|
|||
35
src/main.js
35
src/main.js
|
|
@ -165,7 +165,7 @@ document.head.appendChild(stylesheetLink);
|
|||
// CONSTRUCTORS
|
||||
const observers = new Observers(); // Constructs a new Observers object
|
||||
const overlay = new Overlay(name, version); // Constructs a new Overlay object
|
||||
const templateManager = new TemplateManager(); // Constructs a new TemplateManager object
|
||||
const templateManager = new TemplateManager(name, version); // Constructs a new TemplateManager object
|
||||
const apiManager = new ApiManager(templateManager); // Constructs a new ApiManager object
|
||||
|
||||
overlay.setApiManager(apiManager); // Sets the API manager
|
||||
|
|
@ -223,10 +223,10 @@ function buildOverlayMain() {
|
|||
}
|
||||
}
|
||||
).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
|
||||
.buildElement()
|
||||
.addInputFile({'id': 'bm-input-file-template', 'textContent': 'Upload Template', 'accept': 'image/png, image/jpeg, image/webp, image/bmp, image/gif'}).buildElement()
|
||||
.addDiv({'id': 'bm-contain-buttons-template'})
|
||||
|
|
@ -234,13 +234,24 @@ function buildOverlayMain() {
|
|||
button.onclick = () => {
|
||||
const input = document.querySelector('#bm-input-file-template');
|
||||
|
||||
const coordTlX = document.querySelector('#bm-input-tx');
|
||||
if (!coordTlX.checkValidity()) {coordTlX.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
|
||||
const coordTlY = document.querySelector('#bm-input-ty');
|
||||
if (!coordTlY.checkValidity()) {coordTlY.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
|
||||
const coordPxX = document.querySelector('#bm-input-px');
|
||||
if (!coordPxX.checkValidity()) {coordPxX.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
|
||||
const coordPxY = document.querySelector('#bm-input-py');
|
||||
if (!coordPxY.checkValidity()) {coordPxY.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
|
||||
|
||||
// Kills itself if there is no file
|
||||
if (!input?.files[0]) {instance.handleDisplayError(`No file selected!`); return;}
|
||||
|
||||
console.log(`TCoords: ${apiManager.templateCoordsTilePixel}\nCoords: ${apiManager.coordsTilePixel}`);
|
||||
apiManager.templateCoordsTilePixel = apiManager.coordsTilePixel; // Update template coords
|
||||
console.log(`TCoords: ${apiManager.templateCoordsTilePixel}\nCoords: ${apiManager.coordsTilePixel}`);
|
||||
templateManager.setTemplateImage(input.files[0]);
|
||||
templateManager.createTemplate(input.files[0], input.files[0]?.name.replace(/\.[^/.]+$/, ''), [Number(coordTlX.value), Number(coordTlY.value), Number(coordPxX.value), Number(coordPxY.value)]);
|
||||
|
||||
// console.log(`TCoords: ${apiManager.templateCoordsTilePixel}\nCoords: ${apiManager.coordsTilePixel}`);
|
||||
// apiManager.templateCoordsTilePixel = apiManager.coordsTilePixel; // Update template coords
|
||||
// console.log(`TCoords: ${apiManager.templateCoordsTilePixel}\nCoords: ${apiManager.coordsTilePixel}`);
|
||||
// templateManager.setTemplateImage(input.files[0]);
|
||||
|
||||
instance.handleDisplayStatus(`Drew to canvas!`);
|
||||
}
|
||||
|
|
@ -253,6 +264,12 @@ function buildOverlayMain() {
|
|||
.addButton({'id': 'bm-button-teleport', 'className': 'bm-help', 'textContent': '✈'}).buildElement()
|
||||
.addButton({'id': 'bm-button-favorite', 'className': 'bm-help', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="10,2 12,7.5 18,7.5 13.5,11.5 15.5,18 10,14 4.5,18 6.5,11.5 2,7.5 8,7.5" fill="white"></polygon></svg>'}).buildElement()
|
||||
.addButton({'id': 'bm-button-templates', 'className': 'bm-help', 'innerHTML': '🖌'}).buildElement()
|
||||
.addButton({'id': 'bm-button-convert', 'className': 'bm-help', 'innerHTML': '🎨'},
|
||||
(instance, button) => {
|
||||
button.addEventListener('click', () => {
|
||||
window.open('https://pepoafonso.github.io/color_converter_wplace/', '_blank', 'noopener noreferrer');
|
||||
});
|
||||
}).buildElement()
|
||||
.buildElement()
|
||||
.addSmall({'textContent': 'Made by SwingTheVine', 'style': 'margin-top: auto;'}).buildElement()
|
||||
.buildElement()
|
||||
|
|
|
|||
|
|
@ -1,28 +1,56 @@
|
|||
import { numberToEncoded } from "./utils";
|
||||
|
||||
/** Manages the template system.
|
||||
* This class handles all external requests for modification to a Template.
|
||||
* @since 0.55.8
|
||||
* @example
|
||||
* // Example of JSON structure for a template
|
||||
{
|
||||
"scriptVersion": "1.13.0",
|
||||
"schemaVersion": "2.1.0",
|
||||
"templates": {
|
||||
""
|
||||
}
|
||||
}
|
||||
* // JSON structure for a template
|
||||
* {
|
||||
* "whoami": "BlueMarble",
|
||||
* "scriptVersion": "1.13.0",
|
||||
* "schemaVersion": "2.1.0",
|
||||
* "templates": {
|
||||
* "0 $Z": {
|
||||
* "name": "My Template",
|
||||
* "enabled": true,
|
||||
* "tiles": {
|
||||
* "1231,0047,183,593": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
|
||||
* "1231,0048,183,000": "data:image/png;AAAFCAYAAACNbyblAAAAHElEQVQI12P4"
|
||||
* }
|
||||
* },
|
||||
* "1 $Z": {
|
||||
* "name": "My Template",
|
||||
* "enabled": false,
|
||||
* "tiles": {
|
||||
* "375,1846,276,188": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
|
||||
* "376,1846,000,188": "data:image/png;AAAFCAYAAACNbyblAAAAHElEQVQI12P4"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export default class TemplateManager {
|
||||
|
||||
/** The constructor for the {@link TemplateManager} class.
|
||||
* @since 0.55.8
|
||||
*/
|
||||
constructor() {
|
||||
constructor(name, version) {
|
||||
|
||||
// Meta
|
||||
this.name = name; // Name of userscript
|
||||
this.version = version; // Version of userscript
|
||||
this.templatesVersion = '1.0.0'; // Version of JSON schema
|
||||
this.userID = null; // The ID of the current user
|
||||
this.encodingBase = '!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'; // Characters to use for encoding/decoding
|
||||
|
||||
// Template
|
||||
this.canvasTemplate = null; // Our canvas
|
||||
this.canvasTemplateZoomed = null; // The template when zoomed out
|
||||
this.canvasTemplateID = 'bm-canvas'; // Our canvas ID
|
||||
this.canvasMainID = 'div#map canvas.maplibregl-canvas'; // The selector for the main canvas
|
||||
this.template = null; // The template image.
|
||||
this.templateState = ''; // The state of the template ('blob', 'proccessing', 'template', etc.)
|
||||
this.templates = null; // All templates currently loaded (JSON)
|
||||
}
|
||||
|
||||
/** Retrieves the pixel art canvas.
|
||||
|
|
@ -65,18 +93,177 @@ export default class TemplateManager {
|
|||
return this.canvasTemplate; // Return the new canvas
|
||||
}
|
||||
|
||||
createTemplate() {
|
||||
/** Creates the JSON object to store templates in
|
||||
* @returns {{ whoami: string, scriptVersion: string, schemaVersion: string, templates: Object }} The JSON object
|
||||
* @since 0.65.4
|
||||
*/
|
||||
async createJSON() {
|
||||
return {
|
||||
"whoami": this.name.replace(' ', ''), // Name of userscript without spaces
|
||||
"scriptVersion": this.version, // Version of userscript
|
||||
"schemaVersion": this.templatesVersion, // Version of JSON schema
|
||||
"templates": {} // The templates
|
||||
};
|
||||
}
|
||||
|
||||
/** Creates the template from the inputed file blob
|
||||
* @param {File} blob - The file blob to create a template from
|
||||
* @param {string} name - The display name of the template
|
||||
* @param {Array<number, number, number, number>} coords - The coordinates of the top left corner of the template
|
||||
*/
|
||||
async createTemplate(blob, name, coords) {
|
||||
|
||||
// Creates the JSON object if it does not already exist
|
||||
if (!this.templates) {this.templates = await this.createJSON();}
|
||||
|
||||
const tileSize = 1000; // The size of a tile in pixels
|
||||
|
||||
console.log(`Awaiting creation...`);
|
||||
|
||||
// Appends a child into the templates object
|
||||
// The child's name is the number of templates already in the list (sort order) plus the encoded player ID
|
||||
this.templates.templates[`${this.templates.templates.length || 0} ${numberToEncoded(this.userID || 0, this.encodingBase)}`] = {
|
||||
"name": name, // Display name of template
|
||||
"tiles": await this.#createTemplateTiles(blob, coords, tileSize)
|
||||
};
|
||||
|
||||
console.log(this.templates);
|
||||
}
|
||||
|
||||
/** Creates chunks of the template for each tile.
|
||||
* @param {File} blob - The File blob to process
|
||||
* @param {Array<number, number, number, number>} coords - The coordinates of the top left corner of the template
|
||||
* @param {number} tileSize - The size of a tile (assumes tiles are square)
|
||||
* @returns {Object} Collection of template bitmaps in a Object
|
||||
* @since 0.65.4
|
||||
*/
|
||||
async #createTemplateTiles(blob, coords, tileSize) {
|
||||
|
||||
console.log(coords);
|
||||
|
||||
const shreadSize = 3; // Scale image factor. Must be odd
|
||||
const bitmap = await createImageBitmap(blob); // Creates a bitmap image
|
||||
const imageWidth = bitmap.width;
|
||||
const imageHeight = bitmap.height;
|
||||
|
||||
const templateTiles = {}; // Holds the template tiles
|
||||
|
||||
const canvas = new OffscreenCanvas(tileSize, tileSize);
|
||||
const context = canvas.getContext('2d', { willReadFrequently: true });
|
||||
|
||||
// For every tile...
|
||||
for (let pixelY = coords[3]; pixelY < (imageHeight + coords[3]);) {
|
||||
|
||||
// Draws the partial tile first, if any
|
||||
// This calculates the size based on which is smaller:
|
||||
// A. The top left corner of the current tile to the bottom right corner of the current tile
|
||||
// B. The top left corner of the current tile to the bottom right corner of the image
|
||||
const drawSizeY = Math.min(tileSize - (pixelY % tileSize), imageHeight - ((pixelY - coords[3]) * (pixelY != coords[3])));
|
||||
console.log(`Math.min(${tileSize} - (${pixelY} % ${tileSize}), ${imageHeight} - (${pixelY - coords[3]} * (${pixelY} != ${coords[3]})))`);
|
||||
|
||||
for (let pixelX = coords[2]; pixelX < (imageWidth + coords[2]);) {
|
||||
console.log(`Pixel X: ${pixelX}\nPixel Y: ${pixelY}`);
|
||||
|
||||
// Draws the partial tile first, if any
|
||||
// This calculates the size based on which is smaller:
|
||||
// A. The top left corner of the current tile to the bottom right corner of the current tile
|
||||
// B. The top left corner of the current tile to the bottom right corner of the image
|
||||
const drawSizeX = Math.min(tileSize - (pixelX % tileSize), imageWidth - ((pixelX - coords[2]) * (pixelX != coords[2])));
|
||||
console.log(`Math.min(${tileSize} - (${pixelX} % ${tileSize}), ${imageWidth} - (${pixelX} * (${pixelX} != ${coords[2]})))`);
|
||||
|
||||
console.log(`Draw Size X: ${drawSizeX}\nDraw Size Y: ${drawSizeY}`);
|
||||
|
||||
console.log(`Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${drawSizeX * shreadSize}\nCanvas Height: ${drawSizeY * shreadSize}`);
|
||||
|
||||
// Change the canvas size and wipe the canvas
|
||||
canvas.width = drawSizeX * shreadSize;
|
||||
canvas.height = drawSizeY * shreadSize;
|
||||
|
||||
console.log(`Getting X ${pixelX}-${pixelX + drawSizeX}\nGetting Y ${pixelY}-${pixelY + drawSizeY}`);
|
||||
|
||||
// Draws the template segment on this tile segment
|
||||
context.clearRect(0, 0, drawSizeX * shreadSize, drawSizeY * shreadSize); // Clear any previous drawing (only runs when canvas size does not change)
|
||||
context.drawImage(bitmap, pixelX, pixelY, drawSizeX, drawSizeY, 0, 0, drawSizeX * shreadSize, drawSizeY * shreadSize); // Coordinates and size of draw area of source image, then canvas
|
||||
|
||||
const imageData = context.getImageData(0, 0, drawSizeX * shreadSize, drawSizeY * shreadSize); // Data of the image on the canvas
|
||||
|
||||
for (let y = 0; y < drawSizeY * shreadSize; y++) {
|
||||
for (let x = 0; x < drawSizeX * shreadSize; x++) {
|
||||
// For every pixel...
|
||||
|
||||
// ... Make it transparent unless it is the "center"
|
||||
if ((x % shreadSize !== 1) || (y % shreadSize !== 1)) {
|
||||
const pixelIndex = (y * drawSizeX + x) * 4; // Find the pixel index in an array where every 4 indexes are 1 pixel
|
||||
imageData.data[pixelIndex + 3] = 0; // Make the pixel transparent on the alpha channel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Shreaded pixels for ${pixelX}, ${pixelY}`, imageData);
|
||||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
templateTiles[`${(coords[0] + Math.floor(pixelX / 1000)).toString().padStart(4, '0')},${(coords[1] + Math.floor(pixelY / 1000)).toString().padStart(4, '0')},${(pixelX % 1000).toString().padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`] = await canvas.convertToBlob({ type: 'image/png' });
|
||||
|
||||
console.log(templateTiles);
|
||||
|
||||
pixelX += drawSizeX;
|
||||
}
|
||||
|
||||
pixelY += drawSizeY;
|
||||
}
|
||||
|
||||
console.log('Template Tiles: ', templateTiles);
|
||||
return templateTiles;
|
||||
}
|
||||
|
||||
/** Creates an image from a blob File
|
||||
* @param {File} blob - The blob to convert to an Image
|
||||
* @returns {Image} The image of the blob as an Image
|
||||
* @since 0.65.4
|
||||
*/
|
||||
#loadImageFromBlob(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image(); // Create a blank image
|
||||
image.onload = () => resolve(image); // When the blank image loads, populate it with the blob
|
||||
image.onerror = reject; // Return the error, if any
|
||||
image.src = URL.createObjectURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
/** Generates a {@link Template} class instance from the JSON object template
|
||||
*
|
||||
*/
|
||||
#loadTemplate() {
|
||||
|
||||
}
|
||||
|
||||
/** Deletes a template from the JSON object.
|
||||
* Also delete's the corrosponding {@link Template} class instance
|
||||
*
|
||||
*/
|
||||
deleteTemplate() {
|
||||
|
||||
}
|
||||
|
||||
/** Draws all templates on that tile
|
||||
*
|
||||
*/
|
||||
drawTemplateOnTile() {
|
||||
|
||||
}
|
||||
|
||||
importJSON() {
|
||||
|
||||
}
|
||||
|
||||
#parseBlueMarble() {
|
||||
|
||||
}
|
||||
|
||||
#parseOSU() {
|
||||
|
||||
}
|
||||
|
||||
/** Sets the template to the image passed in.
|
||||
* @param {File} file - The file of the template image.
|
||||
* @since 0.55.8
|
||||
|
|
|
|||
30
src/utils.js
30
src/utils.js
|
|
@ -70,4 +70,32 @@ export function consoleError(...args) {((consoleError) => consoleError(...args))
|
|||
* @param {...any} args - Arguments to be passed into the `warn()` function of the Console
|
||||
* @since 0.58.13
|
||||
*/
|
||||
export function consoleWarn(...args) {((consoleWarn) => consoleWarn(...args))(console.warn);}
|
||||
export function consoleWarn(...args) {((consoleWarn) => consoleWarn(...args))(console.warn);}
|
||||
|
||||
/** Encodes a number into a custom encoded string.
|
||||
* @param {number} number - The number to encode
|
||||
* @param {string} encoding - The characters to use when encoding
|
||||
* @since 0.65.2
|
||||
* @returns {string} Encoded string
|
||||
* @example
|
||||
* const encode = '012abcABC'; // Base 9
|
||||
* console.log(numberToEncoded(0, encode)); // 0
|
||||
* console.log(numberToEncoded(5, encode)); // c
|
||||
* console.log(numberToEncoded(15, encode)); // 1A
|
||||
* console.log(numberToEncoded(12345, encode)); // 1BCaA
|
||||
*/
|
||||
export function numberToEncoded(number, encoding) {
|
||||
|
||||
if (number === 0) return encoding[0]; // End quickly if number equals 0. No special calculation needed
|
||||
|
||||
let result = ''; // The encoded string
|
||||
const base = encoding.length; // The number of characters used, which determines the base
|
||||
|
||||
// Base conversion algorithm
|
||||
while (number > 0) {
|
||||
result = encoding[number % base] + result; // Find's the character's encoded value determined by the modulo of the base
|
||||
number = Math.floor(number / base); // Divides the number by the base so the next iteration can find the next modulo character
|
||||
}
|
||||
|
||||
return result; // The final encoded string
|
||||
}
|
||||
Loading…
Reference in a new issue