FM/Assets/Scripts/FUJIFILM/Other/DoubleCaptureSystem.cs

668 lines
28 KiB
C#
Raw Normal View History

2025-08-22 00:33:25 +08:00
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
2025-08-22 00:33:25 +08:00
using System.IO;
using UnityEngine.UI;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Processing;
namespace HK.FUJIFILM
{
public class DoubleCaptureSystem : TransparentCaptureSystem<DoubleCaptureSystem>
{
/// <summary>
/// 执行两次截图并裁剪,支持分别定制参数
/// </summary>
/// <param name="onBothComplete">两次都完成后的回调(返回两次的字节数组)</param>
public void CaptureTwice(Action<byte[], byte[]> onBothComplete)
{
StartCoroutine(CoCaptureTwice(onBothComplete));
}
/// <summary>
/// 一开多
/// </summary>
/// <param name="onBothComplete"></param>
public void CaptureTwice_ManyToMany(Action<List<byte[]>, List<byte[]>> onBothComplete)
{
StartCoroutine(CoCaptureTwice_ManyToMany(onBothComplete));
}
public void CaptureTwice_OneToMany(Action<byte[], List<byte[]>> onBothComplete)
{
StartCoroutine(CoCaptureTwice_OneToMany(onBothComplete));
}
public void CaptureOnlyDesign(Action<byte[],string> onBothComplete)
2025-08-22 00:33:25 +08:00
{
StartCoroutine(CoCaptureOnlyDesign(onBothComplete));
}
#if UNITY_EDITOR
[ContextMenu("CaptureTwice")]
public void Test()
{
StartCoroutine(CoCaptureTwice(null));
}
#endif
float ConvertMmToPixel(float mm, int dpi = 300)
{
return mm * (dpi / 25.4f);
}
// private void Update()
// {
// if (Input.GetKeyDown(KeyCode.J))
// {
// UnityEngine.Debug.LogError($"px is {ConvertMmToPixel(85.6f)}");
// }
// }
// 协程:顺序执行两次截图
private IEnumerator CoCaptureTwice(Action<byte[], byte[]> onBothComplete)
{
// 存储两次截图的结果
byte[] firstResult = null;
byte[] secondResult = null;
var tmpSaveFolder = saveFolder;
2025-08-22 00:33:25 +08:00
saveFolder = Path.Combine(saveFolder, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
onlyFileName = "PreviewImage1";
var mugActualModelRenderFixed = uiRoot.GetComponent<MugActualModelRender_Fixed>();
var image = mugActualModelRenderFixed.designParent.GetChild(0).GetComponent<UnityEngine.UI.Image>();
image.enabled = true;
// 第一次截图(使用基类默认参数)
Debug.Log("开始第一次截图...");
yield return StartCoroutine(CaptureAndCrop((firstBytes) =>
{
firstResult = firstBytes;
Debug.Log("第一次截图完成");
}));
image.enabled = false;
// 确保第一次完成后再执行第二次
if (firstResult == null)
{
Debug.LogError("第一次截图失败,取消第二次");
onBothComplete?.Invoke(null, null);
yield break;
}
bool tmpImageActive = image.enabled;
image.enabled = mugActualModelRenderFixed.productScriptableObject.isShowTemplate;
var verticalLayoutGroup = mugActualModelRenderFixed.designParent.GetComponent<VerticalLayoutGroup>();
verticalLayoutGroup.enabled = true;
var tmpWidth = cropWidth;
var tmpHeight = cropHeight;
var productScriptableObject = mugActualModelRenderFixed.productScriptableObject;
var screenshotSize = productScriptableObject.screenshotSize;
cropWidth = (int)screenshotSize.x;
cropHeight = (int)screenshotSize.y;
cropOffset = new Vector2(0.5f, 0.5f);
onlyFileName = "DesignImage1";
// 第二次截图(使用修改后的参数)
Debug.Log("开始第二次截图...");
yield return StartCoroutine(CaptureAndCrop((secondBytes) =>
{
secondResult = secondBytes;
Debug.Log("第二次截图完成");
}));
image.enabled = tmpImageActive;
2025-08-22 00:33:25 +08:00
// 1. 校验文件是否存在
var fileInfo = new FileInfo(fullPath);
if (!fileInfo.Exists)
{
Debug.LogError($"原始图片不存在:{fullPath}");
secondResult = null;
yield break; // 若在协程中,用 yield break 退出
}
try
{
// 2. 加载图像并校验原始尺寸
using (var sImage = SixLabors.ImageSharp.Image.Load(fileInfo.FullName))
{
// 校验原始图片尺寸是否有效
if (sImage.Width <= 0 || sImage.Height <= 0)
{
Debug.LogError($"加载的图片尺寸无效:宽={sImage.Width}, 高={sImage.Height}");
secondResult = null;
yield break;
}
if (productScriptableObject.printingSize.x != 0)
{
// 3. 校验缩放宽度是否有效
int targetWidth = (int)ConvertMmToPixel(productScriptableObject.printingSize.x);
int targetHeight = (int)ConvertMmToPixel(productScriptableObject.printingSize.y);
if (targetWidth <= 0)
{
Debug.LogError($"缩放宽度无效(必须大于 0{targetWidth}");
// 可选:使用默认宽度(如 200避免错误
targetWidth = 200;
}
// 4. 等比缩放(确保目标尺寸有效)
// sImage.Mutate(x => x.Resize(new ResizeOptions
// {
// Size = new Size(targetWidth, targetHeight), // 高度为0则自动计算
// Mode = ResizeMode.Max,
// Sampler = KnownResamplers.Lanczos3 // 高质量缩放算法
// }));
// 强制缩放
sImage.Mutate(x => x.Resize(targetWidth, targetHeight));
}
// 5. 确保保存目录存在
if (!Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder); // 自动创建目录
}
// 6. 保存缩放后的图片
var filePath = Path.Combine(saveFolder, "Printing1.png");
sImage.SaveAsPng(filePath, new PngEncoder());
// 7. 校验保存结果并读取字节数组
if (File.Exists(filePath))
{
secondResult = File.ReadAllBytes(filePath);
Debug.Log($"第二次截图缩放后保存至:{filePath}");
}
else
{
Debug.LogError($"图片保存失败,文件不存在:{filePath}");
secondResult = null;
}
}
}
catch (Exception ex)
{
// 捕获所有异常(如图片格式错误、权限问题等)
Debug.LogError($"图片处理失败:{ex.Message}\n{ex.StackTrace}");
secondResult = null;
}
// 恢复原始参数(避免影响后续截图)
verticalLayoutGroup.enabled = false;
cropWidth = tmpWidth;
cropHeight = tmpHeight;
cropOffset = new Vector2(0f, 0f);
image.enabled = false;
saveFolder = tmpSaveFolder;
2025-08-22 00:33:25 +08:00
// 触发最终回调
onBothComplete?.Invoke(firstResult, secondResult);
}
private IEnumerator CoCaptureTwice_OneToMany(Action<byte[], List<byte[]>> onBothComplete)
{
byte[] firstResult = null;
List<byte[]> secondResults = new List<byte[]>();
var tmpSaveFolder = saveFolder;
var mugActualModelRenderFixed = uiRoot.GetComponent<MugActualModelRender_Fixed>();
saveFolder = Path.Combine(saveFolder, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
var designParent = mugActualModelRenderFixed.designParent.GetChild(0);
onlyFileName = $"PreviewImage";
var tmpImageEnabled = false;
for (var i = 0; i < designParent.childCount; i++)
{
var image = designParent.GetChild(i).GetComponent<UnityEngine.UI.Image>();
tmpImageEnabled = image.enabled;
image.enabled = mugActualModelRenderFixed.productScriptableObject.isShowBaseMap;
}
// 第一次截图(使用基类默认参数)
Debug.Log("开始第一次截图...");
yield return StartCoroutine(CaptureAndCrop((firstBytes) =>
{
firstResult = firstBytes;
Debug.Log("第一次截图完成");
}));
for (var i = 0; i < designParent.childCount; i++)
{
var image = designParent.GetChild(i).GetComponent<UnityEngine.UI.Image>();
image.enabled = tmpImageEnabled;
}
// 确保第一次完成后再执行第二次
if (firstResult == null)
{
Debug.LogError("第一次截图失败,取消第二次");
onBothComplete?.Invoke(null, null);
yield break;
}
for (var i = 0; i < designParent.childCount; i++)
{
// 存储两次截图的结果
byte[] secondResult = null;
for (var j = 0; j < designParent.childCount; j++)
{
designParent.GetChild(j).gameObject.SetActive(false);
}
designParent.GetChild(i).gameObject.SetActive(true);
var verticalLayoutGroup = designParent.GetComponent<LayoutGroup>();
if (verticalLayoutGroup != null)
verticalLayoutGroup.enabled = true;
var tmpWidth = cropWidth;
var tmpHeight = cropHeight;
var productScriptableObject = mugActualModelRenderFixed.productScriptableObject;
var screenshotSize = productScriptableObject.screenshotSize;
cropWidth = (int)screenshotSize.x;
cropHeight = (int)screenshotSize.y;
cropOffset = new Vector2(0.5f, 0.5f);
onlyFileName = $"DesignImage{i}";
// 第二次截图(使用修改后的参数)
Debug.Log("开始第二次截图...");
yield return StartCoroutine(CaptureAndCrop((secondBytes) =>
{
secondResult = secondBytes;
Debug.Log("第二次截图完成");
}));
// image.enabled = tmpImageActive;
// 1. 校验文件是否存在
var fileInfo = new FileInfo(fullPath);
if (!fileInfo.Exists)
{
Debug.LogError($"原始图片不存在:{fullPath}");
secondResult = null;
yield break; // 若在协程中,用 yield break 退出
}
try
{
// 2. 加载图像并校验原始尺寸
using (var sImage = SixLabors.ImageSharp.Image.Load(fileInfo.FullName))
{
// 校验原始图片尺寸是否有效
if (sImage.Width <= 0 || sImage.Height <= 0)
{
Debug.LogError($"加载的图片尺寸无效:宽={sImage.Width}, 高={sImage.Height}");
secondResult = null;
yield break;
}
if (productScriptableObject.printingSize.x != 0)
{
// 3. 校验缩放宽度是否有效
int targetWidth = (int)ConvertMmToPixel(productScriptableObject.printingSize.x);
int targetHeight = (int)ConvertMmToPixel(productScriptableObject.printingSize.y);
if (targetWidth <= 0)
{
Debug.LogError($"缩放宽度无效(必须大于 0{targetWidth}");
// 可选:使用默认宽度(如 200避免错误
targetWidth = 200;
}
// 4. 等比缩放(确保目标尺寸有效)
// sImage.Mutate(x => x.Resize(new ResizeOptions
// {
// Size = new Size(targetWidth, targetHeight), // 高度为0则自动计算
// Mode = ResizeMode.Max,
// Sampler = KnownResamplers.Lanczos3 // 高质量缩放算法
// }));
// 强制缩放
sImage.Mutate(x => x.Resize(targetWidth, targetHeight));
}
// 5. 确保保存目录存在
if (!Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder); // 自动创建目录
}
// 6. 保存缩放后的图片
var filePath = Path.Combine(saveFolder, $"Printing{i}.png");
sImage.SaveAsPng(filePath, new PngEncoder());
// 7. 校验保存结果并读取字节数组
if (File.Exists(filePath))
{
secondResult = File.ReadAllBytes(filePath);
Debug.Log($"第二次截图缩放后保存至:{filePath}");
}
else
{
Debug.LogError($"图片保存失败,文件不存在:{filePath}");
secondResult = null;
}
}
}
catch (Exception ex)
{
// 捕获所有异常(如图片格式错误、权限问题等)
Debug.LogError($"图片处理失败:{ex.Message}\n{ex.StackTrace}");
secondResult = null;
}
// 恢复原始参数(避免影响后续截图)
if (verticalLayoutGroup != null)
verticalLayoutGroup.enabled = false;
cropWidth = tmpWidth;
cropHeight = tmpHeight;
cropOffset = new Vector2(0f, 0f);
// image.enabled = false;
secondResults.Add(secondResult);
}
for (var j = 0; j < designParent.childCount; j++)
{
designParent.GetChild(j).gameObject.SetActive(true);
}
saveFolder = tmpSaveFolder;
// 触发最终回调
onBothComplete?.Invoke(firstResult, secondResults);
}
private IEnumerator CoCaptureTwice_ManyToMany(Action<List<byte[]>, List<byte[]>> onBothComplete)
{
List<byte[]> firstResults = new List<byte[]>();
List<byte[]> secondResults = new List<byte[]>();
var tmpSaveFolder = saveFolder;
var mugActualModelRenderFixed = uiRoot.GetComponent<MugActualModelRender_Fixed>();
saveFolder = Path.Combine(saveFolder, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
var designParent = mugActualModelRenderFixed.designParent.GetChild(0);
for (var i = 0; i < designParent.childCount; i++)
{
// 存储两次截图的结果
byte[] firstResult = null;
byte[] secondResult = null;
onlyFileName = $"PreviewImage{i}";
var image = designParent.GetChild(i).GetComponent<UnityEngine.UI.Image>();
image.enabled = true;
// 第一次截图(使用基类默认参数)
Debug.Log("开始第一次截图...");
yield return StartCoroutine(CaptureAndCrop((firstBytes) =>
{
firstResult = firstBytes;
Debug.Log("第一次截图完成");
}));
image.enabled = false;
// 确保第一次完成后再执行第二次
if (firstResult == null)
{
Debug.LogError("第一次截图失败,取消第二次");
onBothComplete?.Invoke(null, null);
yield break;
}
bool tmpImageActive = image.enabled;
image.enabled = mugActualModelRenderFixed.productScriptableObject.isShowTemplate;
var verticalLayoutGroup = designParent.GetComponent<VerticalLayoutGroup>();
verticalLayoutGroup.enabled = true;
var tmpWidth = cropWidth;
var tmpHeight = cropHeight;
var productScriptableObject = mugActualModelRenderFixed.productScriptableObject;
var screenshotSize = productScriptableObject.screenshotSize;
cropWidth = (int)screenshotSize.x;
cropHeight = (int)screenshotSize.y;
cropOffset = new Vector2(0.5f, 0.5f);
onlyFileName = $"DesignImage{i}";
// 第二次截图(使用修改后的参数)
Debug.Log("开始第二次截图...");
yield return StartCoroutine(CaptureAndCrop((secondBytes) =>
{
secondResult = secondBytes;
Debug.Log("第二次截图完成");
}));
image.enabled = tmpImageActive;
// 1. 校验文件是否存在
var fileInfo = new FileInfo(fullPath);
if (!fileInfo.Exists)
{
Debug.LogError($"原始图片不存在:{fullPath}");
secondResult = null;
yield break; // 若在协程中,用 yield break 退出
}
try
{
// 2. 加载图像并校验原始尺寸
using (var sImage = SixLabors.ImageSharp.Image.Load(fileInfo.FullName))
{
// 校验原始图片尺寸是否有效
if (sImage.Width <= 0 || sImage.Height <= 0)
{
Debug.LogError($"加载的图片尺寸无效:宽={sImage.Width}, 高={sImage.Height}");
secondResult = null;
yield break;
}
if (productScriptableObject.printingSize.x != 0)
{
// 3. 校验缩放宽度是否有效
int targetWidth = (int)ConvertMmToPixel(productScriptableObject.printingSize.x);
int targetHeight = (int)ConvertMmToPixel(productScriptableObject.printingSize.y);
if (targetWidth <= 0)
{
Debug.LogError($"缩放宽度无效(必须大于 0{targetWidth}");
// 可选:使用默认宽度(如 200避免错误
targetWidth = 200;
}
// 4. 等比缩放(确保目标尺寸有效)
// sImage.Mutate(x => x.Resize(new ResizeOptions
// {
// Size = new Size(targetWidth, targetHeight), // 高度为0则自动计算
// Mode = ResizeMode.Max,
// Sampler = KnownResamplers.Lanczos3 // 高质量缩放算法
// }));
// 强制缩放
sImage.Mutate(x => x.Resize(targetWidth, targetHeight));
}
// 5. 确保保存目录存在
if (!Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder); // 自动创建目录
}
// 6. 保存缩放后的图片
var filePath = Path.Combine(saveFolder, $"Printing{i}.png");
sImage.SaveAsPng(filePath, new PngEncoder());
// 7. 校验保存结果并读取字节数组
if (File.Exists(filePath))
{
secondResult = File.ReadAllBytes(filePath);
Debug.Log($"第二次截图缩放后保存至:{filePath}");
}
else
{
Debug.LogError($"图片保存失败,文件不存在:{filePath}");
secondResult = null;
}
}
}
catch (Exception ex)
{
// 捕获所有异常(如图片格式错误、权限问题等)
Debug.LogError($"图片处理失败:{ex.Message}\n{ex.StackTrace}");
secondResult = null;
}
// 恢复原始参数(避免影响后续截图)
verticalLayoutGroup.enabled = false;
cropWidth = tmpWidth;
cropHeight = tmpHeight;
cropOffset = new Vector2(0f, 0f);
image.enabled = false;
firstResults.Add(firstResult);
secondResults.Add(secondResult);
}
saveFolder = tmpSaveFolder;
// 触发最终回调
onBothComplete?.Invoke(firstResults, secondResults);
}
2025-08-22 00:33:25 +08:00
// 协程:顺序执行一次设计截图
private IEnumerator CoCaptureOnlyDesign(Action<byte[], string> onBothComplete)
2025-08-22 00:33:25 +08:00
{
// 存储两次截图的结果
byte[] secondResult = null;
string tmpFolder = "";
2025-08-22 00:33:25 +08:00
var tmpSaveFolder = saveFolder;
2025-08-22 00:33:25 +08:00
saveFolder = Path.Combine(saveFolder, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
tmpFolder = saveFolder;
2025-08-22 00:33:25 +08:00
var mugActualModelRenderFixed = uiRoot.GetComponent<MugActualModelRender_Fixed>();
var image = mugActualModelRenderFixed.designParent.GetChild(0).GetComponent<UnityEngine.UI.Image>();
bool tmpImageActive = image.enabled;
image.enabled = mugActualModelRenderFixed.productScriptableObject.isShowTemplate;
var verticalLayoutGroup = mugActualModelRenderFixed.designParent.GetComponent<VerticalLayoutGroup>();
verticalLayoutGroup.enabled = true;
var tmpWidth = cropWidth;
var tmpHeight = cropHeight;
var productScriptableObject = mugActualModelRenderFixed.productScriptableObject;
var screenshotSize = productScriptableObject.screenshotSize;
cropWidth = (int)screenshotSize.x;
cropHeight = (int)screenshotSize.y;
cropOffset = new Vector2(0.5f, 0.5f);
onlyFileName = "DesignImage1";
// 第二次截图(使用修改后的参数)
Debug.Log("开始第二次截图...");
yield return StartCoroutine(CaptureAndCrop((secondBytes) =>
{
secondResult = secondBytes;
Debug.Log("第二次截图完成");
}));
image.enabled = tmpImageActive;
2025-08-22 00:33:25 +08:00
// 1. 校验文件是否存在
var fileInfo = new FileInfo(fullPath);
if (!fileInfo.Exists)
{
Debug.LogError($"原始图片不存在:{fullPath}");
secondResult = null;
yield break; // 若在协程中,用 yield break 退出
}
try
{
// 2. 加载图像并校验原始尺寸
using (var sImage = SixLabors.ImageSharp.Image.Load(fileInfo.FullName))
{
// 校验原始图片尺寸是否有效
if (sImage.Width <= 0 || sImage.Height <= 0)
{
Debug.LogError($"加载的图片尺寸无效:宽={sImage.Width}, 高={sImage.Height}");
secondResult = null;
yield break;
}
if (productScriptableObject.printingSize.x != 0)
{
// 3. 校验缩放宽度是否有效
int targetWidth = (int)ConvertMmToPixel(productScriptableObject.printingSize.x);
int targetHeight = (int)ConvertMmToPixel(productScriptableObject.printingSize.y);
if (targetWidth <= 0)
{
Debug.LogError($"缩放宽度无效(必须大于 0{targetWidth}");
// 可选:使用默认宽度(如 200避免错误
targetWidth = 200;
}
// 4. 等比缩放(确保目标尺寸有效)
// sImage.Mutate(x => x.Resize(new ResizeOptions
// {
// Size = new Size(targetWidth, targetHeight), // 高度为0则自动计算
// Mode = ResizeMode.Max,
// Sampler = KnownResamplers.Lanczos3 // 高质量缩放算法
// }));
// 强制缩放
sImage.Mutate(x => x.Resize(targetWidth, targetHeight));
}
// 5. 确保保存目录存在
if (!Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder); // 自动创建目录
}
// 6. 保存缩放后的图片
var filePath = Path.Combine(saveFolder, "Printing1.png");
sImage.SaveAsPng(filePath, new PngEncoder());
// 7. 校验保存结果并读取字节数组
if (File.Exists(filePath))
{
secondResult = File.ReadAllBytes(filePath);
Debug.Log($"第二次截图缩放后保存至:{filePath}");
}
else
{
Debug.LogError($"图片保存失败,文件不存在:{filePath}");
secondResult = null;
}
}
}
catch (Exception ex)
{
// 捕获所有异常(如图片格式错误、权限问题等)
Debug.LogError($"图片处理失败:{ex.Message}\n{ex.StackTrace}");
secondResult = null;
}
// 恢复原始参数(避免影响后续截图)
verticalLayoutGroup.enabled = false;
cropWidth = tmpWidth;
cropHeight = tmpHeight;
cropOffset = new Vector2(0f, 0f);
image.enabled = false;
saveFolder = tmpSaveFolder;
2025-08-22 00:33:25 +08:00
// 触发最终回调
onBothComplete?.Invoke(secondResult, tmpFolder);
2025-08-22 00:33:25 +08:00
}
// 可选:重写基类的立即截图方法,使其默认执行两次
// public override void CaptureAndCropNow(Action<byte[]> callback = null)
// {
// base.CaptureAndCropNow(callback);
// // // 如果需要点击按钮时默认执行两次可在这里调用CaptureTwice
// // CaptureTwice((first, second) =>
// // {
// // callback?.Invoke(first); // 这里仅返回第一次的结果,或按需处理
// // });
// }
}
}