using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; public static class Cut { // Cut a circular category tile out of the screenshot: drop everything outside the // circle, then flood-fill the flat grey circle background from its rim. public static void Circle(string src, string dst, int cx, int cy, int r, int fadeX) { using (var b = new Bitmap(src)) { int s = r * 2, ox = cx - r, oy = cy - r; var o = new Bitmap(s, s, PixelFormat.Format32bppArgb); var px = new Color[s, s]; for (int y = 0; y < s; y++) for (int x = 0; x < s; x++) px[x, y] = b.GetPixel(ox + x, oy + y); var bg = new bool[s, s]; var q = new Queue(); Func isBg = (x, y) => { Color c = px[x, y]; int mx = Math.Max(c.R, Math.Max(c.G, c.B)), mn = Math.Min(c.R, Math.Min(c.G, c.B)); if (mx - mn > 5) return false; if (Math.Abs(mx - 244) <= 4) return true; return (ox + x) < fadeX && mn >= 238; }; for (int y = 0; y < s; y++) for (int x = 0; x < s; x++) { double d = Math.Sqrt((x - r + 0.5) * (x - r + 0.5) + (y - r + 0.5) * (y - r + 0.5)); if (d > r - 1) { bg[x, y] = true; } else if (d > r - 3 && isBg(x, y)) { bg[x, y] = true; q.Enqueue(new Point(x, y)); } } while (q.Count > 0) { var p = q.Dequeue(); for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) { int nx = p.X + dx, ny = p.Y + dy; if (nx < 0 || ny < 0 || nx >= s || ny >= s || bg[nx, ny]) continue; if (!isBg(nx, ny)) continue; bg[nx, ny] = true; q.Enqueue(new Point(nx, ny)); } } for (int y = 0; y < s; y++) for (int x = 0; x < s; x++) { if (bg[x, y]) { o.SetPixel(x, y, Color.Transparent); continue; } Color c = px[x, y]; bool edge = false; for (int dy = -1; dy <= 1 && !edge; dy++) for (int dx = -1; dx <= 1 && !edge; dx++) { int nx = x + dx, ny = y + dy; if (nx >= 0 && ny >= 0 && nx < s && ny < s && bg[nx, ny]) edge = true; } if (edge) { int dist = Math.Max(Math.Abs(c.R - 244), Math.Max(Math.Abs(c.G - 244), Math.Abs(c.B - 244))); double a = Math.Min(1.0, Math.Max(0.15, dist / 60.0)); Func un = v => Math.Max(0, Math.Min(255, (int)Math.Round((v - (1 - a) * 244) / a))); o.SetPixel(x, y, Color.FromArgb((int)(a * 255), un(c.R), un(c.G), un(c.B))); } else o.SetPixel(x, y, c); } o.Save(dst, ImageFormat.Png); } } // Crop a rectangle; optionally patch over a square UI overlay (e.g. a heart button) // by smearing the column just left of it across the patch. public static void Crop(string src, string dst, int x0, int y0, int w, int h, int px0, int py0, int pw, int ph, bool jpeg) { using (var b = new Bitmap(src)) { var o = new Bitmap(w, h, PixelFormat.Format24bppRgb); for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { int sx = x0 + x, sy = y0 + y; if (pw > 0 && sx >= px0 && sx < px0 + pw && sy >= py0 && sy < py0 + ph) { Color l = b.GetPixel(px0 - 3, sy), rgt = b.GetPixel(Math.Min(b.Width - 1, px0 + pw + 2), sy); double t = (sx - px0) / (double)pw; o.SetPixel(x, y, Color.FromArgb((int)(l.R + (rgt.R - l.R) * t), (int)(l.G + (rgt.G - l.G) * t), (int)(l.B + (rgt.B - l.B) * t))); } else o.SetPixel(x, y, b.GetPixel(sx, sy)); } if (jpeg) { var enc = Array.Find(ImageCodecInfo.GetImageEncoders(), e => e.MimeType == "image/jpeg"); var ps = new EncoderParameters(1); ps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L); o.Save(dst, enc, ps); } else o.Save(dst, ImageFormat.Png); } } // Resize-and-center-crop to an exact size, saved as JPEG. public static void Cover(string src, string dst, int w, int h, int q) { using (var b = Image.FromFile(src)) { double sc = Math.Max(w / (double)b.Width, h / (double)b.Height); int sw = (int)Math.Round(w / sc), sh = (int)Math.Round(h / sc); int sx = (b.Width - sw) / 2, sy = (b.Height - sh) / 2; var o = new Bitmap(w, h, PixelFormat.Format24bppRgb); using (var g = Graphics.FromImage(o)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; g.DrawImage(b, new Rectangle(0, 0, w, h), new Rectangle(sx, sy, sw, sh), GraphicsUnit.Pixel); } var enc = Array.Find(ImageCodecInfo.GetImageEncoders(), e => e.MimeType == "image/jpeg"); var ps = new EncoderParameters(1); ps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)q); o.Save(dst, enc, ps); } } }