预修改适配对多轨道动画
This commit is contained in:
@@ -607,7 +607,7 @@ namespace SpineViewer.Controls
|
||||
lock (SpineListView.Spines)
|
||||
{
|
||||
foreach (var spine in SpineListView.Spines)
|
||||
spine.CurrentAnimation = spine.CurrentAnimation;
|
||||
spine.Track0Animation = spine.Track0Animation; // TODO: 多轨道重置
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,7 +619,7 @@ namespace SpineViewer.Controls
|
||||
lock (SpineListView.Spines)
|
||||
{
|
||||
foreach (var spine in SpineListView.Spines)
|
||||
spine.CurrentAnimation = spine.CurrentAnimation;
|
||||
spine.Track0Animation = spine.Track0Animation; // TODO: 多轨道重置
|
||||
}
|
||||
}
|
||||
IsUpdating = true;
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace SpineViewer.Exporter.Implementations.Exporter
|
||||
{
|
||||
var args = (VideoExportArgs)ExportArgs;
|
||||
|
||||
// 独立导出时如果 args.Duration 小于 0 则使用自己的动画时长
|
||||
// 独立导出时如果 args.Duration 小于 0 则使用 Track0 的动画时长
|
||||
var duration = args.Duration;
|
||||
if (duration < 0) duration = spine.CurrentAnimationDuration;
|
||||
if (duration < 0) duration = spine.GetAnimationDuration(spine.Track0Animation); // TODO: 也许可以使用所有轨道的最大值
|
||||
|
||||
float delta = 1f / args.FPS;
|
||||
int total = Math.Max(1, (int)(duration * args.FPS)); // 至少导出 1 帧
|
||||
@@ -75,7 +75,7 @@ namespace SpineViewer.Exporter.Implementations.Exporter
|
||||
public override void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
||||
{
|
||||
// 导出视频格式需要把模型时间都重置到 0
|
||||
foreach (var spine in spines) spine.CurrentAnimation = spine.CurrentAnimation;
|
||||
foreach (var spine in spines) spine.Track0Animation = spine.Track0Animation; // TODO: 多轨道重置
|
||||
base.Export(spines, worker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +82,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -113,8 +109,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var animation = CurrentAnimation;
|
||||
var skin = CurrentSkin;
|
||||
var animation = Track0Animation; // TODO: 适配多轨道
|
||||
var skin = Skin;
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
@@ -137,8 +133,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
CurrentAnimation = animation;
|
||||
CurrentSkin = skin;
|
||||
Track0Animation = animation; // TODO: 适配多轨道
|
||||
Skin = skin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +161,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
set { skeleton.FlipY = value; Update(0); }
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -178,18 +186,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -112,8 +108,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
var position = Position;
|
||||
var flipX = FlipX;
|
||||
var flipY = FlipY;
|
||||
var animation = CurrentAnimation;
|
||||
var skin = CurrentSkin;
|
||||
var animation = Track0Animation; // TODO: 适配多轨道
|
||||
var skin = Skin;
|
||||
|
||||
var val = Math.Max(value, SCALE_MIN);
|
||||
if (skeletonBinary is not null)
|
||||
@@ -136,8 +132,8 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
Position = position;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
CurrentAnimation = animation;
|
||||
CurrentSkin = skin;
|
||||
Track0Animation = animation; // TODO: 适配多轨道
|
||||
Skin = skin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +160,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
set { skeleton.FlipY = value; Update(0); }
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -177,18 +185,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -79,10 +79,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -137,7 +133,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -150,18 +158,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -85,10 +85,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -143,7 +139,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -156,18 +164,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -139,7 +135,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -152,18 +160,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -139,7 +135,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -152,18 +160,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -81,10 +81,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
|
||||
foreach (var anime in skeletonData.Animations)
|
||||
animationNames.Add(anime.Name);
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
CurrentAnimation = animationNames.Last();
|
||||
CurrentSkin = skinNames.Last();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -139,7 +135,19 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentAnimation
|
||||
public override string Skin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Track0Animation
|
||||
{
|
||||
get => animationState.GetCurrent(0)?.Animation.Name ?? EMPTY_ANIMATION;
|
||||
set
|
||||
@@ -152,18 +160,6 @@ namespace SpineViewer.Spine.Implementations.Spine
|
||||
}
|
||||
}
|
||||
|
||||
public override string CurrentSkin
|
||||
{
|
||||
get => skeleton.Skin?.Name ?? "default";
|
||||
set
|
||||
{
|
||||
if (!skinNames.Contains(value)) return;
|
||||
skeleton.SetSkin(value);
|
||||
skeleton.SetSlotsToSetupPose();
|
||||
Update(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override RectangleF Bounds
|
||||
{
|
||||
get
|
||||
|
||||
@@ -182,7 +182,38 @@ namespace SpineViewer.Spine
|
||||
{
|
||||
throw new NotImplementedException($"Not implemented version: {version}");
|
||||
}
|
||||
return (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
|
||||
|
||||
var spine = (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
|
||||
|
||||
// 统一初始化
|
||||
spine.initBounds = spine.Bounds;
|
||||
|
||||
// XXX: tex 没办法在这里主动 Dispose
|
||||
// 批量添加在获取预览图的时候极大概率会和预览线程死锁
|
||||
// 虽然两边不会同时调用 Draw, 但是死锁似乎和 Draw 函数有关
|
||||
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
||||
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
||||
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
||||
tex.SetView(spine.InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||
tex.Draw(spine);
|
||||
tex.Display();
|
||||
|
||||
using (var img = tex.Texture.CopyToImage())
|
||||
{
|
||||
img.SaveToMemory(out var imgBuffer, "bmp");
|
||||
using (var stream = new MemoryStream(imgBuffer))
|
||||
{
|
||||
// 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错
|
||||
spine.preview = new Bitmap(new Bitmap(stream));
|
||||
}
|
||||
}
|
||||
|
||||
// 取最后一个作为初始, 尽可能去显示非默认的内容
|
||||
spine.Skin = spine.SkinNames.Last();
|
||||
spine.Track0Animation = spine.AnimationNames.Last();
|
||||
|
||||
return spine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -300,26 +331,6 @@ namespace SpineViewer.Spine
|
||||
|
||||
#region 属性 | [3] 动画
|
||||
|
||||
/// <summary>
|
||||
/// 包含的所有动画名称
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public ReadOnlyCollection<string> AnimationNames { get => animationNames.AsReadOnly(); }
|
||||
protected List<string> animationNames = [EMPTY_ANIMATION];
|
||||
|
||||
/// <summary>
|
||||
/// 当前动画名称, 如果设置的动画不存在则忽略
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(AnimationConverter))]
|
||||
[Category("[3] 动画"), DisplayName("当前动画")]
|
||||
public abstract string CurrentAnimation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前动画时长
|
||||
/// </summary>
|
||||
[Category("[3] 动画"), DisplayName("当前动画时长")]
|
||||
public float CurrentAnimationDuration { get => GetAnimationDuration(CurrentAnimation); }
|
||||
|
||||
/// <summary>
|
||||
/// 包含的所有皮肤名称
|
||||
/// </summary>
|
||||
@@ -328,11 +339,31 @@ namespace SpineViewer.Spine
|
||||
protected List<string> skinNames = [];
|
||||
|
||||
/// <summary>
|
||||
/// 当前皮肤名称, 如果设置的皮肤不存在则忽略
|
||||
/// 使用的皮肤名称, 如果设置的皮肤不存在则忽略
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SkinConverter))]
|
||||
[Category("[3] 动画"), DisplayName("当前皮肤")]
|
||||
public abstract string CurrentSkin { get; set; }
|
||||
[Category("[3] 动画"), DisplayName("皮肤")]
|
||||
public abstract string Skin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包含的所有动画名称
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public ReadOnlyCollection<string> AnimationNames { get => animationNames.AsReadOnly(); }
|
||||
protected List<string> animationNames = [EMPTY_ANIMATION];
|
||||
|
||||
/// <summary>
|
||||
/// 默认轨道动画名称, 如果设置的动画不存在则忽略
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(AnimationConverter))]
|
||||
[Category("[3] 动画"), DisplayName("默认轨道动画")]
|
||||
public abstract string Track0Animation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认轨道动画时长
|
||||
/// </summary>
|
||||
[Category("[3] 动画"), DisplayName("默认轨道动画时长")]
|
||||
public float Track0AnimationDuration { get => GetAnimationDuration(Track0Animation); } // TODO: 动画时长变成伪属性在面板显示
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -395,55 +426,15 @@ namespace SpineViewer.Spine
|
||||
/// 初始状态下的骨骼包围盒
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public RectangleF InitBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initBounds is null)
|
||||
{
|
||||
var tmp = CurrentAnimation;
|
||||
CurrentAnimation = EMPTY_ANIMATION;
|
||||
initBounds = Bounds;
|
||||
CurrentAnimation = tmp;
|
||||
}
|
||||
return (RectangleF)initBounds;
|
||||
}
|
||||
}
|
||||
private RectangleF? initBounds = null;
|
||||
public RectangleF InitBounds { get => initBounds; }
|
||||
private RectangleF initBounds;
|
||||
|
||||
/// <summary>
|
||||
/// 骨骼预览图
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public Image Preview
|
||||
{
|
||||
get
|
||||
{
|
||||
if (preview is null)
|
||||
{
|
||||
// XXX: tex 没办法在这里主动 Dispose
|
||||
// 批量添加在获取预览图的时候极大概率会和预览线程死锁
|
||||
// 虽然两边不会同时调用 Draw, 但是死锁似乎和 Draw 函数有关
|
||||
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
||||
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
||||
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
||||
tex.SetView(InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||
var tmp = CurrentAnimation;
|
||||
CurrentAnimation = EMPTY_ANIMATION;
|
||||
tex.Draw(this);
|
||||
CurrentAnimation = tmp;
|
||||
tex.Display();
|
||||
|
||||
using var img = tex.Texture.CopyToImage();
|
||||
img.SaveToMemory(out var imgBuffer, "bmp");
|
||||
using var stream = new MemoryStream(imgBuffer);
|
||||
preview = new Bitmap(new Bitmap(stream)); // 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错
|
||||
}
|
||||
return preview;
|
||||
}
|
||||
}
|
||||
private Image preview = null;
|
||||
public Image Preview { get => preview; }
|
||||
private Image preview;
|
||||
|
||||
/// <summary>
|
||||
/// 获取动画时长, 如果动画不存在则返回 0
|
||||
|
||||
Reference in New Issue
Block a user