You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C语言Pixel结构体克隆BMP图像失败求助

BMP图像像素复制问题排查

我是C语言新手,使用Clion C17读取并复制BMP图像像素。已确认BMP头可正确复制,但分配的像素数据未被正确复制,代码存在问题,参考相关代码后仍未解决,请求帮忙排查。

相关代码

typedef struct {
    uint8_t blue;
    uint8_t green;
    uint8_t red;
} Pixel;

Pixel* read_bmp_pixels(FILE* stream, BMPHeader* header,  Pixel* pixels) {
    int padding = (4 - (header->width_px * sizeof(Pixel)) % 4) % 4;

    if (pixels == NULL) {
        printf("Error: Failed to allocate memory for pixel data.\n");
        exit(EXIT_FAILURE);
    }
    fseek(stream, 54, SEEK_SET);
    int index_p = 0;
    for (int i = 0; i < header->width_px; i++) {
        for (int j = 0; j < header->height_px; j++) {
            fread(&(pixels[index_p].blue), 1, 1, stream);
            fread(&(pixels[index_p].green), 1, 1, stream);
            fread(&(pixels[index_p].red), 1, 1, stream);
            index_p++;
        }
        fseek(stream, padding, SEEK_CUR);
    }

    //print_pixels(pixels, header->width_px * header->height_px);

    return pixels;
}
void copy(){
 Pixel *small_pixel = malloc(num_of_small_pixels * sizeof(Pixel));
    Pixel *big_pixel = malloc(num_of_big_pixels * sizeof(Pixel));
    if (small_pixel == NULL) {
        printf("Error: Failed to allocate memory for pixel data.\n");
        exit(EXIT_FAILURE);
    }
    if (big_pixel == NULL) {
        printf("Error: Failed to allocate memory for pixel data.\n");
        exit(EXIT_FAILURE);
    }
    Pixel *read1= read_bmp_pixels(small_file, bmpHeader[0], small_pixel);
 FILE* test = fopen("test.bmp", "wb");
    if (!test) {
        printf("Error: could not open output BMP file\n");
        exit(1);
    }

// Write BMP header to the output file
    fseek(test, 0, SEEK_SET);
    fwrite(small_header, sizeof(char), 54, test);
    rewind(test);
    fseek(test, 54, SEEK_SET);
    printf("%s", big_buffer);
// Write the pixel data to the output file
    int num_pixels = bmpHeader[1]->width_px * bmpHeader[1]->height_px;
    int bytes_per_pixel = bmpHeader[0]->bits_per_pixel / 8;
    int row_padding = (4 - (bmpHeader[0]->width_px * bytes_per_pixel) % 4) % 4;
    print_pixels(small_pixel, bmpHeader[0]->width_px * bmpHeader[0]->height_px);
    for (int i = bmpHeader[0]->height_px - 1; i >= 0; i--) {
        for (int j = 0; j < bmpHeader[0]->width_px; j++) {
            fwrite(&small_pixel[i * bmpHeader[0]->width_px + j].blue, sizeof(uint8_t), 1, test);
            fwrite(&small_pixel[i * bmpHeader[0]->width_px + j].green, sizeof(uint8_t), 1, test);
            fwrite(&small_pixel[i * bmpHeader[0]->width_px + j].red, sizeof(uint8_t), 1, test);
        }
        // Write row padding
        fwrite(&row_padding, 1, row_padding, test);
    }

    fclose(test);
    }

问题排查与修正

1. 读取循环行列颠倒

BMP像素按行存储,每行包含width_px个像素,原代码先遍历宽度再遍历高度,完全搞反了行和列的顺序,导致像素存储混乱。修正后的读取循环:

// 修正read_bmp_pixels中的循环逻辑
int index_p = 0;
// 不要硬编码54,用header的data_offset字段定位像素起始位置,适配不同BMP格式
fseek(stream, header->data_offset, SEEK_SET); 
int bytes_per_pixel = header->bits_per_pixel / 8;
int padding = (4 - (header->width_px * bytes_per_pixel) % 4) % 4;

for (int i = 0; i < header->height_px; i++) { // 先遍历每一行(高度方向)
    for (int j = 0; j < header->width_px; j++) { // 再遍历该行的每个像素(宽度方向)
        fread(&(pixels[index_p].blue), 1, 1, stream);
        fread(&(pixels[index_p].green), 1, 1, stream);
        fread(&(pixels[index_p].red), 1, 1, stream);
        index_p++;
    }
    fseek(stream, padding, SEEK_CUR); // 跳过当前行的padding
}

2. 写入padding的错误

原代码直接写入row_padding变量的内存值,而非填充对应数量的0字节。比如padding为1时,写入的是int类型的0x01000000,而非单个0x01字节。修正方式:

// 替换原padding写入代码
uint8_t pad_byte = 0;
for (int p = 0; p < row_padding; p++) {
    fwrite(&pad_byte, 1, 1, test);
}

3. 冗余的文件指针操作

写入BMP头时,fseek(test, 0, SEEK_SET)、rewind(test)、fseek(test, 54, SEEK_SET)都是冗余操作,fwrite后文件指针会自动移动到写入的末尾,直接删除这些语句即可。

4. 索引计算与读取顺序匹配

修正读取循环后,写入时的索引计算i * width + j就能正确对应存储的像素顺序,无需额外调整行顺序(如果读取是按BMP从下到上的存储顺序,写入时倒序行是正确的,前提是读取行列顺序正确)。

5. 避免硬编码偏移量

不要直接用fseek(stream, 54, SEEK_SET),BMP头长度不一定是54字节(比如带调色板的BMP),应该用header->data_offset字段定位到像素数据的起始位置。

内容的提问来源于stack exchange,提问作者Aaron Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 06:12:04