From a4e2ed0853b0fce84d3c16c8a1650dc6f307a6c6 Mon Sep 17 00:00:00 2001 From: cinder Date: Sun, 27 Apr 2025 17:34:22 -0500 Subject: [PATCH] Add basic tga encoder for SKBitmap --- LibreMetaverse/Imaging/Targa.cs | 66 ++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/LibreMetaverse/Imaging/Targa.cs b/LibreMetaverse/Imaging/Targa.cs index 6921467b..dec181cf 100644 --- a/LibreMetaverse/Imaging/Targa.cs +++ b/LibreMetaverse/Imaging/Targa.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Sjofn LLC. + * Copyright (c) 2024-2025, Sjofn LLC. * All rights reserved. * * - Redistribution and use in source and binary forms, with or without @@ -34,7 +34,7 @@ namespace OpenMetaverse.Imaging { public static class Targa { - /// Decode Truvision TGA file to + /// Decode Truevision TGA file to public static SKBitmap Decode(string fileName) { using (var image = Pfimage.FromFile(fileName)) @@ -43,7 +43,7 @@ namespace OpenMetaverse.Imaging } } - /// Decode Truvision TGA stream to + /// Decode Truevision TGA stream to public static SKBitmap Decode(Stream stream) { using (var image = Pfimage.FromStream(stream)) @@ -100,8 +100,64 @@ namespace OpenMetaverse.Imaging } } } - - /// Encode to Truvision TGA byte array + + public static byte[] Encode(SKBitmap image) + { + if (image == null) { return null; } + + var imageType = (byte)(image.ColorType == SKColorType.Gray8 || image.ColorType == SKColorType.Alpha8 + ? 0x03 : 0x02); + var imageDescriptor = (byte)(image.AlphaType <= SKAlphaType.Opaque ? 0 : 0x8); + + var tga = new byte[image.Width * image.Height * image.BytesPerPixel + 18]; + var di = 0; + tga[di++] = 0x00; // id length + tga[di++] = 0x00; // colormap type = 0: no colormap + tga[di++] = imageType; // image type + tga[di++] = 0x00; // color map spec is five zeroes for no color map + tga[di++] = 0x00; // color map spec is five zeroes for no color map + tga[di++] = 0x00; // color map spec is five zeroes for no color map + tga[di++] = 0x00; // color map spec is five zeroes for no color map + tga[di++] = 0x00; // 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.BytesPerPixel*8); // pixel depth, includes attribute bits + tga[di++] = imageDescriptor; // image descriptor byte + + for (var y = image.Height - 1; y >= 0; --y) // takes lines from bottom lines to top (mirrored horizontally) + { + for (var x = 0; x < image.Width; ++x) + { + var c = image.GetPixel(x, y); + if (image.ColorType == SKColorType.Gray8) + { + tga[di++] = c.Red; + } else if (image.ColorType == SKColorType.Alpha8) + { + tga[di++] = c.Alpha; + } + else + { + tga[di++] = c.Blue; + tga[di++] = c.Green; + tga[di++] = c.Red; + + tga[di++] = (byte)(image.AlphaType > SKAlphaType.Opaque ? 0x0 : c.Alpha); + } + + } + } + + return tga; + } + + /// Encode to Truevision 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];