File: src/js/app.ts

Recommend this page to a friend!
  Classes of Dom Hastings   JS Image to ANSI   src/js/app.ts   Download  
File: src/js/app.ts
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: JS Image to ANSI
Convert an image pixels to ANSI colour codes
Author: By
Last change: Fix bug where changing an option without a url or uplaoded image would lock the UI.
Updates and simplification to core code.
Added `docker-compose.yml` for easy local testing.
Date: 2 years ago
Size: 4,217 bytes
 

Contents

Class file image Download
import readImage, { loadImage } from './readImage'; import process from './process'; import { Terminal } from 'xterm'; import { FitAddon } from 'xterm-addon-fit'; import 'bootstrap/dist/js/bootstrap.bundle.min'; document.addEventListener('click', (event): void => { const eventTarget = event.target; if (!(eventTarget instanceof HTMLElement)) { return; } if (!eventTarget.matches('a.copy')) { return; } event.preventDefault(); const target = eventTarget.dataset.clipboardTarget ?? null; if (!target) { return; } const contentElement = document.querySelector(target); if (!contentElement) { return; } navigator.clipboard.writeText( (contentElement as HTMLElement).innerText.replace(/\x1b/g, '\\e') ); }); const fileButton = document.querySelector('.parser .btn') as HTMLLabelElement, fileInput = fileButton.querySelector( 'input[type="file"]' ) as HTMLInputElement, spinner = fileButton.querySelector('.spinner-border') as HTMLSpanElement, urlInput = document.querySelector('input[type="url"]') as HTMLInputElement, errorContainer = document.querySelector('.error-container') as HTMLDivElement, errorContent = errorContainer.querySelector( '.error-content' ) as HTMLDivElement, coloursInputs = Array.from( document.querySelectorAll('input[name="colours"]') ) as HTMLInputElement[], maxHeightInput = document.querySelector( 'input[name="maxHeight"]' ) as HTMLInputElement, maxWidthInput = document.querySelector( 'input[name="maxWidth"]' ) as HTMLInputElement, unicodeInput = document.querySelector( 'input[name="unicode"]' ) as HTMLInputElement, terminal = new Terminal({ convertEol: true, theme: { background: '#272822', cursor: 'transparent', foreground: '#f8f8f2', }, }), fit = new FitAddon(), copyPaste = document.querySelector('pre.copy-paste code') as HTMLElement, displayError = (error: string = '') => { if (error === '') { errorContainer.classList.add('d-none'); errorContent.innerText = ''; return; } errorContainer.classList.remove('d-none'); errorContent.innerText = error; }, processImage = (url: string, done: () => void = () => {}): Promise<void> => loadImage(url) .then((image) => { const ansiEscape = process(image, { colours: coloursInputs.reduce((value: string, el) => { if (el.checked) { return el.value; } return value; }, '256'), maxHeight: parseInt(maxHeightInput.value, 10), maxWidth: parseInt(maxWidthInput.value, 10), unicode: unicodeInput.checked, }); terminal.reset(); terminal.write(ansiEscape); copyPaste.innerText = `printf "${ansiEscape.replace(/\x1b/g, '\\e')}";`; displayError(''); }) .catch((e) => displayError(e.message)) .finally(() => done()), generate = (done: () => void = () => {}) => { const file = fileInput?.files?.[0], url = urlInput.value; if (file) { readImage(file) .then((url) => processImage(url, done)) .catch((e) => displayError(e.message)); return; } if (url) { processImage(url, done); return; } requestAnimationFrame(done); }; terminal.loadAddon(fit); terminal.open(document.querySelector('div.terminal') as HTMLDivElement); fit.fit(); window.addEventListener('resize', () => fit.fit()); fileInput.addEventListener('input', () => { urlInput.value = ''; }); urlInput.addEventListener('input', (event) => { if (!urlInput.reportValidity() || urlInput.value === '') { event.stopImmediatePropagation(); return; } fileInput.value = ''; }); [ ...coloursInputs, maxHeightInput, maxWidthInput, unicodeInput, fileInput, urlInput, ].forEach((input) => input.addEventListener('input', () => { fileButton.classList.add('disabled'); urlInput.setAttribute('disabled', ''); spinner.classList.remove('d-none'); generate(() => { fileButton.classList.remove('disabled'); urlInput.removeAttribute('disabled'); spinner.classList.add('d-none'); }); }) );