public static SosHeader ReadSosHeader(byte[] bytes)
        {
            //SOS HEADER

            UInt32 sosHeaderOffset = RawReader.FindByteValueIndex(bytes, 0xFF, 0xDA);

            byte[] sosHeaderBytes = RawReader.ReadBytes(bytes, sosHeaderOffset);

            UInt32 sosHeaderLengthOffset = 2;

            byte[] sosHeaderLengthBytes = RawReader.ReadBytes(sosHeaderBytes, sosHeaderLengthOffset, 2);
            UInt16 sosHeaderLength      = ConvertHelper.ConvertToUInt16(sosHeaderLengthBytes, true);

            UInt32 sosHeaderComponentsNumberOffset = 4;
            byte   sosHeaderComponentsNumber       = RawReader.ReadByte(sosHeaderBytes, sosHeaderComponentsNumberOffset);

            SosHeaderComponentInfo[] components = new SosHeaderComponentInfo[sosHeaderComponentsNumber];
            UInt32 sosHeaderComponentsOffset    = 5;

            for (byte k = 0; k < sosHeaderComponentsNumber; k++)
            {
                SosHeaderComponentInfo componentInfo = RawReader.ReadSosHeaderComponentInfo(sosHeaderBytes, sosHeaderComponentsOffset);
                components[k]              = componentInfo;
                sosHeaderComponentsOffset += 2;
            }

            return(new SosHeader()
            {
                Offset = sosHeaderOffset,

                HeaderLength = sosHeaderLength,
                Components = components
            });
        }
        private static SosHeaderComponentInfo ReadSosHeaderComponentInfo(byte[] bytes, UInt32 offset)
        {
            byte[]     componentBytes = RawReader.ReadBytes(bytes, offset, 2);
            HalvedByte halvedByte     = new HalvedByte(componentBytes[1]);

            return(new SosHeaderComponentInfo()
            {
                ComponentNumber = componentBytes[0],
                DCtable = halvedByte.High,
                ACtable = halvedByte.Low
            });
        }
        private static Sof3HeaderComponentInfo ReadSof3HeaderComponentInfo(byte[] bytes, UInt32 offset)
        {
            byte[]     componentBytes = RawReader.ReadBytes(bytes, offset, 3);
            HalvedByte halvedByte     = new HalvedByte(componentBytes[1]);

            return(new Sof3HeaderComponentInfo()
            {
                ComponentNumber = componentBytes[0],
                HorizontalSamplingFactor = halvedByte.High,
                VerticalSamplingFactor = halvedByte.Low,
                QuantizationTable = componentBytes[2]
            });
        }
        public static Sof3Header ReadSof3Header(byte[] bytes)
        {
            //SOF3 HEADER

            UInt32 sof3HeaderOffset = RawReader.FindByteValueIndex(bytes, 0xFF, 0xC3);

            byte[] sof3HeaderBytes = RawReader.ReadBytes(bytes, sof3HeaderOffset);

            UInt32 sof3HeaderLengthOffset = 2;

            byte[] sof3HeaderLengthBytes = RawReader.ReadBytes(sof3HeaderBytes, sof3HeaderLengthOffset, 2);
            UInt16 sof3HeaderLength      = ConvertHelper.ConvertToUInt16(sof3HeaderLengthBytes, true);

            UInt32 sof3HeaderSamplePrecisionOffset = 4;
            byte   sof3HeaderSamplePrecision       = RawReader.ReadByte(sof3HeaderBytes, sof3HeaderSamplePrecisionOffset);

            UInt32 sof3HeaderLinesNumberOffset = 5;

            byte[] sof3HeaderLinesNumberBytes = RawReader.ReadBytes(sof3HeaderBytes, sof3HeaderLinesNumberOffset, 2);
            UInt16 sof3HeaderLinesNumber      = ConvertHelper.ConvertToUInt16(sof3HeaderLinesNumberBytes, true);

            UInt32 sof3HeaderSamplesPerLineNumberOffset = 7;

            byte[] sof3HeaderSamplesPerLineNumberBytes = RawReader.ReadBytes(sof3HeaderBytes, sof3HeaderSamplesPerLineNumberOffset, 2);
            UInt16 sof3HeaderSamplesPerLineNumber      = ConvertHelper.ConvertToUInt16(sof3HeaderSamplesPerLineNumberBytes, true);

            UInt32 sof3HeaderImageComponentsPerFrameNumberOffset = 9;
            byte   sof3HeaderImageComponentsPerFrameNumber       = RawReader.ReadByte(sof3HeaderBytes, sof3HeaderImageComponentsPerFrameNumberOffset);

            Sof3HeaderComponentInfo[] components = new Sof3HeaderComponentInfo[sof3HeaderImageComponentsPerFrameNumber];
            UInt32 sof3HeaderComponentsOffset    = 10;

            for (byte k = 0; k < sof3HeaderImageComponentsPerFrameNumber; k++)
            {
                Sof3HeaderComponentInfo componentInfo = RawReader.ReadSof3HeaderComponentInfo(sof3HeaderBytes, sof3HeaderComponentsOffset);
                components[k] = componentInfo;
                sof3HeaderComponentsOffset += 3;
            }

            return(new Sof3Header()
            {
                Offset = sof3HeaderOffset,

                HeaderLength = sof3HeaderLength,
                SamplePrecision = sof3HeaderSamplePrecision,
                LinesNumber = sof3HeaderLinesNumber,
                SamplesPerLineNumber = sof3HeaderSamplesPerLineNumber,
                Components = components
            });
        }
        public static UInt16[] ReadUInt16Array(byte[] bytes, UInt32 offset, UInt32 length)
        {
            UInt16[] resArray = new UInt16[length];
            UInt32   itemSize = sizeof(UInt16);

            for (UInt32 index = 0; index < length; index++)
            {
                byte[] bytesValue = RawReader.ReadBytes(bytes, offset + index * itemSize, itemSize);
                UInt16 value      = ConvertHelper.ConvertToUInt16(bytesValue);
                resArray[index] = value;
            }

            return(resArray);
        }
        public static DhtHeader ReadDhtHeader(byte[] bytes)
        {
            UInt32 dhtHeaderOffset = RawReader.FindByteValueIndex(bytes, 0xFF, 0xC4);

            byte[] dhtHeaderBytes = RawReader.ReadBytes(bytes, dhtHeaderOffset);

            UInt32 dhtHeaderLengthOffset = 2;

            byte[] dhtHeaderLengthBytes = RawReader.ReadBytes(dhtHeaderBytes, dhtHeaderLengthOffset, 2);
            UInt16 dhtHeaderLength      = ConvertHelper.ConvertToUInt16(dhtHeaderLengthBytes, true);
            UInt32 valueHuffmanCodesOffset;
            UInt32 lengthNumberHuffmanCodesSum = 0;

            //Huffman table 1
            UInt32 dhtHeaderTableIndexOffset = 4;
            byte   dhtHeaderTableIndex;
            UInt32 tableOffset = dhtHeaderTableIndexOffset + 1;

            HuffmanTable tableOne = new HuffmanTable();

            dhtHeaderTableIndex = RawReader.ReadByte(dhtHeaderBytes, dhtHeaderTableIndexOffset);
            tableOne.TableClass = (new HalvedByte(dhtHeaderTableIndex)).High;
            tableOne.TableIndex = (new HalvedByte(dhtHeaderTableIndex)).Low;

            byte[] lengthNumberHuffmanCodesBytes =
                RawReader.ReadBytes(dhtHeaderBytes, tableOffset, DhtHeader.LENGTH_NUMBER_HUFFMAN_CODES_COUNT);
            lengthNumberHuffmanCodesSum = Convert.ToUInt32(lengthNumberHuffmanCodesBytes.Sum(x => x));
            valueHuffmanCodesOffset     = tableOffset + DhtHeader.LENGTH_NUMBER_HUFFMAN_CODES_COUNT;
            byte[] valueHuffmanCodesBytes = RawReader.ReadBytes(dhtHeaderBytes, valueHuffmanCodesOffset, lengthNumberHuffmanCodesSum);

            tableOne.LengthHuffmanCodes = lengthNumberHuffmanCodesBytes;
            tableOne.ValueHuffmanCodes  = valueHuffmanCodesBytes;


            //Huffman table 2
            dhtHeaderTableIndexOffset = valueHuffmanCodesOffset + lengthNumberHuffmanCodesSum;
            tableOffset = dhtHeaderTableIndexOffset + 1;

            HuffmanTable tableTwo = new HuffmanTable();

            dhtHeaderTableIndex = RawReader.ReadByte(dhtHeaderBytes, dhtHeaderTableIndexOffset);
            tableTwo.TableClass = (new HalvedByte(dhtHeaderTableIndex)).High;
            tableTwo.TableIndex = (new HalvedByte(dhtHeaderTableIndex)).Low;

            lengthNumberHuffmanCodesBytes =
                RawReader.ReadBytes(dhtHeaderBytes, tableOffset, DhtHeader.LENGTH_NUMBER_HUFFMAN_CODES_COUNT);
            lengthNumberHuffmanCodesSum = Convert.ToUInt32(lengthNumberHuffmanCodesBytes.Sum(x => x));
            valueHuffmanCodesOffset     = tableOffset + DhtHeader.LENGTH_NUMBER_HUFFMAN_CODES_COUNT;
            valueHuffmanCodesBytes      = RawReader.ReadBytes(dhtHeaderBytes, valueHuffmanCodesOffset, lengthNumberHuffmanCodesSum);

            tableTwo.LengthHuffmanCodes = lengthNumberHuffmanCodesBytes;
            tableTwo.ValueHuffmanCodes  = valueHuffmanCodesBytes;

            return(new DhtHeader()
            {
                Offset = dhtHeaderOffset,

                HeaderLength = dhtHeaderLength,
                HuffmanTables = new HuffmanTable[] { tableOne, tableTwo }
            });
        }
        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));
        }