Initial commit: Futonizer MKV track stripper
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
function New-AnimeEyeBitmap {
|
||||
param([int]$Size)
|
||||
|
||||
$bmp = New-Object System.Drawing.Bitmap($Size, $Size)
|
||||
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
||||
$g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
||||
$g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
|
||||
$g.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality
|
||||
$g.Clear([System.Drawing.Color]::Transparent)
|
||||
|
||||
$s = $Size
|
||||
$rect = New-Object System.Drawing.Rectangle(0, 0, $s, $s)
|
||||
$radius = [Math]::Max(2, [int]($s * 0.22))
|
||||
|
||||
# --- rounded-square background gradient (indigo -> violet -> magenta, anime-ish) ---
|
||||
$path = New-Object System.Drawing.Drawing2D.GraphicsPath
|
||||
$d = $radius * 2
|
||||
$path.AddArc(0, 0, $d, $d, 180, 90)
|
||||
$path.AddArc($s - $d, 0, $d, $d, 270, 90)
|
||||
$path.AddArc($s - $d, $s - $d, $d, $d, 0, 90)
|
||||
$path.AddArc(0, $s - $d, $d, $d, 90, 90)
|
||||
$path.CloseFigure()
|
||||
|
||||
$bgBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush(
|
||||
$rect,
|
||||
[System.Drawing.Color]::FromArgb(255, 40, 20, 90),
|
||||
[System.Drawing.Color]::FromArgb(255, 150, 40, 130),
|
||||
[System.Drawing.Drawing2D.LinearGradientMode]::ForwardDiagonal)
|
||||
$g.FillPath($bgBrush, $path)
|
||||
|
||||
# subtle top highlight
|
||||
$topRect = New-Object System.Drawing.Rectangle(0, 0, $s, [int]($s * 0.55))
|
||||
$topBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush(
|
||||
$topRect,
|
||||
[System.Drawing.Color]::FromArgb(60, 255, 255, 255),
|
||||
[System.Drawing.Color]::FromArgb(0, 255, 255, 255),
|
||||
[System.Drawing.Drawing2D.LinearGradientMode]::Vertical)
|
||||
$oldClip = $g.Clip
|
||||
$g.SetClip($path)
|
||||
$g.FillRectangle($topBrush, $topRect)
|
||||
$g.Clip = $oldClip
|
||||
|
||||
# --- anime eye ---
|
||||
$cx = $s * 0.5
|
||||
$cy = $s * 0.46
|
||||
$eyeW = $s * 0.72
|
||||
$eyeH = $s * 0.46
|
||||
|
||||
# white of the eye
|
||||
$eyePath = New-Object System.Drawing.Drawing2D.GraphicsPath
|
||||
$eyeRect = New-Object System.Drawing.RectangleF(($cx - $eyeW/2), ($cy - $eyeH/2), $eyeW, $eyeH)
|
||||
$eyePath.AddEllipse($eyeRect)
|
||||
|
||||
$whiteBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(250, 255, 255, 255))
|
||||
$g.FillPath($whiteBrush, $eyePath)
|
||||
|
||||
# upper eyelid line (thick, sweeping) + eyelash accent
|
||||
$lidPen = New-Object System.Drawing.Pen([System.Drawing.Color]::FromArgb(255, 25, 15, 40), [Math]::Max(1.0, $s * 0.045))
|
||||
$lidPen.StartCap = [System.Drawing.Drawing2D.LineCap]::Round
|
||||
$lidPen.EndCap = [System.Drawing.Drawing2D.LineCap]::Round
|
||||
$lidRect = New-Object System.Drawing.RectangleF(($cx - $eyeW/2), ($cy - $eyeH/2 - $s*0.02), $eyeW, $eyeH*1.1)
|
||||
$g.DrawArc($lidPen, $lidRect, 195, 150)
|
||||
|
||||
$lashX = $cx + $eyeW/2 * 0.92
|
||||
$lashY = $cy - $eyeH/2 * 0.55
|
||||
$g.DrawLine($lidPen, $lashX, $lashY, $lashX + $s*0.06, $lashY - $s*0.10)
|
||||
|
||||
# iris (gradient blue -> violet with highlight)
|
||||
$irisSize = $eyeH * 0.95
|
||||
$irisRect = New-Object System.Drawing.RectangleF(($cx - $irisSize/2), ($cy - $irisSize/2), $irisSize, $irisSize)
|
||||
$irisBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush(
|
||||
$irisRect,
|
||||
[System.Drawing.Color]::FromArgb(255, 60, 190, 255),
|
||||
[System.Drawing.Color]::FromArgb(255, 130, 60, 220),
|
||||
[System.Drawing.Drawing2D.LinearGradientMode]::Vertical)
|
||||
$g.FillEllipse($irisBrush, $irisRect)
|
||||
|
||||
# pupil
|
||||
$pupilSize = $irisSize * 0.42
|
||||
$pupilRect = New-Object System.Drawing.RectangleF(($cx - $pupilSize/2), ($cy - $pupilSize/2), $pupilSize, $pupilSize)
|
||||
$g.FillEllipse([System.Drawing.Brushes]::Black, $pupilRect)
|
||||
|
||||
# ring accent inside iris
|
||||
$ringPen = New-Object System.Drawing.Pen([System.Drawing.Color]::FromArgb(150, 20, 20, 40), [Math]::Max(1.0, $s*0.012))
|
||||
$ringSize = $irisSize * 0.72
|
||||
$ringRect = New-Object System.Drawing.RectangleF(($cx - $ringSize/2), ($cy - $ringSize/2), $ringSize, $ringSize)
|
||||
$g.DrawEllipse($ringPen, $ringRect)
|
||||
|
||||
# big specular highlight
|
||||
$hlSize = $irisSize * 0.32
|
||||
$hlRect = New-Object System.Drawing.RectangleF(($cx - $irisSize*0.28), ($cy - $irisSize*0.32), $hlSize, $hlSize)
|
||||
$g.FillEllipse([System.Drawing.Brushes]::White, $hlRect)
|
||||
|
||||
# small secondary sparkle
|
||||
$sp2Size = $irisSize * 0.14
|
||||
$sp2Rect = New-Object System.Drawing.RectangleF(($cx + $irisSize*0.10), ($cy + $irisSize*0.18), $sp2Size, $sp2Size)
|
||||
$g.FillEllipse([System.Drawing.Brushes]::White, $sp2Rect)
|
||||
|
||||
# --- "subtitle bar" accent motif near the bottom ---
|
||||
$barY = $s * 0.80
|
||||
$barH = [Math]::Max(1.0, $s * 0.07)
|
||||
$barW1 = $s * 0.5
|
||||
$bar1 = New-Object System.Drawing.RectangleF(($cx - $barW1/2), $barY, $barW1, $barH)
|
||||
$barBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(235, 255, 255, 255))
|
||||
$g.FillRectangle($barBrush, $bar1)
|
||||
|
||||
$g.Dispose()
|
||||
return $bmp
|
||||
}
|
||||
|
||||
function Get-PngBytes($bmp) {
|
||||
$ms = New-Object System.IO.MemoryStream
|
||||
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
return [byte[]]$ms.ToArray()
|
||||
}
|
||||
|
||||
$sizes = @(16, 32, 48, 256)
|
||||
$pngList = @()
|
||||
foreach ($sz in $sizes) {
|
||||
$bmp = New-AnimeEyeBitmap -Size $sz
|
||||
$bytes = Get-PngBytes $bmp
|
||||
$pngList += ,@{ Size = $sz; Bytes = $bytes }
|
||||
$bmp.Dispose()
|
||||
}
|
||||
|
||||
# Save the 256px version separately as a standalone PNG for use as ui:ImageIcon source.
|
||||
$png256 = ($pngList | Where-Object { $_.Size -eq 256 }).Bytes
|
||||
[System.IO.File]::WriteAllBytes("Assets/app.png", [byte[]]$png256)
|
||||
|
||||
# --- Manually pack a multi-size .ico (ICONDIR + ICONDIRENTRY headers wrapping raw PNG bytes) ---
|
||||
$icoPath = "Assets/app.ico"
|
||||
$fs = New-Object System.IO.FileStream($icoPath, [System.IO.FileMode]::Create)
|
||||
$bw = New-Object System.IO.BinaryWriter($fs)
|
||||
|
||||
# ICONDIR: reserved(2)=0, type(2)=1 (icon), count(2)
|
||||
$bw.Write([UInt16]0)
|
||||
$bw.Write([UInt16]1)
|
||||
$bw.Write([UInt16]$pngList.Count)
|
||||
|
||||
$headerSize = 6
|
||||
$entrySize = 16
|
||||
$offset = $headerSize + ($entrySize * $pngList.Count)
|
||||
|
||||
foreach ($entry in $pngList) {
|
||||
$sz = $entry.Size
|
||||
$byteLen = $entry.Bytes.Length
|
||||
$widthByte = if ($sz -ge 256) { 0 } else { $sz }
|
||||
$heightByte = if ($sz -ge 256) { 0 } else { $sz }
|
||||
$bw.Write([byte]$widthByte) # width (0 = 256)
|
||||
$bw.Write([byte]$heightByte) # height (0 = 256)
|
||||
$bw.Write([byte]0) # color palette
|
||||
$bw.Write([byte]0) # reserved
|
||||
$bw.Write([UInt16]1) # color planes
|
||||
$bw.Write([UInt16]32) # bits per pixel
|
||||
$bw.Write([UInt32]$byteLen) # size of image data
|
||||
$bw.Write([UInt32]$offset) # offset of image data
|
||||
$offset += $byteLen
|
||||
}
|
||||
|
||||
# NOTE: the explicit [byte[]] cast below is required - without it, PowerShell's
|
||||
# method-overload binding can silently resolve BinaryWriter.Write() to the wrong
|
||||
# overload and write garbage instead of the actual PNG bytes.
|
||||
foreach ($entry in $pngList) {
|
||||
$bw.Write([byte[]]$entry.Bytes)
|
||||
}
|
||||
|
||||
$bw.Flush()
|
||||
$bw.Close()
|
||||
$fs.Close()
|
||||
|
||||
Write-Output "Icon generated: $icoPath ($((Get-Item $icoPath).Length) bytes)"
|
||||
Write-Output "PNG generated: Assets/app.png"
|
||||
Reference in New Issue
Block a user