Created
February 11, 2021 23:46
-
-
Save goaaats/7ad97e70a37e4ed46485b90a8a152442 to your computer and use it in GitHub Desktop.
Extracts FFXIV icons with Lumina
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Drawing; | |
using System.Drawing.Imaging; | |
using System.IO; | |
using Lumina.Data.Files; | |
using Cyalume = Lumina.Lumina; | |
namespace LuminaIconExtract | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var lumina = new Cyalume(args[0]); | |
var start = int.Parse(args[1]); | |
var end = int.Parse(args[2]); | |
var outPath = new DirectoryInfo("out"); | |
if (!outPath.Exists) | |
outPath.Create(); | |
for (var i = start; i < end; i++) | |
{ | |
var icon = GetIcon(lumina, i); | |
if (icon == null) | |
continue; | |
Console.WriteLine($"-> {i:D6}"); | |
var folder = outPath.CreateSubdirectory($"{i / 1000:D3}000"); | |
GetImage(icon).Save(Path.Combine(folder.FullName, $"{i:D6}.png"), ImageFormat.Png); | |
} | |
} | |
private enum ClientLanguage | |
{ | |
Japanese, | |
English, | |
German, | |
French | |
} | |
/// <summary> | |
/// Get a <see cref="TexFile"/> containing the icon with the given ID. | |
/// </summary> | |
/// <param name="iconId">The icon ID.</param> | |
/// <returns>The <see cref="TexFile"/> containing the icon.</returns> | |
private static TexFile GetIcon(Cyalume lumina, int iconId) | |
{ | |
return GetIcon(lumina, ClientLanguage.English, iconId); | |
} | |
/// <summary> | |
/// Get a <see cref="TexFile"/> containing the icon with the given ID, of the given language. | |
/// </summary> | |
/// <param name="iconLanguage">The requested language.</param> | |
/// <param name="iconId">The icon ID.</param> | |
/// <returns>The <see cref="TexFile"/> containing the icon.</returns> | |
private static TexFile GetIcon(Cyalume lumina, ClientLanguage iconLanguage, int iconId) | |
{ | |
var type = iconLanguage switch | |
{ | |
ClientLanguage.Japanese => "ja/", | |
ClientLanguage.English => "en/", | |
ClientLanguage.German => "de/", | |
ClientLanguage.French => "fr/", | |
_ => throw new ArgumentOutOfRangeException(nameof(iconLanguage), | |
"Unknown Language: " + iconLanguage) | |
}; | |
return GetIcon(lumina, type, iconId); | |
} | |
private const string IconFileFormat = "ui/icon/{0:D3}000/{1}{2:D6}.tex"; | |
/// <summary> | |
/// Get a <see cref="TexFile"/> containing the icon with the given ID, of the given type. | |
/// </summary> | |
/// <param name="type">The type of the icon (e.g. 'hq' to get the HQ variant of an item icon).</param> | |
/// <param name="iconId">The icon ID.</param> | |
/// <returns>The <see cref="TexFile"/> containing the icon.</returns> | |
private static TexFile GetIcon(Cyalume lumina, string type, int iconId) | |
{ | |
type ??= string.Empty; | |
if (type.Length > 0 && !type.EndsWith("/")) | |
type += "/"; | |
var filePath = string.Format(IconFileFormat, iconId / 1000, type, iconId); | |
var file = lumina.GetFile<TexFile>(filePath); | |
if (file != default(TexFile) || type.Length <= 0) return file; | |
// Couldn't get specific type, try for generic version. | |
filePath = string.Format(IconFileFormat, iconId / 1000, string.Empty, iconId); | |
file = lumina.GetFile<TexFile>(filePath); | |
return file; | |
} | |
private static unsafe Image GetImage(TexFile tex) | |
{ | |
// this is terrible please find something better or get rid of .net imaging altogether | |
Image image; | |
fixed (byte* p = tex.ImageData) | |
{ | |
var ptr = (IntPtr)p; | |
using var tempImage = new Bitmap(tex.Header.Width, tex.Header.Height, tex.Header.Width * 4, PixelFormat.Format32bppArgb, ptr); | |
image = new Bitmap(tempImage); | |
} | |
return image; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment