ASCIInator/server/lib/converters.js
dev c1cf06ed67 feat: initial commit — ASCIInator v0.1
Vue 3 + Vite + Tailwind frontend, Fastify API server, execa shell bridge.
All components built, server validated, 41 unit tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 19:47:57 +00:00

80 lines
2.5 KiB
JavaScript

import { execa } from 'execa'
const TIMEOUT = 30_000
const SCHEMAS = {
chafa: {
size: { type: 'value' },
colors: { type: 'value', valid: ['none', '2', '8', '16/8', '16', '240', '256', 'full'] },
symbols: { type: 'value' },
dither: { type: 'value', valid: ['none', 'ordered', 'diffusion', 'noise'] },
threshold: { type: 'value' },
'font-ratio': { type: 'value' },
},
jp2a: {
width: { type: 'value' },
height: { type: 'value' },
chars: { type: 'value' },
background: { type: 'value', valid: ['light', 'dark'] },
},
'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' },
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 })
}