尽管遵循以下格式规范,位图编写程序仍无法产生可读图像

问题描述 投票:0回答:2

我正在用C做一个位图编写器,这是一个较大项目的一部分。我遵循了Windows .bmp标头格式规范,并在十六进制编辑器中检查了生成的文件,以将其与功能性.bmp图像进行比较,但是我计算机上的所有图像程序都无法打开它。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#pragma pack(push, 1) /* remove padding from sructs */

void generateBitmap(int width, int height, float dpi, const char* filename, pixel* imgData) {
    FILE* bitmap;

    struct fHeader {
        uint16_t type; 
        uint32_t size;
        uint16_t reserved1;
        uint16_t reserved2;
        uint32_t offset;
    }bmpFileHeader;

    struct iHeader {
        uint32_t headerSize;
        int32_t  width;
        int32_t  height;
        uint16_t planes;
        uint16_t bitCount;
        uint32_t compression;
        uint32_t imageSize; /* may be 0 if uncompressed */
        int32_t  xPPM;
        int32_t  yPPM;
        uint32_t colorEntriesUsed;
        uint32_t importantColors;
    }bmpImageHeader;

    int bytesPerPixel = 3; /* 24 bit color */
    uint32_t imgSize = width * height;
    uint32_t fileSize = sizeof(bmpFileHeader) + sizeof(bmpImageHeader) + (bytesPerPixel * width * height);
    int32_t ppm = dpi * 39;

    bmpFileHeader.type = 0x4D42;
    bmpFileHeader.size = fileSize;
    bmpFileHeader.reserved1 = 0;
    bmpFileHeader.reserved2 = 0;
    bmpFileHeader.offset = sizeof(bmpFileHeader) + sizeof(bmpImageHeader);

    bmpImageHeader.headerSize = sizeof(bmpImageHeader);
    bmpImageHeader.width = width;
    bmpImageHeader.height = height;
    bmpImageHeader.planes = 1;
    bmpImageHeader.bitCount = 8 * bytesPerPixel;
    bmpImageHeader.compression = 0;
    bmpImageHeader.imageSize = bytesPerPixel * height * width;
    bmpImageHeader.xPPM = ppm; /* typically set these to zero */
    bmpImageHeader.yPPM = ppm;
    bmpImageHeader.colorEntriesUsed = 0;
    bmpImageHeader.importantColors = 0;

    bitmap = fopen(filename, "wb");
    fwrite(&bmpFileHeader, 1, sizeof(bmpFileHeader), bitmap);
    fwrite(&bmpImageHeader, 1, sizeof(bmpImageHeader), bitmap);

    int i;
    for (i = 0; i < (width * height); i++) {
        fwrite(&imgData[i], 3, sizeof(char), bitmap);
    }

    fclose(bitmap);
}

int main(void) {
    pixel imData[4];

    int i;

    for(i = 0; i < 4; i++) {
        imData[i].r = 32;
        imData[i].g = 64;
        imData[i].b = 32;
    }

    generateBitmap(2, 2, 0, "bmptest.bmp", imData);

    return 0;
}

最终结果应仅为2x2单调图像。我发现一些示例将更多的标头值(例如imageSize)设置为零,但其他示例将其视为此处的示例。

c file-io bmp
2个回答
1
投票

以位图格式填充像素,以便每一行的“字节宽度”为4字节的倍数。有关更多详细信息,请参见link

在这种情况下,每行有2个像素,每个像素为3个字节。因此,每行有6个字节。它必须被填充,所以每行是8个字节(最后2个字节将被忽略)。

这也会影响位图文件的大小以及imageSize结构的iHeader

int bytesPerPixel = 3; 
int bits_per_pixel = bytesPerPixel * 8;
int width_in_bytes = ((width * bits_per_pixel + 31) / 32) * 4;

...
bmpFileHeader.size = fileSize;

...
uint32_t fileSize = sizeof(bmpFileHeader) + sizeof(bmpImageHeader) + width_in_bytes * height;

...
bmpImageHeader.imageSize = width_in_bytes * height; 

您要重写循环,使其从上到下,从左到右

for(int y = height - 1; y >= 0; y--)
{
    for(int x = 0; x < width; x++)
    {
        int i = y * width + x;
        fwrite(&imgData[i], 3, sizeof(char), bitmap);
    }

    for(int x = width * bits_per_pixel / 8; x < width_in_bytes; x++)
        fputc('\0', bitmap);
}

最近您可以使用#pragma pack(pop)恢复编译器的默认包

#pragma pack(push, 1) /* remove padding from sructs */
    struct fHeader {
    ...
    };

    struct iHeader {
    ...
    };
#pragma pack(pop)

0
投票

好吧,我终于可以使用它了。问题出在像素行之间的偏移填充位。我个人没有发现它的文档记录得非常好,但是.bmp文件格式期望每行的末尾都有空的填充字节,具体取决于图像的尺寸。我要做的就是将这一行添加到像素编写代码中:

int i;
int p;
for (i = 0; i < (width * height); i++) {
    fwrite(&imgData[i], 3, sizeof(char), bitmap);
    if ((i + 1) % width == 0) { /* if at end of scanline */
        for(p = 0; p < (width % 4); p++) {
            fputc('\0', bitmap); /* append appropriate # of padding bits */
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.