Files
aigen/utils/imageAspect.ts
T

55 lines
2.2 KiB
TypeScript

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 }
}