private PointData getBorderData(byte[] bytes)
        {
            PointData isborderpoint = new PointData(size.Height * size.Width);
            bool      prevtrans     = false;
            bool      currenttrans  = false;

            for (int y = 0; y < size.Height; y++)
            {
                prevtrans = false;
                for (int x = 0; x <= size.Width; x++)
                {
                    if (x == size.Width)
                    {
                        if (!prevtrans)
                        {
                            isborderpoint.SetPoint(y * size.Width + x - 1, true);
                        }
                        continue;
                    }
                    currenttrans = bytes[y * stride + x * 4 + 3] == 0;
                    if (x == 0 && !currenttrans)
                    {
                        isborderpoint.SetPoint(y * size.Width + x, true);
                    }
                    if (prevtrans && !currenttrans)
                    {
                        isborderpoint.SetPoint(y * size.Width + x - 1, true);
                    }
                    if (!prevtrans && currenttrans && x != 0)
                    {
                        isborderpoint.SetPoint(y * size.Width + x, true);
                    }
                    prevtrans = currenttrans;
                }
            }
            for (int x = 0; x < size.Width; x++)
            {
                prevtrans = false;
                for (int y = 0; y <= size.Height; y++)
                {
                    if (y == size.Height)
                    {
                        if (!prevtrans)
                        {
                            isborderpoint.SetPoint((y - 1) * size.Width + x, true);
                        }
                        continue;
                    }
                    currenttrans = bytes[y * stride + x * 4 + 3] == 0;
                    if (y == 0 && !currenttrans)
                    {
                        isborderpoint.SetPoint(y * size.Width + x, true);
                    }
                    if (prevtrans && !currenttrans)
                    {
                        isborderpoint.SetPoint((y - 1) * size.Width + x, true);
                    }
                    if (!prevtrans && currenttrans && y != 0)
                    {
                        isborderpoint.SetPoint(y * size.Width + x, true);
                    }
                    prevtrans = currenttrans;
                }
            }
            return(isborderpoint);
        }
        public List <Point[]> Find(Bitmap bmp, bool outside = true)
        {
            this.outside = outside;
            List <Point> border  = new List <Point>();
            BitmapData   bmpdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            stride = bmpdata.Stride;
            bytes  = new byte[bmp.Width * bmp.Height * 4];
            size   = bmp.Size;

            Marshal.Copy(bmpdata.Scan0, bytes, 0, bytes.Length);

            // Get all Borderpoint

            borderdata = getBorderData(bytes);

            bmp.UnlockBits(bmpdata);

            List <List <Point> > regions = new List <List <Point> >();

            //Loop until no more borderpoints are available

            while (borderdata.PointCount > 0)
            {
                List <Point> region = new List <Point>();

                //if valid is false the region doesn't close
                bool valid = true;

                //Find the first borderpoint from where whe start crawling
                Point startpos = getFirstPoint(borderdata);

                //we need this to know if and how often we already visted the point.
                //we somtime have to visit a point a second time because we have to go backward until a unvisted point is found again
                //for example if we go int a narrow 1px hole
                visited = new int[bmp.Size.Width * bmp.Size.Height];

                region.Add(startpos);

                //Find the next possible point
                Point current = getNextPoint(startpos);

                if (current != zeropoint)
                {
                    visited[current.Y * bmp.Width + current.X]++;
                    region.Add(current);
                }

                //May occure with just one transparent pixel without neighbors
                if (current == zeropoint)
                {
                    valid = false;
                }

                //Loop until the area closed or colsing the area wasn't poosible
                while (!current.Equals(startpos) && valid)
                {
                    var pos = current;
                    //Check if the area was aready visited
                    if (visited[current.Y * bmp.Width + current.X] < 2)
                    {
                        current = getNextPoint(pos);
                        visited[pos.Y * bmp.Width + pos.X]++;
                        //If no possible point was found, search in reversed direction
                        if (current == zeropoint)
                        {
                            current = getNextPointBackwards(pos);
                        }
                    }
                    else
                    { //If point was already visited, search in reversed direction
                        current = getNextPointBackwards(pos);
                    }

                    //No possible point was found. Closing isn't possible
                    if (current == zeropoint)
                    {
                        valid = false;
                        break;
                    }

                    visited[current.Y * bmp.Width + current.X]++;

                    region.Add(current);
                }
                //Remove point from source borderdata
                foreach (var p in region)
                {
                    borderdata.SetPoint(p.Y * bmp.Width + p.X, false);
                }
                //Add region if closing was possible
                if (valid)
                {
                    regions.Add(region);
                }
            }

            //Checks if Region goes the same way back and trims it in this case
            foreach (var region in regions)
            {
                int duplicatedpos = -1;

                bool[] duplicatecheck = new bool[size.Width * size.Height];
                int    length         = region.Count;
                for (int i = 0; i < length; i++)
                {
                    var p = region[i];
                    if (duplicatecheck[p.Y * size.Width + p.X])
                    {
                        duplicatedpos = i - 1;
                        break;
                    }
                    duplicatecheck[p.Y * size.Width + p.X] = true;
                }

                if (duplicatedpos == -1)
                {
                    continue;
                }

                if (duplicatedpos != ((region.Count - 1) / 2))
                {
                    continue;
                }

                bool reversed = true;

                for (int i = 0; i < duplicatedpos; i++)
                {
                    if (region[duplicatedpos - i - 1] != region[duplicatedpos + i + 1])
                    {
                        reversed = false;
                        break;
                    }
                }

                if (!reversed)
                {
                    continue;
                }

                region.RemoveRange(duplicatedpos + 1, region.Count - duplicatedpos - 1);
            }

            List <List <Point> > tempregions = new List <List <Point> >(regions);

            regions.Clear();

            bool connected = true;

            //Connects region if possible
            while (connected)
            {
                connected = false;
                foreach (var region in tempregions)
                {
                    int   connectionpos    = -1;
                    int   connectionregion = -1;
                    Point pointstart       = region.First();
                    Point pointend         = region.Last();
                    for (int ir = 0; ir < regions.Count; ir++)
                    {
                        var otherregion = regions[ir];
                        if (region == otherregion)
                        {
                            continue;
                        }

                        for (int ip = 0; ip < otherregion.Count; ip++)
                        {
                            var p = otherregion[ip];
                            if ((isConnected(pointstart, p) && isConnected(pointend, p)) ||
                                (isConnected(pointstart, p) && isConnected(pointstart, p)))
                            {
                                connectionregion = ir;
                                connectionpos    = ip;
                            }

                            if ((isConnected(pointend, p) && isConnected(pointend, p)))
                            {
                                region.Reverse();
                                connectionregion = ir;
                                connectionpos    = ip;
                            }
                        }
                    }

                    if (connectionpos == -1)
                    {
                        regions.Add(region);
                    }
                    else
                    {
                        regions[connectionregion].InsertRange(connectionpos, region);
                    }
                }

                tempregions = new List <List <Point> >(regions);
                regions.Clear();
            }

            List <Point[]> returnregions = new List <Point[]>();

            foreach (var region in tempregions)
            {
                returnregions.Add(region.ToArray());
            }

            return(returnregions);
        }