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; // 每帧检查一次,不阻塞主线程
}
}
}
}