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

Windows正常运行的BMP像素修改代码在Linux报文件提前结束错误求助

解决Linux下BMP文件生成"premature end of file"错误的方案

我看到你的代码在Windows能正常运行,但Linux下生成的BMP文件打不开,提示文件提前结束——这通常是因为写入的文件字节数和头部声明的大小不匹配,或者代码里存在读写逻辑错误导致数据缺失。下面我帮你梳理几个关键问题和修复方法:

1. 文件头读写的致命错误

先看这段代码,这里有两个严重错误:

fwrite(&fh.unused1,2,1,g);
fread(&fh.unused1,2,1,g);  // 错误:应该是fwrite,不是fread!
fwrite(&fh.imageDataOffset,4,1,g);

你试图从输出文件g里读取数据,这完全不符合逻辑,直接导致文件头数据缺失。另外,前面读取文件头时,你两次读的都是fh.unused1,把fh.unused2给忽略了:

fread(&fh.unused1,2,1,f);
fread(&fh.unused1,2,1,f);  // 错误:应该读取fh.unused2!

修复后的文件头读写代码:

// 读取文件头
fread(&fh.fileMarker1,1,1,f);
fread(&fh.fileMarker2,1,1,f);
fread(&fh.bfSize,4,1,f);
fread(&fh.unused1,2,1,f);
fread(&fh.unused2,2,1,f);  // 正确读取unused2
fread(&fh.imageDataOffset,4,1,f);

// 写入文件头
fwrite(&fh.fileMarker1,1,1,g);
fwrite(&fh.fileMarker2,1,1,g);
fwrite(&fh.bfSize,4,1,g);
fwrite(&fh.unused1,2,1,g);
fwrite(&fh.unused2,2,1,g);  // 正确写入unused2
fwrite(&fh.imageDataOffset,4,1,g);

2. Padding计算与处理错误

BMP要求每行像素数据对齐到4字节倍数,你的padding计算和处理逻辑都有问题:

  • 原计算方式padding=(ih.width*3) % 4无法正确处理刚好整除的情况(此时padding应为0)
  • 处理padding时错误地读取了多余字节,还强制把padding改成0(其实BMP的padding可以是任意值,原样复制即可)

修复后的padding处理逻辑:

int row_size = ih.width * 3;
padding = (4 - (row_size % 4)) % 4;  // 正确计算padding值

for(i=0;i<ih.height;i++) {
    for(j=0;j<ih.width;j++) {
        fread(&clr,3,1,f);
        if(clr[0]==255 && clr[1]==255 && clr[2]==255)
            fwrite(clr,3,1,g);
        else
            fwrite(clrNew,3,1,g);
    }
    // 原样复制padding,不需要修改
    if(padding > 0) {
        unsigned char pad[3];
        fread(pad, padding, 1, f);
        fwrite(pad, padding, 1, g);
    }
}

3. 结构体字节对齐问题

Windows和Linux的编译器默认字节对齐规则不同,会导致你的FH和IH结构体大小与BMP文件头部不匹配,进而读取错误。解决方法是强制结构体1字节对齐:

#pragma pack(push, 1)  // 开启1字节对齐
typedef struct bmp_fileheader {
    unsigned char fileMarker1; /* 'B' */
    unsigned char fileMarker2; /* 'M' */
    unsigned int bfSize; /* File's size */
    unsigned short unused1;
    unsigned short unused2;
    unsigned int imageDataOffset; /* Offset to the start of image data */
}FH;

typedef struct bmp_infoheader {
    unsigned int biSize; /* Size of the info header - 40 bytes */
    signed int width; /* Width of the image */
    signed int height; /* Height of the image */
    unsigned short planes;
    unsigned short bitPix;
    unsigned int biCompression;
    unsigned int biSizeImage; /* Size of the image data */
    int biXPelsPerMeter;
    int biYPelsPerMeter;
    unsigned int biClrUsed;
    unsigned int biClrImportant;
}IH;
#pragma pack(pop)  // 恢复默认对齐规则

修复后的完整代码

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

#pragma pack(push, 1)
typedef struct bmp_fileheader {
    unsigned char fileMarker1; /* 'B' */
    unsigned char fileMarker2; /* 'M' */
    unsigned int bfSize; /* File's size */
    unsigned short unused1;
    unsigned short unused2;
    unsigned int imageDataOffset; /* Offset to the start of image data */
}FH;

typedef struct bmp_infoheader {
    unsigned int biSize; /* Size of the info header - 40 bytes */
    signed int width; /* Width of the image */
    signed int height; /* Height of the image */
    unsigned short planes;
    unsigned short bitPix;
    unsigned int biCompression;
    unsigned int biSizeImage; /* Size of the image data */
    int biXPelsPerMeter;
    int biYPelsPerMeter;
    unsigned int biClrUsed;
    unsigned int biClrImportant;
}IH;
#pragma pack(pop)

int main() {
    FH fh;
    IH ih;
    FILE *f,*g;
    int B,G,R,i,j,padding, row_size;
    char fileName[256],fileNameTask[256],*p;
    unsigned char clr[3],clrNew[3];
    
    f=fopen("input100.txt","rt");
    if(f==NULL) {
        perror("Failed to open input file");
        return -1;
    }
    if(fscanf(f,"%s %d %d %d",fileName,&B,&G,&R) != 4) {
        perror("Invalid input format");
        fclose(f);
        return -1;
    }
    clrNew[0] = (unsigned char)B;
    clrNew[1] = (unsigned char)G;
    clrNew[2] = (unsigned char)R;
    fclose(f);

    f=fopen(fileName,"rb");
    if(f==NULL) {
        perror("Failed to open BMP file");
        return -1;
    }

    // 处理生成输出文件名
    p=strchr(fileName,'.');
    if(p != NULL) {
        *p='\0';
    }
    strcpy(fileNameTask,fileName);
    strcat(fileNameTask,"_task1.bmp");

    g=fopen(fileNameTask,"wb");
    if(g==NULL) {
        perror("Failed to create output BMP file");
        fclose(f);
        return -1;
    }

    // 读取并写入文件头
    fread(&fh.fileMarker1,1,1,f);
    fread(&fh.fileMarker2,1,1,f);
    fread(&fh.bfSize,4,1,f);
    fread(&fh.unused1,2,1,f);
    fread(&fh.unused2,2,1,f);
    fread(&fh.imageDataOffset,4,1,f);

    fwrite(&fh.fileMarker1,1,1,g);
    fwrite(&fh.fileMarker2,1,1,g);
    fwrite(&fh.bfSize,4,1,g);
    fwrite(&fh.unused1,2,1,g);
    fwrite(&fh.unused2,2,1,g);
    fwrite(&fh.imageDataOffset,4,1,g);

    // 读取并写入信息头
    fread(&ih.biSize,4,1,f);
    fread(&ih.width,4,1,f);
    fread(&ih.height,4,1,f);
    fread(&ih.planes,2,1,f);
    fread(&ih.bitPix,2,1,f);
    fread(&ih.biCompression,4,1,f);
    fread(&ih.biSizeImage,4,1,f);
    fread(&ih.biXPelsPerMeter,4,1,f);
    fread(&ih.biYPelsPerMeter,4,1,f);
    fread(&ih.biClrUsed,4,1,f);
    fread(&ih.biClrImportant,4,1,f);

    fwrite(&ih.biSize,4,1,g);
    fwrite(&ih.width,4,1,g);
    fwrite(&ih.height,4,1,g);
    fwrite(&ih.planes,2,1,g);
    fwrite(&ih.bitPix,2,1,g);
    fwrite(&ih.biCompression,4,1,g);
    fwrite(&ih.biSizeImage,4,1,g);
    fwrite(&ih.biXPelsPerMeter,4,1,g);
    fwrite(&ih.biYPelsPerMeter,4,1,g);
    fwrite(&ih.biClrUsed,4,1,g);
    fwrite(&ih.biClrImportant,4,1,g);

    // 计算正确的行对齐padding
    row_size = ih.width * 3;
    padding = (4 - (row_size % 4)) % 4;

    // 处理像素数据
    for(i=0;i<ih.height;i++) {
        for(j=0;j<ih.width;j++) {
            if(fread(&clr,3,1,f) != 1) {
                perror("Failed to read pixel data");
                fclose(f);
                fclose(g);
                return -1;
            }
            if(clr[0]==255 && clr[1]==255 && clr[2]==255) {
                fwrite(clr,3,1,g);
            } else {
                fwrite(clrNew,3,1,g);
            }
        }
        // 复制padding字节
        if(padding > 0) {
            unsigned char pad[3];
            if(fread(pad, padding, 1, f) != 1) {
                perror("Failed to read padding");
                fclose(f);
                fclose(g);
                return -1;
            }
            fwrite(pad, padding, 1, g);
        }
    }

    fclose(f);
    fclose(g);
    return 0;
}

为什么这些修复能解决Linux下的问题?

  • 文件头的读写错误直接破坏了BMP的结构,Linux下的图像查看器对格式校验更严格,因此会提示文件提前结束;
  • 字节对齐问题会导致读取的头部数据偏移,使得后续像素数据的读取位置错误,最终写入的文件大小与头部声明的bfSize不匹配;
  • 错误的padding处理会导致每行字节数错误,累积下来整个文件的字节数缺失,触发"premature end of file"错误。

内容的提问来源于stack exchange,提问作者Alexandru Corbescu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:02:14