/// <summary> /// Color filtering in HSL color space. /// </summary> public static unsafe Bitmap HSLFilter(Bitmap image, Rectangle rect, IntRange hue, DoubleRange sat, DoubleRange lum) { Bitmap dest = new Bitmap(image.Width, image.Height, PixelFormat.Format8bppIndexed); BitmapData source = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat); BitmapData destination = dest.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, dest.PixelFormat); int startX = rect.Left; int startY = rect.Top; int stopX = rect.Right; int stopY = rect.Bottom; // get pixel size int pixelSize = (image.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int srcOffset = source.Stride - rect.Width * pixelSize; int dstOffset = destination.Stride - rect.Width; RGB rgb = new RGB(); HSL hsl = new HSL(); // do the job byte *src = (byte *)source.Scan0 + startY * source.Stride + startX * pixelSize; byte *dst = (byte *)destination.Scan0 + startY * destination.Stride + startX; // for each row for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src += pixelSize, dst++) { rgb.Red = src[RGB.R]; rgb.Green = src[RGB.G]; rgb.Blue = src[RGB.B]; // convert to HSL HSL.FromRGB(rgb, hsl); // check HSL values if (hue.IsInside(hsl.Hue) && sat.IsInside(hsl.Saturation) && lum.IsInside(hsl.Luminance)) { *dst = 0; } else { *dst = 255; } } src += srcOffset; dst += dstOffset; } int width = image.Width; int height = image.Height; int stride = destination.Stride; // remove upper part for (int y = 0; y < startY; y++) { dst = (byte *)destination.Scan0.ToPointer() + y * stride; SystemTools.SetUnmanagedMemory(dst, 255, stride); } // remove lower part for (int y = stopY; y < height; y++) { dst = (byte *)destination.Scan0.ToPointer() + y * stride; SystemTools.SetUnmanagedMemory(dst, 255, stride); } for (int y = startY; y < stopY; y++) { // remove left part dst = (byte *)destination.Scan0.ToPointer() + y * stride; SystemTools.SetUnmanagedMemory(dst, 255, startX); // remove right part dst += stopX; SystemTools.SetUnmanagedMemory(dst, 255, stride - stopX); } image.UnlockBits(source); dest.UnlockBits(destination); return(dest); }
/// <summary> /// Adjust hue saturation lightness of image /// </summary> public static unsafe Bitmap AdjustHSL(Bitmap image, Rectangle rect, int hue, int saturation, int lightness) { int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8; Bitmap dest = (Bitmap)image.Clone(); BitmapData imgDat = dest.LockBits(rect, ImageLockMode.ReadWrite, dest.PixelFormat); int startX = rect.Left; int startY = rect.Top; int stopX = startX + rect.Width; int stopY = startY + rect.Height; int offset = imgDat.Stride - rect.Width * pixelSize; RGB rgb = new RGB(); HSL hsl = new HSL(); // do the job byte *img = (byte *)imgDat.Scan0; // align pointer to the first pixel to process img += (startY * imgDat.Stride + startX * pixelSize); int intensity; int a, invA; RGB blendColor; if (lightness > 0) { a = (int)((lightness * 255) / 100); blendColor = new RGB(255, 255, 255); } else { a = (int)((-lightness * 255) / 100); blendColor = new RGB(0, 0, 0); } invA = 255 - a; if (lightness == 0) { // for each row for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, img += pixelSize) { // adjust saturation intensity = (int)((7471 * img[RGB.B] + 38470 * img[RGB.G] + 19595 * img[RGB.R]) >> 16); rgb.Red = ClampToByte((intensity * 1024 + (img[RGB.R] - intensity) * saturation) >> 10); rgb.Green = ClampToByte((intensity * 1024 + (img[RGB.G] - intensity) * saturation) >> 10); rgb.Blue = ClampToByte((intensity * 1024 + (img[RGB.B] - intensity) * saturation) >> 10); // adjust hue hsl = HSL.FromRGB(rgb); hsl.Hue += hue; if (hsl.Hue < 0) { hsl.Hue += 360; } else if (hsl.Hue > 360) { hsl.Hue -= 360; } rgb = hsl.ToRGB(); img[RGB.R] = rgb.Red; img[RGB.G] = rgb.Green; img[RGB.B] = rgb.Blue; } img += offset; } } else { // for each row for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, img += pixelSize) { // adjust saturation intensity = (int)((7471 * img[RGB.B] + 38470 * img[RGB.G] + 19595 * img[RGB.R]) >> 16); rgb.Red = ClampToByte((intensity * 1024 + (img[RGB.R] - intensity) * saturation) >> 10); rgb.Green = ClampToByte((intensity * 1024 + (img[RGB.G] - intensity) * saturation) >> 10); rgb.Blue = ClampToByte((intensity * 1024 + (img[RGB.B] - intensity) * saturation) >> 10); // adjust hue hsl = HSL.FromRGB(rgb); hsl.Hue += hue; if (hsl.Hue < 0) { hsl.Hue += 360; } else if (hsl.Hue > 360) { hsl.Hue -= 360; } rgb = hsl.ToRGB(); // adjust lightness img[RGB.R] = (byte)(((rgb.Red * invA) + (blendColor.Red * a)) / 256); img[RGB.G] = (byte)(((rgb.Green * invA) + (blendColor.Green * a)) / 256); img[RGB.B] = (byte)(((rgb.Blue * invA) + (blendColor.Blue * a)) / 256); } img += offset; } } dest.UnlockBits(imgDat); return(dest); }