欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#?wpf使用GDI+實(shí)現(xiàn)截屏效果

 更新時(shí)間:2023年09月07日 08:52:07   作者:CodeOfCC  
wpf做屏幕錄制或者屏幕廣播之類的功能時(shí)需要實(shí)現(xiàn)截屏,在C#中比較容易實(shí)現(xiàn)的截屏方法是使用GDI+,所以本文將展示一下如何使用GDI+實(shí)現(xiàn)截屏,需要的可以參考下

前言

wpf做屏幕錄制或者屏幕廣播之類的功能時(shí)需要實(shí)現(xiàn)截屏,在C#中比較容易實(shí)現(xiàn)的截屏方法是使用GDI+,本文將展示使用GDI+截屏的具體實(shí)現(xiàn)方案,包括如何繪制鼠標(biāo),按幀率采集屏幕、將GDI+對(duì)象轉(zhuǎn)成wpf對(duì)象等。

一、引用System.Drawing

在wpf中使用GDI+功能需要引入System.Drawing庫(kù),有2種方式:在.net framework中直接引用系統(tǒng)庫(kù)即可。在.net core中可以引用mono實(shí)現(xiàn)的跨平臺(tái)的System.Drawing,提供接口與系統(tǒng)程序集是一模一樣的,而且性能略好一些。

方法一、引用系統(tǒng)程序集

1、右鍵引用

2、搜索drawing,勾選后確定即可。

方法二、NuGet獲取跨平臺(tái)Drawing

在.net core中無(wú)法引用系統(tǒng)的Drawing,只能通過(guò)Nuget獲取跨平臺(tái)Drawing。1、右鍵引用打開(kāi)NuGet界面

2、搜索drawing并安裝

二、實(shí)現(xiàn)截屏

1.簡(jiǎn)單截屏

簡(jiǎn)單的截屏只需幾行代碼即可實(shí)現(xiàn):

/// <summary>
/// 截取一幀圖片
/// </summary>
/// <param name="x">x坐標(biāo)</param>
/// <param name="y">y坐標(biāo)</param>
/// <param name="width">寬</param>
/// <param name="height">高</param>
/// <returns>截屏后的位圖對(duì)象,需要調(diào)用Dispose手動(dòng)釋放資源。</returns>
public static System.Drawing.Bitmap Snapshot(int x, int y, int width, int height)
{
    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
    {
         graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height), System.Drawing.CopyPixelOperation.SourceCopy);
    }
    return bitmap;
}

2.繪制鼠標(biāo)

上述方式實(shí)現(xiàn)的截屏是沒(méi)有鼠標(biāo)的,如果要顯示鼠標(biāo)則需要我們手動(dòng)繪制,通過(guò)獲取鼠標(biāo)的icon繪制到背景圖像中。繪制鼠標(biāo)需要用到win32Api以及gdi的rop。大致步驟如下(示例):

CURSORINFO ci;
ICONINFO info = new ICONINFO();
ci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
if (GetCursorInfo(out ci))
{
    if (GetIconInfo(ci.hCursor, info))
    {
        if (異或光標(biāo))
        {
            使用gdi的rop繪制
        }
        else
        {
            using (var icon = System.Drawing.Icon.FromHandle(ci.hCursor))
            {
                graphics.DrawIcon(icon, mouseX, mouseY);
            }
        }
    }
}

3.轉(zhuǎn)換成wpf對(duì)象

參考我的另一篇文章《C# wpf Bitmap轉(zhuǎn)換成WriteableBitmap(BitmapSource)的方法

4.屏幕采集

基于上面的實(shí)現(xiàn)加上開(kāi)線程及循環(huán)截屏就可以做到屏幕采集了。示例代碼如下:

System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
{
    while (!_exitFlag)
    {
        graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height), System.Drawing.CopyPixelOperation.SourceCopy);
        //繪制鼠標(biāo)
        ...
       //繪制鼠標(biāo)--end
       //將位圖數(shù)據(jù)寫入wpf對(duì)象、編碼推流等
         ...
       //將位圖數(shù)據(jù)寫入wpf對(duì)象、編碼推流等--end
       Thread.Sleep(幀率延時(shí));
    }
}

三、完整代碼

通過(guò)上述方法得到的接口設(shè)計(jì)如下(不含具體實(shí)現(xiàn)):

/// <summary>
/// 截屏事件參數(shù)
/// </summary>
public class ScreenCaptureEventArgs : EventArgs
{
    /// <summary>
    /// 像素格式
    /// </summary>
    public System.Drawing.Imaging.PixelFormat PixelFormat { set; get; }
    /// <summary>
    /// 圖像寬
    /// </summary>
    public int Width { set; get; }
    /// <summary>
    /// 圖像高
    /// </summary>
    public int Height { set; get; }
}
/// <summary>
/// 截屏數(shù)據(jù)事件參數(shù)
/// </summary>
public class ScreenCaptureDataEventArgs : ScreenCaptureEventArgs
{
    /// <summary>
    /// 圖像數(shù)據(jù)
    /// </summary>
    public IntPtr Data { set; get; }
    /// <summary>
    /// 數(shù)據(jù)長(zhǎng)度
    /// </summary>
    public int Length { set; get; }
    /// <summary>
    /// 一行數(shù)據(jù)長(zhǎng)度
    /// </summary>
    public int Stride { set; get; }
}
/// <summary>
/// 數(shù)值類型
/// </summary>
public enum ScreenCaptureValueType
{
    /// <summary>
    /// 實(shí)際值
    /// </summary>
    TrueValue,
    /// <summary>
    /// 按比例計(jì)算
    /// </summary>
    RadioValue
}
/// <summary>
/// 截屏對(duì)象
/// </summary>
public class ScreenCapture
{
    /// <summary>
    /// 截屏事件,每截取一幀都會(huì)回調(diào)
    /// </summary>
    public event EventHandler<ScreenCaptureDataEventArgs> Captured;
    /// <summary>
    /// 截屏開(kāi)始時(shí)回調(diào)
    /// </summary>
    public event EventHandler<ScreenCaptureEventArgs> Started;
    /// <summary>
    /// 結(jié)束時(shí)回調(diào)
    /// </summary>
    public event EventHandler Stoped;
    /// <summary>
    /// 截屏是否已停止
    /// </summary>
    public bool IsStoped { private set; get; }
    /// <summary>
    /// 是否截取鼠標(biāo)
    /// </summary>
    public bool IsPaintMouse { set; get; } = true;
    /// <summary>
    /// 截屏區(qū)域的計(jì)算方式
    /// TrueValue為實(shí)際值。RatioValue為比例值,范圍0-1,全屏設(shè)為0,0,1,1,則無(wú)論任何設(shè)備任何分辨率都是截取全屏。
    /// </summary>
    public ScreenCaptureValueType ClipRectValueType { private set; get; } = ScreenCaptureValueType.RadioValue;
    /// <summary>
    /// 截屏區(qū)域X坐標(biāo)
    /// </summary>
    public double ClipX { private set; get; } = 0;
    /// <summary>
    /// 截屏區(qū)域Y坐標(biāo)
    /// </summary>
    public double ClipY { private set; get; } = 0;
    /// <summary>
    /// 截屏區(qū)域?qū)?
    /// </summary>
    public double ClipWidth { private set; get; } = 1;
    /// <summary>
    /// 截屏區(qū)域高
    /// </summary>
    public double ClipHeight { private set; get; } = 1;
    /// <summary>
    /// 截屏幀率
    /// </summary>
    public double Framerate{ set; get; }=30;
    /// <summary>
    /// 設(shè)置截屏區(qū)域
    /// </summary>
    /// <param name="x">x坐標(biāo)</param>
    /// <param name="y">y坐標(biāo)</param>
    /// <param name="width">寬</param>
    /// <param name="height">高</param>
    /// <param name="valueType">TrueValue為實(shí)際值。RatioValue為比例值,范圍0-1,全屏設(shè)為0,0,1,1,則無(wú)論任何設(shè)備任何分辨率都是截取全屏。</param>
    public void SetClipRect(double x, double y, double width, double height, ScreenCaptureValueType valueType);
    /// <summary>
    /// 啟動(dòng)屏幕采集
    /// </summary>
    public void Start();
    /// <summary>
    /// 停止屏幕采集
    /// 異步方法,Stoped事件為真正的停止。
    /// </summary>
    public void Stop();
    /// <summary>
    /// 截取一幀圖片
    /// </summary>
    /// <param name="x">x坐標(biāo)</param>
    /// <param name="y">y坐標(biāo)</param>
    /// <param name="width">寬</param>
    /// <param name="height">高</param>
    /// <param name="isPaintMouse">是否繪制鼠標(biāo)</param>
    /// <returns>截屏后的位圖對(duì)象,需要調(diào)用Dispose手動(dòng)釋放資源。</returns>
    public static System.Drawing.Bitmap Snapshot(int x, int y, int width, int height, bool isPaintMouse);

四、使用示例

1.截屏

xaml

<Window x:Class="WpfScreenCaptureGdi.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfScreenCaptureGdi"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Cursor="Cross">
        <Image x:Name="img"  ></Image>
    </Grid>
</Window>

cs

public MainWindow()
{
    InitializeComponent();
    var bm = ScreenCapture.Snapshot(0, 0, 1920, 1080, true);
    var wb = BitmapInterop.BitmapToWriteableBitmap(bm);
    img.Source = wb;
    bm.Dispose();
}

效果預(yù)覽:

2.屏幕采集

示例一、顯示桌面

xaml

<Window x:Class="WpfScreenCaptureGdi.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfScreenCaptureGdi"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        Closing="Window_Closing"
        >
    <Grid Cursor="Cross">
        <Image x:Name="img"  ></Image>
    </Grid>
</Window>

cs

ScreenCapture sc = new ScreenCapture();
public MainWindow()
{
    InitializeComponent();
    //注冊(cè)事件
    sc.Captured += Sc_Captured;
    sc.Started += Sc_Started;
    //開(kāi)始采集
    sc.Start();
}
private void Sc_Started(object sender, ScreenCaptureEventArgs e)
{
    Dispatcher.Invoke(() =>
    {
        //初始化位圖對(duì)象    
        img.Source = BitmapInterop.CreateCompatibleWriteableBitmap(e.Width, e.Height, e.PixelFormat);
    });
}
private void Sc_Captured(object sender, ScreenCaptureDataEventArgs e)
{
    //采集的畫面用于顯示
    Dispatcher.Invoke(() =>
    {
        var wb = img.Source as WriteableBitmap;
        if (wb.Width < e.Width || wb.Height < e.Height)
        //寬高改變了重新初始化位圖對(duì)象
        {
            wb = BitmapInterop.CreateCompatibleWriteableBitmap(e.Width, e.Height, e.PixelFormat);
            img.Source = wb;
        }
        wb.WritePixels(new Int32Rect(0, 0, e.Width, e.Height), e.Data, e.Length, e.Stride, 0, 0);
    });
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    //異步的方式退出才不會(huì)造成死鎖
    if (!sc.IsStoped)
    {
        sc.Stop();
        sc.Stoped += (s, e) =>
        {
            Dispatcher.Invoke(() =>
            {
                Close();
            });
        };
        e.Cancel = true;
    }
}

示例二、動(dòng)態(tài)調(diào)整參數(shù)

可以在采集過(guò)程中動(dòng)態(tài)調(diào)整參數(shù),比如采集區(qū)域、幀率、鼠標(biāo)繪制。

在示例一的基礎(chǔ)上添加如下代碼:

//測(cè)試動(dòng)態(tài)調(diào)整參數(shù)
var t = new Thread(() =>
  {
      while (true)
      {
          for (int i = 1; i <= 100; i++)
          {
              sc.SetClipRect(0, 0, i / 100.0, i / 100.0, ScreenCaptureValueType.RadioValue);
              Thread.Sleep(100);
          }
          for (int i = 1; i <= 1920; i++)
          {
              sc.SetClipRect(0, 0, i, 1080, ScreenCaptureValueType.TrueValue);
              Thread.Sleep(1);
          }
      }
  });
t.IsBackground = true;
t.Start();
//測(cè)試動(dòng)態(tài)調(diào)整參數(shù) --end

效果預(yù)覽:

總結(jié)

本文簡(jiǎn)單介紹GDI+截屏的方法,添加鼠標(biāo)的實(shí)現(xiàn)以及將GDI+對(duì)象轉(zhuǎn)換成wpf對(duì)象,和屏幕采集的實(shí)現(xiàn),總的來(lái)說(shuō)不算是特別容易,原理很簡(jiǎn)單但是有不少細(xì)節(jié)需要處理,尤其是調(diào)試中出現(xiàn)資源釋放問(wèn)題,需要有c++開(kāi)發(fā)的意識(shí),才能很好的定位和解決問(wèn)題。

到此這篇關(guān)于C# wpf使用GDI+實(shí)現(xiàn)截屏效果的文章就介紹到這了,更多相關(guān)C# wpf截屏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入分析C#連接Oracle數(shù)據(jù)庫(kù)的連接字符串詳解

    深入分析C#連接Oracle數(shù)據(jù)庫(kù)的連接字符串詳解

    本篇文章是對(duì)C#連接Oracle數(shù)據(jù)庫(kù)的連接字符串進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C#正則表達(dá)式Regex用法詳解

    C#正則表達(dá)式Regex用法詳解

    本文詳細(xì)講解了C#正則表達(dá)式Regex的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C# WinForm制作登錄界面的實(shí)現(xiàn)步驟

    C# WinForm制作登錄界面的實(shí)現(xiàn)步驟

    本文主要介紹了C# WinForm制作登錄界面的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C#中winform中panel重疊無(wú)法顯示問(wèn)題的解決

    C#中winform中panel重疊無(wú)法顯示問(wèn)題的解決

    這篇文章主要介紹了C#中winform中panel重疊無(wú)法顯示問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • c#?如何將字符串轉(zhuǎn)換為大寫或小寫

    c#?如何將字符串轉(zhuǎn)換為大寫或小寫

    這篇文章主要介紹了c#?如何將字符串轉(zhuǎn)換為大寫或小寫,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • C# 使用WPF 用MediaElement控件實(shí)現(xiàn)視頻循環(huán)播放

    C# 使用WPF 用MediaElement控件實(shí)現(xiàn)視頻循環(huán)播放

    在WPF里用MediaElement控件,實(shí)現(xiàn)一個(gè)循環(huán)播放單一視頻的程序,同時(shí)可以控制視頻的播放、暫停、停止。這篇文章給大家介紹了C# 使用WPF 用MediaElement控件實(shí)現(xiàn)視頻循環(huán)播放,需要的朋友參考下吧
    2018-04-04
  • C#中常見(jiàn)的文件處理操作小結(jié)

    C#中常見(jiàn)的文件處理操作小結(jié)

    這篇文章主要為大家詳細(xì)介紹了C#中常見(jiàn)的一些文件處理操作,例如文件管理,獲取文件信息和控制處理文件,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • C#實(shí)現(xiàn)注冊(cè)碼注冊(cè)機(jī)制效果詳解

    C#實(shí)現(xiàn)注冊(cè)碼注冊(cè)機(jī)制效果詳解

    這篇文章主要為大家詳細(xì)介紹了C#如何實(shí)現(xiàn)注冊(cè)碼注冊(cè)機(jī)制效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-01-01
  • C#調(diào)用百度API實(shí)現(xiàn)活體檢測(cè)的方法

    C#調(diào)用百度API實(shí)現(xiàn)活體檢測(cè)的方法

    這篇文章主要給大家介紹了關(guān)于C#調(diào)用百度API實(shí)現(xiàn)活體檢測(cè)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • C#中委托和事件的區(qū)別詳解

    C#中委托和事件的區(qū)別詳解

    C# 中的委托(Delegate)類似于 C 或 C++ 中函數(shù)的指針。事件是在委托類型變量前加上 event 關(guān)鍵字,其本質(zhì)是用來(lái)對(duì)委托類型的變量進(jìn)行封裝,類似于類的屬性對(duì)字段的封裝。本文就來(lái)聊聊C#中委托和事件的區(qū)別,感興趣的可以了解一下
    2022-11-11

最新評(píng)論