/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// <param name="destinationData">Destination image data.</param> /// /// <exception cref="InvalidImagePropertiesException">Texture size does not match image size.</exception> /// <exception cref="ApplicationException">Filters should not change image dimension.</exception> /// protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData) { // get source image dimension int width = sourceData.Width; int height = sourceData.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 InvalidImagePropertiesException("Texture size does not match image size."); } } // apply first filter UnmanagedImage filteredImage1 = filter1.Apply(sourceData); // check size of the result image if ((width != filteredImage1.Width) || (height != filteredImage1.Height)) { filteredImage1.Dispose( ); throw new ApplicationException("Filters should not change image dimension."); } // convert 1st image to RGB if required if (filteredImage1.PixelFormat == PixelFormat.Format8bppIndexed) { GrayscaleToRGB coloringFilter = new GrayscaleToRGB( ); UnmanagedImage temp = coloringFilter.Apply(filteredImage1); filteredImage1.Dispose( ); filteredImage1 = temp; } UnmanagedImage filteredImage2 = null; // apply second filter, if it was specified if (filter2 != null) { filteredImage2 = filter2.Apply(sourceData); // check size of the result image if ((width != filteredImage2.Width) || (height != filteredImage2.Height)) { filteredImage1.Dispose( ); filteredImage2.Dispose( ); // we are not handling such situations yet throw new ApplicationException("Filters should not change image dimension."); } // convert 2nd image to RGB if required if (filteredImage2.PixelFormat == PixelFormat.Format8bppIndexed) { GrayscaleToRGB coloringFilter = new GrayscaleToRGB( ); UnmanagedImage temp = coloringFilter.Apply(filteredImage2); filteredImage2.Dispose( ); filteredImage2 = temp; } } // use source image as a second image, if second filter is not set if (filteredImage2 == null) { filteredImage2 = sourceData; } // do the job unsafe { byte *dst = (byte *)destinationData.ImageData.ToPointer( ); byte *src1 = (byte *)filteredImage1.ImageData.ToPointer( ); byte *src2 = (byte *)filteredImage2.ImageData.ToPointer( ); int dstOffset = destinationData.Stride - 3 * width; int src1Offset = filteredImage1.Stride - 3 * width; int src2Offset = filteredImage2.Stride - 3 * width; 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 t1 = texture[y, x]; double t2 = 1 - t1; for (int i = 0; i < 3; i++, src1++, src2++, dst++) { *dst = (byte)Math.Min(255.0f, filterLevel * (t1 * (*src1) + t2 * (*src2)) + preserveLevel * (*src2)); } } src1 += src1Offset; src2 += src2Offset; dst += dstOffset; } } 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 < 3; i++, src1++, src2++, dst++) { *dst = (byte)Math.Min(255.0f, t1 * *src1 + t2 * *src2); } } src1 += src1Offset; src2 += src2Offset; dst += dstOffset; } } } // dispose temp images filteredImage1.Dispose( ); if (filteredImage2 != sourceData) { filteredImage2.Dispose( ); } }