1. 程式人生 > >c# wpf 利用截屏鍵實現截屏功能

c# wpf 利用截屏鍵實現截屏功能

aging psc 獲取圖片 print href bits ng2 ont 包裝

原文:c# wpf 利用截屏鍵實現截屏功能

? ? 最近做一個wpf程序需要截圖功能,查找資料費了一些曲折,跟大家分享一下。

????先是找到了這樣一份代碼:

????static?class?ScreenCut

????{

????????public?static?System.Drawing.Bitmap?GetScreenSnapshot()

????????{

????????????System.Drawing.Rectangle?rc = System.Windows.Forms.SystemInformation

.VirtualScreen;

????????????System.Drawing.Bitmap?bitmap = new?System.Drawing.Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

????????????using?(System.Drawing.Graphics?g = System.Drawing.Graphics.FromImage(bitmap))

????????????{

????????????????g.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, System.Drawing.CopyPixelOperation

.SourceCopy);

????????????}

????????????return?bitmap;

????????}

????????public?static?BitmapSource?ToBitmapSource(this?System.Drawing.Bitmap?bmp)

????????{

????????????BitmapSource?returnSource;

????????????try

????????????{

????????????????returnSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr

.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

????????????}

????????????catch

????????????{

????????????????returnSource = null;

????????????}

????????????return?returnSource;

????????}

?

????????public?static?BitmapSource?CopyFromScreenSnapshot(BitmapSource?screenSnapshot, Rect?region)

????????{

????????????var?sourceRect = new?System.Drawing.Rectangle((int)region.Left, (int)region.Top, (int)region.Width, (int)region.Height);

????????????var?destRect = new?System.Drawing.Rectangle(0, 0, sourceRect.Width, sourceRect.Height);

?

????????????if?(screenSnapshot != null)

????????????{

????????????????var?bitmap = new?System.Drawing.Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

????????????????using?(System.Drawing.Graphics?g = System.Drawing.Graphics.FromImage(bitmap))

????????????????{

????????????????????g.DrawImage(bitmap, destRect, sourceRect.Left, sourceRect.Top, sourceRect.Width, sourceRect.Height, System.Drawing.GraphicsUnit.Pixel);

????????????????}

?

????????????????return?bitmap.ToBitmapSource();

????????????}

?

????????????return?null;

????????}

}

?

調用時包裝一下,下面的函數截下屏幕指定區域並保存:

????System.Drawing.Image?takePicture(Rect?wnd, String?saveLocation, String?pictureName)

{ ???

????????BitmapSource?bitmapScr = ScreenCut.CopyFromScreenSnapshot(ScreenCut.ToBitmapSource(ScreenCut.GetScreenSnapshot()),wnd);

????????PngBitmapEncoder?encoder = new?PngBitmapEncoder();

????????encoder.Frames.Add(BitmapFrame.Create(bitmapScr));

????????FileStream?fileStream = new?FileStream(saveLocation + "\\"?+ pictureName ".png", FileMode.Create, FileAccess.Write);

????????encoder.Save(fileStream);

????????fileStream.Close();

}

?

但實際效果保存下來的圖是空的,經驗證前兩個函數沒有問題。於是我查資料找到了另一種切割BitmapSource的方法,將第三個函數改成這樣:

BitmapSource?CopyFromScreenSnapshot(BitmapSource?screenSnapshot, Rect?region)

{

????????Int32Rect?window?= new Int32Rect(region.X, region.Y, region.Width, region.Height);

????????BitmapSource?bitmapScr = ScreenCut.ToBitmapSource(ScreenCut.GetScreenSnapshot());

????????//計算Stride

????????int?stride = bitmapScr.Format.BitsPerPixel * window.Width / 8;

????????//聲明字節數組

????????byte[] data = new?byte[window.Height * stride];

????????//調用CopyPixels

????????bitmapScr.CopyPixels(window, data, stride, 0);

????????PngBitmapEncoder?encoder = new?PngBitmapEncoder();

????return?BitmapSource.Create(window.Width, window.Height, 0, 0, PixelFormats.Bgr32, null, data, stride);

}

?

這樣總算能截到屏了。不過後來發現在某些主題下有些程序的窗口在截下的圖中是透明的。這個方法還是不夠完美。

我想到了利用鍵盤的截屏鍵截圖再進行剪切的方法。分為三步:1、模擬按下截屏鍵 2、從剪貼板獲取圖片 3、截取和保存圖片。

對於第一點,利用SendMessage函數發送WM_KEY事件沒有用,不過我找到了另一個模擬鍵盤輸入的方法:

using?System.Runtime.InteropServices;

????[DllImport("user32.dll")]

????static?extern?void?keybd_event

????(

????????byte?bVk,// 虛擬鍵值

????????byte?bScan,// 硬件掃描碼 ???

????????uint?dwFlags,// 動作標識 ???

????????IntPtr?dwExtraInfo// 與鍵盤動作關聯的輔加信息 ???

);

?

上面這個函數對本程序發送按鈕事件,模擬截屏鍵的話像下面這樣寫,wpf需要在項目添加引用System.Windows.Forms

const?int?VK_SNAPSHOT = 0x2C;

????public?void?PrintScreen()

????{

????????keybd_event((byte)VK_SNAPSHOT, 0, 0x0, IntPtr.Zero);//down ?

????????System.Windows.Forms.Application.DoEvents();//強制窗口響應按鈕事件

????????keybd_event((byte)VK_SNAPSHOT, 0, 0x2, IntPtr.Zero);//up ?

????????System.Windows.Forms.Application.DoEvents();

}

?

接下來從剪貼板獲取圖片,wpf需要在項目添加引用System.Windows.Forms??System.Drawing

????if?(System.Windows.Forms.Clipboard.ContainsImage())

????{

???????System.Drawing.Image?image = System.Windows.Forms.Clipboard.GetImage();

}

?

然後剪切。

????System.Drawing.Image?cutPicture(System.Drawing.Image?image, Int32Rect?window)

????{

????????PrintScreen();

????????if?(window.X + window.Width > image.Width)

????????????window.Width = image.Width - window.X;

????????if?(window.Y + window.Height > image.Height)

????????????window.Height = image.Height - window.Y;

????????if?(image == null)

????????{

????????????//新建一個bmp圖片

????????????System.Drawing.Image?bitmap = new?System.Drawing.Bitmap(window.Width, window.Height);

????????????//新建一個畫板

????????????System.Drawing.Graphics?graphic = System.Drawing.Graphics.FromImage(bitmap);

????????????//設置高質量查值法

????????????graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;

????????????//設置高質量,低速度呈現平滑程度

????????????graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

????????????//清空畫布並以透明背景色填充

????????????graphic.Clear(System.Drawing.Color.Transparent);

????????????//在指定位置並且按指定大小繪制原圖片的指定部分

????????????graphic.DrawImage(image, new?System.Drawing.Rectangle(0, 0, window.Width, window.Height), new?System.Drawing.Rectangle(window.X, window.Y, window.Width, window.Height), System.Drawing.GraphicsUnit.Pixel);

????????????return?bitmap;

????????}

????????else

????????{

????????????return?null;

????????}

}

?

最後包裝一下

????System.Drawing.Image?cutScreen(Int32Rect?window)

????{

????????PrintScreen();

????????Thread.Sleep(1000);

????????if?(System.Windows.Forms.Clipboard.ContainsImage())

????????{

????????????System.Drawing.Image?image?=?cutPicture(System.Windows.Forms.Clipboard.GetImage(), Int32Rect?window);

????????????return?image;

????????}

????????else

????????{

????????????Console.WriteLine("clipboard doesn‘t contain picture");

????????????return?null;

????????}

}

System.Drawing.Image類有實例函數Save,保存很簡單,就不細說了。

資料來源:

http://www.cnblogs.com/zhouyinhui/archive/2010/08/20/1804762.html

https://www.mgenware.com/blog/?p=285

http://blog.csdn.net/testcs_dn/article/details/39762017

c# wpf 利用截屏鍵實現截屏功能