// Write the BMP image to a file
bool Bitmap::write(std::string fileName) {
    std::ofstream file(fileName, std::ios::binary);

    if (!file) {
        std::cerr << "Error: Could not open file for writing." << std::endl;
        return 0;
    }

    file.write("BM", 2);

    bmpFileHeader header;
    header.bmpOffset = 2 + sizeof(bmpFileHeader) + sizeof(bmpFileDibInfo);

    bmpFileDibInfo dibInfo = {0};
    dibInfo.headerSize = sizeof(bmpFileDibInfo);
    dibInfo.width = pixels[0].size();
    dibInfo.height = pixels.size();
    dibInfo.planes = 1;

    if (isGrayscale) {
        dibInfo.bitsPerPixel = 8;
        dibInfo.compression = 0;
        dibInfo.imageSize = dibInfo.width * dibInfo.height;
        dibInfo.colorsUsed = 256;
    } else {
        dibInfo.bitsPerPixel = 24;
        dibInfo.imageSize = dibInfo.width * dibInfo.height * 3;
        dibInfo.colorsUsed = 0;
    }

    dibInfo.xPixelsPerMeter = 2834;
    dibInfo.yPixelsPerMeter = 2834;
    dibInfo.importantColors = 0;

    if (dibInfo.bitsPerPixel == 8) {
        header.bmpOffset += 256 * 4;  // +Color palette (256 colors, 4 bytes each)
        header.fileSize = header.bmpOffset + (dibInfo.width * dibInfo.height + dibInfo.width % 4) * dibInfo.height;
    } else {
        header.fileSize = header.bmpOffset + (dibInfo.width * 3 + dibInfo.width % 4) * dibInfo.height;
    }

    file.write(reinterpret_cast<char*>(&header), sizeof(bmpFileHeader));
    file.write(reinterpret_cast<char*>(&dibInfo), sizeof(bmpFileDibInfo));

    // If 8-bit grayscale, write base color palette
    if (dibInfo.bitsPerPixel == 8) { 
        for (int i = 0; i < 256; i++) {
            file.put(i);
            file.put(i);
            file.put(i);
            file.put(0);
        }
    }

    int bytesPerPixel = dibInfo.bitsPerPixel / 8;
    int rowSize = dibInfo.width * bytesPerPixel;
    int paddingSize = (4 - (rowSize % 4)) % 4;

    // Preallocate a buffer large enough for one row plus padding
    std::vector<char> buffer(rowSize + paddingSize, 0); // Initialize padding bytes to 0

    for (int x = dibInfo.height - 1; x >= 0; x--) {
        const std::vector<Pixel> &rowPixels = pixels[x];
        
        // Fill the buffer with pixel data
        for (int y = 0; y < dibInfo.width; y++) {
            const Pixel &pixel = rowPixels[y];
            
            if (dibInfo.bitsPerPixel == 8) {
                buffer[y] = static_cast<char>(pixel.blue);
            } else if (dibInfo.bitsPerPixel == 24) {
                buffer[y * 3] = static_cast<char>(pixel.blue);
                buffer[y * 3 + 1] = static_cast<char>(pixel.green);
                buffer[y * 3 + 2] = static_cast<char>(pixel.red);
            }
        }

        file.write(buffer.data(), buffer.size());
    }

    file.close();

    return 1;
}
==3057== Memcheck, a memory error detector
==3057== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3057== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==3057== Command: ./main
==3057== 
Number of threads is set to 2
Memory required to load image.bmp: 798KB
Loaded image.bmp with 640x426 pixels and 24 bits per pixel
==3057== Syscall param writev(vector[...]) points to uninitialised byte(s)
==3057==    at 0x4CBEA57: writev (writev.c:26)
==3057==    by 0x4941D91: std::__basic_file<char>::xsputn_2(char const*, long, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x4984D26: std::basic_filebuf<char, std::char_traits<char> >::xsputn(char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x49AD375: std::ostream::write(char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x10CE04: Bitmap::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x11A5F0: rotateAndSave(Bitmap&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x117EEB: main (in /content/LabWork1/main)
==3057==  Address 0x54035e6 is 6 bytes inside a block of size 8,192 alloc'd
==3057==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==3057==    by 0x4986023: std::basic_filebuf<char, std::char_traits<char> >::_M_allocate_internal_buffer() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x498A015: std::basic_filebuf<char, std::char_traits<char> >::open(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x498AA7D: std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x10C8D0: Bitmap::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x11A5F0: rotateAndSave(Bitmap&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x117EEB: main (in /content/LabWork1/main)
==3057==  Uninitialised value was created by a stack allocation
==3057==    at 0x10C88F: Bitmap::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057== 
image.bmp rotated clockwise and saved to output/rotatedClockwise_image.bmp
image.bmp rotated counter-clockwise and saved to output/rotatedCounterClockwise_image.bmp
image.bmp Gaussian filtered
==3057== Syscall param writev(vector[...]) points to uninitialised byte(s)
==3057==    at 0x4CBEA8D: __writev (writev.c:26)
==3057==    by 0x4CBEA8D: writev (writev.c:24)
==3057==    by 0x4941D91: std::__basic_file<char>::xsputn_2(char const*, long, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x4984D26: std::basic_filebuf<char, std::char_traits<char> >::xsputn(char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x49AD375: std::ostream::write(char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x10CE04: Bitmap::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x11A5F0: rotateAndSave(Bitmap&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x1180C5: main (in /content/LabWork1/main)
==3057==  Address 0x5902356 is 6 bytes inside a block of size 8,192 alloc'd
==3057==    at 0x484A2F3: operator new[](unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==3057==    by 0x4986023: std::basic_filebuf<char, std::char_traits<char> >::_M_allocate_internal_buffer() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x498A015: std::basic_filebuf<char, std::char_traits<char> >::open(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x498AA7D: std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==3057==    by 0x10C8D0: Bitmap::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x11A5F0: rotateAndSave(Bitmap&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057==    by 0x1180C5: main (in /content/LabWork1/main)
==3057==  Uninitialised value was created by a stack allocation
==3057==    at 0x10C88F: Bitmap::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /content/LabWork1/main)
==3057== 
image.bmp rotated clockwise and saved to output/filteredRotatedClockwise_image.bmp
image.bmp rotated counter-clockwise and saved to output/filteredRotatedCounterClockwise_image.bmp
==3057== 
==3057== HEAP SUMMARY:
==3057==     in use at exit: 0 bytes in 0 blocks
==3057==   total heap usage: 12,003 allocs, 12,003 frees, 13,566,140 bytes allocated
==3057== 
==3057== All heap blocks were freed -- no leaks are possible
==3057== 
==3057== For lists of detected and suppressed errors, rerun with: -s
==3057== ERROR SUMMARY: 4 errors from 2 contexts (suppressed: 0 from 0)