C#搞跨平台桌面UI,分别实现Windows,Mac,Linux屏幕截图
搞跨平台IM,截图功能少不了。
Windows
创建GDI的兼容位图,把桌面的图像通过BitBlt拷贝到兼容位图里,通过兼容位图的数据指针创建Bitmap对象,由于兼容位图的内存是非托管的,Bitmap无法释放该内存,拷贝一下,把兼容位图的释放掉,新的Bitmap的内存就可以由新Bitmap来自己托管释放。
public override Bitmap Screenshot()
{
var srcDC = GetDC(IntPtr.Zero);
var bounds = Bounds; IntPtr memDc = CreateCompatibleDC(srcDC);
BITMAPINFOHEADER info = new BITMAPINFOHEADER();
info.biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER));
info.biBitCount = 32;
info.biHeight = -(int)bounds.Height;
info.biWidth = (int)bounds.Width;
info.biPlanes = 1;
var hBitmap = CreateDIBSection(memDc, ref info, 0, out var ppvBits, IntPtr.Zero, 0);
var oldBits = SelectObject(memDc, hBitmap); BitBlt(memDc, 0, 0, (int)bounds.Width,
(int)bounds.Height, srcDC, (int)bounds.X, (int)bounds.Y, TernaryRasterOperations.SRCCOPY);
Bitmap temp = new Bitmap((int)bounds.Width, (int)bounds.Height, (int)bounds.Width * 4, PixelFormat.Bgra, ppvBits); Bitmap bitmap = (Bitmap)temp.Clone();
temp.Dispose(); SelectObject(memDc, oldBits);
DeleteObject(hBitmap);
DeleteDC(memDc); ReleaseDC(IntPtr.Zero, srcDC);
return bitmap;
}
Mac
直接使用Mac里的 CGWindowListCreateImage 来截图,由于数据格式不同,需要读取像素,一个个设置给Bitmap
Mac里在不同权限选项下截取的图片内容不同的,没有录制权限的情况下只能截取当前程序的界面和空的桌面。
public unsafe override Bitmap Screenshot()
{
using (var img = new CGImage(CGImage.CGWindowListCreateImage(screen.Frame, CGWindowListOption.All, 0, CGWindowImageOption.Default), owns: true))
{
//CGImage imageRef = CGImage.CGWindowListCreateImage(mainRect, kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageNominalResolution | kCGWindowImageShouldBeOpaque);
var height = img.Height;
var width = img.Width;
var bpr = img.BytesPerRow;
var bpp = img.BitsPerPixel;
var bpc = img.BitsPerComponent;
var bytes_per_pixel = bpp / bpc; using (var data = img.DataProvider.CopyData())
{
var bitmap = new Bitmap(img.Width, img.Height);
var bytes = (byte*)data.Bytes;
using (var b = bitmap.Lock())
{
for (var row = 0; row < height; row++)
{
for (var col = 0; col < width; col++)
{
var pixel = &bytes[row * bpr + col * bytes_per_pixel]; b.SetPixel(col, row, pixel[3], pixel[2], pixel[1], pixel[0]);
}
}
}
return bitmap;
}
}
}
Linux
使用XGetImage来截图,同样需要转换一下位图格式
public override Bitmap Screenshot()
{
var bounds = Bounds;
var image = XGetImage(LinuxPlatform.Platform.Display, LinuxPlatform.Platform.Info.RootWindow, (int)bounds.X, (int)bounds.Y, (int)bounds.Width,
(int)bounds.Height, ~0, 2 /* ZPixmap*/);
if (image == IntPtr.Zero)
{
string s = String.Format("XGetImage returned NULL when asked to for a {0}x{1} region block",
bounds.Width, bounds.Height);
throw new InvalidOperationException(s);
} Bitmap bmp = new Bitmap((int)bounds.Width, (int)bounds.Height);
var visual = LinuxPlatform.Platform.Info.TransparentVisualInfo;
int red, blue, green;
int red_mask = (int)visual.red_mask;
int blue_mask = (int)visual.blue_mask;
int green_mask = (int)visual.green_mask;
using (var b = bmp.Lock())
{
for (int y = 0; y < bounds.Height; y++)
{
for (int x = 0; x < bounds.Width; x++)
{
var pixel = XGetPixel(image, x, y); switch (visual.depth)
{
case 16: /* 16bbp pixel transformation */
red = (int)((pixel & red_mask) >> 8) & 0xff;
green = (int)(((pixel & green_mask) >> 3)) & 0xff;
blue = (int)((pixel & blue_mask) << 3) & 0xff;
break;
case 24:
case 32:
red = (int)((pixel & red_mask) >> 16) & 0xff;
green = (int)(((pixel & green_mask) >> 8)) & 0xff;
blue = (int)((pixel & blue_mask)) & 0xff;
break;
default:
string text = string.Format("{0}bbp depth not supported.", visual.depth);
throw new NotImplementedException(text);
} b.SetPixel(x, y, 255, (byte)red, (byte)green, (byte)blue);
}
}
} XDestroyImage(image);
return bmp;
}
上面的就是CPF的内部实现,一般你不需要管这些细节,直接调用CPF的函数就行了。
最终封装到CPF就是一行代码就行
window.Screen.Screenshot();
要实现QQ截图的效果的话,先截图,再搞个全屏的窗体,把截图内容放到里面,再对屏幕截图进行裁剪,绘图处理。
C#搞跨平台桌面UI,分别实现Windows,Mac,Linux屏幕截图的更多相关文章
- [.net 面向对象程序设计深入](5)MVC 6 —— 构建跨平台.NET开发环境(Windows/Mac OS X/Linux)
[.net 面向对象程序设计深入](5)MVC 6 —— 构建跨平台.NET开发环境(Windows/Mac OS X/Linux) 1.关于跨平台 上篇中介绍了MVC的发展历程,说到ASP.NET ...
- BesLyric 全新版本下载 ( windows \ mac \ linux )
导读 BesLyric , 一款专门制作 网易云音乐 LRC 滚动歌词的软件! 搜索.下载.制作 歌词更方便! 很荣幸地,自 beslyric 2017 年开发推出以来,得到了很多云村村民的肯定,现在 ...
- OpenGL环境搭建Windows+Mac+Linux
OpenGL环境搭建Windows+Mac+Linux Mac平台下 下载列表:GLFWcmake 下载的GLFW解压缩 然后安装cmake, 安装好cmake之后打开 1.browse source ...
- SSH客户端,FinalShell服务器管理,远程桌面加速软件,支持Windows,Mac OS X,Linux,版本2.6.3.1
FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工具,充分满足开发,运维需求. 用户QQ群 342045988 Windows版下载地址:http:/ ...
- 实现一个跨平台的mysock库(windows、linux)
源码下载 1.首先确定自己的操作系统为32位还是64位: root@bfq:~/mysock# uname -a Linux bfq 3.11.0-26-generic#45~precise1- ...
- centos7 通过kvm+vnc 实现远程桌面虚拟化和创建windows、Linux虚拟机
感谢朋友支持本博客.欢迎共同探讨交流,因为能力和时间有限.错误之处在所难免,欢迎指正! 假设转载.请保留作者信息. 博客地址:http://blog.csdn.net/qq_21398167 原博文地 ...
- 全网最详细的Git学习系列之介绍各个Git图形客户端(Windows、Linux、Mac系统皆适用ing)(图文详解)
不多说,直接上干货! 一.TortoiseGit - The coolest Interface to Git Version Control TortoiseGit 是 TortoiseSVN 的 ...
- C#搞跨平台UI,封装Cef作为Cpf的控件支持Windows,Linux,Mac
终于封装完成了,采用离屏渲染方式,支持JS和C#互相调用,C#方法自动绑定到JS里,中文输入有自动调整输入法位置. 基于开源的CefGlue 移植,本来想用CefSharp,不过这个里面有很多C++的 ...
- 原创|我是如何从零学习开发一款跨平台桌面软件的(Markdown编辑器)
原始冲动 最近一直在学习 Electron 开发桌面应用程序,目的是想做一个桌面编辑器,虽然一直在使用Typore这款神器,但无奈Typore太过国际化,在国内水土不服,无法满足我的一些需求. 比如实 ...
随机推荐
- Intel汇编语言程序设计学习-第一章 基本概念
第一章基本概念 1.1 简单介绍 本书着重讲述MS-Windows平台上IA-32(Intel Architecture 32bit,英特尔32位体系架构)兼容微处理器的汇编语言程序设计,可以使用I ...
- [CTF]凯撒密码
[CTF]凯撒密码 --------------------- 作者:___Blue_H 来源:CSDN 原文:https://blog.csdn.net/qq_37653144/article ...
- 在网页添加 Live2D 看板娘
只需要将以下代码粘贴到 标签中即可 <!--看板娘--> <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jqu ...
- 【前端】vue2.x 配合 bootstrapTable 动态添加元素和绑定点击事件,事件无效 解决
背景: 使用bootstrap-table 表格插件时,每一行的最后一班会加操作按钮列.如果不加入vue的话,使用插件自己的列属性formatter:function(value, row, inde ...
- 【.Net Core】分析.net core在linux下内存占用过高问题
现象 随着程序运行,内存占用率越来越高,直到触发linux的OOM,程序被杀死. 分析工具 运行环境:.net core 3.1(微软的分析工具要求最低3.0,无法分析2.1的core程序,需要先改为 ...
- FFmpeg应用实践之命令查询
0. 前言 FFmpeg 中常用的工具有三个,分别是多媒体编解码工具ffmpeg.多媒体内容分析工具ffprobe和多媒体播放器ffplay.本文介绍的指令都是与编解码工具 ffmpeg 相关的. 学 ...
- [并发编程 - 多线程:信号量、死锁与递归锁、时间Event、定时器Timer、线程队列、GIL锁]
[并发编程 - 多线程:信号量.死锁与递归锁.时间Event.定时器Timer.线程队列.GIL锁] 信号量 信号量Semaphore:管理一个内置的计数器 每当调用acquire()时内置计数器-1 ...
- Git 系列教程(12)- 分支的新建与合并
实际工作场景 可能会遇到的工作流 开发某个网站 为实现某个新的用户需求,创建一个分支 在这个分支上开展新工作 正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补,你将按照如下方式来处理: 切换 ...
- 设了padding要减去盒高 和 line-height 行高
增加了padding 一定要减去相应的高度,不然整个元素的高度会增高(原高+padding) line-height:行高 1.行高要比字体大,不然字体会挤到一块去 2.若父盒子没有设置高度,则行高会 ...
- 阿里云上安装 OpenStack 是什么体验
阿里云上跑火车(安装 OpenStack Train 版本),猜猜最终花了多少钱? 前言 前面给大家提供了用虚拟机安装 OpenStack 的镜像,虽然已经很简便了,但还是略显笨重.一来镜像文件比较大 ...