using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; public static class CutoutRgb { // Crop src to (cx,cy,cw,ch), remove a flat coloured background (bR,bG,bB) by flood-filling from the // crop border, soften the 1px edge, then scale to ow x oh. Pixels inside (ex,ey,ew,eh) are treated as // background first (used to erase the title text baked into the reference image). public static void Run(string src, string dst, int cx, int cy, int cw, int ch, int bR, int bG, int bB, int tol, int ex, int ey, int ew, int eh, int ow, int oh) { using (var b0 = new Bitmap(src)) using (var b = b0.Clone(new Rectangle(cx, cy, cw, ch), 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); for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { int X = x + cx, Y = y + cy; if (X >= ex && X < ex + ew && Y >= ey && Y < ey + eh) { int i = (y * w + x) * 4; px[i] = (byte)bB; px[i + 1] = (byte)bG; px[i + 2] = (byte)bR; } } Func dist = i => Math.Max(Math.Abs(px[i + 2] - bR), Math.Max(Math.Abs(px[i + 1] - bG), Math.Abs(px[i] - bB))); 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] || dist(p * 4) > tol) 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); } int[] bg = { bB, bG, bR }; 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; double a = Math.Min(1.0, Math.Max(0.2, dist(i) / 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[c]) / a))); px[i + 3] = (byte)(a * 255); } Marshal.Copy(px, 0, data.Scan0, px.Length); b.UnlockBits(data); using (var o = new Bitmap(ow, oh, 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, ow, oh)); o.Save(dst, ImageFormat.Png); } } } }