一、前言
本文要讲的录屏不是使用Unity自带的那个截屏方法,因为unity自带的都只能截取unity程序本身显示的画面内容,至于unity程序之外的内容,如电脑桌面上的其他的程序内容是无法录屏的。本文所讲的内容是采用C#本身的截屏方法,效果如图所示:
使用的Unity版本为Unity2018.4.17。
二、实现
1、基本思路:先通过C#获取到屏幕的数据,再转换成Unity的Texture,获取很简单,主要是这个转换的过程会比较的棘手。
2、获取截图数据代码如下,获取的是C#里面的Bitmap类型
Bitmap bit = new Bitmap(shotScreenRect.width,shotScreenRect.height);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bit);
g.CopyFromScreen(shotScreenRect.x, shotScreenRect.y, 0,0, bit.Size);
先要转换成字节数组Byte[],然后再转成Texture,完整的代码如下
using UnityEngine;
using UnityEngine.UI;
using System.Drawing;
using System.IO;
using System;
using System.Threading;
using System.Drawing.Imaging;
public class CaptureScreen : MonoBehaviour
{
public RawImage shotShowImage;//显示视频的组件
public RectInt shotScreenRect;//截图的区域和宽高
private Thread threadGetData;//截图的线程
private static byte[] ShotScreenData;//截图的临时数据数组
private static bool LoadImageOver = false;//没截张图要等到下一次加载完
void Start()
{
threadGetData = new Thread(new ThreadStart(Thread_GetScreenData));
threadGetData.IsBackground = true;
threadGetData.Start();
}
// Update is called once per frame
void Update()
{
//将截取的图片的数据转换成Texture2D
if (ShotScreenData != null&&LoadImageOver)
{
Texture2D tempTex = new Texture2D(shotScreenRect.width, shotScreenRect.height);
tempTex.LoadImage(ShotScreenData);
shotShowImage.texture = tempTex;
shotShowImage.SetNativeSize();
LoadImageOver = false;
}
if(Input.GetKeyDown(KeyCode.Escape))
{
Application.Quit();
}
}
///
/// 开启线程截图获得数据
///
private void Thread_GetScreenData()
{
try
{
while (true)
{
if (!LoadImageOver)
{
MemoryStream ms = new MemoryStream();
CompressImage(GetScreen(), ms);
ShotScreenData = ms.ToArray();
LoadImageOver = true;
}
//Thread.Sleep(1000);
}
}
catch (Exception ee)
{
Debug.LogError(ee.Message);
return;
}
}
private void OnApplicationQuit()
{
if(null!= threadGetData)
threadGetData.Abort();
}
///
/// 截取一张图片
///
///
private Bitmap GetScreen()
{
Bitmap bit = new Bitmap(shotScreenRect.width,shotScreenRect.height);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bit);
g.CopyFromScreen(shotScreenRect.x, shotScreenRect.y, 0,0, bit.Size);
return bit;
}
///
/// 获取图片编码信息
///
/// 编码类型
/// ImageCodecInfo
private ImageCodecInfo getImageCoderInfo(string coderType)
{
ImageCodecInfo[] iciS = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo retIci = null;
foreach (ImageCodecInfo ici in iciS)
{
if (ici.MimeType.Equals(coderType))
retIci = ici;
}
return retIci;
}
///
/// 压缩图片
///
///
///
private void CompressImage(Bitmap bitmap, MemoryStream ms)
{
ImageCodecInfo ici = null;
Encoder ecd = null;
EncoderParameter ept = null;
EncoderParameters eptS = null;
try
{
ici = this.getImageCoderInfo("image/jpeg");
ecd = Encoder.Quality;
eptS = new EncoderParameters(1);
ept = new EncoderParameter(ecd, 10L);
eptS.Param[0] = ept;
bitmap.Save(ms, ici, eptS);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
ept.Dispose();
eptS.Dispose();
}
}
}
3、这里使用的Bitmap类型以及其他相关的类都是在System.Drawing.dll的动态链接库中,这个链接库在unity的安装文件中可以找到,但是要注意的是找到正确的版本,我因为一开始使用的是“Unity2018.4.17\Editor\Data\Mono\lib\mono\2.0”下的“System.Drawing.dll",在Editor模式下没有问题,但是发布之后会报“ Fallback handler could not load library Mono/libc.dll”这样的错误,看Log信息应该知道是dll加载的问题,无法加载。直到我一个个试才找到“Unity2018.4.17\Editor\Data\MonoBleedingEdge\lib\mono\unityjit”路径下的这个“System.Drawing.dll"是可以用的版本。
4、最后是Unity的设置如图
三、总结
1、使用unity自带的截图又一定的局限性,想要录取其他的程序或电脑桌面的内容还是要借助C#本身的API;
2、动态链接库的版本一定要控制好。