WPF创建位图的灰度图滤镜效果

当RGB三个值的分量为同一个值时,图像会显示成灰度的,这个灰度值可以通过一个公式得到:

gray=BYTE(0.299*red)+BYTE(0.587*green)+BYTE(0.114*blue);

WPF的ImageSource类提供对位图的创建功能,利用它的CopyPixels方法,可以复制位图任意矩形范围内的像素字节,再利用上面的公式进行灰度化。

    public class BitmapFilterCreater
    {
        public static BitmapSource GrayFilter(BitmapSource bitmapSource)
        {
            var width = bitmapSource.PixelWidth;
            var height = bitmapSource.PixelHeight;
            var pixelFormat = bitmapSource.Format;
            var stride = (width * pixelFormat.BitsPerPixel + 7) / 8;
            var pixels = new byte[stride * height];

            bitmapSource.CopyPixels(Int32Rect.Empty, pixels, stride, 0);

            //gray=BYTE(0.299*red)+BYTE(0.587*green)+BYTE(0.114*blue); 

            for (int i = 0; i < pixels.LongLength; i += 4)
            {
                var gray = (byte)(0.299 * pixels[i] + 0.587 * pixels[i + 1] + 0.114 * pixels[i + 2]);
                pixels[i] = gray;
                pixels[i + 1] = gray;
                pixels[i + 2] = gray;
            }

            var bitmap = BitmapSource.Create(width, height, bitmapSource.DpiX, bitmapSource.DpiY, pixelFormat, null,
                                             pixels, stride);
            return bitmap;
        }

    }

测试例子:

用VS创建一个WPF应用程序,然后MainWindow.xaml代码修改如下:

<Window x:Class="BitmapFilter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="创建灰度图演示 - 左击窗口选择位图,右击窗口保存位图" Height="350" Width="525" Loaded="MainWindow_OnLoaded" MouseDown="Window_MouseDown"> 
    <Grid>
        
    </Grid>
</Window>


MainWindow.xaml.cs代码修改如下:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace BitmapFilter
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
        {
            try
            {
                //窗口加载时将桌面壁纸转换为原始位深度的灰色位图
                var r = BitmapFilterCreater.GrayFilter(
                    new BitmapImage(new Uri(Utility.GetDesktopBackground())));
                this.Background = new ImageBrush(r);
            }
            catch (Exception ex)
            {
            }
        }

        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                //左击选择转换位图
                var dialog = new Microsoft.Win32.OpenFileDialog();
                dialog.Filter = "常用位图(*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png";
                if (true == dialog.ShowDialog())
                {
                    if (File.Exists(dialog.FileName))
                    {
                        try
                        {
                            //转换为8位灰色位图
                            var r = BitmapFilterCreater.GrayFilter8Bytes(
                                new BitmapImage(new Uri(dialog.FileName)));
                            this.Background = new ImageBrush(r);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                    }
                }
            }
            else if (e.RightButton == MouseButtonState.Pressed)
            {
                //右击保存窗口背景位图
                var dialog = new Microsoft.Win32.SaveFileDialog();
                dialog.Filter = "*.jpg|*.jpg|*.png|*.png|*.bmp|*.bmp";
                if (true == dialog.ShowDialog())
                {
                    try
                    {
                        Utility.Save((BitmapSource)(((ImageBrush)this.Background).ImageSource), dialog.FileName);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);                        
                    }
                }
            }
        }
    }


    public class Utility
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int SystemParametersInfo(int uAction, int uParam, StringBuilder lpvParam, int fuWinIni);
        public const int SPI_GETDESKWALLPAPER = 0x0073;

        /// <summary>
        /// 获得桌面壁纸
        /// </summary>
        /// <returns></returns>
        public static string GetDesktopBackground()
        {
            var sb = new StringBuilder(255);
            SystemParametersInfo(SPI_GETDESKWALLPAPER, sb.Capacity, sb, 0);
            return sb.ToString();
        }

        /// <summary>
        /// 保存位图
        /// </summary>
        /// <param name="bitmapSource"></param>
        /// <param name="path"></param>
        public static void Save(BitmapSource bitmapSource, string path)
        {
            using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                var extension = Path.GetExtension(path);
                BitmapEncoder encoder;
                if (".jpg".Equals(extension, StringComparison.OrdinalIgnoreCase))
                {
                    encoder = new JpegBitmapEncoder();
                }
                else if (".png".Equals(extension, StringComparison.OrdinalIgnoreCase))
                {
                    encoder = new PngBitmapEncoder();
                }
                else
                {
                    encoder = new BmpBitmapEncoder();

                }
                encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
                encoder.Save(fs);
            }
        }
    }

    public class BitmapFilterCreater
    {
        /// <summary>
        /// 生成灰色位图
        /// </summary>
        /// <param name="bitmapSource"></param>
        /// <returns></returns>
        public static BitmapSource GrayFilter(BitmapSource bitmapSource)
        {
            if (bitmapSource == null)
                return null;

            var width = bitmapSource.PixelWidth;
            var height = bitmapSource.PixelHeight;
            var pixelFormat = bitmapSource.Format;
            var bpp = pixelFormat.BitsPerPixel;

            if (bpp == 32 || bpp == 24)
            {
                var stride = (width * pixelFormat.BitsPerPixel + 7) / 8;
                var pixels = new byte[stride * height];

                bitmapSource.CopyPixels(Int32Rect.Empty, pixels, stride, 0);

                //gray=BYTE(0.299*red)+BYTE(0.587*green)+BYTE(0.114*blue);   

                for (int i = 0; i < pixels.LongLength; i += bpp / 8)
                {
                    var gray =
                        (byte)((byte)(0.299 * pixels[i]) + (byte)(0.587 * pixels[i + 1]) + (byte)(0.114 * pixels[i + 2]));
                    pixels[i] = gray;
                    pixels[i + 1] = gray;
                    pixels[i + 2] = gray;
                }

                var bitmap = BitmapSource.Create(width, height, bitmapSource.DpiX, bitmapSource.DpiY, pixelFormat, null,
                                                 pixels, stride);
                return bitmap;
            }

            return null;
        }

        /// <summary>
        /// 生成8位灰色位图
        /// </summary>
        /// <param name="bitmapSource"></param>
        /// <returns></returns>
        public static BitmapSource GrayFilter8Bytes(BitmapSource bitmapSource)
        {
            if(bitmapSource==null)
                return null;

            var width = bitmapSource.PixelWidth;
            var height = bitmapSource.PixelHeight;
            var pixelFormat = bitmapSource.Format;
            var bpp = pixelFormat.BitsPerPixel;

            if (bpp == 32 || bpp == 24)
            {
                var stride = (width * pixelFormat.BitsPerPixel + 7) / 8;
                var pixels = new byte[stride * height];

                bitmapSource.CopyPixels(Int32Rect.Empty, pixels, stride, 0);

                //gray=BYTE(0.299*red)+BYTE(0.587*green)+BYTE(0.114*blue); 
                var stride8Gray = (width * 8 + 7) / 8;
                var pixels8Gray = new byte[stride8Gray * height];
                for (int i = 0, j = 0; i < pixels.LongLength; i += bpp / 8, j++)
                {
                    var gray =
                        (byte)((byte)(0.299 * pixels[i]) + (byte)(0.587 * pixels[i + 1]) + (byte)(0.114 * pixels[i + 2]));
                    pixels8Gray[j] = gray;
                }
                var bitmap = BitmapSource.Create(width, height,
                    bitmapSource.DpiX, bitmapSource.DpiY,
                    PixelFormats.Gray8, null, //BitmapPalettes.Gray256,
                    pixels8Gray, stride8Gray);

                return bitmap;
            }

            return null;
        }
    }
}


编译运行程序。



另外,简单的格式转换,可以使用System.Windows.Media.Imaging.FormatConvertedBitmap这个类实现。

例子见:http://msdn.microsoft.com/zh-cn/library/system.windows.media.imaging.formatconvertedbitmap(v=VS.85).aspx

测试代码如下:

// csc /t:winexe /r:system.dll,system.xaml.dll,"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\WPF\windowsbase.dll","%WINDIR%\Microsoft.NET\Framework\v4.0.30319\WPF\presentationcore.dll","%WINDIR%\Microsoft.NET\Framework\v4.0.30319\WPF\presentationframework.dll" FormatGray8.cs
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

class Program
{
    [STAThread]
    public static void Main()
    {
        var window = new Window();
        window.MouseDown += (sender, e) =>
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                //左击选择转换位图  
                var dialog = new Microsoft.Win32.OpenFileDialog();
                dialog.Filter = "常用位图(*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png";
                if (true == dialog.ShowDialog())
                {
                    if (File.Exists(dialog.FileName))
                    {
                        try
                        {
                            window.Background = new ImageBrush(FormatGray8(new BitmapImage(new Uri(dialog.FileName))));
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                    }
                }
            }
            else if (e.RightButton == MouseButtonState.Pressed)
            {
                //右击保存窗口背景位图  
                var dialog = new Microsoft.Win32.SaveFileDialog();
                dialog.Filter = "*.jpg|*.jpg|*.png|*.png|*.bmp|*.bmp";
                if (true == dialog.ShowDialog())
                {
                    try
                    {
                        Utility.Save((BitmapSource)(((ImageBrush)window.Background).ImageSource), dialog.FileName);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
        };

        window.Loaded += (sender, e) =>
        {
            try
            {
                //窗口加载时将桌面壁纸转换为原始位深度的灰色位图
                var r = FormatGray8(new BitmapImage(new Uri(Utility.GetDesktopBackground())));
                window.Background = new ImageBrush(r);
            }
            catch
            {
            }
        };

        window.Title = "用FormatConvertedBitmap转换为8位灰度图,左击选择文件,右击保存位图";
        window.Show();
        var app = new Application();
        app.Run();
    }

    /// <summary>  
    /// 用FormatConvertedBitmap转换为8位灰度图
    /// </summary>  
    public static BitmapSource FormatGray8(BitmapSource bitmapSource)
    {
        if (bitmapSource == null)
            return bitmapSource;

        var f = new FormatConvertedBitmap();
        f.BeginInit();
        f.Source = bitmapSource;
        f.DestinationFormat = PixelFormats.Gray8;
        f.EndInit();
        return f;
    }
}


public class Utility
{
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int SystemParametersInfo(int uAction, int uParam, StringBuilder lpvParam, int fuWinIni);
    public const int SPI_GETDESKWALLPAPER = 0x0073;

    /// <summary>  
    /// 获得桌面壁纸  
    /// </summary>  
    /// <returns></returns>  
    public static string GetDesktopBackground()
    {
        var sb = new StringBuilder(255);
        SystemParametersInfo(SPI_GETDESKWALLPAPER, sb.Capacity, sb, 0);
        return sb.ToString();
    }

    /// <summary>  
    /// 保存位图  
    /// </summary>  
    /// <param name="bitmapSource"></param>  
    /// <param name="path"></param>  
    public static void Save(BitmapSource bitmapSource, string path)
    {
        using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            var extension = Path.GetExtension(path);
            BitmapEncoder encoder;
            if (".jpg".Equals(extension, StringComparison.OrdinalIgnoreCase))
            {
                encoder = new JpegBitmapEncoder();
            }
            else if (".png".Equals(extension, StringComparison.OrdinalIgnoreCase))
            {
                encoder = new PngBitmapEncoder();
            }
            else
            {
                encoder = new BmpBitmapEncoder();

            }
            encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
            encoder.Save(fs);
        }
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值