├── docu └── screenshot.png ├── App.config ├── Properties ├── Settings.settings ├── Settings.Designer.cs ├── AssemblyInfo.cs ├── Resources.Designer.cs └── Resources.resx ├── Program.cs ├── README.md ├── Irbis-Format.sln ├── LICENSE ├── DirectBitmap.cs ├── Form1.cs ├── Logging.cs ├── Irbis-Format.csproj ├── StreamReader.cs ├── Form1.resx ├── BufferReader.cs ├── Form1.Designer.cs ├── IrbImg.cs └── IrbFileReader.cs /docu/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomsoftware/Irbis-File-Format/HEAD/docu/screenshot.png -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace Irbis_Format 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// Der Haupteinstiegspunkt für die Anwendung. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new Form1()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Irbis-File-Format 2 | This Project demonstrates how to read the file format used by the software infratec IRBIS (*.irb) and there cameras to store 3 | thermographic Images. 4 | 5 | ![alt text](docu/screenshot.png) 6 | 7 | Magic File Number: 8 | 9 | ``` 10 | FF 49 52 42 00 49 52 42 41 43 53 IRB IRBACS 11 | ``` 12 | 13 | 14 | Disclaim: infratec and IRBIS are registered Trademarks. I do not have any connections to infratec and this is just a hobby project. 15 | 16 | ## Absolute temperatures 17 | Be very careful if you want to measure absolute temperatures! More details can be found in my master thesis 18 | https://www.hmilch.net/h/master.html 19 | or on wikipedia 20 | https://en.wikipedia.org/wiki/Emissivity 21 | 22 | # Java-Version 23 | You can find a JAVA-Port at https://github.com/jonathanschilling/irb 24 | -------------------------------------------------------------------------------- /Irbis-Format.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Irbis-Format", "Irbis-Format.csproj", "{DDCDC4FC-A642-4B09-9F17-34CEA935504C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {DDCDC4FC-A642-4B09-9F17-34CEA935504C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {DDCDC4FC-A642-4B09-9F17-34CEA935504C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {DDCDC4FC-A642-4B09-9F17-34CEA935504C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {DDCDC4FC-A642-4B09-9F17-34CEA935504C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Thomas Zeugner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Irbis_Format.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die einer Assembly zugeordnet sind. 8 | [assembly: AssemblyTitle("Irbis-Format")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Irbis-Format")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 18 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("ddcdc4fc-a642-4b09-9f17-34cea935504c")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 33 | // übernehmen, indem Sie "*" eingeben: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DirectBitmap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace Irbis_Format 7 | { 8 | public class DirectBitmap : IDisposable 9 | { 10 | public Bitmap Bitmap { get; private set; } 11 | public Int32[] Bits { get; private set; } 12 | public bool Disposed { get; private set; } 13 | public int Height { get; private set; } 14 | public int Width { get; private set; } 15 | 16 | protected GCHandle BitsHandle { get; private set; } 17 | 18 | public DirectBitmap(int width, int height) 19 | { 20 | Width = width; 21 | Height = height; 22 | Bits = new int[width * height]; 23 | BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); 24 | Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject()); 25 | } 26 | 27 | public void SetPixel(int x, int y, Color colour) 28 | { 29 | int index = x + (y * Width); 30 | int col = colour.ToArgb(); 31 | 32 | Bits[index] = col; 33 | } 34 | 35 | public Color GetPixel(int x, int y) 36 | { 37 | int index = x + (y * Width); 38 | int col = Bits[index]; 39 | Color result = Color.FromArgb(col); 40 | 41 | return result; 42 | } 43 | 44 | public void Dispose() 45 | { 46 | if (Disposed) return; 47 | Disposed = true; 48 | Bitmap.Dispose(); 49 | BitsHandle.Free(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Irbis_Format 12 | { 13 | public partial class Form1 : Form 14 | { 15 | private IrbImgFormat.IrbFileReader reader; 16 | private IrbImgFormat.IrbImg imgStream; 17 | private int frameIndex = 0; 18 | 19 | public Form1() 20 | { 21 | InitializeComponent(); 22 | } 23 | 24 | private void button1_Click(object sender, EventArgs e) 25 | { 26 | reader = new IrbImgFormat.IrbFileReader(txtFileName.Text); 27 | imgStream = new IrbImgFormat.IrbImg(reader); 28 | 29 | lblTextInfo.Text = reader.GetTextInfo(); 30 | 31 | labFrameCountNo.Text = reader.GetImageCount().ToString(); 32 | 33 | ShowNextFrame(); 34 | } 35 | 36 | private void ShowNextFrame() 37 | { 38 | lblFrameIndex.Text = frameIndex.ToString(); 39 | 40 | if (!imgStream.ReadImage(frameIndex)) 41 | { 42 | lblFrameIndex.Text = "eof"; 43 | return; 44 | } 45 | 46 | frameIndex++; 47 | 48 | var img = imgStream.GetData(); 49 | var w = imgStream.GetWidth(); 50 | var h = imgStream.GetHeight(); 51 | var dataSize = w * h; 52 | 53 | var maxValue = float.MinValue; 54 | var minValue = float.MaxValue; 55 | 56 | for (int i = 0; i < dataSize; i++) 57 | { 58 | maxValue = Math.Max(maxValue, img[i]); 59 | minValue = Math.Min(minValue, img[i]); 60 | } 61 | 62 | if (maxValue == minValue) 63 | { 64 | maxValue = minValue + 1; 65 | } 66 | 67 | lblMax.Text = maxValue.ToString(); 68 | lblMin.Text = minValue.ToString(); 69 | 70 | DirectBitmap bmp = new DirectBitmap(w, h); 71 | 72 | float scale = 255.0f / (maxValue - minValue); 73 | 74 | for (int i = 0; i < dataSize; i++) 75 | { 76 | var x = i % w; 77 | var y = i / w; 78 | var c = (int)((img[i] - minValue) * scale); 79 | 80 | bmp.SetPixel(x, y, Color.FromArgb(c, c, c)); 81 | } 82 | picResult.Image = bmp.Bitmap; 83 | } 84 | 85 | private void button2_Click(object sender, EventArgs e) 86 | { 87 | ShowNextFrame(); 88 | } 89 | 90 | private void Form1_Load(object sender, EventArgs e) 91 | { 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Logging.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IrbImgFormat 4 | { 5 | public class Logging 6 | { 7 | private string m_className; 8 | 9 | //- main error handler 10 | private static Logging s_mainError; 11 | 12 | 13 | //-------------------------------------------------------// 14 | public enum enumErrorType 15 | { 16 | enumErrorType_error, 17 | enumErrorType_warning, 18 | enumErrorType_info 19 | } 20 | 21 | 22 | //-------------------------------------------------------// 23 | public Logging(string classStr = "") 24 | { 25 | m_className = classStr; 26 | } 27 | 28 | //-------------------------------------------------------// 29 | public bool addError(string errorStr, string info1 = null, string info2 = null, string info3 = null) 30 | { 31 | getMainInstance().addMSG(errorStr, enumErrorType.enumErrorType_error, m_className, info1, info2, info3); 32 | return false; 33 | } 34 | 35 | //-------------------------------------------------------// 36 | public bool addInfo(string errorStr, string info1 = null, string info2 = null, string info3 = null) 37 | { 38 | getMainInstance().addMSG(errorStr, enumErrorType.enumErrorType_info, m_className, info1, info2, info3); 39 | return false; 40 | } 41 | 42 | //-------------------------------------------------------// 43 | public bool addWarning(string errorStr, string info1 = null, string info2 = null, string info3 = null) 44 | { 45 | getMainInstance().addMSG(errorStr, enumErrorType.enumErrorType_warning, m_className, info1, info2, info3); 46 | return false; 47 | } 48 | 49 | //-------------------------------------------------------// 50 | public static void addAnonymousError(string errorStr, string className = "", string info1 = null, string info2 = null, string info3 = null) 51 | { 52 | getMainInstance().addMSG(errorStr, enumErrorType.enumErrorType_error, className, info1, info2, info3); 53 | } 54 | 55 | //-------------------------------------------------------// 56 | protected static Logging getMainInstance() 57 | { 58 | if (s_mainError == null) s_mainError = new Logging(""); 59 | 60 | return s_mainError; 61 | } 62 | 63 | 64 | 65 | 66 | //-------------------------------------------------------// 67 | protected void addMSG(string errorStr, enumErrorType ErrorType, string classStr, string errorStr2 = null, string errorStr3 = null, string errorStr4 = null) 68 | { 69 | System.Diagnostics.Debug.WriteLine(classStr + " " + errorStr + " " + errorStr2); 70 | 71 | System.DateTime ErrorTimeStamp = System.DateTime.Now; 72 | 73 | System.Console.WriteLine(ErrorType + "/t" + ErrorTimeStamp + "/t" + errorStr + "/t" + classStr + "/t" + errorStr2 + "/t" + errorStr3 + "/t" + errorStr4); 74 | 75 | } 76 | 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Dieser Code wurde von einem Tool generiert. 4 | // Laufzeitversion: 4.0.30319.42000 5 | // 6 | // Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn 7 | // der Code neu generiert wird. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Irbis_Format.Properties 12 | { 13 | 14 | 15 | /// 16 | /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. 17 | /// 18 | // Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse 19 | // über ein Tool wie ResGen oder Visual Studio automatisch generiert. 20 | // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen 21 | // mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Irbis_Format.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle 56 | /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Irbis-Format.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DDCDC4FC-A642-4B09-9F17-34CEA935504C} 8 | WinExe 9 | Properties 10 | Irbis_Format 11 | Irbis-Format 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Form 56 | 57 | 58 | Form1.cs 59 | 60 | 61 | 62 | 63 | 64 | Form1.cs 65 | 66 | 67 | ResXFileCodeGenerator 68 | Resources.Designer.cs 69 | Designer 70 | 71 | 72 | True 73 | Resources.resx 74 | 75 | 76 | SettingsSingleFileGenerator 77 | Settings.Designer.cs 78 | 79 | 80 | True 81 | Settings.settings 82 | True 83 | 84 | 85 | 86 | 87 | 88 | 89 | 96 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /StreamReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | 5 | namespace IrbImgFormat 6 | { 7 | class StreamReader 8 | { 9 | private static Logging logging = new Logging("StreamReader"); 10 | private BinaryReader m_reader; 11 | private bool m_eof; 12 | 13 | private int m_offset; 14 | private int m_blocklen; 15 | private string filename; 16 | 17 | public StreamReader(string filename) 18 | { 19 | this.m_eof = true; 20 | this.m_offset = 0; 21 | 22 | Open(filename); 23 | } 24 | 25 | /// 26 | /// return the filename of the stream 27 | /// 28 | /// 29 | public string GetFileName() 30 | { 31 | try 32 | { 33 | return System.IO.Path.GetFileName(filename); 34 | } 35 | catch (Exception) 36 | { 37 | return string.Empty; 38 | } 39 | 40 | } 41 | 42 | 43 | /// 44 | /// Open the stream 45 | /// 46 | /// 47 | private void Open(string filename) 48 | { 49 | this.filename = filename; 50 | 51 | //- Datei öffnen 52 | try 53 | { 54 | m_reader = new System.IO.BinaryReader(System.IO.File.Open(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)); 55 | 56 | this.m_eof = false; 57 | m_blocklen = (int)m_reader.BaseStream.Length; //- Beschränkung auf max 2GB Dateigröße 58 | } 59 | catch (System.Exception ex) 60 | { 61 | logging.addError("IO.BinaryReader fail", ex.Message, filename); 62 | return; 63 | } 64 | 65 | } 66 | 67 | 68 | /// 69 | /// Close the stream 70 | /// 71 | public void Close() 72 | { 73 | if (m_reader != null) m_reader.Close(); 74 | } 75 | 76 | 77 | /// 78 | /// is the stream pointer at the end of the file? 79 | /// 80 | public bool Eof 81 | { 82 | get 83 | { 84 | return ((m_reader == null) || (m_eof)); 85 | } 86 | } 87 | 88 | /// 89 | /// Sets the stream read position 90 | /// 91 | /// 92 | public void SetOffset(int offset) 93 | { 94 | if ((offset < m_blocklen) && (offset >= 0)) 95 | { 96 | m_offset = offset; 97 | m_reader.BaseStream.Seek(m_offset, System.IO.SeekOrigin.Begin); 98 | m_eof = false; 99 | } 100 | else 101 | { 102 | m_eof = true; 103 | if (offset < 0) m_offset = 0; 104 | if (offset >= m_blocklen) m_offset = m_blocklen; 105 | m_reader.BaseStream.Seek(m_offset, System.IO.SeekOrigin.Begin); 106 | } 107 | } 108 | 109 | 110 | /// 111 | /// Read length bytes from the stream 112 | /// 113 | public byte[] ReadByte(int length, int offset) 114 | { 115 | if (length < 0) length = 0; 116 | if (offset > -1) 117 | { 118 | m_reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin); 119 | m_offset = offset; 120 | } 121 | 122 | byte[] dataArray = null; 123 | 124 | 125 | if (m_offset < m_blocklen) 126 | { 127 | if ((m_offset + length) > m_blocklen) 128 | { 129 | m_eof = true; 130 | length = m_blocklen - m_offset; 131 | } 132 | 133 | dataArray = new byte[length]; 134 | 135 | 136 | try 137 | { 138 | length = m_reader.Read(dataArray, 0, length); 139 | } 140 | catch (Exception e) 141 | { 142 | logging.addError("readByte(): length: " + length + " / offset: " + offset + " - " + e.Message); 143 | length = 0; 144 | m_eof = true; 145 | } 146 | 147 | if (length != dataArray.Length) System.Array.Resize(ref dataArray, length); 148 | } 149 | else 150 | { 151 | if (length > 0) 152 | { 153 | logging.addWarning("ReadStr:EOF!"); 154 | length = 0; 155 | } 156 | 157 | m_eof = true; 158 | } 159 | 160 | 161 | if (length > 0) m_offset = m_offset + length; 162 | 163 | return dataArray; 164 | } 165 | 166 | 167 | /// 168 | /// Read a string from the stream 169 | /// 170 | public string ReadStr(int length, int offset = -1) 171 | { 172 | string outVal = ""; 173 | 174 | byte[] tmpData = this.ReadByte(length, offset); 175 | 176 | if (tmpData != null) 177 | { 178 | outVal = System.Text.Encoding.Default.GetString(tmpData); 179 | } 180 | 181 | return outVal; 182 | } 183 | 184 | 185 | 186 | /// 187 | /// Read big ending int from the stream 188 | /// 189 | public int ReadIntBE(int offset = -1) 190 | { 191 | byte[] tmpData = this.ReadByte(4, offset); 192 | 193 | if ((tmpData == null) || (tmpData.Length != 4)) 194 | { 195 | return 0; 196 | } 197 | 198 | return (int)(tmpData[0] | (tmpData[1] << 8) | (tmpData[2] << 16) | (tmpData[3] << 24)); 199 | 200 | } 201 | 202 | 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /BufferReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace IrbImgFormat 5 | { 6 | class BufferReader 7 | { 8 | private static Logging logging = new Logging("BufferReader"); 9 | 10 | /// 11 | /// Union to cast a 4-byte int to a float 12 | /// 13 | [StructLayout(LayoutKind.Explicit)] 14 | private struct BinaryConvertIntToFloat 15 | { 16 | [FieldOffset(0)] 17 | public float toFloat; 18 | [FieldOffset(0)] 19 | public int toInt; 20 | } 21 | 22 | 23 | 24 | /// 25 | /// Union to cast a 8 byte long into a double 26 | /// 27 | [StructLayout(LayoutKind.Explicit)] 28 | private struct BinaryConvertLongToDouble 29 | { 30 | [FieldOffset(0)] 31 | public double toDouble; 32 | [FieldOffset(0)] 33 | public long toLong; 34 | } 35 | 36 | 37 | byte[] data; 38 | int offset = 0; 39 | int dataLength = 0; 40 | 41 | public BufferReader(byte[] data) 42 | { 43 | this.data = data; 44 | dataLength = (data != null) ? data.Length : 0; 45 | } 46 | 47 | /// 48 | /// is the buffer Pointer at the end of the buffer 49 | /// 50 | public bool Eof 51 | { 52 | get 53 | { 54 | return ((offset < 0) || (offset >= dataLength) || (data == null)); 55 | } 56 | } 57 | 58 | /// 59 | /// Return the lenght of the buffer 60 | /// 61 | public int Length 62 | { 63 | get 64 | { 65 | return data.Length; 66 | } 67 | } 68 | 69 | /// 70 | /// Read a string from the the buffer 71 | /// 72 | public string ReadStr(int length, int offset) 73 | { 74 | if (length < 0) length = 0; 75 | if (offset > -1) this.offset = offset; 76 | 77 | string outVal = ""; 78 | 79 | 80 | if (this.offset < dataLength) 81 | { 82 | if ((this.offset + length) > dataLength) 83 | { 84 | length = dataLength - this.offset; 85 | } 86 | 87 | outVal = System.Text.Encoding.Default.GetString(data, this.offset, length); 88 | } 89 | else 90 | { 91 | if (length > 0) 92 | { 93 | logging.addWarning("ReadStr:EOF!"); 94 | length = 0; 95 | } 96 | } 97 | 98 | 99 | if (length > 0) this.offset = this.offset + length; 100 | 101 | return outVal; 102 | } 103 | 104 | 105 | /// 106 | /// read a NULL terminated string from buffer 107 | /// 108 | public string ReadNullTerminatedString(int offset, int size) 109 | { 110 | string s = this.ReadStr(size, offset); 111 | 112 | int pos = s.IndexOf('\0'); 113 | 114 | if (pos > 0) 115 | { 116 | return s.Substring(0, pos); 117 | } 118 | return s; 119 | } 120 | 121 | 122 | /// 123 | /// Read 8 byte big ending long from buffer 124 | /// 125 | public long ReadLongBE(int offset = -1) 126 | { 127 | if (offset > -1) this.offset = offset; 128 | 129 | if (this.offset < dataLength) 130 | { 131 | if ((this.offset + 8) > dataLength) 132 | { 133 | this.offset = dataLength; 134 | return 0; 135 | } 136 | 137 | 138 | byte[] d = data; 139 | int i = this.offset; 140 | 141 | byte[] bytes = { d[i + 0], d[i + 1], d[i + 2], d[i + 3], d[i + 4], d[i + 5], d[i + 6], d[i + 7] }; 142 | 143 | return BitConverter.ToInt64(bytes, 0); 144 | } 145 | return 0; 146 | 147 | 148 | } 149 | 150 | /// 151 | /// Read one byte from buffer 152 | /// 153 | public int ReadByte(int offset = -1) 154 | { 155 | if (offset > -1) this.offset = offset; 156 | 157 | if (this.offset >= dataLength) 158 | { 159 | return 0; 160 | } 161 | 162 | if ((this.offset + 1) > dataLength) 163 | { 164 | this.offset = dataLength; 165 | return 0; 166 | } 167 | 168 | 169 | var result = data[this.offset]; 170 | this.offset++; 171 | return result; 172 | 173 | 174 | } 175 | 176 | 177 | /// 178 | /// Read big ending word (2 Bytes) from buffer 179 | /// 180 | /// 181 | /// 182 | public int ReadWordBE(int offset = -1) 183 | { 184 | if (offset > -1) 185 | { 186 | this.offset = offset; 187 | } 188 | 189 | 190 | if (this.offset >= dataLength) 191 | { 192 | return 0; 193 | } 194 | 195 | if ((this.offset + 2) > dataLength) 196 | { 197 | this.offset = dataLength; 198 | return 0; 199 | } 200 | 201 | 202 | var result = (int)data[this.offset] + (data[this.offset + 1] << 8); 203 | 204 | this.offset += 2; 205 | return result; 206 | 207 | 208 | } 209 | 210 | 211 | 212 | /// 213 | /// Read big-ending int from buffer 214 | /// 215 | public int ReadIntBE(int offset = -1) 216 | { 217 | if (offset > -1) 218 | { 219 | this.offset = offset; 220 | } 221 | 222 | 223 | if (this.offset >= dataLength) 224 | { 225 | return 0; 226 | } 227 | 228 | if ((this.offset + 4) > dataLength) 229 | { 230 | this.offset = dataLength; 231 | return 0; 232 | } 233 | 234 | 235 | var result = (int)data[this.offset] + (data[this.offset + 1] << 8) + (data[this.offset + 2] << 16) + (data[this.offset + 3] << 24); 236 | 237 | this.offset += 4; 238 | return result; 239 | } 240 | 241 | 242 | /// 243 | /// read double from buffer 244 | /// 245 | public double ReadDoubleBE(int length = 8, int offset = -1) 246 | { 247 | BinaryConvertLongToDouble converterLongDouble; 248 | converterLongDouble.toDouble = 0.0; /// need to be set to avoid compiler errors 249 | 250 | converterLongDouble.toLong = ReadLongBE(offset); 251 | return converterLongDouble.toDouble; 252 | } 253 | 254 | 255 | /// 256 | /// read float from buffer 257 | /// 258 | public float ReadSingleBE(int offset = -1) 259 | { 260 | BinaryConvertIntToFloat converterIntFloat; 261 | converterIntFloat.toFloat = 0.0f; /// need to be set to avoid compiler errors 262 | 263 | converterIntFloat.toInt = ReadIntBE(offset); 264 | return converterIntFloat.toFloat; 265 | } 266 | 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Irbis_Format 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Erforderliche Designervariable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Verwendete Ressourcen bereinigen. 12 | /// 13 | /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Vom Windows Form-Designer generierter Code 24 | 25 | /// 26 | /// Erforderliche Methode für die Designerunterstützung. 27 | /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.button1 = new System.Windows.Forms.Button(); 32 | this.txtFileName = new System.Windows.Forms.TextBox(); 33 | this.labFrameCount = new System.Windows.Forms.Label(); 34 | this.labFrameCountNo = new System.Windows.Forms.Label(); 35 | this.button2 = new System.Windows.Forms.Button(); 36 | this.picResult = new System.Windows.Forms.PictureBox(); 37 | this.lblMax = new System.Windows.Forms.Label(); 38 | this.label2 = new System.Windows.Forms.Label(); 39 | this.lblMin = new System.Windows.Forms.Label(); 40 | this.label4 = new System.Windows.Forms.Label(); 41 | this.lblTextInfo = new System.Windows.Forms.Label(); 42 | this.label1 = new System.Windows.Forms.Label(); 43 | this.lblFrameIndex = new System.Windows.Forms.Label(); 44 | this.label5 = new System.Windows.Forms.Label(); 45 | this.label3 = new System.Windows.Forms.Label(); 46 | ((System.ComponentModel.ISupportInitialize)(this.picResult)).BeginInit(); 47 | this.SuspendLayout(); 48 | // 49 | // button1 50 | // 51 | this.button1.Location = new System.Drawing.Point(625, 11); 52 | this.button1.Name = "button1"; 53 | this.button1.Size = new System.Drawing.Size(70, 45); 54 | this.button1.TabIndex = 0; 55 | this.button1.Text = "load"; 56 | this.button1.UseVisualStyleBackColor = true; 57 | this.button1.Click += new System.EventHandler(this.button1_Click); 58 | // 59 | // txtFileName 60 | // 61 | this.txtFileName.Location = new System.Drawing.Point(12, 25); 62 | this.txtFileName.Name = "txtFileName"; 63 | this.txtFileName.Size = new System.Drawing.Size(409, 20); 64 | this.txtFileName.TabIndex = 1; 65 | this.txtFileName.Text = "C:\\Irbis-Format\\start.irb"; 66 | // 67 | // labFrameCount 68 | // 69 | this.labFrameCount.AutoSize = true; 70 | this.labFrameCount.Location = new System.Drawing.Point(506, 66); 71 | this.labFrameCount.Name = "labFrameCount"; 72 | this.labFrameCount.Size = new System.Drawing.Size(69, 13); 73 | this.labFrameCount.TabIndex = 2; 74 | this.labFrameCount.Text = "Frame count:"; 75 | // 76 | // labFrameCountNo 77 | // 78 | this.labFrameCountNo.AutoSize = true; 79 | this.labFrameCountNo.Location = new System.Drawing.Point(524, 79); 80 | this.labFrameCountNo.Name = "labFrameCountNo"; 81 | this.labFrameCountNo.Size = new System.Drawing.Size(10, 13); 82 | this.labFrameCountNo.TabIndex = 3; 83 | this.labFrameCountNo.Text = "-"; 84 | // 85 | // button2 86 | // 87 | this.button2.Location = new System.Drawing.Point(625, 62); 88 | this.button2.Name = "button2"; 89 | this.button2.Size = new System.Drawing.Size(70, 45); 90 | this.button2.TabIndex = 4; 91 | this.button2.Text = "next frame"; 92 | this.button2.UseVisualStyleBackColor = true; 93 | this.button2.Click += new System.EventHandler(this.button2_Click); 94 | // 95 | // picResult 96 | // 97 | this.picResult.Location = new System.Drawing.Point(127, 53); 98 | this.picResult.Name = "picResult"; 99 | this.picResult.Size = new System.Drawing.Size(364, 271); 100 | this.picResult.TabIndex = 5; 101 | this.picResult.TabStop = false; 102 | // 103 | // lblMax 104 | // 105 | this.lblMax.AutoSize = true; 106 | this.lblMax.Location = new System.Drawing.Point(524, 158); 107 | this.lblMax.Name = "lblMax"; 108 | this.lblMax.Size = new System.Drawing.Size(10, 13); 109 | this.lblMax.TabIndex = 7; 110 | this.lblMax.Text = "-"; 111 | // 112 | // label2 113 | // 114 | this.label2.AutoSize = true; 115 | this.label2.Location = new System.Drawing.Point(506, 144); 116 | this.label2.Name = "label2"; 117 | this.label2.Size = new System.Drawing.Size(58, 13); 118 | this.label2.TabIndex = 6; 119 | this.label2.Text = "max-value:"; 120 | // 121 | // lblMin 122 | // 123 | this.lblMin.AutoSize = true; 124 | this.lblMin.Location = new System.Drawing.Point(524, 197); 125 | this.lblMin.Name = "lblMin"; 126 | this.lblMin.Size = new System.Drawing.Size(10, 13); 127 | this.lblMin.TabIndex = 9; 128 | this.lblMin.Text = "-"; 129 | // 130 | // label4 131 | // 132 | this.label4.AutoSize = true; 133 | this.label4.Location = new System.Drawing.Point(506, 184); 134 | this.label4.Name = "label4"; 135 | this.label4.Size = new System.Drawing.Size(55, 13); 136 | this.label4.TabIndex = 8; 137 | this.label4.Text = "min-value:"; 138 | // 139 | // lblTextInfo 140 | // 141 | this.lblTextInfo.AutoSize = true; 142 | this.lblTextInfo.Location = new System.Drawing.Point(12, 66); 143 | this.lblTextInfo.Name = "lblTextInfo"; 144 | this.lblTextInfo.Size = new System.Drawing.Size(10, 13); 145 | this.lblTextInfo.TabIndex = 10; 146 | this.lblTextInfo.Text = "-"; 147 | // 148 | // label1 149 | // 150 | this.label1.AutoSize = true; 151 | this.label1.Location = new System.Drawing.Point(0, 53); 152 | this.label1.Name = "label1"; 153 | this.label1.Size = new System.Drawing.Size(31, 13); 154 | this.label1.TabIndex = 11; 155 | this.label1.Text = "Text:"; 156 | // 157 | // lblFrameIndex 158 | // 159 | this.lblFrameIndex.AutoSize = true; 160 | this.lblFrameIndex.Location = new System.Drawing.Point(524, 119); 161 | this.lblFrameIndex.Name = "lblFrameIndex"; 162 | this.lblFrameIndex.Size = new System.Drawing.Size(10, 13); 163 | this.lblFrameIndex.TabIndex = 13; 164 | this.lblFrameIndex.Text = "-"; 165 | // 166 | // label5 167 | // 168 | this.label5.AutoSize = true; 169 | this.label5.Location = new System.Drawing.Point(506, 105); 170 | this.label5.Name = "label5"; 171 | this.label5.Size = new System.Drawing.Size(67, 13); 172 | this.label5.TabIndex = 12; 173 | this.label5.Text = "Frame-index:"; 174 | // 175 | // label3 176 | // 177 | this.label3.AutoSize = true; 178 | this.label3.Location = new System.Drawing.Point(0, 9); 179 | this.label3.Name = "label3"; 180 | this.label3.Size = new System.Drawing.Size(41, 13); 181 | this.label3.TabIndex = 14; 182 | this.label3.Text = "Source"; 183 | // 184 | // Form1 185 | // 186 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 187 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 188 | this.ClientSize = new System.Drawing.Size(707, 414); 189 | this.Controls.Add(this.label3); 190 | this.Controls.Add(this.lblFrameIndex); 191 | this.Controls.Add(this.label5); 192 | this.Controls.Add(this.label1); 193 | this.Controls.Add(this.lblTextInfo); 194 | this.Controls.Add(this.lblMin); 195 | this.Controls.Add(this.label4); 196 | this.Controls.Add(this.lblMax); 197 | this.Controls.Add(this.label2); 198 | this.Controls.Add(this.picResult); 199 | this.Controls.Add(this.button2); 200 | this.Controls.Add(this.labFrameCountNo); 201 | this.Controls.Add(this.labFrameCount); 202 | this.Controls.Add(this.txtFileName); 203 | this.Controls.Add(this.button1); 204 | this.Name = "Form1"; 205 | this.Text = "IRBIS File Format"; 206 | this.Load += new System.EventHandler(this.Form1_Load); 207 | ((System.ComponentModel.ISupportInitialize)(this.picResult)).EndInit(); 208 | this.ResumeLayout(false); 209 | this.PerformLayout(); 210 | 211 | } 212 | 213 | #endregion 214 | 215 | private System.Windows.Forms.Button button1; 216 | private System.Windows.Forms.TextBox txtFileName; 217 | private System.Windows.Forms.Label labFrameCount; 218 | private System.Windows.Forms.Label labFrameCountNo; 219 | private System.Windows.Forms.Button button2; 220 | private System.Windows.Forms.PictureBox picResult; 221 | private System.Windows.Forms.Label lblMax; 222 | private System.Windows.Forms.Label label2; 223 | private System.Windows.Forms.Label lblMin; 224 | private System.Windows.Forms.Label label4; 225 | private System.Windows.Forms.Label lblTextInfo; 226 | private System.Windows.Forms.Label label1; 227 | private System.Windows.Forms.Label lblFrameIndex; 228 | private System.Windows.Forms.Label label5; 229 | private System.Windows.Forms.Label label3; 230 | } 231 | } 232 | 233 | -------------------------------------------------------------------------------- /IrbImg.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | 4 | 5 | namespace IrbImgFormat 6 | { 7 | class IrbImg 8 | { 9 | private static Logging logging = new Logging("IrbImg"); 10 | 11 | 12 | public double ShotRangeMin { get; protected set; } 13 | public double ShotRangeMax { get; protected set; } 14 | public double CalibRangeMin { get; protected set; } 15 | public double CalibRangeMax { get; protected set; } 16 | 17 | 18 | IrbFileReader reader; 19 | 20 | int BytePerPixel; 21 | int Compressed; 22 | 23 | float Emissivity; 24 | 25 | float EnvironmentalTemp; 26 | float Distanz; 27 | 28 | float PathTemperature; 29 | float CenterWavelength; 30 | 31 | float CalibRange_min; 32 | float CalibRange_max; 33 | 34 | float ShotRange_start_ERROR; 35 | float ShotRange_size; 36 | 37 | double TimeStamp_Raw; 38 | DateTime TimeStamp; 39 | DateTime TimeStampOffsetTime; 40 | 41 | int TimeStampOffsetMilliseconds; 42 | int TimeStampMilliseconds; 43 | 44 | string Device; 45 | string DeviceSerial; 46 | string Optics; 47 | string OpticsResolution; 48 | string OpticsText; 49 | 50 | public float[] Data; 51 | 52 | 53 | private int Width; 54 | private int Height; 55 | 56 | 57 | 58 | public IrbImg(IrbFileReader FileReader, int imageIndex = 0) 59 | { 60 | reader = FileReader; 61 | ReadImage(imageIndex); 62 | } 63 | 64 | 65 | /// 66 | /// Width of the image 67 | /// 68 | /// 69 | public int GetWidth() 70 | { 71 | return Width; 72 | } 73 | 74 | /// 75 | /// Height of the image 76 | /// 77 | public int GetHeight() 78 | { 79 | return Height; 80 | } 81 | 82 | /// 83 | /// Return the data of the image as float array 84 | /// 85 | /// 86 | public float[] GetData() 87 | { 88 | if (Data == null) logging.addError("getData() Accessing non initialised data!"); 89 | return Data; 90 | } 91 | 92 | 93 | /// 94 | /// Read a image from the file 95 | /// 96 | public bool ReadImage(int imageIndex) 97 | { 98 | System.DateTime FrameTime = System.DateTime.Now; 99 | 100 | 101 | var reader = new BufferReader(this.reader.GetImageData(imageIndex)); 102 | 103 | if (reader.Eof) 104 | { 105 | return false; 106 | } 107 | 108 | Width = 0; 109 | Height = 0; 110 | 111 | 112 | //- Image header 113 | BytePerPixel = reader.ReadWordBE(); 114 | Compressed = reader.ReadWordBE(); 115 | Width = reader.ReadWordBE(); 116 | Height = reader.ReadWordBE(); 117 | 118 | 119 | reader.ReadIntBE(); //-- don't know - alway 0 120 | reader.ReadWordBE(); //-- don't know - alway 0 121 | 122 | //- dont know why but it is alwasy the width -1 123 | if (reader.ReadWordBE() != (Width - 1)) 124 | { 125 | logging.addError("??? value != (Height - 1)"); 126 | } 127 | 128 | 129 | reader.ReadWordBE(); //-- don't know - alway 0 130 | 131 | //- dont know why but it is alwasy the height -1 132 | if (reader.ReadWordBE() != (Height - 1)) 133 | { 134 | logging.addError("??? value != (Height - 1)"); 135 | } 136 | 137 | 138 | reader.ReadWordBE(); //-- don't know - alway 0 139 | reader.ReadWordBE(); //-- don't know - alway 0 140 | 141 | Emissivity = reader.ReadSingleBE(); 142 | 143 | Distanz = reader.ReadSingleBE(); 144 | 145 | EnvironmentalTemp = reader.ReadSingleBE(); 146 | 147 | 148 | reader.ReadWordBE(); //-- don't know - always 0 149 | reader.ReadWordBE(); //-- don't know - always 0 150 | 151 | PathTemperature = reader.ReadSingleBE(); 152 | 153 | reader.ReadWordBE(); //-- don't know - always 0x65 154 | reader.ReadWordBE(); //-- don't know - always 0 155 | 156 | 157 | CenterWavelength = reader.ReadSingleBE(); 158 | 159 | 160 | reader.ReadWordBE(); //-- don't know - always 0 161 | reader.ReadWordBE(); //-- don't know - always 0xH4080 162 | reader.ReadWordBE(); //-- don't know - always 0x9 163 | reader.ReadWordBE(); //-- don't know - always 0x101 164 | 165 | 166 | if ((Width > 10000) || (Height > 10000)) 167 | { 168 | logging.addError("Defect Irbis Image File: Image Width(" + Width + ") or Height(" + Height + ") is out of range!"); 169 | Width = 1; 170 | Height = 1; 171 | return false; 172 | } 173 | 174 | //- liest weitere Bildinforationen aus 175 | this.ReadFlags(reader, 1084); 176 | 177 | Data = ReadImageData(reader, 0x6C0, Width, Height, 60, Compressed); 178 | 179 | 180 | 181 | if (reader.Eof) logging.addError("end of file!"); 182 | 183 | return true; 184 | } 185 | 186 | 187 | /// 188 | /// Read image flags from the file 189 | /// 190 | public void ReadFlags(BufferReader reader, int offset) 191 | { 192 | CalibRange_min = reader.ReadSingleBE(offset + 92); 193 | CalibRange_max = reader.ReadSingleBE(offset + 96); 194 | 195 | 196 | Device = reader.ReadNullTerminatedString(offset + 142, 12); 197 | DeviceSerial = reader.ReadNullTerminatedString(offset + 186, 16); 198 | Optics = reader.ReadNullTerminatedString(offset + 202, 32); 199 | OpticsResolution = reader.ReadNullTerminatedString(offset + 234, 32); 200 | OpticsText = reader.ReadNullTerminatedString(offset + 554, 48); 201 | 202 | ShotRange_start_ERROR = reader.ReadSingleBE(offset + 532); 203 | ShotRange_size = reader.ReadSingleBE(offset + 536); 204 | 205 | 206 | TimeStamp_Raw = reader.ReadDoubleBE(8, offset + 540); 207 | TimeStampMilliseconds = reader.ReadIntBE(offset + 548); 208 | 209 | TimeStamp = Double2DateTime(TimeStamp_Raw, TimeStampMilliseconds); 210 | } 211 | 212 | 213 | 214 | 215 | /// 216 | /// Read the compressing "pallet" from file 217 | /// 218 | private float[] ReadPallet(BufferReader reader, int offset) 219 | { 220 | float[] palette = new float[256]; 221 | 222 | int pos = offset; 223 | 224 | for (int i = 0; i < 256; i++) 225 | { 226 | palette[i] = reader.ReadSingleBE(pos); 227 | pos += 4; 228 | } 229 | 230 | return palette; 231 | } 232 | 233 | 234 | 235 | /// 236 | /// Read the image data from file 237 | /// 238 | /// 239 | private float[] ReadImageData(BufferReader reader, int bindata_offset, int width, int height, int palette_offset, int useCompression) 240 | { 241 | int data_size = width * height; //- count of pixles 242 | bool useComp = (useCompression == 1); 243 | 244 | int pixelCount = data_size; 245 | float[] matrixData = new float[pixelCount]; 246 | 247 | int matrixDataPos = 0; 248 | 249 | int v1_pos = bindata_offset; 250 | int v2_pos = v1_pos + width * height; //- used if data are compressed 251 | 252 | //byte data_v1 = &bindata[v1_pos]; 253 | //unsigned char* data_v2 = &bindata[v2_pos]; 254 | 255 | int v1 = 0; 256 | int v2 = 0; 257 | 258 | 259 | float[] Palette = ReadPallet(reader, palette_offset); 260 | 261 | 262 | int v2_count = 0; 263 | float v = 0; 264 | float f; 265 | 266 | 267 | if (!useComp) 268 | { 269 | for (int i = pixelCount; i > 0; i--) 270 | { 271 | //- read values 272 | v1 = reader.ReadByte(v1_pos); 273 | v1_pos++; 274 | v2 = reader.ReadByte(v1_pos); 275 | v1_pos++; 276 | 277 | f = (float)v1 * (1.0f / 256.0f); 278 | 279 | //- lineare interpolation 280 | v = Palette[v2 + 1] * f + Palette[v2] * (1.0f - f); 281 | 282 | if (v < 0) v = 0; //- oder 255 283 | 284 | matrixData[matrixDataPos] = v; 285 | matrixDataPos++; 286 | } 287 | } 288 | else 289 | { 290 | for (int i = pixelCount; i > 0; i--) 291 | { 292 | //- werte lesen 293 | if (v2_count-- < 1) //- ok... neuen wert für V2 lesen 294 | { 295 | v2_count = reader.ReadByte(v2_pos) - 1; 296 | v2_pos++; 297 | 298 | v2 = reader.ReadByte(v2_pos); 299 | v2_pos++; 300 | } 301 | 302 | v1 = reader.ReadByte(v1_pos); 303 | v1_pos++; 304 | 305 | f = (float)v1 * (1.0f / 256.0f); 306 | 307 | //- lineare interpolation 308 | v = Palette[v2 + 1] * f + Palette[v2] * (1.0f - f); 309 | 310 | if (v < 0) v = 0; //- oder 255 311 | 312 | matrixData[matrixDataPos] = v; 313 | matrixDataPos++; 314 | } 315 | } 316 | 317 | return matrixData; 318 | 319 | } 320 | 321 | 322 | /// 323 | /// convert a double value to a date time 324 | /// 325 | private System.DateTime Double2DateTime(double date, int Milliseconds = 0) 326 | { 327 | System.DateTime d = DateTime.FromOADate(date); 328 | 329 | //- calc the time from the Date + Milliseconds 330 | if ((TimeStampOffsetTime != DateTime.MinValue) && (Milliseconds > 0) && (Milliseconds > TimeStampOffsetMilliseconds) && (d >= TimeStampOffsetTime)) 331 | { 332 | return TimeStampOffsetTime.AddMilliseconds(Milliseconds - TimeStampOffsetMilliseconds); 333 | } 334 | else 335 | { 336 | //- never set so save start-date/time 337 | TimeStampOffsetMilliseconds = Milliseconds; 338 | TimeStampOffsetTime = d; 339 | return d; 340 | } 341 | 342 | } 343 | 344 | 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /IrbFileReader.cs: -------------------------------------------------------------------------------- 1 | namespace IrbImgFormat 2 | { 3 | class IrbFileReader 4 | { 5 | public enum enumBlockType 6 | { 7 | enumBlockTypeUnknown = -1, 8 | enumBlockTypeEmpty = 0, 9 | enumBlockTypeImage = 1, 10 | enumBlockTypePreview = 2, 11 | enumBlockTypeTextInfo = 3, 12 | enumBlockTypeHeader = 4, 13 | enumBlockTypeAudio = 7 14 | 15 | }; 16 | 17 | public enum enumFileType 18 | { 19 | enumFileTypeImage = 1, 20 | enumFileTypeSequenz = 2 21 | }; 22 | 23 | private struct tyBlock 24 | { 25 | public enumBlockType BlockType; 26 | public int DWord2; 27 | public int FrameIndex; 28 | public int offset; 29 | public int size; 30 | public int DWord6; 31 | public int DWord7; 32 | public int DWord8; 33 | public int headerOffset; 34 | public int headerSize; 35 | public int imageOffset; 36 | public int imageSize; 37 | }; 38 | 39 | 40 | private struct tyHead 41 | { 42 | public string MagicNumber; 43 | public string FileType; 44 | public string FileType2; 45 | public enumFileType FileType2enum; 46 | 47 | public int Flag1; 48 | public int FirstBlockCount; 49 | 50 | public int BlockOffset; 51 | public int BlockCount; 52 | public tyBlock[] Block; 53 | public int BlockCountMax; 54 | }; 55 | 56 | private static Logging logging = new Logging("IrbFileReader"); 57 | 58 | 59 | private tyHead Head; 60 | 61 | private StreamReader reader; 62 | private int m_imageCount; 63 | 64 | 65 | 66 | //-------------------------------------// 67 | public IrbFileReader(string filename) 68 | { 69 | this.m_imageCount = 0; 70 | 71 | reader = new StreamReader(filename); 72 | 73 | 74 | Head.MagicNumber = reader.ReadStr(5); 75 | 76 | //- ID 77 | if (string.Compare(Head.MagicNumber, "\xFFIRB\0") != 0) //-- soll "\xFF" "IRB" "\0" aber C schneidet das \0 weg! 78 | { 79 | logging.addError("Irb File - ''Magische Number'' wrong"); 80 | return; 81 | } 82 | 83 | //- FileType 84 | Head.FileType = reader.ReadStr(8); 85 | 86 | if (string.Compare(Head.FileType, "IRBACS\0\0") != 0) 87 | { 88 | Head.FileType2enum = enumFileType.enumFileTypeImage; 89 | } 90 | else if (string.Compare(Head.FileType, "IRBIS 3\0") != 0) 91 | { 92 | Head.FileType2enum = enumFileType.enumFileTypeSequenz; 93 | } 94 | else 95 | { 96 | logging.addError("Unknown Irbis File Type"); 97 | return; 98 | } 99 | 100 | 101 | 102 | Head.FileType2 = reader.ReadStr(8); 103 | 104 | Head.Flag1 = reader.ReadIntBE(); 105 | Head.BlockOffset = reader.ReadIntBE(); //- starts at 0 106 | Head.FirstBlockCount = reader.ReadIntBE(); 107 | 108 | Head.BlockCount = 0; 109 | this.AddHead(Head.BlockOffset, Head.FirstBlockCount); 110 | 111 | int i = 0; 112 | while (i < Head.BlockCount) 113 | { 114 | if (Head.Block[i].BlockType == enumBlockType.enumBlockTypeHeader) 115 | { 116 | this.AddHead(Head.Block[i].offset, 2); 117 | } 118 | i++; 119 | } 120 | 121 | 122 | } 123 | 124 | //-------------------------------------------------------// 125 | public void Close() 126 | { 127 | if (reader != null) 128 | { 129 | reader.Close(); 130 | } 131 | } 132 | 133 | 134 | 135 | //-------------------------------------// 136 | private void AddHead(int offset, int count) 137 | { 138 | if ((Head.BlockCount + count) > Head.BlockCountMax) 139 | { 140 | Head.BlockCountMax = Head.BlockCountMax + count + 100; 141 | 142 | System.Array.Resize(ref Head.Block, Head.BlockCountMax); 143 | } 144 | 145 | 146 | reader.SetOffset(offset); 147 | 148 | if (reader.Eof) return; 149 | 150 | 151 | for (int i = 0; i < count; i++) 152 | { 153 | if (reader.Eof) return; 154 | 155 | SetHeadBlockVars(ref Head.Block[Head.BlockCount]); 156 | 157 | Head.BlockCount++; 158 | } 159 | } 160 | 161 | 162 | //-------------------------------------// 163 | private void SetHeadBlockVars(ref tyBlock block) 164 | { 165 | block.BlockType = (enumBlockType)reader.ReadIntBE(); 166 | 167 | block.DWord2 = reader.ReadIntBE(); 168 | block.FrameIndex = reader.ReadIntBE(); 169 | 170 | 171 | block.offset = reader.ReadIntBE(); // starts at 0 172 | 173 | block.size = reader.ReadIntBE(); 174 | 175 | //- head is wlways 0x6C0 Byte in lengtg 176 | block.headerSize = 0x6C0; 177 | if (block.headerSize > block.size) block.headerSize = block.size; 178 | 179 | 180 | block.headerOffset = 0; 181 | 182 | block.imageOffset = block.headerSize; 183 | block.imageSize = block.size - block.imageOffset; 184 | 185 | 186 | 187 | block.DWord6 = reader.ReadIntBE(); 188 | block.DWord7 = reader.ReadIntBE(); 189 | block.DWord8 = reader.ReadIntBE(); 190 | 191 | if (block.BlockType == enumBlockType.enumBlockTypeImage) 192 | { 193 | this.m_imageCount++; 194 | } 195 | } 196 | 197 | 198 | //-------------------------------------// 199 | public int GetImageCount() 200 | { 201 | return this.m_imageCount; 202 | } 203 | 204 | 205 | 206 | 207 | //-------------------------------------// 208 | public int GetBlockCount() 209 | { 210 | return Head.BlockCount; 211 | } 212 | 213 | 214 | //-------------------------------------// 215 | public int GetBlockSize(int index) 216 | { 217 | if ((index >= 0) && (index < Head.BlockCount)) 218 | { 219 | return Head.Block[index].size; 220 | } 221 | else 222 | { 223 | return 0; 224 | } 225 | } 226 | 227 | 228 | //-------------------------------------// 229 | public bool IsBlockImage(int index) 230 | { 231 | if ((index >= 0) && (index < Head.BlockCount)) 232 | { 233 | return (Head.Block[index].BlockType == enumBlockType.enumBlockTypeImage); 234 | } 235 | else 236 | { 237 | return false; 238 | } 239 | } 240 | 241 | 242 | //-------------------------------------// 243 | public bool IsBlockTextInfo(int index) 244 | { 245 | if ((index >= 0) && (index < Head.BlockCount)) 246 | { 247 | return (Head.Block[index].BlockType == enumBlockType.enumBlockTypeTextInfo); 248 | } 249 | else 250 | { 251 | return false; 252 | } 253 | } 254 | 255 | 256 | //-------------------------------------// 257 | public enumBlockType GetBlockType(int index) 258 | { 259 | if ((index >= 0) && (index < Head.BlockCount)) 260 | { 261 | return Head.Block[index].BlockType; 262 | } 263 | else 264 | { 265 | return enumBlockType.enumBlockTypeUnknown; 266 | } 267 | } 268 | 269 | 270 | 271 | //-------------------------------------// 272 | public bool IsBlockPreview(int index) 273 | { 274 | if ((index >= 0) && (index < Head.BlockCount)) 275 | { 276 | return (Head.Block[index].BlockType == enumBlockType.enumBlockTypePreview); 277 | } 278 | else 279 | { 280 | return false; 281 | } 282 | } 283 | 284 | 285 | 286 | /// 287 | /// Return the info text of this file 288 | /// 289 | public string GetTextInfo(int index = 0) 290 | { 291 | var blockIndex = FindBlockIndexByType(enumBlockType.enumBlockTypeTextInfo, index); 292 | 293 | if (blockIndex < 0) 294 | { 295 | return string.Empty; 296 | } 297 | 298 | tyBlock block = Head.Block[blockIndex]; 299 | 300 | return reader.ReadStr(block.size, block.offset); 301 | 302 | } 303 | 304 | 305 | 306 | /// 307 | /// return the data of an image 308 | /// 309 | public byte[] GetImageData(int imageIndex) 310 | { 311 | int blockIndex = GetImageBlockIndex(imageIndex); 312 | 313 | if (blockIndex < 0) 314 | { 315 | logging.addError("getImageData(imageIndex) fail - ImageIndex: " + imageIndex + " not found"); 316 | return null; 317 | } 318 | 319 | //- Header zurückgeben 320 | tyBlock block = Head.Block[blockIndex]; 321 | return reader.ReadByte(block.size, block.offset); 322 | } 323 | 324 | 325 | /// 326 | /// Return the n-th index of a given data block type 327 | /// 328 | private int FindBlockIndexByType(enumBlockType type, int number) 329 | { 330 | if ((number < 0) || (number >= Head.BlockCount)) 331 | { 332 | return -1; 333 | } 334 | 335 | for (int i = 0; i < Head.BlockCount; i++) 336 | { 337 | tyBlock block = Head.Block[i]; 338 | 339 | //- find all images 340 | if (block.BlockType == type) 341 | { 342 | /// return image if 343 | number--; 344 | if (number < 0) 345 | { 346 | return i; 347 | } 348 | } 349 | } 350 | 351 | return -1; 352 | 353 | } 354 | 355 | /// 356 | /// Retrun the data block for a given image index 357 | /// 358 | private int GetImageBlockIndex(int imageIndex) 359 | { 360 | return FindBlockIndexByType(enumBlockType.enumBlockTypeImage, imageIndex); 361 | } 362 | 363 | 364 | 365 | /// 366 | /// Return the file offset for a given data block 367 | /// 368 | public int GetBlockOffset(int index) 369 | { 370 | if ((index >= 0) && (index < Head.BlockCount)) 371 | { 372 | return Head.Block[index].offset; 373 | } 374 | else 375 | { 376 | return 0; 377 | } 378 | 379 | } 380 | 381 | 382 | 383 | 384 | } 385 | } 386 | --------------------------------------------------------------------------------