C/C++实现BMP图像读写平移后Visual Studio输出格式不支持问题
问题根因分析
- 核心错误:未处理BMP文件的行对齐规则。BMP格式规定每一行像素数据的字节数必须向上对齐到4的整数倍,不足的位置用0字节填充。你当前直接用
3 * width * height计算像素总大小,仅在宽度是4的倍数时成立,对于宽度不是4的倍数的图像,读取、写入的像素数据长度和实际文件不匹配,导致输出文件头信息和实际数据不一致,系统无法识别格式。 - 次要问题:平移函数中新分配的像素数组未初始化,超出有效平移区域的像素是随机垃圾值;代码存在多处内存泄漏,BMP结构体的
pixels指针申请的堆内存全程没有释放。 - 潜在问题:
BMP newImage = image是浅拷贝,只会复制pixels指针的地址,不会复制实际像素数据,后续操作容易出现野指针、重复释放问题。
修复方案
- 新增行对齐计算逻辑,读取、写入时按对齐后的行大小处理数据
- 平移函数中先初始化新像素数组为全黑(或自定义背景色)
- 补充内存释放逻辑,避免内存泄漏
修复后代码示例
#include <iostream> #include <string> #include <cstring> using namespace std; struct BMP { int width; int height; int rowSize; // 对齐后的单行字节数 unsigned char header[54]; unsigned char *pixels; int size; }; // 读取BMP图像 BMP readBMP(string filename) { BMP image; FILE *f = fopen(filename.c_str(), "rb"); if(!f) { cout << "文件打开失败" << endl; exit(1); } fread(image.header, sizeof(unsigned char), 54, f); image.width = *(int*)&image.header[18]; image.height = *(int*)&image.header[22]; // 计算对齐后的单行字节数,总像素大小 image.rowSize = (image.width * 3 + 3) / 4 * 4; image.size = image.rowSize * abs(image.height); image.pixels = new unsigned char[image.size]; // 按对齐后的大小读取像素数据 fread(image.pixels, sizeof(unsigned char), image.size, f); fclose(f); // BGR转RGB,注意要按行处理,跳过对齐填充的0字节 for(int y = 0; y < abs(image.height); y++) { for(int x = 0; x < image.width; x++) { int idx = y * image.rowSize + x * 3; swap(image.pixels[idx], image.pixels[idx + 2]); } } return image; } // 写入BMP图像 void writeBMP(string filename, BMP image) { FILE *out = fopen(filename.c_str(), "wb"); if(!out) { cout << "输出文件创建失败" << endl; exit(1); } fwrite(image.header, sizeof(unsigned char), 54, out); // RGB转回BGR,同样按行处理跳过填充字节 for(int y = 0; y < abs(image.height); y++) { for(int x = 0; x < image.width; x++) { int idx = y * image.rowSize + x * 3; swap(image.pixels[idx], image.pixels[idx + 2]); } } // 按对齐后的大小写入像素数据 fwrite(image.pixels, sizeof(unsigned char), image.size, out); fclose(out); } // 图像平移 BMP translation(BMP image, int tx, int ty) { BMP newImage = image; newImage.pixels = new unsigned char[image.size]; // 初始化新图像像素为全黑 memset(newImage.pixels, 0, image.size); for(int y = 0; y < abs(image.height); y++) { for(int x = 0; x < image.width; x++) { int xx = x - tx; int yy = y + ty; if(xx >=0 && xx < image.width && yy >=0 && yy < abs(image.height)) { int srcIdx = yy * image.rowSize + xx * 3; int dstIdx = y * image.rowSize + x * 3; newImage.pixels[dstIdx] = image.pixels[srcIdx]; newImage.pixels[dstIdx + 1] = image.pixels[srcIdx + 1]; newImage.pixels[dstIdx + 2] = image.pixels[srcIdx + 2]; } } } return newImage; } // 释放BMP内存 void freeBMP(BMP &image) { if(image.pixels) { delete[] image.pixels; image.pixels = nullptr; } } int main() { BMP image = readBMP("sample_640×426.bmp"); writeBMP("Output-11.bmp", image); int x0 = 100, y0 = 50; BMP image_t = translation(image, x0, y0); writeBMP("Out_translate.bmp", image_t); // 释放内存 freeBMP(image); freeBMP(image_t); return 0; }
内容的提问来源于stack exchange,提问作者user17279105
相关产品推荐
相关产品推荐

