MonoGame 3.2 下,截屏与 Texture2D 的保存

注意,由于采用的是 MonoGame 3.2,因此方法与 XNA 4.0 不完全相同。

目标是将当前 GraphicsDevice 的内容保存为一个 Texture2D,同时还要能输出至文件。

截屏,在 XNA 下早就有人做了,例如这个:XNA4.0 保存屏幕截图方法[1]。

同时,针对 Texture.SaveAsPng()(XNA 下),也有人早就发现了其内存泄露问题,并写出了自己的解决方案:Texture2d.SaveAsPng() Memory Leak[2]。

不过 MonoGame 在 Windows 平台下是不支持 Texture2D.SaveAsPng() 和 Texture2D.SaveAsJpeg() 的,所以不管别人内存泄露啥的,这个保存方法还是要自己实现。(请参考 MonoGame 的代码;有相关外文帖子,不过地址我忘记了。)

其实呢,是我想偷懒,毕竟保存到 Texture2D 后还要写一段代码让其显示出来、消失、再进入原主循环,太麻烦;而且别人的代码还未必可行,先保存为文件看看结果如何。但是保存的时候就出问题了……

链接[2]中有保存的实现,不过那是针对 XNA 的,我在 MonoGame 上运行时出现了颜色错误。也就是说,到目前为止,至少还没有 MonoGame 开发者公开一个成功的保存方案。(当然,像 FEZ 那样的 Indie Game,写了也不会放在网上,对吧。)

其中最值得注意的是像素格式。GDI+ 是 0xARGB(但是有时是 ABGR,在做 VB6 的时候碰到过),但是 MonoGame 呢?(这里 MonoGame 可能没有遵循 XNA 的规范?)这个我不知道。之前几次用的都是 SurfaceFormat.Color,微软文档上说这是一个 RGB 颜色带 Alpha 通道,不过顺序未指明(从后面看来,应该是 ARGB)。不过 MonoGame 3.2 的 Windows(不是 WindowsGL)模板用的是 SharpDX,DirectX 这里定义的似乎是 A8R8G8B8。直接保存,颜色错误。对比同一个像素发现有这样的事情:0xff3dab0d(正确)→0xffd3abd0(直接保存),因此做这样的处理,还是失败。最后这个成功的结果应该说还是偶然吧。

这里就不展示错误的效果了,我附上了复现错误的注释,有兴趣的人可以自己试试。

下面就是代码。请预先添加两个引用:

1 using System.Drawing.Imaging;
2 using System.Runtime.InteropServices;

创建一个 RenderTarget2D 对象(继承自 Texture2D)保存截屏内容:

 1 public Texture2D TakeScreenshot()
 2 {
 3     int w, h;
 4     w = GraphicsDevice.PresentationParameters.BackBufferWidth;
 5     h = GraphicsDevice.PresentationParameters.BackBufferHeight;
 6     RenderTarget2D screenshot;
 7     // 注意格式一定要是 SurfaceFormat.Bgra32,与 GDI+ 统一。默认的 SurfaceFormat.Color 会导致颜色错误。
 8     screenshot = new RenderTarget2D(GraphicsDevice, w, h, false, SurfaceFormat.Bgra32, DepthFormat.None);
 9     GraphicsDevice.SetRenderTarget(screenshot);
10     Draw(_lastUpdatedGameTime != null ? _lastUpdatedGameTime : new GameTime());
11     GraphicsDevice.Present();
12     GraphicsDevice.SetRenderTarget(null);
13     return screenshot;
14 }

然后是对 Texture2D 的扩展(框架来自链接[2]):

 1 public static void Save(this Texture2D texture, ImageFormat imageFormat, Stream stream)
 2 {
 3     var width = texture.Width;
 4     var height = texture.Height;
 5     using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
 6     {
 7         IntPtr safePtr;
 8         BitmapData bitmapData;
 9         System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, width, height);
10         // 这里用 int[width * height] 而不用原文的 byte[4 * width * height],否则图像大小异常
11         int[] textureData = new int[width * height];
12
13         texture.GetData(textureData);
14         bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
15         safePtr = bitmapData.Scan0;
16         Marshal.Copy(textureData, 0, safePtr, textureData.Length);
17         bitmap.UnlockBits(bitmapData);
18         bitmap.Save(stream, imageFormat);
19
20         textureData = null;
21     }
22     GC.Collect();
23 }

最后是调用:

 1 void mainButton4_MouseClick(object sender, MouseEventArgs e)
 2 {
 3     var screenshot = RootControlContainer.TakeScreenshot();
 4     if (screenshot != null)
 5     {
 6         // System.Drawing.Bitmap.Save() 方法的文件名必须是绝对路径
 7         // 而在 MonoGame 下难以获取绝对路径,因此若要保存至相对路径,请使用 System.IO.FileStream
 8         using (var fs = new System.IO.FileStream(@"screenshot.png", System.IO.FileMode.OpenOrCreate))
 9         {
10             screenshot.Save(System.Drawing.Imaging.ImageFormat.Png, fs);
11         }
12         screenshot.Dispose();
13     }
14 }
时间: 2024-11-08 17:28:46

MonoGame 3.2 下,截屏与 Texture2D 的保存的相关文章

mac下截屏快捷键

在Mac OS中,有非常方便的截屏快捷键: Command-Shift-3: 对整个屏幕截屏,图片会保存的一个文件中(默认保存的桌面上) Command-Ctrl-Shift-3: 对整个屏幕截屏,图片被保存到剪贴板(夹纸板)中. Command-Shift-4: 对选定区域进行截屏,并将图片保存到文件中(默认保存的桌面上).在触发这个快捷键后,按空格(Space)键,可以对一整个窗口或菜单进行截屏. Command-Ctrl-Shift-4: 对选定区域进行截屏,图片被保存到剪贴板(夹纸板)中

IMAC双系统WIN下截屏快捷键

一.Mac下有自带的截图功能 新Mac用户根本不必麻烦去寻找截屏软件,默认快捷键是 全屏幕截图:Command+Shift+3 区域截图:Command+Shift+4 随后按 Space(空格) 可以选定窗口截图 Mac下屏幕快照快捷键可以自定义设置: 系统偏好设置——键盘——键盘快捷键 Mac下截图默认保存在桌面上,格式为PNG: 二.苹果电脑在Win系统中,由于Macbook键盘上是没有Print Screen按键的 大家可以用如下方法截图: 全屏截图:fn+shift+F11 窗口截图:

团队软件开发_基于windows下截屏软件关于NABC框架的特点

经过我们小组数次的激烈讨论,就自己的能力和时间而言,我们小组的初步的计划是开发一款基于windows下的截图软件. 关于这个软件的功能,我们初步的想法如下: 1.能在windows下后台运行,有相应的快捷键,以便随时随地的截取用户所需要的信息: 2.在截屏开始钱前有一个关于形状的选择(如矩形,圆形等),当然,还有我们小组自认为比较好的随意形状的截图: 3.当随意形状截屏时,此软件还有磁性吸附轮廓的功能,以避免鼠标使用时截屏的轮廓不合理情况:

如何在Windows7下截屏。

看到大家经常用手机拍电脑桌面,当然这不是不可以,但是电脑本身自己就有截屏的操作,为什么还要用手机拍照呢?手机拍照的缺点:一.上班用手机拍照,心里是不是有点慌?怕被抓住?二.手机拍照,手机像素先不论,一般拍的也不清楚,有的时候还会出现残影,看你照片的人眼睛都瞎了呢.三.用手机拍照会让人认为是电脑小白,因此要高端起来.希望大家心里能有个Balance.以上纯属个人观点,欢迎指正交流. 那么如何截屏呢?截屏首推截屏软件,这个话自行百度即可.(像自带截屏功能的QQ等也算在里面)如果不能装软件的话,也有办

【转】使用adb命令对手机进行截屏(截图)保存到电脑,SDCard

原文网址:http://blog.csdn.net/huangyabin001/article/details/29198367 adb shell /system/bin/screencap -p /sdcard/screenshot.png(保存到SDCard) adb pull /sdcard/screenshot.png d:/screenshot.png(保存到电脑)

Android 系统截屏与系统内置DVR录像冲突,导致SystemUI重启的问题解决与分享

上周六加班在解决一个关于SystemUI内嵌的DVR录像与系统截屏操作冲突的问题,介于问题的复杂性,所以我把这个分享出来便 于以后自己更加的理解,又方便以后遇到此问题的同行能够提供一些帮助,若有疑问可向鄙人的博客提供你的宝贵意见! 首先我们需要找到系统截屏的按键定义,并且知道它在哪里执行的,先摈弃从硬件底层的协议,我们直接从framework层开始 讲,因为底层底层硬件返回的结果由.c.o.h这些文件,再由Binder aidl 将结果给到framework,所以我们就从开始从framework

使用laravel框架与phantomjs实现截屏功能

在网上看到的关于phantomjs实现截屏功能很多都是与node结合在一起使用,并需要输入命令才能执行.因此我想要实现输入网址即可截屏并输出图片的功能. 一:下载并安装phantomjs 二:装后台集成环境Appserv 三:安装laravel开发框架 三:实现代码及注意事项 1.phantomjs很好安装,http://phantomjs.org/官网下载到任意目录(注意:如果为了省事,最好安装到本地环境变量的目录下  如下图),如果不想下载到此目录下,可下载完后到计算机属性的环境变量增加ph

APP进入后台时自动截屏的应对方法

点击HOME键使应用进入后台时,iOS会自动对当前屏幕进行截屏处理,并保存成图片文件. 在Mac中可以看到,这些截屏文件会被保存在下述路径中: <Home>/Library/Caches/Snapshots/(Bundle identifier)/ 且文件名以"UIApplicationAutomaticSnapshotDefault-"开头. 这些自动生成的截屏文件,对启用了密码保护功能的应用而言,在安全性方面会是个比较严重的问题. 经过各种试验,找到了3中解决方法. 方

mac系统截屏的快捷键

Command + Shift + 3: 对整个屏幕进行截屏,图片自动保存在桌面上Command + Ctrl + Shift + 3:对整个屏幕截屏,图片保存到剪贴板中.Command + Shift + 4:这个感觉不错,对选定区域进行截屏,图片保存在桌面上.Command + Ctrl + Shift + 4:对选定区域进行截屏,图片被保存到剪贴板中.