ArtemisFgTools/ArtemisFgTools/Program.cs
2024-10-31 23:42:33 +08:00

342 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using ImageMagick;
using NLua;
using System.Text.RegularExpressions;
using static ArtemisFgTools.FgHelper;
namespace ArtemisFgTools
{
internal class Program
{
static void Main()
{
Console.WriteLine("请输入立绘fg文件夹的所在路径无需\"\"");
string? fgImagePath = Console.ReadLine();
Console.WriteLine("要合并的游戏有找到exlist吗(y/n) ");
string spModeStr = Console.ReadLine() ?? throw new Exception("Invalid input");
bool spMode = (spModeStr == "n") || (spModeStr == "y" ? false : throw new Exception("Invalid input"));
string? luaFilePath = Console.ReadLine();
if (spMode)
{
dosth();
return;
}
Console.WriteLine("请输入保存位置:");
string? savePath = Console.ReadLine();
if (string.IsNullOrEmpty(fgImagePath) || string.IsNullOrEmpty(luaFilePath) || string.IsNullOrEmpty(savePath))
{
Console.WriteLine("路径不能为空");
return;
}
if (!Directory.Exists(fgImagePath) || !File.Exists(luaFilePath))
{
Console.WriteLine("路径不存在");
return;
}
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
Dictionary<object, object>? dictionary = ParseLuaTable(luaFilePath);
if (dictionary != null)
{
if (dictionary["fg"] is Dictionary<object, object> fgDictionary)
{
if (fgDictionary["size"] is not List<object> size || size.Count == 0)
{
throw new Exception("size not found or empty");
}
fgDictionary.Remove("size");
//convert to FgObject
List<FgObject> fgObjects = [];
foreach (var fg in fgDictionary)
{
if (fg.Value is Dictionary<object, object> fgValue)
{
var fuku = ConvertToStringList(fgValue["fuku"] as List<object>);
var pose = ConvertToNestedStringList(fgValue["pose"] as List<object>);
var face = ConvertToStringDictionary(fgValue["face"] as Dictionary<object, object>);
//check null
if (fgValue["path"] is not string path || fgValue["head"] is not string head || fuku == null || pose == null || face == null)
{
Console.WriteLine("fg object has null value");
continue;
}
path = path[4..]; // remove :fg/../
fgObjects.Add(new FgObject(path, head, fuku, pose, face));
}
}
//jmp
foreach (var fgObject in fgObjects)
{
foreach (var siz in size)
{
if (siz != null && fgObject.Path != null)
{
string savePathWithSizePart = Path.Combine(savePath, fgObject.Path, siz.ToString() ?? string.Empty);
string pathWithSize = Path.Combine(fgImagePath, fgObject.Path, siz.ToString() ?? string.Empty);
foreach (var pose in fgObject.Pose)
{
Parallel.ForEach(fgObject.Fuku, fuku =>
{
//💢 skip //For ハミダシクリエイティブ
if (fuku == "99")
{
return;
}
bool special = false;
string special_text = "";
string fuku_current = fuku;
int index = fuku_current.IndexOf('|');
if (index != -1)
{
special = true;
special_text = fuku_current[(index + 1)..];
fuku_current = fuku_current[..index];
}
// <head><siz><pose[0]><fuku><pose[1]>0
// *sp:fuku: 02 | 0099→02fuku & 0099face
string baseImg = Path.Combine(pathWithSize, $"{fgObject.Head}{siz}{pose[0]}{fuku_current}{pose[1]}0.png");
foreach (var face in fgObject.Face[pose[0]])
{
string layerImg = Path.Combine(pathWithSize, $"{face}.png");
string layer2Img = special ? Path.Combine(pathWithSize, $"{pose[0]}{special_text}.png") : ""; //眼镜
string savePathWithAll = Path.Combine(savePathWithSizePart, $"{fgObject.Head}{siz}{pose[0]}{fuku_current}{pose[1]}0_{face}" + (special ? ($"_{pose[0]}{special_text}.png") : (".png")));
ProcessAndSave(baseImg, layerImg, layer2Img, savePathWithAll, special);
}
});
}
}
}
string siz2 = "fa"; //别急着换下一个还有个fa //这里的代码和上面那块一样
if (fgObject.Path != null)
{
string savePathWithSizePart = Path.Combine(savePath, fgObject.Path, siz2.ToString() ?? string.Empty);
string pathWithSize = Path.Combine(fgImagePath, fgObject.Path, siz2.ToString() ?? string.Empty);
foreach (var pose in fgObject.Pose)
{
Parallel.ForEach(fgObject.Fuku, fuku =>
{
//💢 skip //For ハミダシクリエイティブ
if (fuku == "99")
{
return;
}
bool special = false;
string special_text = "";
string fuku_current = fuku;
int index = fuku_current.IndexOf('|');
if (index != -1)
{
special = true;
special_text = fuku_current[(index + 1)..];
fuku_current = fuku_current[..index];
}
string baseImg = Path.Combine(pathWithSize, $"{fgObject.Head}no{pose[0]}{fuku_current}{pose[1]}0.png");
foreach (var face in fgObject.Face[pose[0]])
{
string layerImg = Path.Combine(pathWithSize, $"{face}.png");
string layer2Img = special ? Path.Combine(pathWithSize, $"{pose[0]}{special_text}.png") : "";
string savePathWithAll = Path.Combine(savePathWithSizePart, $"{fgObject.Head}no{pose[0]}{fuku_current}{pose[1]}0_{face}" + (special ? ($"_{pose[0]}{special_text}.png") : (".png")));
ProcessAndSave(baseImg, layerImg, layer2Img, savePathWithAll, special);
}
});
}
}
}
}
else
{
Console.WriteLine("fg not found");
}
}
}
private static void dosth()
{
throw new NotImplementedException();
}
private static void ProcessAndSave(string baseImg, string layerImg, string layer2Img, string target, bool special)
{
if (File.Exists(target))
{
Console.WriteLine($"{Path.GetFileName(target)}已存在,跳过!");
return;
}
string? directory = Path.GetDirectoryName(target);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using MagickImage firstImage = new(baseImg);
List<int> comment1 = ReadPngComment(firstImage.Comment); //base
using MagickImage secondImage = new(layerImg);
List<int> comment2 = ReadPngComment(secondImage.Comment); //face
int x = comment2[0] - comment1[0]; // face x - base x
int y = comment2[1] - comment1[1]; // face y - base y
firstImage.Composite(secondImage, x, y, CompositeOperator.Over);
if (special)
{
using MagickImage thirdImage = new(layer2Img);
List<int> comment3 = ReadPngComment(thirdImage.Comment); //face
x = comment3[0] - comment1[0]; // face x - base x
y = comment3[1] - comment1[1]; // face y - base y
firstImage.Composite(thirdImage, x, y, CompositeOperator.Over);
}
//确保target所处位置文件夹是存在的不存在则创建
firstImage.Write(target);
Console.WriteLine($"{Path.GetFileName(target)}图像合并完成!");
}
static Dictionary<object, object>? ParseLuaTable(string luaFilePath)
{
Lua lua = new();
try
{
lua.DoFile(luaFilePath);
}
catch (Exception ex)
{
Console.WriteLine($"Error loading Lua file: {ex.Message}");
return null;
}
LuaTable luaTable = lua.GetTable("exfgtable");
if (luaTable != null)
{
return (Dictionary<object, object>?)LuaTableToSs(luaTable);
}
else
{
Console.WriteLine("Lua table not found");
return null;
}
}
static object LuaTableToSs(LuaTable luaTable)
{
if (NeedConvertList(luaTable))
{
List<object> list = [];
foreach (var key in luaTable.Keys)
{
object value = luaTable[key];
if (value is LuaTable nestedTable)
{
list.Add(LuaTableToSs(nestedTable));
}
else
{
list.Add(value);
}
}
return list;
}
else
{
Dictionary<object, object> dictionary = [];
foreach (var key in luaTable.Keys)
{
object value = luaTable[key];
if (value is LuaTable nestedTable)
{
dictionary[key] = LuaTableToSs(nestedTable);
}
else
{
dictionary[key] = value;
}
}
return dictionary;
}
}
private static bool NeedConvertList(LuaTable luaTable)
{
long index = 1;
foreach (var key in luaTable.Keys)
{
if (key is string)
{
return false;
}
else
{
long n = (long)key;
if (n != index)
{
return false;
}
index++;
}
}
return true;
}
private static List<string>? ConvertToStringList(List<object>? list)
{
return list?.ConvertAll(item => item?.ToString() ?? string.Empty);
}
private static List<List<string>> ConvertToNestedStringList(List<object>? list)
{
if (list == null) return [];
return list.ConvertAll(item => ConvertToStringList(item as List<object>) ?? []);
}
private static Dictionary<string, List<string>>? ConvertToStringDictionary(Dictionary<object, object>? dictionary)
{
if (dictionary == null) return null;
Dictionary<string, List<string>> result = [];
foreach (var kvp in dictionary)
{
result[kvp.Key?.ToString() ?? string.Empty] = ConvertToStringList(kvp.Value as List<object>) ?? [];
}
return result;
}
public static List<int> ReadPngComment(string? comment)
{
if (comment != null)
{
string pattern = @"^pos,(-?\d+),(-?\d+),(-?\d+),(-?\d+)$";
Match match = Regex.Match(comment, pattern);
if (match.Success)
{
int x = int.Parse(match.Groups[1].Value);
int y = int.Parse(match.Groups[2].Value);
int w = int.Parse(match.Groups[3].Value);
int h = int.Parse(match.Groups[4].Value);
return [x, y, w, h];
}
else
{
throw new Exception("Unexpected result");
}
}
else
{
throw new Exception("Comment not found");
}
}
}
}