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

如何用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行像素,实际对应视觉上的下半部分,因此需要调整文件指针位置,跳过不需要的行数据。

具体步骤:

  1. 计算原图像每行的总字节数(含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;
    
  2. 定位到目标数据的起始位置
    要保留视觉上的上半部分,需要跳过原图像的前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);
    
  3. 读取目标行数据并写入输出文件
    此时文件指针已指向视觉上半部分的起始行,读取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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:24:49