25/5/2011, 16:57
Đây là code tô màu bằng stack, tình hình là mình chưa hiểu lắm nên chưa áp dụng vào bài tập lớn được, nhóm nào áp dụng được thì bảo mình với nhé.
- Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
namespace Paint
{
/// <summary>
/// Fills a bitmap using a non-recursive flood-fill.
/// </summary>
public class MapFill
{
public MapFill()
{
}
static Stack stack = new Stack();
/// <summary>
/// Checks to make sure a pixel is in an image.
/// </summary>
/// <param name="pos">The position to check</param>
/// <param name="bmd">The BitmapData from which the bounds are determined
/// </param>
/// <returns>True if the point is in the image</returns>
private static bool CheckPixel(Point pos, BitmapData bmd)
{
return (pos.X > -1) && (pos.Y > -1) && (pos.X < bmd.Width) && (pos.Y < bmd.Height);
}
/// <summary>
/// Returns the color at a specific pixel
/// </summary>
/// <param name="pos">The position of the pixel</param>
/// <param name="bmd">The locked bitmap data</param>
/// <returns>The color of the pixel under the nominated point</returns>
private static Color GetPixel(Point pos, BitmapData bmd)
{
if (CheckPixel(pos, bmd))
{
//always assumes 32 bit per pixels
int offset = pos.Y * bmd.Stride + (4 * pos.X);
return Color.FromArgb(
Marshal.ReadByte(bmd.Scan0, offset + 2),
Marshal.ReadByte(bmd.Scan0, offset + 1),
Marshal.ReadByte(bmd.Scan0, offset));
}
else
return Color.FromArgb(0, 0, 0, 0);
}
/// <summary>
/// Sets a pixel at a nominated point to a specified color
/// </summary>
/// <param name="pos">The coordinate of the pixel to set</param>
/// <param name="bmd">The locked bitmap data</param>
/// <param name="c">The color to set</param>
private static void SetPixel(Point pos, BitmapData bmd, Color c)
{
if (CheckPixel(pos, bmd))
{
//always assumes 32 bit per pixels
int offset = pos.Y * bmd.Stride + (4 * pos.X);
Marshal.WriteByte(bmd.Scan0, offset + 2, c.R);
Marshal.WriteByte(bmd.Scan0, offset + 1, c.G);
Marshal.WriteByte(bmd.Scan0, offset, c.B);
Marshal.WriteByte(bmd.Scan0, offset + 3, 255);
}
}
/// <summary>
/// Fills a pixel and its un-filled neigbors with a specified color
/// </summary>
/// <param name="pos">The position at which to begin</param>
/// <param name="bmd">The locked bitmap data</param>
/// <param name="c">The color with which to fill the area</param>
/// <param name="org">The original colour of the point. Filling stops when all connected pixels of this color are exhausted</param>
private static void FillPixel(Point pos, BitmapData bmd, Color c, Color org)
{
if (c.ToArgb() == org.ToArgb())
return;
Point currpos = new Point(0, 0);
stack.Push(pos);
do
{
currpos = (Point)stack.Pop();
SetPixel(currpos, bmd, c);
if (GetPixel(new Point(currpos.X + 1, currpos.Y), bmd) == org)
stack.Push(new Point(currpos.X + 1, currpos.Y));
if (GetPixel(new Point(currpos.X, currpos.Y - 1), bmd) == org)
stack.Push(new Point(currpos.X, currpos.Y - 1));
if (GetPixel(new Point(currpos.X - 1, currpos.Y), bmd) == org)
stack.Push(new Point(currpos.X - 1, currpos.Y));
if (GetPixel(new Point(currpos.X, currpos.Y + 1), bmd) == org)
stack.Push(new Point(currpos.X, currpos.Y + 1));
} while (stack.Count > 0);
}
/// <summary>
/// Fills a bitmap with color.
/// </summary>
/// <remarks>If a non 32-bit image is passed to this routine and only 32 bit image will be created, the original image will be copied to the new image and filling will take place on the new image which will be handed back when complete. </remarks>
/// <param name="img">The image to fill</param>
/// <param name="pos">The position to begin filling at</param>
/// <param name="color">The color to fill</param>
/// <returns>A Bitmap object with the filled area.</returns>
public Bitmap Fill(Image img, Point pos, Color color)
{
//Ensure the bitmap is in the right format
Bitmap bm = (Bitmap)img;
if (img.PixelFormat != PixelFormat.Format32bppArgb)
{
//if it isn't, convert it.
bm = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bm);
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(img, new
Rectangle(0, 0, bm.Width, bm.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
g.Dispose();
}
//Lock the bitmap data
BitmapData bmd = bm.LockBits(new
Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadWrite, bm.PixelFormat);
//get the color under the point. This is the original.
Color org = GetPixel(pos, bmd);
//Fill the first pixel and recursively fill all it's neighbors
FillPixel(pos, bmd, color, org);
//unlock the bitmap
bm.UnlockBits(bmd);
return bm;
}
}
}