BMP 為無壓縮位圖格式,主要包含:
BM、檔案大小、資料偏移。stride = ((width * bitCount + 31) / 32) * 4)。90° 順時針:原座標 (x, y) → 新座標 (y, H-1-x),其中 W, H 為原寬高。新圖寬高互換。單色圖每像素 1 bit,需按位操作。
// bmp_rotate90.c
#include
#include
#include
#include
#include
#pragma pack(push, 2)
typedef struct {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop)
typedef struct {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BITMAPINFOHEADER;
int rotate90_cw(const char *src, const char *dst) {
FILE *fp = fopen(src, "rb");
if (!fp) { perror("open src"); return -1; }
BITMAPFILEHEADER fh;
BITMAPINFOHEADER ih;
fread(&fh, sizeof(fh), 1, fp);
fread(&ih, sizeof(ih), 1, fp);
if (fh.bfType != 0x4D42) { fprintf(stderr, "Not BMP\n"); fclose(fp); return -1; }
if (ih.biBitCount != 1) { fprintf(stderr, "Only 1-bit supported\n"); fclose(fp); return -1; }
// 讀取調色盤 (2 色 = 8 bytes)
uint8_t palette[8];
fread(palette, 1, 8, fp);
// 讀取像素資料
uint32_t srcStride = ((ih.biWidth + 31) / 32) * 4;
uint8_t *srcData = malloc(ih.biSizeImage);
fread(srcData, 1, ih.biSizeImage, fp);
fclose(fp);
// 計算目標參數
int32_t dstW = ih.biHeight;
int32_t dstH = ih.biWidth;
uint32_t dstStride = ((dstW + 31) / 32) * 4;
uint32_t dstImgSize = dstStride * dstH;
// 分配目標像素緩衝
uint8_t *dstData = calloc(1, dstImgSize);
// 逐像素旋轉(按位操作)
for (int y = 0; y < ih.biHeight; ++y) {
for (int x = 0; x < ih.biWidth; ++x) {
// 讀取源像素
uint32_t srcByteIdx = y * srcStride + (x >> 3);
uint8_t srcBit = 7 - (x & 7);
uint8_t pixel = (srcData[srcByteIdx] >> srcBit) & 1;
// 計算目標座標
int dx = y;
int dy = ih.biWidth - 1 - x;
uint32_t dstByteIdx = dy * dstStride + (dx >> 3);
uint8_t dstBit = 7 - (dx & 7);
if (pixel) dstData[dstByteIdx] |= (1 << dstBit);
}
}
// 寫入目標檔案
FILE *out = fopen(dst, "wb");
if (!out) { perror("open dst"); free(srcData); free(dstData); return -1; }
BITMAPFILEHEADER ofh = fh;
BITMAPINFOHEADER oih = ih;
oih.biWidth = dstW;
oih.biHeight = dstH;
oih.biSizeImage = dstImgSize;
ofh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 8 + dstImgSize;
ofh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 8;
fwrite(&ofh, sizeof(ofh), 1, out);
fwrite(&oih, sizeof(oih), 1, out);
fwrite(palette, 1, 8, out);
fwrite(dstData, 1, dstImgSize, out);
fclose(out);
free(srcData);
free(dstData);
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s input.bmp output.bmp\n", argv[0]);
return 1;
}
return rotate90_cw(argv[1], argv[2]);
}
gcc bmp_rotate90.c -o bmp_rotate90
./bmp_rotate90 input.bmp output.bmp
Windows 下若 int32_t 警告,可將 typedef int LONG 改為 typedef long LONG。
O(W×H),單色圖每像素需位運算,較 24/32 位圖慢。memcpy 3 bytes 更快。