mirror of
https://github.com/Wyrrrd/serialize-mtg.git
synced 2026-03-25 17:19:51 +01:00
290 lines
8.7 KiB
PowerShell
290 lines
8.7 KiB
PowerShell
# Serialize_MTG.ps1
|
|
# © Wyrrrd 30.01.2026
|
|
|
|
# This script bulk overlays a box with numbers over input images to have serialized versions of them, just as WotC does it.
|
|
# The concept includes handling of any input image size (assuming it is roughly a scaled 63mm x 88mm MTG card design).
|
|
# As the box to be applied is taken from a source image, there needs to be two pixel spaces: reference space (1500px x 2100px)
|
|
# and image space (defined by the input image). They will be transformed via an automatically calculated scale. This scale
|
|
# is not x/y separate and only a best effort to not squash the box image, so it might break with input images too far removed
|
|
# from the MTG ratio.
|
|
|
|
|
|
### Parameters
|
|
|
|
param (
|
|
# Total count of serialization, so how many versions you want of a card
|
|
[Parameter(Mandatory = $true)]
|
|
[int] $TotalCount,
|
|
|
|
# Font of the numbers in serial box
|
|
# BEWARE: The Gotham font family is only free for personal use. If you want to use it commercially, you have to license it.
|
|
[string] $FontPath = "gothambold.otf",
|
|
|
|
# Offsets as tuples @(x,y)
|
|
# supplied in final image pixels (not in reference space)
|
|
[int[]] $Offset,
|
|
|
|
# Apply color map using colormap.png
|
|
[switch] $UseColorMap
|
|
)
|
|
|
|
|
|
### Paths & constants
|
|
|
|
# Path to magick executable, or just "magick" if it's in the PATH.
|
|
$magick = "magick"
|
|
|
|
# Static directories and files
|
|
$inputDir = "input"
|
|
$outputDir = "output"
|
|
$backgroundImg = "background.png"
|
|
$colormapImg = "colormap.png"
|
|
|
|
# Reference card resolution
|
|
$refResolution = @{ Width=1500; Height=2100 }
|
|
|
|
# Hardcoded background / color map reference size and offset
|
|
# background.png and color map.png MUST match size
|
|
# offset will be overridden by Offset parameter later in image space, if supplied
|
|
$backgroundBoxRef = @{ X=128; Y=1032; Width=346; Height=107 }
|
|
|
|
# Text boxes (in reference space, relative to background box)
|
|
$currentBoxRef = @{ X=25; Y=24; Width=135; Height=63 }
|
|
$totalBoxRef = @{ X=190; Y=24; Width=135; Height=63 }
|
|
|
|
|
|
### Functions
|
|
|
|
function DisplayFileSize {
|
|
param (
|
|
$bytecount
|
|
)
|
|
|
|
switch -Regex ([math]::truncate([math]::log($bytecount,1024))) {
|
|
'^0' {"$bytecount Bytes"}
|
|
'^1' {"{0:n2} KB" -f ($bytecount / 1KB)}
|
|
'^2' {"{0:n2} MB" -f ($bytecount / 1MB)}
|
|
'^3' {"{0:n2} GB" -f ($bytecount / 1GB)}
|
|
'^4' {"{0:n2} TB" -f ($bytecount / 1TB)}
|
|
Default {"{0:n2} Bytes" -f ($bytecount / 1KB)}
|
|
}
|
|
}
|
|
|
|
function ScaleBox {
|
|
param (
|
|
$box
|
|
)
|
|
|
|
@{
|
|
X = [int]($box.X * $scale)
|
|
Y = [int]($box.Y * $scale)
|
|
Width = [int]($box.Width * $scale)
|
|
Height = [int]($box.Height * $scale)
|
|
}
|
|
}
|
|
|
|
|
|
########
|
|
# MAIN #
|
|
########
|
|
|
|
|
|
### Prepare input/output directory
|
|
|
|
if (-not (Test-Path $inputDir)) {
|
|
New-Item -ItemType Directory -Path $inputDir | Out-Null
|
|
}
|
|
|
|
$inputFiles = Get-ChildItem $inputDir -File | Where-Object {
|
|
$_.Extension -match '\.(png|jpg|jpeg)$'
|
|
}
|
|
|
|
# Wait for input files to be added
|
|
while ($inputFiles.Count -eq 0) {
|
|
Write-Host "Input directory is empty."
|
|
Write-Host "Please place input images into '$inputDir' directory, then continue."
|
|
start $inputDir
|
|
Pause
|
|
$inputFiles = Get-ChildItem $inputDir -File | Where-Object {
|
|
$_.Extension -match '\.(png|jpg|jpeg)$'
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path $outputDir)) {
|
|
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
|
|
}
|
|
|
|
|
|
### Loop over input images
|
|
|
|
foreach ($inputFile in $inputFiles) {
|
|
|
|
$baseName = [IO.Path]::GetFileNameWithoutExtension($inputFile.Name)
|
|
$ext = $inputFile.Extension
|
|
$outputSubDir = Join-Path $outputDir $baseName
|
|
|
|
if (-not (Test-Path $outputSubDir)) {
|
|
New-Item -ItemType Directory -Force -Path $outputSubDir | Out-Null
|
|
}
|
|
|
|
# Input image size & scaling
|
|
$imageInfo = & $magick identify -format "%w %h" $inputFile.FullName
|
|
$image = @{}
|
|
$image.Width, $image.Height = $imageInfo -split " " | ForEach-Object { [int]$_ }
|
|
$scaleX = $image.Width / $refResolution.Width
|
|
$scaleY = $image.Height / $refResolution.Height
|
|
$scale = [Math]::Min($scaleX, $scaleY)
|
|
|
|
|
|
### Transform box positions and dimensions
|
|
|
|
$backgroundBox = ScaleBox $backgroundBoxRef
|
|
|
|
# Override with offset, if supplied
|
|
if (-not $useDefaultOffset -and $Offset) {
|
|
if ($Offset.Count -eq 2) {
|
|
$backgroundBox.X = $Offset[0]
|
|
$backgroundBox.Y = $Offset[1]
|
|
} else {
|
|
"`nThe given offset was malformed, please enter it as '@(x,y)'.`nDo you want to continue with the default offset?" | Write-Warning -WarningAction Inquire
|
|
$useDefaultOffset = true
|
|
}
|
|
}
|
|
|
|
$currentBox = ScaleBox $currentBoxRef
|
|
$totalBox = ScaleBox $totalBoxRef
|
|
|
|
### Sanity checks
|
|
|
|
# Total file size >500MB check
|
|
if ($inputFile.Length * $totalCount -gt 524288000) {
|
|
$totalFileSize = DisplayFileSize($inputFile.Length * $totalCount)
|
|
"`nYou specified a total count of $totalCount for $inputFile.`nThis would result in new image files using up approximately $totalFileSize of your disk." | Write-Warning -WarningAction Inquire
|
|
}
|
|
|
|
Write-Host "Starting to serialize $inputFile."
|
|
|
|
# Out of bounds check
|
|
if ( $backgroundBox.X + $backgroundBox.Width -gt $image.Width -or $backgroundBox.Y + $backgroundBox.Height -gt $image.Height) {
|
|
if (-not $useDefaultOffset -and $Offset) {
|
|
Write-Host -NoNewline "The given "
|
|
} else {
|
|
Write-Host -NoNewline "The default "
|
|
}
|
|
Write-Host "offset would cause the serial box to be (partially) outside of the input image's boundaries.`nSkipping input image $inputFile."
|
|
continue
|
|
} else {
|
|
Write-Host -NoNewline "Using "
|
|
if (-not $useDefaultOffset -and $Offset) {
|
|
Write-Host -NoNewline "given "
|
|
} else {
|
|
Write-Host -NoNewline "scaled default "
|
|
}
|
|
Write-Host -NoNewline "offset of '@($($backgroundBox.X),$($backgroundBox.Y))'"
|
|
if ($UseColorMap) {
|
|
Write-Host -NoNewline " with color map"
|
|
}
|
|
Write-Host "."
|
|
}
|
|
|
|
|
|
### Temporary files
|
|
|
|
$currentFile = Join-Path $outputSubDir "_current.png"
|
|
$totalFile = Join-Path $outputSubDir "_total.png"
|
|
$boxFile = Join-Path $outputSubDir "_box.png"
|
|
|
|
|
|
### Generate total number file
|
|
|
|
$totalStr = $TotalCount.ToString()
|
|
|
|
& $magick `
|
|
-size "$($totalBox.Width)x$($totalBox.Height)" `
|
|
-background none `
|
|
-fill white `
|
|
-font $FontPath `
|
|
-kerning 3 `
|
|
-gravity center `
|
|
caption:"$totalStr" `
|
|
$totalFile
|
|
|
|
|
|
### Serialization padding
|
|
|
|
$padLength = $totalStr.Length
|
|
|
|
|
|
### Per-card generation of current number
|
|
|
|
for ($i = 1; $i -le $TotalCount; $i++) {
|
|
|
|
|
|
### Generate current number file
|
|
|
|
$currentStr = $i.ToString("D$padLength")
|
|
|
|
& $magick `
|
|
-size "$($currentBox.Width)x$($currentBox.Height)" `
|
|
-background none `
|
|
-fill white `
|
|
-font $FontPath `
|
|
-kerning 3 `
|
|
-gravity center `
|
|
caption:"$currentStr" `
|
|
$currentFile
|
|
|
|
|
|
### Output file
|
|
|
|
$outputFile = Join-Path $outputSubDir ("{0}_{1}{2}" -f $baseName, $currentStr, $ext)
|
|
|
|
|
|
### Compose file
|
|
|
|
# Create box with numbers
|
|
& $magick `
|
|
"(" $backgroundImg -resize "$($backgroundBox.Width)x$($backgroundBox.Height)!" ")" `
|
|
$currentFile -geometry +$($currentBox.X)+$($currentBox.Y) -composite `
|
|
$totalFile -geometry +$($totalBox.X)+$($totalBox.Y) -composite `
|
|
$boxFile
|
|
|
|
if ($UseColorMap) {
|
|
# Convert to mask
|
|
& $magick `
|
|
$boxFile -background black -alpha remove -alpha off `
|
|
$boxFile
|
|
|
|
# Mask color map
|
|
& $magick `
|
|
"(" $colormapImg -resize "$($backgroundBox.Width)x$($backgroundBox.Height)!" ")" `
|
|
$boxFile -compose CopyOpacity -composite `
|
|
$boxFile
|
|
|
|
# Re-add background
|
|
& $magick `
|
|
"(" $backgroundImg -resize "$($backgroundBox.Width)x$($backgroundBox.Height)!" ")" `
|
|
$boxFile -colorspace srgb -composite `
|
|
$boxFile
|
|
}
|
|
|
|
# Compose over input image at offset location
|
|
& $magick `
|
|
$inputFile.FullName `
|
|
$boxFile -geometry +$($backgroundBox.X)+$($backgroundBox.Y) -composite `
|
|
$outputFile
|
|
|
|
Write-Host -NoNewline "`r($i/$totalCount)"
|
|
}
|
|
|
|
|
|
### Cleanup
|
|
|
|
Remove-Item $currentFile
|
|
Remove-Item $totalFile
|
|
Remove-Item $boxFile
|
|
Write-Host "`n"
|
|
}
|
|
|
|
Write-Host "All cards serialized successfully."
|
|
start $outputDir |