如何用C语言裁剪BMP图像以保留上半部分(当前仅能导出下半部分)
如何修改BMP垂直裁剪代码以保留上半部分内容
我正在编写一个仅依赖stdio.h和stdlib.h的C程序,读取3200x1200的BMP文件并将其垂直裁剪为高度600的图像。当前代码只能导出图像的下半部分,而我需要保留上半部分。已知BMP头的width和height均为正值,当前代码修改头信息后直接读取前600行像素写入,但因BMP像素数据从底部开始存储,导致结果不符合需求,寻求修改方案。
核心裁剪代码(当前版本)
// Update the width and height in the BMP header header.width = newWidth; header.height = newHeight; printf("New header width: %d\n", header.width); printf("New header height: %d\n", header.height); // Write the modified BMP header to the output file fwrite(&header, sizeof(BMPHeader), 1, outputFile); // Calculate the padding int padding = (4 - (header.width * (header.bpp / 8)) % 4) % 4; // Copy the image data unsigned char pixel[4]; for (int y = 0; y < newHeight; y++) { for (int x = 0; x < header.width; x++) { fread(pixel, sizeof(unsigned char), header.bpp / 8, inputFile); fwrite(pixel, sizeof(unsigned char), header.bpp / 8, outputFile); } for (int p = 0; p < padding; p++) { fputc(0, outputFile); // Write padding for the new image } } // Close the files fclose(inputFile); fclose(outputFile); printf("BMP image cropped successfully\n");
修改方案
问题根源在于BMP的像素数据是从图像底部到顶部存储的:视觉上的图像上半部分,对应文件中像素数据的最后600行。当前代码直接读取文件开头的600行像素,实际对应视觉上的下半部分,因此需要调整文件指针位置,跳过不需要的行数据。
具体步骤:
计算原图像每行的总字节数(含padding)
先计算原图像每行像素的字节数,再加上BMP要求的4字节对齐padding:int original_width = 3200; // 原图像宽度 int original_height = 1200; // 原图像高度 int pixel_bytes_per_row = original_width * (header.bpp / 8); int original_padding = (4 - (pixel_bytes_per_row % 4)) % 4; int original_row_size = pixel_bytes_per_row + original_padding;定位到目标数据的起始位置
要保留视觉上的上半部分,需要跳过原图像的前original_height - new_height行(即600行)。先将输入文件指针移动到BMP数据区的起始位置(由BMP头中的offset字段指定),再跳过对应字节:// 移动到BMP数据区开头 fseek(inputFile, header.offset, SEEK_SET); // 跳过原图像的前600行(对应视觉下半部分的存储数据) int skip_rows = original_height - new_height; fseek(inputFile, skip_rows * original_row_size, SEEK_CUR);读取目标行数据并写入输出文件
此时文件指针已指向视觉上半部分的起始行,读取600行数据即可,同时要注意跳过输入文件中每行的原padding,避免指针错位。
修改后的完整核心代码
// 原图像尺寸 int original_width = 3200; int original_height = 1200; int newWidth = original_width; int newHeight = 600; // Update the width and height in the BMP header header.width = newWidth; header.height = newHeight; printf("New header width: %d\n", header.width); printf("New header height: %d\n", header.height); // Write the modified BMP header to the output file fwrite(&header, sizeof(BMPHeader), 1, outputFile); // 计算原图像每行总字节数(含padding) int pixel_bytes_per_row = original_width * (header.bpp / 8); int original_padding = (4 - (pixel_bytes_per_row % 4)) % 4; int original_row_size = pixel_bytes_per_row + original_padding; // 计算新图像的padding int new_padding = (4 - (newWidth * (header.bpp / 8)) % 4) % 4; // 定位到视觉上半部分的起始数据位置 fseek(inputFile, header.offset, SEEK_SET); int skip_rows = original_height - newHeight; fseek(inputFile, skip_rows * original_row_size, SEEK_CUR); // Copy the image data unsigned char pixel[4]; for (int y = 0; y < newHeight; y++) { // 读取一行像素并写入 for (int x = 0; x < newWidth; x++) { fread(pixel, sizeof(unsigned char), header.bpp / 8, inputFile); fwrite(pixel, sizeof(unsigned char), header.bpp / 8, outputFile); } // 跳过输入文件中当前行的padding fseek(inputFile, original_padding, SEEK_CUR); // 写入新图像的padding for (int p = 0; p < new_padding; p++) { fputc(0, outputFile); } } // Close the files fclose(inputFile); fclose(outputFile); printf("BMP image cropped successfully\n");
关键说明:
- 必须跳过输入文件中每行的原padding,否则文件指针会错位,导致后续读取的像素数据混乱。
- 新图像的padding需要单独计算并写入,即使本次宽度未修改,该逻辑也能适配后续宽度调整的场景。
内容的提问来源于stack exchange,提问作者corp
相关产品推荐
相关产品推荐

