/// <summary> /// Apply filter to an image /// </summary> /// /// <param name="imageData">Source image to apply filter to</param> /// /// <returns>Returns filter's result obtained by applying the filter to /// the source image</returns> /// /// <remarks>The filter accepts birmap data as input and returns the result /// of image processing filter as new image. The source image data are kept /// unchanged.</remarks> /// public Bitmap Apply(BitmapData imageData) { // get mask dimension int width = mask.Width; int height = mask.Height; // check source image size if ((width != imageData.Width) || (height != imageData.Height)) { // sorry, but source image must have the same dimension as mask image throw new ArgumentException("Source image has wrong dimension (does not equal to mask dimension"); } // apply first filter Bitmap dstImg1 = filter1.Apply(imageData); // check dimension of the result image if ((width != dstImg1.Width) || (height != dstImg1.Height)) { dstImg1.Dispose( ); // we are not handling such situations yet throw new ApplicationException("Filters should not change image dimension"); } Bitmap dstImg2 = null; // apply second filter, if it was specified if (filter2 != null) { dstImg2 = filter2.Apply(imageData); // check dimension of the result image if ((width != dstImg2.Width) || (height != dstImg2.Height)) { dstImg1.Dispose( ); dstImg2.Dispose( ); // we are not handling such situations yet throw new ApplicationException("Filters should not change image dimension"); } } // lock second image or get source instead of it BitmapData dstData2 = (dstImg2 == null) ? imageData : dstImg2.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, (dstImg2.PixelFormat == PixelFormat.Format8bppIndexed) ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb); // check pixel formats if (dstImg1.PixelFormat != dstData2.PixelFormat) { IFilter f = new GrayscaleToRGB( ); // convert 1st image to RGB format if (dstImg1.PixelFormat == PixelFormat.Format8bppIndexed) { Bitmap t = f.Apply(dstImg1); dstImg1.Dispose( ); dstImg1 = t; } // convert 2nd image to RGB format if (dstData2.PixelFormat == PixelFormat.Format8bppIndexed) { Bitmap t = f.Apply(dstData2); // dispose temporary image if (dstImg2 != null) { dstImg2.UnlockBits(dstData2); dstImg2.Dispose( ); } dstImg2 = t; // lock second image again dstData2 = dstImg2.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); } } // lock 1st image - result image BitmapData dstData1 = dstImg1.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, dstImg1.PixelFormat); // lock mask bitmap data BitmapData maskData = mask.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, mask.PixelFormat); int pixelSize = (dstImg1.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int offset = dstData1.Stride - width * pixelSize; int maskInc = (mask.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int maskOffset = maskData.Stride - width * maskInc; // do the job unsafe { byte *dst = (byte *)dstData1.Scan0.ToPointer( ); byte *src = (byte *)dstData2.Scan0.ToPointer( ); byte *m = (byte *)maskData.Scan0.ToPointer( ); // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, m += maskInc) { if (*m != 0) { for (int i = 0; i < pixelSize; i++, src++, dst++) { *dst = *src; } } else { src += pixelSize; dst += pixelSize; } } src += offset; dst += offset; m += maskOffset; } } // unlock 1st image and mask dstImg1.UnlockBits(dstData1); mask.UnlockBits(maskData); // dispose 2nd image if (dstImg2 != null) { dstImg2.UnlockBits(dstData2); dstImg2.Dispose( ); } // return result image return(dstImg1); }
/// <summary> /// Apply filter to an image /// </summary> /// /// <param name="imageData">Source image to apply filter to</param> /// /// <returns>Returns filter's result obtained by applying the filter to /// the source image</returns> /// /// <remarks>The filter accepts birmap data as input and returns the result /// of image processing filter as new image. The source image data are kept /// unchanged.</remarks> /// public Bitmap Apply(BitmapData imageData) { // get source image dimension int width = imageData.Width; int height = imageData.Height; // if generator was specified, then generate a texture // otherwise use provided texture if (textureGenerator != null) { texture = textureGenerator.Generate(width, height); } else { // check existing texture if ((texture.GetLength(0) != height) || (texture.GetLength(1) != width)) { // sorry, but source image must have the same dimension as texture throw new ArgumentException("Texture size does not match image size"); } } // apply first filter Bitmap dstImg1 = filter1.Apply(imageData); // check dimension of the result image if ((width != dstImg1.Width) || (height != dstImg1.Height)) { dstImg1.Dispose( ); // we are not handling such situations yet throw new ApplicationException("Filters should not change image dimension"); } Bitmap dstImg2 = null; // apply second filter, if it was specified if (filter2 != null) { dstImg2 = filter2.Apply(imageData); // check dimension of the result image if ((width != dstImg2.Width) || (height != dstImg2.Height)) { dstImg1.Dispose( ); dstImg2.Dispose( ); // we are not handling such situations yet throw new ApplicationException("Filters should not change image dimension"); } } // lock second image or get source instead of it BitmapData dstData2 = (dstImg2 == null) ? imageData : dstImg2.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, (dstImg2.PixelFormat == PixelFormat.Format8bppIndexed) ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb); // check pixel formats if (dstImg1.PixelFormat != dstData2.PixelFormat) { IFilter f = new GrayscaleToRGB( ); // convert 1st image to RGB format if (dstImg1.PixelFormat == PixelFormat.Format8bppIndexed) { Bitmap t = f.Apply(dstImg1); dstImg1.Dispose( ); dstImg1 = t; } // convert 2nd image to RGB format if (dstData2.PixelFormat == PixelFormat.Format8bppIndexed) { Bitmap t = f.Apply(dstData2); // dispose temporary image if (dstImg2 != null) { dstImg2.UnlockBits(dstData2); dstImg2.Dispose( ); } dstImg2 = t; // lock second image again dstData2 = dstImg2.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); } } // lock 1st image - result image BitmapData dstData1 = dstImg1.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, dstImg1.PixelFormat); int pixelSize = (dstData1.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int offset = dstData1.Stride - width * pixelSize; // do the job unsafe { byte *dst = (byte *)dstData1.Scan0.ToPointer( ); byte *src = (byte *)dstData2.Scan0.ToPointer( ); if (preserveLevel != 0.0) { // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++) { double t = texture[y, x]; for (int i = 0; i < pixelSize; i++, src++, dst++) { *dst = (byte)Math.Min(255.0f, (preserveLevel * *src) + (filterLevel * *dst) * t); } } src += offset; dst += offset; } } else { // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++) { double t1 = texture[y, x]; double t2 = 1 - t1; for (int i = 0; i < pixelSize; i++, src++, dst++) { *dst = (byte)Math.Min(255.0f, t1 * *dst + t2 * *src); } } src += offset; dst += offset; } } } // unlock 1st image and mask dstImg1.UnlockBits(dstData1); // dispose 2nd image if (dstImg2 != null) { dstImg2.UnlockBits(dstData2); dstImg2.Dispose( ); } // return result image return(dstImg1); }