1
0
mirror of https://github.com/Wyrrrd/serialize-mtg.git synced 2026-03-25 09:09:51 +01:00
Files
serialize-mtg/Serialize_MTG.ps1
2026-01-31 16:09:03 +01:00

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