public IEnumerable<MouseDragAction> GetDrawInstructions(List<ColorSpot> color, IDictionary<string, string> settings = null, IBrushChanger brushChanger = null) { List<ColorSpot> knownColors = color.ToList(); int ignoredColor; try { ignoredColor = knownColors.IndexOf(knownColors.First(x => x.IsBackgroundColor)); } catch (Exception) { throw new Exception("I need a background color!!"); } // prevent drawing of single pixels etc int colorGroupMinSize = settings.GetIntValueOrDefault("MinimumStrokeSize", 15); var output = new List<MouseDragAction>(); using (var bitmap = new Bitmap(this._bitmapPath)) { this._bitmapHeight = bitmap.Height; this._bitmapWidth = bitmap.Width; var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); this._colors = new int[bitmap.Width,bitmap.Height]; this._colorsProcessed = new bool[bitmap.Width,bitmap.Height]; //_pixels = new KeyValuePair<Point, PixelMeta>[bitmap.Width * bitmap.Height]; BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = bmpData.Stride * bitmap.Height; var rgbValues = new byte[bytes]; Marshal.Copy(ptr, rgbValues, 0, bytes); for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { int position = (y * bmpData.Stride) + (x * 3); int blue = rgbValues[position]; int green = rgbValues[position + 1]; int red = rgbValues[position + 2]; Color currentColor = Color.FromArgb(red, green, blue); ColorSpot closestColor = knownColors.OrderBy(c => c.Color.DifferenceTo(currentColor)).FirstOrDefault(); this._colors[x, y] = knownColors.IndexOf(closestColor); } } bitmap.UnlockBits(bmpData); } var colorGroups = new List<List<Point>>(); for (int x = 0; x < this._bitmapWidth; x++) { for (int y = 0; y < this._bitmapHeight; y++) { if (this._colors[x, y] != ignoredColor && !this._colorsProcessed[x, y]) { colorGroups.AddRange(this.GetNeighboringColors(x, y)); } } } int? lastColorIndex = null; IOrderedEnumerable<List<Point>> colorGroupsOrderedByColor = colorGroups.Where(x => x.Count >= colorGroupMinSize).OrderBy(x => this._colors[x.First().X, x.First().Y]); foreach (var colorGroup in colorGroupsOrderedByColor) { var colorOutput = new List<MouseDragAction>(); int currentColorIndex = this._colors[colorGroup.First().X, colorGroup.First().Y]; if (!lastColorIndex.HasValue || lastColorIndex.Value != currentColorIndex) { lastColorIndex = currentColorIndex; ColorSpot currentColor = knownColors[this._colors[colorGroup.First().X, colorGroup.First().Y]]; var colorChangeAction = new MouseDragAction(new List<Point> { currentColor.Point }, true, currentColor.Color); colorOutput.Add(colorChangeAction); } var ma = new MouseDragAction(colorGroup.Select(x => new Point(x.X, x.Y)).ToList()); colorOutput.Add(ma); output.AddRange(colorOutput); } return output; }