UNPKG

crmod-api

Version:

A dynamic mod/asset generator for Cosmic Reach

124 lines (110 loc) 4.13 kB
import { Canvas, Image, createCanvas, loadImage } from "canvas"; import Writeable from "./writeable.js"; import Mod from "./mod.js"; /** * Converts an image to a {@link Canvas}. * * @package * @param {Image} image The image to convert. * @returns {Canvas} The converted canvas. */ function imageToCanvas(image) { const canvas = createCanvas(image.width, image.height); canvas.getContext("2d").drawImage(image, 0, 0); return canvas; } /** * Defines a texture within a {@link Mod}. * * @class Texture * @extends {Writeable} */ class Texture extends Writeable { /** * Creates a new Texture from file location * * @param {string} source Image source file name * @return {Promise<Texture>} */ static async fromFile(source) { return new Texture(source.split(/[\/\\]/g).pop(), imageToCanvas(await loadImage(source))); } /** * Initializes a new Texture. * * @param {string} name Image output name * @param {Image|Canvas} canvas Image data */ constructor(name, canvas) { super(); /** @type {string} */ this.name = name; /** @type {Canvas} */ this.canvas = (canvas instanceof Canvas) ? canvas : imageToCanvas(canvas); } /** * Serializes the Texture into a JSON object. * * @override * @return {Object} The serialized Texture as a JSON object. * @memberof Texture */ serialize() { return this.canvas.toBuffer(); } } /** * Defines a colorized texture within a {@link Mod}. * * @class ColorizedTexture */ class ColorizedTexture { /** * Creates a colorized texture from two image files. * * @static * @async * @param {string} whiteSource The path for the white variant image. * @param {string} blackSource The path for the black variant image. * @return {Promise<ColorizedTexture>} The colorized texture. * @memberof ColorizedTexture */ static async createFromFiles(whiteSource, blackSource) { return new ColorizedTexture(await loadImage(whiteSource), await loadImage(blackSource)); } /** * Initializes a new ColorizedTexture. * * @param {Image} whiteTexture White variant image * @param {Image} blackTexture Black variant image */ constructor(whiteTexture, blackTexture) { /** @type {Canvas} */ this.whiteTexture = imageToCanvas(whiteTexture); /** @type {Canvas} */ this.blackTexture = imageToCanvas(blackTexture); } /** * Creates a colorized image by interpolating each color channel from black's channel value to white's channel value * @param {string} name Image output name * @param {Number} r Red coefficient * @param {Number} g Green coefficient * @param {Number} b Blue coefficient * @param {Number?} a Alpha coefficient (default 0.5) * @returns {Canvas} */ createTexture(name, r, g, b, a = 0.5) { const canvas = createCanvas(this.whiteTexture.width, this.whiteTexture.height); const context = canvas.getContext("2d"); const whiteData = this.whiteTexture.getContext("2d").getImageData(0, 0, canvas.width, canvas.height); const blackData = this.blackTexture.getContext("2d").getImageData(0, 0, canvas.width, canvas.height); const newData = context.getImageData(0, 0, canvas.width, canvas.height); for(let y = 0, i = 0; y < canvas.height; y++) { for(let x = 0; x < canvas.width; x++, i += 4) { newData.data[i + 0] = (whiteData.data[i + 0] - blackData.data[i + 0]) * r + blackData.data[i + 0]; newData.data[i + 1] = (whiteData.data[i + 1] - blackData.data[i + 1]) * g + blackData.data[i + 1]; newData.data[i + 2] = (whiteData.data[i + 2] - blackData.data[i + 2]) * b + blackData.data[i + 2]; newData.data[i + 3] = (whiteData.data[i + 3] - blackData.data[i + 3]) * a + blackData.data[i + 3]; } } context.putImageData(newData, 0, 0); return new Texture(name, canvas); } } export { ColorizedTexture, Texture };