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

356 lines
12 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 = "";
private RenderTexture _renderTexture;
private Texture2D _originalTexture;
private Texture2D _croppedTexture;
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;
}
protected virtual void Init()
{
}
public IEnumerator CaptureAndCrop(Action<byte[]> callback = null)
{
// 确保尺寸有效
ValidateSizes();
// 创建原始截图
yield return StartCoroutine(CaptureOriginalScreenshot());
// 裁剪图片(保留透明通道)
CropWithTransparency();
// 保存结果
SaveCroppedImage();
// 清理资源
CleanupResources();
callback?.Invoke(bytes);
}
// 【核心修改】优化截图渲染流程避免RT显示在屏幕上
private IEnumerator CaptureOriginalScreenshot()
{
// 1. 保存相机原始状态(增加关键状态保存)
RenderTexture originalRT = targetCamera.targetTexture;
CameraClearFlags originalClearFlags = targetCamera.clearFlags;
Color originalBackgroundColor = targetCamera.backgroundColor;
bool originalEnabled = targetCamera.enabled; // 保存相机启用状态
// bool originalRenderInEditMode = targetCamera.renderInEditMode; // 编辑模式渲染状态
// 2. 创建临时RenderTexture
_renderTexture = RenderTexture.GetTemporary(
captureWidth,
captureHeight,
32,
RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear
);
try
{
// 3. 配置相机仅渲染到RT不显示在屏幕
targetCamera.enabled = false; // 禁用相机的自动渲染
// targetCamera.renderInEditMode = true; // 允许编辑模式渲染
targetCamera.targetTexture = _renderTexture;
targetCamera.clearFlags = CameraClearFlags.SolidColor;
targetCamera.backgroundColor = preserveAlpha ? backgroundColor : Color.black;
// 4. 手动渲染相机到RT此操作不会显示在屏幕
targetCamera.Render();
// 5. 读取RT像素到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
{
// 6. 无论是否出错,都强制恢复相机设置
targetCamera.targetTexture = originalRT;
targetCamera.clearFlags = originalClearFlags;
targetCamera.backgroundColor = originalBackgroundColor;
targetCamera.enabled = originalEnabled;
// targetCamera.renderInEditMode = originalRenderInEditMode;
RenderTexture.active = null; // 强制取消RT激活状态
}
yield return null;
}
private IEnumerator CaptureOriginalScreenshot1()
{
// 创建RenderTexture带alpha通道
_renderTexture = new RenderTexture(captureWidth, captureHeight, 32, RenderTextureFormat.ARGB32);
_renderTexture.Create();
// 保存原始相机设置
RenderTexture originalRT = targetCamera.targetTexture;
CameraClearFlags originalClearFlags = targetCamera.clearFlags;
Color originalBackgroundColor = targetCamera.backgroundColor;
// 配置相机透明背景
targetCamera.targetTexture = _renderTexture;
targetCamera.clearFlags = CameraClearFlags.SolidColor;
targetCamera.backgroundColor = preserveAlpha ? backgroundColor : Color.black;
// 渲染相机
targetCamera.Render();
// 创建Texture2D带alpha通道
_originalTexture = new Texture2D(captureWidth, captureHeight,
preserveAlpha ? TextureFormat.ARGB32 : TextureFormat.RGB24,
false);
// 读取像素包括alpha
RenderTexture.active = _renderTexture;
_originalTexture.ReadPixels(new Rect(0, 0, captureWidth, captureHeight), 0, 0);
_originalTexture.Apply();
RenderTexture.active = null;
// 恢复相机设置
targetCamera.targetTexture = originalRT;
targetCamera.clearFlags = originalClearFlags;
targetCamera.backgroundColor = originalBackgroundColor;
yield return null;
}
string fullPath;
public string FullPath => fullPath;
private 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);
// 创建裁剪后的纹理带alpha通道
_croppedTexture = new Texture2D(cropWidth, cropHeight,
preserveAlpha ? TextureFormat.ARGB32 : TextureFormat.RGB24,
false);
// 获取原始纹理的像素数据包括alpha
Color[] pixels = _originalTexture.GetPixels(startX, startY, cropWidth, cropHeight);
// 设置到裁剪纹理
_croppedTexture.SetPixels(pixels);
_croppedTexture.Apply();
}
// public static void SaveImage(Texture2D tex, string name)
// {
// byte[] bytes = tex.EncodeToPNG();
// var dirPath = "SaveImages/";
// if (!Directory.Exists(dirPath))
// {
// Directory.CreateDirectory(dirPath);
// }
// File.WriteAllBytes(dirPath + name + ".png", B83.Image.PNGTools.ChangePPI(bytes, 300, 300));
// }
private 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 dpiName;
if (string.IsNullOrEmpty(onlyFileName))
fileName = $"{fileNamePrefix}_{cropWidth}x{cropHeight}_{timestamp}{extension}";
else
fileName = $"{onlyFileName}{extension}";
dpiName = $"{fileNamePrefix}_{cropWidth}x{cropHeight}_{timestamp}_DPI_{extension}";
fullPath = Path.Combine(folderPath, fileName);
var dpiFullPath = Path.Combine(folderPath, dpiName);
// 编码保存
byte[] imageBytes;
if (saveAsPNG)
{
imageBytes = _croppedTexture.EncodeToPNG();
}
else
{
// JPG不支持透明通道强制去除alpha
Texture2D jpgTexture =
new Texture2D(_croppedTexture.width, _croppedTexture.height, TextureFormat.RGB24, false);
jpgTexture.SetPixels(_croppedTexture.GetPixels());
jpgTexture.Apply();
imageBytes = jpgTexture.EncodeToJPG(90);
Destroy(jpgTexture);
}
// File.WriteAllBytes(fullPath, imageBytes);
ImageDpiProcessor.SaveTextureWithDpi(_croppedTexture, fullPath, 300);
Debug.Log($"save as: {fullPath}");
// 验证透明度
if (saveAsPNG && preserveAlpha)
{
// 检查左上角像素是否透明
Color topLeft = _croppedTexture.GetPixel(0, _croppedTexture.height - 1);
Debug.Log($"保存的图片左上角透明度: {topLeft.a}");
// 检查中心像素是否透明
Color center = _croppedTexture.GetPixel(_croppedTexture.width / 2, _croppedTexture.height / 2);
Debug.Log($"保存的图片中心透明度: {center.a}");
}
Debug.Log($"截图已保存至: {fullPath}");
bytes = File.ReadAllBytes(fullPath);
// NetworkUpload.instance.miniCooperData.items[0].preview1 = System.Convert.ToBase64String(bytes);
#if UNITY_EDITOR
UnityEditor.EditorUtility.RevealInFinder(fullPath);
#endif
}
byte[] bytes;
private 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);
// 确保偏移量在0-1范围
cropOffset.x = Mathf.Clamp01(cropOffset.x);
cropOffset.y = Mathf.Clamp01(cropOffset.y);
}
private void CleanupResources()
{
if (_renderTexture != null)
{
Destroy(_renderTexture);
_renderTexture = null;
}
if (_originalTexture != null)
{
Destroy(_originalTexture);
_originalTexture = null;
}
// 保留裁剪纹理用于预览或后续使用
// 如果不再需要,可以取消注释下面一行
Destroy(_croppedTexture);
}
[ContextMenu("立即截图并裁剪")]
public virtual void CaptureAndCropNow(Action<byte[]> callback = null)
{
StartCoroutine(CaptureAndCrop(callback));
}
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), "包含透明通道");
}
}
}
void OnDestroy()
{
CleanupResources();
if (_croppedTexture != null)
{
Destroy(_croppedTexture);
_croppedTexture = null;
}
}
}