读写BMP图像(灰度)

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

我有这段代码来读取 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;
}

c image bmp
1个回答
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

© www.soinside.com 2019 - 2024. All rights reserved.