import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs' import { join } from 'node:path' import { tmpdir } from 'node:os' import { runFfmpeg } from '../ffmpeg' import { imageDimensions } from '../resolution' export async function fitStill(data: Buffer, width: number, height: number) { const dir=mkdtempSync(join(tmpdir(),'studio2-fit-')) try { const input=join(dir,'source'),output=join(dir,'fitted.png') writeFileSync(input,data) await runFfmpeg(['-y','-i',input,'-vf',`scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1`,'-frames:v','1',output]) return readFileSync(output) } finally { rmSync(dir,{recursive:true,force:true}) } } /** Only skip the scale+pad when the still already matches the job canvas pixel-for-pixel. * A same-aspect-but-larger still (e.g. a 4032x2268 phone photo against a 1344x768 canvas) * still needs fitting: MiniMaxH3AddGuide expects an image sized to the job's own latent, * not merely the same aspect ratio. Unreadable dimensions always fit (safe default). */ export function needsFit(data: Buffer, width: number, height: number) { const size = imageDimensions(data) if (!size?.width || !size?.height) return true return !(size.width === width && size.height === height) }