//кодирование изображения
        public void Compress(Bitmap image, IProgress <int> progress = null, CancellationToken?token = null)
        {
            if (progress == null)
            {
                progress = new Progress <int>();
            }
            if (token == null)
            {
                token = new CancellationToken();
            }
            Stopwatch sw = new Stopwatch();

            sw.Start();
            Bitmap[,] parts = SplitImage(image, out numberOfParts);
            Bitmap[,,] domainBlocks;
            int partOffsetX = image.Width / Data.RankBlockSize / numberOfParts;
            int partOffsetY = image.Height / Data.RankBlockSize / numberOfParts;
            var bbOriginal  = new BufferedBitmap(image);

            if (bbOriginal.IsGrey())
            {
                Data.ColorFlag = 1;
            }
            else
            {
                Data.ColorFlag = 3;
            }
            bbOriginal.Unlock();

            double[] contrast   = new double[Data.ColorFlag];
            double[] brightness = new double[Data.ColorFlag];
            double[] metric     = new double[Data.ColorFlag];
            double[] min        = new double[Data.ColorFlag];
            double[,,,] compressedData = new double[Data.ColorFlag, bbOriginal.Width / Data.RankBlockSize,
                                                    bbOriginal.Height / Data.RankBlockSize, numberOfParameters];
            double controlValue = (bbOriginal.Width / Data.RankBlockSize) * (bbOriginal.Height / Data.RankBlockSize) / 100.0;
            double count        = 0;
            int    value        = 1;
            double mse          = 0;

            for (int partX = 0; partX < numberOfParts; partX++)
            {
                for (int partY = 0; partY < numberOfParts; partY++)
                {
                    domainBlocks = CreateAllDomainBlocks(parts[partX, partY]);
                    bbOriginal   = new BufferedBitmap(parts[partX, partY]);

                    for (int i = 0; i *Data.RankBlockSize != bbOriginal.Width; i++)
                    {
                        for (int j = 0; j *Data.RankBlockSize != bbOriginal.Height; j++)
                        {
                            if ((bool)token?.IsCancellationRequested)
                            {
                                progress.Report(0);
                                MessageBox.Show("Операция прервана");
                                return;
                            }

                            int    indexX    = i + partX * partOffsetX;
                            int    indexY    = j + partY * partOffsetY;
                            Bitmap rankBlock = SelectBlockFromImage(bbOriginal, i, j, Data.RankBlockSize);
                            if (min[0] != 0)
                            {
                                for (int k = 0; k < Data.ColorFlag; k++)
                                {
                                    mse += min[k];
                                }
                            }
                            for (int k = 0; k < Data.ColorFlag; k++)
                            {
                                min[k] = double.PositiveInfinity;
                            }
                            var meanRankBlock = Metric.Mean(rankBlock);

                            for (int p = 0; p < parts[partX, partY].Width / Data.DomainBlockSize; p++)
                            {
                                for (int q = 0; q < parts[partX, partY].Height / Data.DomainBlockSize; q++)
                                {
                                    var meanDomainBlock = Metric.Mean(domainBlocks[p, q, 0]);

                                    for (int rotation = 0; rotation < numberOfRotations; rotation++)
                                    {
                                        contrast   = Metric.GetContrast(rankBlock, domainBlocks[p, q, rotation], meanRankBlock, meanDomainBlock);
                                        brightness = Metric.GetBrightness(contrast, meanRankBlock, meanDomainBlock);
                                        metric     = Metric.GetMetric(rankBlock, domainBlocks[p, q, rotation], contrast, brightness);

                                        for (int m = 0; m < Data.ColorFlag; m++)
                                        {
                                            if (metric[m] < min[m])
                                            {
                                                min[m] = metric[m];
                                                double[] mas = new double[] { p + partX * partOffsetX / Data.Factor, q + partY * partOffsetY / Data.Factor, rotation, contrast[m], brightness[m] };

                                                for (int k = 0; k < mas.Length; k++)
                                                {
                                                    compressedData[m, indexX, indexY, k] = mas[k];
                                                }
                                            }
                                        }
                                        //if (Data.FastCompression && min[0] <= 100)
                                        //break;
                                    }
                                    //if (Data.FastCompression && min[0] <= 100)
                                    //break;
                                }
                                count += 1.0 / domainBlocks.GetLength(1);
                                if (count >= controlValue)
                                {
                                    if (value > 100)
                                    {
                                        value = 100;
                                    }
                                    progress.Report(value);
                                    value++;
                                    count -= controlValue;
                                    count  = Math.Round(count, 2);
                                }
                                //if (Data.FastCompression && min[0] <= 100)
                                //break;
                            }
                        }
                    }
                }
            }
            mse = mse / ((image.Width / Data.RankBlockSize) * (image.Height / Data.RankBlockSize));
            bbOriginal.Unlock();
            double psnr = 10 * Math.Log10(image.Width * image.Height * Math.Pow(byte.MaxValue, 2) * Data.ColorFlag / mse);

            WriteData(compressedData, image.Width, image.Height);
            sw.Stop();
            MessageBox.Show("Сжатие завершено\r\nВремя: " + (sw.ElapsedMilliseconds / 1000.0).ToString());
            progress.Report(0);
        }