13 KiB
Clone-Image.ps1
Clones (copies) an image file using ffmpeg with optional resizing, quality and compression settings. Reads PNG, JPEG, WEBP, BMP, AVIF and TIFF sources and writes to any of those formats depending on the -Target file extension.
Synopsis
The output format is chosen from the -Target extension (.png, .jpg/.jpeg, .webp, .bmp, .avif, .tif/.tiff; defaults to .png when no recognised extension is given). Each format has its own encoder profile — the script picks the appropriate ffmpeg encoder and applies any quality/compression settings. See Output formats for the full matrix.
When -Size is provided, the source image is resized using a cover-then-crop strategy:
- The image is scaled (preserving its original pixel aspect ratio) so it fully covers the requested width and height — one dimension matches exactly, the other overflows.
- The overflowing dimension is then centre-cropped so the final image is exactly the requested size.
The source aspect ratio is preserved at all times (no warping/stretching).
Parameters
-Source(required): Path to input image file. Accepted formats:.png,.jpg,.jpeg,.webp,.bmp,.avif,.tif,.tiff. If the path has no extension, the script tries each supported extension in turn.-Target(required): Path to output image file. The extension picks the output format (PNG, JPEG, WEBP, BMP, AVIF, or TIFF). If the extension is missing or unrecognised,.pngis appended and the PNG profile is used.-Size(optional): Size of the output image. Uses the source image's size if not specified. Possible values:480p,720p,1080p,HD,1440p,2K,2160p,4K, or custom size in formatwidth:height. When specified, the source is cover-scaled (aspect ratio preserved) so it fully covers the requested dimensions, then centre-cropped to the exact target size. No image warping.-Quality(optional): Quality factor for lossy output formats (JPEG, WEBP, AVIF). Lower values mean better quality (consistent across all three formats). Ignored for PNG, BMP and TIFF (lossless).- JPEG: passed to ffmpeg's
-q:v(typical range1-31, lower = better). - WEBP: inverted internally and passed to libwebp's
-quality(0-100, higher = better), so the "lower = better" semantic is preserved from the caller's perspective. - AVIF: passed to libaom-av1's
-crf(0-63, lower = better).
- JPEG: passed to ffmpeg's
-Compression(optional): Compression level for PNG and WEBP outputs.- PNG: libpng's
-compression_level(0-9, higher = smaller files / slower encoding). - WEBP: libwebp's
-compression_level(0-6, higher = smaller files / slower encoding). - Ignored for JPEG, AVIF, BMP and TIFF.
- PNG: libpng's
-Metadata: Copy available metadata from source image file to target image file.-Upscale(optional): Upscale factor (2,3or4) applied to the source image withupscayl-bin.exebefore ffmpeg runs. The upscaled image is written to a Windows temp PNG (under%TEMP%) and used as the ffmpeg input, so any-Size/-LTXcover-scale-then-crop is applied to the already-upscaled image. The temp PNG is deleted automatically when the script finishes. Requiresupscayl-bin.exein PATH and theUPSCAYL_HOMEandNCNN_GPU_IDenvironment variables (see index). Omit (or pass0) to disable upscaling.-Model(optional): Upscayl model name to use when-Upscaleis specified. Defaults to4xNomos8kSC. The model files (<Model>.binand<Model>.param) must exist under%UPSCAYL_HOME%\models(see the Upscalers installation guide for installing additional models). Ignored when-Upscaleis not specified.-Keep(optional): Path at which to save a copy of the upscayl-bin output (i.e. the upscaled image, before ffmpeg's cover-scale-then-crop). The file extension picks the format (.png,.jpg/.jpeg,.webp,.bmp,.avif,.tif/.tiff); if the extension is missing or unrecognised,.pngis appended. When the requested format is.png(the upscayl native output) the temp file is simply copied; otherwise it is converted with ffmpeg using the same per-format encoders as-Target(with default quality settings). Only valid when-Upscaleis specified — it is ignored (with a warning) otherwise.-LTX: Override the dimensions chosen by-Sizewith the closest LTX-2 (Wan2GP by DeepBeepMeep) canonical resolution for the source's aspect ratio. Only valid when-Sizeis one ofHD,1080p,720por480p. The script probes the source's width/height, computes its aspect ratio, and picks the bucket whose ratio is numerically closest. Cover-scale-then-centre-crop still applies, so the source is fitted to the picked LTX dimensions without warping. The buckets per-Sizeare:HD/1080p:1920x1088(16:9),1088x1920(9:16),1664x960(21:9),960x1664(9:21).720p:1280x704(16:9),704x1280(9:16),1088x576(21:9),576x1088(9:21).480p:832x448(16:9),448x832(9:16),896x512(4:3),512x896(3:4).
Examples
Clone entire image (same size, same format):
.\Clone-Image.ps1 -Source photo.png -Target output.png
Convert PNG to JPEG with default quality:
.\Clone-Image.ps1 -Source photo.png -Target photo.jpg
Convert with custom JPEG quality (lower = better):
.\Clone-Image.ps1 -Source photo.png -Target photo.jpg -Quality 3
# Uses ffmpeg -q:v 3
Convert to WEBP at high quality:
.\Clone-Image.ps1 -Source photo.png -Target photo.webp -Quality 10
# Internally maps to libwebp -quality 90 (100 - 10)
Convert to AVIF at near-visually-lossless:
.\Clone-Image.ps1 -Source photo.png -Target photo.avif -Quality 18
# Uses libaom-av1 -crf 18 -still-picture 1
Upscale 4x with the default model, then crop to 4K:
.\Clone-Image.ps1 -Source small.jpg -Target big_4k.png -Upscale 4 -Size 4K
# small.jpg is upscaled x4 with 4xNomos8kSC into a temp PNG;
# ffmpeg then cover-scales the upscaled image and centre-crops to 3840x2160.
Upscale 2x with a custom model:
.\Clone-Image.ps1 -Source photo.png -Target photo_2x.png -Upscale 2 -Model 4xUltraSharp
# Requires 4xUltraSharp.bin and 4xUltraSharp.param under %UPSCAYL_HOME%\models.
Upscale 4x to a JPEG with custom quality:
.\Clone-Image.ps1 -Source thumb.jpg -Target thumb_hi.jpg -Upscale 4 -Quality 3
Upscale 4x and also keep the full-resolution upscaled PNG:
.\Clone-Image.ps1 -Source small.jpg -Target small_4k.png -Upscale 4 -Size 4K -Keep small_upscaled.png
# small_upscaled.png is the raw upscayl output (no crop); small_4k.png is cover-scaled+cropped to 3840x2160.
Upscale and keep the upscaled image as JPEG (format conversion via ffmpeg):
.\Clone-Image.ps1 -Source photo.png -Target photo_2x.png -Upscale 2 -Keep photo_upscaled.jpg
# upscayl writes a PNG; ffmpeg converts that PNG to photo_upscaled.jpg before the main clone step.
Resize using a named preset (cover-scale then crop):
.\Clone-Image.ps1 -Source photo.png -Target photo_720.png -Size 720p
# Scales the source so it fully covers 1280x720, then centre-crops to exactly 1280x720.
Pick the closest LTX-2 720p bucket from a 16:9 source:
.\Clone-Image.ps1 -Source landscape.png -Target landscape_ltx720.png -Size 720p -LTX
# A 1920x1080 (16:9) source is fitted to 1280x704.
Pick the closest LTX-2 1080p bucket from a 9:16 phone shot:
.\Clone-Image.ps1 -Source portrait.jpg -Target portrait_ltx1080.png -Size 1080p -LTX
# A 1080x1920 (9:16) source is fitted to 1088x1920.
Pick the closest LTX-2 480p bucket from a 4:3 source:
.\Clone-Image.ps1 -Source legacy.jpg -Target legacy_ltx480.png -Size 480p -LTX
# A 1024x768 (4:3) source is fitted to 896x512.
Resize with a custom resolution:
.\Clone-Image.ps1 -Source photo.png -Target square.jpg -Size 1024:1024
# Scales so the image fully covers 1024x1024, then centre-crops to a square.
Maximum PNG compression:
.\Clone-Image.ps1 -Source photo.png -Target small.png -Compression 9
WEBP with explicit quality and compression effort:
.\Clone-Image.ps1 -Source photo.png -Target photo.webp -Quality 20 -Compression 6
# libwebp -quality 80 -compression_level 6
Preserve metadata when converting formats:
.\Clone-Image.ps1 -Source photo.jpg -Target photo.webp -Metadata
# Copies EXIF/XMP/etc. that ffmpeg can transport into the WEBP container.
Using absolute paths:
.\Clone-Image.ps1 -Source "C:\Photos\input.png" -Target "D:\Output\result.jpg"
Output formats
The output format is selected from the -Target file extension. Each format has its own ffmpeg encoder and the parameters that apply to it.
| Format | Target extension(s) | ffmpeg encoder | Lossy? | -Quality applies |
-Compression applies |
|---|---|---|---|---|---|
| PNG | .png (default) |
png |
No | No | Yes (0-9, higher = smaller) |
| JPEG | .jpg, .jpeg |
mjpeg (yuvj420p) |
Yes | Yes (1-31, lower = better) |
No |
| WEBP | .webp |
libwebp |
Yes | Yes (inverted: 0-100, lower = better) |
Yes (0-6, higher = smaller) |
| AVIF | .avif |
libaom-av1 (still-picture) |
Yes | Yes (0-63, lower = better) |
No |
| BMP | .bmp |
bmp |
No | No | No |
| TIFF | .tif, .tiff |
tiff |
No | No | No |
General rules
- The output format is determined entirely by the
-Targetextension. If-Targethas no extension (or an unrecognised one),.pngis appended and the PNG profile is used. - Resizing always uses the cover-scale then centre-crop strategy. The source pixel aspect ratio is preserved (no warping). When
-Sizeis omitted, the source dimensions are kept as-is. -Qualityand-Compressionare interpreted in a format-agnostic way from the caller's perspective: lower-Qualityalways means better quality, and higher-Compressionalways means smaller files. Per-format ffmpeg mappings (including the libwebp-qualityinversion) happen inside the script.- Defaults when
-Quality/-Compressionare omitted: JPEG uses-q:v 2, WEBP uses-quality 90, AVIF uses-crf 25. PNG and lossless formats are encoded with ffmpeg's default settings. - AVIF output uses
libaom-av1with-still-picture 1and-cpu-used 4for a reasonable speed/quality tradeoff. Your ffmpeg build must includelibaom-av1for.avifoutput to work. -Metadatatoggles ffmpeg's-map_metadata 0(copy) vs-map_metadata -1(strip). Which metadata actually survives the conversion depends on what the source and target formats can carry.-LTXonly takes effect when-SizeisHD,1080p,720por480p. Combining it with any other-Sizevalue (or omitting-Size) is rejected with an explicit error so the user is never silently downgraded to the regular preset.-Upscalerunsupscayl-bin.exebefore ffmpeg. The script validates thatupscayl-bin.exeis on PATH, thatUPSCAYL_HOMEis set and exists, that themodelssubfolder and the requested<Model>.bin/<Model>.paramfiles are present, and thatNCNN_GPU_IDis set to a valid integer (-1for CPU,0+for GPU). The intermediate upscaled PNG is created under%TEMP%and deleted after the run (including on ffmpeg failure).-Keepsaves the raw upscayl output (no cropping/scaling). When the-Keepextension is.png, the temp file is copied directly (no re-encode); for any other supported extension a separate ffmpeg invocation converts the PNG to the requested format with default quality settings (JPEG-q:v 2, WEBP-quality 90, AVIF-crf 25).-Keepis ignored with a warning if-Upscaleis not specified.
Notes
- AVIF encoding is slow.
libaom-av1is significantly slower than the other encoders even with-cpu-used 4. WebP at high-Compressionis also slower than PNG or JPEG. - JPEG output is always 4:2:0 chroma (
yuvj420p). If you need 4:4:4 JPEG or 16-bit output, edit the encoder args directly. - TIFF and BMP are stored uncompressed (TIFF can be configured for LZW/Deflate via additional ffmpeg options if needed).
Existing Files
- An existing
-Targetimage is replaced without a prompt. ffmpeg runs with-y, so the old file is lost. Use-WhatIffirst, or write to a new name. - An existing file at
-Keepis replaced in the same way. - The folders that contain
-Targetand-Keepmust already exist. The script stops with an error instead of creating them. - The temporary upscaled PNG is deleted when the script finishes.
Safe Execution
This script supports -WhatIf and -Confirm for safe execution:
-WhatIf: Simulate the operation without actually creating files. Shows what would be done.-Confirm: Prompt for confirmation before each state-changing operation.
Simulate without making changes:
.\Clone-Image.ps1 -Source photo.png -Target output.jpg -WhatIf
Prompt before creating files:
.\Clone-Image.ps1 -Source photo.png -Target output.avif -Confirm