import { execa } from 'execa' const TIMEOUT = 30_000 export const SCHEMAS = { chafa: { size: { type: 'value' }, colors: { type: 'value', valid: ['none', '2', '8', '16/8', '16', '240', '256', 'full'] }, 'color-extractor': { type: 'value', valid: ['average', 'median', 'mode'] }, 'color-space': { type: 'value', valid: ['rgb', 'din99d'] }, symbols: { type: 'value' }, fill: { type: 'value' }, dither: { type: 'value', valid: ['none', 'ordered', 'diffusion', 'noise'] }, 'dither-grain': { type: 'value', valid: ['1x1', '2x2', '4x4', '8x8'] }, 'dither-intensity':{ type: 'value' }, threshold: { type: 'value' }, 'font-ratio': { type: 'value' }, work: { type: 'value' }, zoom: { type: 'bool' }, stretch: { type: 'bool' }, 'fg-only': { type: 'bool' }, format: { type: 'value', valid: ['symbols', 'utf8'] }, }, jp2a: { width: { type: 'value' }, height: { type: 'value' }, chars: { type: 'value' }, background: { type: 'value', valid: ['light', 'dark'] }, colors: { type: 'bool' }, 'color-depth': { type: 'value', valid: ['4', '8', '24'] }, fill: { type: 'bool' }, grayscale: { type: 'bool' }, invert: { type: 'bool' }, border: { type: 'bool' }, flipx: { type: 'bool' }, flipy: { type: 'bool' }, red: { type: 'value' }, green: { type: 'value' }, blue: { type: 'value' }, 'edge-threshold': { type: 'value' }, 'edges-only': { type: 'bool' }, }, 'ascii-image-converter': { width: { type: 'value' }, height: { type: 'value' }, color: { type: 'bool' }, braille: { type: 'bool' }, threshold: { type: 'value' }, }, img2txt: { width: { type: 'value' }, height: { type: 'value' }, format: { type: 'value', valid: ['ansi', 'utf8', 'html'] }, dither: { type: 'value', valid: ['none', 'ordered2', 'ordered4', 'ordered8', 'random', 'fstein'] }, gamma: { type: 'value' }, }, } export function buildArgs(tool, flags) { const schema = SCHEMAS[tool] if (!schema) throw new Error(`Unknown tool: ${tool}`) const args = [] for (const [key, value] of Object.entries(flags)) { const def = schema[key] if (!def) throw new Error(`Unknown flag for ${tool}: --${key}`) if (def.valid && !def.valid.includes(String(value))) { throw new Error(`Invalid value for --${key}: ${value}. Expected one of: ${def.valid.join(', ')}`) } if (def.type === 'bool') { if (value) args.push(`--${key}`) } else { args.push(`--${key}`, String(value)) } } return args } export async function runChafa(imagePath, flags) { const { width, height, ...rest } = flags const processed = { ...rest } if (width && height) processed.size = `${width}x${height}` else if (width) processed.size = `${width}x` else if (height) processed.size = `x${height}` const args = buildArgs('chafa', processed) return execa('chafa', [...args, imagePath], { timeout: TIMEOUT }) } export async function runJp2a(imagePath, flags) { const args = buildArgs('jp2a', flags) return execa('jp2a', [...args, imagePath], { timeout: TIMEOUT }) } export async function runAsciiImageConverter(imagePath, flags) { const args = buildArgs('ascii-image-converter', flags) return execa('ascii-image-converter', [...args, imagePath], { timeout: TIMEOUT }) } export async function runImgToTxt(imagePath, flags) { const args = buildArgs('img2txt', flags) return execa('img2txt', [...args, imagePath], { timeout: TIMEOUT }) }