增加格式转换

This commit is contained in:
ww-rm
2025-03-16 16:22:19 +08:00
parent c622b60215
commit a0833580f8
7 changed files with 3787 additions and 4 deletions

View File

@@ -0,0 +1,357 @@
namespace SpineViewer.Dialogs
{
partial class ConvertFileFormatDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConvertFileFormatDialog));
panel = new Panel();
tableLayoutPanel1 = new TableLayoutPanel();
flowLayoutPanel_TargetFormat = new FlowLayoutPanel();
radioButton_BinaryTarget = new RadioButton();
radioButton_JsonTarget = new RadioButton();
label1 = new Label();
label4 = new Label();
label3 = new Label();
comboBox_Version = new ComboBox();
tableLayoutPanel2 = new TableLayoutPanel();
button_Ok = new Button();
button_Cancel = new Button();
listBox_FilePath = new ListBox();
button_SelectSkel = new Button();
label_Tip = new Label();
label2 = new Label();
flowLayoutPanel_SourceFormat = new FlowLayoutPanel();
radioButton_BinarySource = new RadioButton();
radioButton_JsonSource = new RadioButton();
openFileDialog_Skel = new OpenFileDialog();
panel.SuspendLayout();
tableLayoutPanel1.SuspendLayout();
flowLayoutPanel_TargetFormat.SuspendLayout();
tableLayoutPanel2.SuspendLayout();
flowLayoutPanel_SourceFormat.SuspendLayout();
SuspendLayout();
//
// panel
//
panel.Controls.Add(tableLayoutPanel1);
panel.Dock = DockStyle.Fill;
panel.Location = new Point(0, 0);
panel.Name = "panel";
panel.Padding = new Padding(50, 15, 50, 10);
panel.Size = new Size(1039, 530);
panel.TabIndex = 2;
//
// tableLayoutPanel1
//
tableLayoutPanel1.ColumnCount = 2;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
tableLayoutPanel1.Controls.Add(flowLayoutPanel_TargetFormat, 1, 5);
tableLayoutPanel1.Controls.Add(label1, 0, 4);
tableLayoutPanel1.Controls.Add(label4, 0, 0);
tableLayoutPanel1.Controls.Add(label3, 0, 3);
tableLayoutPanel1.Controls.Add(comboBox_Version, 1, 3);
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 6);
tableLayoutPanel1.Controls.Add(listBox_FilePath, 0, 2);
tableLayoutPanel1.Controls.Add(button_SelectSkel, 0, 1);
tableLayoutPanel1.Controls.Add(label_Tip, 1, 1);
tableLayoutPanel1.Controls.Add(label2, 0, 5);
tableLayoutPanel1.Controls.Add(flowLayoutPanel_SourceFormat, 1, 4);
tableLayoutPanel1.Dock = DockStyle.Fill;
tableLayoutPanel1.Location = new Point(50, 15);
tableLayoutPanel1.Name = "tableLayoutPanel1";
tableLayoutPanel1.RowCount = 7;
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.Size = new Size(939, 505);
tableLayoutPanel1.TabIndex = 1;
//
// flowLayoutPanel_TargetFormat
//
flowLayoutPanel_TargetFormat.AutoSize = true;
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_BinaryTarget);
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_JsonTarget);
flowLayoutPanel_TargetFormat.Dock = DockStyle.Fill;
flowLayoutPanel_TargetFormat.Location = new Point(146, 381);
flowLayoutPanel_TargetFormat.Name = "flowLayoutPanel_TargetFormat";
flowLayoutPanel_TargetFormat.Size = new Size(790, 34);
flowLayoutPanel_TargetFormat.TabIndex = 19;
//
// radioButton_BinaryTarget
//
radioButton_BinaryTarget.AutoSize = true;
radioButton_BinaryTarget.Location = new Point(3, 3);
radioButton_BinaryTarget.Name = "radioButton_BinaryTarget";
radioButton_BinaryTarget.Size = new Size(151, 28);
radioButton_BinaryTarget.TabIndex = 17;
radioButton_BinaryTarget.Text = "二进制 (*.skel)";
radioButton_BinaryTarget.UseVisualStyleBackColor = true;
radioButton_BinaryTarget.CheckedChanged += radioButton_Target_CheckedChanged;
//
// radioButton_JsonTarget
//
radioButton_JsonTarget.AutoSize = true;
radioButton_JsonTarget.Checked = true;
radioButton_JsonTarget.Location = new Point(160, 3);
radioButton_JsonTarget.Name = "radioButton_JsonTarget";
radioButton_JsonTarget.Size = new Size(135, 28);
radioButton_JsonTarget.TabIndex = 18;
radioButton_JsonTarget.TabStop = true;
radioButton_JsonTarget.Text = "文本 (*.json)";
radioButton_JsonTarget.UseVisualStyleBackColor = true;
radioButton_JsonTarget.CheckedChanged += radioButton_Target_CheckedChanged;
//
// label1
//
label1.Anchor = AnchorStyles.Right;
label1.AutoSize = true;
label1.Location = new Point(72, 346);
label1.Name = "label1";
label1.Size = new Size(68, 24);
label1.TabIndex = 15;
label1.Text = "源格式:";
//
// label4
//
label4.AutoSize = true;
tableLayoutPanel1.SetColumnSpan(label4, 4);
label4.Dock = DockStyle.Fill;
label4.Location = new Point(15, 15);
label4.Margin = new Padding(15);
label4.Name = "label4";
label4.Size = new Size(909, 24);
label4.TabIndex = 14;
label4.Text = "说明:将在每个文件同级目录下生成目标格式后缀的文件,会覆盖已存在文件";
label4.TextAlign = ContentAlignment.MiddleCenter;
//
// label3
//
label3.Anchor = AnchorStyles.Right;
label3.AutoSize = true;
label3.Location = new Point(72, 307);
label3.Name = "label3";
label3.Size = new Size(68, 24);
label3.TabIndex = 12;
label3.Text = "源版本:";
//
// comboBox_Version
//
comboBox_Version.Anchor = AnchorStyles.Left;
comboBox_Version.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox_Version.FormattingEnabled = true;
comboBox_Version.Location = new Point(146, 303);
comboBox_Version.Name = "comboBox_Version";
comboBox_Version.Size = new Size(182, 32);
comboBox_Version.Sorted = true;
comboBox_Version.TabIndex = 13;
//
// tableLayoutPanel2
//
tableLayoutPanel2.AutoSize = true;
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
tableLayoutPanel2.ColumnCount = 2;
tableLayoutPanel1.SetColumnSpan(tableLayoutPanel2, 4);
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
tableLayoutPanel2.Dock = DockStyle.Bottom;
tableLayoutPanel2.Location = new Point(3, 462);
tableLayoutPanel2.Name = "tableLayoutPanel2";
tableLayoutPanel2.RowCount = 1;
tableLayoutPanel2.RowStyles.Add(new RowStyle());
tableLayoutPanel2.Size = new Size(933, 40);
tableLayoutPanel2.TabIndex = 11;
//
// button_Ok
//
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
button_Ok.Location = new Point(324, 3);
button_Ok.Margin = new Padding(3, 3, 30, 3);
button_Ok.Name = "button_Ok";
button_Ok.Size = new Size(112, 34);
button_Ok.TabIndex = 7;
button_Ok.Text = "确认";
button_Ok.UseVisualStyleBackColor = true;
button_Ok.Click += button_Ok_Click;
//
// button_Cancel
//
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
button_Cancel.Location = new Point(496, 3);
button_Cancel.Margin = new Padding(30, 3, 3, 3);
button_Cancel.Name = "button_Cancel";
button_Cancel.Size = new Size(112, 34);
button_Cancel.TabIndex = 8;
button_Cancel.Text = "取消";
button_Cancel.UseVisualStyleBackColor = true;
button_Cancel.Click += button_Cancel_Click;
//
// listBox_FilePath
//
tableLayoutPanel1.SetColumnSpan(listBox_FilePath, 2);
listBox_FilePath.Dock = DockStyle.Fill;
listBox_FilePath.FormattingEnabled = true;
listBox_FilePath.HorizontalScrollbar = true;
listBox_FilePath.ItemHeight = 24;
listBox_FilePath.Location = new Point(3, 97);
listBox_FilePath.Name = "listBox_FilePath";
listBox_FilePath.Size = new Size(933, 200);
listBox_FilePath.TabIndex = 2;
//
// button_SelectSkel
//
button_SelectSkel.Anchor = AnchorStyles.None;
button_SelectSkel.Location = new Point(3, 57);
button_SelectSkel.Name = "button_SelectSkel";
button_SelectSkel.Size = new Size(137, 34);
button_SelectSkel.TabIndex = 1;
button_SelectSkel.Text = "选择文件...";
button_SelectSkel.UseVisualStyleBackColor = true;
button_SelectSkel.Click += button_SelectSkel_Click;
//
// label_Tip
//
label_Tip.AutoSize = true;
label_Tip.Dock = DockStyle.Fill;
label_Tip.Location = new Point(146, 54);
label_Tip.Name = "label_Tip";
label_Tip.Size = new Size(790, 40);
label_Tip.TabIndex = 0;
label_Tip.Text = "已选择 0 个文件";
label_Tip.TextAlign = ContentAlignment.MiddleLeft;
//
// label2
//
label2.Anchor = AnchorStyles.Right;
label2.AutoSize = true;
label2.Location = new Point(54, 386);
label2.Name = "label2";
label2.Size = new Size(86, 24);
label2.TabIndex = 16;
label2.Text = "目标格式:";
//
// flowLayoutPanel_SourceFormat
//
flowLayoutPanel_SourceFormat.AutoSize = true;
flowLayoutPanel_SourceFormat.Controls.Add(radioButton_BinarySource);
flowLayoutPanel_SourceFormat.Controls.Add(radioButton_JsonSource);
flowLayoutPanel_SourceFormat.Dock = DockStyle.Fill;
flowLayoutPanel_SourceFormat.Location = new Point(146, 341);
flowLayoutPanel_SourceFormat.Name = "flowLayoutPanel_SourceFormat";
flowLayoutPanel_SourceFormat.Size = new Size(790, 34);
flowLayoutPanel_SourceFormat.TabIndex = 18;
//
// radioButton_BinarySource
//
radioButton_BinarySource.AutoSize = true;
radioButton_BinarySource.Checked = true;
radioButton_BinarySource.Location = new Point(3, 3);
radioButton_BinarySource.Name = "radioButton_BinarySource";
radioButton_BinarySource.Size = new Size(151, 28);
radioButton_BinarySource.TabIndex = 17;
radioButton_BinarySource.TabStop = true;
radioButton_BinarySource.Text = "二进制 (*.skel)";
radioButton_BinarySource.UseVisualStyleBackColor = true;
radioButton_BinarySource.CheckedChanged += radioButton_Source_CheckedChanged;
//
// radioButton_JsonSource
//
radioButton_JsonSource.AutoSize = true;
radioButton_JsonSource.Location = new Point(160, 3);
radioButton_JsonSource.Name = "radioButton_JsonSource";
radioButton_JsonSource.Size = new Size(135, 28);
radioButton_JsonSource.TabIndex = 18;
radioButton_JsonSource.Text = "文本 (*.json)";
radioButton_JsonSource.UseVisualStyleBackColor = true;
radioButton_JsonSource.CheckedChanged += radioButton_Source_CheckedChanged;
//
// openFileDialog_Skel
//
openFileDialog_Skel.AddExtension = false;
openFileDialog_Skel.AddToRecent = false;
openFileDialog_Skel.Filter = "skel 文件 (*.skel; *.json)|*.skel;*.json|二进制文件 (*.skel)|*.skel|文本文件 (*.json)|*.json|所有文件 (*.*)|*.*";
openFileDialog_Skel.Multiselect = true;
openFileDialog_Skel.Title = "批量选择skel文件";
//
// ConvertFileFormatDialog
//
AcceptButton = button_Ok;
AutoScaleDimensions = new SizeF(11F, 24F);
AutoScaleMode = AutoScaleMode.Font;
CancelButton = button_Cancel;
ClientSize = new Size(1039, 530);
Controls.Add(panel);
FormBorderStyle = FormBorderStyle.FixedDialog;
Icon = (Icon)resources.GetObject("$this.Icon");
MaximizeBox = false;
MinimizeBox = false;
Name = "ConvertFileFormatDialog";
ShowInTaskbar = false;
StartPosition = FormStartPosition.CenterScreen;
Text = "骨骼文件格式转换";
panel.ResumeLayout(false);
tableLayoutPanel1.ResumeLayout(false);
tableLayoutPanel1.PerformLayout();
flowLayoutPanel_TargetFormat.ResumeLayout(false);
flowLayoutPanel_TargetFormat.PerformLayout();
tableLayoutPanel2.ResumeLayout(false);
flowLayoutPanel_SourceFormat.ResumeLayout(false);
flowLayoutPanel_SourceFormat.PerformLayout();
ResumeLayout(false);
}
#endregion
private Panel panel;
private TableLayoutPanel tableLayoutPanel1;
private Label label4;
private Label label3;
private ComboBox comboBox_Version;
private TableLayoutPanel tableLayoutPanel2;
private Button button_Ok;
private Button button_Cancel;
private ListBox listBox_FilePath;
private Button button_SelectSkel;
private Label label_Tip;
private OpenFileDialog openFileDialog_Skel;
private Label label1;
private Label label2;
private RadioButton radioButton_BinarySource;
private FlowLayoutPanel flowLayoutPanel_SourceFormat;
private RadioButton radioButton_JsonSource;
private FlowLayoutPanel flowLayoutPanel_TargetFormat;
private RadioButton radioButton_BinaryTarget;
private RadioButton radioButton_JsonTarget;
}
}

View File

@@ -0,0 +1,94 @@
using SpineViewer.Spine;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SpineViewer.Dialogs
{
public partial class ConvertFileFormatDialog : Form
{
public string[] SkelPaths { get; private set; }
public Spine.Version Version { get; private set; }
public bool ConvertToJson { get; private set; }
public ConvertFileFormatDialog()
{
InitializeComponent();
comboBox_Version.DataSource = VersionHelper.Versions.ToList();
comboBox_Version.DisplayMember = "Value";
comboBox_Version.ValueMember = "Key";
comboBox_Version.SelectedValue = Spine.Version.V38;
}
private void button_SelectSkel_Click(object sender, EventArgs e)
{
if (openFileDialog_Skel.ShowDialog() == DialogResult.OK)
{
listBox_FilePath.Items.Clear();
foreach (var p in openFileDialog_Skel.FileNames)
listBox_FilePath.Items.Add(Path.GetFullPath(p));
label_Tip.Text = $"已选择 {listBox_FilePath.Items.Count} 个文件";
}
}
private void button_Ok_Click(object sender, EventArgs e)
{
var version = (Spine.Version)comboBox_Version.SelectedValue;
if (listBox_FilePath.Items.Count <= 0)
{
MessageBox.Show("未选择任何文件", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
foreach (string p in listBox_FilePath.Items)
{
if (!File.Exists(p))
{
MessageBox.Show($"{p}", "skel文件不存在", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
if (!Spine.Spine.ImplementedVersions.Contains(version) ||
!SkeletonConverter.ImplementedVersions.Contains(version))
{
MessageBox.Show($"{version.String()} 版本尚未实现(咕咕咕~", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
SkelPaths = listBox_FilePath.Items.Cast<string>().ToArray();
Version = version;
ConvertToJson = radioButton_BinarySource.Checked;
DialogResult = DialogResult.OK;
}
private void button_Cancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
private void radioButton_Source_CheckedChanged(object sender, EventArgs e)
{
if (radioButton_BinarySource.Checked)
radioButton_JsonTarget.Checked = true;
else
radioButton_BinaryTarget.Checked = true;
}
private void radioButton_Target_CheckedChanged(object sender, EventArgs e)
{
if (radioButton_BinaryTarget.Checked)
radioButton_JsonSource.Checked = true;
else
radioButton_BinarySource.Checked = true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -184,7 +184,7 @@
// toolStripMenuItem_ManageResource
//
toolStripMenuItem_ManageResource.Name = "toolStripMenuItem_ManageResource";
toolStripMenuItem_ManageResource.Size = new Size(270, 34);
toolStripMenuItem_ManageResource.Size = new Size(260, 34);
toolStripMenuItem_ManageResource.Text = "管理下载资源(&M)...";
//
// toolStripMenuItem_Help

View File

@@ -160,8 +160,69 @@ namespace SpineViewer
private void toolStripMenuItem_ConvertFileFormat_Click(object sender, EventArgs e)
{
var openDialog = new Dialogs.ConvertFileFormatDialog();
if (openDialog.ShowDialog() != DialogResult.OK)
return;
return;
var progressDialog = new Dialogs.ProgressDialog();
progressDialog.DoWork += ConvertFileFormat_Work;
progressDialog.RunWorkerAsync(openDialog);
progressDialog.ShowDialog();
}
private void ConvertFileFormat_Work(object? sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
var arguments = e.Argument as Dialogs.ConvertFileFormatDialog;
var skelPaths = arguments.SkelPaths;
var version = arguments.Version;
var convertToJson = arguments.ConvertToJson;
var newSuffix = convertToJson ? ".json" : ".skel";
int totalCount = skelPaths.Length;
int success = 0;
int error = 0;
SkeletonConverter cvter = SkeletonConverter.New(version);
worker.ReportProgress(0, $"已处理 0/{totalCount}");
for (int i = 0; i < totalCount; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
var skelPath = skelPaths[i];
var newPath = Path.ChangeExtension(skelPath, newSuffix);
try
{
if (convertToJson)
cvter.BinaryToJson(skelPath, newPath);
else
cvter.JsonToBinary(skelPath, newPath);
success++;
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to convert {}", skelPath);
error++;
}
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
}
if (error > 0)
{
Program.Logger.Warn("Batch convert {} successfully, {} failed", success, error);
}
else
{
Program.Logger.Info("{} skel converted successfully", success);
}
}
private void toolStripMenuItem_About_Click(object sender, EventArgs e)

View File

@@ -346,8 +346,7 @@ namespace SpineViewer.Spine.Implementations.SkeletonConverter
data["int"] = reader.ReadVarInt(false);
data["float"] = reader.ReadFloat();
data["string"] = reader.ReadString();
string audio = reader.ReadString();
if (audio is not null)
if (reader.ReadString() is string audio)
{
data["audio"] = audio;
data["volume"] = reader.ReadFloat();

View File

@@ -35,6 +35,7 @@ namespace SpineViewer.Spine
/// 实现类缓存
/// </summary>
private static readonly Dictionary<Version, Type> ImplementationTypes = [];
public static readonly Dictionary<Version, Type>.KeyCollection ImplementedVersions;
/// <summary>
/// 静态构造函数
@@ -54,6 +55,7 @@ namespace SpineViewer.Spine
}
}
Program.Logger.Debug("Find SkeletonConverter implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
ImplementedVersions = ImplementationTypes.Keys;
}
/// <summary>