diff --git a/LibreMetaverse/Imaging/ManagedImage.cs b/LibreMetaverse/Imaging/ManagedImage.cs
index 1361750f..39f3fc1e 100644
--- a/LibreMetaverse/Imaging/ManagedImage.cs
+++ b/LibreMetaverse/Imaging/ManagedImage.cs
@@ -118,7 +118,7 @@ namespace OpenMetaverse.Imaging
/// Constructs ManagedImage class from
/// Currently only supporting 8-bit channels;
///
- /// Input
+ /// Input
public ManagedImage(PortableImage image)
{
Width = image.Width;
@@ -436,6 +436,7 @@ namespace OpenMetaverse.Imaging
return SKBitmap.FromImage(img);
}
+ [Obsolete("ExportTGA() is deprecated, please use Targa.Encode() instead.")]
public byte[] ExportTGA()
{
byte[] tga = new byte[Width * Height * ((Channels & ImageChannels.Alpha) == 0 ? 3 : 4) + 32];
diff --git a/LibreMetaverse/Imaging/Targa.cs b/LibreMetaverse/Imaging/Targa.cs
index 013ddda8..f91dbc95 100644
--- a/LibreMetaverse/Imaging/Targa.cs
+++ b/LibreMetaverse/Imaging/Targa.cs
@@ -32,8 +32,9 @@ using SkiaSharp;
namespace OpenMetaverse.Imaging
{
- public class Targa
+ public static class Targa
{
+ /// Decode Truvision TGA file to
public static SKBitmap Decode(string fileName)
{
using (var image = Pfimage.FromFile(fileName))
@@ -42,6 +43,7 @@ namespace OpenMetaverse.Imaging
}
}
+ /// Decode Truvision TGA stream to
public static SKBitmap Decode(Stream stream)
{
using (var image = Pfimage.FromStream(stream))
@@ -98,5 +100,70 @@ namespace OpenMetaverse.Imaging
}
}
}
+
+ /// Encode to Truvision TGA byte array
+ public static byte[] Encode(ManagedImage image)
+ {
+ var tga = new byte[image.Width * image.Height * ((image.Channels & ManagedImage.ImageChannels.Alpha) == 0 ? 3 : 4) + 32];
+ var di = 0;
+ tga[di++] = 0; // idlength
+ tga[di++] = 0; // colormaptype = 0: no colormap
+ tga[di++] = 2; // image type = 2: uncompressed RGB
+ tga[di++] = 0; // color map spec is five zeroes for no color map
+ tga[di++] = 0; // color map spec is five zeroes for no color map
+ tga[di++] = 0; // color map spec is five zeroes for no color map
+ tga[di++] = 0; // color map spec is five zeroes for no color map
+ tga[di++] = 0; // color map spec is five zeroes for no color map
+ tga[di++] = 0; // x origin = two bytes
+ tga[di++] = 0; // x origin = two bytes
+ tga[di++] = 0; // y origin = two bytes
+ tga[di++] = 0; // y origin = two bytes
+ tga[di++] = (byte)(image.Width & 0xFF); // width - low byte
+ tga[di++] = (byte)(image.Width >> 8); // width - hi byte
+ tga[di++] = (byte)(image.Height & 0xFF); // height - low byte
+ tga[di++] = (byte)(image.Height >> 8); // height - hi byte
+ tga[di++] = (byte)((image.Channels & ManagedImage.ImageChannels.Alpha) == 0 ? 24 : 32); // 24/32 bits per pixel
+ tga[di++] = (byte)((image.Channels & ManagedImage.ImageChannels.Alpha) == 0 ? 32 : 40); // image descriptor byte
+
+ int n = image.Width * image.Height;
+
+ if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ {
+ if ((image.Channels & ManagedImage.ImageChannels.Color) != 0)
+ {
+ // RGBA
+ for (var i = 0; i < n; i++)
+ {
+ tga[di++] = image.Blue[i];
+ tga[di++] = image.Green[i];
+ tga[di++] = image.Red[i];
+ tga[di++] = image.Alpha[i];
+ }
+ }
+ else
+ {
+ // Alpha only
+ for (var i = 0; i < n; i++)
+ {
+ tga[di++] = image.Alpha[i];
+ tga[di++] = image.Alpha[i];
+ tga[di++] = image.Alpha[i];
+ tga[di++] = byte.MaxValue;
+ }
+ }
+ }
+ else
+ {
+ // RGB
+ for (var i = 0; i < n; i++)
+ {
+ tga[di++] = image.Blue[i];
+ tga[di++] = image.Green[i];
+ tga[di++] = image.Red[i];
+ }
+ }
+
+ return tga;
+ }
}
}
\ No newline at end of file
diff --git a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
index 95f38825..76c1b285 100644
--- a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
@@ -31,8 +31,10 @@ using System.IO;
using System.Collections.Generic;
using CSJ2K;
using OpenMetaverse.Assets;
+using OpenMetaverse.Imaging;
using Pfim;
using SkiaSharp;
+using Targa = OpenMetaverse.Imaging.Targa;
namespace OpenMetaverse.TestClient
{
@@ -119,13 +121,13 @@ namespace OpenMetaverse.TestClient
File.WriteAllBytes(assetTexture.AssetID + ".jp2", assetTexture.AssetData);
Console.WriteLine($"Wrote JPEG2000 image {assetTexture.AssetID}.jp2");
- // FIXME: Need to readd TARGA support!
- //var bitmap = J2kImage.FromBytes(assetTexture.AssetData).As();
- //var image = SKImage.FromPixels(bitmap.PeekPixels());
- //var bytes = image.Encode(SKEncodedImageFormat.Tga, 100);
- //File.WriteAllBytes(assetTexture.AssetID + ".tga", bytes.ToArray());
- //
- //Console.WriteLine($"Wrote TGA image {assetTexture.AssetID}.tga");
+ using (var bitmap = J2kImage.FromBytes(assetTexture.AssetData).As())
+ {
+ var mi = new ManagedImage(bitmap);
+ var bytes = Targa.Encode(mi);
+ File.WriteAllBytes(assetTexture.AssetID + ".tga", bytes);
+ Console.WriteLine($"Wrote TGA image {assetTexture.AssetID}.tga");
+ }
}
catch (Exception e)
{
diff --git a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
index 7e2cc59e..fe720fc3 100644
--- a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
+++ b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
@@ -190,7 +190,7 @@ namespace OpenMetaverse.TestClient
if (asset.Decode())
{
- try { File.WriteAllBytes(asset.AssetID + ".tga", asset.Image.ExportTGA()); }
+ try { File.WriteAllBytes(asset.AssetID + ".tga", Imaging.Targa.Encode(asset.Image)); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
}
else