using UnityEngine; using System.IO; using System.Collections; using System; using Zenith; public class TransparentCaptureSystem : MonoBehaviour { [Header("相机设置")] public Camera targetCamera; public KeyCode captureKey = KeyCode.C; [Header("原始截图设置")] public int captureWidth = 1080; public int captureHeight = 1920; [Header("裁剪设置")] public int cropWidth = 1080; public int cropHeight = 1920; public Vector2 cropOffset = Vector2.zero; // 裁剪偏移量 (0-1) [Header("透明通道")] public bool preserveAlpha = true; public Color backgroundColor = new Color(0, 0, 0, 0); // 透明背景 [Header("输出设置")] public string saveFolder = "Screenshots"; public string fileNamePrefix = "Screenshot"; public bool saveAsPNG = true; public string onlyFileName = ""; // 改为protected,允许子类访问关键资源 protected RenderTexture _renderTexture; protected Texture2D _originalTexture; protected Texture2D _croppedTexture; protected byte[] bytes; // 图片字节数组,子类可直接使用 public Transform uiRoot; public static T Instance; private void Awake() { // 读取保存路径逻辑保留 var allText = File.ReadAllText(Application.streamingAssetsPath + "/picSavePath.txt"); if (string.IsNullOrEmpty(allText)) { #if !UNITY_EDITOR saveFolder = Path.Combine(Application.dataPath, "Screenshots"); #endif } else { saveFolder = allText; } Init(); } void Start() { if (targetCamera == null) targetCamera = Camera.main; OnStart(); // 启动钩子 } // 初始化方法,允许子类重写 protected virtual void Init() { if (Instance == null) Instance = (T)(object)this; } // 主流程:截图并裁剪(保留原有逻辑) public IEnumerator CaptureAndCrop(Action callback = null) { OnBeforeCapture(); // 截图前钩子 ValidateSizes(); // 创建原始截图 yield return StartCoroutine(CaptureOriginalScreenshot()); OnAfterCaptureOriginal(); // 原始截图后钩子 // 裁剪图片 CropWithTransparency(); OnAfterCrop(); // 裁剪后钩子 // 保存结果 SaveCroppedImage(); OnAfterSave(); // 保存后钩子 // 清理资源 CleanupResources(); callback?.Invoke(bytes); OnCaptureComplete(); // 完整流程结束钩子 } // 【核心】原始截图方法(标记为virtual,允许子类重写) protected virtual IEnumerator CaptureOriginalScreenshot() { // 保存相机原始状态 RenderTexture originalRT = targetCamera.targetTexture; CameraClearFlags originalClearFlags = targetCamera.clearFlags; Color originalBackgroundColor = targetCamera.backgroundColor; bool originalEnabled = targetCamera.enabled; // 创建临时RenderTexture _renderTexture = RenderTexture.GetTemporary( captureWidth, captureHeight, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear ); try { // 配置相机仅渲染到RT targetCamera.enabled = false; targetCamera.targetTexture = _renderTexture; targetCamera.clearFlags = CameraClearFlags.SolidColor; targetCamera.backgroundColor = preserveAlpha ? backgroundColor : Color.black; // 手动渲染 targetCamera.Render(); // 读取像素到Texture2D RenderTexture.active = _renderTexture; _originalTexture = new Texture2D(captureWidth, captureHeight, preserveAlpha ? TextureFormat.ARGB32 : TextureFormat.RGB24, false); _originalTexture.ReadPixels(new Rect(0, 0, captureWidth, captureHeight), 0, 0); _originalTexture.Apply(); } finally { // 恢复相机设置 targetCamera.targetTexture = originalRT; targetCamera.clearFlags = originalClearFlags; targetCamera.backgroundColor = originalBackgroundColor; targetCamera.enabled = originalEnabled; RenderTexture.active = null; } yield return null; } // 裁剪逻辑(标记为virtual) protected virtual void CropWithTransparency() { if (_originalTexture == null) { Debug.LogError("原始截图未创建!"); return; } // 计算裁剪起始位置 int startX = Mathf.FloorToInt((_originalTexture.width - cropWidth) * cropOffset.x); int startY = Mathf.FloorToInt((_originalTexture.height - cropHeight) * cropOffset.y); // 边界检查 startX = Mathf.Clamp(startX, 0, _originalTexture.width - cropWidth); startY = Mathf.Clamp(startY, 0, _originalTexture.height - cropHeight); // 创建裁剪纹理 _croppedTexture = new Texture2D(cropWidth, cropHeight, preserveAlpha ? TextureFormat.ARGB32 : TextureFormat.RGB24, false); // 设置像素 Color[] pixels = _originalTexture.GetPixels(startX, startY, cropWidth, cropHeight); _croppedTexture.SetPixels(pixels); _croppedTexture.Apply(); } // 保存逻辑(标记为virtual) protected virtual void SaveCroppedImage() { if (_croppedTexture == null) { Debug.LogError("裁剪后的纹理未创建!"); return; } // 创建保存目录 string folderPath = saveFolder; if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath); // 生成文件名 string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); string extension = saveAsPNG ? ".png" : ".jpg"; string fileName = string.IsNullOrEmpty(onlyFileName) ? $"{fileNamePrefix}_{cropWidth}x{cropHeight}_{timestamp}{extension}" : $"{onlyFileName}{extension}"; fullPath = Path.Combine(folderPath, fileName); // 编码图片 byte[] imageBytes = saveAsPNG ? _croppedTexture.EncodeToPNG() : EncodeToJPG(_croppedTexture); // 保存并读取字节数组 ImageDpiProcessor.SaveTextureWithDpi(_croppedTexture, fullPath, 300); fullPath = new FileInfo(fullPath).FullName; Debug.Log($"截图已保存至: {fullPath}"); bytes = File.ReadAllBytes(fullPath); #if UNITY_EDITOR UnityEditor.EditorUtility.RevealInFinder(fullPath); #endif } // JPG编码辅助方法(protected,允许子类复用) protected byte[] EncodeToJPG(Texture2D texture) { Texture2D jpgTexture = new Texture2D(texture.width, texture.height, TextureFormat.RGB24, false); jpgTexture.SetPixels(texture.GetPixels()); jpgTexture.Apply(); byte[] bytes = jpgTexture.EncodeToJPG(90); Destroy(jpgTexture); return bytes; } // 尺寸验证(标记为virtual) protected virtual void ValidateSizes() { captureWidth = Mathf.Clamp(captureWidth, 32, SystemInfo.maxTextureSize); captureHeight = Mathf.Clamp(captureHeight, 32, SystemInfo.maxTextureSize); cropWidth = Mathf.Clamp(cropWidth, 32, captureWidth); cropHeight = Mathf.Clamp(cropHeight, 32, captureHeight); cropOffset.x = Mathf.Clamp01(cropOffset.x); cropOffset.y = Mathf.Clamp01(cropOffset.y); } // 资源清理(标记为virtual) protected virtual void CleanupResources() { if (_renderTexture != null) { RenderTexture.ReleaseTemporary(_renderTexture); _renderTexture = null; } if (_originalTexture != null) { Destroy(_originalTexture); _originalTexture = null; } if (_croppedTexture != null) { Destroy(_croppedTexture); _croppedTexture = null; } } // 立即截图方法(保留) [ContextMenu("立即截图并裁剪")] public virtual void CaptureAndCropNow(Action callback = null) { StartCoroutine(CaptureAndCrop(callback)); } // GUI预览(标记为virtual) protected virtual void OnGUI() { // 显示原始截图预览 if (_originalTexture != null) { GUI.DrawTexture(new Rect(10, 10, 200, 200 * (float)captureHeight / captureWidth), _originalTexture, ScaleMode.ScaleToFit); GUI.Label(new Rect(10, 220, 200, 30), $"原始尺寸: {captureWidth}x{captureHeight}"); } // 显示裁剪后截图预览 if (_croppedTexture != null) { GUI.DrawTexture(new Rect(Screen.width - 210, 10, 200, 200 * (float)cropHeight / cropWidth), _croppedTexture, ScaleMode.ScaleToFit); GUI.Label(new Rect(Screen.width - 210, 220, 200, 30), $"裁剪尺寸: {cropWidth}x{cropHeight}"); if (preserveAlpha) { GUI.Label(new Rect(Screen.width - 210, 250, 200, 30), "包含透明通道"); } } } // 销毁时清理(保留) protected virtual void OnDestroy() { CleanupResources(); } // -------------- 钩子方法(Hook):子类可重写添加逻辑 -------------- /// Start后触发 protected virtual void OnStart() { } /// 截图流程开始前触发 protected virtual void OnBeforeCapture() { } /// 原始截图完成后触发 protected virtual void OnAfterCaptureOriginal() { } /// 裁剪完成后触发 protected virtual void OnAfterCrop() { } /// 保存完成后触发 protected virtual void OnAfterSave() { } /// 整个截图流程完成后触发 protected virtual void OnCaptureComplete() { } // -------------- 字段保护 -------------- protected string fullPath; public string FullPath => fullPath; // 保留路径访问 }