FM/Assets/Scripts/FUJIFILM/UI/Other/PngCompressor.cs

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