Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,4 @@ $RECYCLE.BIN/

# JetBrains
.idea
SaintCoinach.Cmd/Properties/launchSettings.json
29 changes: 20 additions & 9 deletions SaintCoinach.Cmd/Commands/ImageCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,28 @@ public ImageCommand(ARealmReversed realm)

public override async Task InvokeAsync(string[] paramList) {
try {
if (_Realm.Packs.TryGetFile(paramList[0].Trim(), out var file)) {
if (file is Imaging.ImageFile imgFile) {
var img = imgFile.GetImage();
var path = paramList[0].Trim();
if (_Realm.Packs.TryGetFile(path, out var file)) {
Imaging.ImageFile imgFile = null;
if (path.EndsWith(".atex")) {
imgFile = new Imaging.ImageFile((IO.FileDefault) file);
} else if (file is Imaging.ImageFile) {
imgFile = (Imaging.ImageFile) file;
}

var target = new FileInfo(Path.Combine(_Realm.GameVersion, file.Path));
if (!target.Directory.Exists)
target.Directory.Create();
var pngPath = target.FullName.Substring(0, target.FullName.Length - target.Extension.Length) + ".png";
img.Save(pngPath);
} else
if (imgFile is null) {
OutputError($"File is not an image (actual: {file.CommonHeader.FileType}).");
return;
}

var img = imgFile.GetImage();

var target = new FileInfo(Path.Combine(_Realm.GameVersion, file.Path));
if (!target.Directory.Exists)
target.Directory.Create();
var pngPath = target.FullName.Substring(0, target.FullName.Length - target.Extension.Length) + ".png";
img.Save(pngPath);

} else
OutputError("File not found.");
} catch (Exception e) {
Expand Down
34 changes: 33 additions & 1 deletion SaintCoinach/Imaging/ImageConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

using System.Drawing.Text;
using BCnEncoder.Decoder;
using BCnEncoder.Shared;
using DotSquish;

namespace SaintCoinach.Imaging {
Expand All @@ -14,7 +16,7 @@
public uint dwRGBBitCount;
public uint dwRBitMask;
public uint dwGBitMask;
public uint dwBBitMask;

Check warning on line 19 in SaintCoinach/Imaging/ImageConverter.cs

View workflow job for this annotation

GitHub Actions / Build on Windows

Field 'DDS_PIXELFORMAT.dwBBitMask' is never assigned to, and will always have its default value 0
public uint dwABitMask;
};

Expand All @@ -31,7 +33,7 @@
public uint dwReserved2;
public uint dwReserved3;
public uint dwReserved4;
public uint dwReserved5;

Check warning on line 36 in SaintCoinach/Imaging/ImageConverter.cs

View workflow job for this annotation

GitHub Actions / Build on Windows

Field 'DDS_HEADER.dwReserved5' is never assigned to, and will always have its default value 0
public uint dwReserved6;
public uint dwReserved7;
public uint dwReserved8;
Expand All @@ -41,7 +43,7 @@
public DDS_PIXELFORMAT ddspf;
public uint dwCaps;
public uint dwCaps2;
public uint dwCaps3;

Check warning on line 46 in SaintCoinach/Imaging/ImageConverter.cs

View workflow job for this annotation

GitHub Actions / Build on Windows

Field 'DDS_HEADER.dwCaps3' is never assigned to, and will always have its default value 0
public uint dwCaps4;
public uint dwReserved11;
};
Expand Down Expand Up @@ -103,6 +105,10 @@
ImageFormat.Dxt5, ProcessDxt5
}, {
ImageFormat.R3G3B2, ProcessR3G3B2
}, {
ImageFormat.BC5, ProcessBC5
}, {
ImageFormat.BC7, ProcessBC7
}
};

Expand Down Expand Up @@ -183,7 +189,7 @@
default:
System.Diagnostics.Debug.WriteLine("Texture format " + file.ImageHeader.Format.ToString() + " DDS export not supported!\n");
return null;
break;

Check warning on line 192 in SaintCoinach/Imaging/ImageConverter.cs

View workflow job for this annotation

GitHub Actions / Build on Windows

Unreachable code detected
}

format.dwSize = 32;
Expand Down Expand Up @@ -288,6 +294,32 @@
}
}

// https://github.com/0ceal0t/Dalamud-VFXEditor/blob/main/VFXEditor/Formats/TextureFormat/TextureDataFile.cs#L275

private static void ProcessBC5(byte[] src, byte[] dst, int width, int height) {
ProcessBC(src, dst, width, height, CompressionFormat.Bc5);
}

private static void ProcessBC7(byte[] src, byte[] dst, int width, int height) {
ProcessBC(src, dst, width, height, CompressionFormat.Bc7);
}

private static void ProcessBC(byte[] src, byte[] dst, int width, int height, CompressionFormat format) {
var decoder = new BcDecoder();
var output = decoder.DecodeRaw2D(src, width, height, format).ToArray();

var p = 0;
for (var i = 0; i < height; i++) {
for (var j = 0; j < width; j++) {
var pixel = output[i, j];
dst[p] = pixel.b;
dst[p + 1] = pixel.g;
dst[p + 2] = pixel.r;
dst[p + 3] = pixel.a;
p += 4;
}
}
}
#endregion
}
}
12 changes: 12 additions & 0 deletions SaintCoinach/Imaging/ImageFile.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;

Expand Down Expand Up @@ -38,6 +39,17 @@ public ImageFile(Pack pack, FileCommonHeader commonHeader)
ImageHeader = new ImageHeader(stream);
}

// For atex texture files
public ImageFile(FileDefault file) : base(file.Pack, file.CommonHeader) {
var data = file.GetData();

var stream = new MemoryStream(data);
ImageHeader = new ImageHeader(stream);
var imgData = new byte[data.Length - ImageHeader.EndOfHeader];
Array.Copy(data, ImageHeader.EndOfHeader, imgData, 0, imgData.Length);
_BufferCache = new WeakReference<byte[]>(imgData);
}

#endregion

#region Read
Expand Down
15 changes: 14 additions & 1 deletion SaintCoinach/Imaging/ImageFormat.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
namespace SaintCoinach.Imaging {
public enum ImageFormat {
Unknown = 0,
R16G16F = 0x2250,
A16R16G16B16Float = 0x2460,
A32R32G32B32Float = 0x2470,

A8R8G8B8_1 = 0x1131,
A8R8G8B8_2 = 0x1450,
A8R8G8B8_Cube = 0x1451,
A8R8G8B82 = 0x1452,
A8R8G8B8_4 = 0x2150,
A8R8G8B8_5 = 0x4401,

A4R4G4B4 = 0x1440,
A1R5G5B5 = 0x1441,
R3G3B2 = 0x1130,
L8 = 0x1130,
A8 = 0x1131,

Dxt1 = 0x3420,
Dxt3 = 0x3430,
Dxt5 = 0x3431
Dxt5 = 0x3431,

D16 = 0x4140,
D24S8 = 0x4250,

Shadow16 = 0x5140,
Shadow24 = 0x5150,
BC5 = 0x6230,
BC7 = 0x6432,
}
}
1 change: 1 addition & 0 deletions SaintCoinach/SaintCoinach.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BCnEncoder.Net" Version="2.2.0" />
<PackageReference Include="DotNetZip" Version="1.16.0" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Expand Down
Loading