增加预览图导出功能

This commit is contained in:
ww-rm
2025-03-19 16:29:10 +08:00
parent 091301e945
commit 008067fccb
7 changed files with 3912 additions and 197 deletions

View File

@@ -40,46 +40,6 @@ namespace SpineViewer.Controls
/// </summary> /// </summary>
public ListView.SelectedIndexCollection SelectedIndices { get => listView.SelectedIndices; } public ListView.SelectedIndexCollection SelectedIndices { get => listView.SelectedIndices; }
/// <summary>
/// 弹出添加对话框在指定位置之前插入一项
/// </summary>
private void Insert(int index = -1)
{
var dialog = new Dialogs.OpenSpineDialog();
if (dialog.ShowDialog() != DialogResult.OK)
return;
try
{
var spine = Spine.Spine.New(dialog.Version, dialog.SkelPath, dialog.AtlasPath);
// 如果索引无效则在末尾添加
if (index < 0 || index > listView.Items.Count)
index = listView.Items.Count;
// 锁定外部的读操作
lock (Spines)
{
spines.Insert(index, spine);
listView.SmallImageList.Images.Add(spine.ID, spine.Preview);
listView.LargeImageList.Images.Add(spine.ID, spine.Preview);
}
listView.Items.Insert(index, new ListViewItem(spine.Name, spine.ID) { ToolTipText = spine.SkelPath });
// 选中新增项
listView.SelectedIndices.Clear();
listView.SelectedIndices.Add(index);
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to load {} {}", dialog.SkelPath, dialog.AtlasPath);
MessageBox.Show(ex.ToString(), "骨骼加载失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Program.Logger.Info($"Current memory usage: {Program.Process.WorkingSet64 / 1024.0 / 1024.0:F2} MB");
}
/// <summary> /// <summary>
/// 弹出添加对话框 /// 弹出添加对话框
/// </summary> /// </summary>
@@ -103,61 +63,25 @@ namespace SpineViewer.Controls
progressDialog.ShowDialog(); progressDialog.ShowDialog();
} }
private void BatchAdd_Work(object? sender, DoWorkEventArgs e) public void ExportPreviews()
{ {
var worker = sender as BackgroundWorker; lock (Spines)
var arguments = e.Argument as Dialogs.BatchOpenSpineDialog;
var skelPaths = arguments.SkelPaths;
var version = arguments.Version;
int totalCount = skelPaths.Length;
int success = 0;
int error = 0;
worker.ReportProgress(0, $"已处理 0/{totalCount}");
for (int i = 0; i < totalCount; i++)
{ {
if (worker.CancellationPending) if (spines.Count <= 0)
{ {
e.Cancel = true; MessageBox.Show("请至少打开一个骨骼文件", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
break; return;
} }
var skelPath = skelPaths[i];
try
{
var spine = Spine.Spine.New(version, skelPath);
var preview = spine.Preview;
lock (Spines) { spines.Add(spine); }
listView.Invoke(() =>
{
listView.SmallImageList.Images.Add(spine.ID, preview);
listView.LargeImageList.Images.Add(spine.ID, preview);
listView.Items.Add(new ListViewItem(spine.Name, spine.ID) { ToolTipText = spine.SkelPath });
});
success++;
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to load {}", skelPath);
error++;
}
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
} }
if (error > 0) var saveDialog = new Dialogs.ExportPreviewDialog();
{ if (saveDialog.ShowDialog() != DialogResult.OK)
Program.Logger.Warn("Batch load {} successfully, {} failed", success, error); return;
}
else
{
Program.Logger.Info("{} skel loaded successfully", success);
}
Program.Logger.Info($"Current memory usage: {Program.Process.WorkingSet64 / 1024.0 / 1024.0:F2} MB"); var progressDialog = new Dialogs.ProgressDialog();
progressDialog.DoWork += ExportPreview_Work;
progressDialog.RunWorkerAsync(saveDialog);
progressDialog.ShowDialog();
} }
private void listView_SelectedIndexChanged(object sender, EventArgs e) private void listView_SelectedIndexChanged(object sender, EventArgs e)
@@ -379,5 +303,155 @@ namespace SpineViewer.Controls
{ {
listView.View = View.Details; listView.View = View.Details;
} }
/// <summary>
/// 弹出添加对话框在指定位置之前插入一项
/// </summary>
private void Insert(int index = -1)
{
var dialog = new Dialogs.OpenSpineDialog();
if (dialog.ShowDialog() != DialogResult.OK)
return;
try
{
var spine = Spine.Spine.New(dialog.Version, dialog.SkelPath, dialog.AtlasPath);
// 如果索引无效则在末尾添加
if (index < 0 || index > listView.Items.Count)
index = listView.Items.Count;
// 锁定外部的读操作
lock (Spines)
{
spines.Insert(index, spine);
listView.SmallImageList.Images.Add(spine.ID, spine.Preview);
listView.LargeImageList.Images.Add(spine.ID, spine.Preview);
}
listView.Items.Insert(index, new ListViewItem(spine.Name, spine.ID) { ToolTipText = spine.SkelPath });
// 选中新增项
listView.SelectedIndices.Clear();
listView.SelectedIndices.Add(index);
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to load {} {}", dialog.SkelPath, dialog.AtlasPath);
MessageBox.Show(ex.ToString(), "骨骼加载失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Program.Logger.Info($"Current memory usage: {Program.Process.WorkingSet64 / 1024.0 / 1024.0:F2} MB");
}
private void BatchAdd_Work(object? sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
var arguments = e.Argument as Dialogs.BatchOpenSpineDialog;
var skelPaths = arguments.SkelPaths;
var version = arguments.Version;
int totalCount = skelPaths.Length;
int success = 0;
int error = 0;
worker.ReportProgress(0, $"已处理 0/{totalCount}");
for (int i = 0; i < totalCount; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
var skelPath = skelPaths[i];
try
{
var spine = Spine.Spine.New(version, skelPath);
var preview = spine.Preview;
lock (Spines) { spines.Add(spine); }
listView.Invoke(() =>
{
listView.SmallImageList.Images.Add(spine.ID, preview);
listView.LargeImageList.Images.Add(spine.ID, preview);
listView.Items.Add(new ListViewItem(spine.Name, spine.ID) { ToolTipText = spine.SkelPath });
});
success++;
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to load {}", skelPath);
error++;
}
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
}
if (error > 0)
{
Program.Logger.Warn("Batch load {} successfully, {} failed", success, error);
}
else
{
Program.Logger.Info("{} skel loaded successfully", success);
}
Program.Logger.Info($"Current memory usage: {Program.Process.WorkingSet64 / 1024.0 / 1024.0:F2} MB");
}
private void ExportPreview_Work(object? sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
var arguments = e.Argument as Dialogs.ExportPreviewDialog;
var outputDir = arguments.OutputDir;
var width = arguments.PreviewWidth;
var height = arguments.PreviewHeight;
int success = 0;
int error = 0;
lock (Spines)
{
int totalCount = spines.Count;
worker.ReportProgress(0, $"已处理 0/{totalCount}");
for (int i = 0; i < totalCount; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
var spine = spines[i];
try
{
var preview = spine.GetPreview(width, height);
var savePath = Path.Combine(outputDir, $"{spine.Name}.png");
preview.SaveToFile(savePath);
success++;
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to save preview {}", spine.SkelPath);
error++;
}
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
}
}
if (error > 0)
{
Program.Logger.Warn("Preview save {} successfully, {} failed", success, error);
}
else
{
Program.Logger.Info("{} preview saved successfully", success);
}
Program.Logger.Info($"Current memory usage: {Program.Process.WorkingSet64 / 1024.0 / 1024.0:F2} MB");
}
} }
} }

View File

@@ -0,0 +1,269 @@
namespace SpineViewer.Dialogs
{
partial class ExportPreviewDialog
{
/// <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(ExportPreviewDialog));
panel1 = new Panel();
tableLayoutPanel1 = new TableLayoutPanel();
label4 = new Label();
label1 = new Label();
label2 = new Label();
label3 = new Label();
textBox_OutputDir = new TextBox();
button_SelectOutputDir = new Button();
tableLayoutPanel2 = new TableLayoutPanel();
button_Ok = new Button();
button_Cancel = new Button();
numericUpDown_Width = new NumericUpDown();
numericUpDown_Height = new NumericUpDown();
folderBrowserDialog = new FolderBrowserDialog();
panel1.SuspendLayout();
tableLayoutPanel1.SuspendLayout();
tableLayoutPanel2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)numericUpDown_Width).BeginInit();
((System.ComponentModel.ISupportInitialize)numericUpDown_Height).BeginInit();
SuspendLayout();
//
// panel1
//
panel1.Controls.Add(tableLayoutPanel1);
panel1.Dock = DockStyle.Fill;
panel1.Location = new Point(0, 0);
panel1.Name = "panel1";
panel1.Padding = new Padding(50, 15, 50, 10);
panel1.Size = new Size(919, 276);
panel1.TabIndex = 2;
//
// tableLayoutPanel1
//
tableLayoutPanel1.AutoSize = true;
tableLayoutPanel1.ColumnCount = 4;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
tableLayoutPanel1.Controls.Add(label4, 0, 0);
tableLayoutPanel1.Controls.Add(label1, 0, 1);
tableLayoutPanel1.Controls.Add(label2, 0, 2);
tableLayoutPanel1.Controls.Add(label3, 0, 3);
tableLayoutPanel1.Controls.Add(textBox_OutputDir, 1, 1);
tableLayoutPanel1.Controls.Add(button_SelectOutputDir, 3, 1);
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 4);
tableLayoutPanel1.Controls.Add(numericUpDown_Width, 1, 2);
tableLayoutPanel1.Controls.Add(numericUpDown_Height, 1, 3);
tableLayoutPanel1.Dock = DockStyle.Fill;
tableLayoutPanel1.Location = new Point(50, 15);
tableLayoutPanel1.Name = "tableLayoutPanel1";
tableLayoutPanel1.RowCount = 5;
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(819, 251);
tableLayoutPanel1.TabIndex = 0;
//
// 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(789, 24);
label4.TabIndex = 11;
label4.Text = "说明:导出的文件名与骨骼文件名相同";
label4.TextAlign = ContentAlignment.MiddleCenter;
//
// label1
//
label1.Anchor = AnchorStyles.Right;
label1.AutoSize = true;
label1.Location = new Point(3, 62);
label1.Name = "label1";
label1.Size = new Size(104, 24);
label1.TabIndex = 0;
label1.Text = "输出文件夹:";
//
// label2
//
label2.Anchor = AnchorStyles.Right;
label2.AutoSize = true;
label2.Location = new Point(75, 100);
label2.Name = "label2";
label2.Size = new Size(32, 24);
label2.TabIndex = 1;
label2.Text = "宽:";
//
// label3
//
label3.Anchor = AnchorStyles.Right;
label3.AutoSize = true;
label3.Location = new Point(75, 136);
label3.Name = "label3";
label3.Size = new Size(32, 24);
label3.TabIndex = 2;
label3.Text = "高:";
//
// textBox_OutputDir
//
tableLayoutPanel1.SetColumnSpan(textBox_OutputDir, 2);
textBox_OutputDir.Dock = DockStyle.Fill;
textBox_OutputDir.Location = new Point(113, 57);
textBox_OutputDir.Name = "textBox_OutputDir";
textBox_OutputDir.Size = new Size(664, 30);
textBox_OutputDir.TabIndex = 3;
//
// button_SelectOutputDir
//
button_SelectOutputDir.AutoSize = true;
button_SelectOutputDir.AutoSizeMode = AutoSizeMode.GrowAndShrink;
button_SelectOutputDir.Location = new Point(783, 57);
button_SelectOutputDir.Name = "button_SelectOutputDir";
button_SelectOutputDir.Size = new Size(32, 34);
button_SelectOutputDir.TabIndex = 5;
button_SelectOutputDir.Text = "...";
button_SelectOutputDir.UseVisualStyleBackColor = true;
button_SelectOutputDir.Click += button_SelectOutputDir_Click;
//
// 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, 208);
tableLayoutPanel2.Name = "tableLayoutPanel2";
tableLayoutPanel2.RowCount = 1;
tableLayoutPanel2.RowStyles.Add(new RowStyle());
tableLayoutPanel2.Size = new Size(813, 40);
tableLayoutPanel2.TabIndex = 10;
//
// button_Ok
//
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
button_Ok.Location = new Point(264, 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(436, 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;
//
// numericUpDown_Width
//
numericUpDown_Width.Anchor = AnchorStyles.Left;
numericUpDown_Width.Location = new Point(113, 97);
numericUpDown_Width.Maximum = new decimal(new int[] { 4096, 0, 0, 0 });
numericUpDown_Width.Minimum = new decimal(new int[] { 32, 0, 0, 0 });
numericUpDown_Width.Name = "numericUpDown_Width";
numericUpDown_Width.Size = new Size(180, 30);
numericUpDown_Width.TabIndex = 12;
numericUpDown_Width.TextAlign = HorizontalAlignment.Right;
numericUpDown_Width.Value = new decimal(new int[] { 256, 0, 0, 0 });
//
// numericUpDown_Height
//
numericUpDown_Height.Anchor = AnchorStyles.Left;
numericUpDown_Height.Location = new Point(113, 133);
numericUpDown_Height.Maximum = new decimal(new int[] { 4096, 0, 0, 0 });
numericUpDown_Height.Minimum = new decimal(new int[] { 32, 0, 0, 0 });
numericUpDown_Height.Name = "numericUpDown_Height";
numericUpDown_Height.Size = new Size(180, 30);
numericUpDown_Height.TabIndex = 13;
numericUpDown_Height.TextAlign = HorizontalAlignment.Right;
numericUpDown_Height.Value = new decimal(new int[] { 256, 0, 0, 0 });
//
// folderBrowserDialog
//
folderBrowserDialog.AddToRecent = false;
//
// ExportPreviewDialog
//
AcceptButton = button_Ok;
AutoScaleDimensions = new SizeF(11F, 24F);
AutoScaleMode = AutoScaleMode.Font;
CancelButton = button_Cancel;
ClientSize = new Size(919, 276);
Controls.Add(panel1);
FormBorderStyle = FormBorderStyle.FixedDialog;
Icon = (Icon)resources.GetObject("$this.Icon");
MaximizeBox = false;
MinimizeBox = false;
Name = "ExportPreviewDialog";
ShowInTaskbar = false;
StartPosition = FormStartPosition.CenterScreen;
Text = "导出预览图";
panel1.ResumeLayout(false);
panel1.PerformLayout();
tableLayoutPanel1.ResumeLayout(false);
tableLayoutPanel1.PerformLayout();
tableLayoutPanel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)numericUpDown_Width).EndInit();
((System.ComponentModel.ISupportInitialize)numericUpDown_Height).EndInit();
ResumeLayout(false);
}
#endregion
private Panel panel1;
private TableLayoutPanel tableLayoutPanel1;
private Label label4;
private Label label1;
private Label label2;
private Label label3;
private TextBox textBox_OutputDir;
private Button button_SelectOutputDir;
private TableLayoutPanel tableLayoutPanel2;
private Button button_Ok;
private Button button_Cancel;
private NumericUpDown numericUpDown_Width;
private NumericUpDown numericUpDown_Height;
private FolderBrowserDialog folderBrowserDialog;
}
}

View File

@@ -0,0 +1,75 @@
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 ExportPreviewDialog: Form
{
public string OutputDir { get; private set; }
public uint PreviewWidth { get; private set; }
public uint PreviewHeight { get; private set; }
public ExportPreviewDialog()
{
InitializeComponent();
}
private void button_SelectOutputDir_Click(object sender, EventArgs e)
{
folderBrowserDialog.InitialDirectory = textBox_OutputDir.Text;
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
textBox_OutputDir.Text = Path.GetFullPath(folderBrowserDialog.SelectedPath);
}
}
private void button_Ok_Click(object sender, EventArgs e)
{
var outputDir = textBox_OutputDir.Text;
if (File.Exists(outputDir))
{
MessageBox.Show("输出文件夹无效", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (!Directory.Exists(outputDir))
{
if (MessageBox.Show($"文件夹 {outputDir} 不存在,是否创建?", "操作确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
{
try
{
Directory.CreateDirectory(outputDir);
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
MessageBox.Show(ex.ToString(), "文件夹创建失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
else
{
return;
}
}
OutputDir = Path.GetFullPath(outputDir);
PreviewWidth = (uint)numericUpDown_Width.Value;
PreviewHeight = (uint)numericUpDown_Height.Value;
DialogResult = DialogResult.OK;
}
private void button_Cancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -63,6 +63,7 @@
spinePreviewer = new SpineViewer.Controls.SpinePreviewer(); spinePreviewer = new SpineViewer.Controls.SpinePreviewer();
panel_MainForm = new Panel(); panel_MainForm = new Panel();
toolTip = new ToolTip(components); toolTip = new ToolTip(components);
toolStripMenuItem_ExportPreview = new ToolStripMenuItem();
menuStrip.SuspendLayout(); menuStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)splitContainer_MainForm).BeginInit(); ((System.ComponentModel.ISupportInitialize)splitContainer_MainForm).BeginInit();
splitContainer_MainForm.Panel1.SuspendLayout(); splitContainer_MainForm.Panel1.SuspendLayout();
@@ -100,7 +101,7 @@
// //
// toolStripMenuItem_File // toolStripMenuItem_File
// //
toolStripMenuItem_File.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_Open, toolStripMenuItem_BatchOpen, toolStripSeparator1, toolStripMenuItem_Export, toolStripSeparator2, toolStripMenuItem_Exit }); toolStripMenuItem_File.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_Open, toolStripMenuItem_BatchOpen, toolStripSeparator1, toolStripMenuItem_Export, toolStripMenuItem_ExportPreview, toolStripSeparator2, toolStripMenuItem_Exit });
toolStripMenuItem_File.Name = "toolStripMenuItem_File"; toolStripMenuItem_File.Name = "toolStripMenuItem_File";
toolStripMenuItem_File.Size = new Size(84, 28); toolStripMenuItem_File.Size = new Size(84, 28);
toolStripMenuItem_File.Text = "文件(&F)"; toolStripMenuItem_File.Text = "文件(&F)";
@@ -109,40 +110,40 @@
// //
toolStripMenuItem_Open.Name = "toolStripMenuItem_Open"; toolStripMenuItem_Open.Name = "toolStripMenuItem_Open";
toolStripMenuItem_Open.ShortcutKeys = Keys.Control | Keys.O; toolStripMenuItem_Open.ShortcutKeys = Keys.Control | Keys.O;
toolStripMenuItem_Open.Size = new Size(254, 34); toolStripMenuItem_Open.Size = new Size(270, 34);
toolStripMenuItem_Open.Text = "打开(&O)..."; toolStripMenuItem_Open.Text = "打开(&O)...";
toolStripMenuItem_Open.Click += toolStripMenuItem_Open_Click; toolStripMenuItem_Open.Click += toolStripMenuItem_Open_Click;
// //
// toolStripMenuItem_BatchOpen // toolStripMenuItem_BatchOpen
// //
toolStripMenuItem_BatchOpen.Name = "toolStripMenuItem_BatchOpen"; toolStripMenuItem_BatchOpen.Name = "toolStripMenuItem_BatchOpen";
toolStripMenuItem_BatchOpen.Size = new Size(254, 34); toolStripMenuItem_BatchOpen.Size = new Size(270, 34);
toolStripMenuItem_BatchOpen.Text = "批量打开(&B)..."; toolStripMenuItem_BatchOpen.Text = "批量打开(&B)...";
toolStripMenuItem_BatchOpen.Click += toolStripMenuItem_BatchOpen_Click; toolStripMenuItem_BatchOpen.Click += toolStripMenuItem_BatchOpen_Click;
// //
// toolStripSeparator1 // toolStripSeparator1
// //
toolStripSeparator1.Name = "toolStripSeparator1"; toolStripSeparator1.Name = "toolStripSeparator1";
toolStripSeparator1.Size = new Size(251, 6); toolStripSeparator1.Size = new Size(267, 6);
// //
// toolStripMenuItem_Export // toolStripMenuItem_Export
// //
toolStripMenuItem_Export.Name = "toolStripMenuItem_Export"; toolStripMenuItem_Export.Name = "toolStripMenuItem_Export";
toolStripMenuItem_Export.ShortcutKeys = Keys.Control | Keys.S; toolStripMenuItem_Export.ShortcutKeys = Keys.Control | Keys.S;
toolStripMenuItem_Export.Size = new Size(254, 34); toolStripMenuItem_Export.Size = new Size(270, 34);
toolStripMenuItem_Export.Text = "导出(&E)..."; toolStripMenuItem_Export.Text = "导出(&E)...";
toolStripMenuItem_Export.Click += toolStripMenuItem_Export_Click; toolStripMenuItem_Export.Click += toolStripMenuItem_Export_Click;
// //
// toolStripSeparator2 // toolStripSeparator2
// //
toolStripSeparator2.Name = "toolStripSeparator2"; toolStripSeparator2.Name = "toolStripSeparator2";
toolStripSeparator2.Size = new Size(251, 6); toolStripSeparator2.Size = new Size(267, 6);
// //
// toolStripMenuItem_Exit // toolStripMenuItem_Exit
// //
toolStripMenuItem_Exit.Name = "toolStripMenuItem_Exit"; toolStripMenuItem_Exit.Name = "toolStripMenuItem_Exit";
toolStripMenuItem_Exit.ShortcutKeys = Keys.Alt | Keys.F4; toolStripMenuItem_Exit.ShortcutKeys = Keys.Alt | Keys.F4;
toolStripMenuItem_Exit.Size = new Size(254, 34); toolStripMenuItem_Exit.Size = new Size(270, 34);
toolStripMenuItem_Exit.Text = "退出(&X)"; toolStripMenuItem_Exit.Text = "退出(&X)";
toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click; toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click;
// //
@@ -156,7 +157,7 @@
// toolStripMenuItem_ResetAnimation // toolStripMenuItem_ResetAnimation
// //
toolStripMenuItem_ResetAnimation.Name = "toolStripMenuItem_ResetAnimation"; toolStripMenuItem_ResetAnimation.Name = "toolStripMenuItem_ResetAnimation";
toolStripMenuItem_ResetAnimation.Size = new Size(242, 34); toolStripMenuItem_ResetAnimation.Size = new Size(270, 34);
toolStripMenuItem_ResetAnimation.Text = "重置动画时间(&R)"; toolStripMenuItem_ResetAnimation.Text = "重置动画时间(&R)";
toolStripMenuItem_ResetAnimation.Click += toolStripMenuItem_ResetAnimation_Click; toolStripMenuItem_ResetAnimation.Click += toolStripMenuItem_ResetAnimation_Click;
// //
@@ -170,7 +171,7 @@
// toolStripMenuItem_ConvertFileFormat // toolStripMenuItem_ConvertFileFormat
// //
toolStripMenuItem_ConvertFileFormat.Name = "toolStripMenuItem_ConvertFileFormat"; toolStripMenuItem_ConvertFileFormat.Name = "toolStripMenuItem_ConvertFileFormat";
toolStripMenuItem_ConvertFileFormat.Size = new Size(254, 34); toolStripMenuItem_ConvertFileFormat.Size = new Size(270, 34);
toolStripMenuItem_ConvertFileFormat.Text = "转换文件格式(&C)..."; toolStripMenuItem_ConvertFileFormat.Text = "转换文件格式(&C)...";
toolStripMenuItem_ConvertFileFormat.Click += toolStripMenuItem_ConvertFileFormat_Click; toolStripMenuItem_ConvertFileFormat.Click += toolStripMenuItem_ConvertFileFormat_Click;
// //
@@ -184,7 +185,7 @@
// toolStripMenuItem_ManageResource // toolStripMenuItem_ManageResource
// //
toolStripMenuItem_ManageResource.Name = "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_ManageResource.Text = "管理下载资源(&M)...";
toolStripMenuItem_ManageResource.Click += toolStripMenuItem_ManageResource_Click; toolStripMenuItem_ManageResource.Click += toolStripMenuItem_ManageResource_Click;
// //
@@ -424,6 +425,13 @@
// //
toolTip.ShowAlways = true; toolTip.ShowAlways = true;
// //
// toolStripMenuItem_ExportPreviews
//
toolStripMenuItem_ExportPreview.Name = "toolStripMenuItem_ExportPreviews";
toolStripMenuItem_ExportPreview.Size = new Size(270, 34);
toolStripMenuItem_ExportPreview.Text = "导出预览图(&P)...";
toolStripMenuItem_ExportPreview.Click += toolStripMenuItem_ExportPreview_Click;
//
// MainForm // MainForm
// //
AutoScaleDimensions = new SizeF(11F, 24F); AutoScaleDimensions = new SizeF(11F, 24F);
@@ -501,5 +509,6 @@
private ToolStripMenuItem toolStripMenuItem_ManageResource; private ToolStripMenuItem toolStripMenuItem_ManageResource;
private ToolStripMenuItem toolStripMenuItem_Tool; private ToolStripMenuItem toolStripMenuItem_Tool;
private ToolStripMenuItem toolStripMenuItem_ConvertFileFormat; private ToolStripMenuItem toolStripMenuItem_ConvertFileFormat;
private ToolStripMenuItem toolStripMenuItem_ExportPreview;
} }
} }

View File

@@ -43,6 +43,101 @@ namespace SpineViewer
LogManager.ReconfigExistingLoggers(); LogManager.ReconfigExistingLoggers();
} }
private void MainForm_Load(object sender, EventArgs e)
{
spinePreviewer.StartPreview();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
spinePreviewer.StopPreview();
}
private void toolStripMenuItem_Open_Click(object sender, EventArgs e)
{
spineListView.Add();
}
private void toolStripMenuItem_BatchOpen_Click(object sender, EventArgs e)
{
spineListView.BatchAdd();
}
private void toolStripMenuItem_Export_Click(object sender, EventArgs e)
{
lock (spineListView.Spines)
{
if (spineListView.Spines.Count <= 0)
{
MessageBox.Show("请至少打开一个骨骼文件", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
var exportDialog = new Dialogs.ExportPngDialog();
if (exportDialog.ShowDialog() != DialogResult.OK)
return;
var progressDialog = new Dialogs.ProgressDialog();
progressDialog.DoWork += ExportPng_Work;
progressDialog.RunWorkerAsync(exportDialog);
progressDialog.ShowDialog();
}
private void toolStripMenuItem_ExportPreview_Click(object sender, EventArgs e)
{
spineListView.ExportPreviews();
}
private void toolStripMenuItem_Exit_Click(object sender, EventArgs e)
{
Close();
}
private void toolStripMenuItem_ResetAnimation_Click(object sender, EventArgs e)
{
lock (spineListView.Spines)
{
foreach (var spine in spineListView.Spines)
spine.CurrentAnimation = spine.CurrentAnimation;
}
}
private void toolStripMenuItem_ConvertFileFormat_Click(object sender, EventArgs e)
{
var openDialog = new Dialogs.ConvertFileFormatDialog();
if (openDialog.ShowDialog() != DialogResult.OK)
return;
var progressDialog = new Dialogs.ProgressDialog();
progressDialog.DoWork += ConvertFileFormat_Work;
progressDialog.RunWorkerAsync(openDialog);
progressDialog.ShowDialog();
}
private void toolStripMenuItem_ManageResource_Click(object sender, EventArgs e)
{
}
private void toolStripMenuItem_About_Click(object sender, EventArgs e)
{
(new Dialogs.AboutDialog()).ShowDialog();
}
private void toolStripMenuItem_Diagnostics_Click(object sender, EventArgs e)
{
(new Dialogs.DiagnosticsDialog()).ShowDialog();
}
private void splitContainer_SplitterMoved(object sender, SplitterEventArgs e) { ActiveControl = null; }
private void splitContainer_MouseUp(object sender, MouseEventArgs e) { ActiveControl = null; }
private void propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e) { (sender as PropertyGrid)?.Refresh(); }
private void spinePreviewer_MouseUp(object sender, MouseEventArgs e) { propertyGrid_Spine.Refresh(); }
private void ExportPng_Work(object? sender, DoWorkEventArgs e) private void ExportPng_Work(object? sender, DoWorkEventArgs e)
{ {
var worker = sender as BackgroundWorker; var worker = sender as BackgroundWorker;
@@ -105,73 +200,6 @@ namespace SpineViewer
spinePreviewer.StartPreview(); spinePreviewer.StartPreview();
} }
private void MainForm_Load(object sender, EventArgs e)
{
spinePreviewer.StartPreview();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
spinePreviewer.StopPreview();
}
private void toolStripMenuItem_Open_Click(object sender, EventArgs e)
{
spineListView.Add();
}
private void toolStripMenuItem_BatchOpen_Click(object sender, EventArgs e)
{
spineListView.BatchAdd();
}
private void toolStripMenuItem_Export_Click(object sender, EventArgs e)
{
lock (spineListView.Spines)
{
if (spineListView.Spines.Count <= 0)
{
MessageBox.Show("请至少打开一个骨骼文件", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
var exportDialog = new Dialogs.ExportPngDialog();
if (exportDialog.ShowDialog() != DialogResult.OK)
return;
var progressDialog = new Dialogs.ProgressDialog();
progressDialog.DoWork += ExportPng_Work;
progressDialog.RunWorkerAsync(exportDialog);
progressDialog.ShowDialog();
}
private void toolStripMenuItem_Exit_Click(object sender, EventArgs e)
{
Close();
}
private void toolStripMenuItem_ResetAnimation_Click(object sender, EventArgs e)
{
lock (spineListView.Spines)
{
foreach (var spine in spineListView.Spines)
spine.CurrentAnimation = spine.CurrentAnimation;
}
}
private void toolStripMenuItem_ConvertFileFormat_Click(object sender, EventArgs e)
{
var openDialog = new Dialogs.ConvertFileFormatDialog();
if (openDialog.ShowDialog() != DialogResult.OK)
return;
var progressDialog = new Dialogs.ProgressDialog();
progressDialog.DoWork += ConvertFileFormat_Work;
progressDialog.RunWorkerAsync(openDialog);
progressDialog.ShowDialog();
}
private void ConvertFileFormat_Work(object? sender, DoWorkEventArgs e) private void ConvertFileFormat_Work(object? sender, DoWorkEventArgs e)
{ {
var worker = sender as BackgroundWorker; var worker = sender as BackgroundWorker;
@@ -236,28 +264,5 @@ namespace SpineViewer
Program.Logger.Info("{} skel converted successfully", success); Program.Logger.Info("{} skel converted successfully", success);
} }
} }
private void toolStripMenuItem_ManageResource_Click(object sender, EventArgs e)
{
}
private void toolStripMenuItem_About_Click(object sender, EventArgs e)
{
(new Dialogs.AboutDialog()).ShowDialog();
}
private void toolStripMenuItem_Diagnostics_Click(object sender, EventArgs e)
{
(new Dialogs.DiagnosticsDialog()).ShowDialog();
}
private void splitContainer_SplitterMoved(object sender, SplitterEventArgs e) { ActiveControl = null; }
private void splitContainer_MouseUp(object sender, MouseEventArgs e) { ActiveControl = null; }
private void propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e) { (sender as PropertyGrid)?.Refresh(); }
private void spinePreviewer_MouseUp(object sender, MouseEventArgs e) { propertyGrid_Spine.Refresh(); }
} }
} }

View File

@@ -244,17 +244,33 @@ namespace SpineViewer.Spine
/// 骨骼预览图 /// 骨骼预览图
/// </summary> /// </summary>
[Browsable(false)] [Browsable(false)]
public Image Preview { get => preview ??= GetPreview(PREVIEW_SIZE); } public Image Preview
{
get
{
if (preview is null)
{
using var img = GetPreview((uint)PREVIEW_SIZE.Width, (uint)PREVIEW_SIZE.Height);
img.SaveToMemory(out var imgBuffer, "bmp");
using var stream = new MemoryStream(imgBuffer);
preview = new Bitmap(stream);
}
return preview;
}
}
private Image preview = null; private Image preview = null;
public Image GetPreview(Size size) /// <summary>
/// 获取指定尺寸的预览图
/// </summary>
public SFML.Graphics.Image GetPreview(uint width, uint height)
{ {
var curAnimation = CurrentAnimation; var curAnimation = CurrentAnimation;
CurrentAnimation = EMPTY_ANIMATION; CurrentAnimation = EMPTY_ANIMATION;
var bounds = Bounds; var bounds = Bounds;
float viewX = size.Width; float viewX = width;
float viewY = size.Height; float viewY = height;
float sizeX = bounds.Width; float sizeX = bounds.Width;
float sizeY = bounds.Height; float sizeY = bounds.Height;
@@ -267,7 +283,7 @@ namespace SpineViewer.Spine
viewX *= scale; viewX *= scale;
viewY *= scale; viewY *= scale;
var tex = new SFML.Graphics.RenderTexture((uint)size.Width, (uint)size.Height); using var tex = new SFML.Graphics.RenderTexture(width, height);
var view = tex.GetView(); var view = tex.GetView();
view.Center = new(bounds.X + viewX / 2, bounds.Y + viewY / 2); view.Center = new(bounds.X + viewX / 2, bounds.Y + viewY / 2);
view.Size = new(viewX, -viewY); view.Size = new(viewX, -viewY);
@@ -276,10 +292,7 @@ namespace SpineViewer.Spine
tex.Draw(this); tex.Draw(this);
tex.Display(); tex.Display();
CurrentAnimation = curAnimation; CurrentAnimation = curAnimation;
using var img = tex.Texture.CopyToImage(); return tex.Texture.CopyToImage();
img.SaveToMemory(out var imgBuffer, "bmp");
using var stream = new MemoryStream(imgBuffer);
return new Bitmap(stream);
} }
/// <summary> /// <summary>