Files
2026-09-21 17:45:24 +02:00

176 lines
6.9 KiB
C#

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
public class ImageProcessor
{
public static void MakeCleanTransparent(string inputPath, string outputPath)
{
using var original = (Bitmap)Image.FromFile(inputPath);
int w = original.Width;
int h = original.Height;
using var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(bmp))
{
g.DrawImage(original, 0, 0, w, h);
}
var rect = new Rectangle(0, 0, w, h);
var data = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int bytesPerPixel = 4;
int byteCount = data.Stride * h;
byte[] pixels = new byte[byteCount];
System.Runtime.InteropServices.Marshal.Copy(data.Scan0, pixels, 0, byteCount);
bool[,] isBg = new bool[w, h];
var queue = new Queue<Point>();
bool CheckWhite(int x, int y)
{
int idx = y * data.Stride + x * bytesPerPixel;
byte b = pixels[idx];
byte g = pixels[idx + 1];
byte r = pixels[idx + 2];
// Pure/near white or light background
return r > 215 && g > 215 && b > 215 && Math.Abs(r - g) < 25 && Math.Abs(g - b) < 25;
}
// Seed borders
for (int x = 0; x < w; x++)
{
if (CheckWhite(x, 0)) { isBg[x, 0] = true; queue.Enqueue(new Point(x, 0)); }
if (CheckWhite(x, h - 1)) { isBg[x, h - 1] = true; queue.Enqueue(new Point(x, h - 1)); }
}
for (int y = 0; y < h; y++)
{
if (CheckWhite(0, y)) { isBg[0, y] = true; queue.Enqueue(new Point(0, y)); }
if (CheckWhite(w - 1, y)) { isBg[w - 1, y] = true; queue.Enqueue(new Point(w - 1, y)); }
}
int[] dx = { 0, 0, 1, -1 };
int[] dy = { 1, -1, 0, 0 };
while (queue.Count > 0)
{
var p = queue.Dequeue();
for (int i = 0; i < 4; i++)
{
int nx = p.X + dx[i];
int ny = p.Y + dy[i];
if (nx >= 0 && nx < w && ny >= 0 && ny < h && !isBg[nx, ny])
{
if (CheckWhite(nx, ny))
{
isBg[nx, ny] = true;
queue.Enqueue(new Point(nx, ny));
}
}
}
}
// Apply transparency
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int idx = y * data.Stride + x * bytesPerPixel;
if (isBg[x, y])
{
pixels[idx + 3] = 0; // Alpha = 0
}
else
{
// Check if adjacent to background for soft anti-aliased edge
bool nearBg = false;
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < w && ny >= 0 && ny < h && isBg[nx, ny])
{
nearBg = true;
break;
}
}
byte b = pixels[idx];
byte g = pixels[idx + 1];
byte r = pixels[idx + 2];
if (nearBg && r > 210 && g > 210 && b > 210)
{
double avg = (r + g + b) / 3.0;
int alpha = (int)(255.0 * (1.0 - (avg - 210.0) / 45.0));
pixels[idx + 3] = (byte)Math.Clamp(alpha, 0, 255);
}
}
}
}
System.Runtime.InteropServices.Marshal.Copy(pixels, 0, data.Scan0, byteCount);
bmp.UnlockBits(data);
// Ensure output dir
var dir = Path.GetDirectoryName(outputPath);
if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
bmp.Save(outputPath, ImageFormat.Png);
Console.WriteLine($"Exported: {outputPath}");
}
public static void Main(string[] args)
{
string brain = @"C:\Users\mvrba\.gemini\antigravity\brain\f097144f-e914-4120-8461-4bdfe0d3cdef";
string root = @"src\CiselnaVyprava\wwwroot\assets\images";
// 1. Knight (Exact same boy character)
string knightIdleSrc = Path.Combine(brain, "disney_hero_knight_1789996129818.jpg");
string knightAtkSrc = Path.Combine(brain, "knight_action_strike_1789998031553.jpg");
string knightDefSrc = Path.Combine(brain, "knight_action_shield_1789998042563.jpg");
string knightDizzySrc = Path.Combine(brain, "hero_knight_dizzy_1789997064946.jpg");
// 2. Goblin
string goblinIdleSrc = Path.Combine(brain, "disney_monster_goblin_1789996145106.jpg");
string goblinAtkSrc = Path.Combine(brain, "goblin_monster_attack_1789997081347.jpg");
string goblinHurtSrc = Path.Combine(brain, "goblin_monster_hurt_1789997090819.jpg");
// 3. Golem Boss
string golemSrc = Path.Combine(brain, "stone_golem_boss_1789997102336.jpg");
// Process Knight
for (int p = 1; p <= 4; p++)
{
string idleSrc = (p <= 2) ? knightIdleSrc : knightDizzySrc;
MakeCleanTransparent(idleSrc, Path.Combine(root, $"heroes/knight_idle_p{p}.png"));
MakeCleanTransparent(knightAtkSrc, Path.Combine(root, $"heroes/knight_attack_p{p}.png"));
MakeCleanTransparent(knightDefSrc, Path.Combine(root, $"heroes/knight_defend_p{p}.png"));
MakeCleanTransparent(knightDizzySrc, Path.Combine(root, $"heroes/knight_hurt_p{p}.png"));
}
// Process Goblin & Slime
for (int p = 1; p <= 4; p++)
{
MakeCleanTransparent(goblinIdleSrc, Path.Combine(root, $"enemies/goblin_idle_p{p}.png"));
MakeCleanTransparent(goblinAtkSrc, Path.Combine(root, $"enemies/goblin_attack_p{p}.png"));
MakeCleanTransparent(goblinHurtSrc, Path.Combine(root, $"enemies/goblin_hurt_p{p}.png"));
MakeCleanTransparent(goblinIdleSrc, Path.Combine(root, $"enemies/slime_idle_p{p}.png"));
MakeCleanTransparent(goblinAtkSrc, Path.Combine(root, $"enemies/slime_attack_p{p}.png"));
MakeCleanTransparent(goblinHurtSrc, Path.Combine(root, $"enemies/slime_hurt_p{p}.png"));
}
// Process Golem
for (int p = 1; p <= 4; p++)
{
MakeCleanTransparent(golemSrc, Path.Combine(root, $"enemies/golem_idle_p{p}.png"));
MakeCleanTransparent(golemSrc, Path.Combine(root, $"enemies/golem_attack_p{p}.png"));
MakeCleanTransparent(golemSrc, Path.Combine(root, $"enemies/golem_hurt_p{p}.png"));
}
Console.WriteLine("All assets converted to clean 32-bit transparent PNGs!");
}
}