Initial commit to new repository
This commit is contained in:
205
tools/IconGenerator/Program.cs
Normal file
205
tools/IconGenerator/Program.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
// 다이아몬드 픽셀 아이콘 생성기 v4
|
||||
// 보석 다이아몬드 컷 실루엣 (flat top → wide girdle → bottom point)
|
||||
// 내부 facet 선 + RGBG 4색 채움
|
||||
// 참고: Samsung Diamond Pixel 구조 (흰색선 다이아몬드 도형)
|
||||
|
||||
var outputPath = args.Length > 0 ? args[0]
|
||||
: Path.Combine(AppContext.BaseDirectory, "icon.ico");
|
||||
|
||||
int[] sizes = [16, 24, 32, 48, 64, 128, 256];
|
||||
var pngList = new List<byte[]>();
|
||||
|
||||
foreach (var sz in sizes)
|
||||
{
|
||||
using var bmp = DrawGemDiamond(sz);
|
||||
using var ms = new MemoryStream();
|
||||
bmp.Save(ms, ImageFormat.Png);
|
||||
pngList.Add(ms.ToArray());
|
||||
Console.WriteLine($" {sz}x{sz} OK");
|
||||
}
|
||||
|
||||
CreateIco(pngList, sizes, outputPath);
|
||||
Console.WriteLine($"Icon saved: {outputPath}");
|
||||
|
||||
static Bitmap DrawGemDiamond(int size)
|
||||
{
|
||||
var bmp = new Bitmap(size, size, PixelFormat.Format32bppArgb);
|
||||
using var g = Graphics.FromImage(bmp);
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
g.Clear(Color.Transparent);
|
||||
|
||||
float s = size;
|
||||
float cx = s / 2f;
|
||||
|
||||
// ── 보석 다이아몬드 외곽 좌표 ──
|
||||
// Table (평평한 윗면)
|
||||
float tableL = s * 0.22f;
|
||||
float tableR = s * 0.78f;
|
||||
float tableY = s * 0.18f;
|
||||
|
||||
// Girdle (가장 넓은 부분)
|
||||
float girdleL = s * 0.06f;
|
||||
float girdleR = s * 0.94f;
|
||||
float girdleY = s * 0.40f;
|
||||
|
||||
// Culet (바닥 뾰족한 점)
|
||||
float culetX = cx;
|
||||
float culetY = s * 0.92f;
|
||||
|
||||
// 주요 꼭짓점
|
||||
PointF TL = new(tableL, tableY); // 테이블 좌
|
||||
PointF TR = new(tableR, tableY); // 테이블 우
|
||||
PointF GL = new(girdleL, girdleY); // 거들 좌
|
||||
PointF GR = new(girdleR, girdleY); // 거들 우
|
||||
PointF BT = new(culetX, culetY); // 바닥 점
|
||||
|
||||
// Crown 내부 포인트 (table → girdle 사이 facet)
|
||||
PointF CM = new(cx, girdleY); // 거들 중앙
|
||||
PointF CT = new(cx, tableY); // 테이블 중앙
|
||||
|
||||
// Crown facet 분할점
|
||||
PointF CL = new(s * 0.14f, girdleY); // 거들 좌측 근처
|
||||
PointF CR = new(s * 0.86f, girdleY); // 거들 우측 근처
|
||||
|
||||
// Pavilion facet 내부 교차점들
|
||||
float pavMidY = s * 0.62f;
|
||||
PointF PL = new(s * 0.28f, pavMidY); // 파빌리온 좌 중간
|
||||
PointF PR = new(s * 0.72f, pavMidY); // 파빌리온 우 중간
|
||||
PointF PM = new(cx, pavMidY); // 파빌리온 중앙
|
||||
|
||||
// ── 색상 ──
|
||||
var blue = Color.FromArgb(50, 110, 230);
|
||||
var blueBright = Color.FromArgb(80, 150, 255);
|
||||
var green = Color.FromArgb(60, 200, 80);
|
||||
var greenBright = Color.FromArgb(100, 235, 110);
|
||||
var red = Color.FromArgb(230, 50, 65);
|
||||
var redBright = Color.FromArgb(255, 90, 100);
|
||||
var greenDk = Color.FromArgb(45, 170, 75);
|
||||
var greenDkBr = Color.FromArgb(80, 210, 100);
|
||||
|
||||
// ── Crown (상단부) 채우기 ──
|
||||
|
||||
// Crown 좌: Blue
|
||||
FillPoly(g, new[]{TL, GL, CM, CT}, blueBright, blue);
|
||||
// Crown 우: Green
|
||||
FillPoly(g, new[]{TR, CT, CM, GR}, greenBright, green);
|
||||
|
||||
// ── Pavilion (하단부) 채우기 ──
|
||||
|
||||
// Pavilion 좌: Red
|
||||
FillPoly(g, new[]{GL, CM, BT}, redBright, red);
|
||||
// Pavilion 우: Green (darker)
|
||||
FillPoly(g, new[]{CM, GR, BT}, greenDkBr, greenDk);
|
||||
|
||||
// ── Facet 내부 색상 변화 (깊이감) ──
|
||||
// Crown 좌측 어두운 삼각형
|
||||
using var crownShadow = new SolidBrush(Color.FromArgb(25, 0, 0, 0));
|
||||
g.FillPolygon(crownShadow, new[]{TL, GL, new PointF(cx * 0.7f, girdleY * 0.85f)});
|
||||
|
||||
// Pavilion 중앙 밝은 삼각형 (반사)
|
||||
using var pavHighlight = new SolidBrush(Color.FromArgb(20, 255, 255, 255));
|
||||
g.FillPolygon(pavHighlight, new[]{CM, BT, new PointF(cx - s*0.08f, pavMidY)});
|
||||
|
||||
// ── Facet 선 (흰색) ──
|
||||
float lw = Math.Max(0.8f, s / 140f);
|
||||
using var facetPen = new Pen(Color.FromArgb(180, 255, 255, 255), lw)
|
||||
{
|
||||
LineJoin = LineJoin.Round,
|
||||
StartCap = LineCap.Round,
|
||||
EndCap = LineCap.Round
|
||||
};
|
||||
|
||||
// Crown facet lines
|
||||
// 테이블 윗변
|
||||
g.DrawLine(facetPen, TL, TR);
|
||||
// 테이블 → 거들 대각선
|
||||
g.DrawLine(facetPen, TL, GL);
|
||||
g.DrawLine(facetPen, TR, GR);
|
||||
// 세로 중심선 (table → girdle)
|
||||
g.DrawLine(facetPen, CT, CM);
|
||||
// Crown 크로스 facet
|
||||
g.DrawLine(facetPen, TL, CM);
|
||||
g.DrawLine(facetPen, TR, CM);
|
||||
// 추가 Crown facet (table 모서리 → 거들 중간)
|
||||
g.DrawLine(facetPen, TL, new PointF(girdleL + (cx - girdleL) * 0.5f, girdleY));
|
||||
g.DrawLine(facetPen, TR, new PointF(cx + (girdleR - cx) * 0.5f, girdleY));
|
||||
|
||||
// Girdle 수평선
|
||||
g.DrawLine(facetPen, GL, GR);
|
||||
|
||||
// Pavilion facet lines
|
||||
// 거들 → 바닥 점
|
||||
g.DrawLine(facetPen, GL, BT);
|
||||
g.DrawLine(facetPen, GR, BT);
|
||||
// 중심 → 바닥
|
||||
g.DrawLine(facetPen, CM, BT);
|
||||
// Pavilion 크로스 facets
|
||||
float crossY = girdleY + (culetY - girdleY) * 0.45f;
|
||||
PointF crossL = new(girdleL + (culetX - girdleL) * 0.45f, crossY);
|
||||
PointF crossR = new(girdleR - (girdleR - culetX) * 0.45f, crossY);
|
||||
g.DrawLine(facetPen, GL, crossR);
|
||||
g.DrawLine(facetPen, GR, crossL);
|
||||
// 거들 중간점에서 바닥으로
|
||||
g.DrawLine(facetPen, new PointF(girdleL + (cx - girdleL) * 0.5f, girdleY), BT);
|
||||
g.DrawLine(facetPen, new PointF(cx + (girdleR - cx) * 0.5f, girdleY), BT);
|
||||
|
||||
// ── 외곽선 (두꺼운 흰색) ──
|
||||
float olw = Math.Max(1.2f, s / 100f);
|
||||
using var outlinePen = new Pen(Color.FromArgb(220, 255, 255, 255), olw)
|
||||
{
|
||||
LineJoin = LineJoin.Round
|
||||
};
|
||||
g.DrawPolygon(outlinePen, new[]{TL, TR, GR, BT, GL});
|
||||
|
||||
// ── 상단 하이라이트 (테이블 면 빛 반사) ──
|
||||
using var tableHL = new LinearGradientBrush(
|
||||
TL, new PointF(cx, girdleY),
|
||||
Color.FromArgb(45, 255, 255, 255),
|
||||
Color.Transparent);
|
||||
g.FillPolygon(tableHL, new[]{TL, TR, CT});
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
static void FillPoly(Graphics g, PointF[] pts, Color c1, Color c2)
|
||||
{
|
||||
float minX = pts.Min(p => p.X), maxX = pts.Max(p => p.X);
|
||||
float minY = pts.Min(p => p.Y), maxY = pts.Max(p => p.Y);
|
||||
var rect = new RectangleF(minX, minY, Math.Max(1, maxX - minX), Math.Max(1, maxY - minY));
|
||||
try
|
||||
{
|
||||
using var brush = new LinearGradientBrush(rect, c1, c2, LinearGradientMode.Vertical);
|
||||
g.FillPolygon(brush, pts);
|
||||
}
|
||||
catch
|
||||
{
|
||||
using var brush = new SolidBrush(c1);
|
||||
g.FillPolygon(brush, pts);
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateIco(List<byte[]> pngs, int[] sizes, string path)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
using var bw = new BinaryWriter(ms);
|
||||
bw.Write((short)0);
|
||||
bw.Write((short)1);
|
||||
bw.Write((short)pngs.Count);
|
||||
int offset = 6 + 16 * pngs.Count;
|
||||
for (int i = 0; i < pngs.Count; i++)
|
||||
{
|
||||
byte dim = (byte)(sizes[i] >= 256 ? 0 : sizes[i]);
|
||||
bw.Write(dim); bw.Write(dim);
|
||||
bw.Write((byte)0); bw.Write((byte)0);
|
||||
bw.Write((short)1); bw.Write((short)32);
|
||||
bw.Write(pngs[i].Length); bw.Write(offset);
|
||||
offset += pngs[i].Length;
|
||||
}
|
||||
foreach (var png in pngs) bw.Write(png);
|
||||
File.WriteAllBytes(path, ms.ToArray());
|
||||
}
|
||||
Reference in New Issue
Block a user