maksit-cluster-console/packaging/microsoft-store/New-StoreLogos.ps1

158 lines
5.5 KiB
PowerShell

# Renders Microsoft Store logo PNGs from the Cluster Console icon geometry.
# Requires Windows PowerShell 5.1 (System.Drawing). Output: packaging/microsoft-store/logos/
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Drawing
$outDir = Join-Path $PSScriptRoot "logos"
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
Add-Type -ReferencedAssemblies System.Drawing -TypeDefinition @"
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
public static class StoreLogos {
static readonly Color Bg0 = Color.FromArgb(0x33, 0xA5, 0xCF);
static readonly Color Bg1 = Color.FromArgb(0x00, 0x2A, 0x6A);
static readonly Color Tile0 = Color.White;
static readonly Color Tile1 = Color.FromArgb(0xC5, 0xE8, 0xF6);
static readonly Color Ink = Color.FromArgb(0x00, 0x2A, 0x6A);
public static void SaveAll(string dir) {
SaveIcon(Path.Combine(dir, "box-1x1-2160x2160.png"), 2160);
SaveIcon(Path.Combine(dir, "box-1x1-1080x1080.png"), 1080);
SaveIcon(Path.Combine(dir, "tile-1x1-300x300.png"), 300);
SaveIcon(Path.Combine(dir, "tile-1x1-150x150.png"), 150);
SaveIcon(Path.Combine(dir, "tile-1x1-71x71.png"), 71);
SavePoster(Path.Combine(dir, "poster-9x16-1440x2160.png"), 1440, 2160);
SavePoster(Path.Combine(dir, "poster-9x16-720x1080.png"), 720, 1080);
}
static void SaveIcon(string path, int size) {
using (var bmp = new Bitmap(size, size, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(bmp)) {
Quality(g);
DrawBackground(g, size, size);
DrawMark(g, 0f, 0f, size / 256f, true);
bmp.Save(path, ImageFormat.Png);
}
}
static void SavePoster(string path, int w, int h) {
using (var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(bmp)) {
Quality(g);
DrawBackground(g, w, h);
float scale = 0.62f * w / 184f;
float markH = 148f * scale;
using (var font = FitFont(g, "Cluster Console", w * 0.84f, w * 0.072f)) {
SizeF text = g.MeasureString("Cluster Console", font);
float gap = h * 0.045f;
float block = markH + gap + text.Height;
float top = (h - block) / 2f;
float ox = (w / 2f) - (128f * scale);
float oy = (top + markH / 2f) - (124f * scale);
DrawMark(g, ox, oy, scale, false);
using (var brush = new SolidBrush(Color.White))
using (var fmt = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Near }) {
g.DrawString("Cluster Console", font, brush, new RectangleF(0f, top + markH + gap, w, text.Height + 4f), fmt);
}
}
bmp.Save(path, ImageFormat.Png);
}
}
static void DrawBackground(Graphics g, int w, int h) {
using (var brush = new LinearGradientBrush(
new PointF(w * 0.2f, 0f),
new PointF(w * 0.9f, h),
Bg0,
Bg1)) {
g.FillRectangle(brush, 0, 0, w, h);
}
}
static void DrawMark(Graphics g, float ox, float oy, float s, bool shine) {
if (shine) {
using (var brush = new SolidBrush(Color.FromArgb(41, 255, 255, 255))) {
float rx = 150f * s;
float ry = 88f * s;
g.FillEllipse(brush, ox + (128f * s) - rx, oy + (8f * s) - ry, rx * 2f, ry * 2f);
}
}
Tile(g, ox, oy, s, 36f, 50f);
Tile(g, ox, oy, s, 132f, 50f);
Tile(g, ox, oy, s, 84f, 110f);
using (var pen = new Pen(Ink, 14f * s)) {
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
pen.LineJoin = LineJoin.Round;
g.DrawLines(pen, new[] {
new PointF(ox + 112f * s, oy + 134f * s),
new PointF(ox + 152f * s, oy + 154f * s),
new PointF(ox + 112f * s, oy + 174f * s)
});
}
}
static void Tile(Graphics g, float ox, float oy, float s, float x, float y) {
float rx = ox + x * s;
float ry = oy + y * s;
float side = 88f * s;
float radius = 20f * s;
using (var path = RoundedRect(rx, ry, side, side, radius))
using (var brush = new LinearGradientBrush(
new PointF(rx, ry),
new PointF(rx + side, ry + side),
Tile0,
Tile1)) {
g.FillPath(brush, path);
}
}
static GraphicsPath RoundedRect(float x, float y, float w, float h, float r) {
float d = r * 2f;
var path = new GraphicsPath();
path.AddArc(x, y, d, d, 180f, 90f);
path.AddArc(x + w - d, y, d, d, 270f, 90f);
path.AddArc(x + w - d, y + h - d, d, d, 0f, 90f);
path.AddArc(x, y + h - d, d, d, 90f, 90f);
path.CloseFigure();
return path;
}
static Font FitFont(Graphics g, string text, float maxWidth, float startPx) {
float size = startPx;
Font font = null;
while (size > 12f) {
if (font != null) font.Dispose();
font = new Font("Segoe UI", size, FontStyle.Bold, GraphicsUnit.Pixel);
if (g.MeasureString(text, font).Width <= maxWidth) return font;
size -= 1f;
}
return font;
}
static void Quality(Graphics g) {
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
}
}
"@
[StoreLogos]::SaveAll($outDir)
Add-Type -AssemblyName System.Drawing
Get-ChildItem $outDir -Filter *.png | ForEach-Object {
$img = [System.Drawing.Image]::FromFile($_.FullName)
"{0}`t{1}x{2}`t{3:N0} KB" -f $_.Name, $img.Width, $img.Height, ($_.Length / 1KB)
$img.Dispose()
}