Перенеси в png_backup поддержку RGB и RGBA, поддержку динамических таблиц кодов Хаффмана. Так же возможно ты заметишь ещё что то что я улучшил в png_zlib, но нету в png_backup. Zlib не считается за улучшение, просто я сдался делать свой DEFLATE, но если ты его доделаешь я буду рад. 
png_zlib.h :
#pragma once 
#include <cstdint>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <cstring>
#include <algorithm>
#include "zlib/zlib.h"
namespace png {
    struct Image {
        uint32_t width;
        uint32_t height;
        uint8_t channels; 
        std::vector<uint8_t> data; 
    };
    class PngImage {
    public:
        PngImage() : width_(0), height_(0), bit_depth_(8), color_type_(6), channels_(4) {}
        bool read(const std::string& filename) {
            std::ifstream file(filename, std::ios::binary);
            if (!file) {
                std::cerr << "Не удалось открыть файл для чтения: " << filename << "\n";
                return false;
            }
            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 (true) {
                uint32_t chunk_length = 0;
                if (!file.read(reinterpret_cast<char*>(&chunk_length), 4)) break;
                chunk_length = swapEndian(chunk_length);
                char chunk_type[5] = { 0 };
                if (!file.read(chunk_type, 4)) break;
                if (chunk_length > 0x7fffffff) {
                    std::cerr << "Некорректная длина чанка: " << chunk_length << ".\n";
                    return false;
                }
                std::vector<uint8_t> chunk_data(chunk_length);
                if (chunk_length > 0) {
                    if (!file.read(reinterpret_cast<char*>(chunk_data.data()), chunk_length)) break;
                }
                uint32_t crc = 0;
                if (!file.read(reinterpret_cast<char*>(&crc), 4)) break;
                crc = swapEndian(crc);
                uint32_t computed_crc = crc32(0L, Z_NULL, 0);
                computed_crc = crc32(computed_crc, reinterpret_cast<const uint8_t*>(chunk_type), 4);
                if (chunk_length > 0) {
                    computed_crc = crc32(computed_crc, chunk_data.data(), chunk_length);
                }
                if (crc != computed_crc) {
                    std::cerr << "CRC ошибка в чанке " << chunk_type << ".\n";
                    return false;
                }
                if (strcmp(chunk_type, "IHDR") == 0) {
                    if (ihdr_read) {
                        std::cerr << "Найдено более одного чанка IHDR.\n";
                        return false;
                    }
                    ihdr_read = true;
                    if (chunk_length != 13) {
                        std::cerr << "Некорректная длина чанка IHDR.\n";
                        return false;
                    }
                    width_ = readUInt32BE(chunk_data.data());
                    height_ = readUInt32BE(chunk_data.data() + 4);
                    bit_depth_ = chunk_data[8];
                    color_type_ = chunk_data[9];
                    if (bit_depth_ != 8) {
                        std::cerr << "Поддерживаются только 8-битные изображения.\n";
                        return false;
                    }
                    if (color_type_ == 2) {
                        std::cout << "\nЦветовой тип: RGB\n";
                        channels_ = 3; 
                    }
                    else if (color_type_ == 6) {
                        std::cout << "\nЦветовой тип: RGBA\n";
                        channels_ = 4; 
                    }
                    else {
                        std::cerr << "Поддерживаются только цветовые типы RGB и RGBA.\n";
                        return false;
                    }
                }
                else if (strcmp(chunk_type, "IDAT") == 0) {
                    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;
            }
            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;
        }
        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;
            }
            uint8_t png_signature[8] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
            file.write(reinterpret_cast<char*>(png_signature), 8);
            uint8_t ihdr_data[13];
            writeUInt32BE(ihdr_data, image_.width);
            writeUInt32BE(ihdr_data + 4, image_.height);
            ihdr_data[8] = 8;  
            ihdr_data[9] = (image_.channels == 4) ? 6 : 2;  
            ihdr_data[10] = 0; 
            ihdr_data[11] = 0; 
            ihdr_data[12] = 0; 
            writeChunk(file, "IHDR", ihdr_data, 13);
            std::vector<uint8_t> filtered_data;
            if (!prepareImageData(filtered_data)) {
                std::cerr << "Ошибка при подготовке данных изображения.\n";
                return false;
            }
            std::vector<uint8_t> compressed_data;
            if (!compressData(filtered_data, compressed_data)) {
                std::cerr << "Ошибка при сжатии данных изображения.\n";
                return false;
            }
            writeChunk(file, "IDAT", compressed_data.data(), compressed_data.size());
            writeChunk(file, "IEND", nullptr, 0);
            file.close();
            std::cout << "PNG файл успешно сохранен: " << filename << "\n";
            return true;
        }
        void setImage(const Image& image) {
            image_ = image;
            width_ = image_.width;
            height_ = image_.height;
            bit_depth_ = 8;
            channels_ = image_.channels;
            color_type_ = (channels_ == 4) ? 6 : 2;
        }
        Image& getImage() {
            return image_;
        }
        void flipVertically() {
            if (image_.data.empty()) {
                std::cerr << "Данные изображения не инициализированы.\n";
                return;
            }
            size_t stride = width_ * channels_;
            size_t half_height = height_ / 2;
            for (size_t y = 0; y < half_height; ++y) {
                size_t top = y * stride;
                size_t bottom = (height_ - 1 - y) * stride;
                std::swap_ranges(image_.data.begin() + top, image_.data.begin() + top + stride, image_.data.begin() + bottom);
            }
        }
        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) * image_.channels;
            if (image_.channels == 4) {
                image_.data[index + 0] = (color >> 24) & 0xFF; 
                image_.data[index + 1] = (color >> 16) & 0xFF; 
                image_.data[index + 2] = (color >> 8) & 0xFF;  
                image_.data[index + 3] = color & 0xFF;         
            }
            else if (image_.channels == 3) {
                image_.data[index + 0] = (color >> 16) & 0xFF; 
                image_.data[index + 1] = (color >> 8) & 0xFF;  
                image_.data[index + 2] = color & 0xFF;         
            }
        }
        void initialize(uint32_t width, uint32_t height, bool has_alpha = true) {
            width_ = width;
            height_ = height;
            bit_depth_ = 8;
            channels_ = has_alpha ? 4 : 3;
            color_type_ = has_alpha ? 6 : 2;
            image_.width = width;
            image_.height = height;
            image_.channels = channels_;
            image_.data.resize(width * height * channels_, 0);
        }
    private:
        uint32_t readUInt32BE(const uint8_t* data) const {
            return (static_cast<uint32_t>(data[0]) << 24) |
                (static_cast<uint32_t>(data[1]) << 16) |
                (static_cast<uint32_t>(data[2]) << 8) |
                static_cast<uint32_t>(data[3]);
        }
        void writeUInt32BE(uint8_t* data, uint32_t value) const {
            data[0] = (value >> 24) & 0xFF;
            data[1] = (value >> 16) & 0xFF;
            data[2] = (value >> 8) & 0xFF;
            data[3] = value & 0xFF;
        }
        bool decompressData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            z_stream strm = {};
            strm.next_in = const_cast<Bytef*>(input.data());
            strm.avail_in = input.size();
            if (inflateInit(&strm) != Z_OK) {
                return false;
            }
            const size_t bufferSize = 16384;
            uint8_t buffer[bufferSize];
            int ret;
            do {
                strm.next_out = buffer;
                strm.avail_out = bufferSize;
                ret = inflate(&strm, Z_NO_FLUSH);
                if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
                    inflateEnd(&strm);
                    return false;
                }
                size_t have = bufferSize - strm.avail_out;
                output.insert(output.end(), buffer, buffer + have);
            } while (ret != Z_STREAM_END);
            inflateEnd(&strm);
            return ret == Z_STREAM_END;
        }
        bool processImageData(const std::vector<uint8_t>& data) {
            size_t bytesPerPixel = channels_;
            size_t stride = width_ * bytesPerPixel;
            image_.width = width_;
            image_.height = height_;
            image_.channels = channels_;
            image_.data.resize(width_ * height_ * bytesPerPixel);
            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:
                    memcpy(dst_line, src_line, stride);
                    break;
                case 1:
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t left = (i >= bytesPerPixel) ? dst_line[i - bytesPerPixel] : 0;
                        dst_line[i] = val + left;
                    }
                    break;
                case 2:
                    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:
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t left = (i >= bytesPerPixel) ? dst_line[i - bytesPerPixel] : 0;
                        uint8_t up = (y > 0) ? image_.data[dst_offset - stride + i] : 0;
                        dst_line[i] = val + static_cast<uint8_t>((left + up) / 2);
                    }
                    break;
                case 4:
                    for (size_t i = 0; i < stride; ++i) {
                        uint8_t val = src_line[i];
                        uint8_t left = (i >= bytesPerPixel) ? dst_line[i - bytesPerPixel] : 0;
                        uint8_t up = (y > 0) ? image_.data[dst_offset - stride + i] : 0;
                        uint8_t up_left = (y > 0 && i >= bytesPerPixel) ? image_.data[dst_offset - stride + i - bytesPerPixel] : 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 bytesPerPixel = channels_;
            size_t stride = image_.width * bytesPerPixel;
            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) {
                output[dst_offset++] = 0; 
                memcpy(&output[dst_offset], &image_.data[src_offset], stride);
                src_offset += stride;
                dst_offset += stride;
            }
            return true;
        }
        bool compressData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            z_stream strm = {};
            if (deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) {
                return false;
            }
            strm.next_in = const_cast<Bytef*>(input.data());
            strm.avail_in = input.size();
            const size_t bufferSize = 16384;
            uint8_t buffer[bufferSize];
            int ret;
            do {
                strm.next_out = buffer;
                strm.avail_out = bufferSize;
                ret = deflate(&strm, Z_FINISH);
                if (ret == Z_STREAM_ERROR) {
                    deflateEnd(&strm);
                    return false;
                }
                size_t have = bufferSize - strm.avail_out;
                output.insert(output.end(), buffer, buffer + have);
            } while (ret != Z_STREAM_END);
            deflateEnd(&strm);
            return ret == Z_STREAM_END;
        }
        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);
            }
            uint32_t crc = crc32(0L, Z_NULL, 0);
            crc = crc32(crc, reinterpret_cast<const unsigned char*>(type), 4);
            if (length > 0 && data) {
                crc = crc32(crc, data, length);
            }
            uint32_t crc_be = swapEndian(crc);
            file.write(reinterpret_cast<char*>(&crc_be), 4);
        }
        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);
        }
        uint32_t swapEndian(uint32_t val) const {
            return ((val & 0x000000FF) << 24) |
                ((val & 0x0000FF00) << 8) |
                ((val & 0x00FF0000) >> 8) |
                ((val & 0xFF000000) >> 24);
        }
        uint32_t width_;
        uint32_t height_;
        uint8_t bit_depth_;
        uint8_t color_type_;
        uint8_t channels_; 
        Image image_;
    };
}
png_backup.h:
#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; 
    };
    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_;
    };
    class PngImage {
    public:
        PngImage() : width_(0), height_(0), bit_depth_(8), color_type_(6) {
            makeCRCTable();
            generateFixedHuffmanCodes();
        }
        bool read(const std::string& filename) {
            std::ifstream file(filename, std::ios::binary);
            if (!file) {
                std::cerr << "Не удалось открыть файл для чтения: " << filename << "\n";
                return false;
            }
            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);
                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) {
                    if (ihdr_read) {
                        std::cerr << "Найдено более одного чанка IHDR.\n";
                        return false;
                    }
                    ihdr_read = true;
                    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];
                    if (color_type_ != 6 || bit_depth_ != 8) {
                        std::cerr << "Поддерживаются только изображения с RGBA и 8 бит на канал.\n";
                        return false;
                    }
                }
                else if (strcmp(chunk_type, "IDAT") == 0) {
                    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;
            }
            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;
        }
        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;
            }
            uint8_t png_signature[8] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
            file.write(reinterpret_cast<char*>(png_signature), 8);
            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;  
            ihdr_data[9] = 6;  
            ihdr_data[10] = 0; 
            ihdr_data[11] = 0; 
            ihdr_data[12] = 0; 
            writeChunk(file, "IHDR", ihdr_data, 13);
            std::vector<uint8_t> filtered_data;
            if (!prepareImageData(filtered_data)) {
                std::cerr << "Ошибка при подготовке данных изображения.\n";
                return false;
            }
            std::vector<uint8_t> compressed_data;
            if (!compressData(filtered_data, compressed_data)) {
                std::cerr << "Ошибка при сжатии данных изображения.\n";
                return false;
            }
            writeChunk(file, "IDAT", compressed_data.data(), compressed_data.size());
            writeChunk(file, "IEND", nullptr, 0);
            file.close();
            std::cout << "PNG файл успешно сохранен: " << filename << "\n";
            return true;
        }
        void setImage(const Image& image) {
            image_ = image;
            width_ = image_.width;
            height_ = image_.height;
            bit_depth_ = 8;
            color_type_ = 6;
        }
        Image& getImage() {
            return image_;
        }
        void flipVertically() {
            if (image_.data.empty()) {
                std::cerr << "Данные изображения не инициализированы.\n";
                return;
            }
            size_t stride = width_ * 4; 
            size_t half_height = height_ / 2;
            for (size_t y = 0; y < half_height; ++y) {
                size_t top = y * stride;
                size_t bottom = (height_ - 1 - y) * stride;
                std::swap_ranges(image_.data.begin() + top, image_.data.begin() + top + stride, image_.data.begin() + bottom);
            }
        }
        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; 
            image_.data[index + 1] = (color >> 16) & 0xFF; 
            image_.data[index + 2] = (color >> 8) & 0xFF;  
            image_.data[index + 3] = color & 0xFF;         
        }
        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
        };
        bool decompressData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            if (input.size() < 2) {
                std::cerr << "Недостаточно данных для проверки заголовка zlib.\n";
                return false;
            }
            uint8_t cmf = input[0];
            uint8_t flg = input[1];
            if ((cmf & 0x0F) != 8) {
                std::cerr << "Неподдерживаемый метод компрессии.\n";
                return false;
            }
            size_t pos = 2;
            output.clear();
            if (!inflateData(input, pos, output)) {
                std::cerr << "Ошибка при распаковке DEFLATE.\n";
                return false;
            }
            return true;
        }
        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) {
                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) {
                    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, fixedLitBits, fixedLitBitsToSymbol)) {
                    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;
                    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, fixedDistBits, fixedDistBitsToSymbol)) {
                        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 uint8_t* code_lengths, 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 |= (bit << (bits_read - 1));
                uint16_t code_reversed = reverseBits(code, bits_read);
                if (bitsToSymbol.count(bits_read) > 0 && bitsToSymbol.at(bits_read).count(code_reversed) > 0) {
                    symbol = bitsToSymbol.at(bits_read).at(code_reversed);
                    return true;
                }
            }
            return false;
        }
        uint16_t reverseBits(uint16_t code, int length) {
            uint16_t reversed = 0;
            for (int i = 0; i < length; ++i) {
                reversed |= ((code >> i) & 1) << (length - i - 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 = bb_pos % 8;
                uint8_t bit = (byte >> bit_offset) & 0x01;
                result |= (bit << i);
                bb_pos++;
            }
            return true;
        }
        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: 
                    memcpy(dst_line, src_line, stride);
                    break;
                case 1: 
                    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: 
                    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: 
                    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: 
                    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 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;
        }
        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) {
                output[dst_offset++] = 0; 
                memcpy(&output[dst_offset], &image_.data[src_offset], stride);
                src_offset += stride;
                dst_offset += stride;
            }
            return true;
        }
        bool compressData(const std::vector<uint8_t>& input, std::vector<uint8_t>& output) {
            uint8_t cmf = 0x78; 
            uint8_t flg = 0x9C; 
            output.push_back(cmf);
            output.push_back(flg);
            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());
            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;
        }
        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);
            size_t pos = 0;
            while (pos < input.size()) {
                size_t match_length = 0;
                size_t match_distance = 0;
                const size_t window_size = 32768; 
                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;
        }
        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);
            }
            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);
        }
        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);
        }
        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;
        }
        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;
            }
        }
        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;
        }
        uint32_t crcFunction(const uint8_t* buf, size_t len) const {
            return updateCRC(0, buf, len);
        }
        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;
    };
}