165 lines
6.4 KiB
C#
165 lines
6.4 KiB
C#
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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 压缩 PNG 并设置为 300 DPI
|
||
/// </summary>
|
||
/// <param name="inputPath">原始 PNG 路径</param>
|
||
/// <param name="outputPath">压缩后 PNG 输出路径</param>
|
||
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; // 每帧检查一次,不阻塞主线程
|
||
}
|
||
}
|
||
}
|
||
} |