Initial commit
This commit is contained in:
commit
e84f027bd5
6 changed files with 885 additions and 0 deletions
23
DgfTxmConvert/DgfTxmConvert.csproj
Normal file
23
DgfTxmConvert/DgfTxmConvert.csproj
Normal file
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.0-beta.74" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="LibDgf">
|
||||
<HintPath>..\..\LibDgf\LibDgf\bin\Debug\netstandard2.0\LibDgf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="LibDgf.Graphics">
|
||||
<HintPath>..\..\LibDgf\LibDgf.Graphics\bin\Debug\netstandard2.0\LibDgf.Graphics.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
402
DgfTxmConvert/Program.cs
Normal file
402
DgfTxmConvert/Program.cs
Normal file
|
@ -0,0 +1,402 @@
|
|||
using LibDgf.Dat;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Path = System.IO.Path;
|
||||
using LibDgf.Aqualead;
|
||||
using LibDgf.Aqualead.Image.Conversion;
|
||||
using LibDgf;
|
||||
using LibDgf.Txm;
|
||||
using LibDgf.Aqualead.Image;
|
||||
using LibDgf.Aqualead.Texture;
|
||||
using System.Diagnostics;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using LibDgf.Graphics;
|
||||
using System.Threading.Tasks;
|
||||
using McMaster.Extensions.CommandLineUtils;
|
||||
|
||||
namespace DgfTxmConvert
|
||||
{
|
||||
class Program
|
||||
{
|
||||
const string ETC1TOOL_PATH = @"etc1tool.exe";
|
||||
|
||||
static List<IAlImageConverter> imageConverters;
|
||||
|
||||
static int Main(string[] args)
|
||||
{
|
||||
imageConverters = new List<IAlImageConverter>
|
||||
{
|
||||
new PkmConverter(),
|
||||
//new KtxConverter(),
|
||||
new PngConverter(),
|
||||
};
|
||||
|
||||
var app = new CommandLineApplication
|
||||
{
|
||||
Name = Path.GetFileName(Environment.GetCommandLineArgs()[0]),
|
||||
FullName = "DDG Final TXM Converter"
|
||||
};
|
||||
|
||||
app.Command("convert-dat", config =>
|
||||
{
|
||||
config.FullName = "Convert DAT to images";
|
||||
config.Description = "Converts each individual TXM in a DAT into PNGs.";
|
||||
|
||||
var datPathArg = config.Argument("datPath", "Path of the DAT to extract").IsRequired();
|
||||
datPathArg.Accepts().ExistingFile();
|
||||
config.HelpOption();
|
||||
|
||||
config.OnExecute(() =>
|
||||
{
|
||||
ConvertDat(datPathArg.Value);
|
||||
});
|
||||
});
|
||||
|
||||
app.Command("convert-txm", config =>
|
||||
{
|
||||
config.FullName = "Convert TXM to image";
|
||||
config.Description = "Converts TXM to PNG.";
|
||||
|
||||
var txmPathArg = config.Argument("txmPath", "Path of the TXM to convert").IsRequired();
|
||||
txmPathArg.Accepts().ExistingFile();
|
||||
config.HelpOption();
|
||||
|
||||
config.OnExecute(() =>
|
||||
{
|
||||
ConvertTxm(txmPathArg.Value);
|
||||
});
|
||||
});
|
||||
|
||||
app.Command("replace-dat", config =>
|
||||
{
|
||||
config.FullName = "Replace image in DAT";
|
||||
config.Description = "Converts list of images and replaces entries in DAT file";
|
||||
|
||||
var srcDatPath = config.Argument("srcDatPath", "Path of the source DAT").IsRequired();
|
||||
srcDatPath.Accepts().ExistingFile();
|
||||
var listPath = config.Argument("listPath", "Path of the image replacement list").IsRequired();
|
||||
listPath.Accepts().ExistingFile();
|
||||
var destDatPath = config.Argument("destDatPath", "Path to output DAT to").IsRequired();
|
||||
listPath.Accepts().LegalFilePath();
|
||||
config.HelpOption();
|
||||
|
||||
config.OnExecute(() =>
|
||||
{
|
||||
ReplaceDatImages(srcDatPath.Value, destDatPath.Value, listPath.Value);
|
||||
});
|
||||
});
|
||||
|
||||
app.VersionOptionFromAssemblyAttributes(System.Reflection.Assembly.GetExecutingAssembly());
|
||||
app.HelpOption();
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
app.ShowHelp();
|
||||
return 1;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (CommandParsingException ex)
|
||||
{
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
return 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("Error while processing: {0}", ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ReplaceDatImages(string srcDatPath, string destDatPath, string replacementList)
|
||||
{
|
||||
List<string> tempPaths = new List<string>();
|
||||
try
|
||||
{
|
||||
using (DatReader dat = new DatReader(File.OpenRead(srcDatPath)))
|
||||
{
|
||||
DatBuilder builder = new DatBuilder(dat);
|
||||
using (StreamReader sr = File.OpenText(replacementList))
|
||||
{
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
var line = sr.ReadLine();
|
||||
var lineSplit = line.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (lineSplit.Length != 2)
|
||||
throw new InvalidDataException($"Invalid line \"{line}\".");
|
||||
if (!int.TryParse(lineSplit[0], out var imageIndex))
|
||||
throw new InvalidDataException($"Invalid index on line \"{line}\".");
|
||||
|
||||
string tempPath = Path.GetTempFileName();
|
||||
tempPaths.Add(tempPath);
|
||||
using (FileStream fs = File.Create(tempPath))
|
||||
{
|
||||
TxmConversion.ConvertImageToTxm(lineSplit[1], fs);
|
||||
}
|
||||
|
||||
builder.ReplacementEntries.Add(new DatBuilder.ReplacementEntry
|
||||
{
|
||||
Index = imageIndex,
|
||||
SourceFile = tempPath
|
||||
});
|
||||
}
|
||||
}
|
||||
using (FileStream fs = File.Create(destDatPath))
|
||||
{
|
||||
builder.Build(fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var path in tempPaths)
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ConvertDat(string path)
|
||||
{
|
||||
using (Stream fs = Utils.CheckDecompress(File.OpenRead(path)))
|
||||
using (DatReader dat = new DatReader(fs))
|
||||
{
|
||||
for (int i = 0; i < dat.EntriesCount; ++i)
|
||||
{
|
||||
using (MemoryStream subfile = new MemoryStream(dat.GetData(i)))
|
||||
{
|
||||
string outPath = path + $"_{i}.png";
|
||||
Console.WriteLine(outPath);
|
||||
try
|
||||
{
|
||||
TxmConversion.ConvertTxmToPng(subfile, outPath);
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
File.WriteAllBytes(path + $"_{i}.txm", subfile.ToArray());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void BulkConvertDat(string inPath, string filter, bool recursive)
|
||||
{
|
||||
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
ConvertDat(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertTxm(string path)
|
||||
{
|
||||
using (Stream fs = Utils.CheckDecompress(File.OpenRead(path)))
|
||||
{
|
||||
string outPath = Path.ChangeExtension(path, ".png");
|
||||
TxmConversion.ConvertTxmToPng(fs, outPath);
|
||||
}
|
||||
}
|
||||
|
||||
static void BulkConvertTxm(string inPath, string filter, bool recursive)
|
||||
{
|
||||
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
string outPath = Path.ChangeExtension(path, ".png");
|
||||
Console.WriteLine(outPath);
|
||||
ConvertTxm(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void BulkConvertAtx(string inPath, string filter, bool recursive)
|
||||
{
|
||||
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
Console.WriteLine(path);
|
||||
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
||||
{
|
||||
var tex = new AlTexture();
|
||||
tex.Read(new BinaryReader(fs));
|
||||
|
||||
var img = new AlImage();
|
||||
using (Stream ms = Utils.CheckDecompress(new MemoryStream(tex.ImageData)))
|
||||
{
|
||||
img.Read(new BinaryReader(ms));
|
||||
ConvertAig(img, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void BulkConvertAtxMulti(string inPath, string filter, bool recursive)
|
||||
{
|
||||
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
||||
{
|
||||
var tex = new AlTexture();
|
||||
tex.Read(new BinaryReader(fs));
|
||||
|
||||
if (tex.ChildTextures.Count < 2) continue;
|
||||
Console.WriteLine(path);
|
||||
|
||||
var img = new AlImage();
|
||||
using (Stream ms = Utils.CheckDecompress(new MemoryStream(tex.ImageData)))
|
||||
{
|
||||
img.Read(new BinaryReader(ms));
|
||||
if (img.PixelFormat != "BGRA")
|
||||
{
|
||||
Console.WriteLine("Not BGRA, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
using (MemoryStream ims = new MemoryStream(img.Mipmaps[0]))
|
||||
using (var imgConv = PngConverter.ConvertBgra32(new BinaryReader(ims), (int)img.Width, (int)img.Height))
|
||||
{
|
||||
foreach (var child in tex.ChildTextures)
|
||||
{
|
||||
// First mip only
|
||||
var bounds = child.Bounds[0];
|
||||
using (var childImage = new Image<Bgra32>(bounds.W, bounds.H))
|
||||
{
|
||||
childImage.Mutate(ctx => ctx.DrawImage(imgConv, new Point(-bounds.X, -bounds.Y), 1f));
|
||||
childImage.SaveAsPng($"{Path.ChangeExtension(path, null)}_{child.Id:x8}.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void BulkConvertAtxToPng(string inPath, string filter, bool recursive)
|
||||
{
|
||||
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
Console.WriteLine(path);
|
||||
string fileExtension;
|
||||
|
||||
// Export the texture (probably KTX)
|
||||
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
||||
{
|
||||
var tex = new AlTexture();
|
||||
tex.Read(new BinaryReader(fs));
|
||||
|
||||
var img = new AlImage();
|
||||
using (Stream ms = Utils.CheckDecompress(new MemoryStream(tex.ImageData)))
|
||||
{
|
||||
img.Read(new BinaryReader(ms));
|
||||
fileExtension = ConvertAig(img, path);
|
||||
}
|
||||
}
|
||||
|
||||
if (fileExtension != ".pkm") continue;
|
||||
|
||||
// Convert main texture to PNG
|
||||
string mainPath = Path.ChangeExtension(path, fileExtension);
|
||||
var startInfo = new ProcessStartInfo(ETC1TOOL_PATH);
|
||||
startInfo.ArgumentList.Add(mainPath);
|
||||
startInfo.ArgumentList.Add("--decode");
|
||||
startInfo.CreateNoWindow = false;
|
||||
startInfo.UseShellExecute = false;
|
||||
Process.Start(startInfo).WaitForExit();
|
||||
|
||||
// Convert alpha texture if present
|
||||
string altPath = $"{Path.ChangeExtension(path, null)}_alt{fileExtension}";
|
||||
if (File.Exists(altPath))
|
||||
{
|
||||
startInfo = new ProcessStartInfo(ETC1TOOL_PATH);
|
||||
startInfo.ArgumentList.Add(altPath);
|
||||
startInfo.ArgumentList.Add("--decode");
|
||||
startInfo.CreateNoWindow = false;
|
||||
startInfo.UseShellExecute = false;
|
||||
Process.Start(startInfo).WaitForExit();
|
||||
|
||||
var mainPngPath = Path.ChangeExtension(mainPath, ".png");
|
||||
var altPngPath = Path.ChangeExtension(altPath, ".png");
|
||||
|
||||
using (var mainImg = Image.Load<Rgb24>(mainPngPath))
|
||||
using (var altImg = Image.Load<Rgb24>(altPngPath))
|
||||
{
|
||||
using (var mergedImg = MergeAlpha(mainImg, altImg))
|
||||
using (FileStream newFs = File.Create(mainPngPath))
|
||||
{
|
||||
mergedImg.SaveAsPng(newFs);
|
||||
}
|
||||
}
|
||||
|
||||
File.Delete(altPngPath);
|
||||
File.Delete(altPath);
|
||||
}
|
||||
|
||||
File.Delete(mainPath);
|
||||
}
|
||||
}
|
||||
|
||||
static Image<Rgba32> MergeAlpha(Image<Rgb24> main, Image<Rgb24> alpha)
|
||||
{
|
||||
var newImg = new Image<Rgba32>(main.Width, main.Height);
|
||||
for (int y = 0; y < newImg.Height; ++y)
|
||||
{
|
||||
var newRow = newImg.GetPixelRowSpan(y);
|
||||
var mainRow = main.GetPixelRowSpan(y);
|
||||
var alphaRow = alpha.GetPixelRowSpan(y);
|
||||
for (int x = 0; x < newImg.Width; ++x)
|
||||
{
|
||||
var mainPix = mainRow[x];
|
||||
var alphaPix = alphaRow[x];
|
||||
newRow[x] = new Rgba32(mainPix.R, mainPix.G, mainPix.B, alphaPix.R);
|
||||
}
|
||||
}
|
||||
return newImg;
|
||||
}
|
||||
|
||||
static void BulkConvertAig(string inPath, string filter, bool recursive)
|
||||
{
|
||||
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
Console.WriteLine(path);
|
||||
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
||||
{
|
||||
var img = new AlImage();
|
||||
img.Read(new BinaryReader(fs));
|
||||
ConvertAig(img, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string ConvertAig(AlImage img, string path)
|
||||
{
|
||||
foreach (var converter in imageConverters)
|
||||
{
|
||||
if (converter.CanConvert(img.PixelFormat))
|
||||
{
|
||||
string outPath = Path.ChangeExtension(path, converter.FileExtension);
|
||||
using (FileStream ofs = File.Create(outPath))
|
||||
{
|
||||
converter.ConvertFromAl(img, ofs);
|
||||
}
|
||||
if (converter.HasAlternativeFile(img))
|
||||
{
|
||||
outPath = Path.ChangeExtension(path, null);
|
||||
outPath = $"{outPath}_alt{converter.FileExtension}";
|
||||
using (FileStream ofs = File.Create(outPath))
|
||||
{
|
||||
converter.ConvertFromAlAlt(img, ofs);
|
||||
}
|
||||
}
|
||||
return converter.FileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Cannot find converter for {img.PixelFormat}");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue