Name outputs from the input, engine, and LoRA keys instead of aigen_0001. Image-edit presets now store prompts, and aspect fill pads stills without stretching.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-30 16:24:49 -05:00
co-authored by Cursor
parent 4d411f83d4
commit 0e1222d035
23 changed files with 668 additions and 93 deletions
+54
View File
@@ -0,0 +1,54 @@
export const IMAGE_ASPECT_IDS = ['auto', '16:9', '9:16', '1:1'] as const
export type ImageAspectId = (typeof IMAGE_ASPECT_IDS)[number]
export const IMAGE_FILL_INSTRUCTION =
'Extend the photograph to fill the empty edges of the frame. Do not stretch or squash the original image. Keep the original subject, pose, and framing. Match lighting, perspective, and texture in the filled areas.'
export function parseImageAspect(raw: unknown): ImageAspectId {
const value = String(raw || 'auto').trim()
return value === '16:9' || value === '9:16' || value === '1:1' ? value : 'auto'
}
export function imageAspectRatio(aspect: Exclude<ImageAspectId, 'auto'>) {
if (aspect === '16:9') return 16 / 9
if (aspect === '9:16') return 9 / 16
return 1
}
export function generateSizeForAspect(aspect: ImageAspectId) {
if (aspect === '16:9') return { width: 1280, height: 768, aspect: '16:9' as const }
if (aspect === '9:16') return { width: 768, height: 1280, aspect: '9:16' as const }
return { width: 1024, height: 1024, aspect: '1:1' as const }
}
export function composeFillPrompt(userPrompt: string, padded: boolean) {
const body = String(userPrompt || '').trim()
if (!padded) return body
return body ? `${IMAGE_FILL_INSTRUCTION}\n\n${body}` : IMAGE_FILL_INSTRUCTION
}
export function snapImagePad(value: number) {
return Math.max(32, Math.round(value / 32) * 32)
}
export function padExtents(srcW: number, srcH: number, aspect: Exclude<ImageAspectId, 'auto'>) {
if (!srcW || !srcH) return null
const target = imageAspectRatio(aspect)
const src = srcW / srcH
if (Math.abs(src - target) < 0.03) return null
let canvasW = srcW
let canvasH = srcH
if (src > target) {
canvasW = snapImagePad(srcW)
canvasH = snapImagePad(canvasW / target)
} else {
canvasH = snapImagePad(srcH)
canvasW = snapImagePad(canvasH * target)
}
if (canvasW < srcW) canvasW = snapImagePad(srcW)
if (canvasH < srcH) canvasH = snapImagePad(srcH)
const x = Math.max(0, Math.floor((canvasW - srcW) / 2))
const y = Math.max(0, Math.floor((canvasH - srcH) / 2))
if (x === 0 && y === 0 && canvasW === srcW && canvasH === srcH) return null
return { canvasW, canvasH, x, y, srcW, srcH }
}