|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | + Draws the ADO Lens icon: a lens over three work item bars on an Azure blue tile. |
| 4 | + Writes adolens.ico (16-256 px, PNG frames) and icon.png (512 px) next to this script. |
| 5 | +#> |
| 6 | +$ErrorActionPreference = 'Stop' |
| 7 | +Add-Type -AssemblyName System.Drawing |
| 8 | + |
| 9 | +function New-RoundedRect([float] $x, [float] $y, [float] $w, [float] $h, [float] $r) { |
| 10 | + $p = New-Object System.Drawing.Drawing2D.GraphicsPath |
| 11 | + $d = 2 * $r |
| 12 | + $p.AddArc($x, $y, $d, $d, 180, 90) |
| 13 | + $p.AddArc($x + $w - $d, $y, $d, $d, 270, 90) |
| 14 | + $p.AddArc($x + $w - $d, $y + $h - $d, $d, $d, 0, 90) |
| 15 | + $p.AddArc($x, $y + $h - $d, $d, $d, 90, 90) |
| 16 | + $p.CloseFigure() |
| 17 | + return $p |
| 18 | +} |
| 19 | + |
| 20 | +function New-IconBitmap([int] $size) { |
| 21 | + $bmp = New-Object System.Drawing.Bitmap $size, $size, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb) |
| 22 | + $g = [System.Drawing.Graphics]::FromImage($bmp) |
| 23 | + $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias |
| 24 | + $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality |
| 25 | + $g.Clear([System.Drawing.Color]::Transparent) |
| 26 | + $s = [float] $size |
| 27 | + |
| 28 | + # Tile: Azure blue, lighter at the top. |
| 29 | + $margin = [Math]::Max(0.5, $s * 0.03) |
| 30 | + $tile = New-RoundedRect $margin $margin ($s - 2 * $margin) ($s - 2 * $margin) ($s * 0.2) |
| 31 | + $grad = New-Object System.Drawing.Drawing2D.LinearGradientBrush (New-Object System.Drawing.PointF 0, 0), (New-Object System.Drawing.PointF 0, $s), |
| 32 | + ([System.Drawing.Color]::FromArgb(255, 0, 137, 230)), ([System.Drawing.Color]::FromArgb(255, 0, 90, 170)) |
| 33 | + $g.FillPath($grad, $tile) |
| 34 | + |
| 35 | + $white = [System.Drawing.Color]::White |
| 36 | + # Lens: a ring, centred a little up and left, with a handle to the bottom right. |
| 37 | + $cx = $s * 0.43; $cy = $s * 0.43; $r = $s * 0.24 |
| 38 | + $ring = [Math]::Max(1.5, $s * 0.075) |
| 39 | + if ($size -ge 32) { |
| 40 | + # Three work item bars inside the lens (left out at small sizes, where they would blur). |
| 41 | + $bar = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(235, 255, 255, 255)) |
| 42 | + $bh = $s * 0.045 |
| 43 | + foreach ($i in 0..2) { |
| 44 | + $w = $r * (1.05 - 0.25 * $i) |
| 45 | + $y = $cy - $r * 0.42 + $i * $r * 0.42 - $bh / 2 |
| 46 | + $path = New-RoundedRect ($cx - $r * 0.55) $y $w $bh ($bh / 2) |
| 47 | + $g.FillPath($bar, $path) |
| 48 | + } |
| 49 | + } |
| 50 | + $pen = New-Object System.Drawing.Pen $white, $ring |
| 51 | + $g.DrawEllipse($pen, $cx - $r, $cy - $r, 2 * $r, 2 * $r) |
| 52 | + $handle = New-Object System.Drawing.Pen $white, ([Math]::Max(2, $s * 0.11)) |
| 53 | + $handle.StartCap = [System.Drawing.Drawing2D.LineCap]::Round |
| 54 | + $handle.EndCap = [System.Drawing.Drawing2D.LineCap]::Round |
| 55 | + $a = 0.7071 * ($r + $ring / 2) |
| 56 | + $g.DrawLine($handle, $cx + $a, $cy + $a, $s * 0.76, $s * 0.76) |
| 57 | + $g.Dispose() |
| 58 | + return $bmp |
| 59 | +} |
| 60 | + |
| 61 | +$dir = $PSScriptRoot |
| 62 | +$sizes = 16, 20, 24, 32, 40, 48, 64, 128, 256 |
| 63 | +$frames = foreach ($n in $sizes) { |
| 64 | + $bmp = New-IconBitmap $n |
| 65 | + $ms = New-Object System.IO.MemoryStream |
| 66 | + $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) |
| 67 | + $bmp.Dispose() |
| 68 | + , $ms.ToArray() |
| 69 | +} |
| 70 | + |
| 71 | +# ICO: header, one directory entry per size, then the PNG frames. |
| 72 | +$out = New-Object System.IO.MemoryStream |
| 73 | +$w = New-Object System.IO.BinaryWriter $out |
| 74 | +$w.Write([UInt16]0); $w.Write([UInt16]1); $w.Write([UInt16]$sizes.Count) |
| 75 | +$offset = 6 + 16 * $sizes.Count |
| 76 | +for ($i = 0; $i -lt $sizes.Count; $i++) { |
| 77 | + $n = $sizes[$i] |
| 78 | + $dim = if ($n -ge 256) { 0 } else { $n } |
| 79 | + $w.Write([byte]$dim); $w.Write([byte]$dim); $w.Write([byte]0); $w.Write([byte]0) |
| 80 | + $w.Write([UInt16]1); $w.Write([UInt16]32) |
| 81 | + $w.Write([UInt32]$frames[$i].Length); $w.Write([UInt32]$offset) |
| 82 | + $offset += $frames[$i].Length |
| 83 | +} |
| 84 | +foreach ($f in $frames) { $w.Write($f) } |
| 85 | +$w.Flush() |
| 86 | +[IO.File]::WriteAllBytes((Join-Path $dir 'adolens.ico'), $out.ToArray()) |
| 87 | + |
| 88 | +$big = New-IconBitmap 512 |
| 89 | +$big.Save((Join-Path $dir 'icon.png'), [System.Drawing.Imaging.ImageFormat]::Png) |
| 90 | +$big.Dispose() |
| 91 | +Write-Host "written adolens.ico and icon.png in $dir" |
0 commit comments