Why in this code std::cout << (int)pixelDataSize << " " << (dibInfo.width + (4 - (dibInfo.width % 4))) * dibInfo.height << std::endl; prints different numbers for colored images but identical for grayscale: #include <cstdint>
#include <string>
#include <vector>

#include <cstdint>
#include <fstream>
#include <sstream>
#include <vector>
#include <iostream>
#include <cmath>
#include <unistd.h>
#include <thread>

// Structure representing the BMP file header
struct bmpFileHeader {
    uint32_t fileSize;       // Size of the BMP file in bytes
    uint16_t reserved1;      // Reserved; actual value depends on the application that creates the image
    uint16_t reserved2;      // Reserved; actual value depends on the application that creates the image
    uint32_t bmpOffset;      // Offset where the pixel array (bitmap data) can be found
};

// Structure containing DIB header information of a BMP file
struct bmpFileDibInfo {
    uint32_t headerSize;         // Size of this header
    int32_t width;               // Bitmap width in pixels
    int32_t height;              // Bitmap height in pixels
    uint16_t planes;             // Number of color planes being used
    uint16_t bitsPerPixel;       // Number of bits per pixel
    uint32_t compression;        // Compression method being used
    uint32_t imageSize;          // Size of the raw bitmap data
    int32_t xPixelsPerMeter;     // Horizontal resolution of the image (pixel per meter)
    int32_t yPixelsPerMeter;     // Vertical resolution of the image (pixel per meter)
    uint32_t colorsUsed;         // Number of colors in the color palette
    uint32_t importantColors;    // Number of important colors used
};

#include <iostream>
#include <bitset>

template<size_t N>
std::bitset<N> multiplyBitsetByInt(const std::bitset<N>& bits, int multiplier) {
    // Convert bitset to unsigned long
    unsigned long value = bits.to_ulong();
    
    // Perform multiplication
    unsigned long result = value * multiplier;
    
    // Return the result as a bitset (ensure it fits within N bits)
    return std::bitset<N>(result);
}

template<size_t BitsPerPixel>
struct Pixel {
    static constexpr size_t bits_per_pixel = BitsPerPixel;
    std::bitset<BitsPerPixel> color;
};
// Class representing a Bitmap image

class Bitmap {
    private:
        bool isGrayscale;
        uint8_t bitsPerPixel;
        std::vector<uint8_t> pixels;
        std::vector<uint8_t> importantData;

        std::vector<std::vector<uint8_t>> palette;

        bmpFileHeader header;
        bmpFileDibInfo dibInfo;

    public:
        Bitmap() { } // Default constructor

        // Copy constructor
        Bitmap(const Bitmap& other) : pixels(other.pixels), isGrayscale(other.isGrayscale), palette(other.palette) { }

        ~Bitmap() { pixels.clear(); } // Destructor clearing the pixel data

        // Method to load a bitmap from a file
        void load(std::string);

        // Method to write a bitmap to a file
        void write(std::string);

        // Method to rotate the bitmap image
        void rotate(bool clockwise);

        // Method to apply a Gaussian filter to the bitmap image
        void applyGaussianFilter(const std::vector<std::vector<float>>& kernel, int numThreads);
        void applyGaussianFilterThread(const std::vector<std::vector<float>>& kernel, int startY, int endY);
};

// Function to generate a Gaussian kernel
std::vector<std::vector<float> > generateGaussianKernel(int size, float sigma) {
    std::vector<std::vector<float> > kernel(size, std::vector<float>(size));
    float sum = 0.0;
    int halfSize = size / 2;

    // Calculate the Gaussian values for each position in the kernel
    for (int x = -halfSize; x <= halfSize; x++) {
        for (int y = -halfSize; y <= halfSize; y++) {
            float exponent = -(x * x + y * y) / (2 * sigma * sigma);
            float value = exp(exponent) / (2 * M_PI * sigma * sigma);

            kernel[x + halfSize][y + halfSize] = value;
            sum += value;
        }
    }

    // Normalize the kernel to ensure the sum of all values is 1
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            kernel[i][j] /= sum;
        }
    }

    return kernel;
}

// Extract the image name from a full path
std::string getImageName(std::string &imagePath) {
    std::string token;
    std::istringstream tokenStream(imagePath);
    std::string imageName;

    while (std::getline(tokenStream, token, '/')) {
        imageName = token;
    }
    
    return imageName;
}

// Load a BMP image from a file
void Bitmap::load(std::string fileName) {
    std::ifstream file(fileName, std::ios::binary);

    if (!file.is_open()) {
        std::cerr << "Error: Could not open file " << fileName << std::endl;
        exit(1);
    }

    unsigned char fileType[2];
    file.read(reinterpret_cast<char*>(fileType), 2);
    
    if ((fileType[0] != 'B') || (fileType[1] != 'M')) {
        std::cerr << "Error: File is not a BMP file" << std::endl;
        exit(1);
    }

    //bmpFileHeader header;
    file.read(reinterpret_cast<char*>(&header), sizeof(bmpFileHeader));

    //bmpFileDibInfo dibInfo;
    file.read(reinterpret_cast<char*>(&dibInfo), sizeof(bmpFileDibInfo));

    // Read palette
    if (dibInfo.bitsPerPixel == 8) {
        for (int i = 0; i < 256; ++i) {
            uint8_t b, g, r, alpha;

            file.read(reinterpret_cast<char*>(&b), sizeof(b));
            file.read(reinterpret_cast<char*>(&g), sizeof(g));
            file.read(reinterpret_cast<char*>(&r), sizeof(r));
            file.read(reinterpret_cast<char*>(&alpha), sizeof(alpha));
            palette.push_back({b, g, r, alpha});

            //std::cout << "r: " << static_cast<int>(palette[i][2]) << " g: " << static_cast<int>(palette[i][1]) << " b: " << static_cast<int>(palette[i][0]) << "\n";
        }
    }

    // Read important data before header.bmpOffset
    for (int i = 0; i < header.bmpOffset - sizeof(bmpFileHeader) - sizeof(bmpFileDibInfo); ++i) {
        uint8_t temp;
        std::cout << "i: " << temp << "\n";
        file.read(reinterpret_cast<char*>(&temp), sizeof(temp));
        importantData.push_back(temp);
    }

    // Seek to the pixel data start position
    file.seekg(header.bmpOffset, std::ios::beg);
    /*std::cout << dibInfo.height << " " << dibInfo.width << "\n";
    if (dibInfo.bitsPerPixel == 8) {
        //pixels.resize(dibInfo.height, std::vector<uint8_t>(dibInfo.width));
        for (int x = 0; x < dibInfo.height; x++) {
            std::vector<uint8_t> pixelRow;
            for (int y = 0; y < dibInfo.width; y++) {
                uint8_t pixel = file.get();
                //file.read(reinterpret_cast<char*>(&pixel), sizeof(pixel));
                //std::cout << (int)pixel.to_ulong() << std::endl;
                //pixels[x][y] = pixel;
                //std::cout << (int)pixel.to_ulong() << std::endl;
                pixelRow.push_back(pixel);
            }
            file.seekg(dibInfo.width % 4, std::ios::cur);

            pixels.insert(pixels.begin(), pixelRow);
        }
    }*/
    //std::vector<std::vector<uint8_t>> pixelsRaw;
       // Calculate the number of bytes per row (including padding)
        // Calculate the size of the pixel data

    //std::vector<uint8_t> pixelsRaw;

    std::streampos pixelDataSize = header.fileSize - header.bmpOffset;
    std::cout << (int)pixelDataSize << " " << (dibInfo.width + (4 - (dibInfo.width % 4))) * dibInfo.height << std::endl;

    // Resize the vector to hold the pixel data
    pixels.resize(pixelDataSize);

    // Seek to the pixel data start position
    file.seekg(header.bmpOffset, std::ios::beg);

    // Read the pixel data into the vector
    file.read(reinterpret_cast<char*>(pixels.data()), pixelDataSize);

    // Print pixels
    for (auto &row : pixels) {
        //std::cout << row << " ";
    }
    //std::cout << std::endl;

    // Close the file
    file.close();

    // Check if the read was successful
    if (!file) {
        std::cerr << "Error: Failed to read pixel data from file " << fileName << std::endl;
        exit(1);
    }

    // Close the file
    file.close();
}

// Write the BMP image to a file
void 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;
    }

    file.write("BM", 2);

    /*bmpFileHeader header = {0};
    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));
    
    //dibInfo.width = pixels[0].size();
    //dibInfo.height = pixels.size();
    // If 8-bit, write the color palette
    if (dibInfo.bitsPerPixel == 8) {
        for (int i = 0; i < 256; i++) {
            file.put(palette[i][0]); // Blue
            file.put(palette[i][1]); // Green
            file.put(palette[i][2]); // Red
            file.put(palette[i][3]); // Reserved
        }
    }
    for (auto &data : importantData) {
        file.write(reinterpret_cast<char*>(&data), sizeof(uint8_t));
    }
    file.seekp(header.bmpOffset);
    // Write pixel data
    /*for (int x = dibInfo.height - 1; x >= 0; x--) {
        const std::vector<uint8_t> &rowPixels = pixels[x]; 
        for (int y = 0; y < dibInfo.width; y++) {
            const uint8_t &pixel = rowPixels[y];
            file.put(pixel);
            //std::cout << (int)pixel.to_ulong() << std::endl;
            //file.write(reinterpret_cast<char*>(&pixel), sizeof(pixel));
        }

        // Write padding bytes
        for (int i = 0; i < dibInfo.width % 4; i++) {
            file.put(0);
        }
    }*/
    for (auto &row : pixels) {
        file.put(row); 
    }

    file.close();
}

int main() {
    // Load image
    Bitmap image;
    image.load("lopq32x7.bmp");
    image.write("output.bmp");
    // Print image info
}