我正在尝试将图像数据写入BMP文件。我发现了这个website,它为文件头提供了以下结构:
typedef struct { // Total: 54 bytes
uint16_t type; // Magic identifier: 0x4d42
uint32_t size; // File size in bytes
uint16_t reserved1; // Not used
uint16_t reserved2; // Not used
uint32_t offset; // Offset to image data in bytes from beginning of file (54 bytes)
uint32_t dib_header_size; // DIB Header size in bytes (40 bytes)
int32_t width_px; // Width of the image
int32_t height_px; // Height of image
uint16_t num_planes; // Number of color planes
uint16_t bits_per_pixel; // Bits per pixel
uint32_t compression; // Compression type
uint32_t image_size_bytes; // Image size in bytes
int32_t x_resolution_ppm; // Pixels per meter
int32_t y_resolution_ppm; // Pixels per meter
uint32_t num_colors; // Number of colors
uint32_t important_colors; // Important colors
} BMPHeader;
我知道C/C++不保证结构体中的数据会连续存储,所以简单地将头结构体写入文件如下:
BMPHeader header(width, height, bytespp, fileSize);
int num_read = fwrite(&header, BMP_HEADER_SIZE, 1, fp);
或者说:
BMPHeader* header = new BMPHeader(width, height, bytespp, fileSize);
int num_read = fwrite(header, BMP_HEADER_SIZE, 1, fp);
使用下面的构造函数(这可能是不必要的信息,但包括它,以防它可能有用):
BMPHeader(
unsigned int width, unsigned int height, unsigned short bytespp, unsigned int fileSize) :
type(MAGIC_VALUE), size(fileSize),
reserved1(RESERVED), reserved2(RESERVED), offset(BMP_HEADER_SIZE),
dib_header_size(40), width_px(width), height_px(height), num_planes(NUM_PLANE),
bits_per_pixel(bytespp*BITS_PER_BYTE), compression(COMPRESSION),
image_size_bytes(width * height * bytespp), x_resolution_ppm(0x00),
y_resolution_ppm(0x00), num_colors(0x00), important_colors(IMPORTANT_COLORS)
{
}
因为不能保证变量将按照它们被写入的顺序存储,也不能保证变量之间没有填充。
不管怎样,我还是试了一下,不出所料,它不起作用。
我的问题是:有没有什么方法可以更优雅地将数据写入文件,而不是按照我想要的顺序将每个成员变量单独写入文件?
我尝试将结构体示例化到堆上作为BMPHeader*
,以及堆栈上。
我也试着使用这样的联合:
struct BMPHeader
{
union
{
struct
{
unsigned short type; // Magic identifier: 0x4d42
unsigned int size; // File size in bytes
unsigned short reserved1; // Not used
unsigned short reserved2; // Not used
unsigned int offset; // Offset to image data in bytes from beginning of file (54 bytes)
unsigned int dib_header_size; // DIB Header size in bytes (40 bytes)
unsigned int width_px; // Width of the image
unsigned int height_px; // Height of image
unsigned short num_planes; // Number of color planes
unsigned short bits_per_pixel; // Bits per pixel
unsigned int compression; // Compression type
unsigned int image_size_bytes; // Image size in bytes
unsigned int x_resolution_ppm; // Pixels per meter
unsigned int y_resolution_ppm; // Pixels per meter
unsigned int num_colors; // Number of colors
unsigned int important_colors; // Important colors
};
unsigned char raw[54];
};
看看我是否可以将数组写入文件,但我遇到了同样的问题。
3条答案
按热度按时间o8x7eapl1#
Microsoft多年来一直使用这种结构,并且对文件的单次写入与Visual Studio中结构类型的标准设置一起工作。
但有一个令人讨厌的陷阱:
必须强制执行,以保证字段
bfType
和bfReserved1/2
存储在两个字节上。相比之下,
BITMAPINFOHEADER
(以及更高版本)不使用此设置。2lpgd9682#
作为Yksisarvinen和**n。我会在Reddit上看到你们,在上面的评论中提到,我没有包括
pragma pack
指令。以下是修复它的更改:
谢谢大家!
aiazj4mn3#
恕我直言,最优雅的方法是将方法复制到缓冲区中。这允许您控制间距(如果有)和字节序:
然后你可以使用它来写块:
类似地,编写一个方法从缓冲区读取成员。read对于非POD成员(如字符串)非常有效。
附带的方法
size_in_buffer()
将返回每个成员在缓冲区中占用的累积大小。这在分配动态数组(缓冲区)来保存数据时非常有用。效率是基于写内存比写文件更快的理性。此外,对文件的块写入比对每个成员单独进行许多小写入更快、更高效。流在保持运行时效率最高。
另外,在互联网上搜索“C++序列化”。