From 2204eb6c7576eaa65804e53fb00f4adebeab8455 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Thu, 2 Oct 2025 22:18:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0apng=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=B9=B6=E4=B8=94=E8=B0=83=E6=95=B4=E9=83=A8=E5=88=86=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Spine/Exporters/FFmpegVideoExporter.cs | 25 +- SpineViewer/Resources/Strings/en.xaml | 4 +- SpineViewer/Resources/Strings/ja.xaml | 4 +- SpineViewer/Resources/Strings/zh.xaml | 4 +- .../Exporters/FFmpegVideoExporterViewModel.cs | 43 +- SpineViewer/Views/AboutDialog.xaml | 42 +- SpineViewer/Views/DiagnosticsDialog.xaml | 7 +- .../CustomFFmpegExporterDialog.xaml | 286 +++++---- .../FFmpegVideoExporterDialog.xaml | 262 +++++--- .../ExporterDialogs/FrameExporterDialog.xaml | 153 +++-- .../FrameSequenceExporterDialog.xaml | 175 ++++-- SpineViewer/Views/MainWindow.xaml | 566 +++++++++++------- SpineViewer/Views/PreferenceDialog.xaml | 48 +- 13 files changed, 1033 insertions(+), 586 deletions(-) diff --git a/Spine/Exporters/FFmpegVideoExporter.cs b/Spine/Exporters/FFmpegVideoExporter.cs index e3fd2c3..ea04666 100644 --- a/Spine/Exporters/FFmpegVideoExporter.cs +++ b/Spine/Exporters/FFmpegVideoExporter.cs @@ -28,6 +28,7 @@ namespace Spine.Exporters { Gif, Webp, + Apng, Mp4, Webm, Mkv, @@ -41,31 +42,37 @@ namespace Spine.Exporters private VideoFormat _format = VideoFormat.Mp4; /// - /// 动图是否循环 [Gif/Webp] + /// [Gif/Webp/Apng] 动图是否循环 /// public bool Loop { get => _loop; set => _loop = value; } private bool _loop = true; /// - /// 质量 [Webp] + /// [Webp] 质量 /// public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); } private int _quality = 75; /// - /// 无损压缩 [Webp] + /// [Webp] 无损压缩 /// public bool Lossless { get => _lossless; set => _lossless = value; } private bool _lossless = false; /// - /// CRF [Mp4/Webm/Mkv] + /// [Apng] 预测器算法, 取值范围 0-5, 分别对应 none, sub, up, avg, paeth, mixed + /// + public int ApngPred { get => _apngPred; set => _apngPred = Math.Clamp(value, 0, 5); } + private int _apngPred = 5; + + /// + /// [Mp4/Webm/Mkv] CRF /// public int Crf { get => _crf; set => _crf = Math.Clamp(value, 0, 63); } private int _crf = 23; /// - /// prores_ks 编码器的配置等级, -1 是自动, 越高质量越好, 只有 4 及以上才有透明通道 [Mov] + /// [Mov] prores_ks 编码器的配置等级, -1 是自动, 越高质量越好, 只有 4 及以上才有透明通道 /// public int Profile { get => _profile; set => _profile = Math.Clamp(value, -1, 5); } private int _profile = 5; @@ -93,6 +100,7 @@ namespace Spine.Exporters { VideoFormat.Gif => SetGifOptions, VideoFormat.Webp => SetWebpOptions, + VideoFormat.Apng => SetApngOptions, VideoFormat.Mp4 => SetMp4Options, VideoFormat.Webm => SetWebmOptions, VideoFormat.Mkv => SetMkvOptions, @@ -132,6 +140,13 @@ namespace Spine.Exporters .WithCustomArgument(customArgs); } + private void SetApngOptions(FFMpegArgumentOptions options) + { + var customArgs = $"-vf unpremultiply=inplace=1 -plays {(_loop ? 0 : 1)} -pred {_apngPred}"; + options.ForceFormat("apng").WithVideoCodec("apng").ForcePixelFormat("rgba") + .WithCustomArgument(customArgs); + } + private void SetMp4Options(FFMpegArgumentOptions options) { // XXX: windows 默认播放器在播放 MP4 格式时对于 libx264 编码器只支持 yuv420p 的像素格式 diff --git a/SpineViewer/Resources/Strings/en.xaml b/SpineViewer/Resources/Strings/en.xaml index be3fd86..0ddc1af 100644 --- a/SpineViewer/Resources/Strings/en.xaml +++ b/SpineViewer/Resources/Strings/en.xaml @@ -197,11 +197,13 @@ Video Format Loop Play - [Gif/Webp] Whether the animation loops + [Gif/Webp/Apng] Whether the animation loops Quality Parameter [Webp] Quality parameter, range 0-100, higher value means better quality Lossless Compression [Webp] Lossless compression, quality parameter will be ignored + Predictor Method + [Apng] Pred parameter, value range 0-5, corresponding to different encoding strategies: none, sub, up, avg, paeth, and mixed. It affects encoding time and file size. CRF Parameter [Mp4/Webm/Mkv] CRF parameter, range 0-63, lower value means higher quality Profile Parameter diff --git a/SpineViewer/Resources/Strings/ja.xaml b/SpineViewer/Resources/Strings/ja.xaml index 6790f47..39ce6bc 100644 --- a/SpineViewer/Resources/Strings/ja.xaml +++ b/SpineViewer/Resources/Strings/ja.xaml @@ -197,11 +197,13 @@ ビデオフォーマット ループ再生 - [Gif/Webp] アニメーションをループ再生するかどうか + [Gif/Webp/Apng] アニメーションをループ再生するかどうか 品質パラメータ [Webp] 品質パラメータ、範囲は0-100。値が高いほど品質が良い 無損失圧縮 [Webp] 無損失圧縮、品質パラメータは無視されます + 予測器方式 + [Apng] Pred パラメータ。値の範囲は 0~5 で、それぞれ none、sub、up、avg、paeth、mixed の異なるエンコード方式に対応します。 エンコード時間とファイルサイズに影響します。 CRF パラメータ [Mp4/Webm/Mkv] CRF パラメータ、範囲0-63。値が小さいほど品質が高い プロファイルパラメータ diff --git a/SpineViewer/Resources/Strings/zh.xaml b/SpineViewer/Resources/Strings/zh.xaml index 200e717..9eef84f 100644 --- a/SpineViewer/Resources/Strings/zh.xaml +++ b/SpineViewer/Resources/Strings/zh.xaml @@ -197,11 +197,13 @@ 视频格式 循环播放 - [Gif/Webp] 动图是否循环播放 + [Gif/Webp/Apng] 动图是否循环播放 质量参数 [Webp] 质量参数,取值范围 0-100,越高质量越好 无损压缩 [Webp] 无损压缩,会忽略质量参数 + 预测器方法 + [Apng] Pred 参数,取值范围 0-5,分别对应 none、sub、up、avg、paeth、mixed 几种不同的编码策略, 影响编码时间和文件大小 CRF 参数 [Mp4/Webm/Mkv] CRF 参数,取值范围 0-63,越小质量越高 Profile 参数 diff --git a/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs b/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs index ed9d098..c11b986 100644 --- a/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs +++ b/SpineViewer/ViewModels/Exporters/FFmpegVideoExporterViewModel.cs @@ -20,24 +20,64 @@ namespace SpineViewer.ViewModels.Exporters { public static ImmutableArray VideoFormatOptions { get; } = Enum.GetValues().ToImmutableArray(); - public FFmpegVideoExporter.VideoFormat Format { get => _format; set => SetProperty(ref _format, value); } + public FFmpegVideoExporter.VideoFormat Format + { + get => _format; + set + { + if (SetProperty(ref _format, value)) + { + OnPropertyChanged(nameof(EnableParamLoop)); + OnPropertyChanged(nameof(EnableParamQuality)); + OnPropertyChanged(nameof(EnableParamLossless)); + OnPropertyChanged(nameof(EnableParamApngPred)); + OnPropertyChanged(nameof(EnableParamCrf)); + OnPropertyChanged(nameof(EnableParamProfile)); + } + } + } protected FFmpegVideoExporter.VideoFormat _format = FFmpegVideoExporter.VideoFormat.Mp4; public bool Loop { get => _loop; set => SetProperty(ref _loop, value); } protected bool _loop = true; + public bool EnableParamLoop => + _format == FFmpegVideoExporter.VideoFormat.Gif || + _format == FFmpegVideoExporter.VideoFormat.Webp || + _format == FFmpegVideoExporter.VideoFormat.Apng; + public int Quality { get => _quality; set => SetProperty(ref _quality, Math.Clamp(value, 0, 100)); } protected int _quality = 75; + public bool EnableParamQuality => + _format == FFmpegVideoExporter.VideoFormat.Webp; + public bool Lossless { get => _lossless; set => SetProperty(ref _lossless, value); } protected bool _lossless = false; + public bool EnableParamLossless => + _format == FFmpegVideoExporter.VideoFormat.Webp; + + public int ApngPred { get => _apngPred; set => SetProperty(ref _apngPred, Math.Clamp(value, 0, 5)); } + protected int _apngPred = 5; + + public bool EnableParamApngPred => + _format == FFmpegVideoExporter.VideoFormat.Apng; + public int Crf { get => _crf; set => SetProperty(ref _crf, Math.Clamp(value, 0, 63)); } protected int _crf = 23; + public bool EnableParamCrf => + _format == FFmpegVideoExporter.VideoFormat.Mp4 || + _format == FFmpegVideoExporter.VideoFormat.Webm || + _format == FFmpegVideoExporter.VideoFormat.Mkv; + public int Profile { get => _profile; set => SetProperty(ref _profile, Math.Clamp(value, -1, 5)); } protected int _profile = 5; + public bool EnableParamProfile => + _format == FFmpegVideoExporter.VideoFormat.Mov; + private string FormatSuffix => $".{_format.ToString().ToLower()}"; protected override void Export(SpineObjectModel[] models) @@ -63,6 +103,7 @@ namespace SpineViewer.ViewModels.Exporters Loop = _loop, Quality = _quality, Lossless = _lossless, + ApngPred = _apngPred, Crf = _crf, Profile = _profile, }; diff --git a/SpineViewer/Views/AboutDialog.xaml b/SpineViewer/Views/AboutDialog.xaml index 7fa3eac..3be6fbb 100644 --- a/SpineViewer/Views/AboutDialog.xaml +++ b/SpineViewer/Views/AboutDialog.xaml @@ -26,25 +26,31 @@ - - - - - - - - - -