12 KiB
Create-Turnaround.ps1
Combines a sequence of images into a single turnaround (character reference sheet) image using ffmpeg.
A turnaround image shows the same subject from several angles — typically front, 3/4, profile and back — side by side at a consistent scale, in one wide image. It is the usual input for keeping a character consistent across image and video generation models.
Synopsis
All images found at -Source are placed side by side, left to right, in the order given by a numeric-aware sort of their file names. -Target is optional: without it the sheet is saved as a JPEG named after the source directory, in the current directory. Every image keeps its original pixels: nothing is scaled, stretched or cropped. Images smaller than the largest one are centred in their cell and padded with -Background (white by default), so a set of slightly different sizes still produces a clean, aligned sheet.
Supports PNG, JPEG, WEBP, BMP, AVIF and TIFF for both input and output.
Parameters
-Source(required): Directory containing the images, a file pattern (e.g.Img*.jpg), or a single image file. Can be absolute or relative to the current directory. Non-recursive; only supported image extensions are considered.-Target(optional): Path to the output turnaround image. Can be absolute or relative to the current directory. The extension selects the output format;.pngis appended when the extension is missing or unrecognised. When omitted, the name is derived from the source — see Default Target Name.-Rows(optional): Number of rows to arrange the images in. Defaults to1(a single horizontal row). When only-Rowsis given, the column count is computed asceil(imageCount / Rows).-Columns(optional): Number of columns to arrange the images in. When only-Columnsis given, the row count is computed asceil(imageCount / Columns). When both are given,Rows × Columnsmust be at least the number of images.-Background(optional): Colour used to pad images smaller than the largest one, and to fill the unused cells of an incomplete last row. Defaults towhite. Accepts any ffmpeg colour: a name (white,black,silver),0xRRGGBB, orname@alpha(white@0for transparent).-Quality(optional): Quality factor for the lossy output formats (jpeg, webp, avif). Lower values mean better quality in all three, see Quality and Compression. Ignored (with a warning) for png, bmp and tiff.-Compression(optional): Compression level for png (0-9) and webp (0-6); higher means smaller files but slower encoding. Ignored (with a warning) for jpeg, avif, bmp and tiff.
Default Target Name
When -Target is omitted, the script writes a JPEG named after the last directory member of the source, into the current directory:
-Source |
Name taken from | Result (run from C:\work) |
|---|---|---|
A directory, e.g. C:\renders\CharacterA |
The last member of that directory's full path | C:\work\CharacterA.jpg |
A file pattern, e.g. Img*.jpg |
The last member of the current directory's full path | C:\work\work.jpg |
| A single image file | The last member of the current directory's full path | C:\work\work.jpg |
Relative sources are resolved to a full path first, so -Source . run from C:\renders\CharacterA produces CharacterA.jpg in that same directory. Trailing separators are ignored (C:\renders\CharacterA\ behaves identically).
Since the derived name always ends in .jpg, the output uses the JPEG encoder and its default -q:v 2; add -Quality to change it, or pass -Target explicitly for a different format.
PS C:\work> .\Create-Turnaround.ps1 -Source C:\renders\CharacterA
No -Target specified; using C:\work\CharacterA.jpg
Drive-root error
A path with no directory member cannot name the file, so a drive root is rejected:
PS C:\work> .\Create-Turnaround.ps1 -Source "C:\"
Cannot derive a target file name from 'C:\': the path is a drive root with no directory member. Specify -Target explicitly.
The same applies when -Source is a file pattern and the current directory is a drive root (e.g. running Create-Turnaround.ps1 -Source *.png from C:\). Supply -Target explicitly in that case.
Image Order
File names are sorted with a numeric-aware (natural) sort, so digit runs compare as numbers:
Img1.png, Img2.png, Img10.png (not Img1, Img10, Img2)
Frame-00001.png ... Frame-00012.png
Zero-padded sequence names therefore sort identically to a plain alphabetical sort, while non-padded names (Pose2, Pose10) still come out in the intended order.
Cell Size and Padding
The cell is as large as the largest source image in both dimensions:
cellWidth= max width of all sourcescellHeight= max height of all sources- Output size =
cellWidth × columnsbycellHeight × rows
Each image is centred in its cell. Images that already match the cell size are passed through untouched; smaller ones gain -Background margins. No source image is ever resized, so the sheet is lossless with respect to the originals (verified at PSNR = ∞ for PNG in/PNG out).
When padding is applied, the console reports it:
Cell size: 600x768
Note: 2 image(s) smaller than the largest image; centred and padded with white.
Layout
Single row (default)
Four 512x768 images produce a 2048x768 sheet:
[1][2][3][4]
Grid
-Rows and/or -Columns wrap the images into a grid. With 4 images and -Columns 2 (→ 2 rows), the output is 1024x1536:
[1][2]
[3][4]
An incomplete last row is centred inside the full output width and the remaining space filled with -Background. With 4 images and -Columns 3 (→ 2 rows, 1536x1536):
[1][2][3]
[4]
| Images | Switches | Rows x Columns | Output (512x768 cells) |
|---|---|---|---|
| 4 | (none) | 1 x 4 | 2048x768 |
| 4 | -Columns 2 |
2 x 2 | 1024x1536 |
| 4 | -Rows 2 |
2 x 2 | 1024x1536 |
| 4 | -Columns 3 |
2 x 3 | 1536x1536 (last row centred) |
| 4 | -Rows 1 -Columns 2 |
— | Error: 2 cells is not enough for 4 images |
Output Format
The target extension selects the encoder, with the same mapping and defaults as Clone-Image.ps1:
| Extension | Encoder | Default settings | -Quality |
-Compression |
|---|---|---|---|---|
.png |
png |
Lossless | — | -compression_level (0-9) |
.jpg / .jpeg |
mjpeg |
-q:v 2, yuvj420p |
-q:v (1-31) |
— |
.webp |
libwebp |
-quality 90 |
-quality (inverted) |
-compression_level (0-6) |
.avif |
libaom-av1 |
-still-picture 1, -cpu-used 4, -crf 25 |
-crf (0-63) |
— |
.bmp |
bmp |
Lossless | — | — |
.tif / .tiff |
tiff |
Lossless | — | — |
PNG is recommended for a turnaround sheet that will be fed back into a generation model, since it is lossless and preserves transparency.
Quality and Compression
-Quality is always interpreted as lower = better quality, regardless of format. For webp — whose native -quality option means the opposite — the value is inverted internally (-Quality 20 becomes -quality 80), so a single convention holds across jpeg, webp and avif.
| Format | -Quality maps to |
Range | Default when omitted |
|---|---|---|---|
| jpeg | -q:v |
1-31 (lower is better) | 2 |
| webp | -quality = 100 - Quality |
0-100 after inversion | 90 (i.e. -Quality 10) |
| avif | -crf |
0-63 (lower is better) | 25 |
-Compression trades encoding time for file size on the two formats that support it, and does not affect image quality (both are lossless/independent of it):
| Format | -Compression maps to |
Range |
|---|---|---|
| png | -compression_level |
0-9 (higher = smaller, slower) |
| webp | -compression_level |
0-6 (higher = smaller, slower) |
Measured on a 3840x480 sheet:
| Command | Output size |
|---|---|
-Target sheet.jpg (default) |
73,744 B |
-Target sheet.jpg -Quality 2 |
73,744 B (identical to the default) |
-Target sheet.jpg -Quality 28 |
33,349 B |
-Target sheet.webp -Quality 5 |
30,508 B |
-Target sheet.webp -Quality 70 |
17,578 B |
-Target sheet.png -Compression 0 |
7,395,829 B |
-Target sheet.png -Compression 9 |
10,990 B |
Passing -Quality to a lossless format (or -Compression to a format that ignores it) is not an error; the value is dropped and a warning is printed:
WARNING: -Quality is ignored for the lossless png format.
Examples
No -Target — JPEG named after the source directory, written to the current directory:
.\Create-Turnaround.ps1 -Source C:\renders\CharacterA
# Writes .\CharacterA.jpg
No -Target, run from inside the frames directory:
cd C:\renders\CharacterA
.\Create-Turnaround.ps1 -Source "F*.png"
# Writes C:\renders\CharacterA\CharacterA.jpg (name taken from the current directory)
Four frames in a directory into a single-row sheet:
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.png
Using a file pattern:
.\Create-Turnaround.ps1 -Source ".\renders\Img*.jpg" -Target turnaround.png
Extension-less target (.png is appended):
.\Create-Turnaround.ps1 -Source .\renders -Target character-sheet
# Writes character-sheet.png
Eight angles as a 2x4 grid:
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.png -Rows 2
Three columns, incomplete last row centred:
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.png -Columns 3
Transparent background instead of white:
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.png -Background "white@0"
Mid-gray background, JPEG output:
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.jpg -Background 0x808080
Smaller JPEG sheet (lower quality):
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.jpg -Quality 20
Maximum PNG compression (smallest lossless file, slowest encode):
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.png -Compression 9
Near-lossless webp with maximum compression effort:
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.webp -Quality 1 -Compression 6
Safe Execution
This script supports -WhatIf and -Confirm for safe execution:
-WhatIf: Prints the image list, the computed layout and the full ffmpeg command without writing the output file.-Confirm: Prompts for confirmation before creating the turnaround image.
.\Create-Turnaround.ps1 -Source .\renders -Target turnaround.png -WhatIf
Notes
- Requires
ffmpegandffprobein the WindowsPATH. - The target directory must exist; the script errors out rather than creating it.
- Every input is normalised to
rgbabefore stacking, so sources may mix formats (e.g. PNG + JPEG + WEBP) and colour models freely. - Source images are never scaled, stretched or cropped — differing sizes are reconciled with padding only.
- A single image is valid input and produces a one-cell output (useful to normalise/convert a frame).
- Files that are not recognised images are ignored; if none remain, the script errors with the list of supported extensions.
- The output file is excluded from its own input list, so writing
-Targetinto the-Sourcedirectory stays idempotent across re-runs (the previous sheet is not stacked into the new one).