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
相关产品推荐
相关产品推荐

