1
0
mirror of https://github.com/Wyrrrd/serialize-mtg.git synced 2026-05-29 16:42:28 +02:00

Initial commit

This commit is contained in:
Wyrrrd
2026-01-31 16:09:03 +01:00
parent 3ccacc6bec
commit a597889ff2
8 changed files with 322 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
/input
/output
+27
View File
@@ -0,0 +1,27 @@
# Serialize MTG
![Two example cards, one serialized in grayscale with 5/7, one in colored gradient with 42/100](example.png)
## Overview
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.
## Usage
1. Clone or download repository
2. Install [ImageMagick](https://imagemagick.org/)
3. Run
## Parameters
```
.\Serialize_MTG.ps1 -TotalCount 100 [-Offset @(10,20)] [-UseColorMap] [-FontPath arial.ttf]
```
* **TotalCount (required)**: describes, how many versions of each card with incrementing numbers will be created.
* **Offset (optional)**: overrides the location of the upper left corner of the serial box on the cards. This will apply to all inputs, so if you need different offsets, run the script once for each different offset.
* **UseColorMap (optional)**: controls, if the white numbers and box border parts should be overlayed with an image. If you want to customize, replace colormap.png in the repository root directory.
* **FontPath (optional)**: overrides the default font for the numbers.
## Credits
The Gotham font family was designed by Tobias Frere-Jones & Jesse Ragan. It is free for personal use. If you want to use it commercially, you need to license it.
+290
View File
@@ -0,0 +1,290 @@
# 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
+3
View File
@@ -0,0 +1,3 @@
# TODO
- [ ] Add bash version
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

BIN
View File
Binary file not shown.