# v# 1258 f# 2492
PNG файл успешно сохранен: output.png
Ошибка при построении динамических таблиц Хаффмана.
Ошибка декодирования динамического блока Хаффмана.
Ошибка при распаковке DEFLATE.
Ошибка при распаковке данных изображения. Код: #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
    };

    // Класс для записи битов в буфер
    class BitWriter {
    public:
        BitWriter() : bit_pos_(0), current_byte_(0) {}
        void writeBits(uint16_t value, int num_bits) {
            for (int i = 0; i < num_bits; ++i) {
                uint8_t bit = (value >> i) & 0x01;
                current_byte_ |= (bit << bit_pos_);
                bit_pos_++;
                if (bit_pos_ == 8) {
                    buffer_.push_back(current_byte_);
                    current_byte_ = 0;
                    bit_pos_ = 0;
                }
            }
        }
        void flush() {
            if (bit_pos_ != 0) {
                buffer_.push_back(current_byte_);
                current_byte_ = 0;
                bit_pos_ = 0;
            }
        }
        const std::vector<uint8_t>& getBuffer() const { return buffer_; }
    private:
        std::vector<uint8_t> buffer_;
        uint8_t current_byte_;
        int bit_pos_;
    };

    // Класс для чтения и записи PNG-файлов
    class PngImage {
    public:
        // Конструктор
        PngImage() : width_(0), height_(0), bit_depth_(8), color_type_(6) {
            makeCRCTable();
            generateFixedHuffmanCodes();
        }

        // Функция чтения 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);
                if (file.eof()) break;
                chunk_length = swapEndian(chunk_length);
                // Читаем тип чанка
                char chunk_type[5] = { 0 };
                file.read(chunk_type, 4);
                // Читаем данные чанка
                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 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;
        }
        // Функция сохранения 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;
        }
        // Подготовка данных изображения с фильтрацией
        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;
        }
        // Устанавливает изображение из структуры Image
        void setImage(const Image& image) {
            image_ = image;
            width_ = image_.width;
            height_ = image_.height;
            bit_depth_ = 8;
            color_type_ = 6;
        }
        // Функция сжатия данных с использованием DEFLATE с фиксированными кодами Хаффмана
        bool deflateData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            BitWriter bit_writer;
            // Добавляем заголовок блока
            uint8_t BFINAL = 1; // Последний блок
            uint8_t BTYPE = 1;  // Сжатие с фиксированными кодами Хаффмана
            bit_writer.writeBits(BFINAL, 1);
            bit_writer.writeBits(BTYPE, 2);
            // Применяем простой алгоритм 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 + 3 < 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_writer, match_length, match_distance)) {
                        std::cerr << "Ошибка кодирования длины и расстояния.\n";
                        return false;
                    }
                    pos += match_length;
                }
                else {
                    // Кодируем литерал
                    if (!encodeSymbol(bit_writer, input[pos], fixedLitCode, fixedLitBits)) {
                        std::cerr << "Ошибка кодирования литерала.\n";
                        return false;
                    }
                    pos++;
                }
            }
            // Добавляем символ окончания блока
            if (!encodeSymbol(bit_writer, 256, fixedLitCode, fixedLitBits)) {
                std::cerr << "Ошибка кодирования окончания блока.\n";
                return false;
            }
            // Дополнение до байта нулями и получение сжатых данных
            bit_writer.flush();
            const std::vector<uint8_t>& compressed_data = bit_writer.getBuffer();
            output.insert(output.end(), compressed_data.begin(), compressed_data.end());
            return true;
        }
        // Функция кодирования символа с использованием фиксированных кодов Хаффмана
        bool encodeSymbol(BitWriter& bit_writer, uint16_t symbol, const uint16_t* codes, const uint8_t* lengths) {
            if (symbol > 287) {
                std::cerr << "Недопустимый символ для кодирования: " << symbol << ".\n";
                return false;
            }
            uint16_t code = codes[symbol];
            uint8_t code_length = lengths[symbol];
            uint16_t reversed_code = reverseBits(code, code_length);
            bit_writer.writeBits(reversed_code, code_length);
            return true;
        }
        // Функция кодирования длины и расстояния
        bool encodeLengthDistance(BitWriter& bit_writer, size_t length, size_t distance) {
            int length_code = 0;
            int length_extra_bits_val = 0;
            int length_extra = 0;
            for (int i = 0; i < 29; ++i) {
                int length_range = length_base[i] + (1 << length_extra_bits[i]) - 1;
                if (length >= length_base[i] && length <= length_range) {
                    length_code = 257 + i;
                    length_extra_bits_val = length_extra_bits[i];
                    length_extra = length - length_base[i];
                    break;
                }
            }
            // Кодирование символа длины
            if (!encodeSymbol(bit_writer, length_code, fixedLitCode, fixedLitBits)) {
                return false;
            }
            // Запись дополнительных битов длины
            if (length_extra_bits_val > 0) {
                bit_writer.writeBits(length_extra, length_extra_bits_val);
            }
            // Кодирование расстояния
            int dist_code = 0;
            int dist_extra_bits_val = 0;
            int dist_extra = 0;
            for (int i = 0; i < 30; ++i) {
                int dist_range = dist_base[i] + (1 << dist_extra_bits[i]) - 1;
                if (distance >= dist_base[i] && distance <= dist_range) {
                    dist_code = i;
                    dist_extra_bits_val = dist_extra_bits[i];
                    dist_extra = distance - dist_base[i];
                    break;
                }
            }
            if (dist_code > 29) {
                std::cerr << "Недопустимый код расстояния: " << dist_code << ".\n";
                return false;
            }
            // Кодирование символа расстояния
            uint16_t reversed_code = reverseBits(fixedDistCode[dist_code], fixedDistBits[dist_code]);
            bit_writer.writeBits(reversed_code, fixedDistBits[dist_code]);
            // Запись дополнительных битов расстояния
            if (dist_extra_bits_val > 0) {
                bit_writer.writeBits(dist_extra, dist_extra_bits_val);
            }
            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 = 0x9C; // 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;
        }
        // Функция записи чанка 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);
        }
        // Получить структуру изображения
        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:
        // Массивы для длины и расстояния
        static constexpr int length_base[29] = {
            3, 4, 5, 6, 7, 8, 9, 10,
            11, 13, 15, 17, 19, 23, 27, 31,
            35, 43, 51, 59, 67, 83, 99, 115,
            131, 163, 195, 227, 258
        };

        static constexpr int length_extra_bits[29] = {
            0, 0, 0, 0, 0, 0, 0, 0,
            1, 1, 1, 1, 2, 2, 2, 2,
            3, 3, 3, 3, 4, 4, 4, 4,
            5, 5, 5, 5, 0
        };

        static constexpr int dist_base[30] = {
            1, 2, 3, 4,
            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 constexpr int dist_extra_bits[30] = {
            0, 0, 0, 0,
            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
        };

        // Функция распаковки данных с использованием 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) {
            // Убедимся, что pos не превышает размер input
            if (pos >= input.size()) {
                std::cerr << "Недостаточно данных для распаковки.\n";
                return false;
            }

            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) {
                uint16_t temp_final_block = 0;
                // Читаем заголовок блока
                if (!readBits(bit_buffer, bb_pos, 1, temp_final_block)) {
                    std::cerr << "Ошибка чтения BFINAL.\n";
                    return false;
                }
                is_final_block = (temp_final_block != 0);
                uint16_t btype = 0;
                if (!readBits(bit_buffer, bb_pos, 2, btype)) {
                    std::cerr << "Ошибка чтения BTYPE.\n";
                    return false;
                }
                if (btype == 0) {
                    // Несжатый блок
                    if (!inflateStoredBlock(bit_buffer, bb_pos, output)) {
                        std::cerr << "Ошибка декодирования несжатого блока.\n";
                        return false;
                    }
                }
                else if (btype == 1) {
                    // Сжатый блок с фиксированными кодами Хаффмана
                    if (!inflateFixedHuffmanBlock(bit_buffer, bb_pos, output)) {
                        std::cerr << "Ошибка декодирования фиксированного блока Хаффмана.\n";
                        return false;
                    }
                }
                else if (btype == 2) {
                    // Сжатый блок с динамическими кодами Хаффмана
                    if (!inflateDynamicHuffmanBlock(bit_buffer, bb_pos, output)) {
                        std::cerr << "Ошибка декодирования динамического блока Хаффмана.\n";
                        return false;
                    }
                }
                else {
                    // Другие типы блоков не поддерживаются
                    std::cerr << "Неподдерживаемый тип блока: " << btype << ".\n";
                    return false;
                }
            }
            return true;
        }

        // Функция декодирования несжатого блока
        bool inflateStoredBlock(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, std::vector<uint8_t>& output) {
            // Выровняем bb_pos на следующий байт
            bb_pos = ((bb_pos + 7) / 8) * 8;
            size_t byte_pos = bb_pos / 8;

            if (byte_pos + 4 > bit_buffer.size()) {
                std::cerr << "Недостаточно данных для чтения заголовка несжатого блока.\n";
                return false;
            }

            uint16_t len = bit_buffer[byte_pos] | (bit_buffer[byte_pos + 1] << 8);
            uint16_t nlen = bit_buffer[byte_pos + 2] | (bit_buffer[byte_pos + 3] << 8);
            byte_pos += 4;
            bb_pos = byte_pos * 8;

            if ((len ^ nlen) != 0xFFFF) {
                std::cerr << "LEN и NLEN не являются дополнениями друг друга.\n";
                return false;
            }

            if (byte_pos + len > bit_buffer.size()) {
                std::cerr << "Недостаточно данных для чтения несжатого блока.\n";
                return false;
            }

            output.insert(output.end(), bit_buffer.begin() + byte_pos, bit_buffer.begin() + byte_pos + len);
            bb_pos += len * 8;
            return true;
        }

        // Функция декодирования блока с фиксированными кодами Хаффмана
        bool inflateFixedHuffmanBlock(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, std::vector<uint8_t>& output) {
            // Используем ранее сгенерированные фиксированные таблицы кодов
            return decodeHuffmanBlock(bit_buffer, bb_pos, output, fixedLitBitsToSymbol, fixedDistBitsToSymbol);
        }

        // Функция декодирования блока с динамическими кодами Хаффмана
        bool inflateDynamicHuffmanBlock(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, std::vector<uint8_t>& output) {
            // Парсим заголовок для получения кодовых длин кодов литер/длин и расстояний
            std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>> litLenBitsToSymbol;
            std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>> distBitsToSymbol;

            if (!buildDynamicHuffmanTables(bit_buffer, bb_pos, litLenBitsToSymbol, distBitsToSymbol)) {
                std::cerr << "Ошибка при построении динамических таблиц Хаффмана.\n";
                return false;
            }

            return decodeHuffmanBlock(bit_buffer, bb_pos, output, litLenBitsToSymbol, distBitsToSymbol);
        }

        // Функция построения динамических таблиц Хаффмана
        bool buildDynamicHuffmanTables(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos,
            std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>>& litLenBitsToSymbol,
            std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>>& distBitsToSymbol) {

            uint16_t HLIT = 0, HDIST = 0, HCLEN = 0;
            if (!readBits(bit_buffer, bb_pos, 5, HLIT)) {
                return false;
            }
            HLIT += 257;
            if (!readBits(bit_buffer, bb_pos, 5, HDIST)) {
                return false;
            }
            HDIST += 1;
            if (!readBits(bit_buffer, bb_pos, 4, HCLEN)) {
                return false;
            }
            HCLEN += 4;

            // Порядок кодовых длин кодов кода кодовых длин
            static const int code_length_order[19] = {
                16, 17, 18, 0, 8, 7, 9, 6,
                10, 5, 11, 4, 12, 3, 13, 2,
                14, 1, 15
            };

            // Читаем кодовые длины кодов кодовых длин
            uint8_t code_length_codes_lengths[19] = { 0 };
            for (int i = 0; i < HCLEN; ++i) {
                uint16_t len = 0;
                if (!readBits(bit_buffer, bb_pos, 3, len)) {
                    return false;
                }
                if (code_length_order[i] < 19) {
                    code_length_codes_lengths[code_length_order[i]] = static_cast<uint8_t>(len);
                }
                else {
                    std::cerr << "Некорректный индекс в code_length_order: " << code_length_order[i] << "\n";
                    return false;
                }
            }

            // Строим дерево для кодовых длин
            std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>> codeLengthBitsToSymbol;
            if (!buildHuffmanTree(code_length_codes_lengths, 19, codeLengthBitsToSymbol)) {
                return false;
            }

            // Объединяем кодовые длины литер/длин и расстояний
            std::vector<uint8_t> code_lengths;
            int total_codes = HLIT + HDIST;
            int i = 0;
            while (i < total_codes) {
                uint16_t symbol;
                if (!decodeSymbol(bit_buffer, bb_pos, symbol, codeLengthBitsToSymbol)) {
                    return false;
                }
                if (symbol <= 15) {
                    code_lengths.push_back(static_cast<uint8_t>(symbol));
                    ++i;
                }
                else if (symbol == 16) {
                    if (code_lengths.empty()) {
                        std::cerr << "Символ повторения без предыдущей длины кода.\n";
                        return false;
                    }
                    uint16_t repeat_count = 0;
                    if (!readBits(bit_buffer, bb_pos, 2, repeat_count)) {
                        return false;
                    }
                    repeat_count += 3;
                    uint8_t last_length = code_lengths.back();
                    for (uint16_t j = 0; j < repeat_count && i < total_codes; ++j) {
                        code_lengths.push_back(last_length);
                        ++i;
                    }
                }
                else if (symbol == 17) {
                    uint16_t repeat_count = 0;
                    if (!readBits(bit_buffer, bb_pos, 3, repeat_count)) {
                        return false;
                    }
                    repeat_count += 3;
                    for (uint16_t j = 0; j < repeat_count && i < total_codes; ++j) {
                        code_lengths.push_back(0);
                        ++i;
                    }
                }
                else if (symbol == 18) {
                    uint16_t repeat_count = 0;
                    if (!readBits(bit_buffer, bb_pos, 7, repeat_count)) {
                        return false;
                    }
                    repeat_count += 11;
                    for (uint16_t j = 0; j < repeat_count && i < total_codes; ++j) {
                        code_lengths.push_back(0);
                        ++i;
                    }
                }
                else {
                    std::cerr << "Недопустимый символ при декодировании кодовых длин: " << symbol << "\n";
                    return false;
                }
            }

            if (code_lengths.size() != static_cast<size_t>(total_codes)) {
                std::cerr << "Неверное количество кодовых длин.\n";
                return false;
            }

            // Разделяем кодовые длины на литер/длины и расстояния
            std::vector<uint8_t> litLenCodeLengths(code_lengths.begin(), code_lengths.begin() + HLIT);
            std::vector<uint8_t> distCodeLengths(code_lengths.begin() + HLIT, code_lengths.end());

            // Проверяем максимальную длину кода
            for (uint8_t len : litLenCodeLengths) {
                if (len > 15) {
                    std::cerr << "Длина кода литер/длин превышает допустимое значение: " << static_cast<int>(len) << "\n";
                    return false;
                }
            }
            for (uint8_t len : distCodeLengths) {
                if (len > 15) {
                    std::cerr << "Длина кода расстояния превышает допустимое значение: " << static_cast<int>(len) << "\n";
                    return false;
                }
            }

            // Строим деревья Хаффмана для литер/длин и расстояний
            if (!buildHuffmanTree(litLenCodeLengths.data(), litLenCodeLengths.size(), litLenBitsToSymbol)) {
                return false;
            }
            if (!buildHuffmanTree(distCodeLengths.data(), distCodeLengths.size(), distBitsToSymbol)) {
                return false;
            }

            return true;
        }

        // Функция построения дерева Хаффмана
        bool buildHuffmanTree(const uint8_t* code_lengths, size_t num_codes,
            std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>>& bitsToSymbol) {

            uint16_t bl_count[16] = { 0 };
            for (size_t i = 0; i < num_codes; ++i) {
                if (code_lengths[i] > 15) {
                    std::cerr << "Длина кода превышает 15 бит: " << static_cast<int>(code_lengths[i]) << "\n";
                    return false;
                }
                bl_count[code_lengths[i]]++;
            }

            // Проверяем, есть ли ненулевые длины кодов
            size_t total_symbols = 0;
            for (int bits = 1; bits <= 15; bits++) {
                total_symbols += bl_count[bits];
            }
            if (total_symbols == 0) {
                // Нет символов для построения дерева
                return true; // Возвращаем true, но дерево остается пустым
            }

            uint16_t next_code[16] = { 0 };
            uint16_t code = 0;
            bl_count[0] = 0;

            for (int bits = 1; bits <= 15; bits++) {
                code = (code + bl_count[bits - 1]) << 1;
                next_code[bits] = code;
            }

            for (size_t i = 0; i < num_codes; ++i) {
                uint8_t len = code_lengths[i];
                if (len != 0) {
                    uint16_t code_value = next_code[len];
                    uint16_t reversed_code = reverseBits(code_value, len);
                    bitsToSymbol[len][reversed_code] = static_cast<uint16_t>(i);
                    next_code[len]++;
                }
            }

            return true;
        }

        // Универсальная функция декодирования блока Хаффмана
        bool decodeHuffmanBlock(const std::vector<uint8_t>& bit_buffer, size_t& bb_pos, std::vector<uint8_t>& output,
            const std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>>& litLenBitsToSymbol,
            const std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>>& distBitsToSymbol) {

            bool has_dist_tree = !distBitsToSymbol.empty();

            while (true) {
                uint16_t symbol;
                // Декодирование символа литерала/длины
                if (!decodeSymbol(bit_buffer, bb_pos, symbol, litLenBitsToSymbol)) {
                    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) {
                    // Длина и расстояние
                    if (!has_dist_tree) {
                        std::cerr << "Ошибка: обнаружен символ длины, но дерево расстояний отсутствует.\n";
                        return false;
                    }
                    int length = 0;
                    int extra_bits = 0;
                    // Получаем длину
                    int length_index = symbol - 257;
                    length = length_base[length_index];
                    extra_bits = length_extra_bits[length_index];
                    if (extra_bits > 0) {
                        uint16_t extra_value = 0;
                        if (!readBits(bit_buffer, bb_pos, extra_bits, extra_value)) {
                            std::cerr << "Ошибка чтения дополнительных битов для длины.\n";
                            return false;
                        }
                        length += extra_value;
                    }
                    // Получаем расстояние
                    uint16_t dist_symbol = 0;
                    // Декодирование символа расстояния
                    if (!decodeSymbol(bit_buffer, bb_pos, dist_symbol, distBitsToSymbol)) {
                        std::cerr << "Ошибка декодирования символа расстояния.\n";
                        return false;
                    }
                    int distance = 0;
                    int dist_extra_bits_val = 0;
                    if (dist_symbol <= 29) {
                        distance = dist_base[dist_symbol];
                        dist_extra_bits_val = dist_extra_bits[dist_symbol];
                        if (dist_extra_bits_val > 0) {
                            uint16_t extra_value = 0;
                            if (!readBits(bit_buffer, bb_pos, dist_extra_bits_val, extra_value)) {
                                std::cerr << "Ошибка чтения дополнительных битов для расстояния.\n";
                                return false;
                            }
                            distance += extra_value;
                        }
                    }
                    else {
                        std::cerr << "Недопустимый символ расстояния: " << dist_symbol << ".\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 + i]);
                    }
                }
                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,
            const std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>>& bitsToSymbol) {
            uint32_t code = 0;
            for (int bits_read = 1; bits_read <= 15; ++bits_read) {
                uint16_t bit = 0;
                if (!readBits(bit_buffer, bb_pos, 1, bit)) {
                    return false;
                }
                code = (code << 1) | bit;

                if (bitsToSymbol.count(bits_read) > 0 && bitsToSymbol.at(bits_read).count(code) > 0) {
                    symbol = bitsToSymbol.at(bits_read).at(code);
                    return true;
                }
            }
            // Не удалось найти соответствие кода символу
            return false;
        }

        // Функция переворота битов в коде
        uint16_t reverseBits(uint16_t code, int length) {
            uint16_t reversed = 0;
            for (int i = 0; i < length; ++i) {
                reversed = (reversed << 1) | (code & 1);
                code >>= 1;
            }
            return reversed;
        }

        // Чтение битов из битового буфера
        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 = 7 - (bb_pos % 8);
                uint8_t bit = (byte >> bit_offset) & 0x01;
                result = (result << 1) | bit;
                bb_pos++;
            }
            return true;
        }

        // Остальной код остается без изменений...

        // Реализация 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);
        }

        // Генерация кодов фиксированного Хаффмана
        void generateFixedHuffmanCodes() {
            // Инициализация длин кодов
            for (int i = 0; i <= 287; ++i) {
                if (i <= 143) {
                    fixedLitBits[i] = 8;
                }
                else if (i <= 255) {
                    fixedLitBits[i] = 9;
                }
                else if (i <= 279) {
                    fixedLitBits[i] = 7;
                }
                else {
                    fixedLitBits[i] = 8;
                }
            }

            // Генерация кодов для литералов/длин
            uint16_t bl_count[16] = { 0 };
            for (int i = 0; i <= 287; ++i) {
                bl_count[fixedLitBits[i]]++;
            }

            uint16_t next_code[16] = { 0 };
            uint16_t code = 0;
            bl_count[0] = 0;

            for (int bits = 1; bits <= 15; bits++) {
                code = (code + bl_count[bits - 1]) << 1;
                next_code[bits] = code;
            }

            for (int i = 0; i <= 287; ++i) {
                uint8_t len = fixedLitBits[i];
                if (len != 0) {
                    fixedLitCode[i] = next_code[len];

                    // Создаем таблицу для декодирования
                    fixedLitBitsToSymbol[len][fixedLitCode[i]] = i;
                    next_code[len]++;
                }
            }

            // Генерация кодов для расстояний
            for (int i = 0; i <= 29; i++) {
                fixedDistBits[i] = 5;
                fixedDistCode[i] = i;

                // Создаем таблицу для декодирования
                fixedDistBitsToSymbol[5][fixedDistCode[i]] = i;
            }
        }

        uint32_t width_;
        uint32_t height_;
        uint8_t bit_depth_;
        uint8_t color_type_;
        Image image_;
        uint32_t crc_table_[256];

        // Таблицы для фиксированных кодов Хаффмана
        uint16_t fixedLitCode[288];
        uint8_t fixedLitBits[288];
        std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>> fixedLitBitsToSymbol;

        uint16_t fixedDistCode[30];
        uint8_t fixedDistBits[30];
        std::unordered_map<int, std::unordered_map<uint16_t, uint16_t>> fixedDistBitsToSymbol;
    };
} // namespace png