設置 | 登錄 | 註冊

作者共發了9篇帖子。

【程序】屏幕截圖

1樓 巨大八爪鱼 2016-6-24 14:32
#include <stdio.h>
#include <Windows.h>

#pragma warning(disable: 4996) // 關閉fopen, scanf等庫函數的_s警告

// 為指定大小的位圖分配內存
LPBYTE AllocateBits(int nWidth, int nHeight, int nBitcCount, int *pSize)
{
    *pSize = (int)((nWidth * nBitcCount + 31) / 32) * 4 * nHeight;
    if (*pSize < 0)
        *pSize = -*pSize;
    return (LPBYTE)malloc(*pSize);
}

int main(void)
{
    BITMAPFILEHEADER fileheader;
    BITMAPINFOHEADER infoheader; // 由於BITMAPINFO結構體中有一個沒用的調色板, 所以不使用那個結構體
    FILE *fp;
    HBITMAP hbmp; // DDB句柄
    HDC hdc, hdcMem;
    int width, height;
    int size;
    PBYTE pBits; // DIB數據

    /* 獲取屏幕解像度 */
    width = GetSystemMetrics(SM_CXSCREEN);
    height = GetSystemMetrics(SM_CYSCREEN);
    printf("屏幕解像度: %dx%d\n", width, height);

    /* 創建設備有關位圖(DDB)及其DC, 並把屏幕上的內容複製到該位圖上 */
    hdc = GetDC(NULL); // 獲取屏幕DC
    hbmp = CreateCompatibleBitmap(hdc, width, height);
    hdcMem = CreateCompatibleDC(hdc); // 創建內存DC
    SelectObject(hdcMem, hbmp);
    BitBlt(hdcMem, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
    ReleaseDC(NULL, hdc);

    /* 填寫設備無關位圖(DIB)的結構體 */
    ZeroMemory(&infoheader, sizeof(infoheader));
    infoheader.biSize = sizeof(infoheader);
    infoheader.biPlanes = 1;
    infoheader.biBitCount = 24;
    infoheader.biWidth = width;
    infoheader.biHeight = height;
    
    /* 為設備無關位圖分配內存, 然後把設備有關位圖轉換為設備無關位圖 */
    pBits = AllocateBits(width, height, infoheader.biBitCount, &size);
    GetDIBits(hdcMem, hbmp, 0, height, pBits, (BITMAPINFO *)&infoheader, DIB_RGB_COLORS); // DDB -> DIB

    /* 填寫設備無關位圖文件的結構體 */
    fileheader.bfReserved1 = fileheader.bfReserved2 = 0;
    fileheader.bfSize = sizeof(fileheader) + sizeof(infoheader) + size;
    fileheader.bfType = *(PWORD)"BM";
    fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader);

    /* 打開位圖文件並寫入 */
    fp = fopen("file.bmp", "wb");
    if (fp != NULL)
    {
        fwrite(&fileheader, sizeof(fileheader), 1, fp);
        fwrite(&infoheader, sizeof(infoheader), 1, fp);
        fwrite(pBits, size, 1, fp);
        fclose(fp);
    }
    else
        puts("打開文件失敗");
    
    /* 釋放內存 */
    free(pBits);
    DeleteObject(hbmp);
    DeleteDC(hdcMem);
}
2樓 巨大八爪鱼 2016-6-24 14:32
保存的文件:

3樓 巨大八爪鱼 2016-6-24 14:36
設備無關位圖數據大小的計算公式:


4樓 巨大八爪鱼 2016-6-24 14:38
顯示器是設備,其圖像是設備有關位圖,HBITMAP句柄也是設備有關位圖,而bmp位圖文件是設備無關位圖。
因此,必須要把設備有關位圖轉換成設備無關位圖,才能寫入文件。轉換方法就是:調用GetDIBits函數。
5樓 巨大八爪鱼 2016-6-24 14:44
BitBlt是在兩個同類設備之間復製圖像,複製的是設備有關位圖。
如果兩個設備不是同類設備,BitBlt將出錯。

若要把一種設備的設備有關位圖複製到另一種設備,必須先轉換為設備無關位圖,再轉換為另一種設備的設備有關位圖。
DDB轉換為DIB:調用GetDIBits函數
DIB轉換為DDB:調用SetDIBits或StretchDIBits函數
6樓 巨大八爪鱼 2016-6-24 14:46
把顯示器上的圖像用彩色打印機打印到紙上可以發現,兩者的顏色是有差異的,這表明不同的設備支持的顏色是不一樣的。顯示器顯示一個bmp文件(設備無關位圖)的圖像,就有一個從DIB到DDB的轉換過程。
7樓 巨大八爪鱼 2016-6-24 15:12
【使用GetDIBits函數將DDB轉換為使用調色板的DIB的程序】
#include <stdio.h>
#include <Windows.h>

#pragma warning(disable: 4996)

LPBYTE AllocateBits(int nWidth, int nHeight, int nBitcCount, int *pSize)
{
    *pSize = (int)((nWidth * nBitcCount + 31) / 32) * 4 * nHeight;
    if (*pSize < 0)
        *pSize = -*pSize;
    return (LPBYTE)malloc(*pSize);
}

// 設置調色板中的顏色
void set_palette(LPBITMAPINFO info)
{
    info->bmiColors[0].rgbBlue = 14;
    info->bmiColors[0].rgbGreen = 201;
    info->bmiColors[0].rgbRed = 255;
    info->bmiColors[1].rgbBlue = 235;
    info->bmiColors[1].rgbGreen = 35;
    info->bmiColors[1].rgbRed = 90;
}

int main(void)
{
    BITMAPFILEHEADER fileheader;
    FILE *fp;
    HBITMAP hbmp;
    HDC hdc, hdcMem;
    int width, height;
    int size, infosize;
    LPBITMAPINFO info; // 位圖信息和調色板
    PBYTE pBits;

    width = GetSystemMetrics(SM_CXSCREEN);
    height = GetSystemMetrics(SM_CYSCREEN);
    printf("屏幕解像度: %dx%d\n", width, height);

    hdc = GetDC(NULL);
    hbmp = CreateCompatibleBitmap(hdc, width, height);
    hdcMem = CreateCompatibleDC(hdc);
    SelectObject(hdcMem, hbmp);
    BitBlt(hdcMem, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
    ReleaseDC(NULL, hdc);

    infosize = sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);
    info = (LPBITMAPINFO)malloc(infosize);
    ZeroMemory(info, infosize);
    info->bmiHeader.biSize = sizeof(info->bmiHeader);
    info->bmiHeader.biPlanes = 1;
    info->bmiHeader.biBitCount = 1;
    info->bmiHeader.biWidth = width;
    info->bmiHeader.biHeight = height;

    set_palette(info);
    pBits = AllocateBits(width, height, info->bmiHeader.biBitCount, &size);
    GetDIBits(hdcMem, hbmp, 0, height, pBits, info, DIB_PAL_COLORS); // DDB -> DIB
    set_palette(info); // GetDIBits會修改調色板中的顏色

    fileheader.bfReserved1 = fileheader.bfReserved2 = 0;
    fileheader.bfSize = sizeof(fileheader) + infosize + size;
    fileheader.bfType = *(PWORD)"BM";
    fileheader.bfOffBits = sizeof(fileheader) + infosize;

    fp = fopen("file.bmp", "wb");
    if (fp != NULL)
    {
        fwrite(&fileheader, sizeof(fileheader), 1, fp);
        fwrite(info, infosize, 1, fp);
        fwrite(pBits, size, 1, fp);
        fclose(fp);
    }
    else
        puts("打開文件失敗");
   
    free(info);
    free(pBits);
    DeleteObject(hbmp);
    DeleteDC(hdcMem);
}


8樓 巨大八爪鱼 2016-6-24 16:02
屏幕截圖的步驟:創建一個DDB,把屏幕上的內容讀出來放到DDB裏面。然後根據屏幕尺寸分配一塊DIB內存,再將DDB轉換為DIB放進去,最後把DIB寫入文件。
9樓 巨大八爪鱼 2016-6-24 17:36
GetBitmapBits函數的功能和GetDIBits相似,只不過是為了兼容16位程序而保留的函數,不推薦使用。

內容轉換:

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