CS50技术问询:如何修改BMP的biHeight实现图像180度旋转?
实现BMP图像180度旋转的修改方案
要让BMP图像旋转180度,仅修改biHeight的符号是不够的,还需要逆序读取原图像的扫描行,同时将每行内的像素逆序写入。以下是针对你提供的CS50 BMP复制代码的具体修改步骤:
核心修改点
- 调整
BITMAPINFOHEADER中的biHeight:将其设置为原数值的相反数,告知BMP解码器图像存储方向反转 - 逆序读取原图像扫描行:从最后一行开始读取,直到第一行
- 每行像素逆序写入:读取一行像素后,从最后一个像素开始写入输出文件
修改后的完整代码
// Copies a BMP file and rotates it 180 degrees #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "bmp.h" int main(int argc, char *argv[]) { // Ensure proper usage if (argc != 3) { printf("Usage: rotate infile outfile\n"); return 1; } // Remember filenames char *infile = argv[1]; char *outfile = argv[2]; // Open input file FILE *inptr = fopen(infile, "r"); if (inptr == NULL) { printf("Could not open %s.\n", infile); return 2; } // Open output file FILE *outptr = fopen(outfile, "w"); if (outptr == NULL) { fclose(inptr); printf("Could not create %s.\n", outfile); return 3; } // Read infile's BITMAPFILEHEADER BITMAPFILEHEADER bf; fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr); // Read infile's BITMAPINFOHEADER BITMAPINFOHEADER bi; fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr); // Ensure infile is (likely) a 24-bit uncompressed BMP 4.0 if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || bi.biBitCount != 24 || bi.biCompression != 0) { fclose(outptr); fclose(inptr); printf("Unsupported file format.\n"); return 4; } // 计算图像实际高度(兼容biHeight为负的情况) int actual_height = abs(bi.biHeight); // 修改biHeight符号,标记图像存储方向反转 bi.biHeight = -bi.biHeight; // Write outfile's BITMAPFILEHEADER fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr); // Write outfile's modified BITMAPINFOHEADER fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr); // Determine padding for scanlines int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; // 计算每行总字节数(像素数据+padding) int row_size = bi.biWidth * sizeof(RGBTRIPLE) + padding; // 分配内存存储一行像素 RGBTRIPLE *row = malloc(bi.biWidth * sizeof(RGBTRIPLE)); if (row == NULL) { fclose(inptr); fclose(outptr); printf("Memory allocation failed.\n"); return 5; } // 逆序读取每一行:从最后一行到第一行 for (int i = 0; i < actual_height; i++) { // 定位到当前要读取的行的起始位置 long current_row_pos = bf.bfOffBits + (actual_height - 1 - i) * row_size; fseek(inptr, current_row_pos, SEEK_SET); // 读取当前行的所有像素(跳过padding) fread(row, sizeof(RGBTRIPLE), bi.biWidth, inptr); // 逆序写入当前行的像素到输出文件 for (int j = bi.biWidth - 1; j >= 0; j--) { fwrite(&row[j], sizeof(RGBTRIPLE), 1, outptr); } // 写入padding到输出文件 for (int k = 0; k < padding; k++) { fputc(0x00, outptr); } } // 释放内存 free(row); // Close infile fclose(inptr); // Close outfile fclose(outptr); // Success return 0; }
关键修改说明
调整
biHeight:- 用
abs(bi.biHeight)获取图像实际高度,兼容原图像biHeight为负(表示从上到下存储)的场景 - 将
bi.biHeight设为原数值的相反数,告知解码器输出图像的扫描行存储方向与原图像相反
- 用
逆序读取扫描行:
- 通过
fseek定位到原图像倒数第i+1行的起始位置,计算公式为bf.bfOffBits + (actual_height - 1 - i) * row_size,其中bf.bfOffBits是像素数据的起始偏移量,row_size是每行总字节数
- 通过
每行像素逆序写入:
- 先将整行像素读取到内存缓冲区,再从最后一个像素开始循环写入,实现每行的左右翻转
内存管理:
- 用
malloc分配内存存储一行像素,减少频繁IO操作,程序结束前释放内存避免泄漏
- 用
内容的提问来源于stack exchange,提问作者Alok Chedambath
相关产品推荐
相关产品推荐

