VPet/VPet-Simulator.Core/Graph/PNGAnimation.cs

316 lines
12 KiB
C#
Raw Normal View History

2024-03-30 07:00:02 +00:00
using LinePutScript;
using System;
2022-12-13 07:10:18 +00:00
using System.Collections.Generic;
2024-03-30 07:00:02 +00:00
using System.Drawing;
2022-12-13 07:10:18 +00:00
using System.IO;
2024-03-30 07:00:02 +00:00
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
2022-12-13 07:10:18 +00:00
using System.Windows.Controls;
using System.Windows.Media.Imaging;
2024-04-17 04:48:07 +00:00
using static VPet_Simulator.Core.IGraph;
2023-05-31 17:47:23 +00:00
using static VPet_Simulator.Core.Picture;
2022-12-13 07:10:18 +00:00
namespace VPet_Simulator.Core
{
2023-08-12 05:44:17 +00:00
2022-12-13 07:10:18 +00:00
/// <summary>
/// PNGAnimation.xaml 的交互逻辑
/// </summary>
2023-06-01 08:16:45 +00:00
public partial class PNGAnimation : IImageRun
2022-12-13 07:10:18 +00:00
{
/// <summary>
/// 所有动画帧
/// </summary>
public List<Animation> Animations;
/// <summary>
/// 是否循环播放
/// </summary>
public bool IsLoop { get; set; }
2023-07-16 23:58:09 +00:00
/// <summary>
/// 动画信息
/// </summary>
public GraphInfo GraphInfo { get; private set; }
2022-12-13 07:10:18 +00:00
2023-01-20 17:01:10 +00:00
/// <summary>
2023-02-22 05:37:23 +00:00
/// 是否准备完成
/// </summary>
public bool IsReady { get; private set; } = false;
2024-04-17 04:48:07 +00:00
public TaskControl Control { get; set; }
2022-12-13 07:10:18 +00:00
int nowid;
/// <summary>
/// 图片资源
/// </summary>
2023-03-26 22:46:23 +00:00
public string Path;
2023-03-26 22:35:19 +00:00
private GraphCore GraphCore;
/// <summary>
2023-08-15 10:16:52 +00:00
/// 反正一次性生成太多导致闪退
/// </summary>
public static int NowLoading = 0;
/// <summary>
2022-12-13 07:10:18 +00:00
/// 新建 PNG 动画
/// </summary>
2023-02-13 09:48:59 +00:00
/// <param name="path">文件夹位置</param>
/// <param name="paths">文件内容列表</param>
2022-12-13 07:10:18 +00:00
/// <param name="isLoop">是否循环</param>
2023-07-16 23:58:09 +00:00
public PNGAnimation(GraphCore graphCore, string path, FileInfo[] paths, GraphInfo graphinfo, bool isLoop = false)
2022-12-13 07:10:18 +00:00
{
Animations = new List<Animation>();
IsLoop = isLoop;
2023-01-22 17:33:13 +00:00
//StoreMemory = storemem;
2023-07-16 23:58:09 +00:00
GraphInfo = graphinfo;
2023-03-26 22:35:19 +00:00
GraphCore = graphCore;
if (!GraphCore.CommConfig.ContainsKey("PA_Setup"))
{
GraphCore.CommConfig["PA_Setup"] = true;
GraphCore.CommUIElements["Image1.PNGAnimation"] = new System.Windows.Controls.Image() { Height = 500 };
GraphCore.CommUIElements["Image2.PNGAnimation"] = new System.Windows.Controls.Image() { Height = 500 };
2024-04-17 04:48:07 +00:00
GraphCore.CommUIElements["Image3.PNGAnimation"] = new System.Windows.Controls.Image() { Height = 500 }; // 多整个, 防止动画闪烁
2023-03-26 22:35:19 +00:00
}
2023-02-22 05:37:23 +00:00
Task.Run(() => startup(path, paths));
2022-12-13 07:10:18 +00:00
}
2023-03-26 22:35:19 +00:00
2023-05-31 17:47:23 +00:00
public static void LoadGraph(GraphCore graph, FileSystemInfo path, ILine info)
{
2023-07-16 23:58:09 +00:00
if (!(path is DirectoryInfo p))
2023-05-31 17:47:23 +00:00
{
Picture.LoadGraph(graph, path, info);
return;
}
var paths = p.GetFiles();
2023-07-16 23:58:09 +00:00
2023-05-31 17:47:23 +00:00
bool isLoop = info[(gbol)"loop"];
2023-07-24 01:53:18 +00:00
PNGAnimation pa = new PNGAnimation(graph, path.FullName, paths, new GraphInfo(path, info), isLoop);
2023-07-16 23:58:09 +00:00
graph.AddGraph(pa);
2023-05-31 17:47:23 +00:00
}
2023-03-26 22:35:19 +00:00
public double Width;
/// <summary>
/// 最大同时加载数
/// </summary>
2024-03-29 15:33:24 +00:00
public static int MaxLoadNumber = 40;
2023-03-26 22:35:19 +00:00
2023-02-22 05:37:23 +00:00
private void startup(string path, FileInfo[] paths)
{
while (NowLoading > MaxLoadNumber)
2023-08-15 10:16:52 +00:00
{
Thread.Sleep(100);
}
Interlocked.Increment(ref NowLoading);
2023-02-22 05:37:23 +00:00
//新方法:加载大图片
//生成大文件加载非常慢,先看看有没有缓存能用
Path = System.IO.Path.Combine(GraphCore.CachePath, $"{GraphCore.Resolution}_{Math.Abs(Sub.GetHashCode(path))}_{paths.Length}.png");
2024-03-29 15:33:24 +00:00
Width = 500 * (paths.Length + 1);
if (!File.Exists(Path) && !((List<string>)GraphCore.CommConfig["Cache"]).Contains(path))
2023-02-22 05:37:23 +00:00
{
2023-05-15 10:44:30 +00:00
((List<string>)GraphCore.CommConfig["Cache"]).Add(path);
int w = 0;
int h = 0;
FileInfo firstImage = paths[0];
var img = System.Drawing.Image.FromFile(firstImage.FullName);
w = img.Width;
h = img.Height;
if (w > GraphCore.Resolution)
2023-08-12 06:09:20 +00:00
{
w = GraphCore.Resolution;
h = (int)(h * (GraphCore.Resolution / (double)img.Width));
}
2024-03-29 15:33:24 +00:00
if (paths.Length * w >= 60000)
{//修复大长动画导致过长分辨率导致可能的报错
2023-08-31 17:43:10 +00:00
w = 60000 / paths.Length;
h = (int)(img.Height * (w / (double)img.Width));
2023-08-12 06:09:20 +00:00
}
using (Bitmap joinedBitmap = new Bitmap(w * paths.Length, h))
using (Graphics graph = Graphics.FromImage(joinedBitmap))
2023-02-22 05:37:23 +00:00
{
using (img)
graph.DrawImage(img, 0, 0, w, h);
Parallel.For(1, paths.Length, i =>
{
using (var img = System.Drawing.Image.FromFile(paths[i].FullName))
{
lock (graph)
graph.DrawImage(img, w * i, 0, w, h);
}
});
if (!File.Exists(Path))
joinedBitmap.Save(Path);
2023-02-22 05:37:23 +00:00
}
}
for (int i = 0; i < paths.Length; i++)
{
var noExtFileName = System.IO.Path.GetFileNameWithoutExtension(paths[i].Name);
int time = int.Parse(noExtFileName.Substring(noExtFileName.LastIndexOf('_') + 1));
Animations.Add(new Animation(this, time, -500 * i));
2023-02-22 05:37:23 +00:00
}
2023-03-26 22:46:23 +00:00
//stream = new MemoryStream(File.ReadAllBytes(cp));
IsReady = true;
Interlocked.Decrement(ref NowLoading);
2023-02-22 05:37:23 +00:00
}
2022-12-13 07:10:18 +00:00
/// <summary>
/// 单帧动画
/// </summary>
public class Animation
{
private PNGAnimation parent;
2023-03-26 22:35:19 +00:00
public int MarginWIX;
///// <summary>
///// 显示
///// </summary>
//public Action Visible;
2023-02-13 09:48:59 +00:00
///// <summary>
///// 隐藏
///// </summary>
//public Action Hidden;
2022-12-13 07:10:18 +00:00
/// <summary>
/// 帧时间
/// </summary>
public int Time;
2023-03-26 22:35:19 +00:00
public Animation(PNGAnimation parent, int time, int wxi)//, Action hidden)
2022-12-13 07:10:18 +00:00
{
this.parent = parent;
Time = time;
2023-03-26 22:35:19 +00:00
//Visible = visible;
2023-02-13 09:48:59 +00:00
//Hidden = hidden;
2023-03-26 22:35:19 +00:00
MarginWIX = wxi;
2022-12-13 07:10:18 +00:00
}
/// <summary>
/// 运行该图层
/// </summary>
2024-04-17 04:48:07 +00:00
/// <param name="Control">动画控制</param>
/// <param name="This">显示的图层</param>
public void Run(FrameworkElement This, TaskControl Control)
2022-12-13 07:10:18 +00:00
{
//先显示该图层
2023-03-26 22:35:19 +00:00
This.Dispatcher.Invoke(() => This.Margin = new Thickness(MarginWIX, 0, 0, 0));
2022-12-13 07:10:18 +00:00
//然后等待帧时间毫秒
Thread.Sleep(Time);
2022-12-13 07:10:18 +00:00
//判断是否要下一步
2024-04-17 04:48:07 +00:00
switch (Control.Type)
2022-12-13 07:10:18 +00:00
{
2024-04-17 04:48:07 +00:00
case TaskControl.ControlType.Stop:
Control.EndAction?.Invoke();
return;
case TaskControl.ControlType.Status_Stoped:
return;
case TaskControl.ControlType.Status_Quo:
case TaskControl.ControlType.Continue:
if (++parent.nowid >= parent.Animations.Count)
if (parent.IsLoop)
parent.nowid = 0;
else if (Control.Type == TaskControl.ControlType.Continue)
{
Control.Type = TaskControl.ControlType.Status_Quo;
parent.nowid = 0;
}
else
{
Control.Type = TaskControl.ControlType.Status_Stoped;
2024-04-17 21:09:46 +00:00
Control.EndAction?.Invoke(); //运行结束动画时事件
2024-04-17 04:48:07 +00:00
return;
}
//要下一步
parent.Animations[parent.nowid].Run(This, Control);
return;
2022-12-13 07:10:18 +00:00
}
}
}
/// <summary>
/// 从0开始运行该动画
/// </summary>
2024-04-11 15:36:01 +00:00
public void Run(Decorator parant, Action EndAction = null)
2022-12-13 07:10:18 +00:00
{
2024-03-29 15:33:24 +00:00
if (!IsReady)
{
EndAction?.Invoke();
return;
}
2024-04-17 04:48:07 +00:00
if (Control?.PlayState == true)
2023-01-20 17:01:10 +00:00
{//如果当前正在运行,重置状态
2024-04-17 04:48:07 +00:00
Control.Stop(() => Run(parant, EndAction));
2023-01-20 17:01:10 +00:00
return;
}
2022-12-13 07:10:18 +00:00
nowid = 0;
2024-04-17 04:48:07 +00:00
Control = new TaskControl(EndAction);
2023-03-26 22:35:19 +00:00
parant.Dispatcher.Invoke(() =>
{
2023-03-26 22:35:19 +00:00
if (parant.Tag == this)
{
2024-04-17 04:48:07 +00:00
Task.Run(() => Animations[0].Run((System.Windows.Controls.Image)parant.Child, Control));
2023-03-26 22:35:19 +00:00
return;
}
System.Windows.Controls.Image img;
2023-03-28 13:18:14 +00:00
2023-03-26 22:35:19 +00:00
if (parant.Child == GraphCore.CommUIElements["Image1.PNGAnimation"])
{
img = (System.Windows.Controls.Image)GraphCore.CommUIElements["Image1.PNGAnimation"];
}
2024-04-17 04:48:07 +00:00
else if (parant.Child == GraphCore.CommUIElements["Image3.PNGAnimation"])
{
img = (System.Windows.Controls.Image)GraphCore.CommUIElements["Image3.PNGAnimation"];
}
2023-03-26 22:35:19 +00:00
else
{
img = (System.Windows.Controls.Image)GraphCore.CommUIElements["Image2.PNGAnimation"];
if (parant.Child != GraphCore.CommUIElements["Image2.PNGAnimation"])
{
if (img.Parent == null)
{
parant.Child = img;
}
else
{
2023-08-12 05:44:17 +00:00
img = (System.Windows.Controls.Image)GraphCore.CommUIElements["Image1.PNGAnimation"];
2023-08-13 07:28:08 +00:00
if (img.Parent != null)
((Decorator)img.Parent).Child = null;
2023-03-26 22:35:19 +00:00
parant.Child = img;
}
}
}
parant.Tag = this;
2023-03-26 22:46:23 +00:00
img.Source = new BitmapImage(new Uri(Path));
2023-03-26 22:35:19 +00:00
img.Width = Width;
2024-04-17 04:48:07 +00:00
Task.Run(() => Animations[0].Run((System.Windows.Controls.Image)parant.Child, Control));
2023-03-28 13:18:14 +00:00
});
2022-12-13 07:10:18 +00:00
}
2023-05-31 17:47:23 +00:00
/// <summary>
/// 指定图像图像控件准备运行该动画
/// </summary>
/// <param name="img">用于显示的Image</param>
/// <param name="EndAction">结束动画</param>
/// <returns>准备好的线程</returns>
2023-08-16 03:09:32 +00:00
public Task Run(System.Windows.Controls.Image img, Action EndAction = null)
2023-05-31 17:47:23 +00:00
{
2024-04-17 04:48:07 +00:00
if (!IsReady)
{
EndAction?.Invoke();
return Task.CompletedTask;
}
if (Control?.PlayState == true)
{//如果当前正在运行,重置状态
Control.EndAction = null;
Control.Type = TaskControl.ControlType.Stop;
}
2023-05-31 17:47:23 +00:00
nowid = 0;
2024-04-17 04:48:07 +00:00
Control = new TaskControl(EndAction);
2023-05-31 17:47:23 +00:00
return img.Dispatcher.Invoke(() =>
2024-04-17 04:48:07 +00:00
{
if (img.Tag == this)
{
return new Task(() => Animations[0].Run(img, Control));
}
img.Tag = this;
img.Source = new BitmapImage(new Uri(Path));
img.Width = Width;
return new Task(() => Animations[0].Run(img, Control));
});
2022-12-13 07:10:18 +00:00
}
2024-04-17 04:48:07 +00:00
2022-12-13 07:10:18 +00:00
}
}