public static byte[] ReadHeaderItem(byte[] bytes, HeaderItemDescriptor descriptor)
        {
            UInt32 offset = descriptor.Offset;
            UInt32 length = descriptor.Length;
            Type   type   = descriptor.Type;

            UInt32 sizeInBytes = GetSizeInBytes(type, length);

            byte[] resBytes = ReadBytes(bytes, offset, sizeInBytes);

            return(resBytes);
        }
        public static IntegerMatrix ReadImageFromFile(string filePath)
        {
            byte[] fileBytes = File.ReadAllBytes(filePath);

            List <HeaderItemDescriptor> headerItemList = HeaderItemDescriptor.GetHeaderItemDescriptorList();

            #region Byte Order

            //Byte order
            HeaderItemDescriptor headerItemByteOrder =
                headerItemList.FirstOrDefault(item => item.Name == HeaderItemDescriptor.ITEM_BYTE_ORDER);
            byte[] headerItemByteOrderBytes = RawReader.ReadHeaderItem(fileBytes, headerItemByteOrder);

            #endregion

            //First IFD
            HeaderItemDescriptor headerItemFirstIFD =
                headerItemList.FirstOrDefault(item => item.Name == HeaderItemDescriptor.ITEM_TIFF_OFFSET);
            byte[] headerItemFirstIFDBytes = RawReader.ReadHeaderItem(fileBytes, headerItemFirstIFD);

            List <IFD_0_EntryDescriptor> firstIFDEntryDescriptorList = IFD_0_EntryDescriptor.GetEntryDescriptorList();

            //Compression
            int    compressionEntryIndex             = firstIFDEntryDescriptorList.FindIndex(item => item.Name == IFD_0_EntryDescriptor.COMPRESSION);
            UInt32 localCompressionOffset            = ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(compressionEntryIndex));
            UInt32 compressionOffset                 = BitConverter.ToUInt32(headerItemFirstIFDBytes, 0) + localCompressionOffset;
            ImageFileDirectoryEntry compressionEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, compressionOffset);
            UInt16 compressionValue = compressionEntry.GetUInt16Value();

            //Make
            int    makeEntryIndex             = firstIFDEntryDescriptorList.FindIndex(item => item.Name == IFD_0_EntryDescriptor.MAKE);
            UInt32 localMakeOffset            = ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(makeEntryIndex));
            UInt32 makeOffset                 = BitConverter.ToUInt32(headerItemFirstIFDBytes, 0) + localMakeOffset;
            ImageFileDirectoryEntry makeEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, makeOffset);
            UInt32 makeOffseValue             = makeEntry.GetUInt32Value();
            byte[] makeBytes = RawReader.ReadBytesUntilEndingZero(fileBytes, makeOffseValue);
            string makeValue = ConvertHelper.ConvertToString(makeBytes);

            //Model
            int    modelEntryIndex             = firstIFDEntryDescriptorList.FindIndex(item => item.Name == IFD_0_EntryDescriptor.MODEL);
            UInt32 localModelOffset            = ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(modelEntryIndex));
            UInt32 modelOffset                 = BitConverter.ToUInt32(headerItemFirstIFDBytes, 0) + localModelOffset;
            ImageFileDirectoryEntry modelEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, modelOffset);
            UInt32 modelOffsetValue            = modelEntry.GetUInt32Value();
            byte[] modelBytes = RawReader.ReadBytesUntilEndingZero(fileBytes, modelOffsetValue);
            string modelValue = ConvertHelper.ConvertToString(modelBytes);

            //X Resolution
            int    xResolutionEntryIndex             = firstIFDEntryDescriptorList.FindIndex(item => item.Name == IFD_0_EntryDescriptor.X_RESOLUTION);
            UInt32 localXResolutionOffset            = ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(xResolutionEntryIndex));
            UInt32 xResolutionOffset                 = BitConverter.ToUInt32(headerItemFirstIFDBytes, 0) + localXResolutionOffset;
            ImageFileDirectoryEntry xResolutionEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, xResolutionOffset);
            UInt32 xResolutionOffsetValue            = xResolutionEntry.GetUInt32Value();
            byte[] xResolutionBytes = RawReader.ReadBytes(fileBytes, xResolutionOffsetValue, 4);
            UInt32 xResolutionValue = ConvertHelper.ConvertToUInt32(xResolutionBytes);

            //DateTime
            int    dateTimeEntryIndex             = firstIFDEntryDescriptorList.FindIndex(item => item.Name == IFD_0_EntryDescriptor.DATE_TIME);
            UInt32 localDateTimeOffset            = ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(dateTimeEntryIndex));
            UInt32 dateTimeOffset                 = BitConverter.ToUInt32(headerItemFirstIFDBytes, 0) + localDateTimeOffset;
            ImageFileDirectoryEntry dateTimeEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, dateTimeOffset);
            UInt32   dateTimeOffsetValue          = dateTimeEntry.GetUInt32Value();
            byte[]   dateTimeBytes                = RawReader.ReadBytesUntilEndingZero(fileBytes, dateTimeOffsetValue);
            string   dateTimeValue                = ConvertHelper.ConvertToString(dateTimeBytes);
            DateTime dateTimeStruct               = DateTime.ParseExact(dateTimeValue, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture);

            //EXIF bytes
            IFD_0_EntryDescriptor exifEntryDescriptor =
                firstIFDEntryDescriptorList.Where(item => item.Name == IFD_0_EntryDescriptor.EXIF).FirstOrDefault();
            uint exifOffset = RawReader.GetEntryOffsetByTagID(fileBytes, exifEntryDescriptor.TagID);
            ImageFileDirectoryEntry exifOffsetEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, exifOffset);
            UInt32 exifOffsetValue = exifOffsetEntry.GetUInt32Value();
            byte[] exifBytes       = RawReader.ReadBytes(fileBytes, exifOffsetValue);

            //Makernote bytes
            List <EXIF_EntryDescriptor> exifEntryDescriptorList  = EXIF_EntryDescriptor.GetEntryDescriptorList();
            EXIF_EntryDescriptor        makerNoteEntryDescriptor =
                exifEntryDescriptorList.Where(item => item.Name == EXIF_EntryDescriptor.MAKER_NOTE).FirstOrDefault();
            uint makerNoteOffset = RawReader.GetEntryOffsetByTagID(fileBytes, makerNoteEntryDescriptor.TagID);
            ImageFileDirectoryEntry makerNoteOffsetEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, makerNoteOffset);
            UInt32 makerNoteOffsetValue = makerNoteOffsetEntry.GetUInt32Value();
            byte[] makerNoteBytes       = RawReader.ReadBytes(fileBytes, makerNoteOffsetValue);

            //Color Balance
            List <Makernote_EntryDescriptor> makernoteEntryDescriptorList = Makernote_EntryDescriptor.GetEntryDescriptorList();
            Makernote_EntryDescriptor        colorBalanceEntryDescriptor  =
                makernoteEntryDescriptorList.Where(item => item.Name == Makernote_EntryDescriptor.COLOR_BALANCE).FirstOrDefault();
            uint colorBalanceOffset = RawReader.GetEntryOffsetByTagID(makerNoteBytes, colorBalanceEntryDescriptor.TagID);
            ImageFileDirectoryEntry colorBalanceEntry = RawReader.ReadImageFileDirectoryEntry(makerNoteBytes, colorBalanceOffset);
            UInt32 colorBalanceOffsetValue            = colorBalanceEntry.GetUInt32Value();


            //Raw Data IFD
            HeaderItemDescriptor headerItemRawIFD =
                headerItemList.FirstOrDefault(item => item.Name == HeaderItemDescriptor.ITEM_RAW_IFD_OFFSET);
            byte[] headerItemRawBytes = RawReader.ReadHeaderItem(fileBytes, headerItemRawIFD);
            List <IFD_3_EntryDescriptor> rawEntryDescriptorList = IFD_3_EntryDescriptor.GetEntryDescriptorList();

            //Slices
            int    slicesIndex  = rawEntryDescriptorList.FindIndex(item => item.Name == IFD_3_EntryDescriptor.CR2_SLICE);
            UInt32 slicesOffset = BitConverter.ToUInt32(headerItemRawBytes, 0) + ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(slicesIndex));
            ImageFileDirectoryEntry slicesEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, slicesOffset);
            UInt16[] slices = RawReader.ReadUInt16Array(fileBytes, slicesEntry.GetUInt32Value(), slicesEntry.NumberOfValue);

            //Headers and compressed raw bytes
            int    rawOffsetEntryIndex = rawEntryDescriptorList.FindIndex(item => item.Name == IFD_3_EntryDescriptor.STRIP_OFFSET);
            UInt32 localStripOffset    = ImageFileDirectory.GetImageFileDirectoryEntryOffset(Convert.ToUInt32(rawOffsetEntryIndex));
            UInt32 stripOffset         = BitConverter.ToUInt32(headerItemRawBytes, 0) + localStripOffset;
            ImageFileDirectoryEntry stripOffsetEntry = RawReader.ReadImageFileDirectoryEntry(fileBytes, stripOffset);
            UInt32 stripOffsetValue = stripOffsetEntry.GetUInt32Value();
            byte[] rawBytes         = RawReader.ReadBytes(fileBytes, stripOffsetValue);

            DhtHeader  dhtHeader  = RawReader.ReadDhtHeader(rawBytes);
            Sof3Header sof3Header = RawReader.ReadSof3Header(rawBytes);
            SosHeader  sosHeader  = RawReader.ReadSosHeader(rawBytes);

            Dictionary <string, byte> huffmanCodeValueDictionaryOne = dhtHeader.HuffmanTables[0].GetHuffmanCodeValueMap();
            Dictionary <string, byte> huffmanCodeValueDictionaryTwo = dhtHeader.HuffmanTables[1].GetHuffmanCodeValueMap();

            //SCAN DATA
            UInt32 scanDataOffset = sosHeader.Offset + sosHeader.HeaderLength + 2;
            byte[] scanDataBytes  = RawReader.ReadBytes(rawBytes, scanDataOffset);

            return(RawReader.ReadScanData(scanDataBytes, dhtHeader, sof3Header, sosHeader, slices));
        }