UNPKG

canvacard

Version:

Powerful image manipulation package for beginners.

1,145 lines (1,032 loc) 38 kB
const Trigger = require("../libs/Trigger"); const Greyscale = require("../libs/Greyscale"); const Invert = require("../libs/Invert"); const Sepia = require("../libs/Sepia"); const fs = require("fs"); const Brightness = require("../libs/Brightness"); const Threshold = require("../libs/Threshold"); const Convolute = require("../libs/Convolute"); const { createCanvas, loadImage } = require("@napi-rs/canvas"); const Darkness = require("../libs/Darkness"); const circle = require("../plugins/circle"); const formatAndValidateHex = require("./utils/formatAndValidateHex.utils"); const shorten = require("./utils/shorten.utils"); const discordTime = require("./utils/discordTime.utils"); const { ImageFactory } = require("./AssetsFactory"); const APIError = require("./utils/error.utils"); /** * @kind class * @description Image generator * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.trigger("./image.png") .then(triggered => { canvacard.write(triggered, "triggered.gif"); }) .catch(console.error); * ``` */ class Canvacard { constructor() { throw new APIError(`The ${this.constructor.name} class may not be instantiated!`); } /** * @method trigger * @name trigger * @description Trigger an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.trigger("./image.png") .then(triggered => { canvacard.write(triggered, "triggered.gif"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to trigger * @returns {Promise<Buffer>} Triggered image * @throws {APIError} If image is not provided */ static async trigger(image) { if (!image) throw new APIError("Expected image, received nothing!"); await Canvacard.__wait(); return await Trigger(image, ImageFactory.TRIGGERED); // The image is used from ImageFactory } /** * @method invert * @name invert * @description Invert an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.invert("./image.png") .then(inverted => { canvacard.write(inverted, "inverted.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to invert * @returns {Promise<Buffer>} Inverted image * @throws {APIError} If image is not provided */ static async invert(image) { if (!image) throw new APIError("Expected image, received nothing!"); return await Invert(image); } /** * @method sepia * @name sepia * @description Sepia an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.sepia("./image.png") .then(sepia => { canvacard.write(sepia, "sepia.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to sepia * @returns {Promise<Buffer>} Sepia image * @throws {APIError} If image is not provided */ static async sepia(image) { if (!image) throw new APIError("Expected image, received nothing!"); return await Sepia(image); } /** * @method greyscale * @name greyscale * @description Greyscale an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.greyscale("./image.png") .then(greyscale => { canvacard.write(greyscale, "greyscale.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to greyscale * @returns {Promise<Buffer>} Greyscale image * @throws {APIError} If image is not provided */ static async greyscale(image) { if (!image) throw new APIError("Expected image, received nothing!"); return await Greyscale(image); } /** * @method brightness * @name brightness * @description Edit the brightness of the image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.brightness("./image.png", 50) .then(brightened => { canvacard.write(brightened, "brightened.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to brighten * @param {number} amount Amount of brightness * @returns {Promise<Buffer>} Brightened image * @throws {APIError} If image is not provided o la cantidad no es un número */ static async brightness(image, amount) { if (!image) throw new APIError("Expected image, received nothing!"); if (isNaN(amount)) throw new APIError("The quantity must be a number!"); return await Brightness(image, amount); } /** * @method darkness * @name darkness * @description Darken an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.darkness("./image.png", 50) .then(darkened => { canvacard.write(darkened, "darkened.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to darken * @param {number} amount Amount of darkness * @returns {Promise<Buffer>} Darkened image * @throws {APIError} If image is not provided o la cantidad no es un número */ static async darkness(image, amount) { if (!image) throw new APIError("Expected image, received nothing!"); if (isNaN(amount)) throw new APIError("The quantity must be a number!"); return await Darkness(image, amount); } /** * @method threshold * @name threshold * @descrioption Threshold an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.threshold("./image.png", 128) .then(thresholded => { canvacard.write(thresholded, "thresholded.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to threshold * @param {number} amount Amount of threshold * @returns {Promise<Buffer>} Thresholded image * @throws {APIError} If image is not provided o la cantidad no es un número */ static async threshold(image, amount) { if (!image) throw new APIError("Expected image, received nothing!"); if (isNaN(amount)) throw new APIError("The quantity must be a number!"); return await Threshold(image, amount); } /** * @method convolute * @name convolute * @description Convolute an image * @example * ```js const canvacard = require("canvacard"); const matrix = [0, -1, 0, -1, 5, -1, 0, -1, 0]; // Ejemplo de matriz de convolución canvacard.Canvas.convolute("./image.png", matrix, true) .then(convoluted => { canvacard.write(convoluted, "convoluted.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to convolute * @param {number[]} matrix Convolution matrix * @param {boolean} opaque If the image should be opaque * @returns {Promise<Buffer>} Convoluted image * @throws {APIError} If image is not provided o la matriz no es un Array */ static async convolute(image, matrix, opaque) { if (!image) throw new APIError("Expected image, received nothing!"); if (!Array.isArray(matrix)) throw new APIError("The convolution matrix must be Array."); return await Convolute(image, matrix, opaque); } /** * @method pixelate * @name pixelate * @description Pixelate an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.pixelate("./image.png", 5) .then(pixelated => { canvacard.write(pixelated, "pixelated.png"); }) .catch(console.error); * @param {string|Buffer} image Image to pixelate * @param {number} pixels Amount of pixels * @returns {Promise<Buffer>} Pixelated image * @throws {APIError} If image is not provided o los píxeles no son un número */ static async pixelate(image, pixels = 5) { if (!image) throw new APIError("Image was not provided!"); if (!pixels || typeof pixels !== "number") pixels = 100; if (pixels < 1) pixels = 100; if (pixels > 100) pixels = 100; const img = await loadImage(image); const canvas = createCanvas(img.width, img.height); const ctx = canvas.getContext("2d"); const pixel = pixels / 100; ctx.drawImage(img, 0, 0, canvas.width * pixel, canvas.height * pixel); ctx.imageSmoothingEnabled = false; ctx.drawImage(canvas, 0, 0, canvas.width * pixel, canvas.height * pixel, 0, 0, canvas.width + 5, canvas.height + 5); return canvas.toBuffer("image/png"); } /** * @method sharpen * @name sharpen * @description Sharpen an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.sharpen("./image.png", 1) .then(sharpened => { canvacard.write(sharpened, "sharpened.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to sharpen * @param {number} lvl Level of sharpening * @returns {Promise<Buffer>} Sharpened image * @throws {APIError} If image is not provided o el nivel no es un número */ static async sharpen(image, lvl = 1) { if (!image) throw new APIError("Image was not provided!"); if (isNaN(lvl)) throw new APIError("Level must be a number!"); return await Convolute(image, Canvacard.CONVOLUTION_MATRIX.SHARPEN, true, lvl); } /** * @method burn * @name burn * @description Burn an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.burn("./image.png", 1) .then(burned => { canvacard.write(burned, "burned.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to burn * @param {number} lvl Level of burning * @returns {Promise<Buffer>} Burned image * @throws {APIError} If image is not provided o el nivel no es un número */ static async burn(image, lvl = 1) { if (!image) throw new APIError("Image was not provided!"); if (isNaN(lvl)) throw new APIError("Level must be a number!"); return await Convolute(image, Canvacard.CONVOLUTION_MATRIX.BURN, true, lvl); } /** * @method circle * @name circle * @description Circle an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.circle("./image.png") .then(circled => { canvacard.write(circled, "circled.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to circle * @returns {Promise<Buffer>} Circled image * @throws {APIError} If image is not provided */ static async circle(image) { if (!image) throw new APIError("Image was not provided!"); const img = await loadImage(image); const canvas = createCanvas(img.width, img.height); const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); circle(ctx, canvas.width, canvas.height); return canvas.toBuffer("image/png"); } /** * @method fuse * @name fuse * @description Fuse two images * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.fuse("./image1.png", "./image2.png") .then(fused => { canvacard.write(fused, "fused.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image1 First image * @param {string|Buffer} image2 Second image * @returns {Promise<Buffer>} Fused image * @throws {APIError} If image is not provided */ static async fuse(image1, image2) { if (!image1) throw new APIError("The parameter 'image1' is missing."); if (!image2) throw new APIError("The parameter 'image2' is missing."); const img1 = await loadImage(image1); const img2 = await loadImage(image2); const canvas = createCanvas(img1.width, img1.height); const ctx = canvas.getContext("2d"); ctx.globalAlpha = 0.5; ctx.drawImage(img1, 0, 0); ctx.drawImage(img2, 0, 0, canvas.width, canvas.height); return canvas.toBuffer("image/png"); } /** * @method resize * @name resize * @description Resize an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.resize("./image.png", 500, 500) .then(resized => { canvacard.write(resized, "resized.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to resize * @param {number} width Width * @param {number} height Height * @returns {Promise<Buffer>} Resized image * @throws {APIError} If image is not provided */ static async resize(image, width, height) { if (!image) throw new APIError("Image was not provided!"); const img = await loadImage(image); const w = width && !isNaN(width) ? width : img.width; const h = height && !isNaN(height) ? width : img.height; const canvas = await createCanvas(w, h); const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); return canvas.toBuffer("image/png"); } /** * @method kiss * @name kiss * @description Kiss someone ( ͡° ͜ʖ ͡°) * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.kiss("./image1.png", "./image2.png") .then(kissed => { canvacard.write(kissed, "kissed.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image1 First image * @param {string|Buffer} image2 Second image * @returns {Promise<Buffer>} Imagen de beso * @throws {APIError} If image is not provided */ static async kiss(image1, image2) { if (!image1) throw new APIError("The parameter 'image1' is missing."); if (!image2) throw new APIError("The parameter 'image2' is missing."); await this.__wait(); const canvas = createCanvas(768, 574); const ctx = canvas.getContext("2d"); const background = await loadImage(ImageFactory.KISS); ctx.drawImage(background, 0, 0, canvas.width, canvas.height); const avatar = await loadImage(image1); const avatar1 = await loadImage(image2); ctx.drawImage(avatar1, 370, 25, 200, 200); ctx.drawImage(avatar, 150, 25, 200, 200); return canvas.toBuffer("image/png"); } /** * @method spank * @name spank * @description To spank someone ( ͡° ͜ʖ ͡°) * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.spank("./image1.png", "./image2.png") .then(spanked => { canvacard.write(spanked, "spanked.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image1 First image * @param {string|Buffer} image2 Second image * @returns {Promise<Buffer>} Image of spank * @throws {APIError} If image is not provided */ static async spank(image1, image2) { if (!image1) throw new APIError("The parameter 'image1' is missing."); if (!image2) throw new APIError("The parameter 'image2' is missing."); await this.__wait(); const canvas = createCanvas(500, 500); const ctx = canvas.getContext("2d"); const background = await loadImage(ImageFactory.SPANK); ctx.drawImage(background, 0, 0, canvas.width, canvas.height); const avatar = await loadImage(image1); const avatar1 = await loadImage(image2); ctx.drawImage(avatar1, 350, 220, 120, 120); ctx.drawImage(avatar, 225, 5, 140, 140); return canvas.toBuffer("image/png"); } /** * @method slap * @name slap * @description Slap someone ( ͡° ͜ʖ ͡°) * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.slap("./image1.png", "./image2.png") .then(slap => { canvacard.write(slap, "slap.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image1 First image * @param {string|Buffer} image2 Second image * @returns {Promise<Buffer>} Image of slap * @throws {APIError} If image is not provided */ static async slap(image1, image2) { if (!image1) throw new APIError("The parameter 'image1' is missing."); if (!image2) throw new APIError("The parameter 'image2' is missing."); await this.__wait(); const canvas = createCanvas(1000, 500); const ctx = canvas.getContext("2d"); const background = await loadImage(ImageFactory.BATSLAP); ctx.drawImage(background, 0, 0, canvas.width, canvas.height); const avatar = await loadImage(image1); const avatar1 = await loadImage(image2); ctx.drawImage(avatar1, 580, 260, 200, 200); ctx.drawImage(avatar, 350, 70, 220, 220); return canvas.toBuffer("image/png"); } /** * @method facepalm * @name facepalm * @description Facepalm someone * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.facepalm("./image.png") .then(facepalm => { canvacard.write(facepalm, "facepalm.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to facepalm * @returns {Promise<Buffer>} Image of facepalm * @throws {APIError} If image is not provided */ static async facepalm(image) { if (!image) throw new APIError("Image was not provided!"); await this.__wait(); let layer = await loadImage(ImageFactory.FACEPALM); let canvas = createCanvas(632, 357); let ctx = canvas.getContext("2d"); ctx.fillStyle = "black"; ctx.fillRect(0, 0, 632, 357); let avatar = await loadImage(image); ctx.drawImage(avatar, 199, 112, 235, 235); ctx.drawImage(layer, 0, 0, 632, 357); return canvas.toBuffer("image/png"); } /** * @method colorfy * @name colorfy * @description Colorfy an image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.colorfy("./image.png", "#FF0000") .then(colorfy => { canvacard.write(colorfy, "colorfy.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to colorfy * @param {string} color Color to apply to the image (hex) * @returns {Promise<Buffer>} Colorfied image * @throws {APIError} If image is not provided */ static async colorfy(image, color) { if (!image) throw new APIError("Image was not provided!"); const img = await loadImage(image); const canvas = createCanvas(img.width, img.height); const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); if (color) { ctx.globalCompositeOperation = "color"; ctx.fillStyle = color; ctx.fillRect(0, 0, canvas.width, canvas.height); } return canvas.toBuffer("image/png"); } /** * @method distracted * @name distracted * @description Distract someone * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.distracted("./image1.png", "./image2.png", "./image3.png") .then(distracted => { canvacard.write(distracted, "distracted.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image1 Face for the girl in red. * @param {string|Buffer} image2 Face for the boy. * @param {string|Buffer} image3 Face for the other girl [optional] * @returns {Promise<Buffer>} Distracted image * @throws {APIError} If image is not provided */ static async distracted(image1, image2, image3 = null) { if (!image1) throw new APIError("The parameter 'image1' is missing."); if (!image2) throw new APIError("The parameter 'image2' is missing."); await this.__wait(); const background = await loadImage(ImageFactory.DISTRACTED); const avatar1 = await loadImage(await Canvacard.circle(image1)); const avatar2 = await loadImage(await Canvacard.circle(image2)); const avatar3 = image3 ? await loadImage(await Canvacard.circle(image3)) : null; const canvas = createCanvas(background.width, background.height); const ctx = canvas.getContext("2d"); ctx.drawImage(background, 0, 0, canvas.width, canvas.height); ctx.drawImage(avatar1, 180, 90, 150, 150); ctx.drawImage(avatar2, 480, 35, 130, 130); if (avatar3) ctx.drawImage(avatar3, 730, 110, 130, 130); return canvas.toBuffer("image/png"); } /** * @method jail * @name jail * @description Create a jail image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.jail("./image.png") .then(jail => { canvacard.write(jail, "jail.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to jail * @param {boolean} greyscale If the image should be greyscale * @returns {Promise<Buffer>} Jailed image * @throws {APIError} If image is not provided */ static async jail(image, greyscale = false) { if (!image) throw new APIError("Image was not provided!"); await this.__wait(); const img = await loadImage(greyscale ? await Canvacard.greyscale(image) : image); const bg = await loadImage(ImageFactory.JAIL); const canvas = createCanvas(350, 350); const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); ctx.drawImage(bg, 0, 0, canvas.width, canvas.height); return canvas.toBuffer("image/png"); } /** * @method bed * @name bed * @description Create a bed image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.bed("./image1.png", "./image2.png") .then(bed => { canvacard.write(bed, "bed.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image1 First image * @param {string|Buffer} image2 Second image * @returns {Promise<Buffer>} Imagen de cama * @throws {APIError} If image is not provided */ static async bed(image1, image2) { if (!image1) throw new APIError("The parameter 'image1' is missing."); if (!image2) throw new APIError("The parameter 'image2' is missing."); await this.__wait(); const avatar = await loadImage(image1); const avatar1 = await loadImage(image2); const background = await loadImage(ImageFactory.BED); const canvas = createCanvas(background.width, background.height); const ctx = canvas.getContext("2d"); ctx.drawImage(background, 0, 0, canvas.width, canvas.height); ctx.drawImage(avatar, 25, 100, 100, 100); ctx.drawImage(avatar, 25, 300, 100, 100); ctx.drawImage(avatar, 53, 450, 70, 70); ctx.drawImage(avatar1, 53, 575, 100, 100); return canvas.toBuffer("image/png"); } /** * @method delete * @name delete * @description Create a deleted image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.delete("./image.png") .then(deleted => { canvacard.write(deleted, "deleted.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to delete * @param {boolean} dark If the image should be dark * @returns {Promise<Buffer>} Deleted image * @throws {APIError} If image is not provided */ static async delete(image, dark = false) { if (!image) throw new APIError("Image was not provided!"); await this.__wait(); const img = await loadImage(image); const bg = await loadImage(dark ? await Canvacard.invert(ImageFactory.DELETE) : ImageFactory.DELETE); const canvas = createCanvas(bg.width, bg.height); const ctx = canvas.getContext("2d"); ctx.drawImage(bg, 0, 0, canvas.width, canvas.height); ctx.drawImage(img, 120, 135, 195, 195); return canvas.toBuffer("image/png"); } /** * @method gradient * @name gradient * @description Create a gradient image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.gradient("#FF0000", "#0000FF", 500, 500) .then(gradient => { canvacard.write(gradient, "gradient.png"); }) .catch(console.error); * ``` * @param {string} colorFrom First color * @param {string} colorTo Second color * @param {number} width Width of image * @param {number} height Height of image * @returns {Promise<Buffer>} Gradient image * @throws {APIError} If colorFrom or colorTo is not provided */ static gradient(colorFrom, colorTo, width, height) { if (!colorFrom) throw new APIError("ColorFrom was not provided!"); if (!colorTo) throw new APIError("ColorTo was not provided!"); const canvas = createCanvas(width || 400, height || 200); const ctx = canvas.getContext("2d"); const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0); gradient.addColorStop(0, colorFrom); gradient.addColorStop(1, colorTo); ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); return canvas.toBuffer("image/png"); } /** * @method quote * @name quote * @description Create a fake quote image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.quote({ image: "./image.png", message: "This is amazing!", username: "Clyde", color: "#FFFFFF" }) .then(quote => { canvacard.write(quote, "quote.png"); }) .catch(console.error); * ``` * @param {object} options Options * @param {Buffer|string} [options.image] Image * @param {string} [options.message] Message * @param {string} [options.username] Username * @param {string} [options.color] Color * @param {string} [font="Arial"] Text font for the card * @returns {Promise<Buffer>} Quote image */ static async quote(options = { image, message, username, color }, font = "Arial") { await this.__wait(); if (!options.image) options.image = ImageFactory.CLYDE; if (!options.message) options.message = "Please provide a text message."; if (!options.username) options.username = "Clyde"; if (!options.color) options.color = "#FFFFFF"; let image = await loadImage(await Canvacard.circle(options.image)); const canvas = createCanvas(1500, 300); const ctx = canvas.getContext("2d"); ctx.fillStyle = "#36393E"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.drawImage(image, 75, 30, 130, 130); ctx.font = `40px ${font}`; ctx.fillStyle = "#FFFFFF"; ctx.textAlign = "start"; ctx.fillText(shorten(options.message, 66), 230, 150); ctx.font = `50px ${font}`; ctx.fillStyle = typeof options.color == "string" ? options.color : "#FFFFFF"; ctx.textAlign = "start"; ctx.fillText(typeof options.username === "string" ? shorten(options.username, 17) : "Clyde", 230, 80); ctx.font = `50px ${font}`; ctx.fillStyle = "#7D7D7D"; ctx.textAlign = "start"; ctx.fillText(discordTime(), 240 + ctx.measureText(shorten(options.username, 17)).width + 110, 80); return canvas.toBuffer("image/png"); } /** * @method phub * @name phub * @description PornHub Comment * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.phub({ username: "Clyde", message: "This is amazing!", image: "./image.png" }) .then(phub => { canvacard.write(phub, "phub.png"); }) .catch(console.error); * ``` * @param {Object} options Options * @param {String} [options.username] Username * @param {String} [options.message] Message * @param {String|Buffer} [options.image] Image * @param {string} [font="Arial"] Text font for card * @returns {Promise<Buffer>} PornHub Comment image * @throws {APIError} If username, message or image is not provided */ static async phub(options = { username: null, message: null, image: null }, font = "Arial") { if (!options.username) throw new APIError("Username cannot be empty!"); if (!options.message) throw new APIError("Message cannot be empty!"); if (!options.image) throw new APIError("The image cannot be empty!"); await this.__wait(); let image = await loadImage(options.image); let baseImage = await loadImage(ImageFactory.PHUB); let canvas = createCanvas(baseImage.width, baseImage.height); let ctx = canvas.getContext("2d"); ctx.drawImage(baseImage, 0, 0, canvas.width, canvas.height); ctx.drawImage(image, 30, 310, 70, 70); ctx.font = `32px ${font}`; ctx.fillStyle = "#F99600"; ctx.textAlign = "start"; ctx.fillText(shorten(options.username, 20), 115, 350); ctx.font = `32px ${font}`; ctx.fillStyle = "#CCCCCC"; ctx.textAlign = "start"; ctx.fillText(shorten(options.message, 50), 30, 430); return canvas.toBuffer("image/png"); } /** * @method wanted * @name wanted * @description Create a "wanted" image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.wanted("./image.png") .then(wanted => { canvacard.write(wanted, "wanted.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to wanted * @returns {Promise<Buffer>} Wanted image * @throws {APIError} If image is not provided */ static async wanted(image) { if (!image) throw new APIError("Image was not provided!"); await this.__wait(); const img = await loadImage(image); const bg = await loadImage(ImageFactory.WANTED); const canvas = createCanvas(bg.width, bg.height); const ctx = canvas.getContext("2d"); ctx.drawImage(bg, 0, 0, canvas.width, canvas.height); ctx.drawImage(img, 145, 282, 447, 447); return canvas.toBuffer("image/png"); } /** * @method wasted * @name wasted * @description Create a "wasted" image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.wasted("./image.png") .then(wasted => { canvacard.write(wasted, "wasted.png"); }) .catch(console.error); * ``` * @param {string|Buffer} image Image to wasted * @returns {Promise<Buffer>} Wasted image * @throws {APIError} If image is not provided */ static async wasted(image) { if (!image) throw new APIError("Image was not provided!"); await this.__wait(); const img = await loadImage(await Canvacard.greyscale(image)); const bg = await loadImage(ImageFactory.WASTED); const canvas = createCanvas(512, 512); const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); ctx.drawImage(bg, 0, 0, canvas.width, canvas.height); return canvas.toBuffer("image/png"); } /** * @method youtube * @name youtube * @description Create a YouTube comment image * @example * ```js const canvacard = require("canvacard"); canvacard.Canvas.youtube({ username: "Clyde", content: "This is amazing!", avatar: "./image.png" }) .then(youtube => { canvacard.write(youtube, "youtube.png"); }) .catch(console.error); * ``` * @param {object} ops Options * @param {string} [ops.username] Username * @param {string} [ops.content] Content * @param {string|Buffer} [ops.avatar] Avatar * @param {boolean} [ops.dark=false] Dark mode * @returns {Promise<Buffer>} YouTube comment image * @throws {APIError} If username, content or avatar is not provided */ static async youtube(ops = { username: null, content: null, avatar: null, dark: false }) { if (!ops.username || typeof ops.username !== "string") throw new APIError("Username cannot be empty!"); if (!ops.content || typeof ops.content !== "string") throw new APIError("Content cannot be empty!"); if (!ops.avatar) throw new APIError("The avatar font may not be empty!"); ops.dark = !!ops.dark; await this.__wait(); const bg = await loadImage(!ops.dark ? ImageFactory.YOUTUBE : await Canvacard.invert(ImageFactory.YOUTUBE)); const avatar = await loadImage(await Canvacard.circle(ops.avatar)); const canvas = createCanvas(bg.width, bg.height); const ctx = canvas.getContext("2d"); ctx.drawImage(bg, -3, -3, canvas.width + 6, canvas.height + 6); ctx.drawImage(avatar, 17, 33, 52, 52); let time = Math.floor(Math.random() * (59 - 1)) + 1; time = `${time + (time == 1 ? " minute" : " minutes")} ago`; const username = shorten(ops.username, 21); const comment = shorten(ops.content, 60); ctx.font = "20px Roboto"; ctx.fillStyle = ops.dark ? "#FFFFFF" : "#000000"; ctx.fillText(username, 92, 50); ctx.font = "16px Roboto"; ctx.fillStyle = "#909090"; ctx.fillText(time, ctx.measureText(username).width + 140, 50); ctx.font = "18px Roboto"; ctx.fillStyle = ops.dark ? "#FFFFFF" : "#000000"; ctx.fillText(comment, 92, 80); return canvas.toBuffer("image/png"); } /** * @method write * @name write * @description Writes data as a file * @param {Buffer} data data to write * @param {string} name file name * @returns {void} */ static write(data, name) { return fs.writeFileSync(name, data); } /** * @method reply * @name reply * @description Discord Reply Clone * @param {object} options Options * @param {string|Buffer} [options.avatar1] Avatar of the person who responded * @param {string|Buffer} [options.avatar2] Avatar of the other person * @param {string} [options.user1] Username of the person who responded * @param {string} [options.user2] Username of the other person * @param {string} [options.hex1] Hexadecimal color of the person who responded * @param {string} [options.hex2] Hexadecimal color of the other person * @param {string} [options.mainText] Message of the person who responded * @param {string} [options.replyText] Message of the other person * @returns {Promise<Buffer>} Reply image * @throws {APIError} If the avatar, username or message is not provided * @example const img = "https://cdn.discordapp.com/embed/avatars/0.png"; const img2 = "https://cdn.discordapp.com/embed/avatars/4.png"; canvacard.Canvas.reply({ avatar1: img, avatar2: img2, user1: "Maximus", user2: "SrGobi", hex1: "#FF3300", hex2: "#7289da", mainText: "kok", replyText: "Pog" }) .then(img => canvacard.write(img, "reply.png")); */ static async reply(options = { avatar1: null, avatar2: null, user1: null, user2: null, hex1: null, hex2: null, mainText: null, replyText: null }) { const { avatar1, avatar2, user1, user2, hex1, hex2, mainText, replyText } = options; if (!avatar1) throw new APIError("The first avatar was not provided!"); if (!avatar2) throw new APIError("The second avatar was not provided!"); if (!user1) throw new APIError("First username not provided!"); if (!user2) throw new APIError("Second username not provided!"); if (!mainText || typeof mainText !== "string") throw new APIError("The main text was not provided!"); if (!replyText || typeof replyText !== "string") throw new APIError("Response text not provided!"); if (!hex1 || typeof hex1 !== "string") hex1 = "#FFFFFF"; if (!hex2 || typeof hex2 !== "string") hex2 = "#FFFFFF"; const img1 = await loadImage(avatar1); const img2 = await loadImage(avatar2); const canvas = createCanvas(1300, 250); const ctx = canvas.getContext("2d"); ctx.fillStyle = "#36393E"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#ffffff"; ctx.textAlign = "left"; ctx.font = "38px Manrope"; ctx.fillText(shorten(replyText, 32), 186, 200); ctx.font = "38px Whitney"; ctx.fillStyle = formatAndValidateHex(hex1, "#FFFFFF"); ctx.fillText(user1, 185, 147); const usernameWidth = ctx.measureText(user1).width; ctx.fillStyle = "#d1d1d1"; ctx.font = "38px Manrope"; ctx.fillText(" answer ", 165 + usernameWidth + 20, 147); const repliedWidth = ctx.measureText(" answer ").width; ctx.fillStyle = formatAndValidateHex(hex2, "#FFFFFF"); ctx.font = "38px Whitney"; ctx.fillText(user2, 165 + usernameWidth + repliedWidth + 20, 167 - 20); const secondMemberUserWidth = ctx.measureText(user2).width; ctx.font = "26px Whitney"; ctx.fillStyle = "#7a7c80"; const time = discordTime(); ctx.fillText(` ${time}`, 165 + usernameWidth + repliedWidth + secondMemberUserWidth + 3 + 20, 167 - 20) ctx.font = "29px Whitney"; ctx.globalAlpha = 0.7; ctx.fillStyle = "#d1d1d1"; ctx.fillText(shorten(mainText, 64), 195 + 20 + 20, 100 + 5 - 20); ctx.strokeStyle = "#a3a2a2"; ctx.lineWidth = 4; ctx.globalAlpha = 0.4; ctx.moveTo(34 + (105 / 2) + 70 + 20, 92 + 5 - 20); ctx.lineTo(34 + (105 / 2) + 20, 92 + 5 - 20); ctx.moveTo(34 + (105 / 2) + 20, 92 + 5 - 20); ctx.quadraticCurveTo(34 + (105 / 2) + 4, 92 + 5 - 20, 34 + (105 / 2), 103 + 5 - 20); ctx.moveTo(34 + (105 / 2), 125 - 20); ctx.lineTo(34 + (105 / 2), 103 + 5 - 20); ctx.stroke(); ctx.globalAlpha = 1; ctx.save(); ctx.beginPath(); ctx.lineWidth = 1; ctx.arc(90, 182 - 20, 50, 0, Math.PI * 2, true); ctx.strokeStyle = "#36393E"; ctx.stroke(); ctx.closePath(); ctx.clip(); ctx.drawImage(img1, 38, 130 - 20, 105, 105); ctx.restore(); ctx.save(); ctx.beginPath(); ctx.lineWidth = 1; ctx.arc(165 + 20 + 20, 90 + 5 - 20, 20, 0, Math.PI * 2); ctx.strokeStyle = "#36393E"; ctx.stroke(); ctx.closePath(); ctx.clip(); ctx.drawImage(img2, 165 + 20, 70 + 5 - 20, 40, 40); ctx.restore(); return canvas.toBuffer("image/png"); } /** * Canvacard method used for `wait`. * @param {number} dur Number of milliseconds to wait * @returns {Promise<void>} Promise fulfilled after the wait * @private */ static __wait(dur) { return new Promise((res) => { setTimeout(() => res(), dur || 250); }); } /** * Canvacard convolution matrix * @typedef {object} ConvolutionMatrix * @property {number[]} EDGES Edges Matrix * @property {number[]} BLUR Blur Matrix * @property {number[]} SHARPEN Sharpen Matrix * @property {number[]} BURN Burn Matrix * @private */ /** * Array data for **Canvacard.convolute()** * @type {ConvolutionMatrix} * @private */ static get CONVOLUTION_MATRIX() { return { EDGES: [0, -1, 0, -1, 4, -1, 0, -1, 0], BLUR: [1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9], SHARPEN: [0, -1, 0, -1, 5, -1, 0, -1, 0], BURN: [1 / 11, 1 / 11, 1 / 11, 1 / 11, 1 / 11, 1 / 11, 1 / 11, 1 / 11, 1 / 11] }; } } module.exports = Canvacard;