設置 | 登錄 | 註冊

目前共有15篇帖子。

【講解】位圖的結構

1樓 巨大八爪鱼 2016-6-23 20:04
#include <stdio.h>
#include <Windows.h>

#pragma warning(disable: 4996)

int main(void)
{
    BITMAPFILEHEADER fileheader; // 位圖文件頭
    BITMAPINFOHEADER infoheader; // 位圖信息
    BYTE bits[100][452]; // 實際位圖數據, 第一維為高度, 第二維為寬度乘每像素的字節數, 第二維必須是4的倍數
    // 這裡位圖的寬度為150, 因為150*3=450, 450不是4的倍數, 比450大且離450最近的4的倍數是452, 所以第二維為452
    FILE *fp = fopen("image.bmp", "wb");
    if (fp == NULL)
        return 1;

    /* 寫入位圖文件頭信息 */
    fileheader.bfType = *(PWORD)"BM"; // 文件類型, 必須為BM
    fileheader.bfSize = sizeof(fileheader) + sizeof(infoheader) + sizeof(bits); // 位圖總大小
    fileheader.bfReserved1 = fileheader.bfReserved2 = 0; // 保留字節
    fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader); // 文件開頭到位圖數據的距離
    fwrite(&fileheader, sizeof(fileheader), 1, fp);

    /* 寫入位圖信息 */
    infoheader.biSize = sizeof(infoheader); // 本結構體的大小
    infoheader.biWidth = 150; // 位圖的寬度
    infoheader.biHeight = 100; // 位圖的高度 (正數: 位圖數據從底到頂; 負數: 位圖數據從底到頂)
    infoheader.biPlanes = 1; // 目標設備的平面數 (必須為1)
    infoheader.biBitCount = 24; // 每個像素的顏色用24位, 即3位元組表示
    infoheader.biCompression = BI_RGB; // 壓縮方式
    infoheader.biSizeImage = 0; // 位圖數據的大小 (BI_RGB類型的位圖可設為0)
    infoheader.biXPelsPerMeter = infoheader.biYPelsPerMeter = 0; // 位圖水平、垂直解析度, 單位: 像素/米
    infoheader.biClrUsed = 0; // 位圖實際使用的顏色表中的顏色數, 0表示使用了所有顏色
    infoheader.biClrImportant = 0; // 為了顯示該位圖必須要用到的顏色數, 0表示所有顏色都用到了
    fwrite(&infoheader, sizeof(BITMAPINFOHEADER), 1, fp);

    /* 寫入圖像數據 */
    memset(bits, 0, sizeof(bits));
    bits[0][2] = 0xff;
    bits[0][4] = 0xff;
    bits[0][6] = 0xff;
    bits[1][0] = bits[1][1] = bits[1][2] = 0xee;
    fwrite(bits, sizeof(bits), 1, fp);
    
    fclose(fp);
    return 0;
}

所創建的位圖:

左下角:


2樓 巨大八爪鱼 2016-6-23 20:05
從程序中可以看出,一個(不使用調色板的)位圖文件的結構如下:
BITMAPFILEHEADER + BITMAPINFOHEADER + 實際位圖數據
3樓 巨大八爪鱼 2016-6-23 21:01
【一個使用調色板的3色位圖的例子】
#include <stdio.h>
#include <Windows.h>

#pragma warning(disable: 4996)

int main(void)
{
    BITMAPFILEHEADER fileheader;
    BITMAPINFOHEADER infoheader;
    BYTE bits[100][76]; // 150/2=75, 76%4=0
    RGBQUAD colors[] = {{201, 174, 254, 0}, {10, 166, 84, 0}, {1, 128, 255, 0}};
    FILE *fp;
    int i;
   
    fp = fopen("image.bmp", "wb");
    if (fp == NULL)
        return 1;

    fileheader.bfType = *(PWORD)"BM";
    fileheader.bfSize = sizeof(fileheader) + sizeof(infoheader) + sizeof(colors) + sizeof(bits);
    fileheader.bfReserved1 = fileheader.bfReserved2 = 0;
    fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader) + sizeof(colors);
    fwrite(&fileheader, sizeof(fileheader), 1, fp);

    infoheader.biSize = sizeof(infoheader);
    infoheader.biWidth = 150;
    infoheader.biHeight = 100;
    infoheader.biPlanes = 1;
    infoheader.biBitCount = 4; // 1~16色
    infoheader.biCompression = BI_RGB;
    infoheader.biSizeImage = 0;
    infoheader.biXPelsPerMeter = infoheader.biYPelsPerMeter = 0;
    infoheader.biClrUsed = _countof(colors); // 顏色數
    infoheader.biClrImportant = 0;
    fwrite(&infoheader, sizeof(BITMAPINFOHEADER), 1, fp);

    fwrite(&colors, sizeof(colors), 1, fp);

    memset(bits, 0, sizeof(bits));
    for (i = 0; i < 30; i++)
        memset(bits[i], 0x11, 75);
    for (; i < 70; i++)
        memset(bits[i], 0x22, 75);


    fwrite(bits, sizeof(bits), 1, fp);
   
    fclose(fp);
    return 0;
}

所創建的位圖:

4樓 巨大八爪鱼 2016-6-23 21:12
【一個使用調色板的雙色位圖例子】
#include <stdio.h>
#include <Windows.h>

#pragma warning(disable: 4996)

int main(void)
{
    BITMAPFILEHEADER fileheader;
    BITMAPINFOHEADER infoheader;
    BYTE bits[100][20]; // 每字節表示8個像素, 每行只需19位元組, 20%4=0
    RGBQUAD colors[] = {{201, 174, 254, 0}, {10, 166, 84, 0}}; // 調色板中只有兩種顏色
    FILE *fp;
    int i;
   
    fp = fopen("image.bmp", "wb");
    if (fp == NULL)
        return 1;

    fileheader.bfType = *(PWORD)"BM";
    fileheader.bfSize = sizeof(fileheader) + sizeof(infoheader) + sizeof(colors) + sizeof(bits);
    fileheader.bfReserved1 = fileheader.bfReserved2 = 0;
    fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader) + sizeof(colors);
    fwrite(&fileheader, sizeof(fileheader), 1, fp);

    infoheader.biSize = sizeof(infoheader);
    infoheader.biWidth = 150;
    infoheader.biHeight = 100;
    infoheader.biPlanes = 1;
    infoheader.biBitCount = 1; // 每一位表示一個像素
    infoheader.biCompression = BI_RGB;
    infoheader.biSizeImage = 0;
    infoheader.biXPelsPerMeter = infoheader.biYPelsPerMeter = 0;
    infoheader.biClrUsed = 0; // 2^biBitCount
    infoheader.biClrImportant = 0;
    fwrite(&infoheader, sizeof(BITMAPINFOHEADER), 1, fp);

    fwrite(&colors, sizeof(colors), 1, fp);

    memset(bits, 0, sizeof(bits));
    for (i = 0; i < 50; i++)
        memset(bits[i], 0xff, 10);
    for (; i < 100; i++)
    {
        memset(bits[i] + 10, 0xff, 8);
        bits[i][18] = 0xfc;
    }

    fwrite(bits, sizeof(bits), 1, fp);
   
    fclose(fp);
    return 0;
}
所創建的位圖:

5樓 巨大八爪鱼 2016-6-23 21:15
對於使用了調色板的位圖,其文件結構為:
BITMAPFILEHEADER + BITMAPINFOHEADER + RGBQUAD[n] + BYTE[a][b]
其中n為調色板中的顏色數
a為圖像高度
b為圖像寬度除以每字節的像素數,且b必須為4的倍數
6樓 巨大八爪鱼 2016-6-23 21:16
7樓 巨大八爪鱼 2016-6-23 21:23
另外,Windows里還有一個BITMAPINFO結構體,
BITMAPINFO = BITMAPINFOHEADER + RGBQUAD[1],
不過這裡用不到,我們只需要BITMAPINFOHEADER結構就行了
8樓 巨大八爪鱼 2016-6-23 21:27
BITMAPINFOHEADER結構體裡面的biSize成員非常重要,它標識了該結構體的版本。
歷史上已有很多種版本出現:

最常用的是大小為40的那個版本。
9樓 巨大八爪鱼 2016-6-23 22:11
biPlanes成員表示顏色平面數(Number of color planes),可用下面的代碼獲取當前顯示器的顏色平面數:
#include <stdio.h>
#include <Windows.h>

int main(void)
{
    HDC hdc = GetDC(NULL);
    int n;
    n = GetDeviceCaps(hdc, PLANES);
    ReleaseDC(NULL, hdc);
    printf("n=%d\n", n);
    return 0;
}
一般都是1。
10樓 巨大八爪鱼 2016-6-23 22:50
【創建位圖數據並放入剪切板】
#include <Windows.h>

#pragma warning(disable: 4996)

void main(void)
{
    BITMAPINFOHEADER infoheader;
    BYTE bits[100][20]; // 每字節表示8個像素, 每行只需19位元組, 20%4=0
    HGLOBAL hMem;
    LPBYTE lpMem;
    RGBQUAD colors[] = {{101, 174, 254, 0}, {221, 166, 84, 0}}; // 調色板中只有兩種顏色
    int i;

    infoheader.biSize = sizeof(infoheader);
    infoheader.biWidth = 150;
    infoheader.biHeight = 100;
    infoheader.biPlanes = 1;
    infoheader.biBitCount = 1; // 每一位表示一個像素
    infoheader.biCompression = BI_RGB;
    infoheader.biSizeImage = 0;
    infoheader.biXPelsPerMeter = infoheader.biYPelsPerMeter = 0;
    infoheader.biClrUsed = 0; // 2^biBitCount
    infoheader.biClrImportant = 0;

    memset(bits, 0, sizeof(bits));
    for (i = 0; i < 50; i++)
        memset(bits[i], 0xff, 10);
    for (; i < 100; i++)
    {
        memset(bits[i] + 10, 0xff, 8);
        bits[i][18] = 0xfc;
    }

    OpenClipboard(NULL);
    EmptyClipboard();

    hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(infoheader) + sizeof(colors) + sizeof(bits));
    lpMem = (LPBYTE)GlobalLock(hMem);
    memcpy(lpMem, &infoheader, sizeof(infoheader));
    memcpy(lpMem + sizeof(infoheader), colors, sizeof(colors));
    memcpy(lpMem + sizeof(infoheader) + sizeof(colors), bits, sizeof(bits));
    GlobalUnlock(hMem);
    SetClipboardData(CF_DIB, hMem);
   
    CloseClipboard();
}

內容轉換:

回覆帖子
內容:
用戶名: 您目前是匿名發表。
驗證碼:
看不清?換一張
©2010-2025 Purasbar Ver3.0 [手機版] [桌面版]
除非另有聲明,本站採用知識共享署名-相同方式共享 3.0 Unported許可協議進行許可。