не удается инициализировать ссылку типа "uint16_t &" (aka "unsigned short &") (квалифицируется как неконстантная) со значением типа "bool"
выражение должно быть допустимым для изменения левосторонним значением
выражение должно быть допустимым для изменения левосторонним значением
#pragma once
#include <cstdint>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <cstring>
#include <unordered_map>
#include <algorithm>
namespace png {
    // Структура для хранения изображения
    struct Image {
        uint32_t width;
        uint32_t height;
        std::vector<uint8_t> data; // Формат: RGBA
    };
    // Класс для чтения и записи PNG-файлов
    class PngImage {
    public:
        // Конструктор
        PngImage() : width_(0), height_(0), bit_depth_(8), color_type_(6) {
            makeCRCTable();
        }
        // Функция чтения PNG изображения из файла
        bool read(const std::string& filename) {
            std::ifstream file(filename, std::ios::binary);
            if (!file) {
                std::cerr << "Не удалось открыть файл для чтения: " << filename << "\n";
                return false;
            }
            // Проверяем сигнатуру PNG
            uint8_t png_signature[8];
            file.read(reinterpret_cast<char*>(png_signature), 8);
            uint8_t expected_signature[8] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
            if (memcmp(png_signature, expected_signature, 8) != 0) {
                std::cerr << "Файл не является PNG изображением.\n";
                return false;
            }
            std::vector<uint8_t> idat_data;
            bool ihdr_read = false;
            // Читаем чанки
            while (!file.eof()) {
                // Читаем длину чанка
                uint32_t chunk_length = 0;
                file.read(reinterpret_cast<char*>(&chunk_length), 4);
                chunk_length = swapEndian(chunk_length);
                // Читаем тип чанка
                char chunk_type[5] = { 0 };
                file.read(chunk_type, 4);
                // Если достигли конца файла
                if (file.eof()) {
                    break;
                }
                // Читаем данные чанка
                std::vector<uint8_t> chunk_data(chunk_length);
                file.read(reinterpret_cast<char*>(chunk_data.data()), chunk_length);
                // Читаем CRC
                uint32_t crc = 0;
                file.read(reinterpret_cast<char*>(&crc), 4);
                uint32_t computed_crc = crcFunction(reinterpret_cast<uint8_t*>(chunk_type), 4);
                computed_crc = updateCRC(computed_crc, chunk_data.data(), chunk_data.size());
                if (swapEndian(crc) != computed_crc) {
                    std::cerr << "CRC ошибка в чанке " << chunk_type << ".\n";
                    return false;
                }
                // Обрабатываем разные типы чанков
                if (strcmp(chunk_type, "IHDR") == 0) {
                    // Чанка IHDR должна быть прочитана только один раз
                    if (ihdr_read) {
                        std::cerr << "Найдено более одного чанка IHDR.\n";
                        return false;
                    }
                    ihdr_read = true;
                    // Парсинг IHDR
                    width_ = (chunk_data[0] << 24) | (chunk_data[1] << 16) | (chunk_data[2] << 8) | chunk_data[3];
                    height_ = (chunk_data[4] << 24) | (chunk_data[5] << 16) | (chunk_data[6] << 8) | chunk_data[7];
                    bit_depth_ = chunk_data[8];
                    color_type_ = chunk_data[9];
                    // Поддерживаем только цветовой тип 6 (RGBA) и глубину цвета 8 бит
                    if (color_type_ != 6 || bit_depth_ != 8) {
                        std::cerr << "Поддерживаются только изображения с RGBA и 8 бит на канал.\n";
                        return false;
                    }
                }
                else if (strcmp(chunk_type, "IDAT") == 0) {
                    // Собираем данные IDAT для последующей распаковки
                    idat_data.insert(idat_data.end(), chunk_data.begin(), chunk_data.end());
                }
                else if (strcmp(chunk_type, "IEND") == 0) {
                    // Конец изображения
                    break;
                }
                else {
                    // Пропускаем другие чанки
                    continue;
                }
            }
            if (!ihdr_read) {
                std::cerr << "Не найден чанк IHDR.\n";
                return false;
            }
            // Распаковываем данные IDAT без использования zlib
            std::vector<uint8_t> decompressed_data;
            if (!decompressData(idat_data, decompressed_data)) {
                std::cerr << "Ошибка при распаковке данных изображения.\n";
                return false;
            }
            // Обрабатываем фильтры и получаем пиксельные данные
            if (!processImageData(decompressed_data)) {
                std::cerr << "Ошибка при обработке данных изображения.\n";
                return false;
            }
            std::cout << "PNG файл успешно загружен: " << filename << "\n";
            return true;
        }
        // Функция сохранения PNG изображения в файл
        bool save(const std::string& filename) {
            if (image_.width == 0 || image_.height == 0 || image_.data.empty()) {
                std::cerr << "Данные изображения не инициализированы.\n";
                return false;
            }
            std::ofstream file(filename, std::ios::binary);
            if (!file) {
                std::cerr << "Не удалось открыть файл для записи: " << filename << "\n";
                return false;
            }
            // Запись сигнатуры PNG
            uint8_t png_signature[8] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
            file.write(reinterpret_cast<char*>(png_signature), 8);
            // IHDR данные
            uint8_t ihdr_data[13];
            ihdr_data[0] = (image_.width >> 24) & 0xFF;
            ihdr_data[1] = (image_.width >> 16) & 0xFF;
            ihdr_data[2] = (image_.width >> 8) & 0xFF;
            ihdr_data[3] = image_.width & 0xFF;
            ihdr_data[4] = (image_.height >> 24) & 0xFF;
            ihdr_data[5] = (image_.height >> 16) & 0xFF;
            ihdr_data[6] = (image_.height >> 8) & 0xFF;
            ihdr_data[7] = image_.height & 0xFF;
            ihdr_data[8] = 8;  // Bit depth
            ihdr_data[9] = 6;  // Color type (RGBA)
            ihdr_data[10] = 0; // Compression method
            ihdr_data[11] = 0; // Filter method
            ihdr_data[12] = 0; // Interlace method
            // Запись IHDR
            writeChunk(file, "IHDR", ihdr_data, 13);
            // Подготовка данных изображения с фильтрацией
            std::vector<uint8_t> filtered_data;
            if (!prepareImageData(filtered_data)) {
                std::cerr << "Ошибка при подготовке данных изображения.\n";
                return false;
            }
            // Сжатие данных изображения с использованием DEFLATE
            std::vector<uint8_t> compressed_data;
            if (!compressData(filtered_data, compressed_data)) {
                std::cerr << "Ошибка при сжатии данных изображения.\n";
                return false;
            }
            // Запись IDAT
            writeChunk(file, "IDAT", compressed_data.data(), compressed_data.size());
            // Запись IEND
            writeChunk(file, "IEND", nullptr, 0);
            file.close();
            std::cout << "PNG файл успешно сохранен: " << filename << "\n";
            return true;
        }
        // Устанавливает изображение из структуры Image
        void setImage(const Image& image) {
            image_ = image;
            width_ = image_.width;
            height_ = image_.height;
            bit_depth_ = 8;
            color_type_ = 6;
        }
        // Получить структуру изображения
        Image& getImage() {
            return image_;
        }
        // Установка пикселя в изображении
        void setPixel(uint32_t x, uint32_t y, uint32_t color) {
            if (x >= image_.width || y >= image_.height) {
                std::cerr << "Координаты пикселя (" << x << ", " << y << ") выходят за границы изображения.\n";
                return;
            }
            size_t index = (y * image_.width + x) * 4;
            image_.data[index + 0] = (color >> 24) & 0xFF; // R
            image_.data[index + 1] = (color >> 16) & 0xFF; // G
            image_.data[index + 2] = (color >> 8) & 0xFF;  // B
            image_.data[index + 3] = color & 0xFF;         // A
        }
        // Инициализирует изображение с заданной шириной и высотой
        void initialize(uint32_t width, uint32_t height) {
            width_ = width;
            height_ = height;
            bit_depth_ = 8;
            color_type_ = 6;
            image_.width = width;
            image_.height = height;
            image_.data.resize(width * height * 4, 0);
        }
    private:
        // Функция распаковки данных с использованием DEFLATE
        bool decompressData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            // Проверяем заголовок zlib
            if (input.size() < 2) {
                std::cerr << "Недостаточно данных для проверки заголовка zlib.\n";
                return false;
            }
            // Проверка CMF и FLG
            uint8_t cmf = input[0];
            uint8_t flg = input[1];
            // Проверка метода компрессии (DEFLATE)
            if ((cmf & 0x0F) != 8) {
                std::cerr << "Неподдерживаемый метод компрессии.\n";
                return false;
            }
            // Пропускаем заголовок zlib
            size_t pos = 2;
            // Распаковываем данные DEFLATE
            output.clear();
            if (!inflateData(input, pos, output)) {
                std::cerr << "Ошибка при распаковке DEFLATE.\n";
                return false;
            }
            // Пропускаем Adler-32 (последние 4 байта)
            // Можно добавить проверку Adler-32 при необходимости
            return true;
        }
        // Функция распаковки DEFLATE с использованием фиксированных кодов Хаффмана
        bool inflateData(const std::vector<uint8_t>& input, size_t& pos, std::vector<uint8_t>& output) {
            std::vector<uint8_t> bit_buffer;
            size_t bit_pos = 0;
            // Наполняем битовый буфер
            for (size_t i = pos; i < input.size(); ++i) {
                bit_buffer.push_back(input[i]);
            }
            // Переменная для отслеживания позиции в битовом буфере
            size_t bb_pos = 0;
            bool is_final_block = false;
            while (!is_final_block) {
                // Читаем заголовок блока
                if (!readBits(bit_buffer, bb_pos, 1, is_final_block)) {
                    std::cerr << "Ошибка чтения BFINAL.\n";
                    return false;
                }
                uint16_t btype = 0;
                if (!readBits(bit_buffer, bb_pos, 2, btype)) {
                    std::cerr << "Ошибка чтения BTYPE.\n";
                    return false;
                }
                if (btype == 0) {
                    // Несжатый блок (не реализовано)
                    std::cerr << "Найден несжатый блок. Не поддерживается.\n";
                    return false;
                }
                else if (btype == 1) {
                    // Сжатый блок с фиксированными кодами Хаффмана
                    if (!inflateFixedHuffmanBlock(bit_buffer, bb_pos, output)) {
                        std::cerr << "Ошибка декодирования фиксированного блока Хаффмана.\n";
                        return false;
                    }
                }
                else {
                    // Другие типы блоков не поддерживаются
                    std::cerr << "Неподдерживаемый тип блока: " << btype << ".\n";
                    return false;
                }
            }
            return true;
        }
        // Функция декодирования блока с фиксированными кодами Хаффмана
        bool inflateFixedHuffmanBlock(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, std::vector<uint8_t>& output) {
            while (true) {
                uint16_t symbol;
                if (!decodeSymbol(bit_buffer, bb_pos, symbol)) {
                    std::cerr << "Ошибка декодирования символа.\n";
                    return false;
                }
                if (symbol < 256) {
                    // Литерал
                    output.push_back(static_cast<uint8_t>(symbol));
                }
                else if (symbol == 256) {
                    // Конец блока
                    break;
                }
                else if (symbol >= 257 && symbol <= 285) {
                    // Длина и расстояние
                    int length = 0;
                    int extra_bits = 0;
                    // Получаем длину
                    if (symbol <= 264) {
                        length = symbol - 254;
                    }
                    else if (symbol <= 284) {
                        static const int length_base[] = { 11, 13, 15, 17, 19, 23, 27, 31,
                                                           35, 43, 51, 59, 67, 83, 99, 115,
                                                           131, 163, 195, 227, 258 };
                        static const int length_extra[] = { 1, 1, 1, 1, 2, 2, 2, 2,
                                                            3, 3, 3, 3, 4, 4, 4, 4,
                                                            5, 5, 5, 5, 0 };
                        int index = symbol - 265;
                        length = length_base[index];
                        extra_bits = length_extra[index];
                        uint16_t extra_value = 0;
                        if (!readBits(bit_buffer, bb_pos, extra_bits, extra_value)) {
                            std::cerr << "Ошибка чтения дополнительных битов для длины.\n";
                            return false;
                        }
                        length += extra_value;
                    }
                    else if (symbol == 285) {
                        length = 258;
                    }
                    // Получаем расстояние
                    uint16_t dist_symbol = 0;
                    if (!readBits(bit_buffer, bb_pos, 5, dist_symbol)) {
                        std::cerr << "Ошибка чтения символа расстояния.\n";
                        return false;
                    }
                    int distance = 0;
                    if (dist_symbol <= 3) {
                        distance = dist_symbol + 1;
                    }
                    else if (dist_symbol <= 29) {
                        static const int dist_base[] = { 5, 7, 9, 13, 17, 25, 33, 49,
                                                         65, 97, 129, 193, 257, 385, 513, 769,
                                                         1025, 1537, 2049, 3073, 4097, 6145,
                                                         8193, 12289, 16385, 24577 };
                        static const int dist_extra[] = { 1, 1, 2, 2, 3, 3, 4, 4,
                                                          5, 5, 6, 6, 7, 7, 8, 8,
                                                          9, 9, 10, 10, 11, 11,
                                                          12, 12, 13, 13 };
                        int index = dist_symbol - 4;
                        distance = dist_base[index];
                        extra_bits = dist_extra[index];
                        uint16_t extra_value = 0;
                        if (!readBits(bit_buffer, bb_pos, extra_bits, extra_value)) {
                            std::cerr << "Ошибка чтения дополнительных битов для расстояния.\n";
                            return false;
                        }
                        distance += extra_value;
                    }
                    else {
                        std::cerr << "Недопустимый символ расстояния.\n";
                        return false;
                    }
                    // Копируем данные из предыдущих позиций
                    if (distance > output.size()) {
                        std::cerr << "Расстояние больше, чем доступные данные.\n";
                        return false;
                    }
                    size_t copy_pos = output.size() - distance;
                    for (int i = 0; i < length; ++i) {
                        output.push_back(output[copy_pos++]);
                    }
                }
                else {
                    std::cerr << "Недопустимый символ: " << symbol << ".\n";
                    return false;
                }
            }
            return true;
        }
        // Функция декодирования символа с использованием фиксированных кодов Хаффмана
        bool decodeSymbol(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, uint16_t& symbol) {
            // Таблица кодов для фиксированных кодов Хаффмана
            constexpr int MAX_BITS = 9;
            uint16_t code = 0;
            int bits_read = 0;
            while (bits_read <= MAX_BITS) {
                uint16_t bit = 0;
                if (!readBits(bit_buffer, bb_pos, 1, bit)) {
                    return false;
                }
                code = (code << 1) | bit;
                bits_read++;
                // Проверяем соответствие кода по длине
                if (bits_read >= 7 && bits_read <= 9) {
                    uint16_t base_code = code >> (bits_read - 7);
                    if (bits_read == 7 && base_code >= 0b0000000 && base_code <= 0b0010111) {
                        // Символы 256 - 279
                        symbol = base_code + 256;
                        return true;
                    }
                    else if (bits_read == 8 && base_code >= 0b00110000 && base_code <= 0b10111111) {
                        // Символы 0 - 143
                        symbol = base_code - 0b00110000;
                        return true;
                    }
                    else if (bits_read == 8 && base_code >= 0b11000000 && base_code <= 0b11000111) {
                        // Символы 280 - 287
                        symbol = base_code - 0b11000000 + 280;
                        return true;
                    }
                    else if (bits_read == 9 && base_code >= 0b110010000 && base_code <= 0b111111111) {
                        // Символы 144 - 255
                        symbol = base_code - 0b110010000 + 144;
                        return true;
                    }
                }
            }
            return false;
        }
        // Чтение битов из битового буфера
        bool readBits(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, int num_bits, uint16_t& result) {
            result = 0;
            for (int i = 0; i < num_bits; ++i) {
                if (bb_pos >= bit_buffer.size() * 8) {
                    return false;
                }
                size_t byte_pos = bb_pos / 8;
                uint8_t byte = bit_buffer[byte_pos];
                int bit_offset = bb_pos % 8;
                uint8_t bit = (byte >> bit_offset) & 0x01;
                result |= (bit << i);
                bb_pos++;
            }
            return true;
        }
        // Обработка фильтров PNG и получение пиксельных данных
        bool processImageData(const std::vector<uint8_t>& data) {
            size_t stride = width_ * 4;
            image_.width = width_;
            image_.height = height_;
            image_.data.resize(width_ * height_ * 4);
            size_t src_offset = 0;
            size_t dst_offset = 0;
            for (uint32_t y = 0; y < height_; ++y) {
                if (src_offset >= data.size()) {
                    std::cerr << "Размер данных меньше ожидаемого.\n";
                    return false;
                }
                uint8_t filter_type = data[src_offset++];
                const uint8_t* src_line = &data[src_offset];
                uint8_t* dst_line = &image_.data[dst_offset];
                if (src_offset + stride > data.size()) {
                    std::cerr << "Несоответствие размера данных.\n";
                    return false;
                }
                // Применяем фильтр
                switch (filter_type) {
                case 0: // None
                    memcpy(dst_line, src_line, stride);
                    break;
                case 1: // Sub
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t left = (i >= 4) ? dst_line[i - 4] : 0;
                        dst_line[i] = val + left;
                    }
                    break;
                case 2: // Up
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t up = (y > 0) ? image_.data[dst_offset - stride + i] : 0;
                        dst_line[i] = val + up;
                    }
                    break;
                case 3: // Average
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t left = (i >= 4) ? dst_line[i - 4] : 0;
                        uint8_t up = (y > 0) ? image_.data[dst_offset - stride + i] : 0;
                        dst_line[i] = val + ((left + up) / 2);
                    }
                    break;
                case 4: // Paeth
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t left = (i >= 4) ? dst_line[i - 4] : 0;
                        uint8_t up = (y > 0) ? image_.data[dst_offset - stride + i] : 0;
                        uint8_t up_left = (y > 0 && i >= 4) ? image_.data[dst_offset - stride + i - 4] : 0;
                        dst_line[i] = val + paethPredictor(left, up, up_left);
                    }
                    break;
                default:
                    std::cerr << "Неизвестный тип фильтра: " << static_cast<int>(filter_type) << "\n";
                    return false;
                }
                src_offset += stride;
                dst_offset += stride;
            }
            return true;
        }
        // Подготовка данных изображения с фильтрацией
        bool prepareImageData(std::vector<uint8_t>& output) {
            size_t stride = image_.width * 4;
            size_t total_size = image_.height * (stride + 1);
            output.resize(total_size);
            size_t src_offset = 0;
            size_t dst_offset = 0;
            for (uint32_t y = 0; y < image_.height; ++y) {
                // Здесь мы используем фильтр None (0) для простоты
                // Можно улучшить, применяя оптимальные фильтры для каждой строки
                output[dst_offset++] = 0; // Фильтр None
                memcpy(&output[dst_offset], &image_.data[src_offset], stride);
                src_offset += stride;
                dst_offset += stride;
            }
            return true;
        }
        // Функция сжатия данных с использованием DEFLATE
        bool compressData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            // Формируем zlib заголовок
            uint8_t cmf = 0x78; // Compression Method and Flags: CM = 8, CINFO = 7 (32K window)
            uint8_t flg = 0xDA; // Flags: FCHECK (проверочный код), FDICT, FLEVEL
            output.push_back(cmf);
            output.push_back(flg);
            // Сжимаем данные с использованием DEFLATE с фиксированными кодами Хаффмана
            std::vector<uint8_t> deflate_data;
            if (!deflateData(input, deflate_data)) {
                std::cerr << "Ошибка при сжатии данных DEFLATE.\n";
                return false;
            }
            output.insert(output.end(), deflate_data.begin(), deflate_data.end());
            // Вычисляем Adler-32
            uint32_t adler = computeAdler32(input.data(), input.size());
            output.push_back((adler >> 24) & 0xFF);
            output.push_back((adler >> 16) & 0xFF);
            output.push_back((adler >> 8) & 0xFF);
            output.push_back(adler & 0xFF);
            return true;
        }
        // Функция сжатия данных с использованием DEFLATE с фиксированными кодами Хаффмана
        bool deflateData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            std::vector<uint8_t> bit_buffer;
            // Добавляем заголовок блока
            uint8_t BFINAL = 1; // Последний блок
            uint8_t BTYPE = 1;  // Сжатие с фиксированными кодами Хаффмана
            uint8_t header = (BFINAL) | (BTYPE << 1);
            writeBits(bit_buffer, header, 3);
            // Применяем простой алгоритм LZ77
            size_t pos = 0;
            while (pos < input.size()) {
                size_t match_length = 0;
                size_t match_distance = 0;
                // Поиск наибольшего совпадения
                const size_t window_size = 32768; // 32KB
                size_t search_start = (pos >= window_size) ? pos - window_size : 0;
                size_t max_length = 258; // Максимальная длина
                for (size_t i = search_start; i < pos; ++i) {
                    size_t length = 0;
                    while (length < max_length && pos + length < input.size() && input[i + length] == input[pos + length]) {
                        length++;
                    }
                    if (length > match_length) {
                        match_length = length;
                        match_distance = pos - i;
                        if (length == max_length) {
                            break;
                        }
                    }
                }
                if (match_length >= 3) {
                    // Кодируем длину и расстояние
                    if (!encodeLengthDistance(bit_buffer, match_length, match_distance)) {
                        std::cerr << "Ошибка кодирования длины и расстояния.\n";
                        return false;
                    }
                    pos += match_length;
                }
                else {
                    // Кодируем литерал
                    if (!encodeLiteral(bit_buffer, input[pos])) {
                        std::cerr << "Ошибка кодирования литерала.\n";
                        return false;
                    }
                    pos++;
                }
            }
            // Добавляем символ окончания блока
            if (!encodeEndOfBlock(bit_buffer)) {
                std::cerr << "Ошибка кодирования окончания блока.\n";
                return false;
            }
            // Дополнение до байта нулями
            while (bit_buffer.size() % 8 != 0) {
                bit_buffer.push_back(0);
            }
            // Формируем байтовый буфер из битового буфера
            for (size_t i = 0; i < bit_buffer.size(); i += 8) {
                uint8_t byte = 0;
                for (int j = 0; j < 8 && i + j < bit_buffer.size(); ++j) {
                    byte |= (bit_buffer[i + j] << j);
                }
                output.push_back(byte);
            }
            return true;
        }
        // Функция кодирования литерала с использованием фиксированных кодов Хаффмана
        bool encodeLiteral(std::vector<uint8_t>& bit_buffer, uint16_t symbol) {
            // Определяем код и длину кода для литерала
            uint16_t code;
            int code_length;
            if (symbol <= 143) {
                code = 0b00110000 + symbol;
                code_length = 8;
            }
            else if (symbol <= 255) {
                code = 0b110010000 + (symbol - 144);
                code_length = 9;
            }
            else {
                std::cerr << "Недопустимый символ литерала: " << symbol << ".\n";
                return false;
            }
            writeBits(bit_buffer, code, code_length);
            return true;
        }
        // Функция кодирования длины и расстояния
        bool encodeLengthDistance(std::vector<uint8_t>& bit_buffer, size_t length, size_t distance) {
            // Кодирование длины
            int length_code = 0;
            int length_extra_bits = 0;
            int length_extra = 0;
            if (length >= 3 && length <= 10) {
                length_code = 257 + (length - 3);
                length_extra_bits = 0;
                length_extra = 0;
            }
            else if (length <= 258) {
                // Определяем диапазон длины
                static const int length_base[] = { 11, 13, 15, 17, 19, 23, 27, 31,
                                                   35, 43, 51, 59, 67, 83, 99, 115,
                                                   131, 163, 195, 227, 258 };
                static const int length_extra_bits[] = { 1, 1, 1, 1, 2, 2, 2, 2,
                                                        3, 3, 3, 3, 4, 4, 4, 4,
                                                        5, 5, 5, 5, 0 };
                for (int i = 0; i < 20; ++i) {
                    if (length >= length_base[i] && length <= length_base[i] + (1 << length_extra_bits[i]) - 1) {
                        length_code = 265 + i;
                        length_extra_bits = length_extra_bits[i];
                        length_extra = length - length_base[i];
                        break;
                    }
                }
            }
            else {
                std::cerr << "Недопустимая длина: " << length << ".\n";
                return false;
            }
            // Кодирование символа длины
            if (!encodeSymbol(bit_buffer, length_code)) {
                return false;
            }
            // Запись дополнительных битов длины
            if (length_extra_bits > 0) {
                writeBits(bit_buffer, length_extra, length_extra_bits);
            }
            // Кодирование расстояния
            int dist_code = 0;
            int dist_extra_bits = 0;
            int dist_extra = 0;
            if (distance >= 1 && distance <= 4) {
                dist_code = distance - 1;
                dist_extra_bits = 0;
                dist_extra = 0;
            }
            else if (distance <= 32768) {
                // Определяем диапазон расстояния
                static const int dist_base[] = { 5, 7, 9, 13, 17, 25, 33, 49,
                                                 65, 97, 129, 193, 257, 385, 513, 769,
                                                 1025, 1537, 2049, 3073, 4097, 6145,
                                                 8193, 12289, 16385, 24577 };
                static const int dist_extra_bits[] = { 1, 1, 2, 2, 3, 3, 4, 4,
                                                      5, 5, 6, 6, 7, 7, 8, 8,
                                                      9, 9, 10, 10, 11, 11,
                                                      12, 12, 13, 13 };
                for (int i = 0; i < 26; ++i) {
                    int dist_range = dist_base[i] + (1 << dist_extra_bits[i]) - 1;
                    if (distance >= dist_base[i] && distance <= dist_range) {
                        dist_code = 4 + i;
                        dist_extra_bits = dist_extra_bits[i];
                        dist_extra = distance - dist_base[i];
                        break;
                    }
                }
            }
            else {
                std::cerr << "Недопустимое расстояние: " << distance << ".\n";
                return false;
            }
            // Запись кода расстояния (всегда 5 бит для фиксированных кодов)
            writeBits(bit_buffer, dist_code, 5);
            // Запись дополнительных битов расстояния
            if (dist_extra_bits > 0) {
                writeBits(bit_buffer, dist_extra, dist_extra_bits);
            }
            return true;
        }
        // Функция записи битов в битовый буфер
        void writeBits(std::vector<uint8_t>& bit_buffer, uint16_t value, int num_bits) {
            for (int i = 0; i < num_bits; ++i) {
                uint8_t bit = (value >> i) & 0x01;
                bit_buffer.push_back(bit);
            }
        }
        // Функция кодирования символа с использованием фиксированных кодов Хаффмана
        bool encodeSymbol(std::vector<uint8_t>& bit_buffer, uint16_t symbol) {
            uint16_t code;
            int code_length;
            if (symbol <= 143) {
                code = 0b00110000 + symbol;
                code_length = 8;
            }
            else if (symbol <= 255) {
                code = 0b110010000 + (symbol - 144);
                code_length = 9;
            }
            else if (symbol <= 279) {
                code = symbol - 256;
                code_length = 7;
            }
            else if (symbol <= 287) {
                code = 0b11000000 + (symbol - 280);
                code_length = 8;
            }
            else {
                std::cerr << "Недопустимый символ: " << symbol << ".\n";
                return false;
            }
            writeBits(bit_buffer, code, code_length);
            return true;
        }
        // Функция кодирования символа окончания блока
        bool encodeEndOfBlock(std::vector<uint8_t>& bit_buffer) {
            return encodeSymbol(bit_buffer, 256);
        }
        // Функция записи чанка PNG
        void writeChunk(std::ofstream& file, const char* type, const uint8_t* data, size_t length) {
            uint32_t length_be = swapEndian(static_cast<uint32_t>(length));
            file.write(reinterpret_cast<char*>(&length_be), 4);
            file.write(type, 4);
            if (data && length > 0) {
                file.write(reinterpret_cast<const char*>(data), length);
            }
            // Вычисление CRC
            uint32_t crc = crcFunction(reinterpret_cast<const uint8_t*>(type), 4);
            if (data && length > 0) {
                crc = updateCRC(crc, data, length);
            }
            uint32_t crc_be = swapEndian(crc);
            file.write(reinterpret_cast<char*>(&crc_be), 4);
        }
        // Реализация Paeth предиктора
        uint8_t paethPredictor(int a, int b, int c) const {
            int p = a + b - c;
            int pa = abs(p - a);
            int pb = abs(p - b);
            int pc = abs(p - c);
            if (pa <= pb && pa <= pc)
                return static_cast<uint8_t>(a);
            else if (pb <= pc)
                return static_cast<uint8_t>(b);
            else
                return static_cast<uint8_t>(c);
        }
        // Вычисление Adler-32
        uint32_t computeAdler32(const uint8_t* data, size_t len) const {
            uint32_t a = 1, b = 0;
            const uint32_t MOD_ADLER = 65521;
            for (size_t i = 0; i < len; ++i) {
                a = (a + data[i]) % MOD_ADLER;
                b = (b + a) % MOD_ADLER;
            }
            return (b << 16) | a;
        }
        // Создание таблицы CRC32
        void makeCRCTable() {
            for (uint32_t n = 0; n < 256; n++) {
                uint32_t c = n;
                for (uint32_t k = 0; k < 8; k++) {
                    if (c & 1)
                        c = 0xedb88320L ^ (c >> 1);
                    else
                        c = c >> 1;
                }
                crc_table_[n] = c;
            }
        }
        // Обновление CRC
        uint32_t updateCRC(uint32_t crc, const uint8_t* buf, size_t len) const {
            uint32_t c = crc ^ 0xffffffffL;
            for (size_t n = 0; n < len; n++) {
                c = crc_table_[(c ^ buf[n]) & 0xff] ^ (c >> 8);
            }
            return c ^ 0xffffffffL;
        }
        // Вычисление CRC
        uint32_t crcFunction(const uint8_t* buf, size_t len) const {
            return updateCRC(0, buf, len);
        }
        // Обмен байтами (big-endian <-> little-endian)
        uint32_t swapEndian(uint32_t val) const {
            return ((val >> 24) & 0xFF) |
                ((val >> 8) & 0xFF00) |
                ((val << 8) & 0xFF0000) |
                ((val << 24) & 0xFF000000);
        }
        uint32_t width_;
        uint32_t height_;
        uint8_t bit_depth_;
        uint8_t color_type_;
        Image image_;
        uint32_t crc_table_[256];
    };
} // namespace png