我有这段代码来读取 bmp 图像,然后将其写入新图像。我面临的问题是,
write_bmp
函数生成的图像与原始读取图像的大小相同,但我无法打开图像,因为它已损坏。
您能帮我解决代码中的问题吗?
提前谢谢你。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
uint16_t signature;
uint32_t file_size;
uint32_t reserved;
uint32_t data_offset;
uint32_t header_size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bits_per_pixel;
uint32_t compression;
uint32_t image_size;
int32_t x_pixels_per_meter;
int32_t y_pixels_per_meter;
uint32_t total_colors;
uint32_t important_colors;
} BMPHeader;
#pragma pack(pop)
void read_bmp(const char* filename, uint8_t** image_data, int32_t* width, int32_t* height, uint16_t* bits_per_pixel)
{
FILE* file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Failed to open the file\n");
exit(1);
}
BMPHeader header;
fread(&header, sizeof(BMPHeader), 1, file);
if (header.signature != 0x4D42) {
fprintf(stderr, "Invalid BMP file\n");
exit(1);
}
*width = header.width;
*height = header.height;
*bits_per_pixel = header.bits_per_pixel;
int32_t row_padding = (4 - ((*width) % 4)) % 4;
int32_t row_size = (*width) + row_padding;
int32_t data_size = row_size * abs(*height);
*image_data = (uint8_t*)malloc(data_size);
if (!*image_data) {
fprintf(stderr, "Memory allocation failed\n");
exit(1);
}
fseek(file, header.data_offset, SEEK_SET);
int32_t row;
for (row = 0; row < abs(*height); ++row) {
fread(*image_data + (row * row_size), 1, *width, file);
fseek(file, row_padding, SEEK_CUR);
}
fclose(file);
}
void write_bmp(const char* filename, const uint8_t* image_data, int32_t width, int32_t height, uint16_t bits_per_pixel)
{
FILE* file = fopen(filename, "wb");
if (!file) {
fprintf(stderr, "Failed to open the file 4 write\n");
exit(1);
}
int32_t row_padding = (4 - ((width * (bits_per_pixel / 8)) % 4)) % 4;
int32_t row_size = (width * (bits_per_pixel / 8)) + row_padding;
int32_t data_size = row_size * abs(height);
BMPHeader header;
header.signature = 0x4D42;
header.file_size = sizeof(BMPHeader) + data_size;
header.reserved = 0;
header.data_offset = sizeof(BMPHeader);
header.header_size = sizeof(BMPHeader) - 14;
header.width = width;
header.height = height;
header.planes = 1;
header.bits_per_pixel = bits_per_pixel;
header.compression = 0;
header.image_size = data_size;
header.x_pixels_per_meter = 0;
header.y_pixels_per_meter = 0;
header.total_colors = 0;
header.important_colors = 0;
fwrite(&header, sizeof(BMPHeader), 1, file);
int32_t row;
for (row = 0; row < abs(height); ++row) {
fwrite(image_data + (row * width * (bits_per_pixel / 8)), 1, (width * (bits_per_pixel / 8)), file);
uint8_t padding[3] = {0};
fwrite(padding, 1, row_padding, file);
}
fclose(file);
}
int main()
{
const char* input_filename = "C:/Users/pp/Desktop/r/lena.BMP";
const char* output_filename = "C:/Users/pp/Desktop/r/ccoutput.BMP";
uint8_t* image_data;
int32_t width, height;
uint16_t bits_per_pixel;
read_bmp(input_filename, &image_data, &width, &height, &bits_per_pixel);
printf("bits_per_pixel = %d \n",bits_per_pixel );
// Access and process the image data as needed
write_bmp(output_filename, image_data, width, height, bits_per_pixel);
free(image_data);
return 0;
}
看一下您的代码,您似乎忘记了标题末尾和像素数据开头之间的调色板数据。对于这个答案,我使用this图像作为测试。
输入文件和输出文件的大小相差正好1026字节。由于图像每个像素有 8 位,并且颜色以 4 字节 RGBA32 格式存储,因此该表占用 2^8*4=1024 字节。请注意,对于每像素位数的图像,颜色表不是可选的 <= 8.
造成 1026 字节图像大小差异的剩余两个字节似乎是文件末尾的 2 字节空终止符。
此外,在您的
read_bmp
函数中,您不会像在 write_bmp
中那样考虑每像素位数。
最后,您应该听取 Sven Nilsson 的建议,因为您对标头的计算也不完全正确。
来源: https://en.wikipedia.org/wiki/BMP_file_format#Color_table