/// <summary>Removes and returns the <see cref="FloodFillRange"/> at the beginning of the queue.</summary> public FloodFillRange Dequeue() { FloodFillRange range = new FloodFillRange(); if (size > 0) { range = array[head]; array[head] = new FloodFillRange(); head++; //advance head position size--; //update size to exclude dequeued item } return(range); }
private void DoFloodFill(Point pt) { ranges = new FloodFillRangeQueue(((bitmapWidth + bitmapHeight) / 2) * 5);//new Queue<FloodFillRange>(); //***Get starting color. int x = pt.X; int y = pt.Y; int idx = CoordsToByteIndex(ref x, ref y); startColor = new byte[] { bitmap.Bits[idx], bitmap.Bits[idx + 1], bitmap.Bits[idx + 2] }; bool[] pixelsChecked = this.pixelsChecked; //***Do first call to floodfill. LinearFill(ref x, ref y); //***Call floodfill routine while floodfill ranges still exist on the queue while (ranges.Count > 0) { //**Get Next Range Off the Queue FloodFillRange range = ranges.Dequeue(); //**Check Above and Below Each Pixel in the Floodfill Range int downPxIdx = (bitmapWidth * (range.Y + 1)) + range.StartX; //CoordsToPixelIndex(lFillLoc,y+1); int upPxIdx = (bitmapWidth * (range.Y - 1)) + range.StartX; //CoordsToPixelIndex(lFillLoc, y - 1); int upY = range.Y - 1; //so we can pass the y coord by ref int downY = range.Y + 1; int tempIdx; for (int i = range.StartX; i <= range.EndX; i++) { //*Start Fill Upwards //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance tempIdx = CoordsToByteIndex(ref i, ref upY); if (range.Y > 0 && (!pixelsChecked[upPxIdx]) && CheckPixel(ref tempIdx)) { LinearFill(ref i, ref upY); } //*Start Fill Downwards //if we're not below the bottom of the bitmap and the pixel below this one is within the color tolerance tempIdx = CoordsToByteIndex(ref i, ref downY); if (range.Y < (bitmapHeight - 1) && (!pixelsChecked[downPxIdx]) && CheckPixel(ref tempIdx)) { LinearFill(ref i, ref downY); } downPxIdx++; upPxIdx++; } } }
/// <summary> /// Finds the furthermost left and right boundaries of the fill area /// on a given y coordinate, starting from a given x coordinate, filling as it goes. /// Adds the resulting horizontal range to the queue of floodfill ranges, /// to be processed in the main loop. /// </summary> /// <param name="x">The x coordinate to start from.</param> /// <param name="y">The y coordinate to check at.</param> private void LinearFill(ref int x, ref int y) { //cache some bitmap and fill info in local variables for a little extra speed byte[] bitmapBits = this.bitmapBits; bool[] pixelsChecked = this.pixelsChecked; byte[] byteFillColor = this.byteFillColor; int bitmapPixelFormatSize = this.bitmapPixelFormatSize; int bitmapWidth = this.bitmapWidth; //***Find Left Edge of Color Area int lFillLoc = x; //the location to check/fill on the left int idx = CoordsToByteIndex(ref x, ref y); //the byte index of the current location int pxIdx = (bitmapWidth * y) + x; //CoordsToPixelIndex(x,y); while (true) { //**fill with the color //bitmapBits[idx] = byteFillColor[0]; //bitmapBits[idx + 1] = byteFillColor[1]; //bitmapBits[idx + 2] = byteFillColor[2]; // fill the color with alpha blend bitmapBits[idx] = (byte)BlendColor(byteFillColor[0], byteFillColor[3], bitmapBits[idx], bitmapBits[idx + 3]); bitmapBits[idx + 1] = (byte)BlendColor(byteFillColor[1], byteFillColor[3], bitmapBits[idx + 1], bitmapBits[idx + 3]); bitmapBits[idx + 2] = (byte)BlendColor(byteFillColor[2], byteFillColor[3], bitmapBits[idx + 2], bitmapBits[idx + 3]); bitmapBits[idx + 3] = (byte)BlendAlpha(byteFillColor[3], bitmapBits[idx + 3]); //**indicate that this pixel has already been checked and filled pixelsChecked[pxIdx] = true; //**de-increment lFillLoc--; //de-increment counter pxIdx--; //de-increment pixel index idx -= bitmapPixelFormatSize; //de-increment byte index //**exit loop if we're at edge of bitmap or color area // if (lFillLoc <= 0 || (pixelsChecked[pxIdx]) || !CheckPixel(ref idx)) if (lFillLoc <= 0 || (pixelsChecked[pxIdx]) || !CheckPixel(ref idx)) { break; } } lFillLoc++; //***Find Right Edge of Color Area int rFillLoc = x; //the location to check/fill on the left idx = CoordsToByteIndex(ref x, ref y); pxIdx = (bitmapWidth * y) + x; while (true) { //fill with the color //bitmapBits[idx] = byteFillColor[0]; //bitmapBits[idx + 1] = byteFillColor[1]; //bitmapBits[idx + 2] = byteFillColor[2]; // fill the color with alpha blend bitmapBits[idx] = (byte)BlendColor(byteFillColor[0], byteFillColor[3], bitmapBits[idx], bitmapBits[idx + 3]); bitmapBits[idx + 1] = (byte)BlendColor(byteFillColor[1], byteFillColor[3], bitmapBits[idx + 1], bitmapBits[idx + 3]); bitmapBits[idx + 2] = (byte)BlendColor(byteFillColor[2], byteFillColor[3], bitmapBits[idx + 2], bitmapBits[idx + 3]); bitmapBits[idx + 3] = (byte)BlendAlpha(byteFillColor[3], bitmapBits[idx + 3]); //**indicate that this pixel has already been checked and filled pixelsChecked[pxIdx] = true; //**increment rFillLoc++; //increment counter pxIdx++; //increment pixel index idx += bitmapPixelFormatSize; //increment byte index //**exit loop if we're at edge of bitmap or color area if (rFillLoc >= bitmapWidth || pixelsChecked[pxIdx] || !CheckPixel(ref idx)) { break; } } rFillLoc--; //add range to queue FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y); ranges.Enqueue(ref r); }