using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; public static class Cutout { // Remove a flat light-grey studio background by flood-filling from the image border, // soften the 1px edge, then scale down to size x size. public static void Run(string src, string dst, int bg, int tol, int size) { using (var b0 = new Bitmap(src)) using (var b = b0.Clone(new Rectangle(0, 0, b0.Width, b0.Height), PixelFormat.Format32bppArgb)) { int w = b.Width, h = b.Height; var data = b.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var px = new byte[w * h * 4]; Marshal.Copy(data.Scan0, px, 0, px.Length); Func isBg = i => { int B = px[i], G = px[i + 1], R = px[i + 2]; int mx = Math.Max(R, Math.Max(G, B)), mn = Math.Min(R, Math.Min(G, B)); return mx - mn <= 6 && Math.Abs(mx - bg) <= tol; }; var seen = new bool[w * h]; var q = new Queue(); for (int x = 0; x < w; x++) { q.Enqueue(x); q.Enqueue((h - 1) * w + x); } for (int y = 0; y < h; y++) { q.Enqueue(y * w); q.Enqueue(y * w + w - 1); } while (q.Count > 0) { int p = q.Dequeue(); if (seen[p] || !isBg(p * 4)) continue; seen[p] = true; int x = p % w, y = p / w; if (x > 0) q.Enqueue(p - 1); if (x < w - 1) q.Enqueue(p + 1); if (y > 0) q.Enqueue(p - w); if (y < h - 1) q.Enqueue(p + w); } for (int p = 0; p < w * h; p++) { int i = p * 4; if (seen[p]) { px[i + 3] = 0; continue; } int x = p % w, y = p / w; bool edge = (x > 0 && seen[p - 1]) || (x < w - 1 && seen[p + 1]) || (y > 0 && seen[p - w]) || (y < h - 1 && seen[p + w]); if (!edge) continue; int d = Math.Max(Math.Abs(px[i + 2] - bg), Math.Max(Math.Abs(px[i + 1] - bg), Math.Abs(px[i] - bg))); double a = Math.Min(1.0, Math.Max(0.2, d / 50.0)); for (int c = 0; c < 3; c++) px[i + c] = (byte)Math.Max(0, Math.Min(255, Math.Round((px[i + c] - (1 - a) * bg) / a))); px[i + 3] = (byte)(a * 255); } Marshal.Copy(px, 0, data.Scan0, px.Length); b.UnlockBits(data); using (var o = new Bitmap(size, size, PixelFormat.Format32bppArgb)) using (var g = Graphics.FromImage(o)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; g.DrawImage(b, new Rectangle(0, 0, size, size)); o.Save(dst, ImageFormat.Png); } } } }