using System; using System.Collections; using System.IO; using System.Threading; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Processing; using ImageMagick; using UnityEngine; namespace HK.FUJIFILM { public static class PngCompressor { public static void CompressPng(string inputPath, string outputPath) { using (Image image = Image.Load(inputPath)) { // 设置 DPI(如果你知道它是 300,可以手动设置) image.Metadata.VerticalResolution = 300; image.Metadata.HorizontalResolution = 300; // 保存为 PNG,并设置压缩选项 var encoder = new PngEncoder { CompressionLevel = PngCompressionLevel.Level9, // 最高压缩,无损 FilterMethod = PngFilterMethod.Adaptive, // 通常效果最好 ColorType = PngColorType.Rgb // 保留 RGB,避免 Alpha 影响体积 }; image.Save(outputPath, encoder); } } /// /// 压缩 PNG 并设置为 300 DPI /// /// 原始 PNG 路径 /// 压缩后 PNG 输出路径 public static void CompressPngAndSetDpi(string inputPath, string outputPath) { using (var image = new MagickImage(inputPath)) { // 设置 300 DPI image.Density = new Density(300, 300, DensityUnit.PixelsPerInch); // 设置压缩参数(对于 PNG 有效) image.Format = MagickFormat.Png; image.Quality = 100; // 保证无损 image.Depth = 8; // PNG 8bit(通常足够) // 选择压缩过滤器 image.Settings.SetDefine(MagickFormat.Png, "compression-filter", "5"); image.Settings.Compression = CompressionMethod.Zip; // PNG 默认 // 写入输出文件 image.Write(outputPath); } Debug.Log($"✅ 压缩成功,输出文件: {outputPath}"); } public static void CompressPngAndSetDpi(byte[] bytes, string outputPath) { using (var image = new MagickImage(bytes)) { // 设置 300 DPI image.Density = new Density(300, 300, DensityUnit.PixelsPerInch); // 设置压缩参数(对于 PNG 有效) image.Format = MagickFormat.Png; image.Quality = 100; // 保证无损 image.Depth = 8; // PNG 8bit(通常足够) // 选择压缩过滤器 image.Settings.SetDefine(MagickFormat.Png, "compression-filter", "5"); image.Settings.Compression = CompressionMethod.Zip; // PNG 默认 // 写入输出文件 image.Write(outputPath); } Debug.Log($"✅ 压缩成功,输出文件: {outputPath}"); } public static async UniTask CompressPngAndSetDpiAsync(byte[] bytes, string outputPath) { // 关键:用Task.Run替代RunOnThreadPool,在.NET线程池执行后台操作 await Task.Run(() => { using (var image = new MagickImage(bytes)) { // 设置300 DPI image.Density = new Density(300, 300, DensityUnit.PixelsPerInch); // PNG压缩配置 image.Format = MagickFormat.Png; image.Quality = 100; // 无损压缩 image.Depth = 8; image.Settings.SetDefine(MagickFormat.Png, "compression-level", "9"); image.Settings.SetDefine(MagickFormat.Png, "compression-filter", "5"); image.Settings.Compression = CompressionMethod.Zip; image.Write(outputPath); // 同步写入文件(在后台线程) } }); Debug.Log($"✅ 压缩成功,输出文件: {outputPath}"); } public static IEnumerator CompressPngAndSetDpiAsync1(byte[] bytes, string outputPath, CancellationToken cancellationToken = default) { // 验证输入参数 if (bytes == null || bytes.Length == 0) throw new ArgumentException("图片字节数组不能为空", nameof(bytes)); if (string.IsNullOrEmpty(outputPath)) throw new ArgumentException("输出路径不能为空", nameof(outputPath)); bool isWriteDone = false; Task.Run(() => { // 检查是否已取消 cancellationToken.ThrowIfCancellationRequested(); // 使用MagickImage处理图片 using (var image = new MagickImage(bytes)) { // 设置DPI为300 image.Density = new Density(300, 300, DensityUnit.PixelsPerInch); // 配置PNG压缩参数 image.Format = MagickFormat.Png; image.Quality = 100; // 无损压缩 image.Depth = 8; // 8位色深 image.Settings.SetDefine(MagickFormat.Png, "compression-level", "9"); image.Settings.SetDefine(MagickFormat.Png, "compression-filter", "5"); image.Settings.Compression = CompressionMethod.Zip; // 再次检查取消状态 if (cancellationToken.IsCancellationRequested) cancellationToken.ThrowIfCancellationRequested(); // 写入处理后的图片 image.Write(outputPath); } Debug.Log($"✅ 压缩成功,输出文件: {outputPath}"); // 标记完成(线程安全,因为bool是原子操作) isWriteDone = true; }, cancellationToken); // 主线程:等待后台线程完成(用循环+yield return null,避免死等) while (!isWriteDone) { yield return null; // 每帧检查一次,不阻塞主线程 } } } }