mirror of
https://github.com/SwingTheVine/Wplace-BlueMarble.git
synced 2026-03-11 21:26:55 +00:00
230 lines
12 KiB
HTML
230 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>JSDoc: Source: Template.js</title>
|
||
|
||
<script src="scripts/prettify/prettify.js"> </script>
|
||
<script src="scripts/prettify/lang-css.js"> </script>
|
||
<!--[if lt IE 9]>
|
||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||
<![endif]-->
|
||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<div id="main">
|
||
|
||
<h1 class="page-title">Source: Template.js</h1>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<section>
|
||
<article>
|
||
<pre class="prettyprint source linenums"><code>import { uint8ToBase64 } from "./utils";
|
||
|
||
/** An instance of a template.
|
||
* Handles all mathematics, manipulation, and analysis regarding a single template.
|
||
* @since 0.65.2
|
||
*/
|
||
export default class Template {
|
||
|
||
/** The constructor for the {@link Template} class with enhanced pixel tracking.
|
||
* @param {Object} [params={}] - Object containing all optional parameters
|
||
* @param {string} [params.displayName='My template'] - The display name of the template
|
||
* @param {number} [params.sortID=0] - The sort number of the template for rendering priority
|
||
* @param {string} [params.authorID=''] - The user ID of the person who exported the template (prevents sort ID collisions)
|
||
* @param {string} [params.url=''] - The URL to the source image
|
||
* @param {File} [params.file=null] - The template file (pre-processed File or processed bitmap)
|
||
* @param {Array<number>} [params.coords=null] - The coordinates of the top left corner as (tileX, tileY, pixelX, pixelY)
|
||
* @param {Object} [params.chunked=null] - The affected chunks of the template, and their template for each chunk
|
||
* @param {number} [params.tileSize=1000] - The size of a tile in pixels (assumes square tiles)
|
||
* @param {number} [params.pixelCount=0] - Total number of pixels in the template (calculated automatically during processing)
|
||
* @since 0.65.2
|
||
*/
|
||
constructor({
|
||
displayName = 'My template',
|
||
sortID = 0,
|
||
authorID = '',
|
||
url = '',
|
||
file = null,
|
||
coords = null,
|
||
chunked = null,
|
||
tileSize = 1000,
|
||
} = {}) {
|
||
this.displayName = displayName;
|
||
this.sortID = sortID;
|
||
this.authorID = authorID;
|
||
this.url = url;
|
||
this.file = file;
|
||
this.coords = coords;
|
||
this.chunked = chunked;
|
||
this.tileSize = tileSize;
|
||
this.pixelCount = 0; // Total pixel count in template
|
||
}
|
||
|
||
/** Creates chunks of the template for each tile.
|
||
*
|
||
* @returns {Object} Collection of template bitmaps & buffers organized by tile coordinates
|
||
* @since 0.65.4
|
||
*/
|
||
async createTemplateTiles() {
|
||
console.log('Template coordinates:', this.coords);
|
||
|
||
const shreadSize = 3; // Scale image factor for pixel art enhancement (must be odd)
|
||
const bitmap = await createImageBitmap(this.file); // Create efficient bitmap from uploaded file
|
||
const imageWidth = bitmap.width;
|
||
const imageHeight = bitmap.height;
|
||
|
||
// Calculate total pixel count using standard width × height formula
|
||
// TODO: Use non-transparent pixels instead of basic width times height
|
||
const totalPixels = imageWidth * imageHeight;
|
||
console.log(`Template pixel analysis - Dimensions: ${imageWidth}×${imageHeight} = ${totalPixels.toLocaleString()} pixels`);
|
||
|
||
// Store pixel count in instance property for access by template manager and UI components
|
||
this.pixelCount = totalPixels;
|
||
|
||
const templateTiles = {}; // Holds the template tiles
|
||
const templateTilesBuffers = {}; // Holds the buffers of the template tiles
|
||
|
||
const canvas = new OffscreenCanvas(this.tileSize, this.tileSize);
|
||
const context = canvas.getContext('2d', { willReadFrequently: true });
|
||
|
||
// For every tile...
|
||
for (let pixelY = this.coords[3]; pixelY < imageHeight + this.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(this.tileSize - (pixelY % this.tileSize), imageHeight - (pixelY - this.coords[3]));
|
||
|
||
console.log(`Math.min(${this.tileSize} - (${pixelY} % ${this.tileSize}), ${imageHeight} - (${pixelY - this.coords[3]}))`);
|
||
|
||
for (let pixelX = this.coords[2]; pixelX < imageWidth + this.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(this.tileSize - (pixelX % this.tileSize), imageWidth - (pixelX - this.coords[2]));
|
||
|
||
console.log(`Math.min(${this.tileSize} - (${pixelX} % ${this.tileSize}), ${imageWidth} - (${pixelX - this.coords[2]}))`);
|
||
|
||
console.log(`Draw Size X: ${drawSizeX}\nDraw Size Y: ${drawSizeY}`);
|
||
|
||
// Change the canvas size and wipe the canvas
|
||
const canvasWidth = drawSizeX * shreadSize;// + (pixelX % this.tileSize) * shreadSize;
|
||
const canvasHeight = drawSizeY * shreadSize;// + (pixelY % this.tileSize) * shreadSize;
|
||
canvas.width = canvasWidth;
|
||
canvas.height = canvasHeight;
|
||
|
||
console.log(`Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${canvasWidth}\nCanvas Height: ${canvasHeight}`);
|
||
|
||
context.imageSmoothingEnabled = false; // Nearest neighbor
|
||
|
||
console.log(`Getting X ${pixelX}-${pixelX + drawSizeX}\nGetting Y ${pixelY}-${pixelY + drawSizeY}`);
|
||
|
||
// Draws the template segment on this tile segment
|
||
context.clearRect(0, 0, canvasWidth, canvasHeight); // Clear any previous drawing (only runs when canvas size does not change)
|
||
context.drawImage(
|
||
bitmap, // Bitmap image to draw
|
||
pixelX - this.coords[2], // Coordinate X to draw from
|
||
pixelY - this.coords[3], // Coordinate Y to draw from
|
||
drawSizeX, // X width to draw from
|
||
drawSizeY, // Y height to draw from
|
||
0, // Coordinate X to draw at
|
||
0, // Coordinate Y to draw at
|
||
drawSizeX * shreadSize, // X width to draw at
|
||
drawSizeY * shreadSize // Y height to draw at
|
||
); // Coordinates and size of draw area of source image, then canvas
|
||
|
||
// const final = await canvas.convertToBlob({ type: 'image/png' });
|
||
// const url = URL.createObjectURL(final); // Creates a blob URL
|
||
// window.open(url, '_blank'); // Opens a new tab with blob
|
||
// setTimeout(() => URL.revokeObjectURL(url), 60000); // Destroys the blob 1 minute later
|
||
|
||
const imageData = context.getImageData(0, 0, canvasWidth, canvasHeight); // Data of the image on the canvas
|
||
|
||
for (let y = 0; y < canvasHeight; y++) {
|
||
for (let x = 0; x < canvasWidth; x++) {
|
||
// For every pixel...
|
||
|
||
// ... Make it transparent unless it is the "center"
|
||
if (x % shreadSize !== 1 || y % shreadSize !== 1) {
|
||
const pixelIndex = (y * canvasWidth + 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
|
||
|
||
// if (!!imageData.data[pixelIndex + 3]) {
|
||
// imageData.data[pixelIndex + 3] = 50; // Alpha
|
||
// imageData.data[pixelIndex] = 30; // Red
|
||
// imageData.data[pixelIndex + 1] = 30; // Green
|
||
// imageData.data[pixelIndex + 2] = 30; // Blue
|
||
// }
|
||
}
|
||
}
|
||
}
|
||
|
||
console.log(`Shreaded pixels for ${pixelX}, ${pixelY}`, imageData);
|
||
|
||
context.putImageData(imageData, 0, 0);
|
||
|
||
// Creates the "0000,0000,000,000" key name
|
||
const templateTileName = `${(this.coords[0] + Math.floor(pixelX / 1000))
|
||
.toString()
|
||
.padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000))
|
||
.toString()
|
||
.padStart(4, '0')},${(pixelX % 1000)
|
||
.toString()
|
||
.padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`;
|
||
|
||
templateTiles[templateTileName] = await createImageBitmap(canvas); // Creates the bitmap
|
||
|
||
const canvasBlob = await canvas.convertToBlob();
|
||
const canvasBuffer = await canvasBlob.arrayBuffer();
|
||
const canvasBufferBytes = Array.from(new Uint8Array(canvasBuffer));
|
||
templateTilesBuffers[templateTileName] = uint8ToBase64(canvasBufferBytes); // Stores the buffer
|
||
|
||
console.log(templateTiles);
|
||
|
||
pixelX += drawSizeX;
|
||
}
|
||
|
||
pixelY += drawSizeY;
|
||
}
|
||
|
||
console.log('Template Tiles: ', templateTiles);
|
||
console.log('Template Tiles Buffers: ', templateTilesBuffers);
|
||
return { templateTiles, templateTilesBuffers };
|
||
}
|
||
}
|
||
</code></pre>
|
||
</article>
|
||
</section>
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
<nav>
|
||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="module.exports.html">exports</a></li><li><a href="module.exports_module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#addBr">addBr</a></li><li><a href="global.html#addButton">addButton</a></li><li><a href="global.html#addButtonHelp">addButtonHelp</a></li><li><a href="global.html#addCheckbox">addCheckbox</a></li><li><a href="global.html#addDiv">addDiv</a></li><li><a href="global.html#addHeader">addHeader</a></li><li><a href="global.html#addHr">addHr</a></li><li><a href="global.html#addImg">addImg</a></li><li><a href="global.html#addInput">addInput</a></li><li><a href="global.html#addInputFile">addInputFile</a></li><li><a href="global.html#addP">addP</a></li><li><a href="global.html#addSmall">addSmall</a></li><li><a href="global.html#addTextarea">addTextarea</a></li><li><a href="global.html#base64ToUint8">base64ToUint8</a></li><li><a href="global.html#buildElement">buildElement</a></li><li><a href="global.html#buildOverlay">buildOverlay</a></li><li><a href="global.html#buildOverlayMain">buildOverlayMain</a></li><li><a href="global.html#consoleError">consoleError</a></li><li><a href="global.html#consoleLog">consoleLog</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#createJSON">createJSON</a></li><li><a href="global.html#createObserverBody">createObserverBody</a></li><li><a href="global.html#createTemplate">createTemplate</a></li><li><a href="global.html#createTemplateTiles">createTemplateTiles</a></li><li><a href="global.html#deleteTemplate">deleteTemplate</a></li><li><a href="global.html#disableTemplate">disableTemplate</a></li><li><a href="global.html#drawTemplateOnTile">drawTemplateOnTile</a></li><li><a href="global.html#escapeHTML">escapeHTML</a></li><li><a href="global.html#getObserverBody">getObserverBody</a></li><li><a href="global.html#handleDisplayError">handleDisplayError</a></li><li><a href="global.html#handleDisplayStatus">handleDisplayStatus</a></li><li><a href="global.html#handleDrag">handleDrag</a></li><li><a href="global.html#importJSON">importJSON</a></li><li><a href="global.html#inject">inject</a></li><li><a href="global.html#negativeSafeModulo">negativeSafeModulo</a></li><li><a href="global.html#numberToEncoded">numberToEncoded</a></li><li><a href="global.html#observe">observe</a></li><li><a href="global.html#observeBlack">observeBlack</a></li><li><a href="global.html#serverTPtoDisplayTP">serverTPtoDisplayTP</a></li><li><a href="global.html#setApiManager">setApiManager</a></li><li><a href="global.html#setTemplatesShouldBeDrawn">setTemplatesShouldBeDrawn</a></li><li><a href="global.html#spontaneousResponseListener">spontaneousResponseListener</a></li><li><a href="global.html#uint8ToBase64">uint8ToBase64</a></li><li><a href="global.html#updateInnerHTML">updateInnerHTML</a></li></ul>
|
||
</nav>
|
||
|
||
<br class="clear">
|
||
|
||
<footer>
|
||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time)
|
||
</footer>
|
||
|
||
<script> prettyPrint(); </script>
|
||
<script src="scripts/linenumber.js"> </script>
|
||
</body>
|
||
</html>
|