当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这个类实现。
测试代码如下:
// 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);
}
}
}