首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C 語言實現 BMP 圖片 90 度順時針旋轉(單色位圖)

     編輯:關於C

BMP 檔案格式基礎

BMP 為無壓縮位圖格式,主要包含:

  1. File Header (14 bytes):標識 BM、檔案大小、資料偏移。
  2. Info Header (40 bytes, BITMAPINFOHEADER):寬、高、位深、壓縮方式、圖像大小等。
  3. 調色盤(可選):位深 ≤ 8 時存在,單色圖 2 色(8 bytes)。
  4. 像素資料:每行 4 位元組對齊(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 位圖慢。
  • 擴充至 24 位真彩色:像素為 3 bytes,無位運算,直接 memcpy 3 bytes 更快。
  • 大圖建議分塊處理以利用快取局部性。

常見坑點

  1. 行對齊:必須按 4 字節對齊計算 stride,否則旋轉後圖像傾斜或錯位。
  2. 原點位置:BMP 底部為 y=0(biHeight > 0),旋轉公式已處理垂直翻轉。
  3. 調色盤:單色圖必須複製調色盤,否則顏色顯示錯誤。
  4. biHeight 正負:正數=底部優先,負數=頂部優先(DIB),本代碼假設正數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved