diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs
index e96bc13..1321905 100644
--- a/AssetStudioGUI/AssetStudioGUIForm.cs
+++ b/AssetStudioGUI/AssetStudioGUIForm.cs
@@ -19,6 +19,7 @@ using System.Timers;
using System.Windows.Forms;
using static AssetStudioGUI.Studio;
using Font = AssetStudio.Font;
+using ImageFormat = AssetStudio.ImageFormat;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using Vector3 = OpenTK.Vector3;
using Vector4 = OpenTK.Vector4;
@@ -741,9 +742,10 @@ namespace AssetStudioGUI
private void PreviewTexture2D(AssetItem assetItem, Texture2D m_Texture2D)
{
- var bitmap = m_Texture2D.ConvertToBitmap(true);
- if (bitmap != null)
+ var stream = m_Texture2D.ConvertToStream(ImageFormat.Png, true);
+ if (stream != null)
{
+ var bitmap = new Bitmap(stream);
assetItem.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}";
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
{
@@ -1151,11 +1153,11 @@ namespace AssetStudioGUI
private void PreviewSprite(AssetItem assetItem, Sprite m_Sprite)
{
- var bitmap = m_Sprite.GetImage();
- if (bitmap != null)
+ var stream = m_Sprite.GetImage(ImageFormat.Png);
+ if (stream != null)
{
+ var bitmap = new Bitmap(stream);
assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n";
-
PreviewTexture(bitmap);
}
else
diff --git a/AssetStudioGUI/ExportOptions.Designer.cs b/AssetStudioGUI/ExportOptions.Designer.cs
index 02d8fe7..ee9ba01 100644
--- a/AssetStudioGUI/ExportOptions.Designer.cs
+++ b/AssetStudioGUI/ExportOptions.Designer.cs
@@ -72,9 +72,9 @@
//
// OKbutton
//
- this.OKbutton.Location = new System.Drawing.Point(309, 381);
+ this.OKbutton.Location = new System.Drawing.Point(318, 351);
this.OKbutton.Name = "OKbutton";
- this.OKbutton.Size = new System.Drawing.Size(75, 23);
+ this.OKbutton.Size = new System.Drawing.Size(75, 21);
this.OKbutton.TabIndex = 6;
this.OKbutton.Text = "OK";
this.OKbutton.UseVisualStyleBackColor = true;
@@ -83,9 +83,9 @@
// Cancel
//
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.Cancel.Location = new System.Drawing.Point(390, 381);
+ this.Cancel.Location = new System.Drawing.Point(399, 351);
this.Cancel.Name = "Cancel";
- this.Cancel.Size = new System.Drawing.Size(75, 23);
+ this.Cancel.Size = new System.Drawing.Size(75, 21);
this.Cancel.TabIndex = 7;
this.Cancel.Text = "Cancel";
this.Cancel.UseVisualStyleBackColor = true;
@@ -101,9 +101,9 @@
this.groupBox1.Controls.Add(this.convertAudio);
this.groupBox1.Controls.Add(this.panel1);
this.groupBox1.Controls.Add(this.converttexture);
- this.groupBox1.Location = new System.Drawing.Point(12, 13);
+ this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
- this.groupBox1.Size = new System.Drawing.Size(232, 362);
+ this.groupBox1.Size = new System.Drawing.Size(232, 334);
this.groupBox1.TabIndex = 9;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Export";
@@ -113,9 +113,9 @@
this.openAfterExport.AutoSize = true;
this.openAfterExport.Checked = true;
this.openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked;
- this.openAfterExport.Location = new System.Drawing.Point(6, 173);
+ this.openAfterExport.Location = new System.Drawing.Point(6, 160);
this.openAfterExport.Name = "openAfterExport";
- this.openAfterExport.Size = new System.Drawing.Size(137, 17);
+ this.openAfterExport.Size = new System.Drawing.Size(168, 16);
this.openAfterExport.TabIndex = 10;
this.openAfterExport.Text = "Open folder after export";
this.openAfterExport.UseVisualStyleBackColor = true;
@@ -125,9 +125,9 @@
this.restoreExtensionName.AutoSize = true;
this.restoreExtensionName.Checked = true;
this.restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked;
- this.restoreExtensionName.Location = new System.Drawing.Point(6, 63);
+ this.restoreExtensionName.Location = new System.Drawing.Point(6, 58);
this.restoreExtensionName.Name = "restoreExtensionName";
- this.restoreExtensionName.Size = new System.Drawing.Size(190, 17);
+ this.restoreExtensionName.Size = new System.Drawing.Size(216, 16);
this.restoreExtensionName.TabIndex = 9;
this.restoreExtensionName.Text = "Restore TextAsset extension name";
this.restoreExtensionName.UseVisualStyleBackColor = true;
@@ -141,17 +141,17 @@
"container path",
"source file name",
"do not group"});
- this.assetGroupOptions.Location = new System.Drawing.Point(6, 35);
+ this.assetGroupOptions.Location = new System.Drawing.Point(6, 32);
this.assetGroupOptions.Name = "assetGroupOptions";
- this.assetGroupOptions.Size = new System.Drawing.Size(149, 21);
+ this.assetGroupOptions.Size = new System.Drawing.Size(149, 20);
this.assetGroupOptions.TabIndex = 8;
//
// label6
//
this.label6.AutoSize = true;
- this.label6.Location = new System.Drawing.Point(6, 18);
+ this.label6.Location = new System.Drawing.Point(6, 17);
this.label6.Name = "label6";
- this.label6.Size = new System.Drawing.Size(127, 13);
+ this.label6.Size = new System.Drawing.Size(149, 12);
this.label6.TabIndex = 7;
this.label6.Text = "Group exported assets by";
//
@@ -160,9 +160,9 @@
this.convertAudio.AutoSize = true;
this.convertAudio.Checked = true;
this.convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
- this.convertAudio.Location = new System.Drawing.Point(6, 150);
+ this.convertAudio.Location = new System.Drawing.Point(6, 138);
this.convertAudio.Name = "convertAudio";
- this.convertAudio.Size = new System.Drawing.Size(179, 17);
+ this.convertAudio.Size = new System.Drawing.Size(198, 16);
this.convertAudio.TabIndex = 6;
this.convertAudio.Text = "Convert AudioClip to WAV(PCM)";
this.convertAudio.UseVisualStyleBackColor = true;
@@ -173,51 +173,51 @@
this.panel1.Controls.Add(this.tojpg);
this.panel1.Controls.Add(this.topng);
this.panel1.Controls.Add(this.tobmp);
- this.panel1.Location = new System.Drawing.Point(20, 111);
+ this.panel1.Location = new System.Drawing.Point(20, 102);
this.panel1.Name = "panel1";
- this.panel1.Size = new System.Drawing.Size(202, 33);
+ this.panel1.Size = new System.Drawing.Size(202, 30);
this.panel1.TabIndex = 5;
//
// totga
//
this.totga.AutoSize = true;
- this.totga.Location = new System.Drawing.Point(150, 7);
+ this.totga.Location = new System.Drawing.Point(150, 6);
this.totga.Name = "totga";
- this.totga.Size = new System.Drawing.Size(47, 17);
+ this.totga.Size = new System.Drawing.Size(41, 16);
this.totga.TabIndex = 2;
- this.totga.Text = "TGA";
+ this.totga.Text = "Tga";
this.totga.UseVisualStyleBackColor = true;
//
// tojpg
//
this.tojpg.AutoSize = true;
- this.tojpg.Location = new System.Drawing.Point(97, 7);
+ this.tojpg.Location = new System.Drawing.Point(97, 6);
this.tojpg.Name = "tojpg";
- this.tojpg.Size = new System.Drawing.Size(52, 17);
+ this.tojpg.Size = new System.Drawing.Size(47, 16);
this.tojpg.TabIndex = 4;
- this.tojpg.Text = "JPEG";
+ this.tojpg.Text = "Jpeg";
this.tojpg.UseVisualStyleBackColor = true;
//
// topng
//
this.topng.AutoSize = true;
this.topng.Checked = true;
- this.topng.Location = new System.Drawing.Point(50, 7);
+ this.topng.Location = new System.Drawing.Point(50, 6);
this.topng.Name = "topng";
- this.topng.Size = new System.Drawing.Size(48, 17);
+ this.topng.Size = new System.Drawing.Size(41, 16);
this.topng.TabIndex = 3;
this.topng.TabStop = true;
- this.topng.Text = "PNG";
+ this.topng.Text = "Png";
this.topng.UseVisualStyleBackColor = true;
//
// tobmp
//
this.tobmp.AutoSize = true;
- this.tobmp.Location = new System.Drawing.Point(3, 7);
+ this.tobmp.Location = new System.Drawing.Point(3, 6);
this.tobmp.Name = "tobmp";
- this.tobmp.Size = new System.Drawing.Size(48, 17);
+ this.tobmp.Size = new System.Drawing.Size(41, 16);
this.tobmp.TabIndex = 2;
- this.tobmp.Text = "BMP";
+ this.tobmp.Text = "Bmp";
this.tobmp.UseVisualStyleBackColor = true;
//
// converttexture
@@ -225,9 +225,9 @@
this.converttexture.AutoSize = true;
this.converttexture.Checked = true;
this.converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
- this.converttexture.Location = new System.Drawing.Point(6, 87);
+ this.converttexture.Location = new System.Drawing.Point(6, 80);
this.converttexture.Name = "converttexture";
- this.converttexture.Size = new System.Drawing.Size(116, 17);
+ this.converttexture.Size = new System.Drawing.Size(126, 16);
this.converttexture.TabIndex = 1;
this.converttexture.Text = "Convert Texture2D";
this.converttexture.UseVisualStyleBackColor = true;
@@ -252,9 +252,9 @@
this.groupBox2.Controls.Add(this.castToBone);
this.groupBox2.Controls.Add(this.exportAllNodes);
this.groupBox2.Controls.Add(this.eulerFilter);
- this.groupBox2.Location = new System.Drawing.Point(250, 13);
+ this.groupBox2.Location = new System.Drawing.Point(250, 12);
this.groupBox2.Name = "groupBox2";
- this.groupBox2.Size = new System.Drawing.Size(214, 362);
+ this.groupBox2.Size = new System.Drawing.Size(224, 334);
this.groupBox2.TabIndex = 11;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Fbx";
@@ -263,9 +263,9 @@
//
this.exportAllUvsAsDiffuseMaps.AccessibleDescription = "";
this.exportAllUvsAsDiffuseMaps.AutoSize = true;
- this.exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(6, 184);
+ this.exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(6, 171);
this.exportAllUvsAsDiffuseMaps.Name = "exportAllUvsAsDiffuseMaps";
- this.exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(168, 17);
+ this.exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(204, 16);
this.exportAllUvsAsDiffuseMaps.TabIndex = 23;
this.exportAllUvsAsDiffuseMaps.Text = "Export all UVs as diffuse maps";
this.exportUvsTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
@@ -277,9 +277,9 @@
this.exportBlendShape.AutoSize = true;
this.exportBlendShape.Checked = true;
this.exportBlendShape.CheckState = System.Windows.Forms.CheckState.Checked;
- this.exportBlendShape.Location = new System.Drawing.Point(6, 138);
+ this.exportBlendShape.Location = new System.Drawing.Point(6, 127);
this.exportBlendShape.Name = "exportBlendShape";
- this.exportBlendShape.Size = new System.Drawing.Size(114, 17);
+ this.exportBlendShape.Size = new System.Drawing.Size(126, 16);
this.exportBlendShape.TabIndex = 22;
this.exportBlendShape.Text = "Export blendshape";
this.exportBlendShape.UseVisualStyleBackColor = true;
@@ -289,9 +289,9 @@
this.exportAnimations.AutoSize = true;
this.exportAnimations.Checked = true;
this.exportAnimations.CheckState = System.Windows.Forms.CheckState.Checked;
- this.exportAnimations.Location = new System.Drawing.Point(6, 114);
+ this.exportAnimations.Location = new System.Drawing.Point(6, 105);
this.exportAnimations.Name = "exportAnimations";
- this.exportAnimations.Size = new System.Drawing.Size(109, 17);
+ this.exportAnimations.Size = new System.Drawing.Size(126, 16);
this.exportAnimations.TabIndex = 21;
this.exportAnimations.Text = "Export animations";
this.exportAnimations.UseVisualStyleBackColor = true;
@@ -304,9 +304,9 @@
0,
0,
131072});
- this.scaleFactor.Location = new System.Drawing.Point(83, 237);
+ this.scaleFactor.Location = new System.Drawing.Point(83, 224);
this.scaleFactor.Name = "scaleFactor";
- this.scaleFactor.Size = new System.Drawing.Size(60, 20);
+ this.scaleFactor.Size = new System.Drawing.Size(60, 21);
this.scaleFactor.TabIndex = 20;
this.scaleFactor.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.scaleFactor.Value = new decimal(new int[] {
@@ -318,9 +318,9 @@
// label5
//
this.label5.AutoSize = true;
- this.label5.Location = new System.Drawing.Point(6, 239);
+ this.label5.Location = new System.Drawing.Point(6, 226);
this.label5.Name = "label5";
- this.label5.Size = new System.Drawing.Size(64, 13);
+ this.label5.Size = new System.Drawing.Size(71, 12);
this.label5.TabIndex = 19;
this.label5.Text = "ScaleFactor";
//
@@ -331,17 +331,17 @@
this.fbxFormat.Items.AddRange(new object[] {
"Binary",
"Ascii"});
- this.fbxFormat.Location = new System.Drawing.Point(77, 270);
+ this.fbxFormat.Location = new System.Drawing.Point(77, 254);
this.fbxFormat.Name = "fbxFormat";
- this.fbxFormat.Size = new System.Drawing.Size(61, 21);
+ this.fbxFormat.Size = new System.Drawing.Size(61, 20);
this.fbxFormat.TabIndex = 18;
//
// label4
//
this.label4.AutoSize = true;
- this.label4.Location = new System.Drawing.Point(6, 274);
+ this.label4.Location = new System.Drawing.Point(6, 258);
this.label4.Name = "label4";
- this.label4.Size = new System.Drawing.Size(59, 13);
+ this.label4.Size = new System.Drawing.Size(59, 12);
this.label4.TabIndex = 17;
this.label4.Text = "FBXFormat";
//
@@ -356,25 +356,25 @@
"7.3",
"7.4",
"7.5"});
- this.fbxVersion.Location = new System.Drawing.Point(77, 302);
+ this.fbxVersion.Location = new System.Drawing.Point(77, 284);
this.fbxVersion.Name = "fbxVersion";
- this.fbxVersion.Size = new System.Drawing.Size(47, 21);
+ this.fbxVersion.Size = new System.Drawing.Size(47, 20);
this.fbxVersion.TabIndex = 16;
//
// label3
//
this.label3.AutoSize = true;
- this.label3.Location = new System.Drawing.Point(6, 305);
+ this.label3.Location = new System.Drawing.Point(6, 287);
this.label3.Name = "label3";
- this.label3.Size = new System.Drawing.Size(62, 13);
+ this.label3.Size = new System.Drawing.Size(65, 12);
this.label3.TabIndex = 15;
this.label3.Text = "FBXVersion";
//
// boneSize
//
- this.boneSize.Location = new System.Drawing.Point(65, 208);
+ this.boneSize.Location = new System.Drawing.Point(65, 197);
this.boneSize.Name = "boneSize";
- this.boneSize.Size = new System.Drawing.Size(46, 20);
+ this.boneSize.Size = new System.Drawing.Size(46, 21);
this.boneSize.TabIndex = 11;
this.boneSize.Value = new decimal(new int[] {
10,
@@ -385,9 +385,9 @@
// label2
//
this.label2.AutoSize = true;
- this.label2.Location = new System.Drawing.Point(6, 210);
+ this.label2.Location = new System.Drawing.Point(6, 199);
this.label2.Name = "label2";
- this.label2.Size = new System.Drawing.Size(52, 13);
+ this.label2.Size = new System.Drawing.Size(53, 12);
this.label2.TabIndex = 10;
this.label2.Text = "BoneSize";
//
@@ -396,9 +396,9 @@
this.exportSkins.AutoSize = true;
this.exportSkins.Checked = true;
this.exportSkins.CheckState = System.Windows.Forms.CheckState.Checked;
- this.exportSkins.Location = new System.Drawing.Point(6, 90);
+ this.exportSkins.Location = new System.Drawing.Point(6, 83);
this.exportSkins.Name = "exportSkins";
- this.exportSkins.Size = new System.Drawing.Size(83, 17);
+ this.exportSkins.Size = new System.Drawing.Size(96, 16);
this.exportSkins.TabIndex = 8;
this.exportSkins.Text = "Export skins";
this.exportSkins.UseVisualStyleBackColor = true;
@@ -406,9 +406,9 @@
// label1
//
this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(26, 42);
+ this.label1.Location = new System.Drawing.Point(26, 39);
this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(72, 13);
+ this.label1.Size = new System.Drawing.Size(95, 12);
this.label1.TabIndex = 7;
this.label1.Text = "FilterPrecision";
//
@@ -420,9 +420,9 @@
0,
0,
131072});
- this.filterPrecision.Location = new System.Drawing.Point(127, 40);
+ this.filterPrecision.Location = new System.Drawing.Point(127, 37);
this.filterPrecision.Name = "filterPrecision";
- this.filterPrecision.Size = new System.Drawing.Size(51, 20);
+ this.filterPrecision.Size = new System.Drawing.Size(51, 21);
this.filterPrecision.TabIndex = 6;
this.filterPrecision.Value = new decimal(new int[] {
25,
@@ -433,9 +433,9 @@
// castToBone
//
this.castToBone.AutoSize = true;
- this.castToBone.Location = new System.Drawing.Point(6, 161);
+ this.castToBone.Location = new System.Drawing.Point(6, 149);
this.castToBone.Name = "castToBone";
- this.castToBone.Size = new System.Drawing.Size(131, 17);
+ this.castToBone.Size = new System.Drawing.Size(156, 16);
this.castToBone.TabIndex = 5;
this.castToBone.Text = "All nodes cast to bone";
this.castToBone.UseVisualStyleBackColor = true;
@@ -445,9 +445,9 @@
this.exportAllNodes.AutoSize = true;
this.exportAllNodes.Checked = true;
this.exportAllNodes.CheckState = System.Windows.Forms.CheckState.Checked;
- this.exportAllNodes.Location = new System.Drawing.Point(6, 66);
+ this.exportAllNodes.Location = new System.Drawing.Point(6, 61);
this.exportAllNodes.Name = "exportAllNodes";
- this.exportAllNodes.Size = new System.Drawing.Size(101, 17);
+ this.exportAllNodes.Size = new System.Drawing.Size(120, 16);
this.exportAllNodes.TabIndex = 4;
this.exportAllNodes.Text = "Export all nodes";
this.exportAllNodes.UseVisualStyleBackColor = true;
@@ -457,9 +457,9 @@
this.eulerFilter.AutoSize = true;
this.eulerFilter.Checked = true;
this.eulerFilter.CheckState = System.Windows.Forms.CheckState.Checked;
- this.eulerFilter.Location = new System.Drawing.Point(6, 22);
+ this.eulerFilter.Location = new System.Drawing.Point(6, 20);
this.eulerFilter.Name = "eulerFilter";
- this.eulerFilter.Size = new System.Drawing.Size(72, 17);
+ this.eulerFilter.Size = new System.Drawing.Size(90, 16);
this.eulerFilter.TabIndex = 3;
this.eulerFilter.Text = "EulerFilter";
this.eulerFilter.UseVisualStyleBackColor = true;
@@ -467,10 +467,10 @@
// ExportOptions
//
this.AcceptButton = this.OKbutton;
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.Cancel;
- this.ClientSize = new System.Drawing.Size(477, 416);
+ this.ClientSize = new System.Drawing.Size(486, 384);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.Cancel);
diff --git a/AssetStudioGUI/ExportOptions.cs b/AssetStudioGUI/ExportOptions.cs
index 47b7ece..117ceda 100644
--- a/AssetStudioGUI/ExportOptions.cs
+++ b/AssetStudioGUI/ExportOptions.cs
@@ -1,11 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Text;
+using AssetStudio;
+using System;
using System.Windows.Forms;
namespace AssetStudioGUI
@@ -19,7 +13,7 @@ namespace AssetStudioGUI
restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName;
converttexture.Checked = Properties.Settings.Default.convertTexture;
convertAudio.Checked = Properties.Settings.Default.convertAudio;
- var str = Properties.Settings.Default.convertType;
+ var str = Properties.Settings.Default.convertType.ToString();
foreach (Control c in panel1.Controls)
{
if (c.Text == str)
@@ -54,7 +48,7 @@ namespace AssetStudioGUI
{
if (((RadioButton)c).Checked)
{
- Properties.Settings.Default.convertType = c.Text;
+ Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), c.Text);
break;
}
}
diff --git a/AssetStudioGUI/Exporter.cs b/AssetStudioGUI/Exporter.cs
index b501996..5e97e4f 100644
--- a/AssetStudioGUI/Exporter.cs
+++ b/AssetStudioGUI/Exporter.cs
@@ -1,11 +1,9 @@
-using System.Collections.Generic;
-using System.Drawing.Imaging;
+using AssetStudio;
+using Newtonsoft.Json;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
-using AssetStudio;
-using Newtonsoft.Json;
-using TGASharpLib;
namespace AssetStudioGUI
{
@@ -16,40 +14,17 @@ namespace AssetStudioGUI
var m_Texture2D = (Texture2D)item.Asset;
if (Properties.Settings.Default.convertTexture)
{
- var bitmap = m_Texture2D.ConvertToBitmap(true);
- if (bitmap == null)
+ var type = Properties.Settings.Default.convertType;
+ if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
- ImageFormat format = null;
- var ext = Properties.Settings.Default.convertType;
- bool tga = false;
- switch (ext)
- {
- case "BMP":
- format = ImageFormat.Bmp;
- break;
- case "PNG":
- format = ImageFormat.Png;
- break;
- case "JPEG":
- format = ImageFormat.Jpeg;
- break;
- case "TGA":
- tga = true;
- break;
- }
- if (!TryExportFile(exportPath, item, "." + ext.ToLower(), out var exportFullPath))
+ var stream = m_Texture2D.ConvertToStream(type, true);
+ if (stream == null)
return false;
- if (tga)
+ using (stream)
{
- var file = new TGA(bitmap);
- file.Save(exportFullPath);
+ File.WriteAllBytes(exportFullPath, stream.ToArray());
+ return true;
}
- else
- {
- bitmap.Save(exportFullPath, format);
- }
- bitmap.Dispose();
- return true;
}
else
{
@@ -252,40 +227,17 @@ namespace AssetStudioGUI
public static bool ExportSprite(AssetItem item, string exportPath)
{
- ImageFormat format = null;
var type = Properties.Settings.Default.convertType;
- bool tga = false;
- switch (type)
- {
- case "BMP":
- format = ImageFormat.Bmp;
- break;
- case "PNG":
- format = ImageFormat.Png;
- break;
- case "JPEG":
- format = ImageFormat.Jpeg;
- break;
- case "TGA":
- tga = true;
- break;
- }
- if (!TryExportFile(exportPath, item, "." + type.ToLower(), out var exportFullPath))
+ if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
return false;
- var bitmap = ((Sprite)item.Asset).GetImage();
- if (bitmap != null)
+ var stream = ((Sprite)item.Asset).GetImage(type);
+ if (stream != null)
{
- if (tga)
+ using (stream)
{
- var file = new TGA(bitmap);
- file.Save(exportFullPath);
+ File.WriteAllBytes(exportFullPath, stream.ToArray());
+ return true;
}
- else
- {
- bitmap.Save(exportFullPath, format);
- }
- bitmap.Dispose();
- return true;
}
return false;
}
diff --git a/AssetStudioGUI/Properties/Settings.Designer.cs b/AssetStudioGUI/Properties/Settings.Designer.cs
index 82393e1..2ecec40 100644
--- a/AssetStudioGUI/Properties/Settings.Designer.cs
+++ b/AssetStudioGUI/Properties/Settings.Designer.cs
@@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
//
//------------------------------------------------------------------------------
@@ -109,10 +109,10 @@ namespace AssetStudioGUI.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("PNG")]
- public string convertType {
+ [global::System.Configuration.DefaultSettingValueAttribute("Png")]
+ public global::AssetStudio.ImageFormat convertType {
get {
- return ((string)(this["convertType"]));
+ return ((global::AssetStudio.ImageFormat)(this["convertType"]));
}
set {
this["convertType"] = value;
diff --git a/AssetStudioGUI/Properties/Settings.settings b/AssetStudioGUI/Properties/Settings.settings
index db9a5ea..d6eb751 100644
--- a/AssetStudioGUI/Properties/Settings.settings
+++ b/AssetStudioGUI/Properties/Settings.settings
@@ -23,8 +23,8 @@
True
-
- PNG
+
+ Png
True
diff --git a/AssetStudioGUI/app.config b/AssetStudioGUI/app.config
index f9dbe6e..ef38ca4 100644
--- a/AssetStudioGUI/app.config
+++ b/AssetStudioGUI/app.config
@@ -1,7 +1,7 @@
-
+
-
+
@@ -32,7 +32,7 @@
True
- PNG
+ Png
True
@@ -75,4 +75,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj
index c5d11ce..da967d6 100644
--- a/AssetStudioUtility/AssetStudioUtility.csproj
+++ b/AssetStudioUtility/AssetStudioUtility.csproj
@@ -37,9 +37,48 @@
..\packages\Mono.Cecil.0.11.3\lib\net40\Mono.Cecil.dll
+
+ ..\packages\SixLabors.Fonts.1.0.0-beta15\lib\netstandard2.0\SixLabors.Fonts.dll
+
+
+ ..\packages\SixLabors.ImageSharp.1.0.3\lib\net472\SixLabors.ImageSharp.dll
+
+
+ ..\packages\SixLabors.ImageSharp.Drawing.1.0.0-beta13\lib\net472\SixLabors.ImageSharp.Drawing.dll
+
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
-
+
+ ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
+ True
+ True
+
+
+ ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
+ True
+ True
+
+
+ ..\packages\System.IO.UnmanagedMemoryStream.4.3.0\lib\net46\System.IO.UnmanagedMemoryStream.dll
+ True
+ True
+
+
+ ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
+
@@ -63,11 +102,12 @@
+
+
-
@@ -107,6 +147,7 @@
+
diff --git a/AssetStudioUtility/ImageExtensions.cs b/AssetStudioUtility/ImageExtensions.cs
new file mode 100644
index 0000000..7306c45
--- /dev/null
+++ b/AssetStudioUtility/ImageExtensions.cs
@@ -0,0 +1,39 @@
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Bmp;
+using SixLabors.ImageSharp.Formats.Tga;
+using System.IO;
+
+namespace AssetStudio
+{
+ public static class ImageExtensions
+ {
+ public static MemoryStream ConvertToStream(this Image image, ImageFormat imageFormat)
+ {
+ var outputStream = new MemoryStream();
+ switch (imageFormat)
+ {
+ case ImageFormat.Jpeg:
+ image.SaveAsJpeg(outputStream);
+ break;
+ case ImageFormat.Png:
+ image.SaveAsPng(outputStream);
+ break;
+ case ImageFormat.Bmp:
+ image.Save(outputStream, new BmpEncoder
+ {
+ BitsPerPixel = BmpBitsPerPixel.Pixel32,
+ SupportTransparency = true
+ });
+ break;
+ case ImageFormat.Tga:
+ image.Save(outputStream, new TgaEncoder
+ {
+ BitsPerPixel = TgaBitsPerPixel.Pixel32,
+ Compression = TgaCompression.None
+ });
+ break;
+ }
+ return outputStream;
+ }
+ }
+}
diff --git a/AssetStudioUtility/ImageFormat.cs b/AssetStudioUtility/ImageFormat.cs
new file mode 100644
index 0000000..e2f4b8b
--- /dev/null
+++ b/AssetStudioUtility/ImageFormat.cs
@@ -0,0 +1,10 @@
+namespace AssetStudio
+{
+ public enum ImageFormat
+ {
+ Jpeg,
+ Png,
+ Bmp,
+ Tga
+ }
+}
diff --git a/AssetStudioUtility/ModelConverter.cs b/AssetStudioUtility/ModelConverter.cs
index e757dcf..2f46d8c 100644
--- a/AssetStudioUtility/ModelConverter.cs
+++ b/AssetStudioUtility/ModelConverter.cs
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Drawing.Imaging;
-using System.IO;
using System.Linq;
using System.Text;
-using TGASharpLib;
namespace AssetStudio
{
@@ -17,7 +14,7 @@ namespace AssetStudio
public List AnimationList { get; protected set; } = new List();
public List MorphList { get; protected set; } = new List();
- private string imageFormat;
+ private ImageFormat imageFormat;
private Avatar avatar;
private HashSet animationClipHashSet = new HashSet();
private Dictionary bonePathHash = new Dictionary();
@@ -25,7 +22,7 @@ namespace AssetStudio
private Dictionary transformDictionary = new Dictionary();
Dictionary morphChannelNames = new Dictionary();
- public ModelConverter(GameObject m_GameObject, string imageFormat, AnimationClip[] animationList = null)
+ public ModelConverter(GameObject m_GameObject, ImageFormat imageFormat, AnimationClip[] animationList = null)
{
this.imageFormat = imageFormat;
if (m_GameObject.m_Animator != null)
@@ -50,7 +47,7 @@ namespace AssetStudio
ConvertAnimations();
}
- public ModelConverter(string rootName, List m_GameObjects, string imageFormat, AnimationClip[] animationList = null)
+ public ModelConverter(string rootName, List m_GameObjects, ImageFormat imageFormat, AnimationClip[] animationList = null)
{
this.imageFormat = imageFormat;
RootFrame = CreateFrame(rootName, Vector3.Zero, new Quaternion(0, 0, 0, 0), Vector3.One);
@@ -80,7 +77,7 @@ namespace AssetStudio
ConvertAnimations();
}
- public ModelConverter(Animator m_Animator, string imageFormat, AnimationClip[] animationList = null)
+ public ModelConverter(Animator m_Animator, ImageFormat imageFormat, AnimationClip[] animationList = null)
{
this.imageFormat = imageFormat;
InitWithAnimator(m_Animator);
@@ -319,7 +316,7 @@ namespace AssetStudio
}
ImportedMaterial iMat = ConvertMaterial(mat);
iSubmesh.Material = iMat.Name;
- iSubmesh.BaseVertex = (int) mesh.m_SubMeshes[i].firstVertex;
+ iSubmesh.BaseVertex = (int)mesh.m_SubMeshes[i].firstVertex;
//Face
iSubmesh.FaceList = new List(numFaces);
@@ -699,7 +696,7 @@ namespace AssetStudio
texture.Dest = dest;
- var ext = $".{imageFormat.ToLower()}";
+ var ext = $".{imageFormat.ToString().ToLower()}";
if (textureNameDictionary.TryGetValue(m_Texture2D, out var textureName))
{
texture.Name = textureName;
@@ -745,30 +742,13 @@ namespace AssetStudio
return;
}
- var bitmap = m_Texture2D.ConvertToBitmap(true);
- if (bitmap != null)
+ var stream = m_Texture2D.ConvertToStream(imageFormat, true);
+ if (stream != null)
{
- using (var stream = new MemoryStream())
+ using (stream)
{
- switch (imageFormat)
- {
- case "BMP":
- bitmap.Save(stream, ImageFormat.Bmp);
- break;
- case "PNG":
- bitmap.Save(stream, ImageFormat.Png);
- break;
- case "JPEG":
- bitmap.Save(stream, ImageFormat.Jpeg);
- break;
- case "TGA":
- var tga = new TGA(bitmap);
- tga.Save(stream);
- break;
- }
iTex = new ImportedTexture(stream, name);
TextureList.Add(iTex);
- bitmap.Dispose();
}
}
}
diff --git a/AssetStudioUtility/SpriteHelper.cs b/AssetStudioUtility/SpriteHelper.cs
index 3cd095c..891cada 100644
--- a/AssetStudioUtility/SpriteHelper.cs
+++ b/AssetStudioUtility/SpriteHelper.cs
@@ -1,15 +1,31 @@
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Drawing;
+using SixLabors.ImageSharp.Drawing.Processing;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Numerics;
namespace AssetStudio
{
public static class SpriteHelper
{
- public static Bitmap GetImage(this Sprite m_Sprite)
+ public static MemoryStream GetImage(this Sprite m_Sprite, ImageFormat imageFormat)
+ {
+ var image = GetImage(m_Sprite);
+ if (image != null)
+ {
+ using (image)
+ {
+ return image.ConvertToStream(imageFormat);
+ }
+ }
+ return null;
+ }
+
+ public static Image GetImage(this Sprite m_Sprite)
{
if (m_Sprite.m_SpriteAtlas != null && m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlas))
{
@@ -28,46 +44,32 @@ namespace AssetStudio
return null;
}
- private static Bitmap CutImage(Texture2D m_Texture2D, Sprite m_Sprite, Rectf textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
+ private static Image CutImage(Texture2D m_Texture2D, Sprite m_Sprite, Rectf textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
{
- var originalImage = m_Texture2D.ConvertToBitmap(false);
+ var originalImage = m_Texture2D.ConvertToImage(false);
if (originalImage != null)
{
using (originalImage)
{
- //var spriteImage = originalImage.Clone(textureRect, PixelFormat.Format32bppArgb);
var rectf = new RectangleF(textureRect.x, textureRect.y, textureRect.width, textureRect.height);
- var rect = Rectangle.Round(rectf);
- if (rect.Width == 0)
- {
- rect.Width = 1;
- }
- if (rect.Height == 0)
- {
- rect.Height = 1;
- }
- var spriteImage = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
- var destRect = new Rectangle(0, 0, rect.Width, rect.Height);
- using (var graphic = Graphics.FromImage(spriteImage))
- {
- graphic.DrawImage(originalImage, destRect, rect, GraphicsUnit.Pixel);
- }
+ var rect = Rectangle.Ceiling(rectf);
+ var spriteImage = originalImage.Clone(x => x.Crop(rect));
if (settingsRaw.packed == 1)
{
//RotateAndFlip
switch (settingsRaw.packingRotation)
{
case SpritePackingRotation.kSPRFlipHorizontal:
- spriteImage.RotateFlip(RotateFlipType.RotateNoneFlipX);
+ spriteImage.Mutate(x => x.Flip(FlipMode.Horizontal));
break;
case SpritePackingRotation.kSPRFlipVertical:
- spriteImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
+ spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
break;
case SpritePackingRotation.kSPRRotate180:
- spriteImage.RotateFlip(RotateFlipType.Rotate180FlipNone);
+ spriteImage.Mutate(x => x.Rotate(180));
break;
case SpritePackingRotation.kSPRRotate90:
- spriteImage.RotateFlip(RotateFlipType.Rotate270FlipNone);
+ spriteImage.Mutate(x => x.Rotate(270));
break;
}
}
@@ -78,41 +80,32 @@ namespace AssetStudio
try
{
var triangles = GetTriangles(m_Sprite.m_RD);
- var points = triangles.Select(x => x.Select(y => new PointF(y.X, y.Y)).ToArray());
- using (var path = new GraphicsPath())
+ var polygons = triangles.Select(x => new Polygon(new LinearLineSegment(x.Select(y => new PointF(y.X, y.Y)).ToArray()))).ToArray();
+ IPathCollection path = new PathCollection(polygons);
+ var matrix = Matrix3x2.CreateScale(m_Sprite.m_PixelsToUnits);
+ var version = m_Sprite.version;
+ if (version[0] < 5
+ || (version[0] == 5 && version[1] < 4)
+ || (version[0] == 5 && version[1] == 4 && version[2] <= 1)) //5.4.1p3 down
{
- foreach (var p in points)
- {
- path.AddPolygon(p);
- }
- using (var matr = new Matrix())
- {
- var version = m_Sprite.version;
- if (version[0] < 5
- || (version[0] == 5 && version[1] < 4)
- || (version[0] == 5 && version[1] == 4 && version[2] <= 1)) //5.4.1p3 down
- {
- matr.Translate(m_Sprite.m_Rect.width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.height * 0.5f - textureRectOffset.Y);
- }
- else
- {
- matr.Translate(m_Sprite.m_Rect.width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
- }
- matr.Scale(m_Sprite.m_PixelsToUnits, m_Sprite.m_PixelsToUnits);
- path.Transform(matr);
- var bitmap = new Bitmap(rect.Width, rect.Height);
- using (var graphic = Graphics.FromImage(bitmap))
- {
- using (var brush = new TextureBrush(spriteImage))
- {
- graphic.FillPath(brush, path);
- bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
- spriteImage.Dispose();
- return bitmap;
- }
- }
- }
+ matrix *= Matrix3x2.CreateTranslation(m_Sprite.m_Rect.width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.height * 0.5f - textureRectOffset.Y);
}
+ else
+ {
+ matrix *= Matrix3x2.CreateTranslation(m_Sprite.m_Rect.width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
+ }
+ path = path.Transform(matrix);
+ var options = new DrawingOptions
+ {
+ GraphicsOptions = new GraphicsOptions()
+ {
+ AlphaCompositionMode = PixelAlphaCompositionMode.DestOut
+ }
+ };
+ var rectP = new RectangularPolygon(0, 0, rect.Width, rect.Height);
+ spriteImage.Mutate(x => x.Fill(options, SixLabors.ImageSharp.Color.Red, rectP.Clip(path)));
+ spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
+ return spriteImage;
}
catch
{
@@ -121,7 +114,7 @@ namespace AssetStudio
}
//Rectangle
- spriteImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
+ spriteImage.Mutate(x => x.Flip(FlipMode.Vertical));
return spriteImage;
}
}
diff --git a/AssetStudioUtility/TGASharpLib.cs b/AssetStudioUtility/TGASharpLib.cs
deleted file mode 100644
index 7a38b65..0000000
--- a/AssetStudioUtility/TGASharpLib.cs
+++ /dev/null
@@ -1,5963 +0,0 @@
-/* MIT License
- Copyright (c) 2017 TGASharpLib
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace TGASharpLib
-{
- #region Enums
- ///
- /// The first 128 Color Map Type codes are reserved for use by Truevision,
- /// while the second set of 128 Color Map Type codes(128 to 255) may be used for
- /// developer applications.
- /// True-Color images do not normally make use of the color map field, but some current
- /// applications store palette information or developer-defined information in this field.
- /// It is best to check Field 3, Image Type, to make sure you have a file which can use the
- /// data stored in the Color Map Field.
- /// Otherwise ignore the information. When saving or creating files for True-Color
- /// images do not use this field and set it to Zero to ensure compatibility. Please refer
- /// to the Developer Area specification for methods of storing developer defined information.
- ///
- public enum TgaColorMapType : byte
- {
- NoColorMap = 0,
- ColorMap = 1,
- Truevision_2,
- Truevision_3,
- Truevision_4,
- Truevision_5,
- Truevision_6,
- Truevision_7,
- Truevision_8,
- Truevision_9,
- Truevision_10,
- Truevision_11,
- Truevision_12,
- Truevision_13,
- Truevision_14,
- Truevision_15,
- Truevision_16,
- Truevision_17,
- Truevision_18,
- Truevision_19,
- Truevision_20,
- Truevision_21,
- Truevision_22,
- Truevision_23,
- Truevision_24,
- Truevision_25,
- Truevision_26,
- Truevision_27,
- Truevision_28,
- Truevision_29,
- Truevision_30,
- Truevision_31,
- Truevision_32,
- Truevision_33,
- Truevision_34,
- Truevision_35,
- Truevision_36,
- Truevision_37,
- Truevision_38,
- Truevision_39,
- Truevision_40,
- Truevision_41,
- Truevision_42,
- Truevision_43,
- Truevision_44,
- Truevision_45,
- Truevision_46,
- Truevision_47,
- Truevision_48,
- Truevision_49,
- Truevision_50,
- Truevision_51,
- Truevision_52,
- Truevision_53,
- Truevision_54,
- Truevision_55,
- Truevision_56,
- Truevision_57,
- Truevision_58,
- Truevision_59,
- Truevision_60,
- Truevision_61,
- Truevision_62,
- Truevision_63,
- Truevision_64,
- Truevision_65,
- Truevision_66,
- Truevision_67,
- Truevision_68,
- Truevision_69,
- Truevision_70,
- Truevision_71,
- Truevision_72,
- Truevision_73,
- Truevision_74,
- Truevision_75,
- Truevision_76,
- Truevision_77,
- Truevision_78,
- Truevision_79,
- Truevision_80,
- Truevision_81,
- Truevision_82,
- Truevision_83,
- Truevision_84,
- Truevision_85,
- Truevision_86,
- Truevision_87,
- Truevision_88,
- Truevision_89,
- Truevision_90,
- Truevision_91,
- Truevision_92,
- Truevision_93,
- Truevision_94,
- Truevision_95,
- Truevision_96,
- Truevision_97,
- Truevision_98,
- Truevision_99,
- Truevision_100,
- Truevision_101,
- Truevision_102,
- Truevision_103,
- Truevision_104,
- Truevision_105,
- Truevision_106,
- Truevision_107,
- Truevision_108,
- Truevision_109,
- Truevision_110,
- Truevision_111,
- Truevision_112,
- Truevision_113,
- Truevision_114,
- Truevision_115,
- Truevision_116,
- Truevision_117,
- Truevision_118,
- Truevision_119,
- Truevision_120,
- Truevision_121,
- Truevision_122,
- Truevision_123,
- Truevision_124,
- Truevision_125,
- Truevision_126,
- Truevision_127,
- Other_128,
- Other_129,
- Other_130,
- Other_131,
- Other_132,
- Other_133,
- Other_134,
- Other_135,
- Other_136,
- Other_137,
- Other_138,
- Other_139,
- Other_140,
- Other_141,
- Other_142,
- Other_143,
- Other_144,
- Other_145,
- Other_146,
- Other_147,
- Other_148,
- Other_149,
- Other_150,
- Other_151,
- Other_152,
- Other_153,
- Other_154,
- Other_155,
- Other_156,
- Other_157,
- Other_158,
- Other_159,
- Other_160,
- Other_161,
- Other_162,
- Other_163,
- Other_164,
- Other_165,
- Other_166,
- Other_167,
- Other_168,
- Other_169,
- Other_170,
- Other_171,
- Other_172,
- Other_173,
- Other_174,
- Other_175,
- Other_176,
- Other_177,
- Other_178,
- Other_179,
- Other_180,
- Other_181,
- Other_182,
- Other_183,
- Other_184,
- Other_185,
- Other_186,
- Other_187,
- Other_188,
- Other_189,
- Other_190,
- Other_191,
- Other_192,
- Other_193,
- Other_194,
- Other_195,
- Other_196,
- Other_197,
- Other_198,
- Other_199,
- Other_200,
- Other_201,
- Other_202,
- Other_203,
- Other_204,
- Other_205,
- Other_206,
- Other_207,
- Other_208,
- Other_209,
- Other_210,
- Other_211,
- Other_212,
- Other_213,
- Other_214,
- Other_215,
- Other_216,
- Other_217,
- Other_218,
- Other_219,
- Other_220,
- Other_221,
- Other_222,
- Other_223,
- Other_224,
- Other_225,
- Other_226,
- Other_227,
- Other_228,
- Other_229,
- Other_230,
- Other_231,
- Other_232,
- Other_233,
- Other_234,
- Other_235,
- Other_236,
- Other_237,
- Other_238,
- Other_239,
- Other_240,
- Other_241,
- Other_242,
- Other_243,
- Other_244,
- Other_245,
- Other_246,
- Other_247,
- Other_248,
- Other_249,
- Other_250,
- Other_251,
- Other_252,
- Other_253,
- Other_254,
- Other_255
- }
-
- ///
- /// Establishes the number of bits per entry. Typically 15, 16, 24 or 32-bit values are used.
- /// When working with VDA or VDA/D cards it is preferred that you select 16 bits(5 bits
- /// per primary with 1 bit to select interrupt control) and set the 16th bit to 0 so that the
- /// interrupt bit is disabled. Even if this field is set to 15 bits(5 bits per primary) you
- /// must still parse the color map data 16 bits at a time and ignore the 16th bit.
- /// When working with a TARGA M8 card you would select 24 bits (8 bits per primary)
- /// since the color map is defined as 256 entries of 24 bit color values.
- /// When working with a TrueVista card(ATVista or NuVista) you would select 24-bit(8 bits per
- /// primary) or 32-bit(8 bits per primary including Alpha channel) depending on your
- /// application’s use of look-up tables. It is suggested that when working with 16-bit and
- /// 32-bit color images, you store them as True-Color images and do not use the color map
- /// field to store look-up tables. Please refer to the TGA Extensions for fields better suited
- /// to storing look-up table information.
- ///
- public enum TgaColorMapEntrySize : byte
- {
- Other = 0,
- X1R5G5B5 = 15,
- A1R5G5B5 = 16,
- R8G8B8 = 24,
- A8R8G8B8 = 32
- }
-
- ///
- /// Truevision has currently defined seven image types:
- /// 0 - No Image Data Included;
- /// 1 - Uncompressed, Color-mapped Image;
- /// 2 - Uncompressed, True-color Image;
- /// 3 - Uncompressed, Black-and-white Image;
- /// 9 - Run-length encoded, Color-mapped Image;
- /// 10 - Run-length encoded, True-color Image;
- /// 11 - Run-length encoded, Black-and-white Image.
- /// Image Data Type codes 0 to 127 are reserved for use by Truevision for general applications.
- /// Image Data Type codes 128 to 255 may be used for developer applications.
- ///
- public enum TgaImageType : byte
- {
- NoImageData = 0,
- Uncompressed_ColorMapped = 1,
- Uncompressed_TrueColor,
- Uncompressed_BlackWhite,
- _Truevision_4,
- _Truevision_5,
- _Truevision_6,
- _Truevision_7,
- _Truevision_8,
- RLE_ColorMapped = 9,
- RLE_TrueColor,
- RLE_BlackWhite,
- _Truevision_12,
- _Truevision_13,
- _Truevision_14,
- _Truevision_15,
- _Truevision_16,
- _Truevision_17,
- _Truevision_18,
- _Truevision_19,
- _Truevision_20,
- _Truevision_21,
- _Truevision_22,
- _Truevision_23,
- _Truevision_24,
- _Truevision_25,
- _Truevision_26,
- _Truevision_27,
- _Truevision_28,
- _Truevision_29,
- _Truevision_30,
- _Truevision_31,
- _Truevision_32,
- _Truevision_33,
- _Truevision_34,
- _Truevision_35,
- _Truevision_36,
- _Truevision_37,
- _Truevision_38,
- _Truevision_39,
- _Truevision_40,
- _Truevision_41,
- _Truevision_42,
- _Truevision_43,
- _Truevision_44,
- _Truevision_45,
- _Truevision_46,
- _Truevision_47,
- _Truevision_48,
- _Truevision_49,
- _Truevision_50,
- _Truevision_51,
- _Truevision_52,
- _Truevision_53,
- _Truevision_54,
- _Truevision_55,
- _Truevision_56,
- _Truevision_57,
- _Truevision_58,
- _Truevision_59,
- _Truevision_60,
- _Truevision_61,
- _Truevision_62,
- _Truevision_63,
- _Truevision_64,
- _Truevision_65,
- _Truevision_66,
- _Truevision_67,
- _Truevision_68,
- _Truevision_69,
- _Truevision_70,
- _Truevision_71,
- _Truevision_72,
- _Truevision_73,
- _Truevision_74,
- _Truevision_75,
- _Truevision_76,
- _Truevision_77,
- _Truevision_78,
- _Truevision_79,
- _Truevision_80,
- _Truevision_81,
- _Truevision_82,
- _Truevision_83,
- _Truevision_84,
- _Truevision_85,
- _Truevision_86,
- _Truevision_87,
- _Truevision_88,
- _Truevision_89,
- _Truevision_90,
- _Truevision_91,
- _Truevision_92,
- _Truevision_93,
- _Truevision_94,
- _Truevision_95,
- _Truevision_96,
- _Truevision_97,
- _Truevision_98,
- _Truevision_99,
- _Truevision_100,
- _Truevision_101,
- _Truevision_102,
- _Truevision_103,
- _Truevision_104,
- _Truevision_105,
- _Truevision_106,
- _Truevision_107,
- _Truevision_108,
- _Truevision_109,
- _Truevision_110,
- _Truevision_111,
- _Truevision_112,
- _Truevision_113,
- _Truevision_114,
- _Truevision_115,
- _Truevision_116,
- _Truevision_117,
- _Truevision_118,
- _Truevision_119,
- _Truevision_120,
- _Truevision_121,
- _Truevision_122,
- _Truevision_123,
- _Truevision_124,
- _Truevision_125,
- _Truevision_126,
- _Truevision_127,
- _Other_128,
- _Other_129,
- _Other_130,
- _Other_131,
- _Other_132,
- _Other_133,
- _Other_134,
- _Other_135,
- _Other_136,
- _Other_137,
- _Other_138,
- _Other_139,
- _Other_140,
- _Other_141,
- _Other_142,
- _Other_143,
- _Other_144,
- _Other_145,
- _Other_146,
- _Other_147,
- _Other_148,
- _Other_149,
- _Other_150,
- _Other_151,
- _Other_152,
- _Other_153,
- _Other_154,
- _Other_155,
- _Other_156,
- _Other_157,
- _Other_158,
- _Other_159,
- _Other_160,
- _Other_161,
- _Other_162,
- _Other_163,
- _Other_164,
- _Other_165,
- _Other_166,
- _Other_167,
- _Other_168,
- _Other_169,
- _Other_170,
- _Other_171,
- _Other_172,
- _Other_173,
- _Other_174,
- _Other_175,
- _Other_176,
- _Other_177,
- _Other_178,
- _Other_179,
- _Other_180,
- _Other_181,
- _Other_182,
- _Other_183,
- _Other_184,
- _Other_185,
- _Other_186,
- _Other_187,
- _Other_188,
- _Other_189,
- _Other_190,
- _Other_191,
- _Other_192,
- _Other_193,
- _Other_194,
- _Other_195,
- _Other_196,
- _Other_197,
- _Other_198,
- _Other_199,
- _Other_200,
- _Other_201,
- _Other_202,
- _Other_203,
- _Other_204,
- _Other_205,
- _Other_206,
- _Other_207,
- _Other_208,
- _Other_209,
- _Other_210,
- _Other_211,
- _Other_212,
- _Other_213,
- _Other_214,
- _Other_215,
- _Other_216,
- _Other_217,
- _Other_218,
- _Other_219,
- _Other_220,
- _Other_221,
- _Other_222,
- _Other_223,
- _Other_224,
- _Other_225,
- _Other_226,
- _Other_227,
- _Other_228,
- _Other_229,
- _Other_230,
- _Other_231,
- _Other_232,
- _Other_233,
- _Other_234,
- _Other_235,
- _Other_236,
- _Other_237,
- _Other_238,
- _Other_239,
- _Other_240,
- _Other_241,
- _Other_242,
- _Other_243,
- _Other_244,
- _Other_245,
- _Other_246,
- _Other_247,
- _Other_248,
- _Other_249,
- _Other_250,
- _Other_251,
- _Other_252,
- _Other_253,
- _Other_254,
- _Other_255
- }
-
- ///
- /// Number of bits per pixel. This number includes the Attribute or Alpha channel bits.
- /// Common values are 8, 16, 24 and 32 but other pixel depths could be used.
- ///
- public enum TgaPixelDepth : byte
- {
- Other = 0,
- Bpp8 = 8,
- Bpp16 = 16,
- Bpp24 = 24,
- Bpp32 = 32
- }
-
- ///
- /// Used to indicate the order in which pixel data is transferred from the file to the screen.
- /// (Bit 4 (bit 0 in enum) is for left-to-right ordering and bit 5 (bit 1 in enum) is for
- /// topto-bottom ordering as shown below.)
- ///
- public enum TgaImgOrigin : byte
- {
- BottomLeft = 0,
- BottomRight,
- TopLeft,
- TopRight
- }
-
- ///
- /// Contains a value which specifies the type of Alpha channel
- /// data contained in the file. Value Meaning:
- /// 0: no Alpha data included (bits 3-0 of field 5.6 should also be set to zero)
- /// 1: undefined data in the Alpha field, can be ignored
- /// 2: undefined data in the Alpha field, but should be retained
- /// 3: useful Alpha channel data is present
- /// 4: pre-multiplied Alpha(see description below)
- /// 5 -127: RESERVED
- /// 128-255: Un-assigned
- /// Pre-multiplied Alpha Example: Suppose the Alpha channel data is being used to specify the
- /// opacity of each pixel(for use when the image is overlayed on another image), where 0 indicates
- /// that the pixel is completely transparent and a value of 1 indicates that the pixel is
- /// completely opaque(assume all component values have been normalized).
- /// A quadruple(a, r, g, b) of( 0.5, 1, 0, 0) would indicate that the pixel is pure red with a
- /// transparency of one-half. For numerous reasons(including image compositing) is is better to
- /// pre-multiply the individual color components with the value in the Alpha channel.
- /// A pre-multiplication of the above would produce a quadruple(0.5, 0.5, 0, 0).
- /// A value of 3 in the Attributes Type Field(field 23) would indicate that the color components
- /// of the pixel have already been scaled by the value in the Alpha channel.
- ///
- public enum TgaAttrType : byte
- {
- NoAlpha = 0,
- UndefinedAlphaCanBeIgnored,
- UndefinedAlphaButShouldBeRetained,
- UsefulAlpha,
- PreMultipliedAlpha,
- _Reserved_5,
- _Reserved_6,
- _Reserved_7,
- _Reserved_8,
- _Reserved_9,
- _Reserved_10,
- _Reserved_11,
- _Reserved_12,
- _Reserved_13,
- _Reserved_14,
- _Reserved_15,
- _Reserved_16,
- _Reserved_17,
- _Reserved_18,
- _Reserved_19,
- _Reserved_20,
- _Reserved_21,
- _Reserved_22,
- _Reserved_23,
- _Reserved_24,
- _Reserved_25,
- _Reserved_26,
- _Reserved_27,
- _Reserved_28,
- _Reserved_29,
- _Reserved_30,
- _Reserved_31,
- _Reserved_32,
- _Reserved_33,
- _Reserved_34,
- _Reserved_35,
- _Reserved_36,
- _Reserved_37,
- _Reserved_38,
- _Reserved_39,
- _Reserved_40,
- _Reserved_41,
- _Reserved_42,
- _Reserved_43,
- _Reserved_44,
- _Reserved_45,
- _Reserved_46,
- _Reserved_47,
- _Reserved_48,
- _Reserved_49,
- _Reserved_50,
- _Reserved_51,
- _Reserved_52,
- _Reserved_53,
- _Reserved_54,
- _Reserved_55,
- _Reserved_56,
- _Reserved_57,
- _Reserved_58,
- _Reserved_59,
- _Reserved_60,
- _Reserved_61,
- _Reserved_62,
- _Reserved_63,
- _Reserved_64,
- _Reserved_65,
- _Reserved_66,
- _Reserved_67,
- _Reserved_68,
- _Reserved_69,
- _Reserved_70,
- _Reserved_71,
- _Reserved_72,
- _Reserved_73,
- _Reserved_74,
- _Reserved_75,
- _Reserved_76,
- _Reserved_77,
- _Reserved_78,
- _Reserved_79,
- _Reserved_80,
- _Reserved_81,
- _Reserved_82,
- _Reserved_83,
- _Reserved_84,
- _Reserved_85,
- _Reserved_86,
- _Reserved_87,
- _Reserved_88,
- _Reserved_89,
- _Reserved_90,
- _Reserved_91,
- _Reserved_92,
- _Reserved_93,
- _Reserved_94,
- _Reserved_95,
- _Reserved_96,
- _Reserved_97,
- _Reserved_98,
- _Reserved_99,
- _Reserved_100,
- _Reserved_101,
- _Reserved_102,
- _Reserved_103,
- _Reserved_104,
- _Reserved_105,
- _Reserved_106,
- _Reserved_107,
- _Reserved_108,
- _Reserved_109,
- _Reserved_110,
- _Reserved_111,
- _Reserved_112,
- _Reserved_113,
- _Reserved_114,
- _Reserved_115,
- _Reserved_116,
- _Reserved_117,
- _Reserved_118,
- _Reserved_119,
- _Reserved_120,
- _Reserved_121,
- _Reserved_122,
- _Reserved_123,
- _Reserved_124,
- _Reserved_125,
- _Reserved_126,
- _Reserved_127,
- _UnAssigned_128,
- _UnAssigned_129,
- _UnAssigned_130,
- _UnAssigned_131,
- _UnAssigned_132,
- _UnAssigned_133,
- _UnAssigned_134,
- _UnAssigned_135,
- _UnAssigned_136,
- _UnAssigned_137,
- _UnAssigned_138,
- _UnAssigned_139,
- _UnAssigned_140,
- _UnAssigned_141,
- _UnAssigned_142,
- _UnAssigned_143,
- _UnAssigned_144,
- _UnAssigned_145,
- _UnAssigned_146,
- _UnAssigned_147,
- _UnAssigned_148,
- _UnAssigned_149,
- _UnAssigned_150,
- _UnAssigned_151,
- _UnAssigned_152,
- _UnAssigned_153,
- _UnAssigned_154,
- _UnAssigned_155,
- _UnAssigned_156,
- _UnAssigned_157,
- _UnAssigned_158,
- _UnAssigned_159,
- _UnAssigned_160,
- _UnAssigned_161,
- _UnAssigned_162,
- _UnAssigned_163,
- _UnAssigned_164,
- _UnAssigned_165,
- _UnAssigned_166,
- _UnAssigned_167,
- _UnAssigned_168,
- _UnAssigned_169,
- _UnAssigned_170,
- _UnAssigned_171,
- _UnAssigned_172,
- _UnAssigned_173,
- _UnAssigned_174,
- _UnAssigned_175,
- _UnAssigned_176,
- _UnAssigned_177,
- _UnAssigned_178,
- _UnAssigned_179,
- _UnAssigned_180,
- _UnAssigned_181,
- _UnAssigned_182,
- _UnAssigned_183,
- _UnAssigned_184,
- _UnAssigned_185,
- _UnAssigned_186,
- _UnAssigned_187,
- _UnAssigned_188,
- _UnAssigned_189,
- _UnAssigned_190,
- _UnAssigned_191,
- _UnAssigned_192,
- _UnAssigned_193,
- _UnAssigned_194,
- _UnAssigned_195,
- _UnAssigned_196,
- _UnAssigned_197,
- _UnAssigned_198,
- _UnAssigned_199,
- _UnAssigned_200,
- _UnAssigned_201,
- _UnAssigned_202,
- _UnAssigned_203,
- _UnAssigned_204,
- _UnAssigned_205,
- _UnAssigned_206,
- _UnAssigned_207,
- _UnAssigned_208,
- _UnAssigned_209,
- _UnAssigned_210,
- _UnAssigned_211,
- _UnAssigned_212,
- _UnAssigned_213,
- _UnAssigned_214,
- _UnAssigned_215,
- _UnAssigned_216,
- _UnAssigned_217,
- _UnAssigned_218,
- _UnAssigned_219,
- _UnAssigned_220,
- _UnAssigned_221,
- _UnAssigned_222,
- _UnAssigned_223,
- _UnAssigned_224,
- _UnAssigned_225,
- _UnAssigned_226,
- _UnAssigned_227,
- _UnAssigned_228,
- _UnAssigned_229,
- _UnAssigned_230,
- _UnAssigned_231,
- _UnAssigned_232,
- _UnAssigned_233,
- _UnAssigned_234,
- _UnAssigned_235,
- _UnAssigned_236,
- _UnAssigned_237,
- _UnAssigned_238,
- _UnAssigned_239,
- _UnAssigned_240,
- _UnAssigned_241,
- _UnAssigned_242,
- _UnAssigned_243,
- _UnAssigned_244,
- _UnAssigned_245,
- _UnAssigned_246,
- _UnAssigned_247,
- _UnAssigned_248,
- _UnAssigned_249,
- _UnAssigned_250,
- _UnAssigned_251,
- _UnAssigned_252,
- _UnAssigned_253,
- _UnAssigned_254,
- _UnAssigned_255
- }
- #endregion
-
- #region Classes
- public class TgaColorKey : ICloneable
- {
- byte a = 0;
- byte r = 0;
- byte g = 0;
- byte b = 0;
-
- public TgaColorKey()
- {
- }
-
- ///
- /// Make from ARGB bytes.
- ///
- /// Alpha value.
- /// Red value.
- /// Green value.
- /// Blue value.
- public TgaColorKey(byte A, byte R, byte G, byte B)
- {
- a = A;
- r = R;
- g = G;
- b = B;
- }
-
- ///
- /// Make from ARGB bytes.
- ///
- /// Array of bytes(byte[4]).
- public TgaColorKey(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- Color color = Color.FromArgb(BitConverter.ToInt32(Bytes, 0));
- a = color.A;
- r = color.R;
- g = color.G;
- b = color.B;
- }
-
- ///
- /// Make from .
- ///
- /// 32bit ARGB integer color value.
- public TgaColorKey(int ARGB)
- {
- Color ColorARGB = Color.FromArgb(ARGB);
- a = ColorARGB.A;
- r = ColorARGB.R;
- g = ColorARGB.G;
- b = ColorARGB.B;
- }
-
- ///
- /// Make from .
- ///
- /// GDI+ value.
- public TgaColorKey(Color color)
- {
- a = color.A;
- r = color.R;
- g = color.G;
- b = color.B;
- }
-
- ///
- /// Gets or sets alpha color value.
- ///
- public byte A
- {
- get { return a; }
- set { a = value; }
- }
-
- ///
- /// Gets or sets red color value.
- ///
- public byte R
- {
- get { return r; }
- set { r = value; }
- }
-
- ///
- /// Gets or sets green color value.
- ///
- public byte G
- {
- get { return g; }
- set { g = value; }
- }
-
- ///
- /// Gets or sets blue color value.
- ///
- public byte B
- {
- get { return b; }
- set { b = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 4;
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaColorKey Clone()
- {
- return new TgaColorKey(a, r, g, b);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaColorKey) ? Equals((TgaColorKey)obj) : false);
- }
-
- public bool Equals(TgaColorKey item)
- {
- return (a == item.a && r == item.r && g == item.g && b == item.b);
- }
-
- public static bool operator ==(TgaColorKey item1, TgaColorKey item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaColorKey item1, TgaColorKey item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- return ToInt().GetHashCode();
- }
-
- ///
- /// Gets like string.
- ///
- /// String in ARGB format.
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, {4}={5}, {6}={7}",
- nameof(A), a, nameof(R), r, nameof(G), g, nameof(B), b);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with length = 4.
- public byte[] ToBytes()
- {
- return BitConverter.GetBytes(ToInt());
- }
-
- ///
- /// Gets like GDI+ .
- ///
- /// value of .
- public Color ToColor()
- {
- return Color.FromArgb(a, r, g, b);
- }
-
- ///
- /// Gets like ARGB .
- ///
- /// ARGB value of .
- public int ToInt()
- {
- return ToColor().ToArgb();
- }
- }
-
- ///
- /// This field (5 bytes) and its sub-fields describe the color map (if any) used for the image.
- /// If the Color Map Type field is set to zero, indicating that no color map exists, then
- /// these 5 bytes should be set to zero. These bytes always must be written to the file.
- ///
- public class TgaColorMapSpec : ICloneable
- {
- ushort firstEntryIndex = 0;
- ushort colorMapLength = 0;
- TgaColorMapEntrySize colorMapEntrySize = TgaColorMapEntrySize.Other;
-
- ///
- /// Make new .
- ///
- public TgaColorMapSpec()
- {
- }
-
- ///
- /// Make from bytes.
- ///
- /// Array of bytes(byte[5]).
- public TgaColorMapSpec(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- firstEntryIndex = BitConverter.ToUInt16(Bytes, 0);
- colorMapLength = BitConverter.ToUInt16(Bytes, 2);
- colorMapEntrySize = (TgaColorMapEntrySize)Bytes[4];
- }
-
- ///
- /// Field 4.1 (2 bytes):
- /// Index of the first color map entry. Index refers to the starting entry in loading
- /// the color map.
- /// Example: If you would have 1024 entries in the entire color map but you only
- /// need to store 72 of those entries, this field allows you to start in the middle of
- /// the color-map (e.g., position 342).
- ///
- public ushort FirstEntryIndex
- {
- get { return firstEntryIndex; }
- set { firstEntryIndex = value; }
- }
-
- ///
- /// Field 4.2 (2 bytes):
- /// Total number of color map entries included.
- ///
- public ushort ColorMapLength
- {
- get { return colorMapLength; }
- set { colorMapLength = value; }
- }
-
- ///
- /// Field 4.3 (1 byte):
- /// Establishes the number of bits per entry. Typically 15, 16, 24 or 32-bit values are used.
- /// When working with VDA or VDA/D cards it is preferred that you select 16 bits(5 bits
- /// per primary with 1 bit to select interrupt control) and set the 16th bit to 0 so that the
- /// interrupt bit is disabled. Even if this field is set to 15 bits(5 bits per primary) you
- /// must still parse the color map data 16 bits at a time and ignore the 16th bit.
- /// When working with a TARGA M8 card you would select 24 bits (8 bits per primary)
- /// since the color map is defined as 256 entries of 24 bit color values.
- /// When working with a TrueVista card(ATVista or NuVista) you would select 24-bit(8 bits per
- /// primary) or 32-bit(8 bits per primary including Alpha channel) depending on your
- /// application’s use of look-up tables. It is suggested that when working with 16-bit and
- /// 32-bit color images, you store them as True-Color images and do not use the color map
- /// field to store look-up tables. Please refer to the TGA Extensions for fields better suited
- /// to storing look-up table information.
- ///
- public TgaColorMapEntrySize ColorMapEntrySize
- {
- get { return colorMapEntrySize; }
- set { colorMapEntrySize = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 5;
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaColorMapSpec Clone()
- {
- return new TgaColorMapSpec(ToBytes());
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaColorMapSpec) ? Equals((TgaColorMapSpec)obj) : false);
- }
-
- public bool Equals(TgaColorMapSpec item)
- {
- return (firstEntryIndex == item.firstEntryIndex &&
- colorMapLength == item.colorMapLength &&
- colorMapEntrySize == item.colorMapEntrySize);
- }
-
- public static bool operator ==(TgaColorMapSpec item1, TgaColorMapSpec item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaColorMapSpec item1, TgaColorMapSpec item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- return (firstEntryIndex << 16 | colorMapLength).GetHashCode() ^ colorMapEntrySize.GetHashCode();
- }
- }
-
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, {4}={5}", nameof(FirstEntryIndex), FirstEntryIndex,
- nameof(ColorMapLength), ColorMapLength, nameof(ColorMapEntrySize), ColorMapEntrySize);
- }
-
- ///
- /// Convert ColorMapSpec to byte array.
- ///
- /// Byte array with length = 5.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(firstEntryIndex, colorMapLength, (byte)colorMapEntrySize);
- }
- }
-
- public class TgaComment : ICloneable
- {
- const int StrNLen = 80; //80 ASCII chars + 1 '\0' = 81 per SrtN!
- string origString = String.Empty;
- char blankSpaceChar = TgaString.DefaultBlankSpaceChar;
-
- public TgaComment()
- {
- }
-
- public TgaComment(string Str, char BlankSpaceChar = '\0')
- {
- if (Str == null)
- throw new ArgumentNullException(nameof(Str) + " = null!");
-
- origString = Str;
- blankSpaceChar = BlankSpaceChar;
- }
-
- public TgaComment(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- string s = Encoding.ASCII.GetString(Bytes, 0, StrNLen);
- s += Encoding.ASCII.GetString(Bytes, 81, StrNLen);
- s += Encoding.ASCII.GetString(Bytes, 162, StrNLen);
- s += Encoding.ASCII.GetString(Bytes, 243, StrNLen);
-
- switch (s[s.Length - 1])
- {
- case '\0':
- case ' ':
- blankSpaceChar = s[s.Length - 1];
- origString = s.TrimEnd(new char[] { s[s.Length - 1] });
- break;
- default:
- origString = s;
- break;
- }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 81 * 4;
-
- public string OriginalString
- {
- get { return origString; }
- set { origString = value; }
- }
-
- public char BlankSpaceChar
- {
- get { return blankSpaceChar; }
- set { blankSpaceChar = value; }
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaComment Clone()
- {
- return new TgaComment(origString, blankSpaceChar);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaComment) ? Equals((TgaComment)obj) : false);
- }
-
- public bool Equals(TgaComment item)
- {
- return (origString == item.origString && blankSpaceChar == item.blankSpaceChar);
- }
-
- public static bool operator ==(TgaComment item1, TgaComment item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaComment item1, TgaComment item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- return origString.GetHashCode() ^ blankSpaceChar.GetHashCode();
- }
-
- ///
- /// Get ASCII-Like string with string-terminators, example: "Line1 \0\0 Line2 \0\0\0".
- ///
- /// String with replaced string-terminators to "\0".
- public override string ToString()
- {
- return Encoding.ASCII.GetString(ToBytes()).Replace("\0", @"\0");
- }
-
- ///
- /// Get ASCII-Like string to first string-terminator, example:
- /// "Some string \0 Some Data \0" - > "Some string".
- ///
- /// String to first string-terminator.
- public string GetString()
- {
- String Str = Encoding.ASCII.GetString(ToBytes());
- for (int i = 1; i < 4; i++)
- Str = Str.Insert((StrNLen + 1) * i + i - 1, "\n");
- return Str.Replace("\0", String.Empty).TrimEnd(new char[] { '\n' });
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array, every byte is ASCII symbol.
- public byte[] ToBytes()
- {
- return ToBytes(origString, blankSpaceChar);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Input string.
- /// Char for filling blank space in string.
- /// Byte array, every byte is ASCII symbol.
- public static byte[] ToBytes(string Str, char BlankSpaceChar = '\0')
- {
- char[] C = new char[81 * 4];
-
- for (int i = 0; i < C.Length; i++)
- {
- if ((i + 82) % 81 == 0)
- C[i] = TgaString.DefaultEndingChar;
- else
- {
- int Index = i - i / 81;
- C[i] = (Index < Str.Length ? Str[Index] : BlankSpaceChar);
- }
- }
- return Encoding.ASCII.GetBytes(C);
- }
- }
-
- public class TgaDateTime : ICloneable
- {
- ushort month = 0;
- ushort day = 0;
- ushort year = 0;
- ushort hour = 0;
- ushort minute = 0;
- ushort second = 0;
-
- ///
- /// Make empty .
- ///
- public TgaDateTime()
- {
- }
-
- ///
- /// Make from .
- ///
- /// Some variable.
- public TgaDateTime(DateTime DateAndTime)
- {
- month = (ushort)DateAndTime.Month;
- day = (ushort)DateAndTime.Day;
- year = (ushort)DateAndTime.Year;
- hour = (ushort)DateAndTime.Hour;
- minute = (ushort)DateAndTime.Minute;
- second = (ushort)DateAndTime.Second;
- }
-
- ///
- /// Make from ushort values.
- ///
- /// Month (1 - 12).
- /// Day (1 - 31).
- /// Year (4 digit, ie. 1989).
- /// Hour (0 - 23).
- /// Minute (0 - 59).
- /// Second (0 - 59).
- public TgaDateTime(ushort Month, ushort Day, ushort Year, ushort Hour, ushort Minute, ushort Second)
- {
- month = Month;
- day = Day;
- year = Year;
- hour = Hour;
- minute = Minute;
- second = Second;
- }
-
- ///
- /// Make from bytes.
- ///
- /// Array of bytes(byte[12]).
- public TgaDateTime(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- else if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes) + " must be equal " + Size + "!");
-
- month = BitConverter.ToUInt16(Bytes, 0);
- day = BitConverter.ToUInt16(Bytes, 2);
- year = BitConverter.ToUInt16(Bytes, 4);
- hour = BitConverter.ToUInt16(Bytes, 6);
- minute = BitConverter.ToUInt16(Bytes, 8);
- second = BitConverter.ToUInt16(Bytes, 10);
- }
-
- ///
- /// Gets or Sets month (1 - 12).
- ///
- public ushort Month
- {
- get { return month; }
- set { month = value; }
- }
-
- ///
- /// Gets or Sets day (1 - 31).
- ///
- public ushort Day
- {
- get { return day; }
- set { day = value; }
- }
-
- ///
- /// Gets or Sets year (4 digit, ie. 1989).
- ///
- public ushort Year
- {
- get { return year; }
- set { year = value; }
- }
-
- ///
- /// Gets or Sets hour (0 - 23).
- ///
- public ushort Hour
- {
- get { return hour; }
- set { hour = value; }
- }
-
- ///
- /// Gets or Sets minute (0 - 59).
- ///
- public ushort Minute
- {
- get { return minute; }
- set { minute = value; }
- }
-
- ///
- /// Gets or Sets second (0 - 59).
- ///
- public ushort Second
- {
- get { return second; }
- set { second = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 12;
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaDateTime Clone()
- {
- return new TgaDateTime(month, day, year, hour, minute, second);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaDateTime) ? Equals((TgaDateTime)obj) : false);
- }
-
- public bool Equals(TgaDateTime item)
- {
- return (
- month == item.month &&
- day == item.day &&
- year == item.year &&
- hour == item.hour &&
- minute == item.minute &&
- second == item.second);
- }
-
- public static bool operator ==(TgaDateTime item1, TgaDateTime item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaDateTime item1, TgaDateTime item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + (month << 16 | hour).GetHashCode();
- hash = hash * 23 + (day << 16 | minute).GetHashCode();
- hash = hash * 23 + (year << 16 | second).GetHashCode();
- return hash;
- }
- }
-
- ///
- /// Gets like string.
- ///
- /// String in "1990.01.23 1:02:03" format.
- public override string ToString()
- {
- return String.Format("{0:D4}.{1:D2}.{2:D2} {3}:{4:D2}:{5:D2}", year, month, day, hour, minute, second);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with length = 12.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(month, day, year, hour, minute, second);
- }
-
- ///
- /// Gets like .
- ///
- /// value of .
- public DateTime ToDateTime()
- {
- return new DateTime(year, month, day, hour, minute, second);
- }
- }
-
- public class TgaDevEntry : ICloneable
- {
- // Directory
- ushort fieldTag = 0;
- uint fieldFileOffset = 0;
- // Field
- byte[] data = null;
-
- ///
- /// Make empty .
- ///
- public TgaDevEntry()
- {
- }
-
- ///
- /// Make from other .
- ///
- /// Some variable.
- public TgaDevEntry(TgaDevEntry Entry)
- {
- if (Entry == null)
- throw new ArgumentNullException();
-
- fieldTag = Entry.fieldTag;
- fieldFileOffset = Entry.fieldFileOffset;
- data = BitConverterExt.ToBytes(Entry.data);
- }
-
- ///
- /// Make from , and .
- ///
- /// TAG ID (0 - 65535). See .
- /// TAG file offset in bytes. See .
- /// This is DevEntry Field Data. See .
- public TgaDevEntry(ushort Tag, uint Offset, byte[] Data = null)
- {
- fieldTag = Tag;
- fieldFileOffset = Offset;
- data = Data;
- }
-
- ///
- /// Make from bytes.
- ///
- /// Array of bytes(byte[6] or bigger, if exist).
- public TgaDevEntry(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- else if (Bytes.Length < 6)
- throw new ArgumentOutOfRangeException(nameof(Bytes) + " must be >= 6!");
-
- fieldTag = BitConverter.ToUInt16(Bytes, 0);
- fieldFileOffset = BitConverter.ToUInt32(Bytes, 2);
-
- if (Bytes.Length > 6)
- data = BitConverterExt.GetElements(Bytes, 6, Bytes.Length - 6);
- }
-
- ///
- /// Each TAG is a value in the range of 0 to 65535. Values from 0 - 32767 are available for developer use,
- /// while values from 32768 - 65535 are reserved for Truevision.
- ///
- public ushort Tag
- {
- get { return fieldTag; }
- set { fieldTag = value; }
- }
-
- ///
- /// This OFFSET is a number of bytes from the beginning of the file to the start of the field
- /// referenced by the tag.
- ///
- public uint Offset
- {
- get { return fieldFileOffset; }
- set { fieldFileOffset = value; }
- }
-
- ///
- /// Field DATA.
- /// Although the size and format of the actual Developer Area fields are totally up to the developer,
- /// please define your formats to address future considerations you might have concerning your fields.
- /// This means that if you anticipate changing a field, build flexibility into the format to make these
- /// changes easy on other developers.Major changes to an existing TAG’s definition should never happen.
- ///
- public byte[] Data
- {
- get { return data; }
- set { data = value; }
- }
-
- ///
- /// The FIELD SIZE is a number of bytes in the field. Same like: ,
- /// if is null, return -1.
- ///
- public int FieldSize
- {
- get
- {
- if (Data == null)
- return -1;
-
- return Data.Length;
- }
- }
-
- ///
- /// Gets TGA size in bytes (Always constant and equal 10!).
- /// It is not ! It is just size of entry sizeof(ushort + uint + uint).
- ///
- public const int Size = 10;
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaDevEntry Clone()
- {
- return new TgaDevEntry(this);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaDevEntry) ? Equals((TgaDevEntry)obj) : false);
- }
-
- public bool Equals(TgaDevEntry item)
- {
- return (fieldTag == item.fieldTag &&
- fieldFileOffset == item.fieldFileOffset &&
- BitConverterExt.IsArraysEqual(data, item.data));
- }
-
- public static bool operator ==(TgaDevEntry item1, TgaDevEntry item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaDevEntry item1, TgaDevEntry item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + fieldTag.GetHashCode();
- hash = hash * 23 + fieldFileOffset.GetHashCode();
-
- if (data != null)
- for (int i = 0; i < data.Length; i++)
- hash = hash * 23 + data[i].GetHashCode();
-
- return hash;
- }
- }
-
- ///
- /// Gets like string.
- ///
- /// String in "Tag={0}, Offset={1}, FieldSize={2}" format.
- public override string ToString()
- {
- return String.Format("{0}={1}, {1}={2}, {3}={4}", nameof(Tag), fieldTag,
- nameof(Offset), fieldFileOffset, nameof(FieldSize), FieldSize);
- }
-
- ///
- /// Convert to byte array. (Not include !).
- ///
- /// Byte array with length = 10.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(fieldTag, fieldFileOffset, (data == null ? 0 : data.Length));
- }
- } //Not full ToBytes()
-
- public class TgaFraction : ICloneable
- {
- ushort numerator = 0;
- ushort denominator = 0;
-
- ///
- /// Make from and .
- ///
- /// Numerator value.
- /// Denominator value.
- public TgaFraction(ushort Numerator = 0, ushort Denominator = 0)
- {
- numerator = Numerator;
- denominator = Denominator;
- }
-
- ///
- /// Make from bytes.
- ///
- /// Array of bytes(byte[4]).
- public TgaFraction(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- numerator = BitConverter.ToUInt16(Bytes, 0);
- denominator = BitConverter.ToUInt16(Bytes, 2);
- }
-
- ///
- /// Gets or sets numerator value.
- ///
- public ushort Numerator
- {
- get { return numerator; }
- set { numerator = value; }
- }
-
- ///
- /// Gets or sets denominator value.
- ///
- public ushort Denominator
- {
- get { return denominator; }
- set { denominator = value; }
- }
-
- ///
- /// Get aspect ratio = / .
- ///
- public float AspectRatio
- {
- get
- {
- if (numerator == denominator)
- return 1f;
-
- return numerator / (float)denominator;
- }
- }
-
- ///
- /// Gets Empty , all values are 0.
- ///
- public static readonly TgaFraction Empty = new TgaFraction();
-
- ///
- /// Gets One , all values are 1 (ones, 1 / 1 = 1).
- ///
- public static readonly TgaFraction One = new TgaFraction(1, 1);
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 4;
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaFraction Clone()
- {
- return new TgaFraction(numerator, denominator);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaFraction) ? Equals((TgaFraction)obj) : false);
- }
-
- public bool Equals(TgaFraction item)
- {
- return (numerator == item.numerator && denominator == item.denominator);
- }
-
- public static bool operator ==(TgaFraction item1, TgaFraction item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaFraction item1, TgaFraction item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- return (numerator << 16 | denominator).GetHashCode();
- }
-
- ///
- /// Gets like string.
- ///
- /// String in "Numerator=1, Denominator=2" format.
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}", nameof(Numerator), numerator,
- nameof(Denominator), denominator);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with length = 4.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(numerator, denominator);
- }
- }
-
- ///
- /// Contains image origin bits and alpha channel bits(or number of overlay bits)
- ///
- public class TgaImageDescriptor : ICloneable
- {
- TgaImgOrigin imageOrigin = 0; //bits 5-4
- byte alphaChannelBits = 0; //bits 3-0
-
- ///
- /// Make empty .
- ///
- public TgaImageDescriptor()
- {
- }
-
- ///
- /// Make from bytes.
- ///
- /// ImageDescriptor byte with reserved 7-6 bits, bits 5-4 used for
- /// , 3-0 used as alpha channel bits or number of overlay bits.
- public TgaImageDescriptor(byte b)
- {
- imageOrigin = (TgaImgOrigin)((b & 0x30) >> 4);
- alphaChannelBits = (byte)(b & 0x0F);
- }
-
- ///
- /// Gets or Sets Image Origin bits (select from enum only, don'n use 5-4 bits!).
- ///
- public TgaImgOrigin ImageOrigin
- {
- get { return imageOrigin; }
- set { imageOrigin = value; }
- }
-
- ///
- /// Gets or Sets alpha channel bits or number of overlay bits.
- ///
- public byte AlphaChannelBits
- {
- get { return alphaChannelBits; }
- set { alphaChannelBits = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 1;
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- public TgaImageDescriptor Clone()
- {
- return new TgaImageDescriptor(ToByte());
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaImageDescriptor) ? Equals((TgaImageDescriptor)obj) : false);
- }
-
- public bool Equals(TgaImageDescriptor item)
- {
- return (imageOrigin == item.imageOrigin && alphaChannelBits == item.alphaChannelBits);
- }
-
- public static bool operator ==(TgaImageDescriptor item1, TgaImageDescriptor item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaImageDescriptor item1, TgaImageDescriptor item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- return ((int)ImageOrigin << 4 | alphaChannelBits).GetHashCode();
- }
- }
-
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, ImageDescriptor_AsByte={4}", nameof(ImageOrigin),
- imageOrigin, nameof(AlphaChannelBits), alphaChannelBits, ToByte());
- }
-
- ///
- /// Gets ImageDescriptor byte.
- ///
- /// ImageDescriptor byte with reserved 7-6 bits, bits 5-4 used for imageOrigin,
- /// 3-0 used as alpha channel bits or number of overlay bits.
- public byte ToByte()
- {
- return (byte)(((int)imageOrigin << 4) | alphaChannelBits);
- }
- }
-
- ///
- /// Image Specification - Field 5 (10 bytes):
- /// This field and its sub-fields describe the image screen location, size and pixel depth.
- /// These information is always written to the file.
- ///
- public class TgaImageSpec : ICloneable
- {
- ushort x_Origin = 0;
- ushort y_Origin = 0;
- ushort imageWidth = 0;
- ushort imageHeight = 0;
- TgaPixelDepth pixelDepth = TgaPixelDepth.Other;
- TgaImageDescriptor imageDescriptor = new TgaImageDescriptor();
-
- public TgaImageSpec()
- {
- }
-
- ///
- /// Make ImageSpec from values.
- ///
- /// These specify the absolute horizontal coordinate for the lower
- /// left corner of the image as it is positioned on a display device having an origin at
- /// the lower left of the screen(e.g., the TARGA series).
- /// These specify the absolute vertical coordinate for the lower
- /// left corner of the image as it is positioned on a display device having an origin at
- /// the lower left of the screen(e.g., the TARGA series).
- /// This field specifies the width of the image in pixels.
- /// This field specifies the height of the image in pixels.
- /// This field indicates the number of bits per pixel. This number
- /// includes the Attribute or Alpha channel bits. Common values are 8, 16, 24 and 32 but
- /// other pixel depths could be used.
- /// Contains image origin bits and alpha channel bits
- /// (or number of overlay bits).
- public TgaImageSpec(ushort X_Origin, ushort Y_Origin, ushort ImageWidth, ushort ImageHeight,
- TgaPixelDepth PixelDepth, TgaImageDescriptor ImageDescriptor)
- {
- x_Origin = X_Origin;
- y_Origin = Y_Origin;
- imageWidth = ImageWidth;
- imageHeight = ImageHeight;
- pixelDepth = PixelDepth;
- imageDescriptor = ImageDescriptor;
- }
-
- ///
- /// Make ImageSpec from bytes.
- ///
- /// Array of bytes(byte[10]).
- public TgaImageSpec(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- x_Origin = BitConverter.ToUInt16(Bytes, 0);
- y_Origin = BitConverter.ToUInt16(Bytes, 2);
- imageWidth = BitConverter.ToUInt16(Bytes, 4);
- imageHeight = BitConverter.ToUInt16(Bytes, 6);
- pixelDepth = (TgaPixelDepth)Bytes[8];
- imageDescriptor = new TgaImageDescriptor(Bytes[9]);
- }
-
- ///
- /// These specify the absolute horizontal coordinate for the lower left corner of the image
- /// as it is positioned on a display device having an origin at the lower left of the
- /// screen(e.g., the TARGA series).
- ///
- public ushort X_Origin
- {
- get { return x_Origin; }
- set { x_Origin = value; }
- }
-
- ///
- /// These specify the absolute vertical coordinate for the lower left corner of the image
- /// as it is positioned on a display device having an origin at the lower left of the
- /// screen(e.g., the TARGA series).
- ///
- public ushort Y_Origin
- {
- get { return y_Origin; }
- set { y_Origin = value; }
- }
-
- ///
- /// This field specifies the width of the image in pixels.
- ///
- public ushort ImageWidth
- {
- get { return imageWidth; }
- set { imageWidth = value; }
- }
-
- ///
- /// This field specifies the height of the image in pixels.
- ///
- public ushort ImageHeight
- {
- get { return imageHeight; }
- set { imageHeight = value; }
- }
-
- ///
- /// This field indicates the number of bits per pixel. This number includes the Attribute or
- /// Alpha channel bits. Common values are 8, 16, 24 and 32 but other pixel depths could be used.
- ///
- public TgaPixelDepth PixelDepth
- {
- get { return pixelDepth; }
- set { pixelDepth = value; }
- }
-
- ///
- /// Contains image origin bits and alpha channel bits(or number of overlay bits).
- ///
- public TgaImageDescriptor ImageDescriptor
- {
- get { return imageDescriptor; }
- set { imageDescriptor = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 10;
-
- ///
- /// Make full copy of .
- ///
- ///
- public TgaImageSpec Clone()
- {
- return new TgaImageSpec(ToBytes());
- }
-
- ///
- /// Make full copy of .
- ///
- ///
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaImageSpec) ? Equals((TgaImageSpec)obj) : false);
- }
-
- public bool Equals(TgaImageSpec item)
- {
- return (
- x_Origin == item.x_Origin &&
- y_Origin == item.y_Origin &&
- imageWidth == item.imageWidth &&
- imageHeight == item.imageHeight &&
- pixelDepth == item.pixelDepth &&
- imageDescriptor == item.imageDescriptor);
- }
-
- public static bool operator ==(TgaImageSpec item1, TgaImageSpec item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaImageSpec item1, TgaImageSpec item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + x_Origin.GetHashCode();
- hash = hash * 23 + y_Origin.GetHashCode();
- hash = hash * 23 + imageWidth.GetHashCode();
- hash = hash * 23 + imageHeight.GetHashCode();
- hash = hash * 23 + pixelDepth.GetHashCode();
-
- if (imageDescriptor != null)
- hash = hash * 23 + imageDescriptor.GetHashCode();
-
- return hash;
- }
- }
-
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, {4}={5}, {6}={7}, {8}={9}, {10}={11}",
- nameof(X_Origin), x_Origin,
- nameof(Y_Origin), y_Origin,
- nameof(ImageWidth), imageWidth,
- nameof(ImageHeight), imageHeight,
- nameof(PixelDepth), pixelDepth,
- nameof(ImageDescriptor), imageDescriptor);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with length = 10.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(x_Origin, y_Origin, imageWidth, imageHeight,
- (byte)pixelDepth, (imageDescriptor == null ? byte.MinValue : imageDescriptor.ToByte()));
- }
- }
-
- ///
- /// Postage Stamp Image (MaxSize 64x64, uncompressed, PixelDepth like in full image).
- ///
- public class TgaPostageStampImage : ICloneable
- {
- byte width = 0;
- byte height = 0;
- byte[] data = null;
-
- public TgaPostageStampImage()
- {
- }
-
- ///
- /// Make from bytes array.
- ///
- /// Bytes array, first 2 bytes are and ,
- /// next bytes - image data.
- public TgaPostageStampImage(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length < 2)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be >= " + 2 + "!");
-
- width = Bytes[0];
- height = Bytes[1];
-
- if (Bytes.Length > 2)
- data = BitConverterExt.GetElements(Bytes, 2, Bytes.Length - 2);
- }
-
- ///
- /// Make from bytes and size.
- ///
- /// Image Width.
- /// Image Height.
- /// Postage Stamp Image Data.
- public TgaPostageStampImage(byte Width, byte Height, byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
-
- width = Width;
- height = Height;
- data = Bytes;
- }
-
- ///
- /// Postage Stamp Image Data
- ///
- public byte[] Data
- {
- get { return data; }
- set { data = value; }
- }
-
- ///
- /// Postage Stamp Image Width (maximum = 64).
- ///
- public byte Width
- {
- get { return width; }
- set { width = value; }
- }
-
- ///
- /// Postage Stamp Image Height (maximum = 64).
- ///
- public byte Height
- {
- get { return height; }
- set { height = value; }
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- public TgaPostageStampImage Clone()
- {
- return new TgaPostageStampImage(width, height, BitConverterExt.ToBytes(data));
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaPostageStampImage) ? Equals((TgaPostageStampImage)obj) : false);
- }
-
- public bool Equals(TgaPostageStampImage item)
- {
- return width == item.width && height == item.height && BitConverterExt.IsArraysEqual(data, item.data);
- }
-
- public static bool operator ==(TgaPostageStampImage item1, TgaPostageStampImage item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaPostageStampImage item1, TgaPostageStampImage item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 27;
- hash = (13 * hash) + width.GetHashCode();
- hash = (13 * hash) + height.GetHashCode();
- if (data != null)
- for (int i = 0; i < data.Length; i++)
- hash = (13 * hash) + data[i].GetHashCode();
- return hash;
- }
- }
-
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, DataLength={4}",
- nameof(Width), width, nameof(Height), height, (data == null ? -1 : data.Length));
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(width, height, data);
- }
- }
-
- public class TgaSoftVersion : ICloneable
- {
- ushort versionNumber = 0;
- char versionLetter = ' ';
-
- ///
- /// Gets Empty , = ' ' (space).
- ///
- public TgaSoftVersion()
- {
- }
-
- ///
- /// Make from string.
- ///
- /// Input string, example: "123d".
- public TgaSoftVersion(string Str)
- {
- if (Str == null)
- throw new ArgumentNullException();
- if (Str.Length < 3 || Str.Length > 4)
- throw new ArgumentOutOfRangeException(nameof(Str.Length) + " must be equal 3 or 4!");
-
- bool Res = ushort.TryParse(Str.Substring(0, 3), out versionNumber);
- if (Res && Str.Length == 4)
- versionLetter = Str[3];
- }
-
- ///
- /// Make from bytes.
- ///
- /// Bytes array (byte[3]).
- public TgaSoftVersion(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- versionNumber = BitConverter.ToUInt16(Bytes, 0);
- versionLetter = Encoding.ASCII.GetString(Bytes, 2, 1)[0];
- }
-
- public TgaSoftVersion(ushort VersionNumber, char VersionLetter = ' ')
- {
- versionNumber = VersionNumber;
- versionLetter = VersionLetter;
- }
-
- public ushort VersionNumber
- {
- get { return versionNumber; }
- set { versionNumber = value; }
- }
-
- public char VersionLetter
- {
- get { return versionLetter; }
- set { versionLetter = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 3;
-
- ///
- /// Make full copy of .
- ///
- ///
- public TgaSoftVersion Clone()
- {
- return new TgaSoftVersion(versionNumber, versionLetter);
- }
-
- ///
- /// Make full copy of .
- ///
- ///
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaSoftVersion) ? Equals((TgaSoftVersion)obj) : false);
- }
-
- public bool Equals(TgaSoftVersion item)
- {
- return (versionNumber == item.versionNumber && versionLetter == item.versionLetter);
- }
-
- public static bool operator ==(TgaSoftVersion item1, TgaSoftVersion item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaSoftVersion item1, TgaSoftVersion item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- return versionNumber.GetHashCode() ^ versionLetter.GetHashCode();
- }
-
- public override string ToString()
- {
- return (versionNumber.ToString("000") + versionLetter).TrimEnd(new char[] { ' ', '\0' });
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array, (2 bytes) and
- /// (ASCII symbol).
- public byte[] ToBytes()
- {
- return ToBytes(versionNumber, versionLetter);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Set 123 for 1.23 version.
- /// Version letter, example: for 'a' - "1.23a".
- /// Byte array, (2 bytes) and (ASCII symbol).
- public static byte[] ToBytes(ushort VersionNumber, char VersionLetter = ' ')
- {
- return BitConverterExt.ToBytes(VersionNumber, Encoding.ASCII.GetBytes(VersionLetter.ToString()));
- }
- }
-
- ///
- /// Use it for working with ASCII strings in TGA files.
- ///
- public class TgaString : ICloneable
- {
- public const string XFileSignatuteConst = "TRUEVISION-XFILE";
- public const string DotSymbolConst = ".";
-
- string origString = String.Empty;
- int length = 0;
- char blankSpaceChar = DefaultBlankSpaceChar;
- bool useEnding = false;
-
- public TgaString(bool UseEnding = false)
- {
- useEnding = UseEnding;
- }
-
- public TgaString(byte[] Bytes, bool UseEnding = false)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
-
- length = Bytes.Length;
- useEnding = UseEnding;
- string s = Encoding.ASCII.GetString(Bytes, 0, Bytes.Length - (useEnding ? 1 : 0));
-
- if (s.Length > 0)
- switch (s[s.Length - 1])
- {
- case '\0':
- case ' ':
- blankSpaceChar = s[s.Length - 1];
- origString = s.TrimEnd(new char[] { s[s.Length - 1] });
- break;
- default:
- origString = s;
- break;
- }
- }
-
- public TgaString(int Length, bool UseEnding = false)
- {
- length = Length;
- useEnding = UseEnding;
- }
-
- public TgaString(string Str, int Length, bool UseEnding = false, char BlankSpaceChar = '\0')
- {
- if (Str == null)
- throw new ArgumentNullException(nameof(Str) + " = null!");
-
- origString = Str;
- length = Length;
- blankSpaceChar = BlankSpaceChar;
- useEnding = UseEnding;
- }
-
- public string OriginalString
- {
- get { return origString; }
- set { origString = value; }
- }
-
- public int Length
- {
- get { return length; }
- set { length = value; }
- }
-
- public char BlankSpaceChar
- {
- get { return blankSpaceChar; }
- set { blankSpaceChar = value; }
- }
-
- public bool UseEndingChar
- {
- get { return useEnding; }
- set { useEnding = value; }
- }
-
- ///
- /// Gets ending char, default '\0'.
- ///
- public static readonly char DefaultEndingChar = '\0';
-
- ///
- /// Gets blank space char, value = '\0'.
- ///
- public static readonly char DefaultBlankSpaceChar = '\0';
-
- ///
- /// Gets Empty .
- ///
- public static readonly TgaString Empty = new TgaString();
-
- ///
- /// Gets with = '\0' and = true.
- ///
- public static readonly TgaString ZeroTerminator = new TgaString(true);
-
- ///
- /// Gets "." with dot (period) symbol.
- ///
- public static readonly TgaString DotSymbol = new TgaString(DotSymbolConst, DotSymbolConst.Length);
-
- ///
- /// Gets "TRUEVISION-XFILE" (TGA File Format Version 2.0 signatute).
- ///
- public static readonly TgaString XFileSignatute = new TgaString(XFileSignatuteConst, XFileSignatuteConst.Length);
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaString Clone()
- {
- return new TgaString(origString, length, useEnding, blankSpaceChar);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaString) ? Equals((TgaString)obj) : false);
- }
-
- public bool Equals(TgaString item)
- {
- return (
- origString == item.origString &&
- length == item.length &&
- blankSpaceChar == item.blankSpaceChar &&
- useEnding == item.useEnding);
- }
-
- public static bool operator ==(TgaString item1, TgaString item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaString item1, TgaString item2)
- {
- return !(item1 == item2);
- }
-
- public static TgaString operator +(TgaString item1, TgaString item2)
- {
- if (ReferenceEquals(item1, null) || ReferenceEquals(item2, null))
- throw new ArgumentNullException();
-
- return new TgaString(BitConverterExt.ToBytes(item1.ToBytes(), item2.ToBytes()));
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + origString.GetHashCode();
- hash = hash * 23 + length.GetHashCode();
- hash = hash * 23 + blankSpaceChar.GetHashCode();
- hash = hash * 23 + useEnding.GetHashCode();
- return hash;
- }
- }
-
- ///
- /// Get ASCII-Like string with string-terminators, example: "Some string\0\0\0\0\0".
- ///
- /// String with replaced string-terminators to "\0".
- public override string ToString()
- {
- return Encoding.ASCII.GetString(ToBytes()).Replace("\0", @"\0");
- }
-
- ///
- /// Get ASCII-Like string to first string-terminator, example:
- /// "Some string \0 Some Data \0" - > "Some string".
- ///
- /// String to first string-terminator.
- public string GetString()
- {
- String Str = Encoding.ASCII.GetString(ToBytes());
- int EndIndex = Str.IndexOf('\0');
- if (EndIndex != -1)
- Str = Str.Substring(0, EndIndex);
- return Str;
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array, every byte is ASCII symbol.
- public byte[] ToBytes()
- {
- return ToBytes(origString, length, useEnding, blankSpaceChar);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Input string.
- /// Length of output ASCII string with Ending char (if used).
- /// Add to string or not?
- /// Char for filling blank space in string. If this char is '-' (only for example!),
- /// for string "ABC" with = 7, with = true,
- /// is '\0', result string is "ABC---\0".
- /// Byte array, every byte is ASCII symbol.
- public static byte[] ToBytes(string str, int Length, bool UseEnding = true, char BlankSpaceChar = '\0')
- {
- char[] C = new char[Math.Max(Length, (UseEnding ? 1 : 0))];
-
- for (int i = 0; i < C.Length; i++)
- C[i] = (i < str.Length ? str[i] : BlankSpaceChar);
-
- if (UseEnding)
- C[C.Length - 1] = DefaultEndingChar;
-
- return Encoding.ASCII.GetBytes(C);
- }
- }
-
- public class TgaTime : ICloneable
- {
- ushort hours = 0;
- ushort minutes = 0;
- ushort seconds = 0;
-
- ///
- /// Make empty .
- ///
- public TgaTime()
- {
- }
-
- ///
- /// Make from .
- ///
- /// Some variable.
- public TgaTime(TimeSpan Time)
- {
- hours = (ushort)Time.TotalHours;
- minutes = (ushort)Time.Minutes;
- seconds = (ushort)Time.Seconds;
- }
-
- ///
- /// Make from ushort values.
- ///
- /// Hour (0 - 65535).
- /// Minute (0 - 59).
- /// Second (0 - 59).
- public TgaTime(ushort Hours, ushort Minutes, ushort Seconds)
- {
- hours = Hours;
- minutes = Minutes;
- seconds = Seconds;
- }
-
- ///
- /// Make from bytes.
- ///
- /// Array of bytes(byte[6]).
- public TgaTime(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- else if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes) + " must be equal " + Size + "!");
-
- hours = BitConverter.ToUInt16(Bytes, 0);
- minutes = BitConverter.ToUInt16(Bytes, 2);
- seconds = BitConverter.ToUInt16(Bytes, 4);
- }
-
- ///
- /// Gets or Sets hour (0 - 65535).
- ///
- public ushort Hours
- {
- get { return hours; }
- set { hours = value; }
- }
-
- ///
- /// Gets or Sets minute (0 - 59).
- ///
- public ushort Minutes
- {
- get { return minutes; }
- set { minutes = value; }
- }
-
- ///
- /// Gets or Sets second (0 - 59).
- ///
- public ushort Seconds
- {
- get { return seconds; }
- set { seconds = value; }
- }
-
- ///
- /// Gets TGA Field size in bytes.
- ///
- public const int Size = 6;
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- public TgaTime Clone()
- {
- return new TgaTime(hours, minutes, seconds);
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Copy of
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaTime) ? Equals((TgaTime)obj) : false);
- }
-
- public bool Equals(TgaTime item)
- {
- return (hours == item.hours && minutes == item.minutes && seconds == item.seconds);
- }
-
- public static bool operator ==(TgaTime item1, TgaTime item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaTime item1, TgaTime item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + hours.GetHashCode();
- hash = hash * 23 + (minutes << 16 | seconds).GetHashCode();
- return hash;
- }
- }
-
- ///
- /// Gets like string.
- ///
- /// String in "H:M:S" format.
- public override string ToString()
- {
- return String.Format("{0}:{1}:{2}", hours, minutes, seconds);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with length = 6.
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(hours, minutes, seconds);
- }
-
- ///
- /// Gets like .
- ///
- /// value of .
- public TimeSpan ToTimeSpan()
- {
- return new TimeSpan(hours, minutes, seconds);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
-
- ///
- /// File Header Area (18 bytes)
- ///
- public class TgaHeader : ICloneable
- {
- byte idLength = 0;
- TgaColorMapType colorMapType = TgaColorMapType.NoColorMap;
- TgaImageType imageType = TgaImageType.NoImageData;
- TgaColorMapSpec colorMapSpec = new TgaColorMapSpec();
- TgaImageSpec imageSpec = new TgaImageSpec();
-
- ///
- /// Make empty .
- ///
- public TgaHeader()
- {
- }
-
- ///
- /// Make from bytes.
- ///
- /// Bytes array (byte[18]).
- public TgaHeader(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- idLength = Bytes[0];
- colorMapType = (TgaColorMapType)Bytes[1];
- imageType = (TgaImageType)Bytes[2];
- colorMapSpec = new TgaColorMapSpec(BitConverterExt.GetElements(Bytes, 3, TgaColorMapSpec.Size));
- imageSpec = new TgaImageSpec(BitConverterExt.GetElements(Bytes, 8, TgaImageSpec.Size));
- }
-
- ///
- /// ID Length - Field 1 (1 byte):
- /// This field identifies the number of bytes contained in the Field.
- /// The maximum number of characters is 255. A value of zero indicates that no Image ID
- /// field is included with the image.
- ///
- public byte IDLength
- {
- get { return idLength; }
- set { idLength = value; }
- }
-
- ///
- /// Color Map Type - Field 2 (1 byte):
- /// This field indicates the type of color map (if any) included with the image.
- /// There are currently 2 defined values for this field:
- /// 0 - indicates that no color-map data is included with this image;
- /// 1 - indicates that a color-map is included with this image.
- ///
- public TgaColorMapType ColorMapType
- {
- get { return colorMapType; }
- set { colorMapType = value; }
- }
-
- ///
- /// Image Type - Field 3 (1 byte):
- /// The TGA File Format can be used to store Pseudo-Color, True-Color and Direct-Color images
- /// of various pixel depths.
- ///
- public TgaImageType ImageType
- {
- get { return imageType; }
- set { imageType = value; }
- }
-
- ///
- /// Color Map Specification - Field 4 (5 bytes):
- /// This field and its sub-fields describe the color map (if any) used for the image.
- /// If the Color Map Type field is set to zero, indicating that no color map exists, then
- /// these 5 bytes should be set to zero. These bytes always must be written to the file.
- ///
- public TgaColorMapSpec ColorMapSpec
- {
- get { return colorMapSpec; }
- set { colorMapSpec = value; }
- }
-
- ///
- /// Image Specification - Field 5 (10 bytes):
- /// This field and its sub-fields describe the image screen location, size and pixel depth.
- /// These information is always written to the file.
- ///
- public TgaImageSpec ImageSpec
- {
- get { return imageSpec; }
- set { imageSpec = value; }
- }
-
- ///
- /// Gets TGA Header Section size in bytes.
- ///
- public const int Size = 18;
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- public TgaHeader Clone()
- {
- return new TgaHeader(ToBytes());
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaHeader) ? Equals((TgaHeader)obj) : false);
- }
-
- public bool Equals(TgaHeader item)
- {
- return (idLength == item.idLength &&
- colorMapType == item.colorMapType &&
- imageType == item.imageType &&
- colorMapSpec == item.colorMapSpec &&
- imageSpec == item.imageSpec);
- }
-
- public static bool operator ==(TgaHeader item1, TgaHeader item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaHeader item1, TgaHeader item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + (idLength << 24 | (byte)colorMapType << 8 | (byte)imageType).GetHashCode();
-
- if (colorMapSpec != null)
- hash = hash * 23 + colorMapSpec.GetHashCode();
-
- if (imageSpec != null)
- hash = hash * 23 + imageSpec.GetHashCode();
-
- return hash;
- }
- }
-
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, {4}={5}, {6}={7}, {8}={9}",
- nameof(IDLength), idLength,
- nameof(ColorMapType), colorMapType,
- nameof(ImageType), imageType,
- nameof(ColorMapSpec), colorMapSpec,
- nameof(ImageSpec), imageSpec);
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with size equal .
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(idLength, (byte)colorMapType, (byte)imageType,
- (colorMapSpec == null ? new byte[TgaColorMapSpec.Size] : colorMapSpec.ToBytes()),
- (imageSpec == null ? new byte[TgaImageSpec.Size] : imageSpec.ToBytes()));
- }
- }
-
- ///
- /// Image Or ColorMap Area
- ///
- public class TgaImgOrColMap : ICloneable
- {
- TgaString imageID = null;
- byte[] colorMapData = null;
- byte[] imageData = null;
-
- ///
- /// Make empty .
- ///
- public TgaImgOrColMap()
- {
- }
-
- ///
- /// Make from arrays.
- ///
- /// This optional field contains identifying information about the image.
- /// The maximum length for this field is 255 bytes. Refer to
- /// for the length of this field. If field 1 is set to Zero indicating that no Image ID exists
- /// then these bytes are not written to the file.
- /// Color Map Data, see description.
- /// Image Data, see description.
- public TgaImgOrColMap(TgaString ImageID, byte[] ColorMapData, byte[] ImageData)
- {
- imageID = ImageID;
- colorMapData = ColorMapData;
- imageData = ImageData;
- }
-
- ///
- /// Image ID - Field 6 (variable):
- /// This optional field contains identifying information about the image. The maximum length
- /// for this field is 255 bytes. Refer to for the length of this
- /// field. If field 1 is set to Zero indicating that no Image ID exists then these bytes are not
- /// written to the file. Can have text inside (ASCII).
- ///
- public TgaString ImageID
- {
- get { return imageID; }
- set { imageID = value; }
- }
-
- ///
- /// Color Map Data - Field 7 (variable):
- /// If the Color Map Type(field 2) field is set to zero indicating that no Color-Map
- /// exists then this field will not be present (i.e., no bytes written to the file).
- /// This variable-length field contains the actual color map information (LUT data).
- /// Field 4.3 specifies the width in bits of each color map entry while Field 4.2 specifies
- /// the number of color map entries in this field. These two fields together are used to
- /// determine the number of bytes contained in field 7.
- /// Each color map entry is stored using an integral number of bytes.The RGB specification
- /// for each color map entry is stored in successive bit-fields in the multi-byte entries.
- /// Each color bit-field is assumed to be MIN(Field4.3/3, 8) bits in length. If Field 4.3
- /// contains 24, then each color specification is 8 bits in length; if Field 4.3 contains 32,
- /// then each color specification is also 8 bits (32/3 gives 10, but 8 is smaller).
- /// Unused bit(s) in the multi-byte entries are assumed to specify attribute bits. The
- /// attribute bit field is often called the Alpha Channel, Overlay Bit(s) or Interrupt Bit(s).
- /// For the TARGA M-8, ATVista and NuVista, the number of bits in a color map specification is
- /// 24 (or 32). The red, green, and blue components are each represented by one byte.
- ///
- public byte[] ColorMapData
- {
- get { return colorMapData; }
- set { colorMapData = value; }
- }
-
- ///
- /// Image Data - Field 8 (variable):
- /// This field contains (Width)x(Height) pixels. Each pixel specifies image data in one
- /// of the following formats:
- /// a single color-map index for Pseudo-Color;
- /// Attribute, Red, Green and Blue ordered data for True-Color;
- /// and independent color-map indices for Direct-Color.
- /// The values for Width and Height are specified in Fields 5.3 and 5.4 respectively.
- /// The number of attribute and color-definition bits for each pixel are defined in Fields 5.6
- /// and 5.5, respectively.Each pixel is stored as an integral number of bytes.
- ///
- public byte[] ImageData
- {
- get { return imageData; }
- set { imageData = value; }
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independed copy of .
- public TgaImgOrColMap Clone()
- {
- return new TgaImgOrColMap(
- (imageID == null ? null : imageID.Clone()),
- (colorMapData == null ? null : (byte[])colorMapData.Clone()),
- (imageData == null ? null : (byte[])imageData.Clone()));
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independed copy of .
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaImgOrColMap) ? Equals((TgaImgOrColMap)obj) : false);
- }
-
- public bool Equals(TgaImgOrColMap item)
- {
- return imageID == item.imageID &&
- BitConverterExt.IsArraysEqual(colorMapData, item.colorMapData) &&
- BitConverterExt.IsArraysEqual(imageData, item.imageData);
- }
-
- public static bool operator ==(TgaImgOrColMap item1, TgaImgOrColMap item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaImgOrColMap item1, TgaImgOrColMap item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 27;
-
- if (imageID != null)
- hash = (13 * hash) + imageID.GetHashCode();
- if (colorMapData != null)
- for (int i = 0; i < colorMapData.Length; i++)
- hash = (13 * hash) + colorMapData[i].GetHashCode();
- if (imageData != null)
- for (int i = 0; i < imageData.Length; i++)
- hash = (13 * hash) + imageData[i].GetHashCode();
-
- return hash;
- }
- }
- } //No ToBytes()
-
- ///
- /// Developer Area
- /// //?
- public class TgaDevArea : ICloneable
- {
- List entries = new List();
-
- public TgaDevArea()
- {
- }
-
- public TgaDevArea(List Entries)
- {
- if (Entries == null)
- throw new ArgumentNullException(nameof(Entries) + " = null!");
-
- entries = Entries;
- }
-
- ///
- /// Developer Data - Field 9 (variable):
- ///
- public List Entries
- {
- get { return entries; }
- set { entries = value; }
- }
-
- public int Count
- {
- get { return entries.Count; }
- }
-
- public TgaDevEntry this[int index]
- {
- get { return entries[index]; }
- set { entries[index] = value; }
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- public TgaDevArea Clone()
- {
- if (entries == null)
- return new TgaDevArea(null);
-
- List L = new List();
- for (int i = 0; i < entries.Count; i++)
- L.Add(entries[i].Clone());
-
- return new TgaDevArea(L);
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaDevArea) ? Equals((TgaDevArea)obj) : false);
- }
-
- public bool Equals(TgaDevArea item)
- {
- return BitConverterExt.IsListsEqual(entries, item.entries);
- }
-
- public static bool operator ==(TgaDevArea item1, TgaDevArea item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaDevArea item1, TgaDevArea item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 27;
- if (entries != null)
- for (int i = 0; i < entries.Count; i++)
- hash = (13 * hash) + entries[i].GetHashCode();
- return hash;
- }
- }
-
- ///
- /// Convert (without Fields Data, only Directory!) to byte array.
- ///
- /// Byte array, Len = (NUMBER_OF_TAGS_IN_THE_DIRECTORY * 10) + 2 bytes in size.
- /// The "+ 2" includes the 2 bytes for the number of tags in the directory.
- public byte[] ToBytes()
- {
- if (entries == null)
- throw new Exception(nameof(Entries) + " = null!");
-
- ushort NumberOfEntries = (ushort)Math.Min(ushort.MaxValue, entries.Count);
- List DevDir = new List(BitConverter.GetBytes(NumberOfEntries));
-
- for (int i = 0; i < entries.Count; i++)
- {
- DevDir.AddRange(BitConverter.GetBytes(entries[i].Tag));
- DevDir.AddRange(BitConverter.GetBytes(entries[i].Offset));
- DevDir.AddRange(BitConverter.GetBytes(entries[i].FieldSize));
- }
-
- return DevDir.ToArray();
- }
- } //Not full ToBytes()
-
- ///
- /// Extension Area
- ///
- public class TgaExtArea : ICloneable
- {
- public const int MinSize = 495; //bytes
-
- ushort extensionSize = MinSize;
- TgaString authorName = new TgaString(41, true);
- TgaComment authorComments = new TgaComment();
- TgaDateTime dateTimeStamp = new TgaDateTime();
- TgaString jobNameOrID = new TgaString(41, true);
- TgaTime jobTime = new TgaTime();
- TgaString softwareID = new TgaString(41, true);
- TgaSoftVersion softVersion = new TgaSoftVersion();
- TgaColorKey keyColor = new TgaColorKey();
- TgaFraction pixelAspectRatio = TgaFraction.Empty;
- TgaFraction gammaValue = TgaFraction.Empty;
- uint colorCorrectionOffset = 0;
- uint postageStampOffset = 0;
- uint scanLineOffset = 0;
- TgaAttrType attributesType = TgaAttrType.NoAlpha;
- uint[] scanLineTable = null;
- TgaPostageStampImage postageStampImage = null;
- ushort[] colorCorrectionTable = null;
- byte[] otherDataInExtensionArea = null;
-
- public TgaExtArea()
- {
- }
-
- ///
- /// Make from bytes. Warning: ,
- /// , not included,
- /// because thea are can be not in the Extension Area of TGA file!
- ///
- /// Bytes of .
- /// Scan Line Table.
- /// Postage Stamp Image.
- /// Color Correction Table.
- public TgaExtArea(byte[] Bytes, uint[] SLT = null, TgaPostageStampImage PostImg = null, ushort[] CCT = null)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length < MinSize)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be >= " + MinSize + "!");
-
- extensionSize = BitConverter.ToUInt16(Bytes, 0);
- authorName = new TgaString(BitConverterExt.GetElements(Bytes, 2, 41), true);
- authorComments = new TgaComment(BitConverterExt.GetElements(Bytes, 43, TgaComment.Size));
- dateTimeStamp = new TgaDateTime(BitConverterExt.GetElements(Bytes, 367, TgaDateTime.Size));
- jobNameOrID = new TgaString(BitConverterExt.GetElements(Bytes, 379, 41), true);
- jobTime = new TgaTime(BitConverterExt.GetElements(Bytes, 420, TgaTime.Size));
- softwareID = new TgaString(BitConverterExt.GetElements(Bytes, 426, 41), true);
- softVersion = new TgaSoftVersion(BitConverterExt.GetElements(Bytes, 467, TgaSoftVersion.Size));
- keyColor = new TgaColorKey(BitConverterExt.GetElements(Bytes, 470, TgaColorKey.Size));
- pixelAspectRatio = new TgaFraction(BitConverterExt.GetElements(Bytes, 474, TgaFraction.Size));
- gammaValue = new TgaFraction(BitConverterExt.GetElements(Bytes, 478, TgaFraction.Size));
- colorCorrectionOffset = BitConverter.ToUInt32(Bytes, 482);
- postageStampOffset = BitConverter.ToUInt32(Bytes, 486);
- scanLineOffset = BitConverter.ToUInt32(Bytes, 490);
- attributesType = (TgaAttrType)Bytes[494];
-
- if (extensionSize > MinSize)
- otherDataInExtensionArea = BitConverterExt.GetElements(Bytes, 495, Bytes.Length - MinSize);
-
- scanLineTable = SLT;
- postageStampImage = PostImg;
- colorCorrectionTable = CCT;
- }
-
- #region Properties
- ///
- /// Extension Size - Field 10 (2 Bytes):
- /// This field is a SHORT field which specifies the number of BYTES in the fixedlength portion of
- /// the Extension Area. For Version 2.0 of the TGA File Format, this number should be set to 495.
- /// If the number found in this field is not 495, then the file will be assumed to be of a
- /// version other than 2.0. If it ever becomes necessary to alter this number, the change
- /// will be controlled by Truevision, and will be accompanied by a revision to the TGA File
- /// Format with an accompanying change in the version number.
- ///
- public ushort ExtensionSize
- {
- get { return extensionSize; }
- set { extensionSize = value; }
- }
-
- ///
- /// Author Name - Field 11 (41 Bytes):
- /// Bytes 2-42 - This field is an ASCII field of 41 bytes where the last byte must be a null
- /// (binary zero). This gives a total of 40 ASCII characters for the name. If the field is used,
- /// it should contain the name of the person who created the image (author). If the field is not
- /// used, you may fill it with nulls or a series of blanks(spaces) terminated by a null.
- /// The 41st byte must always be a null.
- ///
- public TgaString AuthorName
- {
- get { return authorName; }
- set { authorName = value; }
- }
-
- ///
- /// Author Comments - Field 12 (324 Bytes):
- /// Bytes 43-366 - This is an ASCII field consisting of 324 bytes which are organized as four lines
- /// of 80 characters, each followed by a null terminator.This field is provided, in addition to the
- /// original IMAGE ID field(in the original TGA format), because it was determined that a few
- /// developers had used the IMAGE ID field for their own purposes.This field gives the developer
- /// four lines of 80 characters each, to use as an Author Comment area. Each line is fixed to 81
- /// bytes which makes access to the four lines easy.Each line must be terminated by a null.
- /// If you do not use all 80 available characters in the line, place the null after the last
- /// character and blank or null fill the rest of the line. The 81st byte of each of the four
- /// lines must be null.
- ///
- public TgaComment AuthorComments
- {
- get { return authorComments; }
- set { authorComments = value; }
- }
-
- ///
- /// Date/Time Stamp - Field 13 (12 Bytes):
- /// Bytes 367-378 - This field contains a series of 6 SHORT values which define the integer
- /// value for the date and time that the image was saved. This data is formatted as follows:
- /// SHORT 0: Month(1 - 12)
- /// SHORT 1: Day(1 - 31)
- /// SHORT 2: Year(4 digit, ie. 1989)
- /// SHORT 3: Hour(0 - 23)
- /// SHORT 4: Minute(0 - 59)
- /// SHORT 5: Second(0 - 59)
- /// Even though operating systems typically time- and date-stamp files, this feature is
- /// provided because the operating system may change the time and date stamp if the file is
- /// copied. By using this area, you are guaranteed an unmodified region for date and time
- /// recording. If the fields are not used, you should fill them with binary zeros (0).
- ///
- public TgaDateTime DateTimeStamp
- {
- get { return dateTimeStamp; }
- set { dateTimeStamp = value; }
- }
-
- ///
- /// Job Name/ID - Field 14 (41 Bytes):
- /// Bytes 379-419 - This field is an ASCII field of 41 bytes where the last byte must be
- /// a binary zero. This gives a total of 40 ASCII characters for the job name or the ID.
- /// If the field is used, it should contain a name or id tag which refers to the job with
- /// which the image was associated.This allows production companies (and others) to tie
- /// images with jobs by using this field as a job name (i.e., CITY BANK) or job id number
- /// (i.e., CITY023). If the field is not used, you may fill it with a null terminated series
- /// of blanks (spaces) or nulls. In any case, the 41st byte must be a null.
- ///
- public TgaString JobNameOrID
- {
- get { return jobNameOrID; }
- set { jobNameOrID = value; }
- }
-
- ///
- /// Job Time - Field 15 (6 Bytes):
- /// Bytes 420-425 - This field contains a series of 3 SHORT values which define the integer
- /// value for the job elapsed time when the image was saved.This data is formatted as follows:
- /// SHORT 0: Hours(0 - 65535)
- /// SHORT 1: Minutes(0 - 59)
- /// SHORT 2: Seconds(0 - 59)
- /// The purpose of this field is to allow production houses (and others) to keep a running total
- /// of the amount of time invested in a particular image. This may be useful for billing, costing,
- /// and time estimating. If the fields are not used, you should fill them with binary zeros (0).
- ///
- public TgaTime JobTime
- {
- get { return jobTime; }
- set { jobTime = value; }
- }
-
- ///
- /// Software ID - Field 16 (41 Bytes):
- /// Bytes 426-466 - This field is an ASCII field of 41 bytes where the last byte must be
- /// a binary zero (null). This gives a total of 40 ASCII characters for the Software ID.
- /// The purpose of this field is to allow software to determine and record with what program
- /// a particular image was created.If the field is not used, you may fill it with a
- /// null terminated series of blanks (spaces) or nulls. The 41st byte must always be a null.
- ///
- public TgaString SoftwareID
- {
- get { return softwareID; }
- set { softwareID = value; }
- }
-
- ///
- /// Software Version - Field 17 (3 Bytes):
- /// Bytes 467-469 - This field consists of two sub-fields, a SHORT and an ASCII BYTE.
- /// The purpose of this field is to define the version of software defined by the
- /// “Software ID” field above. The SHORT contains the version number as a binary
- /// integer times 100.
- /// Therefore, software version 4.17 would be the integer value 417.This allows for
- /// two decimal positions of sub-version.The ASCII BYTE supports developers who also
- /// tag a release letter to the end. For example, if the version number is 1.17b, then
- /// the SHORT would contain 117. and the ASCII BYTE would contain “b”.
- /// The organization is as follows:
- /// SHORT (Bytes 0 - 1): Version Number * 100
- /// BYTE(Byte 2): Version Letter
- /// If you do not use this field, set the SHORT to binary zero, and the BYTE to a space(“ “)
- ///
- public TgaSoftVersion SoftVersion
- {
- get { return softVersion; }
- set { softVersion = value; }
- }
-
- ///
- /// Key Color - Field 18 (4 Bytes):
- /// Bytes 470-473 - This field contains a long value which is the key color in effect at
- /// the time the image is saved. The format is in A:R:G:B where ‘A’ (most significant byte)
- /// is the alpha channel key color(if you don’t have an alpha channel in your application,
- /// keep this byte zero [0]).
- /// The Key Color can be thought of as the ‘background color’ or ‘transparent color’.
- /// This is the color of the ‘non image’ area of the screen, and the same color that the
- /// screen would be cleared to if erased in the application. If you don’t use this field,
- /// set it to all zeros (0). Setting the field to all zeros is the same as selecting a key
- /// color of black.
- /// A good example of a key color is the ‘transparent color’ used in TIPS™ for WINDOW loading/saving.
- ///
- public TgaColorKey KeyColor
- {
- get { return keyColor; }
- set { keyColor = value; }
- }
-
- ///
- /// Pixel Aspect Ratio - Field 19 (4 Bytes):
- /// Bytes 474-477 - This field contains two SHORT sub-fields, which when taken together
- /// specify a pixel size ratio.The format is as follows:
- /// SHORT 0: Pixel Ratio Numerator(pixel width)
- /// SHORT 1: Pixel Ratio Denominator(pixel height)
- /// These sub-fields may be used to determine the aspect ratio of a pixel. This is useful when
- /// it is important to preserve the proper aspect ratio of the saved image. If the two values
- /// are set to the same non-zero value, then the image is composed of square pixels. A zero
- /// in the second sub-field (denominator) indicates that no pixel aspect ratio is specified.
- ///
- public TgaFraction PixelAspectRatio
- {
- get { return pixelAspectRatio; }
- set { pixelAspectRatio = value; }
- }
-
- ///
- /// Gamma Value - Field 20 (4 Bytes):
- /// Bytes 478-481 - This field contains two SHORT sub-fields, which when taken together in a ratio,
- /// provide a fractional gamma value.The format is as follows:
- /// SHORT 0: Gamma Numerator
- /// SHORT 1: Gamma Denominator
- /// The resulting value should be in the range of 0.0 to 10.0, with only one decimal place of
- /// precision necessary. An uncorrected image (an image with no gamma) should have the value 1.0 as
- /// the result.This may be accomplished by placing thesame, non-zero values in both positions
- /// (i.e., 1/1). If you decide to totally ignore this field, please set the denominator (the second
- /// SHORT) to the value zero. This will indicate that the Gamma Value field is not being used.
- ///
- public TgaFraction GammaValue
- {
- get { return gammaValue; }
- set { gammaValue = value; }
- }
-
- ///
- /// Color Correction Offset - Field 21 (4 Bytes):
- /// Bytes 482-485 - This field is a 4-byte field containing a single offset value. This is an offset
- /// from the beginning of the file to the start of the Color Correction table. This table may be
- /// written anywhere between the end of the Image Data field (field 8) and the start of the TGA
- /// File Footer. If the image has no Color Correction Table or if the Gamma Value setting is
- /// sufficient, set this value to zero and do not write a Correction Table anywhere.
- ///
- public uint ColorCorrectionTableOffset
- {
- get { return colorCorrectionOffset; }
- set { colorCorrectionOffset = value; }
- }
-
- ///
- /// Postage Stamp Offset - Field 22 (4 Bytes):
- /// Bytes 486-489 - This field is a 4-byte field containing a single offset value. This is an offset
- /// from the beginning of the file to the start of the Postage Stamp Image. The Postage Stamp Image
- /// must be written after Field 25 (Scan Line Table) but before the start of the TGA File Footer.
- /// If no postage stamp is stored, set this field to the value zero (0).
- ///
- public uint PostageStampOffset
- {
- get { return postageStampOffset; }
- set { postageStampOffset = value; }
- }
-
- ///
- /// Scan Line Offset - Field 23 (4 Bytes):
- /// Bytes 490-493 - This field is a 4-byte field containing a single offset value. This is an
- /// offset from the beginning of the file to the start of the Scan Line Table.
- ///
- public uint ScanLineOffset
- {
- get { return scanLineOffset; }
- set { scanLineOffset = value; }
- }
-
- ///
- /// Attributes Type - Field 24 (1 Byte):
- /// Byte 494 - This single byte field contains a value which specifies the type of Alpha channel
- /// data contained in the file. Value Meaning:
- /// 0: no Alpha data included (bits 3-0 of field 5.6 should also be set to zero)
- /// 1: undefined data in the Alpha field, can be ignored
- /// 2: undefined data in the Alpha field, but should be retained
- /// 3: useful Alpha channel data is present
- /// 4: pre-multiplied Alpha(see description below)
- /// 5 -127: RESERVED
- /// 128-255: Un-assigned
- /// Pre-multiplied Alpha Example: Suppose the Alpha channel data is being used to specify the
- /// opacity of each pixel(for use when the image is overlayed on another image), where 0 indicates
- /// that the pixel is completely transparent and a value of 1 indicates that the pixel is
- /// completely opaque(assume all component values have been normalized).
- /// A quadruple(a, r, g, b) of( 0.5, 1, 0, 0) would indicate that the pixel is pure red with a
- /// transparency of one-half. For numerous reasons(including image compositing) is is better to
- /// pre-multiply the individual color components with the value in the Alpha channel.
- /// A pre-multiplication of the above would produce a quadruple(0.5, 0.5, 0, 0).
- /// A value of 3 in the Attributes Type Field(field 23) would indicate that the color components
- /// of the pixel have already been scaled by the value in the Alpha channel.
- ///
- public TgaAttrType AttributesType
- {
- get { return attributesType; }
- set { attributesType = value; }
- }
-
- ///
- /// Scan Line Table - Field 25 (Variable):
- /// This information is provided, at the developers’ request, for two purposes:
- /// 1) To make random access of compressed images easy.
- /// 2) To allow “giant picture” access in smaller “chunks”.
- /// This table should contain a series of 4-byte offsets.Each offset you write should point to the
- /// start of the next scan line, in the order that the image was saved (i.e., top down or bottom up).
- /// The offset should be from the start of the file.Therefore, you will have a four byte value for
- /// each scan line in your image. This means that if your image is 768 pixels tall, you will have 768,
- /// 4-byte offset pointers (for a total of 3072 bytes). This size is not extreme, and thus this table
- /// can be built and maintained in memory, and then written out at the proper time.
- ///
- public uint[] ScanLineTable
- {
- get { return scanLineTable; }
- set { scanLineTable = value; }
- }
-
- ///
- /// Postage Stamp Image - Field 26 (Variable):
- /// The Postage Stamp area is a smaller representation of the original image. This is useful for
- /// “browsing” a collection of image files. If your application can deal with a postage stamp image,
- /// it is recommended that you create one using sub-sampling techniques to create the best
- /// representation possible. The postage stamp image must be stored in the same format as the normal
- /// image specified in the file, but without any compression. The first byte of the postage stamp
- /// image specifies the X size of the stamp in pixels, the second byte of the stamp image specifies the
- /// Y size of the stamp in pixels. Truevision does not recommend stamps larger than 64x64 pixels, and
- /// suggests that any stamps stored larger be clipped. Obviously, the storage of the postage stamp
- /// relies heavily on the storage of the image. The two images are stored using the same format under
- /// the assumption that if you can read the image, then you can read the postage stamp. If the original
- /// image is color mapped, DO NOT average the postage stamp, as you will create new colors not in your map.
- ///
- public TgaPostageStampImage PostageStampImage
- {
- get { return postageStampImage; }
- set { postageStampImage = value; }
- }
-
- ///
- /// Color Correction Table - Field 27 (2K Bytes):
- /// The Color Correction Table is a block of 256 x 4 SHORT values, where each set of
- /// four contiguous values are the desired A:R:G:B correction for that entry. This
- /// allows the user to store a correction table for image remapping or LUT driving.
- /// Since each color in the block is a SHORT, the maximum value for a color gun (i.e.,
- /// A, R, G, B) is 65535, and the minimum value is zero.Therefore, BLACK maps to
- /// 0, 0, 0, 0 and WHITE maps to 65535, 65535, 65535, 65535.
- ///
- public ushort[] ColorCorrectionTable
- {
- get { return colorCorrectionTable; }
- set { colorCorrectionTable = value; }
- }
-
- ///
- /// Other Data In Extension Area (if > 495).
- ///
- public byte[] OtherDataInExtensionArea
- {
- get { return otherDataInExtensionArea; }
- set { otherDataInExtensionArea = value; }
- }
- #endregion
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- public TgaExtArea Clone()
- {
- TgaExtArea NewExtArea = new TgaExtArea();
- NewExtArea.extensionSize = extensionSize;
- NewExtArea.authorName = authorName.Clone();
- NewExtArea.authorComments = authorComments.Clone();
- NewExtArea.dateTimeStamp = dateTimeStamp.Clone();
- NewExtArea.jobNameOrID = jobNameOrID.Clone();
- NewExtArea.jobTime = jobTime.Clone();
- NewExtArea.softwareID = softwareID.Clone();
- NewExtArea.softVersion = softVersion.Clone();
- NewExtArea.keyColor = keyColor.Clone();
- NewExtArea.pixelAspectRatio = pixelAspectRatio.Clone();
- NewExtArea.gammaValue = gammaValue.Clone();
- NewExtArea.colorCorrectionOffset = colorCorrectionOffset;
- NewExtArea.postageStampOffset = postageStampOffset;
- NewExtArea.scanLineOffset = scanLineOffset;
- NewExtArea.attributesType = attributesType;
-
- if (scanLineTable != null)
- NewExtArea.scanLineTable = (uint[])scanLineTable.Clone();
- if (postageStampImage != null)
- NewExtArea.postageStampImage = new TgaPostageStampImage(postageStampImage.ToBytes());
- if (colorCorrectionTable != null)
- NewExtArea.colorCorrectionTable = (ushort[])colorCorrectionTable.Clone();
-
- if (otherDataInExtensionArea != null)
- NewExtArea.otherDataInExtensionArea = (byte[])otherDataInExtensionArea.Clone();
-
- return NewExtArea;
- }
-
- ///
- /// Make full copy of .
- ///
- /// Full independent copy of .
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaExtArea) ? Equals((TgaExtArea)obj) : false);
- }
-
- public bool Equals(TgaExtArea item)
- {
- return (extensionSize == item.extensionSize &&
- authorName == item.authorName &&
- authorComments == item.authorComments &&
- dateTimeStamp == item.dateTimeStamp &&
- jobNameOrID == item.jobNameOrID &&
- jobTime == item.jobTime &&
- softwareID == item.softwareID &&
- softVersion == item.softVersion &&
- keyColor == item.keyColor &&
- pixelAspectRatio == item.pixelAspectRatio &&
- gammaValue == item.gammaValue &&
- colorCorrectionOffset == item.colorCorrectionOffset &&
- postageStampOffset == item.postageStampOffset &&
- scanLineOffset == item.scanLineOffset &&
- attributesType == item.attributesType &&
-
- BitConverterExt.IsArraysEqual(scanLineTable, item.scanLineTable) &&
- postageStampImage == item.postageStampImage &&
- BitConverterExt.IsArraysEqual(colorCorrectionTable, item.colorCorrectionTable) &&
-
- BitConverterExt.IsArraysEqual(otherDataInExtensionArea, item.otherDataInExtensionArea));
- }
-
- public static bool operator ==(TgaExtArea item1, TgaExtArea item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaExtArea item1, TgaExtArea item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 27;
- hash = (13 * hash) + extensionSize.GetHashCode();
- hash = (13 * hash) + authorName.GetHashCode();
- hash = (13 * hash) + authorComments.GetHashCode();
- hash = (13 * hash) + dateTimeStamp.GetHashCode();
- hash = (13 * hash) + jobNameOrID.GetHashCode();
- hash = (13 * hash) + jobTime.GetHashCode();
- hash = (13 * hash) + softwareID.GetHashCode();
- hash = (13 * hash) + softVersion.GetHashCode();
- hash = (13 * hash) + keyColor.GetHashCode();
- hash = (13 * hash) + pixelAspectRatio.GetHashCode();
- hash = (13 * hash) + gammaValue.GetHashCode();
- hash = (13 * hash) + colorCorrectionOffset.GetHashCode();
- hash = (13 * hash) + postageStampOffset.GetHashCode();
- hash = (13 * hash) + scanLineOffset.GetHashCode();
- hash = (13 * hash) + attributesType.GetHashCode();
-
- if (scanLineTable != null)
- for (int i = 0; i < scanLineTable.Length; i++)
- hash = (13 * hash) + scanLineTable[i].GetHashCode();
-
- if (postageStampImage != null)
- hash = (13 * hash) + postageStampImage.GetHashCode();
-
- if (colorCorrectionTable != null)
- for (int i = 0; i < colorCorrectionTable.Length; i++)
- hash = (13 * hash) + colorCorrectionTable[i].GetHashCode();
-
- if (otherDataInExtensionArea != null)
- for (int i = 0; i < otherDataInExtensionArea.Length; i++)
- hash = (13 * hash) + otherDataInExtensionArea[i].GetHashCode();
-
- return hash;
- }
- }
-
- ///
- /// Convert to byte array. Warning: ,
- /// , not included,
- /// because thea are can be not in the Extension Area of TGA file!
- ///
- /// Byte array.
- public byte[] ToBytes()
- {
- #region Exceptions check
- if (authorName == null)
- authorName = new TgaString(41, true);
-
- if (authorComments == null)
- authorComments = new TgaComment();
-
- if (dateTimeStamp == null)
- dateTimeStamp = new TgaDateTime(DateTime.UtcNow);
-
- if (jobNameOrID == null)
- jobNameOrID = new TgaString(41, true);
-
- if (jobTime == null)
- jobTime = new TgaTime();
-
- if (softwareID == null)
- softwareID = new TgaString(41, true);
-
- if (softVersion == null)
- softVersion = new TgaSoftVersion();
-
- if (keyColor == null)
- keyColor = new TgaColorKey();
-
- if (pixelAspectRatio == null)
- pixelAspectRatio = new TgaFraction();
-
- if (gammaValue == null)
- gammaValue = new TgaFraction();
- #endregion
-
- return BitConverterExt.ToBytes(
- extensionSize,
- authorName.ToBytes(),
- authorComments.ToBytes(),
- dateTimeStamp.ToBytes(),
- jobNameOrID.ToBytes(),
- jobTime.ToBytes(),
- softwareID.ToBytes(),
- softVersion.ToBytes(),
- keyColor.ToBytes(),
- pixelAspectRatio.ToBytes(),
- gammaValue.ToBytes(),
- colorCorrectionOffset,
- postageStampOffset,
- scanLineOffset,
- (byte)attributesType,
- otherDataInExtensionArea);
- }
- } //Not full ToBytes()
-
- ///
- /// File Footer Area
- ///
- public class TgaFooter : ICloneable
- {
- uint extAreaOffset = 0;
- uint devDirOffset = 0;
- TgaString signature = TgaString.XFileSignatute;
- TgaString reservedChar = TgaString.DotSymbol;
- TgaString zeroStrTerminator = TgaString.ZeroTerminator;
-
- ///
- /// Make NewXFile format TGA Footer with = 0 and
- /// = 0.
- ///
- public TgaFooter()
- {
- }
-
- ///
- /// Make from values.
- ///
- /// Extension Area Offset, offset from the beginning of the file.
- /// Developer Directory Offset, offset from the beginning of the file.
- /// New TGA format signature.
- /// Reserved Character - ASCII character “.” (period).
- /// Binary Zero Terminator, a binary zero which acts as a final terminator.
- public TgaFooter(uint ExtOff, uint DevDirOff, TgaString Sign, TgaString ReservChr, TgaString Termin)
- {
- extAreaOffset = ExtOff;
- devDirOffset = DevDirOff;
- signature = Sign;
- reservedChar = ReservChr;
- zeroStrTerminator = Termin;
- }
-
- ///
- /// Make from bytes (if signature is right).
- ///
- /// Bytes array (byte[26]).
- public TgaFooter(byte[] Bytes)
- {
- if (Bytes == null)
- throw new ArgumentNullException(nameof(Bytes) + " = null!");
- if (Bytes.Length != Size)
- throw new ArgumentOutOfRangeException(nameof(Bytes.Length) + " must be equal " + Size + "!");
-
- extAreaOffset = BitConverter.ToUInt32(Bytes, 0);
- devDirOffset = BitConverter.ToUInt32(Bytes, 4);
- signature = new TgaString(BitConverterExt.GetElements(Bytes, 8, TgaString.XFileSignatuteConst.Length));
- reservedChar = new TgaString(new byte[] { Bytes[24] });
- zeroStrTerminator = new TgaString(new byte[] { Bytes[25] });
- }
-
- ///
- /// Byte 0-3 - Extension Area Offset - Field 28
- /// The first four bytes (bytes 0-3, the first LONG) of the TGA File Footer contain an
- /// offset from the beginning of the file to the start of the Extension Area. Simply
- /// SEEK to this location to position to the start of the Extension Area. If the
- /// Extension Area Offset is zero, no Extension Area exists in the file.
- ///
- public uint ExtensionAreaOffset
- {
- get { return extAreaOffset; }
- set { extAreaOffset = value; }
- }
-
- ///
- /// Byte 4-7 - Developer Directory Offset - Field 29
- /// The next four bytes(bytes 4-7, the second LONG) contain an offset from the
- /// beginning of the file to the start of the Developer Directory. If the Developer
- /// Directory Offset is zero, then the Developer Area does not exist.
- ///
- public uint DeveloperDirectoryOffset
- {
- get { return devDirOffset; }
- set { devDirOffset = value; }
- }
-
- ///
- /// Byte 8-23 - Signature - Field 30
- /// This string is exactly 16 bytes long and is formatted exactly as shown below
- /// capital letters), with a hyphen between “TRUEVISION” and “XFILE.” If the
- /// signature is detected, the file is assumed to be of the New TGA format and MAY,
- /// therefore, contain the Developer Area and/or the Extension Area fields.If the
- /// signature is not found, then the file is assumed to be in the Original TGA format.
- ///
- public TgaString Signature
- {
- get { return signature; }
- set { signature = value; }
- }
-
- ///
- /// Byte 24 - Reserved Character - Field 31
- /// Byte 24 is an ASCII character “.” (period). This character MUST BE a period or
- /// the file is not considered a proper TGA file.
- ///
- public TgaString ReservedCharacter
- {
- get { return reservedChar; }
- set { reservedChar = value; }
- }
-
- ///
- /// Byte 25 - Binary Zero String Terminator - Field 32
- /// Byte 25 is a binary zero which acts as a final terminator and allows the entire TGA
- /// File Footer to be read and utilized as a “C” string.
- ///
- public TgaString BinaryZeroStringTerminator
- {
- get { return zeroStrTerminator; }
- set { zeroStrTerminator = value; }
- }
-
- ///
- /// Make full copy of .
- ///
- ///
- public TgaFooter Clone()
- {
- return new TgaFooter(extAreaOffset, devDirOffset, signature.Clone(),
- reservedChar.Clone(), zeroStrTerminator.Clone());
- }
-
- ///
- /// Make full copy of .
- ///
- ///
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- ///
- /// Gets TGA Footer Section size in bytes.
- ///
- public const int Size = 26;
-
- public override bool Equals(object obj)
- {
- return ((obj is TgaFooter) ? Equals((TgaFooter)obj) : false);
- }
-
- public bool Equals(TgaFooter item)
- {
- return (extAreaOffset == item.extAreaOffset &&
- devDirOffset == item.devDirOffset &&
- signature == item.signature &&
- reservedChar == item.reservedChar &&
- zeroStrTerminator == item.zeroStrTerminator);
- }
-
- public static bool operator ==(TgaFooter item1, TgaFooter item2)
- {
- if (ReferenceEquals(item1, null))
- return ReferenceEquals(item2, null);
-
- if (ReferenceEquals(item2, null))
- return ReferenceEquals(item1, null);
-
- return item1.Equals(item2);
- }
-
- public static bool operator !=(TgaFooter item1, TgaFooter item2)
- {
- return !(item1 == item2);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + extAreaOffset.GetHashCode();
- hash = hash * 23 + devDirOffset.GetHashCode();
-
- if (signature != null)
- hash = hash * 23 + signature.GetHashCode();
-
- if (reservedChar != null)
- hash = hash * 23 + reservedChar.GetHashCode();
-
- if (zeroStrTerminator != null)
- hash = hash * 23 + zeroStrTerminator.GetHashCode();
-
- return hash;
- }
- }
-
- public override string ToString()
- {
- return String.Format("{0}={1}, {2}={3}, FullSignature={4}",
- nameof(ExtensionAreaOffset), extAreaOffset, nameof(DeveloperDirectoryOffset), devDirOffset,
- (signature + reservedChar + zeroStrTerminator).ToString());
- }
-
- ///
- /// Convert to byte array.
- ///
- /// Byte array with size equal .
- public byte[] ToBytes()
- {
- return BitConverterExt.ToBytes(extAreaOffset, devDirOffset,
- signature.ToBytes(), reservedChar.ToBytes(), zeroStrTerminator.ToBytes());
- }
-
- ///
- /// Is footer is real footer of TGA File Format Version 2.0?
- /// Checking by .
- ///
- public bool IsFooterCorrect
- {
- get { return signature == TgaString.XFileSignatute; }
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
-
- ///
- /// Simplify ByteConversion operations, like concatination of byte arrays, comparing and other.
- ///
- public static class BitConverterExt
- {
- ///
- /// Combine byte, byte[], (u)short, (u)int, (u)long values to byte[] array.
- ///
- /// Array of byte, byte[], (u)short, (u)int, (u)long values.
- /// Array of bytes, null when some object is null.
- public static byte[] ToBytes(params object[] obj)
- {
- if (obj == null)
- return null;
-
- List BytesList = new List();
-
- for (int i = 0; i < obj.Length; i++)
- {
- if (obj[i] == null)
- continue;
- else if (obj[i] is byte)
- BytesList.Add((byte)obj[i]);
- else if (obj[i] is byte[])
- BytesList.AddRange((byte[])obj[i]);
- else if (obj[i] is short)
- BytesList.AddRange(BitConverter.GetBytes((short)obj[i]));
- else if (obj[i] is ushort)
- BytesList.AddRange(BitConverter.GetBytes((ushort)obj[i]));
- else if (obj[i] is int)
- BytesList.AddRange(BitConverter.GetBytes((int)obj[i]));
- else if (obj[i] is uint)
- BytesList.AddRange(BitConverter.GetBytes((uint)obj[i]));
- else if (obj[i] is long)
- BytesList.AddRange(BitConverter.GetBytes((long)obj[i]));
- else if (obj[i] is ulong)
- BytesList.AddRange(BitConverter.GetBytes((ulong)obj[i]));
- }
- return BytesList.ToArray();
- }
-
- ///
- /// Copies a range of elements from an Array starting at the specified source index.
- /// The length and the index are specified as 32-bit integers.
- ///
- /// The that contains the data to copy.
- /// A 32-bit integer that represents the index in the
- /// at which copying begins.
- /// A 32-bit integer that represents the number of elements to copy.
- ///
- public static T[] GetElements(T[] SrcArray, int Offset, int Count)
- {
- if (SrcArray == null)
- throw new ArgumentNullException(nameof(SrcArray) + " is null!");
-
- if (Offset >= SrcArray.Length || Offset < 0)
- throw new ArgumentOutOfRangeException(nameof(Offset) + " has wrong value!");
-
- if (Count <= 0 || Offset + Count > SrcArray.Length)
- throw new ArgumentOutOfRangeException(nameof(Count) + " has wrong value!");
-
- T[] Buff = new T[Count];
- Array.Copy(SrcArray, Offset, Buff, 0, Buff.Length);
- return Buff;
- }
-
- ///
- /// Compare N-dimensional Arrays.
- ///
- /// Arrays Type.
- /// First Array.
- /// Second Array.
- /// True, if Arrays are equal.
- public static bool IsArraysEqual(T[] item1, T[] item2)
- {
- if (ReferenceEquals(item1, item2))
- return true;
-
- if (item1 == null || item2 == null)
- return false;
-
- if (item1.Length != item2.Length)
- return false;
-
- EqualityComparer comparer = EqualityComparer.Default;
- for (int i = 0; i < item1.Length; i++)
- if (!comparer.Equals(item1[i], item2[i]))
- return false;
- return true;
- }
-
- ///
- /// Compare Lists.
- ///
- /// List Type.
- /// First List.
- /// Second List.
- /// True, if Lists are equal.
- public static bool IsListsEqual(List item1, List item2)
- {
- if (ReferenceEquals(item1, item2))
- return true;
-
- if (item1 == null || item2 == null)
- return false;
-
- if (item1.Count != item2.Count)
- return false;
-
- for (int i = 0; i < item1.Count; i++)
- if (!item1[i].Equals(item2[i]))
- return false;
- return true;
- }
-
- ///
- /// Compare elements in one Array with different offsets.
- ///
- /// Array type.
- /// Some Array.
- /// First offset.
- /// Second offset.
- /// Elements count which must be compared.
- ///
- public static bool IsElementsEqual(T[] Arr, int Offset1, int Offset2, int Count)
- {
- if (Arr == null)
- throw new ArgumentNullException(nameof(Arr) + " is null!");
-
- if (Offset1 >= Arr.Length || Offset1 < 0)
- throw new ArgumentOutOfRangeException(nameof(Offset1) + " has wrong value!");
-
- if (Offset2 >= Arr.Length || Offset2 < 0)
- throw new ArgumentOutOfRangeException(nameof(Offset2) + " has wrong value!");
-
- if (Count <= 0 || Offset1 + Count > Arr.Length || Offset2 + Count > Arr.Length)
- throw new ArgumentOutOfRangeException(nameof(Count) + " has wrong value!");
-
- if (Offset1 == Offset2)
- return true;
-
- for (int i = 0; i < Count; i++)
- if (!Arr[Offset1 + i].Equals(Arr[Offset2 + i]))
- return false;
-
- return true;
- }
- }
- #endregion
-
- public class TGA : ICloneable
- {
- public TgaHeader Header = new TgaHeader();
- public TgaImgOrColMap ImageOrColorMapArea = new TgaImgOrColMap();
- public TgaDevArea DevArea = null;
- public TgaExtArea ExtArea = null;
- public TgaFooter Footer = null;
-
- #region TGA Creation, Loading, Saving (all are public, have reference to private metods).
- ///
- /// Create new empty istance.
- ///
- public TGA()
- {
- }
-
- ///
- /// Create instance with some params. If it must have ColorMap,
- /// check all ColorMap fields and settings after.
- ///
- /// Image Width.
- /// Image Height.
- /// Image Pixel Depth (bits / pixel), set ColorMap bpp after, if needed!
- /// Image Type (is RLE compressed, ColorMapped or GrayScaled).
- /// Set numder of Attrbute bits (Alpha channel bits), default: 0, 1, 8.
- /// Use new 2.0 TGA XFile format?
- public TGA(ushort Width, ushort Height, TgaPixelDepth PixDepth = TgaPixelDepth.Bpp24,
- TgaImageType ImgType = TgaImageType.Uncompressed_TrueColor, byte AttrBits = 0, bool NewFormat = true)
- {
- if (Width <= 0 || Height <= 0 || PixDepth == TgaPixelDepth.Other)
- {
- Width = Height = 0;
- PixDepth = TgaPixelDepth.Other;
- ImgType = TgaImageType.NoImageData;
- AttrBits = 0;
- }
- else
- {
- int BytesPerPixel = (int)Math.Ceiling((double)PixDepth / 8.0);
- ImageOrColorMapArea.ImageData = new byte[Width * Height * BytesPerPixel];
-
- if (ImgType == TgaImageType.Uncompressed_ColorMapped || ImgType == TgaImageType.RLE_ColorMapped)
- {
- Header.ColorMapType = TgaColorMapType.ColorMap;
- Header.ColorMapSpec.FirstEntryIndex = 0;
- Header.ColorMapSpec.ColorMapEntrySize = (TgaColorMapEntrySize)Math.Ceiling((double)PixDepth / 8);
- }
- }
-
- Header.ImageType = ImgType;
- Header.ImageSpec.ImageWidth = Width;
- Header.ImageSpec.ImageHeight = Height;
- Header.ImageSpec.PixelDepth = PixDepth;
- Header.ImageSpec.ImageDescriptor.AlphaChannelBits = AttrBits;
-
- if (NewFormat)
- {
- Footer = new TgaFooter();
- ExtArea = new TgaExtArea();
- ExtArea.DateTimeStamp = new TgaDateTime(DateTime.UtcNow);
- ExtArea.AttributesType = (AttrBits > 0 ? TgaAttrType.UsefulAlpha : TgaAttrType.NoAlpha);
- }
- }
-
- ///
- /// Make from some instance.
- /// Equal to function.
- ///
- /// Original instance.
- public TGA(TGA tga)
- {
- Header = tga.Header.Clone();
- ImageOrColorMapArea = tga.ImageOrColorMapArea.Clone();
- DevArea = tga.DevArea.Clone();
- ExtArea = tga.ExtArea.Clone();
- Footer = tga.Footer.Clone();
- }
-
- ///
- /// Load from file.
- ///
- /// Full path to TGA file.
- /// Loaded file.
- public TGA(string filename)
- {
- LoadFunc(filename);
- }
-
- ///
- /// Make from bytes array.
- ///
- /// Bytes array (same like TGA File).
- public TGA(byte[] bytes)
- {
- LoadFunc(bytes);
- }
-
- ///
- /// Make from .
- /// For file opening better use .
- ///
- /// Some stream. You can use a lot of Stream types, but Stream must support:
- /// and .
- public TGA(Stream stream)
- {
- LoadFunc(stream);
- }
-
- ///
- /// Make from .
- ///
- /// Input Bitmap, supported a lot of bitmaps types: 8/15/16/24/32 Bpp's.
- /// Use RLE Compression?
- /// Use new 2.0 TGA XFile format?
- /// Is Color Map Entry size equal 15 or 16 Bpp, else - 24 or 32.
- public TGA(Bitmap bmp, bool UseRLE = false, bool NewFormat = true, bool ColorMap2BytesEntry = false)
- {
- LoadFunc(bmp, UseRLE, NewFormat, ColorMap2BytesEntry);
- }
-
- ///
- /// Load from file.
- ///
- /// Full path to TGA file.
- /// Loaded file.
- public static TGA FromFile(string filename)
- {
- return new TGA(filename);
- }
-
- ///
- /// Make from bytes array.
- ///
- /// Bytes array (same like TGA File).
- public static TGA FromBytes(byte[] bytes)
- {
- return new TGA(bytes);
- }
-
- ///
- /// Make from .
- /// For file opening better use .
- ///
- /// Some stream. You can use a lot of Stream types, but Stream must support:
- /// and .
- public static TGA FromStream(Stream stream)
- {
- return new TGA(stream);
- }
-
- ///
- /// Make from .
- ///
- /// Input Bitmap, supported a lot of bitmaps types: 8/15/16/24/32 Bpp's.
- /// Use RLE Compression?
- /// Use new 2.0 TGA XFile format?
- /// Is Color Map Entry size equal 15 or 16 Bpp, else - 24 or 32.
- public static TGA FromBitmap(Bitmap bmp, bool UseRLE = false,
- bool NewFormat = true, bool ColorMap2BytesEntry = false)
- {
- return new TGA(bmp, UseRLE, NewFormat, ColorMap2BytesEntry);
- }
-
- ///
- /// Save to file.
- ///
- /// Full path to file.
- /// Return "true", if all done or "false", if failed.
- public bool Save(string filename)
- {
- try
- {
- bool Result = false;
- using (FileStream Fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
- {
- using (MemoryStream Ms = new MemoryStream())
- {
- Result = SaveFunc(Ms);
- Ms.WriteTo(Fs);
- Fs.Flush();
- }
- }
- return Result;
- }
- catch
- {
- return false;
- }
- }
-
- ///
- /// Save to .
- ///
- /// Some stream, it must support: .
- /// Return "true", if all done or "false", if failed.
- public bool Save(Stream stream)
- {
- return SaveFunc(stream);
- }
- #endregion
-
- ///
- /// Gets or Sets Image Width (see ).
- ///
- public ushort Width
- {
- get { return Header.ImageSpec.ImageWidth; }
- set { Header.ImageSpec.ImageWidth = value; }
- }
-
- ///
- /// Gets or Sets Image Height (see ).
- ///
- public ushort Height
- {
- get { return Header.ImageSpec.ImageHeight; }
- set { Header.ImageSpec.ImageHeight = value; }
- }
-
- ///
- /// Gets or Sets image Size.
- ///
- public Size Size
- {
- get { return new Size(Header.ImageSpec.ImageWidth, Header.ImageSpec.ImageHeight); }
- set
- {
- Header.ImageSpec.ImageWidth = (ushort)value.Width;
- Header.ImageSpec.ImageHeight = (ushort)value.Height;
- }
- }
-
- ///
- /// Make full independed copy of .
- ///
- /// Full independed copy of .
- public TGA Clone()
- {
- return new TGA(this);
- }
-
- object ICloneable.Clone()
- {
- return Clone();
- }
-
- ///
- /// Flip directions, for more info see .
- ///
- /// Flip horizontal.
- /// Flip vertical.
- public void Flip(bool Horizontal = false, bool Vertical = false)
- {
- int NewOrigin = (int)Header.ImageSpec.ImageDescriptor.ImageOrigin;
- NewOrigin = NewOrigin ^ ((Vertical ? 0x20 : 0) | (Horizontal ? 0x10 : 0));
- Header.ImageSpec.ImageDescriptor.ImageOrigin = (TgaImgOrigin)NewOrigin;
- }
-
- ///
- /// Get information from TGA image.
- ///
- /// MultiLine string with info fields (one per line).
- public string GetInfo()
- {
- StringBuilder SB = new StringBuilder();
-
- SB.AppendLine("Header:");
- SB.AppendLine("\tID Length = " + Header.IDLength);
- SB.AppendLine("\tImage Type = " + Header.ImageType);
- SB.AppendLine("\tHeader -> ImageSpec:");
- SB.AppendLine("\t\tImage Width = " + Header.ImageSpec.ImageWidth);
- SB.AppendLine("\t\tImage Height = " + Header.ImageSpec.ImageHeight);
- SB.AppendLine("\t\tPixel Depth = " + Header.ImageSpec.PixelDepth);
- SB.AppendLine("\t\tImage Descriptor (AsByte) = " + Header.ImageSpec.ImageDescriptor.ToByte());
- SB.AppendLine("\t\tImage Descriptor -> AttributeBits = " + Header.ImageSpec.ImageDescriptor.AlphaChannelBits);
- SB.AppendLine("\t\tImage Descriptor -> ImageOrigin = " + Header.ImageSpec.ImageDescriptor.ImageOrigin);
- SB.AppendLine("\t\tX_Origin = " + Header.ImageSpec.X_Origin);
- SB.AppendLine("\t\tY_Origin = " + Header.ImageSpec.Y_Origin);
- SB.AppendLine("\tColorMap Type = " + Header.ColorMapType);
- SB.AppendLine("\tHeader -> ColorMapSpec:");
- SB.AppendLine("\t\tColorMap Entry Size = " + Header.ColorMapSpec.ColorMapEntrySize);
- SB.AppendLine("\t\tColorMap Length = " + Header.ColorMapSpec.ColorMapLength);
- SB.AppendLine("\t\tFirstEntry Index = " + Header.ColorMapSpec.FirstEntryIndex);
-
- SB.AppendLine("\nImage / Color Map Area:");
- if (Header.IDLength > 0 && ImageOrColorMapArea.ImageID != null)
- SB.AppendLine("\tImage ID = \"" + ImageOrColorMapArea.ImageID.GetString() + "\"");
- else
- SB.AppendLine("\tImage ID = null");
-
- if (ImageOrColorMapArea.ImageData != null)
- SB.AppendLine("\tImage Data Length = " + ImageOrColorMapArea.ImageData.Length);
- else
- SB.AppendLine("\tImage Data = null");
-
- if (ImageOrColorMapArea.ColorMapData != null)
- SB.AppendLine("\tColorMap Data Length = " + ImageOrColorMapArea.ColorMapData.Length);
- else
- SB.AppendLine("\tColorMap Data = null");
-
- SB.AppendLine("\nDevelopers Area:");
- if (DevArea != null)
- SB.AppendLine("\tCount = " + DevArea.Count);
- else
- SB.AppendLine("\tDevArea = null");
-
- SB.AppendLine("\nExtension Area:");
- if (ExtArea != null)
- {
- SB.AppendLine("\tExtension Size = " + ExtArea.ExtensionSize);
- SB.AppendLine("\tAuthor Name = \"" + ExtArea.AuthorName.GetString() + "\"");
- SB.AppendLine("\tAuthor Comments = \"" + ExtArea.AuthorComments.GetString() + "\"");
- SB.AppendLine("\tDate / Time Stamp = " + ExtArea.DateTimeStamp);
- SB.AppendLine("\tJob Name / ID = \"" + ExtArea.JobNameOrID.GetString() + "\"");
- SB.AppendLine("\tJob Time = " + ExtArea.JobTime);
- SB.AppendLine("\tSoftware ID = \"" + ExtArea.SoftwareID.GetString() + "\"");
- SB.AppendLine("\tSoftware Version = \"" + ExtArea.SoftVersion + "\"");
- SB.AppendLine("\tKey Color = " + ExtArea.KeyColor);
- SB.AppendLine("\tPixel Aspect Ratio = " + ExtArea.PixelAspectRatio);
- SB.AppendLine("\tGamma Value = " + ExtArea.GammaValue);
- SB.AppendLine("\tColor Correction Table Offset = " + ExtArea.ColorCorrectionTableOffset);
- SB.AppendLine("\tPostage Stamp Offset = " + ExtArea.PostageStampOffset);
- SB.AppendLine("\tScan Line Offset = " + ExtArea.ScanLineOffset);
- SB.AppendLine("\tAttributes Type = " + ExtArea.AttributesType);
-
- if (ExtArea.ScanLineTable != null)
- SB.AppendLine("\tScan Line Table = " + ExtArea.ScanLineTable.Length);
- else
- SB.AppendLine("\tScan Line Table = null");
-
- if (ExtArea.PostageStampImage != null)
- SB.AppendLine("\tPostage Stamp Image: " + ExtArea.PostageStampImage.ToString());
- else
- SB.AppendLine("\tPostage Stamp Image = null");
-
- SB.AppendLine("\tColor Correction Table = " + (ExtArea.ColorCorrectionTable != null));
- }
- else
- SB.AppendLine("\tExtArea = null");
-
- SB.AppendLine("\nFooter:");
- if (Footer != null)
- {
- SB.AppendLine("\tExtension Area Offset = " + Footer.ExtensionAreaOffset);
- SB.AppendLine("\tDeveloper Directory Offset = " + Footer.DeveloperDirectoryOffset);
- SB.AppendLine("\tSignature (Full) = \"" + Footer.Signature.ToString() +
- Footer.ReservedCharacter.ToString() + Footer.BinaryZeroStringTerminator.ToString() + "\"");
- }
- else
- SB.AppendLine("\tFooter = null");
-
- return SB.ToString();
- }
-
- ///
- /// Check and update all fields with data length and offsets.
- ///
- /// Return "true", if all OK or "false", if checking failed.
- public bool CheckAndUpdateOffsets(out string ErrorStr)
- {
- ErrorStr = String.Empty;
-
- if (Header == null)
- {
- ErrorStr = "Header = null";
- return false;
- }
-
- if (ImageOrColorMapArea == null)
- {
- ErrorStr = "ImageOrColorMapArea = null";
- return false;
- }
-
- uint Offset = TgaHeader.Size; // Virtual Offset
-
- #region Header
- if (ImageOrColorMapArea.ImageID != null)
- {
- int StrMaxLen = 255;
- if (ImageOrColorMapArea.ImageID.UseEndingChar)
- StrMaxLen--;
-
- Header.IDLength = (byte)Math.Min(ImageOrColorMapArea.ImageID.OriginalString.Length, StrMaxLen);
- ImageOrColorMapArea.ImageID.Length = Header.IDLength;
- Offset += Header.IDLength;
- }
- else
- Header.IDLength = 0;
- #endregion
-
- #region ColorMap
- if (Header.ColorMapType != TgaColorMapType.NoColorMap)
- {
- if (Header.ColorMapSpec == null)
- {
- ErrorStr = "Header.ColorMapSpec = null";
- return false;
- }
-
- if (Header.ColorMapSpec.ColorMapLength == 0)
- {
- ErrorStr = "Header.ColorMapSpec.ColorMapLength = 0";
- return false;
- }
-
- if (ImageOrColorMapArea.ColorMapData == null)
- {
- ErrorStr = "ImageOrColorMapArea.ColorMapData = null";
- return false;
- }
-
- int CmBytesPerPixel = (int)Math.Ceiling((double)Header.ColorMapSpec.ColorMapEntrySize / 8.0);
- int LenBytes = Header.ColorMapSpec.ColorMapLength * CmBytesPerPixel;
-
- if (LenBytes != ImageOrColorMapArea.ColorMapData.Length)
- {
- ErrorStr = "ImageOrColorMapArea.ColorMapData.Length has wrong size!";
- return false;
- }
-
- Offset += (uint)ImageOrColorMapArea.ColorMapData.Length;
- }
- #endregion
-
- #region Image Data
- int BytesPerPixel = 0;
- if (Header.ImageType != TgaImageType.NoImageData)
- {
- if (Header.ImageSpec == null)
- {
- ErrorStr = "Header.ImageSpec = null";
- return false;
- }
-
- if (Header.ImageSpec.ImageWidth == 0 || Header.ImageSpec.ImageHeight == 0)
- {
- ErrorStr = "Header.ImageSpec.ImageWidth = 0 or Header.ImageSpec.ImageHeight = 0";
- return false;
- }
-
- if (ImageOrColorMapArea.ImageData == null)
- {
- ErrorStr = "ImageOrColorMapArea.ImageData = null";
- return false;
- }
-
- BytesPerPixel = (int)Math.Ceiling((double)Header.ImageSpec.PixelDepth / 8.0);
- if (Width * Height * BytesPerPixel != ImageOrColorMapArea.ImageData.Length)
- {
- ErrorStr = "ImageOrColorMapArea.ImageData.Length has wrong size!";
- return false;
- }
-
- if (Header.ImageType >= TgaImageType.RLE_ColorMapped &&
- Header.ImageType <= TgaImageType.RLE_BlackWhite)
- {
- byte[] RLE = RLE_Encode(ImageOrColorMapArea.ImageData, Width, Height);
- if (RLE == null)
- {
- ErrorStr = "RLE Compressing error! Check Image Data size.";
- return false;
- }
-
- Offset += (uint)RLE.Length;
- RLE = null;
- }
- else
- Offset += (uint)ImageOrColorMapArea.ImageData.Length;
- }
- #endregion
-
- #region Footer, DevArea, ExtArea
- if (Footer != null)
- {
- #region DevArea
- if (DevArea != null)
- {
- int DevAreaCount = DevArea.Count;
- for (int i = 0; i < DevAreaCount; i++)
- if (DevArea[i] == null || DevArea[i].FieldSize <= 0) //Del Empty Entries
- {
- DevArea.Entries.RemoveAt(i);
- DevAreaCount--;
- i--;
- }
-
- if (DevArea.Count <= 0)
- Footer.DeveloperDirectoryOffset = 0;
-
- if (DevArea.Count > 2)
- {
- DevArea.Entries.Sort((a, b) => { return a.Tag.CompareTo(b.Tag); });
- for (int i = 0; i < DevArea.Count - 1; i++)
- if (DevArea[i].Tag == DevArea[i + 1].Tag)
- {
- ErrorStr = "DevArea Enties has same Tags!";
- return false;
- }
- }
-
- for (int i = 0; i < DevArea.Count; i++)
- {
- DevArea[i].Offset = Offset;
- Offset += (uint)DevArea[i].FieldSize;
- }
-
- Footer.DeveloperDirectoryOffset = Offset;
- Offset += (uint)(DevArea.Count * 10 + 2);
- }
- else
- Footer.DeveloperDirectoryOffset = 0;
- #endregion
-
- #region ExtArea
- if (ExtArea != null)
- {
- ExtArea.ExtensionSize = TgaExtArea.MinSize;
- if (ExtArea.OtherDataInExtensionArea != null)
- ExtArea.ExtensionSize += (ushort)ExtArea.OtherDataInExtensionArea.Length;
-
- ExtArea.DateTimeStamp = new TgaDateTime(DateTime.UtcNow);
-
- Footer.ExtensionAreaOffset = Offset;
- Offset += ExtArea.ExtensionSize;
-
- #region ScanLineTable
- if (ExtArea.ScanLineTable == null)
- ExtArea.ScanLineOffset = 0;
- else
- {
- if (ExtArea.ScanLineTable.Length != Height)
- {
- ErrorStr = "ExtArea.ScanLineTable.Length != Height";
- return false;
- }
-
- ExtArea.ScanLineOffset = Offset;
- Offset += (uint)(ExtArea.ScanLineTable.Length * 4);
- }
- #endregion
-
- #region PostageStampImage
- if (ExtArea.PostageStampImage == null)
- ExtArea.PostageStampOffset = 0;
- else
- {
- if (ExtArea.PostageStampImage.Width == 0 || ExtArea.PostageStampImage.Height == 0)
- {
- ErrorStr = "ExtArea.PostageStampImage Width or Height is equal 0!";
- return false;
- }
-
- if (ExtArea.PostageStampImage.Data == null)
- {
- ErrorStr = "ExtArea.PostageStampImage.Data == null";
- return false;
- }
-
- int PImgSB = ExtArea.PostageStampImage.Width * ExtArea.PostageStampImage.Height * BytesPerPixel;
- if (Header.ImageType != TgaImageType.NoImageData &&
- ExtArea.PostageStampImage.Data.Length != PImgSB)
- {
- ErrorStr = "ExtArea.PostageStampImage.Data.Length is wrong!";
- return false;
- }
-
-
- ExtArea.PostageStampOffset = Offset;
- Offset += (uint)(ExtArea.PostageStampImage.Data.Length);
- }
- #endregion
-
- #region ColorCorrectionTable
- if (ExtArea.ColorCorrectionTable == null)
- ExtArea.ColorCorrectionTableOffset = 0;
- else
- {
- if (ExtArea.ColorCorrectionTable.Length != 1024)
- {
- ErrorStr = "ExtArea.ColorCorrectionTable.Length != 256 * 4";
- return false;
- }
-
- ExtArea.ColorCorrectionTableOffset = Offset;
- Offset += (uint)(ExtArea.ColorCorrectionTable.Length * 2);
- }
- #endregion
- }
- else
- Footer.ExtensionAreaOffset = 0;
- #endregion
-
- #region Footer
- if (Footer.ToBytes().Length != TgaFooter.Size)
- {
- ErrorStr = "Footer.Length is wrong!";
- return false;
- }
-
- Offset += TgaFooter.Size;
- #endregion
- }
- #endregion
-
- return true;
- }
-
- #region Convert
- ///
- /// Convert to .
- ///
- /// Force use alpha channel.
- /// Bitmap or null, on error.
- public Bitmap ToBitmap(bool ForceUseAlpha = false)
- {
- return ToBitmapFunc(ForceUseAlpha, false);
- }
-
- ///
- /// Convert to bytes array.
- ///
- /// Bytes array, (equal to saved file, but in memory) or null (on error).
- public byte[] ToBytes()
- {
- try
- {
- byte[] Bytes;
- using (MemoryStream ms = new MemoryStream())
- {
- Save(ms);
- Bytes = ms.ToArray();
- ms.Flush();
- }
- return Bytes;
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Convert TGA Image to new XFile format (v2.0).
- ///
- public void ToNewFormat()
- {
- if (Footer == null)
- Footer = new TgaFooter();
-
- if (ExtArea == null)
- {
- ExtArea = new TgaExtArea();
-
- ExtArea.DateTimeStamp = new TgaDateTime(DateTime.UtcNow);
-
- if (Header.ImageSpec.ImageDescriptor.AlphaChannelBits > 0)
- ExtArea.AttributesType = TgaAttrType.UsefulAlpha;
- else
- ExtArea.AttributesType = TgaAttrType.NoAlpha;
- }
- }
- #endregion
-
- #region Private functions
- bool LoadFunc(string filename)
- {
- if (!File.Exists(filename))
- throw new FileNotFoundException("File: \"" + filename + "\" not found!");
-
- try
- {
- using (FileStream FS = new FileStream(filename, FileMode.Open))
- return LoadFunc(FS);
- }
- catch
- {
- return false;
- }
- }
-
- bool LoadFunc(byte[] bytes)
- {
- if (bytes == null)
- throw new ArgumentNullException();
-
- try
- {
- using (MemoryStream FS = new MemoryStream(bytes, false))
- return LoadFunc(FS);
- }
- catch
- {
- return false;
- }
- }
-
- bool LoadFunc(Stream stream)
- {
- if (stream == null)
- throw new ArgumentNullException();
- if (!(stream.CanRead && stream.CanSeek))
- throw new FileLoadException("Stream reading or seeking is not avaiable!");
-
- try
- {
- stream.Seek(0, SeekOrigin.Begin);
- BinaryReader Br = new BinaryReader(stream);
-
- Header = new TgaHeader(Br.ReadBytes(TgaHeader.Size));
-
- if (Header.IDLength > 0)
- ImageOrColorMapArea.ImageID = new TgaString(Br.ReadBytes(Header.IDLength));
-
- if (Header.ColorMapSpec.ColorMapLength > 0)
- {
- int CmBytesPerPixel = (int)Math.Ceiling((double)Header.ColorMapSpec.ColorMapEntrySize / 8.0);
- int LenBytes = Header.ColorMapSpec.ColorMapLength * CmBytesPerPixel;
- ImageOrColorMapArea.ColorMapData = Br.ReadBytes(LenBytes);
- }
-
- #region Read Image Data
- int BytesPerPixel = (int)Math.Ceiling((double)Header.ImageSpec.PixelDepth / 8.0);
- if (Header.ImageType != TgaImageType.NoImageData)
- {
- int ImageDataSize = Width * Height * BytesPerPixel;
- switch (Header.ImageType)
- {
- case TgaImageType.RLE_ColorMapped:
- case TgaImageType.RLE_TrueColor:
- case TgaImageType.RLE_BlackWhite:
-
- int DataOffset = 0;
- byte PacketInfo;
- int PacketCount;
- byte[] RLE_Bytes, RLE_Part;
- ImageOrColorMapArea.ImageData = new byte[ImageDataSize];
-
- do
- {
- PacketInfo = Br.ReadByte(); //1 type bit and 7 count bits. Len = Count + 1.
- PacketCount = (PacketInfo & 127) + 1;
-
- if (PacketInfo >= 128) // bit7 = 1, RLE
- {
- RLE_Bytes = new byte[PacketCount * BytesPerPixel];
- RLE_Part = Br.ReadBytes(BytesPerPixel);
- for (int i = 0; i < RLE_Bytes.Length; i++)
- RLE_Bytes[i] = RLE_Part[i % BytesPerPixel];
- }
- else // RAW format
- RLE_Bytes = Br.ReadBytes(PacketCount * BytesPerPixel);
-
- Buffer.BlockCopy(RLE_Bytes, 0, ImageOrColorMapArea.ImageData, DataOffset, RLE_Bytes.Length);
- DataOffset += RLE_Bytes.Length;
- }
- while (DataOffset < ImageDataSize);
- RLE_Bytes = null;
- break;
-
- case TgaImageType.Uncompressed_ColorMapped:
- case TgaImageType.Uncompressed_TrueColor:
- case TgaImageType.Uncompressed_BlackWhite:
- ImageOrColorMapArea.ImageData = Br.ReadBytes(ImageDataSize);
- break;
- }
- }
- #endregion
-
- #region Try parse Footer
- stream.Seek(-TgaFooter.Size, SeekOrigin.End);
- uint FooterOffset = (uint)stream.Position;
- TgaFooter MbFooter = new TgaFooter(Br.ReadBytes(TgaFooter.Size));
- if (MbFooter.IsFooterCorrect)
- {
- Footer = MbFooter;
- uint DevDirOffset = Footer.DeveloperDirectoryOffset;
- uint ExtAreaOffset = Footer.ExtensionAreaOffset;
-
- #region If Dev Area exist, read it.
- if (DevDirOffset != 0)
- {
- stream.Seek(DevDirOffset, SeekOrigin.Begin);
- DevArea = new TgaDevArea();
- uint NumberOfTags = Br.ReadUInt16();
-
- ushort[] Tags = new ushort[NumberOfTags];
- uint[] TagOffsets = new uint[NumberOfTags];
- uint[] TagSizes = new uint[NumberOfTags];
-
- for (int i = 0; i < NumberOfTags; i++)
- {
- Tags[i] = Br.ReadUInt16();
- TagOffsets[i] = Br.ReadUInt32();
- TagSizes[i] = Br.ReadUInt32();
- }
-
- for (int i = 0; i < NumberOfTags; i++)
- {
- stream.Seek(TagOffsets[i], SeekOrigin.Begin);
- var Ent = new TgaDevEntry(Tags[i], TagOffsets[i], Br.ReadBytes((int)TagSizes[i]));
- DevArea.Entries.Add(Ent);
- }
-
- Tags = null;
- TagOffsets = null;
- TagSizes = null;
- }
- #endregion
-
- #region If Ext Area exist, read it.
- if (ExtAreaOffset != 0)
- {
- stream.Seek(ExtAreaOffset, SeekOrigin.Begin);
- ushort ExtAreaSize = Math.Max((ushort)TgaExtArea.MinSize, Br.ReadUInt16());
- stream.Seek(ExtAreaOffset, SeekOrigin.Begin);
- ExtArea = new TgaExtArea(Br.ReadBytes(ExtAreaSize));
-
- if (ExtArea.ScanLineOffset > 0)
- {
- stream.Seek(ExtArea.ScanLineOffset, SeekOrigin.Begin);
- ExtArea.ScanLineTable = new uint[Height];
- for (int i = 0; i < ExtArea.ScanLineTable.Length; i++)
- ExtArea.ScanLineTable[i] = Br.ReadUInt32();
- }
-
- if (ExtArea.PostageStampOffset > 0)
- {
- stream.Seek(ExtArea.PostageStampOffset, SeekOrigin.Begin);
- byte W = Br.ReadByte();
- byte H = Br.ReadByte();
- int ImgDataSize = W * H * BytesPerPixel;
- if (ImgDataSize > 0)
- ExtArea.PostageStampImage = new TgaPostageStampImage(W, H, Br.ReadBytes(ImgDataSize));
- }
-
- if (ExtArea.ColorCorrectionTableOffset > 0)
- {
- stream.Seek(ExtArea.ColorCorrectionTableOffset, SeekOrigin.Begin);
- ExtArea.ColorCorrectionTable = new ushort[256 * 4];
- for (int i = 0; i < ExtArea.ColorCorrectionTable.Length; i++)
- ExtArea.ColorCorrectionTable[i] = Br.ReadUInt16();
- }
- }
- #endregion
- }
- #endregion
-
- Br.Close();
- return true;
- }
- catch
- {
- return false;
- }
- }
-
- bool LoadFunc(Bitmap bmp, bool UseRLE = false, bool NewFormat = true, bool ColorMap2BytesEntry = false)
- {
- if (bmp == null)
- throw new ArgumentNullException();
-
- try
- {
- Header.ImageSpec.ImageWidth = (ushort)bmp.Width;
- Header.ImageSpec.ImageHeight = (ushort)bmp.Height;
- Header.ImageSpec.ImageDescriptor.ImageOrigin = TgaImgOrigin.TopLeft;
-
- switch (bmp.PixelFormat)
- {
- case PixelFormat.Indexed:
- case PixelFormat.Gdi:
- case PixelFormat.Alpha:
- case PixelFormat.Undefined:
- case PixelFormat.PAlpha:
- case PixelFormat.Extended:
- case PixelFormat.Max:
- case PixelFormat.Canonical:
- case PixelFormat.Format16bppRgb565:
- default:
- throw new FormatException(nameof(PixelFormat) + " is not supported!");
-
- case PixelFormat.Format1bppIndexed:
- case PixelFormat.Format4bppIndexed:
- case PixelFormat.Format8bppIndexed:
- case PixelFormat.Format16bppGrayScale:
- case PixelFormat.Format16bppRgb555:
- case PixelFormat.Format16bppArgb1555:
- case PixelFormat.Format24bppRgb:
- case PixelFormat.Format32bppRgb:
- case PixelFormat.Format32bppArgb:
- case PixelFormat.Format32bppPArgb:
- case PixelFormat.Format48bppRgb:
- case PixelFormat.Format64bppArgb:
- case PixelFormat.Format64bppPArgb:
-
- int bpp = Math.Max(8, Image.GetPixelFormatSize(bmp.PixelFormat));
- int BytesPP = bpp / 8;
-
- if (bmp.PixelFormat == PixelFormat.Format16bppRgb555)
- bpp = 15;
-
- bool IsAlpha = Image.IsAlphaPixelFormat(bmp.PixelFormat);
- bool IsPreAlpha = IsAlpha && bmp.PixelFormat.ToString().EndsWith("PArgb");
- bool IsColorMapped = bmp.PixelFormat.ToString().EndsWith("Indexed");
-
- Header.ImageSpec.PixelDepth = (TgaPixelDepth)(BytesPP * 8);
-
- if (IsAlpha)
- {
- Header.ImageSpec.ImageDescriptor.AlphaChannelBits = (byte)(BytesPP * 2);
-
- if (bmp.PixelFormat == PixelFormat.Format16bppArgb1555)
- Header.ImageSpec.ImageDescriptor.AlphaChannelBits = 1;
- }
-
- #region ColorMap
- bool IsGrayImage = (bmp.PixelFormat == PixelFormat.Format16bppGrayScale | IsColorMapped);
-
- if (IsColorMapped && bmp.Palette != null)
- {
- Color[] Colors = bmp.Palette.Entries;
-
- #region Analyze ColorMapType
- int AlphaSum = 0;
- bool ColorMapUseAlpha = false;
-
- for (int i = 0; i < Colors.Length; i++)
- {
- IsGrayImage &= (Colors[i].R == Colors[i].G && Colors[i].G == Colors[i].B);
- ColorMapUseAlpha |= (Colors[i].A < 248);
- AlphaSum |= Colors[i].A;
- }
- ColorMapUseAlpha &= (AlphaSum > 0);
-
- int CMapBpp = (ColorMap2BytesEntry ? 15 : 24) + (ColorMapUseAlpha ? (ColorMap2BytesEntry ? 1 : 8) : 0);
- int CMBytesPP = (int)Math.Ceiling(CMapBpp / 8.0);
- #endregion
-
- Header.ColorMapSpec.ColorMapLength = Math.Min((ushort)Colors.Length, ushort.MaxValue);
- Header.ColorMapSpec.ColorMapEntrySize = (TgaColorMapEntrySize)CMapBpp;
- ImageOrColorMapArea.ColorMapData = new byte[Header.ColorMapSpec.ColorMapLength * CMBytesPP];
-
- byte[] CMapEntry = new byte[CMBytesPP];
-
- const float To5Bit = 32f / 256f; // Scale value from 8 to 5 bits.
- for (int i = 0; i < Colors.Length; i++)
- {
- switch (Header.ColorMapSpec.ColorMapEntrySize)
- {
- case TgaColorMapEntrySize.A1R5G5B5:
- case TgaColorMapEntrySize.X1R5G5B5:
- int R = (int)(Colors[i].R * To5Bit);
- int G = (int)(Colors[i].G * To5Bit) << 5;
- int B = (int)(Colors[i].B * To5Bit) << 10;
- int A = 0;
-
- if (Header.ColorMapSpec.ColorMapEntrySize == TgaColorMapEntrySize.A1R5G5B5)
- A = ((Colors[i].A & 0x80) << 15);
-
- CMapEntry = BitConverter.GetBytes(A | R | G | B);
- break;
-
- case TgaColorMapEntrySize.R8G8B8:
- CMapEntry[0] = Colors[i].B;
- CMapEntry[1] = Colors[i].G;
- CMapEntry[2] = Colors[i].R;
- break;
-
- case TgaColorMapEntrySize.A8R8G8B8:
- CMapEntry[0] = Colors[i].B;
- CMapEntry[1] = Colors[i].G;
- CMapEntry[2] = Colors[i].R;
- CMapEntry[3] = Colors[i].A;
- break;
-
- case TgaColorMapEntrySize.Other:
- default:
- break;
- }
-
- Buffer.BlockCopy(CMapEntry, 0, ImageOrColorMapArea.ColorMapData, i * CMBytesPP, CMBytesPP);
- }
- }
- #endregion
-
- #region ImageType
- if (UseRLE)
- {
- if (IsGrayImage)
- Header.ImageType = TgaImageType.RLE_BlackWhite;
- else if (IsColorMapped)
- Header.ImageType = TgaImageType.RLE_ColorMapped;
- else
- Header.ImageType = TgaImageType.RLE_TrueColor;
- }
- else
- {
- if (IsGrayImage)
- Header.ImageType = TgaImageType.Uncompressed_BlackWhite;
- else if (IsColorMapped)
- Header.ImageType = TgaImageType.Uncompressed_ColorMapped;
- else
- Header.ImageType = TgaImageType.Uncompressed_TrueColor;
- }
-
- Header.ColorMapType = (IsColorMapped ? TgaColorMapType.ColorMap : TgaColorMapType.NoColorMap);
- #endregion
-
- #region NewFormat
- if (NewFormat)
- {
- Footer = new TgaFooter();
- ExtArea = new TgaExtArea();
- ExtArea.DateTimeStamp = new TgaDateTime(DateTime.UtcNow);
-
- if (IsAlpha)
- {
- ExtArea.AttributesType = TgaAttrType.UsefulAlpha;
-
- if (IsPreAlpha)
- ExtArea.AttributesType = TgaAttrType.PreMultipliedAlpha;
- }
- else
- {
- ExtArea.AttributesType = TgaAttrType.NoAlpha;
-
- if (Header.ImageSpec.ImageDescriptor.AlphaChannelBits > 0)
- ExtArea.AttributesType = TgaAttrType.UndefinedAlphaButShouldBeRetained;
- }
- }
- #endregion
-
- #region Bitmap width is aligned by 32 bits = 4 bytes! Delete it.
- int StrideBytes = bmp.Width * BytesPP;
- int PaddingBytes = (int)Math.Ceiling(StrideBytes / 4.0) * 4 - StrideBytes;
-
- byte[] ImageData = new byte[(StrideBytes + PaddingBytes) * bmp.Height];
-
- Rectangle Re = new Rectangle(0, 0, bmp.Width, bmp.Height);
- BitmapData BmpData = bmp.LockBits(Re, ImageLockMode.ReadOnly, bmp.PixelFormat);
- Marshal.Copy(BmpData.Scan0, ImageData, 0, ImageData.Length);
- bmp.UnlockBits(BmpData);
- BmpData = null;
-
- if (PaddingBytes > 0) //Need delete bytes align
- {
- ImageOrColorMapArea.ImageData = new byte[StrideBytes * bmp.Height];
- for (int i = 0; i < bmp.Height; i++)
- Buffer.BlockCopy(ImageData, i * (StrideBytes + PaddingBytes),
- ImageOrColorMapArea.ImageData, i * StrideBytes, StrideBytes);
- }
- else
- ImageOrColorMapArea.ImageData = ImageData;
-
- ImageData = null;
-
- // Not official supported, but works (tested on 16bpp GrayScale test images)!
- if (bmp.PixelFormat == PixelFormat.Format16bppGrayScale)
- {
- for (long i = 0; i < ImageOrColorMapArea.ImageData.Length; i++)
- ImageOrColorMapArea.ImageData[i] ^= byte.MaxValue;
- }
- #endregion
-
- break;
- }
-
- return true;
- }
- catch
- {
- return false;
- }
- }
-
- bool SaveFunc(Stream stream)
- {
- try
- {
- if (stream == null)
- throw new ArgumentNullException();
- if (!(stream.CanWrite && stream.CanSeek))
- throw new FileLoadException("Stream writing or seeking is not avaiable!");
-
- string CheckResult;
- if (!CheckAndUpdateOffsets(out CheckResult))
- return false;
-
- BinaryWriter Bw = new BinaryWriter(stream);
- Bw.Write(Header.ToBytes());
-
- if (ImageOrColorMapArea.ImageID != null)
- Bw.Write(ImageOrColorMapArea.ImageID.ToBytes());
-
- if (Header.ColorMapType != TgaColorMapType.NoColorMap)
- Bw.Write(ImageOrColorMapArea.ColorMapData);
-
- #region ImageData
- if (Header.ImageType != TgaImageType.NoImageData)
- {
- if (Header.ImageType >= TgaImageType.RLE_ColorMapped &&
- Header.ImageType <= TgaImageType.RLE_BlackWhite)
- Bw.Write(RLE_Encode(ImageOrColorMapArea.ImageData, Width, Height));
- else
- Bw.Write(ImageOrColorMapArea.ImageData);
- }
- #endregion
-
- #region Footer
- if (Footer != null)
- {
- #region DevArea
- if (DevArea != null)
- {
- for (int i = 0; i < DevArea.Count; i++)
- Bw.Write(DevArea[i].Data);
-
- Bw.Write((ushort)DevArea.Count);
-
- for (int i = 0; i < DevArea.Count; i++)
- {
- Bw.Write(DevArea[i].Tag);
- Bw.Write(DevArea[i].Offset);
- Bw.Write(DevArea[i].FieldSize);
- }
- }
- #endregion
-
- #region ExtArea
- if (ExtArea != null)
- {
- Bw.Write(ExtArea.ToBytes());
-
- if (ExtArea.ScanLineTable != null)
- for (int i = 0; i < ExtArea.ScanLineTable.Length; i++)
- Bw.Write(ExtArea.ScanLineTable[i]);
-
- if (ExtArea.PostageStampImage != null)
- Bw.Write(ExtArea.PostageStampImage.ToBytes());
-
- if (ExtArea.ColorCorrectionTable != null)
- for (int i = 0; i < ExtArea.ColorCorrectionTable.Length; i++)
- Bw.Write(ExtArea.ColorCorrectionTable[i]);
- }
- #endregion
-
- Bw.Write(Footer.ToBytes());
- }
- #endregion
-
- Bw.Flush();
- stream.Flush();
- return true;
- }
- catch
- {
- return false;
- }
- }
-
- ///
- /// Encode image with RLE compression (used RLE per line)!
- ///
- /// Image data, bytes array with size = Width * Height * BytesPerPixel.
- /// Image Width, must be > 0.
- /// Image Height, must be > 0.
- /// Bytes array with RLE compressed image data.
- byte[] RLE_Encode(byte[] ImageData, int Width, int Height)
- {
- if (ImageData == null)
- throw new ArgumentNullException(nameof(ImageData) + "in null!");
-
- if (Width <= 0 || Height <= 0)
- throw new ArgumentOutOfRangeException(nameof(Width) + " and " + nameof(Height) + " must be > 0!");
-
- int Bpp = ImageData.Length / Width / Height; // Bytes per pixel
- int ScanLineSize = Width * Bpp;
-
- if (ScanLineSize * Height != ImageData.Length)
- throw new ArgumentOutOfRangeException("ImageData has wrong Length!");
-
- try
- {
- int Count = 0;
- int Pos = 0;
- bool IsRLE = false;
- List Encoded = new List();
- byte[] RowData = new byte[ScanLineSize];
-
- for (int y = 0; y < Height; y++)
- {
- Pos = 0;
- Buffer.BlockCopy(ImageData, y * ScanLineSize, RowData, 0, ScanLineSize);
-
- while (Pos < ScanLineSize)
- {
- if (Pos >= ScanLineSize - Bpp)
- {
- Encoded.Add(0);
- Encoded.AddRange(BitConverterExt.GetElements(RowData, Pos, Bpp));
- Pos += Bpp;
- break;
- }
-
- Count = 0; //1
- IsRLE = BitConverterExt.IsElementsEqual(RowData, Pos, Pos + Bpp, Bpp);
-
- for (int i = Pos + Bpp; i < Math.Min(Pos + 128 * Bpp, ScanLineSize) - Bpp; i += Bpp)
- {
- if (IsRLE ^ BitConverterExt.IsElementsEqual(RowData, (IsRLE ? Pos : i), i + Bpp, Bpp))
- {
- //Count--;
- break;
- }
- else
- Count++;
- }
-
- int CountBpp = (Count + 1) * Bpp;
- Encoded.Add((byte)(IsRLE ? Count | 128 : Count));
- Encoded.AddRange(BitConverterExt.GetElements(RowData, Pos, (IsRLE ? Bpp : CountBpp)));
- Pos += CountBpp;
- }
- }
-
- return Encoded.ToArray();
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Convert to .
- ///
- /// Force use alpha channel.
- /// Get Postage Stamp Image (Thumb) or get main image?
- /// Bitmap or null, on error.
- Bitmap ToBitmapFunc(bool ForceUseAlpha = false, bool PostageStampImage = false)
- {
- try
- {
- #region UseAlpha?
- bool UseAlpha = true;
- if (ExtArea != null)
- {
- switch (ExtArea.AttributesType)
- {
- case TgaAttrType.NoAlpha:
- case TgaAttrType.UndefinedAlphaCanBeIgnored:
- case TgaAttrType.UndefinedAlphaButShouldBeRetained:
- UseAlpha = false;
- break;
- case TgaAttrType.UsefulAlpha:
- case TgaAttrType.PreMultipliedAlpha:
- default:
- break;
- }
- }
- UseAlpha = (Header.ImageSpec.ImageDescriptor.AlphaChannelBits > 0 && UseAlpha) | ForceUseAlpha;
- #endregion
-
- #region IsGrayImage
- bool IsGrayImage = Header.ImageType == TgaImageType.RLE_BlackWhite ||
- Header.ImageType == TgaImageType.Uncompressed_BlackWhite;
- #endregion
-
- #region Get PixelFormat
- PixelFormat PixFormat = PixelFormat.Format24bppRgb;
-
- switch (Header.ImageSpec.PixelDepth)
- {
- case TgaPixelDepth.Bpp8:
- PixFormat = PixelFormat.Format8bppIndexed;
- break;
-
- case TgaPixelDepth.Bpp16:
- if (IsGrayImage)
- PixFormat = PixelFormat.Format16bppGrayScale;
- else
- PixFormat = (UseAlpha ? PixelFormat.Format16bppArgb1555 : PixelFormat.Format16bppRgb555);
- break;
-
- case TgaPixelDepth.Bpp24:
- PixFormat = PixelFormat.Format24bppRgb;
- break;
-
- case TgaPixelDepth.Bpp32:
- if (UseAlpha)
- {
- var f = Footer;
- if (ExtArea?.AttributesType == TgaAttrType.PreMultipliedAlpha)
- PixFormat = PixelFormat.Format32bppPArgb;
- else
- PixFormat = PixelFormat.Format32bppArgb;
- }
- else
- PixFormat = PixelFormat.Format32bppRgb;
- break;
-
- default:
- PixFormat = PixelFormat.Undefined;
- break;
- }
- #endregion
-
- ushort BMP_Width = (PostageStampImage ? ExtArea.PostageStampImage.Width : Width);
- ushort BMP_Height = (PostageStampImage ? ExtArea.PostageStampImage.Height : Height);
- Bitmap BMP = new Bitmap(BMP_Width, BMP_Height, PixFormat);
-
- #region ColorMap and GrayPalette
- if (Header.ColorMapType == TgaColorMapType.ColorMap &&
- (Header.ImageType == TgaImageType.RLE_ColorMapped ||
- Header.ImageType == TgaImageType.Uncompressed_ColorMapped))
- {
-
- ColorPalette ColorMap = BMP.Palette;
- Color[] CMapColors = ColorMap.Entries;
-
- switch (Header.ColorMapSpec.ColorMapEntrySize)
- {
- case TgaColorMapEntrySize.X1R5G5B5:
- case TgaColorMapEntrySize.A1R5G5B5:
- const float To8Bit = 255f / 31f; // Scale value from 5 to 8 bits.
- for (int i = 0; i < Math.Min(CMapColors.Length, Header.ColorMapSpec.ColorMapLength); i++)
- {
- ushort A1R5G5B5 = BitConverter.ToUInt16(ImageOrColorMapArea.ColorMapData, i * 2);
- int A = (UseAlpha ? (A1R5G5B5 & 0x8000) >> 15 : 1) * 255; // (0 or 1) * 255
- int R = (int)(((A1R5G5B5 & 0x7C00) >> 10) * To8Bit);
- int G = (int)(((A1R5G5B5 & 0x3E0) >> 5) * To8Bit);
- int B = (int)((A1R5G5B5 & 0x1F) * To8Bit);
- CMapColors[i] = Color.FromArgb(A, R, G, B);
- }
- break;
-
- case TgaColorMapEntrySize.R8G8B8:
- for (int i = 0; i < Math.Min(CMapColors.Length, Header.ColorMapSpec.ColorMapLength); i++)
- {
- int Index = i * 3; //RGB = 3 bytes
- int R = ImageOrColorMapArea.ColorMapData[Index + 2];
- int G = ImageOrColorMapArea.ColorMapData[Index + 1];
- int B = ImageOrColorMapArea.ColorMapData[Index];
- CMapColors[i] = Color.FromArgb(R, G, B);
- }
- break;
-
- case TgaColorMapEntrySize.A8R8G8B8:
- for (int i = 0; i < Math.Min(CMapColors.Length, Header.ColorMapSpec.ColorMapLength); i++)
- {
- int ARGB = BitConverter.ToInt32(ImageOrColorMapArea.ColorMapData, i * 4);
- CMapColors[i] = Color.FromArgb(UseAlpha ? ARGB | (0xFF << 24) : ARGB);
- }
- break;
-
- default:
- ColorMap = null;
- break;
- }
-
- if (ColorMap != null)
- BMP.Palette = ColorMap;
- }
-
- if (PixFormat == PixelFormat.Format8bppIndexed && IsGrayImage)
- {
- ColorPalette GrayPalette = BMP.Palette;
- Color[] GrayColors = GrayPalette.Entries;
- for (int i = 0; i < GrayColors.Length; i++)
- GrayColors[i] = Color.FromArgb(i, i, i);
- BMP.Palette = GrayPalette;
- }
- #endregion
-
- #region Bitmap width must by aligned (align value = 32 bits = 4 bytes)!
- byte[] ImageData;
- int BytesPerPixel = (int)Math.Ceiling((double)Header.ImageSpec.PixelDepth / 8.0);
- int StrideBytes = BMP.Width * BytesPerPixel;
- int PaddingBytes = (int)Math.Ceiling(StrideBytes / 4.0) * 4 - StrideBytes;
-
- if (PaddingBytes > 0) //Need bytes align
- {
- ImageData = new byte[(StrideBytes + PaddingBytes) * BMP.Height];
- for (int i = 0; i < BMP.Height; i++)
- Buffer.BlockCopy(PostageStampImage ? ExtArea.PostageStampImage.Data :
- ImageOrColorMapArea.ImageData, i * StrideBytes, ImageData,
- i * (StrideBytes + PaddingBytes), StrideBytes);
- }
- else
- ImageData = BitConverterExt.ToBytes(PostageStampImage ? ExtArea.PostageStampImage.Data :
- ImageOrColorMapArea.ImageData);
-
- // Not official supported, but works (tested on 2 test images)!
- if (PixFormat == PixelFormat.Format16bppGrayScale)
- {
- for (long i = 0; i < ImageData.Length; i++)
- ImageData[i] ^= byte.MaxValue;
- }
- #endregion
-
- Rectangle Re = new Rectangle(0, 0, BMP.Width, BMP.Height);
- BitmapData BmpData = BMP.LockBits(Re, ImageLockMode.WriteOnly, BMP.PixelFormat);
- Marshal.Copy(ImageData, 0, BmpData.Scan0, ImageData.Length);
- BMP.UnlockBits(BmpData);
- ImageData = null;
- BmpData = null;
-
- if (ExtArea != null && ExtArea.KeyColor.ToInt() != 0)
- BMP.MakeTransparent(ExtArea.KeyColor.ToColor());
-
- #region Flip Image
- switch (Header.ImageSpec.ImageDescriptor.ImageOrigin)
- {
- case TgaImgOrigin.BottomLeft:
- BMP.RotateFlip(RotateFlipType.RotateNoneFlipY);
- break;
- case TgaImgOrigin.BottomRight:
- BMP.RotateFlip(RotateFlipType.RotateNoneFlipXY);
- break;
- case TgaImgOrigin.TopLeft:
- default:
- break;
- case TgaImgOrigin.TopRight:
- BMP.RotateFlip(RotateFlipType.RotateNoneFlipX);
- break;
- }
- #endregion
-
- return BMP;
- }
- catch
- {
- return null;
- }
- }
- #endregion
-
- #region Explicit
- public static explicit operator Bitmap(TGA tga)
- {
- return tga.ToBitmap();
- }
-
- public static explicit operator TGA(Bitmap bmp)
- {
- return FromBitmap(bmp);
- }
- #endregion
-
- #region PostageStamp Image
- ///
- /// Convert to .
- ///
- /// Force use alpha channel.
- /// Bitmap or null.
- public Bitmap GetPostageStampImage(bool ForceUseAlpha = false)
- {
- if (ExtArea == null || ExtArea.PostageStampImage == null || ExtArea.PostageStampImage.Data == null ||
- ExtArea.PostageStampImage.Width <= 0 || ExtArea.PostageStampImage.Height <= 0)
- return null;
-
- return ToBitmapFunc(ForceUseAlpha, true);
- }
-
- ///
- /// Update Postage Stamp Image or set it.
- ///
- public void UpdatePostageStampImage()
- {
- if (Header.ImageType == TgaImageType.NoImageData)
- {
- if (ExtArea != null)
- ExtArea.PostageStampImage = null;
- return;
- }
-
- ToNewFormat();
- if (ExtArea.PostageStampImage == null)
- ExtArea.PostageStampImage = new TgaPostageStampImage();
-
- int PS_Width = Header.ImageSpec.ImageWidth;
- int PS_Height = Header.ImageSpec.ImageHeight;
-
- if (Width > 64 || Height > 64)
- {
- float AspectRatio = Width / (float)Height;
- PS_Width = (byte)(64f * (AspectRatio < 1f ? AspectRatio : 1f));
- PS_Height = (byte)(64f / (AspectRatio > 1f ? AspectRatio : 1f));
- }
- PS_Width = Math.Max(PS_Width, 4);
- PS_Height = Math.Max(PS_Height, 4);
-
- ExtArea.PostageStampImage.Width = (byte)PS_Width;
- ExtArea.PostageStampImage.Height = (byte)PS_Height;
-
- int BytesPerPixel = (int)Math.Ceiling((double)Header.ImageSpec.PixelDepth / 8.0);
- ExtArea.PostageStampImage.Data = new byte[PS_Width * PS_Height * BytesPerPixel];
-
- float WidthCoef = Width / (float)PS_Width;
- float HeightCoef = Height / (float)PS_Height;
-
- for (int y = 0; y < PS_Height; y++)
- {
- int Y_Offset = (int)(y * HeightCoef) * Width * BytesPerPixel;
- int y_Offset = y * PS_Width * BytesPerPixel;
-
- for (int x = 0; x < PS_Width; x++)
- {
- Buffer.BlockCopy(ImageOrColorMapArea.ImageData, Y_Offset + (int)(x * WidthCoef) * BytesPerPixel,
- ExtArea.PostageStampImage.Data, y_Offset + x * BytesPerPixel, BytesPerPixel);
- }
- }
- }
-
- public void DeletePostageStampImage()
- {
- if (ExtArea != null)
- ExtArea.PostageStampImage = null;
- }
- #endregion
- }
-}
diff --git a/AssetStudioUtility/Texture2DConverter.cs b/AssetStudioUtility/Texture2DConverter.cs
index b79a790..a9610ba 100644
--- a/AssetStudioUtility/Texture2DConverter.cs
+++ b/AssetStudioUtility/Texture2DConverter.cs
@@ -1,8 +1,5 @@
using System;
-using System.Drawing;
-using System.Drawing.Imaging;
using System.Linq;
-using System.Runtime.InteropServices;
using Texture2DDecoder;
namespace AssetStudio
@@ -28,26 +25,6 @@ namespace AssetStudio
platform = m_Texture2D.platform;
}
- public Bitmap ConvertToBitmap(bool flip)
- {
- if (image_data == null || image_data.Length == 0)
- return null;
- var buff = DecodeTexture2D();
- if (buff == null)
- {
- return null;
- }
- var bitmap = new Bitmap(m_Width, m_Height, PixelFormat.Format32bppArgb);
- var bmpData = bitmap.LockBits(new Rectangle(0, 0, m_Width, m_Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
- Marshal.Copy(buff, 0, bmpData.Scan0, buff.Length);
- bitmap.UnlockBits(bmpData);
- if (flip)
- {
- bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
- }
- return bitmap;
- }
-
public byte[] DecodeTexture2D()
{
byte[] bytes = null;
diff --git a/AssetStudioUtility/Texture2DExtensions.cs b/AssetStudioUtility/Texture2DExtensions.cs
index 132ca91..6301f1a 100644
--- a/AssetStudioUtility/Texture2DExtensions.cs
+++ b/AssetStudioUtility/Texture2DExtensions.cs
@@ -1,13 +1,39 @@
-using System.Drawing;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using System.IO;
namespace AssetStudio
{
public static class Texture2DExtensions
{
- public static Bitmap ConvertToBitmap(this Texture2D m_Texture2D, bool flip)
+ public static Image ConvertToImage(this Texture2D m_Texture2D, bool flip)
{
var converter = new Texture2DConverter(m_Texture2D);
- return converter.ConvertToBitmap(flip);
+ var bytes = converter.DecodeTexture2D();
+ if (bytes != null && bytes.Length > 0)
+ {
+ var image = Image.LoadPixelData(bytes, m_Texture2D.m_Width, m_Texture2D.m_Height);
+ if (flip)
+ {
+ image.Mutate(x => x.Flip(FlipMode.Vertical));
+ }
+ return image;
+ }
+ return null;
+ }
+
+ public static MemoryStream ConvertToStream(this Texture2D m_Texture2D, ImageFormat imageFormat, bool flip)
+ {
+ var image = ConvertToImage(m_Texture2D, flip);
+ if (image != null)
+ {
+ using (image)
+ {
+ return image.ConvertToStream(imageFormat);
+ }
+ }
+ return null;
}
}
}
diff --git a/AssetStudioUtility/app.config b/AssetStudioUtility/app.config
new file mode 100644
index 0000000..fbe4f92
--- /dev/null
+++ b/AssetStudioUtility/app.config
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AssetStudioUtility/packages.config b/AssetStudioUtility/packages.config
index 85c0c98..b3e8f50 100644
--- a/AssetStudioUtility/packages.config
+++ b/AssetStudioUtility/packages.config
@@ -1,4 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file