In WinForms, I’m looking for a way to achieve the functionality similar to that of JXLayer class in Java’s Swing. To be more specific. I’d like to blur entire content of a window, and paint something over it (a waiting circle, for example). Any ideas will be highly appreciated :)
And here is my solution.
Given a form with Button button1 and Panel panel1 (with listbox and progress bar on it), the following code works pretty well:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
namespace Blur
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = Screenshot.TakeSnapshot(panel1);
BitmapFilter.GaussianBlur(bmp, 4);
PictureBox pb = new PictureBox();
panel1.Controls.Add(pb);
pb.Image = bmp;
pb.Dock = DockStyle.Fill;
pb.BringToFront();
}
}
public class ConvMatrix
{
public int TopLeft = 0, TopMid = 0, TopRight = 0;
public int MidLeft = 0, Pixel = 1, MidRight = 0;
public int BottomLeft = 0, BottomMid = 0, BottomRight = 0;
public int Factor = 1;
public int Offset = 0;
public void SetAll(int nVal)
{
TopLeft = TopMid = TopRight = MidLeft = Pixel = MidRight = BottomLeft = BottomMid = BottomRight = nVal;
}
}
public class BitmapFilter
{
private static bool Conv3x3(Bitmap b, ConvMatrix m)
{
// Avoid divide by zero errors
if (0 == m.Factor) return false;
Bitmap bSrc = (Bitmap)b.Clone();
// GDI+ still lies to us - the return format is BGR, NOT RGB.
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
int stride2 = stride * 2;
System.IntPtr Scan0 = bmData.Scan0;
System.IntPtr SrcScan0 = bmSrc.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
byte* pSrc = (byte*)(void*)SrcScan0;
int nOffset = stride + 6 - b.Width * 3;
int nWidth = b.Width - 2;
int nHeight = b.Height - 2;
int nPixel;
for (int y = 0; y < nHeight; ++y)
{
for (int x = 0; x < nWidth; ++x)
{
nPixel = ((((pSrc[2] * m.TopLeft) + (pSrc[5] * m.TopMid) + (pSrc[8] * m.TopRight) +
(pSrc[2 + stride] * m.MidLeft) + (pSrc[5 + stride] * m.Pixel) + (pSrc[8 + stride] * m.MidRight) +
(pSrc[2 + stride2] * m.BottomLeft) + (pSrc[5 + stride2] * m.BottomMid) + (pSrc[8 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0;
if (nPixel > 255) nPixel = 255;
p[5 + stride] = (byte)nPixel;
nPixel = ((((pSrc[1] * m.TopLeft) + (pSrc[4] * m.TopMid) + (pSrc[7] * m.TopRight) +
(pSrc[1 + stride] * m.MidLeft) + (pSrc[4 + stride] * m.Pixel) + (pSrc[7 + stride] * m.MidRight) +
(pSrc[1 + stride2] * m.BottomLeft) + (pSrc[4 + stride2] * m.BottomMid) + (pSrc[7 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0;
if (nPixel > 255) nPixel = 255;
p[4 + stride] = (byte)nPixel;
nPixel = ((((pSrc[0] * m.TopLeft) + (pSrc[3] * m.TopMid) + (pSrc[6] * m.TopRight) +
(pSrc[0 + stride] * m.MidLeft) + (pSrc[3 + stride] * m.Pixel) + (pSrc[6 + stride] * m.MidRight) +
(pSrc[0 + stride2] * m.BottomLeft) + (pSrc[3 + stride2] * m.BottomMid) + (pSrc[6 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0;
if (nPixel > 255) nPixel = 255;
p[3 + stride] = (byte)nPixel;
p += 3;
pSrc += 3;
}
p += nOffset;
pSrc += nOffset;
}
}
b.UnlockBits(bmData);
bSrc.UnlockBits(bmSrc);
return true;
}
public static bool GaussianBlur(Bitmap b, int nWeight /* default to 4*/)
{
ConvMatrix m = new ConvMatrix();
m.SetAll(1);
m.Pixel = nWeight;
m.TopMid = m.MidLeft = m.MidRight = m.BottomMid = 2;
m.Factor = nWeight + 12;
return BitmapFilter.Conv3x3(b, m);
}
}
class Screenshot
{
public static Bitmap TakeSnapshot(Control ctl)
{
Bitmap bmp = new Bitmap(ctl.Size.Width, ctl.Size.Height);
using (Graphics g = System.Drawing.Graphics.FromImage(bmp))
{
g.CopyFromScreen(
ctl.PointToScreen(ctl.ClientRectangle.Location),
new Point(0, 0), ctl.ClientRectangle.Size
);
}
return bmp;
}
}
}

Code for gaussian blurring is borrowed from here.
This VB.Net code will
The only thing is that the blur is pretty slow. So I would work on that.
Imports System.Drawing.Imaging
Public Class Form1
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
ShowBlurredPicture()
End Sub
Sub ShowBlurredPicture()
Dim blurredpic As Bitmap = gausianBlur(False, New Size(5, 5), GetFormPic)
Dim p As New PictureBox
p.Image = blurredpic
p.Location = New Point(-System.Windows.Forms.SystemInformation.FrameBorderSize.Width, -(System.Windows.Forms.SystemInformation.CaptionHeight + System.Windows.Forms.SystemInformation.FrameBorderSize.Height))
p.Size = New Size(Me.Size)
Me.Controls.Add(p)
p.Visible = True
p.BringToFront()
AddHandler p.Click, AddressOf picclick
End Sub
Sub picclick(ByVal sender As Object, ByVal e As System.EventArgs)
Me.Controls.Remove(sender)
End Sub
Function GetFormPic() As Bitmap
Dim ScreenSize As Size = Me.Size
Dim screenGrab As New Bitmap(Me.Width, Me.Height)
Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(screenGrab)
g.CopyFromScreen(Me.Location, New Point(0, 0), Me.Size)
Return screenGrab
End Function
Private Function Average(ByVal Size As Size, ByVal imageSize As SizeF, ByVal PixelX As Integer, ByVal Pixely As Integer, ByVal theimage As Bitmap) As Color
Dim pixels As New ArrayList
Dim x As Integer, y As Integer
Dim bmp As Bitmap = theimage.Clone
For x = PixelX - CInt(Size.Width / 2) To PixelX + CInt(Size.Width / 2)
For y = Pixely - CInt(Size.Height / 2) To Pixely + CInt(Size.Height / 2)
If (x > 0 And x < imageSize.Width) And (y > 0 And y < imageSize.Height) Then
pixels.Add(bmp.GetPixel(x, y))
End If
Next
Next
Dim thisColor As Color
Dim alpha As Integer = 0
Dim red As Integer = 0
Dim green As Integer = 0
Dim blue As Integer = 0
For Each thisColor In pixels
alpha += thisColor.A
red += thisColor.R
green += thisColor.G
blue += thisColor.B
Next
Return Color.FromArgb(alpha / pixels.Count, red / pixels.Count, green / pixels.Count, blue / pixels.Count)
End Function
Private Function gausianBlur(ByVal alphaEdgesOnly As Boolean, ByVal blurSize As Size, ByVal theimage As Bitmap) As Bitmap
Dim PixelY As Integer
Dim PixelX As Integer
Dim bmp As Bitmap = theimage.Clone
For PixelY = 0 To bmp.Width - 1
For PixelX = 0 To bmp.Height - 1
If Not alphaEdgesOnly Then ' Blur everything
bmp.SetPixel(PixelX, PixelY, Average(blurSize, bmp.PhysicalDimension, PixelX, PixelY, theimage))
ElseIf bmp.GetPixel(PixelX, PixelY).A <> 255 Then ' Alpha blur channel check
bmp.SetPixel(PixelX, PixelY, Average(blurSize, bmp.PhysicalDimension, PixelX, PixelY, theimage))
End If
Application.DoEvents()
Next
Next
Return bmp.Clone
bmp.Dispose()
End Function
End Class

I found the code to do the GasuianBlur here: http://www.codeproject.com/KB/GDI-plus/GausianBlur.aspx
And the code to Copy a form to a bitmap here: http://www.daniweb.com/forums/thread94348.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With