|
param( |
|
[string]$InputFile = "input.mp4", # Input file (GIF or video) |
|
[double]$StartTime = 48, # Start time for video input |
|
[double]$Duration = 4, # Duration to sample |
|
[int]$NumFrames = 24, # Number of frames to extract |
|
[string]$OutputPrefix = "output_strip", # Base name for output files |
|
[ValidateSet("horizontal", "vertical")] |
|
[string]$Layout = "horizontal", # Layout direction |
|
[string]$ResizeTo = "", # Optional: scale output (e.g. "480x270") |
|
[int]$TilePadding = 0 # Optional: spacing between frames (px) |
|
) |
|
|
|
# Auto-detect input type |
|
$IsGif = $InputFile.ToLower().EndsWith(".gif") |
|
$OutputPNG = "$OutputPrefix.png" |
|
$OutputWebP = "$OutputPrefix.webp" |
|
$OutputJSON = "$OutputPrefix.json" |
|
$FrameInterval = [math]::Round($Duration / $NumFrames, 4) |
|
|
|
# Log configuration |
|
Write-Output "`n🔧 Sprite Generation Configuration" |
|
Write-Output " Input file: $InputFile" |
|
if ($IsGif) { |
|
Write-Output " Detected as: GIF" |
|
} else { |
|
Write-Output " Detected as: Video" |
|
} |
|
Write-Output " Start time: $StartTime" |
|
Write-Output " Duration: $Duration" |
|
Write-Output " Num frames: $NumFrames" |
|
Write-Output " Frame every: $FrameInterval s" |
|
Write-Output " Layout: $Layout" |
|
Write-Output " Resize to: $ResizeTo" |
|
Write-Output " Tile padding: $TilePadding px" |
|
Write-Output "" |
|
|
|
# Clean old frames |
|
Remove-Item -ErrorAction Ignore frame_*.png |
|
|
|
# Frame extraction |
|
if ($IsGif) { |
|
# Frame-accurate seek for GIFs |
|
ffmpeg -i $InputFile -ss $StartTime -t $Duration -vf "fps=1/$FrameInterval" -vframes $NumFrames frame_%04d.png |
|
} else { |
|
# Keyframe-aligned seek for video |
|
ffmpeg -ss $StartTime -i $InputFile -t $Duration -vf "fps=1/$FrameInterval" -vframes $NumFrames frame_%04d.png |
|
} |
|
|
|
# Construct tile filter |
|
$TileBase = if ($Layout -eq "horizontal") { "${NumFrames}x1" } else { "1x${NumFrames}" } |
|
$TileFilter = "tile=$TileBase" |
|
if ($TilePadding -gt 0) { |
|
$TileFilter += ":padding=$TilePadding" |
|
} |
|
|
|
# Optional resize |
|
$ResizeFilter = if ($ResizeTo -ne "") { ",scale=$ResizeTo" } else { "" } |
|
|
|
# Generate PNG sprite strip |
|
ffmpeg -i frame_%04d.png -vf "$TileFilter$ResizeFilter" -frames:v 1 $OutputPNG |
|
|
|
# Generate WebP sprite |
|
ffmpeg -i $OutputPNG -c:v libwebp -lossless 1 -qscale 100 -preset default $OutputWebP |
|
|
|
# Clean temp frames |
|
Remove-Item frame_*.png |
|
|
|
# Export metadata |
|
$Metadata = @{ |
|
input = $InputFile |
|
startTime = $StartTime |
|
duration = $Duration |
|
numFrames = $NumFrames |
|
frameEvery = $FrameInterval |
|
layout = $Layout |
|
size = if ($ResizeTo -ne "") { $ResizeTo } else { "original" } |
|
spacing = $TilePadding |
|
outputPNG = $OutputPNG |
|
outputWebP = $OutputWebP |
|
timestamp = (Get-Date).ToString("s") |
|
} |
|
$Metadata | ConvertTo-Json -Depth 3 | Out-File $OutputJSON -Encoding UTF8 |
|
|
|
# Done |
|
Write-Output "`n✅ Sprite strip generated:" |
|
Write-Output " PNG: $OutputPNG" |
|
Write-Output " WebP: $OutputWebP" |
|
Write-Output " JSON: $OutputJSON" |