在C中创建BMP header (不能限制2字节字段)

标签 c bmp

我这样做是基于:

https://en.wikipedia.org/wiki/BMP_file_format

我想用 C 从头开始​​创建 BMP 图像。

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

typedef struct HEADER {
    short FileType;
    int FileSize;
    short R1;
    short R2;
    int dOffset;
} tp_header;

int main () {
    FILE *image;

    image = fopen("test.bmp", "w");

    tp_header bHeader;

    bHeader.FileType = 0x4D42;
    bHeader.FileSize = 70;
    bHeader.R1 = 0;
    bHeader.R2 = 0;
    bHeader.dOffset = 54;

    fwrite(&bHeader, sizeof(struct HEADER), 1, image);

    return 0;
}

我应该得到输出文件:

42 4D 46 00 00 00 00 00 00 00 36 00 00 00

但我得到的是:

42 4D 40 00 46 00 00 00 00 00 00 00 36 00 00 00

第一个应该只包含 14 个字节。那个“40 00”毁了这一切。这是在 C 中设置 header 的正确方法吗?我还能如何限制输出的字节大小?

最佳答案

一个struct字段之间可能包含填充字节,以将下一个字段与某些地址偏移对齐。这些填充字节的值是不确定的。典型的布局可能如下所示:

struct {
    uint8_t field1;
    uint8_t <padding>
    uint8_t <padding>
    uint8_t <padding>
    uint32_t field2;
    uint16_t field3;
    uint8_t <padding>
    uint8_t <padding>
};

<padding>刚刚由编译添加;您的程序无法访问它。 这只是一个示例。实际填充可能有所不同,并由 ABI 为您的架构(CPU/OS/工具链)定义。

此外,较大类型的字节在内存中存储的顺序(字节序)取决于体系结构。但是,由于文件需要特定的字节顺序,因此可能也必须修复此问题。

一些 - 但不是全部 - 编译器允许指定 struct成为packed (避免填充),这仍然无助于解决字节顺序问题。

最好是通过移位正确序列化结构并存储到 uint8_t -数组:

#include <stdint.h>

/** Write an uint16_t to a buffer.
 *
 *  \returns The next position in the buffer for chaining.
 */
inline uint8_t *writeUInt16(uint8_t *bp, value)
{
    *bp++ = (uint8_t)value;
    *bp++ = (uint8_t)(value >> 8);
    return bp;
}

// similar to writeUInt16(), but for uint32_t.
... writeUInt32( ... )
    ...

int main(void)
{
    ...

    uint8_t buffer[BUFFER_SIZE], *bptr;

    bptr = buffer;
    bptr = writeUInt16(bptr, 0x4D42U);    // FileType
    bptr = writeUInt32(bptr, 70U);        // FileSize
    ...

}

这将填充 buffer与标题字段。 BUFFER_SIZE必须根据您要创建的 header 进行设置。存储所有字段后,写入 buffer到文件。

声明函数inline提示一个好的编译器可以为常量创建几乎最佳的代码。

另请注意,short 的大小等不固定。使用stdint.h types 是您需要定义大小的类型。

关于在C中创建BMP header (不能限制2字节字段),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30967031/

相关文章:

c - 在 C 程序中禁用中断

c - makefile 的所有部分中的变量和函数在读取时都会展开

c - 如何将具有字符指针的 C 结构插入 DBD 文件

c - 未映射的符号

C++如何创建位图文件

c - Valgrind 在检查内存泄漏时可能丢失消息 - C

c++ - 无法将参数 1 从 'char *' 转换为 'LPCWSTR'

c - GDB : how can I get the name of all local variables?

c - 在 24 位 rgb 位图中填充

c - 放大未压缩的 BMP