private static bool AreDirectNeighbors(Point point1, Point point2)
 {
     return Math.Abs(point1.X - point2.X) <= 15 && Math.Abs(point1.Y - point2.Y) <= 15;
 }
        private IEnumerable<List<Point>> GetNeighboringColors(int x, int y)
        {
            var results = new List<List<Point>>();
            var result = new List<Point>();
            results.Add(result);
            var currentPoint = new Point { X = x, Y = y };
            this._colorsProcessed[x, y] = true;
            result.Add(currentPoint);

            var processQueue = new List<Point> { currentPoint };
            int i = 0;

            while (processQueue.Count > i)
            {
                Point neighbor = processQueue.ElementAt(i);
                i++;
                foreach (Point newNeighbor in this.GetMatchingUnprocessedDirectNeighbors(neighbor.X, neighbor.Y))
                {
                    this._colorsProcessed[newNeighbor.X, newNeighbor.Y] = true;
                    if (!AreDirectNeighbors(result.Last(), newNeighbor))
                    {
                        result = new List<Point>();
                        results.Add(result);
                    }
                    processQueue.Insert(i, newNeighbor);
                    result.Add(newNeighbor);
                }
            }
            return results;
        }
        public IEnumerable<MouseDragAction> GetDrawInstructions(List<ColorSpot> PaletteColorSpots, IDictionary<string, string> settings = null, IBrushChanger brushChanger = null)
        {
            int ignoreColorIndex =
                PaletteColorSpots.IndexOf(PaletteColorSpots.FirstOrDefault(x => x.Color.Name == IgnoreColor));

            if (!PaletteColorSpots.Any())
            {
                PaletteColorSpots = new List<ColorSpot> {new ColorSpot {Color = Color.Black, Point = Point.Empty}};
            }

            int bitmapHeight;
            int bitmapWidth;

            var output = new List<MouseDragAction>();

            using (var bitmap = new Bitmap(_bitmapPath))
            {
                bitmapHeight = bitmap.Height;
                bitmapWidth = bitmap.Width;

                _colors = new int[bitmapWidth,bitmapHeight];

                var rect = new Rectangle(0, 0, bitmapWidth, bitmapHeight);
                BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
                IntPtr ptr = bmpData.Scan0;
                int bytes = bmpData.Stride*bitmapHeight;
                var rgbValues = new byte[bytes];
                Marshal.Copy(ptr, rgbValues, 0, bytes);
                for (int x = 0; x < bitmapWidth; x++)
                {
                    for (int y = 0; y < bitmapHeight; 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 matchingColor =
                            PaletteColorSpots.OrderBy(c => c.Color.DifferenceTo(currentColor)).First();
                        _colors[x, y] = PaletteColorSpots.IndexOf(matchingColor);
                    }
                }
                bitmap.UnlockBits(bmpData);
            }

            int colorCount = PaletteColorSpots.Count;
            var strokesForEachColor = new List<MouseDragAction>[colorCount];

            for (int i = 0; i < colorCount; i++)
            {
                ColorSpot paletteColorSpot = PaletteColorSpots[i];
                strokesForEachColor[i] = new List<MouseDragAction>
                    {new MouseDragAction(new List<Point> {paletteColorSpot.Point}, true, paletteColorSpot.Color)};
            }

            for (int x = 0; x < bitmapWidth; x++)
            {
                for (int y = 0; y < bitmapHeight; y++)
                {
                    int currentPixelColorIndex = _colors[x, y];
                    if (currentPixelColorIndex == ignoreColorIndex)
                    {
                        continue;
                    }
                    var currentPixelPoint = new Point(x, y);
                    List<MouseDragAction> strokesForCurrentColor = strokesForEachColor[currentPixelColorIndex];
                    bool found = false;

                    foreach (MouseDragAction stroke in strokesForCurrentColor)
                    {
                        if (stroke.DiscardOffset)
                        {
                            continue;
                        }
                        Point lastPoint = stroke.Points[stroke.Points.Count - 1];
                        if (PointsAreNeighbors(lastPoint.X, lastPoint.Y, x, y))
                        {
                            stroke.PushPoint(new Point(x, y));
                            found = true;
                            break;
                        }
                        Point firstPoint = stroke.Points[0];
                        if (PointsAreNeighbors(firstPoint.X, firstPoint.Y, x, y))
                        {
                            stroke.AddPoint(new Point(x, y));
                            found = true;
                            break;
                        }
                    }
                    if (found)
                    {
                        continue;
                    }

                    strokesForEachColor[currentPixelColorIndex].Add(
                        new MouseDragAction(new List<Point> {currentPixelPoint}));
                }
            }

            foreach (var mouseDragActions in strokesForEachColor)
            {
                output.AddRange(mouseDragActions);
            }

            return output;
        }