FM/Assets/Scripts/Base/Tool/TransparentCaptureSystem.cs

322 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using UnityEngine;
using System.IO;
using System.Collections;
using System;
using Zenith;
public class TransparentCaptureSystem<T> : 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<byte[]> 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<byte[]> 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子类可重写添加逻辑 --------------
/// <summary>Start后触发</summary>
protected virtual void OnStart()
{
}
/// <summary>截图流程开始前触发</summary>
protected virtual void OnBeforeCapture()
{
}
/// <summary>原始截图完成后触发</summary>
protected virtual void OnAfterCaptureOriginal()
{
}
/// <summary>裁剪完成后触发</summary>
protected virtual void OnAfterCrop()
{
}
/// <summary>保存完成后触发</summary>
protected virtual void OnAfterSave()
{
}
/// <summary>整个截图流程完成后触发</summary>
protected virtual void OnCaptureComplete()
{
}
// -------------- 字段保护 --------------
protected string fullPath;
public string FullPath => fullPath; // 保留路径访问
}