//Сжатие с использование квадродеревьев
        public static void Compression(string filename, string quality)
        {
            if (!(File.Exists(filename)))
            {
                System.Console.WriteLine("Файла не существует");
                return;
            }
            //Черно-белый файл или нет
            if (quality == "Black")
            {
                colorflag = 1;
            }
            else
            {
                if (quality == "Color")
                {
                    colorflag = 3;
                }
                else
                {
                    System.Console.WriteLine("Тип выбран не правильно");
                    return;
                }
            }
            Bitmap image = new Bitmap(filename);

            imageWidth      = image.Width;
            imageHeigth     = image.Height;
            classImageColor = new Color[image.Width, image.Height];
            for (int i = 0; i < image.Width; ++i)
            {
                for (int j = 0; j < image.Height; ++j)
                {
                    classImageColor[i, j] = image.GetPixel(i, j);
                }
            }
            brightnessImage = new double[image.Width, image.Height];
            for (int i = 0; i < image.Width; ++i)
            {
                for (int j = 0; j < image.Height; ++j)
                {
                    brightnessImage[i, j] = image.GetPixel(i, j).GetBrightness();
                }
            }
            //Создаём ранговое дерево
            range_block_size = 64;
            range_num_width  = image.Width / range_block_size;
            range_num_height = image.Height / range_block_size;
            rangeArray       = new Object.Block[range_num_width, range_num_height];
            //Изначально создаются ранговые блоки, на основе которых будут составляться деревья
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    rangeArray[i, j] = CreateBlockRange(i * range_block_size, j * range_block_size, classImageColor, range_block_size, brightnessImage);
                }
            }
            rangeTree = new BlockTree[range_num_width, range_num_height];
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    numLock         = 1;
                    rangeTree[i, j] = new BlockTree(rangeArray[i, j], rangeArray[i, j].BlockSize);
                }
            }
            //Доменные блоки представлены не в виде деревьев, а в виде трехмерных массивов
            domain_num_width  = range_num_width - 1;
            domain_num_height = range_num_height - 1;
            domain_block_size = range_block_size * 2;
            domainArray       = new Object.Block[domain_num_width, domain_num_height];
            //System.Console.WriteLine(DomainBlocks.Length);
            domainBlocks = new Object.BlockArray[PostProcessing.GetPow(domain_block_size)];
            for (int i = 0; i < domainBlocks.Length; ++i)
            {
                if (i == 0)
                {
                    domainBlocks[i].BlockSize = domain_block_size;
                }
                else
                {
                    domainBlocks[i].BlockSize = domainBlocks[i - 1].BlockSize / 2;
                }
                domainBlocks[i].num_width  = image.Width / domainBlocks[i].BlockSize;
                domainBlocks[i].num_height = image.Height / domainBlocks[i].BlockSize;
                domainBlocks[i].Blocks     = new Object.Block[domainBlocks[i].num_width, domainBlocks[i].num_height];
                for (int j = 0; j < domainBlocks[i].num_width; ++j)
                {
                    for (int k = 0; k < domainBlocks[i].num_height; ++k)
                    {
                        domainBlocks[i].Blocks[j, k] = CreateBlockDomain(j * domainBlocks[i].BlockSize / 2, k * domainBlocks[i].BlockSize / 2, classImageColor, domainBlocks[i].BlockSize / 2, brightnessImage);
                    }
                }
            }
            listCoeff = new List <Object.Coefficients>();
            //Обход всех деревьев и нахождение для нужных коэффициентов преобразования, а так же выписывание их в файл
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    blockChecker = 0;
                    rangeTree[i, j].RoundTree(rangeTree[i, j], domainBlocks, classImageColor, rangeTree[i, j].mainBlock.BlockSize);
                }
            }

            bw = new BinaryWriter(File.Open(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Quad Compression", FileMode.Create));
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Width), 2));
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Height), 2));
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(range_block_size), 1));
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(listCoeff.Count), 4));
            //for (int i = 0; i < range_num_width; ++i)
            //{
            //    for (int j = 0; j < range_num_height; ++j)
            //    {
            //        rangeTree[i, j].PrintTree(rangeTree[i, j], 0);
            //    }
            //}
            for (int i = 0; i < listCoeff.Count; ++i)
            {
                //Запись в файл всех нужные чисел, а так же глубину нахождения узла в дереве
                Byte[] D  = BitConverter.GetBytes(listCoeff[i].Depth);
                Byte[] X  = BitConverter.GetBytes(listCoeff[i].X);
                Byte[] Y  = BitConverter.GetBytes(listCoeff[i].Y);
                Byte[] SR = BitConverter.GetBytes(listCoeff[i].shiftR);
                Byte[] SG = BitConverter.GetBytes(listCoeff[i].shiftG);
                Byte[] SB = BitConverter.GetBytes(listCoeff[i].shiftB);
                //System.Console.WriteLine(listCoeff[i].Depth + " -- " + D[0]);
                bw.Write(MyConverter.Convert(D, 1));
                bw.Write(MyConverter.Convert(X, 1));
                bw.Write(MyConverter.Convert(Y, 1));
                bw.Write(MyConverter.Convert(SR, 2));
                bw.Write(MyConverter.Convert(SG, 2));
                bw.Write(MyConverter.Convert(SB, 2));
            }
            bw.Close();
        }
        public static void ColorDecompression()
        {
            byte[] BytesFile = File.ReadAllBytes(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Compression");
            int    fileCount = 0;
            //Коэффициент масштабирования
            int scale = 1;

            Byte[] tmp         = MyConverter.ReadByte(BytesFile, 0, 2);
            int    Image_width = BitConverter.ToInt16(tmp, 0) * scale;

            fileCount += 2;
            tmp        = MyConverter.ReadByte(BytesFile, 2, 4);
            int Image_height = BitConverter.ToInt16(tmp, 0) * scale;

            fileCount += 2;
            tmp        = MyConverter.ReadByte(BytesFile, 4, 5);
            int range_block_size = tmp[0] * scale;

            fileCount += 1;
            Bitmap newImage         = new Bitmap(Image_width, Image_height);
            int    range_num_width  = newImage.Width / range_block_size;
            int    range_num_height = newImage.Height / range_block_size;

            compressCoeff = new Object.Coefficients[range_num_width, range_num_height, 1];
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 1);
                    compressCoeff[i, j, 0].X = tmp[0];
                    fileCount += 1;

                    tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 1);
                    compressCoeff[i, j, 0].Y = tmp[0];
                    fileCount += 1;

                    tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 2);
                    compressCoeff[i, j, 0].shiftR = BitConverter.ToInt16(tmp, 0);
                    fileCount += 2;
                    tmp        = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 2);
                    compressCoeff[i, j, 0].shiftG = BitConverter.ToInt16(tmp, 0);
                    fileCount += 2;
                    tmp        = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 2);
                    compressCoeff[i, j, 0].shiftB = BitConverter.ToInt16(tmp, 0);
                    fileCount += 2;
                }
            }
            //Создаём ранговые блоки
            Object.Block[,] rangeArray = new Object.Block[range_num_width, range_num_height];
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    rangeArray[i, j].X = i * range_block_size;
                    rangeArray[i, j].Y = j * range_block_size;
                }
            }
            //Создаем доменные блоки
            int domain_num_width  = range_num_width - 1;
            int domain_num_height = range_num_height - 1;
            int domain_block_size = range_block_size * 2;

            Object.Block[,] domainArray = new Object.Block[domain_num_width, domain_num_height];
            for (int i = 0; i < domain_num_width; ++i)
            {
                for (int j = 0; j < domain_num_height; ++j)
                {
                    domainArray[i, j].X = i * range_block_size;
                    domainArray[i, j].Y = j * range_block_size;
                }
            }

            for (int it = 0; it < 10; ++it)
            {
                Color[,] newImageColor = new Color[newImage.Width, newImage.Height];
                for (int i = 0; i < newImage.Width; ++i)
                {
                    for (int j = 0; j < newImage.Height; ++j)
                    {
                        newImageColor[i, j] = newImage.GetPixel(i, j);
                    }
                }
                Color[,] rotateNewImageR = newImageColor;

                for (int i = 0; i < range_num_width; ++i)
                {
                    for (int j = 0; j < range_num_height; ++j)
                    {
                        Object.Block        rangeBlock          = rangeArray[i, j];
                        Object.Coefficients current_coefficentR = compressCoeff[i, j, 0];

                        Object.Block domainBlockR = domainArray[current_coefficentR.X, current_coefficentR.Y];
                        for (int pix_x = 0; pix_x < range_block_size; ++pix_x)
                        {
                            for (int pix_y = 0; pix_y < range_block_size; ++pix_y)
                            {
                                Color colorR1 = rotateNewImageR[domainBlockR.X + (pix_x), domainBlockR.Y + (pix_y)];
                                Color colorR  = rotateNewImageR[domainBlockR.X + (pix_x * 2), domainBlockR.Y + (pix_y * 2)];
                                //int R = (int)(U * ((colorR.R + colorR1.R) / 2) + (Current_coefficentR.shiftR));
                                int r = (int)(u * colorR.R + (current_coefficentR.shiftR));
                                if (r < 0)
                                {
                                    r = 0;
                                }
                                if (r > 255)
                                {
                                    r = 255;
                                }
                                Color colorG1 = rotateNewImageR[domainBlockR.X + (pix_x), domainBlockR.Y + (pix_y)];
                                Color colorG  = rotateNewImageR[domainBlockR.X + (pix_x * 2), domainBlockR.Y + (pix_y * 2)];
                                //int G = (int)(U * ((colorG.G + colorG1.G) / 2) + (Current_coefficentR.shiftG));
                                int g = (int)(u * colorG.G + (current_coefficentR.shiftG));
                                if (g < 0)
                                {
                                    g = 0;
                                }
                                if (g > 255)
                                {
                                    g = 255;
                                }

                                Color colorB1 = rotateNewImageR[domainBlockR.X + (pix_x), domainBlockR.Y + (pix_y)];
                                Color colorB  = rotateNewImageR[domainBlockR.X + (pix_x * 2), domainBlockR.Y + (pix_y * 2)];
                                //int B = (int)(U * ((colorB.B + colorB1.B) / 2) + (Current_coefficentR.shiftB));
                                int b = (int)(u * colorB.B + (current_coefficentR.shiftB));
                                if (b < 0)
                                {
                                    b = 0;
                                }
                                if (b > 255)
                                {
                                    b = 255;
                                }

                                Color Newcolor = Color.FromArgb(r, g, b);
                                newImage.SetPixel(rangeBlock.X + pix_x, rangeBlock.Y + pix_y, Newcolor);
                            }
                        }
                    }
                }
            }
            newImage.Save(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Expanded file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
        }
        static public void Decompression()
        {
            System.Console.WriteLine("Decompression dont work");
            return;

            byte[] bytesFile = File.ReadAllBytes(@"C:\Users\dbogdano\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Quad Compression");
            int    fileCount = 0;
            //Коэффициент масштабирования
            int scale = 1;

            Byte[] tmp         = MyConverter.ReadByte(bytesFile, 0, 2);
            int    image_width = BitConverter.ToInt16(tmp, 0) * scale;

            //+
            fileCount += 2;

            tmp = MyConverter.ReadByte(bytesFile, 2, 4);
            int image_height = BitConverter.ToInt16(tmp, 0) * scale;

            //+
            fileCount += 2;

            tmp = MyConverter.ReadByte(bytesFile, 4, 5);
            int range_block_size = tmp[0] * scale;

            //+
            fileCount += 1;

            tmp        = MyConverter.ReadByte(bytesFile, 5, 9);
            fileCount += 4;
            int    listSize = BitConverter.ToInt32(tmp, 0);
            Bitmap newImage = new Bitmap(image_width, image_height);

            Color[,] newImageColor = new Color[newImage.Width, newImage.Height];
            brightnessImage        = new double[newImage.Width, newImage.Height];
            for (int i = 0; i < newImage.Width; ++i)
            {
                for (int j = 0; j < newImage.Height; ++j)
                {
                    brightnessImage[i, j] = newImage.GetPixel(i, j).GetBrightness();
                }
            }

            int range_num_width  = newImage.Width / range_block_size;
            int range_num_height = newImage.Height / range_block_size;

            Object.Block[,] newRangeArray = new Object.Block[range_num_width, range_num_height];
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    newRangeArray[i, j].X = i * range_block_size;
                    newRangeArray[i, j].Y = j * range_block_size;
                }
            }
            rangeTree = new BlockTree[range_num_width, range_num_height];
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    numLock         = 1;
                    rangeTree[i, j] = new BlockTree(newRangeArray[i, j], newRangeArray[i, j].BlockSize);
                }
            }
            //Доменные блоки представлены не в виде деревьев, а в виде трехмерных массивов
            domain_num_width  = range_num_width - 1;
            domain_num_height = range_num_height - 1;
            domain_block_size = range_block_size * 2;
            domainArray       = new Object.Block[domain_num_width, domain_num_height];
            //System.Console.WriteLine(DomainBlocks.Length);
            domainBlocks = new Object.BlockArray[PostProcessing.GetPow(domain_block_size)];
            for (int i = 0; i < domainBlocks.Length; ++i)
            {
                if (i == 0)
                {
                    domainBlocks[i].BlockSize = domain_block_size;
                }
                else
                {
                    domainBlocks[i].BlockSize = domainBlocks[i - 1].BlockSize / 2;
                }
                domainBlocks[i].num_width  = newImage.Width / domainBlocks[i].BlockSize;
                domainBlocks[i].num_height = newImage.Height / domainBlocks[i].BlockSize;
                domainBlocks[i].Blocks     = new Object.Block[domainBlocks[i].num_width, domainBlocks[i].num_height];
                for (int j = 0; j < domainBlocks[i].num_width; ++j)
                {
                    for (int k = 0; k < domainBlocks[i].num_height; ++k)
                    {
                        domainBlocks[i].Blocks[j, k] = CreateBlockDomain(j * domainBlocks[i].BlockSize / 2, k * domainBlocks[i].BlockSize / 2, newImageColor, domainBlocks[i].BlockSize / 2, brightnessImage);
                    }
                }
            }
            List <Object.Coefficients> listCoeff = new List <Object.Coefficients>();

            Object.Coefficients coeff = new Object.Coefficients();
            for (int i = 0; i < listSize; ++i)
            {
                tmp         = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 1);
                coeff.Depth = tmp[0];
                ++fileCount;

                tmp        = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 1);
                coeff.X    = tmp[0];
                fileCount += 1;

                tmp        = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 1);
                coeff.Y    = tmp[0];
                fileCount += 1;

                tmp          = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 2);
                coeff.shiftR = BitConverter.ToInt16(tmp, 0);
                fileCount   += 2;

                tmp          = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 2);
                coeff.shiftG = BitConverter.ToInt16(tmp, 0);
                fileCount   += 2;

                tmp          = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 2);
                coeff.shiftB = BitConverter.ToInt16(tmp, 0);
                fileCount   += 2;
                listCoeff.Add(coeff);
            }
            int blI = 0, blJ = -1;

            for (int i = 0; i < listCoeff.Count; ++i)
            {
                PrintCoefficients(listCoeff[i]);
            }
            for (int i = 0; i < listCoeff.Count; ++i)
            {
                if (listCoeff[i].Depth < 0)
                {
                    ++blJ;
                    if (blJ == range_num_height)
                    {
                        ++blI;
                        blJ = 0;
                    }
                }
                rangeTree[blI, blJ].AddCoeff(rangeTree[blI, blJ], listCoeff[i]);
            }
            //Построение изображения из деревьев
            for (int i = 0; i < 10; ++i)
            {
                for (int j = 0; j < range_num_width; ++j)
                {
                    for (int k = 0; k < range_num_height; ++k)
                    {
                        rangeTree[j, k].DrawTree(rangeTree[j, k], domainBlocks, newImageColor);
                    }
                }
            }
            for (int j = 0; j < newImage.Width; ++j)
            {
                for (int k = 0; k < newImage.Height; ++k)
                {
                    newImage.SetPixel(j, k, newImageColor[j, k]);
                }
            }
            newImage.Save(@"C:\Users\dbogdano\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Quad file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
        }
        public static void Compression(string filename, string quality)
        {
            if (!(File.Exists(filename)))
            {
                System.Console.WriteLine("Файла не существует");
                return;
            }
            //Черно-белый файл или нет
            if (quality == "Black")
            {
                colorflag = 1;
            }
            else
            {
                if (quality == "Color")
                {
                    colorflag = 3;
                }
                else
                {
                    System.Console.WriteLine("Тип выбран не правильно");
                    return;
                }
            }
            Bitmap image = new Bitmap(filename);

            classImageColor = new Color[image.Width, image.Height];
            for (int i = 0; i < image.Width; ++i)
            {
                for (int j = 0; j < image.Height; ++j)
                {
                    classImageColor[i, j] = image.GetPixel(i, j);
                }
            }
            double[,] BrightnessImage = new double[image.Width, image.Height];
            for (int i = 0; i < image.Width; ++i)
            {
                for (int j = 0; j < image.Height; ++j)
                {
                    BrightnessImage[i, j] = image.GetPixel(i, j).GetBrightness();
                }
            }
            //Основной параметр, отвечающий за размеры ранговых блоков
            range_block_size = 128;
            //Создаём ранговые блоки
            range_num_width  = image.Width / range_block_size;
            range_num_height = image.Height / range_block_size;
            rangeArray       = new Object.Block[range_num_width, range_num_height];
            for (int i = 0; i < range_num_width; ++i)
            {
                for (int j = 0; j < range_num_height; ++j)
                {
                    rangeArray[i, j] = CreateBlockRange(i * range_block_size, j * range_block_size, classImageColor, range_block_size, BrightnessImage);
                }
            }
            //Создаем доменные блоки
            domain_num_width  = range_num_width - 1;
            domain_num_height = range_num_height - 1;
            domain_block_size = range_block_size * 2;
            domainArray       = new Object.Block[domain_num_width, domain_num_height];
            for (int i = 0; i < domain_num_width; ++i)
            {
                for (int j = 0; j < domain_num_height; ++j)
                {
                    domainArray[i, j] = CreateBlockDomain(i * range_block_size, j * range_block_size, classImageColor, range_block_size, BrightnessImage);
                }
            }
            //Алгоритм сжатия
            count = 1;
            //Общеее число преобразований
            block_all_num = colorflag * range_num_width * range_num_height;
            compressCoeff = new Object.Coefficients[range_num_width, range_num_height, 1];
            BinaryWriter bw = new BinaryWriter(File.Open(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Compression", FileMode.Create));

            Parallel.For(0, range_num_width, FindCoefficients);
            //Выводим коэффиценты в файл
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Width), 2));
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Height), 2));
            bw.Write(MyConverter.Convert(BitConverter.GetBytes(range_block_size), 1));
            for (int k = 0; k < 1; ++k)
            {
                for (int i = 0; i < range_num_width; ++i)
                {
                    for (int j = 0; j < range_num_height; ++j)
                    {
                        Byte[] X = BitConverter.GetBytes(compressCoeff[i, j, k].X);
                        Byte[] Y = BitConverter.GetBytes(compressCoeff[i, j, k].Y);

                        Byte[] SR = BitConverter.GetBytes(compressCoeff[i, j, k].shiftR);
                        Byte[] SG = BitConverter.GetBytes(compressCoeff[i, j, k].shiftG);
                        Byte[] SB = BitConverter.GetBytes(compressCoeff[i, j, k].shiftB);

                        bw.Write(MyConverter.Convert(X, 1));
                        bw.Write(MyConverter.Convert(Y, 1));
                        bw.Write(MyConverter.Convert(SR, 2));
                        bw.Write(MyConverter.Convert(SG, 2));
                        bw.Write(MyConverter.Convert(SB, 2));
                    }
                }
            }
            bw.Close();
        }