using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; public static class BoxCut { // Cut the 3D gift box out of its lavender-pink gradient background. Background = bluish pink // (high blue, blue clearly above green); the box itself is warm pink, green ribbon, orange flowers. // Flood-fill from the crop border, feather the edge, trim to the content box, save PNG. public static void Run(string src, string dst, int cropH, int pad) { using (var b0 = new Bitmap(src)) using (var b = b0.Clone(new Rectangle(0, 0, b0.Width, cropH), 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 bgScore = i => { int B = px[i], G = px[i + 1], R = px[i + 2]; // 1 = surely background, 0 = surely box double s = (B - G - 4) / 10.0; if (R < 225 || B < 225) s = Math.Min(s, 0); return Math.Max(0, Math.Min(1, s)); }; 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] || bgScore(p * 4) < 0.5) 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 minX = w, minY = h, maxX = 0, maxY = 0; for (int p = 0; p < w * h; p++) { int i = p * 4, x = p % w, y = p / w; if (seen[p]) { px[i + 3] = 0; continue; } 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) px[i + 3] = (byte)(255 * (1 - 0.6 * bgScore(i))); if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; } Marshal.Copy(px, 0, data.Scan0, px.Length); b.UnlockBits(data); int cw = maxX - minX + 1 + pad * 2, ch = maxY - minY + 1 + pad * 2; using (var o = new Bitmap(cw, ch, PixelFormat.Format32bppArgb)) using (var g = Graphics.FromImage(o)) { g.Clear(Color.Transparent); g.DrawImage(b, new Rectangle(pad, pad, maxX - minX + 1, maxY - minY + 1), new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1), GraphicsUnit.Pixel); o.Save(dst, ImageFormat.Png); } Console.WriteLine("bbox " + minX + "," + minY + " " + (maxX - minX + 1) + "x" + (maxY - minY + 1)); } } }