public static void CompressData(int[,] dataMatrix, BitWriter writer)
        {
            // Write compressed file variables
            ArithmeticCoder coder = new ArithmeticCoder(writer);
            var             size  = (int)Math.Sqrt(dataMatrix.Length);

            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                {
                    uint symbol = (uint)(dataMatrix[i, j] + 255);

                    // For each symbol and update the model statistics
                    coder.EncodeSymbol(symbol);
                    coder.arithmeticModel.UpdateModel(symbol);
                }
            }
            coder.EncodeSymbol(EOF);
            coder.FlushEncoder();
            writer.WriteNBits(1, 7);
            writer.Dispose();
        }
        private void btnSaveEncodedImage_Click(object sender, EventArgs e)
        {
            try
            {
                var headerBmpFile        = bmpObject.GetBmpHeader();
                var compressedDataMatrix = nlEngine.GetErrorPredictedQuantizedMatrix();
                var dataMatrixSize       = (int)Math.Sqrt(compressedDataMatrix.Length);

                var compressedFileName = Path.GetFileNameWithoutExtension(inputFilePathEncoder);
                var fileExtension      = ".k" + userKMaxReconstructionError + "p" + userPredictorSelection;


                if (userKMaxReconstructionError != numericUpDownKValue.Value)
                {
                    throw new NullReferenceException();
                }
                if (userPredictorSelection != comboBoxPredictorSelection.SelectedIndex)
                {
                    throw new NullReferenceException();
                }
                if (String.IsNullOrEmpty(compressedFileName) || isFileEncoded == false)
                {
                    throw new NullReferenceException();
                }

                using (var fbd = new FolderBrowserDialog())
                {
                    var result = fbd.ShowDialog();
                    if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
                    {
                        var compressedFilePath = fbd.SelectedPath;

                        switch (comboBoxSaveMode.SelectedIndex)
                        {
                        case 0:     // Fixed Saving Mode (F)
                        {
                            fileExtension      += "F.nlp";
                            compressedFilePath += "\\" + compressedFileName + fileExtension;

                            // Building the bmp compressed file format
                            BitWriter writer = new BitWriter(compressedFilePath);

                            // [1-F] writing the specific header byte by byte
                            for (int i = 0; i < headerBmpFile.Length; i++)
                            {
                                writer.WriteNBits(headerBmpFile[i], 8);
                            }

                            // [2-F] writing the predictor used (on 4 bits)
                            writer.WriteNBits((uint)userPredictorSelection, 4);

                            // [3-F] writing the k  value  used (on 4 bits)
                            writer.WriteNBits((uint)userKMaxReconstructionError, 4);

                            // [4-F] writing the save mode used (on 2 bits)
                            writer.WriteNBits((uint)comboBoxSaveMode.SelectedIndex, 2);

                            // [5-F] writing bmp data matrix elements (on 9 bits each)
                            for (int i = 0; i < dataMatrixSize; i++)
                            {
                                for (int j = 0; j < dataMatrixSize; j++)
                                {
                                    writer.WriteNBits((uint)compressedDataMatrix[i, j] + 255, 9);
                                }
                            }
                            writer.WriteNBits(1, 7);
                            writer.Dispose();
                            break;
                        }

                        case 1:     // Jpeg Table Saving Mode (T)
                        {
                            fileExtension      += "T.nlp";
                            compressedFilePath += "\\" + compressedFileName + fileExtension;

                            // Building the bmp compressed file format
                            BitWriter writer = new BitWriter(compressedFilePath);

                            // [1-T] writing the specific header byte by byte
                            for (int i = 0; i < headerBmpFile.Length; i++)
                            {
                                writer.WriteNBits(headerBmpFile[i], 8);
                            }

                            // [2-T] writing the predictor used (on 4 bits)
                            writer.WriteNBits((uint)userPredictorSelection, 4);

                            // [3-T] writing the k  value  used (on 4 bits)
                            writer.WriteNBits((uint)userKMaxReconstructionError, 4);

                            // [4-T] writing the save mode used (on 2 bits)
                            writer.WriteNBits((uint)comboBoxSaveMode.SelectedIndex, 2);

                            // [5-T] writing bmp data matrix elements encoded with JPEG Table
                            for (int i = 0; i < dataMatrixSize; i++)
                            {
                                for (int j = 0; j < dataMatrixSize; j++)
                                {
                                    Helpers.WriteValueUsingJPEGTable(writer, compressedDataMatrix[i, j]);
                                }
                            }
                            writer.WriteNBits(1, 7);
                            writer.Dispose();
                            break;
                        }

                        case 2:     // Arithmetic Saving Mode (Entropic Coder) (A)
                        {
                            fileExtension      += "A.nlp";
                            compressedFilePath += "\\" + compressedFileName + fileExtension;

                            // Building the bmp compressed file format
                            BitWriter writer = new BitWriter(compressedFilePath);

                            // [1-A] writing the specific header byte by byte
                            for (int i = 0; i < headerBmpFile.Length; i++)
                            {
                                writer.WriteNBits(headerBmpFile[i], 8);
                            }

                            // [2-A] writing the predictor used (on 4 bits)
                            writer.WriteNBits((uint)userPredictorSelection, 4);

                            // [3-A] writing the k  value  used (on 4 bits)
                            writer.WriteNBits((uint)userKMaxReconstructionError, 4);

                            // [4-A] writing the save mode used (on 2 bits)
                            writer.WriteNBits((uint)comboBoxSaveMode.SelectedIndex, 2);

                            // [5-A] writing bmp data matrix elements encoded with Arithmetic CODER
                            ArithmeticCoder.CompressData(compressedDataMatrix, writer);

                            break;
                        }

                        default: break;
                        }
                    }
                }
                isFileEncoded = false;
                MessageBox.Show("Encoded image succesfully saved!");
            }
            catch (NullReferenceException)
            {
                MessageBox.Show("Warning: You forgot to load/encode the image. (Other causes: encoding settings are changed)");
            }
        }