57 lines
2.1 KiB
TypeScript
57 lines
2.1 KiB
TypeScript
// Resolution tier options for local retake/extend. Offers the source resolution plus
|
|
// standard lower tiers (named by short edge: 1080p / 720p / 540p). Grid sizes such as
|
|
// 576/704/1088 map to the nearest named tier. The backend snaps the chosen size to a
|
|
// valid (÷32, not-upscaled) resolution. Local only — the cloud preserves source resolution.
|
|
|
|
export interface ResolutionOption {
|
|
key: string
|
|
label: string
|
|
// null = "Original" (backend uses the source resolution, still ÷32-corrected).
|
|
width: number | null
|
|
height: number | null
|
|
}
|
|
|
|
const STANDARD_TIERS = [1080, 720, 540]
|
|
const NAMED_TIERS = [2160, 1440, 1080, 720, 540] as const
|
|
|
|
/** Map a pixel short-edge (incl. /64 grid sizes like 576, 704, 1088) to the picker tier name. */
|
|
export function namedResolutionTier(shortEdge: number): (typeof NAMED_TIERS)[number] {
|
|
return NAMED_TIERS.reduce((best, tier) =>
|
|
Math.abs(tier - shortEdge) < Math.abs(best - shortEdge) ? tier : best,
|
|
)
|
|
}
|
|
|
|
export function namedResolutionDisplayName(tier: number): string {
|
|
return tier >= 2160 ? '4K' : `${tier}p`
|
|
}
|
|
|
|
/** Display label for generation resolution ids (`2160p` → `4K`). */
|
|
export function videoGenerationResolutionLabel(resolution: string): string {
|
|
return resolution === '2160p' ? '4K' : resolution
|
|
}
|
|
|
|
export function resolutionOptions(width: number, height: number): ResolutionOption[] {
|
|
if (!width || !height) return []
|
|
const shortEdge = Math.min(width, height)
|
|
const longEdge = Math.max(width, height)
|
|
const portrait = height > width
|
|
|
|
const originalTier = namedResolutionTier(shortEdge)
|
|
|
|
const options: ResolutionOption[] = [
|
|
{ key: 'original', label: `${namedResolutionDisplayName(originalTier)} (Original)`, width: null, height: null },
|
|
]
|
|
for (const tier of STANDARD_TIERS) {
|
|
// Only smaller tiers, and drop the one that already maps to Original.
|
|
if (tier >= shortEdge || tier === originalTier) continue
|
|
const long = Math.round((longEdge * tier) / shortEdge)
|
|
options.push({
|
|
key: String(tier),
|
|
label: `${tier}p`,
|
|
width: portrait ? tier : long,
|
|
height: portrait ? long : tier,
|
|
})
|
|
}
|
|
return options
|
|
}
|