78 lines
3.1 KiB
C#
78 lines
3.1 KiB
C#
using System;
|
||||
|
|
using System.IO;
|
|||
|
|
using System.Windows.Media.Imaging;
|
|||
|
|
|
|||
|
|
namespace PCL.Core.UI.Media;
|
|||
|
|
|
|||
|
|
public static class ImageConverter
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 从 WebP 输入流解码并转换为 PNG,返回包含 PNG 数据的 MemoryStream(Position=0)。
|
|||
|
|
/// 需要系统内置的 WebP WIC 编解码器(Windows 10/11 通常已内置或可通过商店扩展提供)。
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="input">输入 WebP 流(不会在此方法中关闭)</param>
|
|||
|
|
/// <param name="frameIndex">要提取的帧索引,默认 0</param>
|
|||
|
|
/// <returns>包含 PNG 数据的 MemoryStream,调用方负责释放</returns>
|
|||
|
|
/// <exception cref="ArgumentOutOfRangeException">帧索引超出图像支持范围</exception>
|
|||
|
|
/// <exception cref="NotSupportedException">系统缺少 WebP 解码器,或数据格式不受支持</exception>
|
|||
|
|
// Partly generated by gpt-5 (20250813)
|
|||
|
|
public static MemoryStream FromWebpToPng(this Stream input, int frameIndex = 0)
|
|||
|
|
{
|
|||
|
|
// 确保有可寻址的源流
|
|||
|
|
var source = input;
|
|||
|
|
MemoryStream? tempBuffer = null;
|
|||
|
|
if (!input.CanSeek)
|
|||
|
|
{
|
|||
|
|
tempBuffer = new MemoryStream();
|
|||
|
|
input.CopyTo(tempBuffer);
|
|||
|
|
tempBuffer.Position = 0;
|
|||
|
|
source = tempBuffer;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 从开头解码
|
|||
|
|
if (source.Position != 0) source.Position = 0;
|
|||
|
|
}
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 使用 WPF 的 BitmapDecoder(底层是 WIC)。OnLoad 使得图像数据在解码完成后与源流解耦。
|
|||
|
|
var decoder = BitmapDecoder.Create(
|
|||
|
|
source,
|
|||
|
|
BitmapCreateOptions.PreservePixelFormat,
|
|||
|
|
BitmapCacheOption.OnLoad);
|
|||
|
|
|
|||
|
|
if (decoder.Frames.Count == 0)
|
|||
|
|
throw new NotSupportedException("未能从输入数据解码出任何图像帧,可能不是有效的 WebP 图像。");
|
|||
|
|
|
|||
|
|
if (frameIndex < 0 || frameIndex >= decoder.Frames.Count)
|
|||
|
|
throw new ArgumentOutOfRangeException(nameof(frameIndex), $"帧索引超出范围(0..{decoder.Frames.Count - 1})。");
|
|||
|
|
|
|||
|
|
var frame = decoder.Frames[frameIndex];
|
|||
|
|
|
|||
|
|
var encoder = new PngBitmapEncoder();
|
|||
|
|
// 使用 BitmapFrame.Create 包装,避免后续冻结或依赖源的问题
|
|||
|
|
encoder.Frames.Add(BitmapFrame.Create(frame));
|
|||
|
|
|
|||
|
|
var output = new MemoryStream();
|
|||
|
|
encoder.Save(output);
|
|||
|
|
output.Position = 0;
|
|||
|
|
return output;
|
|||
|
|
}
|
|||
|
|
catch (NotSupportedException)
|
|||
|
|
{
|
|||
|
|
// 透传,提示缺少编解码器或格式不支持
|
|||
|
|
throw;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
// 统一转为更明确的异常信息(保留原始异常以便调试)
|
|||
|
|
throw new NotSupportedException("转换 WebP 到 PNG 失败:输入可能不是有效的 WebP,或系统未提供所需的编解码支持。", ex);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
// 仅释放我们创建的临时缓冲,不关闭调用方传入的 input
|
|||
|
|
tempBuffer?.Dispose();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|