失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 相机截图(区域截图 长图 大图)

相机截图(区域截图 长图 大图)

时间:2024-07-05 03:51:08

相关推荐

相机截图(区域截图 长图 大图)

单独创建一个相机和画布实现截取一部分图,或者长图,传入的obj需含有“RectTransform”便于获取所截区域的大小,即obj的尺寸就是截图的尺寸。

我传入的是Content对象,组件有ContentSizeFitter,因为适应宽高刷新不及时,如果不调用延时的话,可能会报错“Reading pixels out of bounds of the current active render texture”,如果没有该组件可以不用延时。

在设置相机画布尺寸后延时DelayCaptureTexture渲染,为了适配好宽高,不然渲染出的是很小的图,是因为画布默认的宽高是窗口的大小,截出的有效区很小。

相机清除时_camera.clearFlags = CameraClearFlags.Depth在真机上截图效果花屏,应改为CameraClearFlags.SolidColor。

private Canvas _canvas;private Camera _camera;private RenderTexture _renderTexture;private RectTransform _rectTransformObj;private GameObject _objClone;private Texture2D _texture2D;public void DoScreenShot(GameObject obj){CreateCanvas();DoCloneGameObject(obj);}//创建画布 画布的尺寸随相机视口大小private void CreateCanvas(){if (_canvas == null){_canvas = new GameObject("ScreenShotCanvas").AddComponent<Canvas>();_canvas.renderMode = RenderMode.ScreenSpaceCamera;CreateCamera();_canvas.worldCamera = _camera;_canvas.gameObject.GetOrAddComponent<CanvasScaler>();_canvas.gameObject.GetOrAddComponent<GraphicRaycaster>();}}//创建相机private void CreateCamera(){_camera = new GameObject("ScreenShotCamera").AddComponent<Camera>();_camera.transform.localPosition = new Vector3(30, 0, -10);_camera.transform.localScale = Vector3.one;//_camera.clearFlags = CameraClearFlags.Depth;_camera.clearFlags = CameraClearFlags.SolidColor;_camera.backgroundColor = new Color32(0, 0, 0, 0);_camera.cullingMask = -1;_camera.orthographic = true;_camera.orthographicSize = 1.5f;_camera.depth = -2;}//克隆需要截图的对象private void DoCloneGameObject(GameObject obj){_objClone = GameObject.Instantiate(obj) as GameObject;_rectTransformObj = _objClone.GetComponent<RectTransform>();_objClone.transform.SetParent(_canvas.transform);_rectTransformObj.pivot = new Vector2(0.5f, 0.5f);_rectTransformObj.anchorMax = new Vector2(0.5f, 0.5f);_rectTransformObj.anchorMin = new Vector2(0.5f, 0.5f);_rectTransformObj.sizeDelta = obj.GetComponent<RectTransform>().rect.size;_objClone.transform.localPosition = Vector3.zero;_objClone.transform.localScale = Vector3.one;StartCoroutine(DelaySetSize());}//延时设置_renderTexture的尺寸,相机的尺寸随_renderTexture的尺寸private IEnumerator DelaySetRenderTextureSize(){yield return new WaitForEndOfFrame();_renderTexture = new RenderTexture((int)_rectTransformObj.rect.width, (int)_rectTransformObj.rect.height, 24,RenderTextureFormat.ARGB32);_camera.targetTexture = _renderTexture;StartCoroutine(DelayCaptureTexture());}private IEnumerator DelayCaptureTexture(){yield return new WaitForEndOfFrame();_camera.RenderDontRestore();_renderTexture.filterMode = FilterMode.Bilinear;_camera.Render();_texture2D = new Texture2D((int)_rectTransformObj.rect.width, (int)_rectTransformObj.rect.height,TextureFormat.ARGB32, false);_texture2D.ReadPixels(new Rect(0, 0, _rectTransformObj.rect.width, _rectTransformObj.rect.height), 0, 0);_texture2D.Apply();ScreenShotImage();_camera.targetTexture = null;GameObject.Destroy(_objClone);}//生成图片并保存private void ScreenShotImage(){byte[] bytes = _texture2D.EncodeToPNG();press(true);_texture2D.Apply();string fileDir = Application.dataPath + "/ScreenShot";if (!Directory.Exists(fileDir)){Directory.CreateDirectory(fileDir);}string filePath = fileDir + "/ScreenShotImage.png";File.WriteAllBytes(filePath, bytes);Debug.Log("截取了一张图片:"+ filePath);}

上面使用的方法是基于画布的Canvas Scaler组件的缩放模式(UI Scale Mode)为Constant Pixel Size画布尺寸同像素大小及Camera的Target Texture。这种方法有个问题的,当传入的obj是关于文字排版时,克隆出的对象和主相机中的对象排版不一,尤其是文字下有下划线时更明显,其他情况下都是OK的。

后面使用的截图方法缩放模式是Scale With Screen Size。

截图读取像素从左下角开始,克隆对象轴点和锚点设置为0,代码段如下:

_rectTransformObj.pivot = Vector2.zero;_rectTransformObj.anchorMax = Vector2.zero;_rectTransformObj.anchorMin = Vector2.zero;_rectTransformObj.sizeDelta = _cloneObjSize;_rectTransformObj.anchoredPosition3D = Vector3.zero;_objClone.transform.localScale = Vector3.one;_objClone.transform.localEulerAngles = Vector3.zero;

private Texture2D GetScreenTexture(Camera _camera,RectTransform _rectTransformObj){RenderTexture rt = RenderTexture.GetTemporary((int)(_canvasSize.x), (int)(_canvasSize.y));_camera.targetTexture = rt;_camera.Render();RenderTexture.active = rt;Texture2D _texture2D;_texture2D = new Texture2D((int)(_rectTransformObj.rect.width), (int)(_rectTransformObj.rect.height/0.95f), TextureFormat.ARGB32, false);_texture2D.ReadPixels(new Rect(0, 0f, (int)(_rectTransformObj.rect.width), (int)(_rectTransformObj.rect.height/0.95f)), 0, 0);_texture2D.Apply();byte[] bytes = _texture2D.EncodeToPNG();_camera.targetTexture = null;RenderTexture.active = null; RenderTexture.ReleaseTemporary(rt);string fileDir = Application.dataPath + "/ScreenShot";if (!Directory.Exists(fileDir)){Directory.CreateDirectory(fileDir);}string filePath = fileDir + "/ScreenShotImage.png";File.WriteAllBytes(filePath, bytes);Debug.Log("截取了一张图片:"+ filePath);return _texture2D;}

上面这种是截取canvas内指定的区域的图片,如果obj尺寸大于canvas的宽或高则等比缩放到canvas内。这种方法有个问题是缩小比例越大,截图放大后就失真越多越模糊。

private void CaptureTexture(int surplusWidth, int surplusHeight, int addX = 0, int addY = 0){Texture2Ds texture2Ds = new Texture2Ds();texture2Ds._X = addX;texture2Ds._Y = addY;if (surplusWidth <= (int)(_canvasSize.x)){if (surplusHeight <= (int)(_canvasSize.y)){texture2Ds._Texture2D = DoCaptureTexture(surplusWidth, surplusHeight);_listTexture2D.Add(texture2Ds);}else{texture2Ds._Texture2D = DoCaptureTexture(surplusWidth, (int)(_canvasSize.y));_listTexture2D.Add(texture2Ds);_rectTransformObj.anchoredPosition3D = new Vector3(_rectTransformObj.anchoredPosition3D.x,_rectTransformObj.anchoredPosition3D.y - (int)(_canvasSize.y), 0);CaptureTexture(surplusWidth, surplusHeight - (int)(_canvasSize.y), addX, addY + (int)(_canvasSize.y));}}else if (surplusWidth > (int)(_canvasSize.x)){if (surplusHeight <= (int)(_canvasSize.y)){texture2Ds._Texture2D = DoCaptureTexture((int)(_canvasSize.x), surplusHeight);_listTexture2D.Add(texture2Ds);_rectTransformObj.anchoredPosition3D = new Vector3(_rectTransformObj.anchoredPosition3D.x-(int)(_canvasSize.x),_rectTransformObj.anchoredPosition3D.y, 0);CaptureTexture(surplusWidth-(int)(_canvasSize.x), surplusHeight, addX+(int)(_canvasSize.x), addY );}else{texture2Ds._Texture2D = DoCaptureTexture((int)(_canvasSize.x), (int)(_canvasSize.y));_listTexture2D.Add(texture2Ds);_rectTransformObj.anchoredPosition3D = new Vector3(_rectTransformObj.anchoredPosition3D.x-(int)(_canvasSize.x),_rectTransformObj.anchoredPosition3D.y - (int)(_canvasSize.y), 0);CaptureTexture(surplusWidth-(int)(_canvasSize.x), surplusHeight - (int)(_canvasSize.y), addX+(int)(_canvasSize.x), addY + (int)(_canvasSize.y));}}}private Texture2D DoCaptureTexture(int width,int height){RenderTexture rt = RenderTexture.GetTemporary((int)_canvasSize.x,(int)_canvasSize.y);_camera.targetTexture = rt;_camera.Render();RenderTexture.active = rt;Texture2D texture2D = new Texture2D(width, height, TextureFormat.ARGB32, false);texture2D.ReadPixels(new Rect(0, 0f, width, height), 0, 0);texture2D.Apply();_camera.targetTexture = null;RenderTexture.active = null;RenderTexture.ReleaseTemporary(rt);return texture2D;}//拼图private void MergeTexture2D(){_texture2D = new Texture2D((int)_cloneObjSize.x, (int)_cloneObjSize.y);int w = 0;int h = 0;for (int i = 0; i < _listTexture2D.Count; i++){//取图Color32[] color = _listTexture2D[i]._Texture2D.GetPixels32(0);//赋给新图if (i > 0){if (_listTexture2D[i]._X > _listTexture2D[i - 1]._X)_texture2D.SetPixels32(w += _listTexture2D[i - 1]._Texture2D.width, h,_listTexture2D[i]._Texture2D.width, _listTexture2D[i]._Texture2D.height, color); //宽度else_texture2D.SetPixels32(w, h += _listTexture2D[i - 1]._Texture2D.height,_listTexture2D[i]._Texture2D.width, _listTexture2D[i]._Texture2D.height, color); //高度}else{_texture2D.SetPixels32(w, h, _listTexture2D[i]._Texture2D.width, _listTexture2D[i]._Texture2D.height, color);}}//应用_texture2D.Apply();byte[] bytes = _texture2D.EncodeToPNG();string fileDir = Application.dataPath + "/ScreenShot";if (!Directory.Exists(fileDir)){Directory.CreateDirectory(fileDir);}string filePath = fileDir + "/ScreenShotImage.png";File.WriteAllBytes(filePath, bytes);Debug.Log("截取了一张图片:"+ filePath);}

调用方法CaptureTexture((int)_cloneObjSize.x, (int)_cloneObjSize.y);传入克隆对象的宽高,传入值必须是整型,因为像素是整型,画布尺寸也需是整型。在调用前先动态获取下_canvasSize的尺寸,如果在创建画布后就获取它的尺寸,还来不及适应,获取的值就不对,裁剪时尺寸会对不上,从而裁剪不完全。

上面这种方法是不用缩放obj的,即使obj的尺寸远远大于画布尺寸,思路是先裁剪再拼图,这种就不会失真了。

如果觉得《相机截图(区域截图 长图 大图)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。