Слоистые эффекты (размытие и т. Д.) В WinForms - PullRequest
3 голосов
/ 30 августа 2010

В WinForms я ищу способ достижения функциональности, аналогичной функциональности класса JXLayer в Java Swing.Чтобы быть более конкретным.Я хотел бы размыть все содержимое окна и закрасить его чем-нибудь (например, кружком ожидания).Любые идеи будут высоко оценены:)

Ответы [ 5 ]

9 голосов
/ 30 августа 2010

А вот и мое решение.

  1. Сделайте скриншот.
  2. Размытие.
  3. Поместите размытое изображение перед всем.

При заданной форме с кнопкой Button1 и панелью панели 1 (со списком и индикатором на нем), следующий код работает довольно хорошо:

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; 
        }            
    }
}

alt textalt text Код для размытия по Гауссу заимствован из здесь .

1 голос
/ 30 августа 2010

Этот код VB.Net будет

  1. Создать изображение формы,
  2. Добавить размытие к изображению
  3. Добавить изображение в поле для картинок
  4. Добавьте обработчик кликов, который удаляет картинку при нажатии.
  5. Добавьте коробку с картинками в форму и установите в качестве заносить

Единственное, что размытие довольно медленное.Так что я бы работал над этим.

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

alt text

Я нашел код для создания GasuianBlur здесь: http://www.codeproject.com/KB/GDI-plus/GausianBlur.aspx

И код для копированияФорма для растрового изображения здесь: http://www.daniweb.com/forums/thread94348.html

0 голосов
/ 21 июня 2016
   Imports System.Drawing
   Imports System.Drawing.Imaging
   Public Class Form1
    #Region "Declarations"
   Dim imagebitmap As Bitmap
   Dim graphicsvariable As Graphics
   Dim WithEvents v As New PictureBox
   Dim panel1 As Panel

  #End Region

  #Region "function for getting screenshot"
     Public Function getscreenshot()
      imagebitmap = New Bitmap(Me.Size.Width, Me.Size.Height) 'creates a new blank bitmap having size of the form'
       graphicsvariable = Graphics.FromImage(imagebitmap)      'creates a      picture template that enables the graphics variable to draw on'
                graphicsvariable.CopyFromScreen(Me.PointToScreen(Me.ClientRectangle.Location), New Point(0, 0), Me.ClientRectangle.Size)    'copies graphics that is on the screen to the imagebitmap'
        Return imagebitmap
       End Function
     #End Region

#Region "method for blurring"
Sub BlurBitmap(ByRef image As Bitmap, Optional ByVal BlurForce As Integer = 2)
    'We get a graphics object from the image'
      Dim g As Graphics = Graphics.FromImage(image)
    'declare an ImageAttributes to use it when drawing'
      Dim att As New ImageAttributes
    'declare a ColorMatrix'
      Dim m As New ColorMatrix
    ' set Matrix33 to 0.5, which represents the opacity. so the drawing will be semi-trasparent.'
      m.Matrix33 = 0.4
    'Setting this ColorMatrix to the ImageAttributes.'
      att.SetColorMatrix(m)
    'drawing the image on it self, but not in the same coordinates, in a way that every pixel will be drawn on the pixels arround it.'
      For x = -1 To BlurForce
          For y = -1 To BlurForce
            'Drawing image on it self using out ImageAttributes to draw it semi-transparent.'
              g.DrawImage(image, New Rectangle(x, y, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, att)
          Next
      Next
    'disposing ImageAttributes and Graphics. the effect is then applied. '
      att.Dispose() 'dispose att'
      g.Dispose() 'dispose g'
    End Sub
  #End Region

 #Region "event that handles the removal of the blurred image when clicked"
    Private Sub v_Click(sender As Object, e As EventArgs) Handles v.Click
    Panel1.Controls.Remove(sender) 'removes the picturebox from the panel'
     Me.Controls.Remove(Panel1)    'removes the panel from the form'
  End Sub
#End Region


   Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
      panel1 = New Panel
      panel1.Size = New Size(763, 441)
      Me.Controls.Add(panel1)

     panel1.Controls.Add(v)  'add picturebox to panel1, pls also note that i made the panel cover the whole form'
     Dim b As Bitmap = getscreenshot() 'get the screen shot'
     BlurBitmap(b) 'blur the screen shot'
     v.Image = b 'set the picturebox image as b (the blurred image)'
     v.Dock = DockStyle.Fill
     v.BringToFront()
     v.Size = Me.Size
     panel1.BringToFront()
    End Sub
End Class
0 голосов
/ 30 августа 2010

Я не уверен насчет размытия, но одну вещь, которую вы можете сделать, - это иметь полупрозрачный элемент управления спереди.

Если вы действительно хотите использовать его перед окном whole (включая строку заголовка и т. д.), это означает полупрозрачную форму , размещенную и измеренную непосредственно вокруг вашей основной формы.Это должно быть модально (ShowDialog()), потому что в противном случае пользователь может «потерять» одну форму за другой ...

Конечно, это создает проблемы, если вы пытаетесь одновременно что-то сделать в окнепозади (как следует из вашего вопроса), потому что ShowDialog блокирует вызывающий код ...

В этом случае вы можете установить форму 'TopMost' - это ужасно глупо, потому что это можетне позволяйте пользователю взаимодействовать с другим приложением, на которое он нажимает во время ожидания вашего приложения, и которое, как оказалось, находится под вашей формой ожидания.Я не знаю лучшего решения с ванильными винами.Возможно, вы можете что-то сделать с окнами более низкого уровня, но я мало что знаю об этом.

0 голосов
/ 30 августа 2010

Я сделал это однажды с модальной формой, расположенной и имеющей размер точно такой же, как была у размытой формы. И затем иметь непрозрачность до 50% в этой форме.

Подтверждение концепции (создайте форму и вставьте в нее кнопку1, вставьте этот код):

Public Class Form1
Private BlurrForm As New Form
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    BlurrForm.StartPosition = FormStartPosition.Manual
    BlurrForm.Opacity = 0.5
    BlurrForm.Location = Me.Location
    BlurrForm.Size = Me.Size
    BlurrForm.Owner = Me
    BlurrForm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
    AddHandler BlurrForm.Click, AddressOf BlurredFormClicked
    BlurrForm.Show(Me)
End Sub
Sub BlurredFormClicked(ByVal sender As System.Object, ByVal e As EventArgs)
    BlurrForm.Hide()
End Sub

End Class

Когда вы нажимаете кнопку1, вся форма становится серой и исчезает при нажатии кнопки мыши.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...