mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add Targa export.
This commit is contained in:
parent
c4853434c8
commit
ded910d8a1
5 changed files with 67 additions and 22 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 552246e595ffab2aaba2c75f578d564f8938fc9a
|
||||
Subproject commit a38e9bcfb80c456102945bbb4c59f5621cae0442
|
||||
|
|
@ -10,6 +10,7 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA
|
|||
=> textureType switch
|
||||
{
|
||||
TextureType.Png => textureManager.SavePng(inputFile, outputFile),
|
||||
TextureType.Targa => textureManager.SaveTga(inputFile, outputFile),
|
||||
TextureType.AsIsTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, true, inputFile, outputFile),
|
||||
TextureType.AsIsDds => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, false, inputFile, outputFile),
|
||||
TextureType.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, inputFile, outputFile),
|
||||
|
|
@ -26,6 +27,7 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA
|
|||
=> textureType switch
|
||||
{
|
||||
TextureType.Png => textureManager.SavePng(new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
|
||||
TextureType.Targa => textureManager.SaveTga(new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
|
||||
TextureType.AsIsTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
|
||||
TextureType.AsIsDds => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
|
||||
TextureType.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
|
||||
|
|
|
|||
|
|
@ -55,6 +55,14 @@ public partial class CombinedTexture : IDisposable
|
|||
SaveTask = textures.SavePng(_current.BaseImage, path, _current.RgbaPixels, _current.TextureWrap!.Width, _current.TextureWrap!.Height);
|
||||
}
|
||||
|
||||
public void SaveAsTarga(TextureManager textures, string path)
|
||||
{
|
||||
if (!IsLoaded || _current == null)
|
||||
return;
|
||||
|
||||
SaveTask = textures.SaveTga(_current.BaseImage, path, _current.RgbaPixels, _current.TextureWrap!.Width, _current.TextureWrap!.Height);
|
||||
}
|
||||
|
||||
private void SaveAs(TextureManager textures, string path, TextureSaveType type, bool mipMaps, bool writeTex)
|
||||
{
|
||||
if (!IsLoaded || _current == null)
|
||||
|
|
@ -72,6 +80,7 @@ public partial class CombinedTexture : IDisposable
|
|||
".tex" => TextureType.Tex,
|
||||
".dds" => TextureType.Dds,
|
||||
".png" => TextureType.Png,
|
||||
".tga" => TextureType.Targa,
|
||||
_ => TextureType.Unknown,
|
||||
};
|
||||
|
||||
|
|
@ -85,6 +94,9 @@ public partial class CombinedTexture : IDisposable
|
|||
break;
|
||||
case TextureType.Png:
|
||||
SaveAsPng(textures, path);
|
||||
break;
|
||||
case TextureType.Targa:
|
||||
SaveAsTarga(textures, path);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException(
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using OtterGui.Tasks;
|
|||
using OtterTex;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.Formats.Tga;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
||||
|
|
@ -33,10 +34,17 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
|
|||
}
|
||||
|
||||
public Task SavePng(string input, string output)
|
||||
=> Enqueue(new SavePngAction(this, input, output));
|
||||
=> Enqueue(new SaveImageSharpAction(this, input, output, TextureType.Png));
|
||||
|
||||
public Task SavePng(BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0)
|
||||
=> Enqueue(new SavePngAction(this, image, path, rgba, width, height));
|
||||
=> Enqueue(new SaveImageSharpAction(this, image, path, TextureType.Png, rgba, width, height));
|
||||
|
||||
public Task SaveTga(string input, string output)
|
||||
=> Enqueue(new SaveImageSharpAction(this, input, output, TextureType.Targa));
|
||||
|
||||
public Task SaveTga(BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0)
|
||||
=> Enqueue(new SaveImageSharpAction(this, image, path, TextureType.Targa, rgba, width, height));
|
||||
|
||||
|
||||
public Task SaveAs(CombinedTexture.TextureSaveType type, bool mipMaps, bool asTex, string input, string output)
|
||||
=> Enqueue(new SaveAsAction(this, type, mipMaps, asTex, input, output));
|
||||
|
|
@ -66,44 +74,65 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
|
|||
return t;
|
||||
}
|
||||
|
||||
private class SavePngAction : IAction
|
||||
private class SaveImageSharpAction : IAction
|
||||
{
|
||||
private readonly TextureManager _textures;
|
||||
private readonly string _outputPath;
|
||||
private readonly ImageInputData _input;
|
||||
private readonly TextureType _type;
|
||||
|
||||
public SavePngAction(TextureManager textures, string input, string output)
|
||||
public SaveImageSharpAction(TextureManager textures, string input, string output, TextureType type)
|
||||
{
|
||||
_textures = textures;
|
||||
_input = new ImageInputData(input);
|
||||
_outputPath = output;
|
||||
_type = type;
|
||||
if (_type.ReduceToBehaviour() is not TextureType.Png)
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, $"Can not save as {type} with ImageSharp.");
|
||||
}
|
||||
|
||||
public SavePngAction(TextureManager textures, BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0)
|
||||
public SaveImageSharpAction(TextureManager textures, BaseImage image, string path, TextureType type, byte[]? rgba = null, int width = 0,
|
||||
int height = 0)
|
||||
{
|
||||
_textures = textures;
|
||||
_input = new ImageInputData(image, rgba, width, height);
|
||||
_outputPath = path;
|
||||
_type = type;
|
||||
if (_type.ReduceToBehaviour() is not TextureType.Png)
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, $"Can not save as {type} with ImageSharp.");
|
||||
}
|
||||
|
||||
public void Execute(CancellationToken cancel)
|
||||
{
|
||||
_textures._logger.Information($"[{nameof(TextureManager)}] Saving {_input} as .png to {_outputPath}...");
|
||||
_textures._logger.Information($"[{nameof(TextureManager)}] Saving {_input} as {_type} to {_outputPath}...");
|
||||
var (image, rgba, width, height) = _input.GetData(_textures);
|
||||
cancel.ThrowIfCancellationRequested();
|
||||
Image<Rgba32>? png = null;
|
||||
Image<Rgba32>? data = null;
|
||||
if (image.Type is TextureType.Unknown)
|
||||
{
|
||||
if (rgba != null && width > 0 && height > 0)
|
||||
png = ConvertToPng(rgba, width, height).AsPng!;
|
||||
data = ConvertToPng(rgba, width, height).AsPng!;
|
||||
}
|
||||
else
|
||||
{
|
||||
png = ConvertToPng(image, cancel, rgba).AsPng!;
|
||||
data = ConvertToPng(image, cancel, rgba).AsPng!;
|
||||
}
|
||||
|
||||
cancel.ThrowIfCancellationRequested();
|
||||
png?.SaveAsync(_outputPath, new PngEncoder() { CompressionLevel = PngCompressionLevel.NoCompression }, cancel).Wait(cancel);
|
||||
switch (_type)
|
||||
{
|
||||
case TextureType.Png:
|
||||
data?.SaveAsync(_outputPath, new PngEncoder() { CompressionLevel = PngCompressionLevel.NoCompression }, cancel)
|
||||
.Wait(cancel);
|
||||
return;
|
||||
case TextureType.Targa:
|
||||
data?.SaveAsync(_outputPath, new TgaEncoder()
|
||||
{
|
||||
Compression = TgaCompression.None,
|
||||
BitsPerPixel = TgaBitsPerPixel.Pixel32,
|
||||
}, cancel).Wait(cancel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
|
@ -111,7 +140,7 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
|
|||
|
||||
public bool Equals(IAction? other)
|
||||
{
|
||||
if (other is not SavePngAction rhs)
|
||||
if (other is not SaveImageSharpAction rhs)
|
||||
return false;
|
||||
|
||||
return string.Equals(_outputPath, rhs._outputPath, StringComparison.OrdinalIgnoreCase) && _input.Equals(rhs._input);
|
||||
|
|
@ -168,9 +197,8 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
|
|||
var imageTypeBehaviour = image.Type.ReduceToBehaviour();
|
||||
var dds = _type switch
|
||||
{
|
||||
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Png => ConvertToRgbaDds(image, _mipMaps,
|
||||
cancel, rgba,
|
||||
width, height),
|
||||
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Png => ConvertToRgbaDds(image, _mipMaps, cancel,
|
||||
rgba, width, height),
|
||||
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Dds => AddMipMaps(image.AsDds!, _mipMaps),
|
||||
CombinedTexture.TextureSaveType.Bitmap => ConvertToRgbaDds(image, _mipMaps, cancel, rgba, width, height),
|
||||
CombinedTexture.TextureSaveType.BC3 => ConvertToCompressedDds(image, _mipMaps, false, cancel, rgba, width, height),
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public partial class ModEditWindow
|
|||
|
||||
ImGuiUtil.SelectableHelpMarker(newDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RedrawOnSaveBox()
|
||||
{
|
||||
|
|
@ -128,7 +128,8 @@ public partial class ModEditWindow
|
|||
? "This saves the texture in place. This is not revertible."
|
||||
: $"This saves the texture in place. This is not revertible. Hold {_config.DeleteModModifier} to save.";
|
||||
|
||||
var buttonSize2 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X) / 2, 0);
|
||||
var buttonSize2 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X) / 2, 0);
|
||||
var buttonSize3 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X * 2) / 3, 0);
|
||||
if (ImGuiUtil.DrawDisabledButton("Save in place", buttonSize2,
|
||||
tt, !isActive || !canSaveInPlace || _center.IsLeftCopy && _currentSaveAs == (int)CombinedTexture.TextureSaveType.AsIs))
|
||||
{
|
||||
|
|
@ -141,17 +142,18 @@ public partial class ModEditWindow
|
|||
if (ImGui.Button("Save as TEX", buttonSize2))
|
||||
OpenSaveAsDialog(".tex");
|
||||
|
||||
if (ImGui.Button("Export as PNG", buttonSize2))
|
||||
if (ImGui.Button("Export as TGA", buttonSize3))
|
||||
OpenSaveAsDialog(".tga");
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Export as PNG", buttonSize3))
|
||||
OpenSaveAsDialog(".png");
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Export as DDS", buttonSize2))
|
||||
if (ImGui.Button("Export as DDS", buttonSize3))
|
||||
OpenSaveAsDialog(".dds");
|
||||
|
||||
ImGui.NewLine();
|
||||
|
||||
var canConvertInPlace = canSaveInPlace && _left.Type is TextureType.Tex && _center.IsLeftCopy;
|
||||
|
||||
var buttonSize3 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X * 2) / 3, 0);
|
||||
if (ImGuiUtil.DrawDisabledButton("Convert to BC7", buttonSize3,
|
||||
"This converts the texture to BC7 format in place. This is not revertible.",
|
||||
!canConvertInPlace || _left.Format is DXGIFormat.BC7Typeless or DXGIFormat.BC7UNorm or DXGIFormat.BC7UNormSRGB))
|
||||
|
|
@ -226,7 +228,8 @@ public partial class ModEditWindow
|
|||
private void OpenSaveAsDialog(string defaultExtension)
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(_left.Path.Length > 0 ? _left.Path : _right.Path);
|
||||
_fileDialog.OpenSavePicker("Save Texture as TEX, DDS or PNG...", "Textures{.png,.dds,.tex},.tex,.dds,.png", fileName, defaultExtension,
|
||||
_fileDialog.OpenSavePicker("Save Texture as TEX, DDS, PNG or TGA...", "Textures{.png,.dds,.tex,.tga},.tex,.dds,.png,.tga", fileName,
|
||||
defaultExtension,
|
||||
(a, b) =>
|
||||
{
|
||||
if (a)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue