UNPKG

image-to-ascii-art

Version:
95 lines (79 loc) 3.25 kB
import { ConfigInterface, Config } from './model'; import { rgbToGray, grayToAsciiString } from './utils'; export class ImageToAsciiArt { private canvas: HTMLCanvasElement; private canvasCtx; private canvasIsStable: boolean; // If remove canvas dom when destroy.If "canvas" param of this Class was passed,it will be true. private config: Config; /** * @param canvas optional,the canvas used to generate ascii art.If it isn't passed,a hidden canvas will be append to body automatically. * @param config configuration */ private constructor({ canvas, config = {} }: { canvas?: HTMLCanvasElement; config?: ConfigInterface } = {}) { if (canvas instanceof HTMLCanvasElement) { this.canvas = canvas; this.canvasIsStable = true; } else { this.canvas = document.createElement('canvas'); this.canvas.style.display = 'none'; document.body.appendChild(this.canvas); } this.canvasCtx = this.canvas.getContext('2d'); this.setConfig(config); } public setConfig(config?: ConfigInterface): void { this.config = new Config(config); } /** * convert an image to an ascii art * @param image a HTMLImageElement instance or an URL of a image */ public convert(image: string | HTMLImageElement): Promise<string> { let _image; if (image instanceof HTMLImageElement) { _image = image; } else { _image = new Image(); _image.src = image; } return new Promise((resolve): void => { let doConvert = (): void => { _image.removeEventListener('load', doConvert); let drawWidth = this.config.drawWidth <= 1 ? this.config.drawWidth * _image.naturalWidth : this.config.drawWidth; let drawHeight = this.config.drawHeight <= 1 ? this.config.drawHeight * _image.naturalHeight : this.config.drawHeight; if (!this.canvasIsStable) { this.canvas.width = drawWidth; this.canvas.height = drawHeight; } this.canvasCtx.drawImage(_image, 0, 0, drawWidth, drawHeight); const imageData = this.canvasCtx.getImageData(0, 0, drawWidth, drawHeight); const imageDataArr = imageData.data; const imageDataHeight = imageData.height; const imageDataWidth = imageData.width; let arrGray = []; for (let h = 0; h < imageDataHeight; h += this.config.pickDensityHorizontal) { for (let w = 0; w < imageDataWidth; w += this.config.pickDensityVertical) { let index = (w + imageDataWidth * h) * 4; let r = imageDataArr[index]; let g = imageDataArr[index + 1]; let b = imageDataArr[index + 2]; arrGray.push(rgbToGray(r, g, b)); } // -1 stands for '\r\n' arrGray.push(-1); } resolve(grayToAsciiString(arrGray, [...this.config.greyRangeChar, { from: -1, to: -1, char: '\r\n' }])); }; if (!_image.complete) { _image.addEventListener('load', doConvert); } else { doConvert(); } }); } public destroy(): void { if (!this.canvasIsStable) { document.body.removeChild(this.canvas); } } }