作者共發了9篇帖子。 字體大小:較小 - 100% (默認)▼  內容轉換:不轉換▼
 
點擊 回復
424 8
【程序】屏幕截图
一派護法 十九級
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位程序而保留的函数,不推荐使用。

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
(快捷鍵:Ctrl+Enter)
 

本帖信息

點擊數:424 回複數:8
評論數: ?
作者:巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2016-6-24 17:36
 
©2010-2024 Arslanbar Ver2.0
除非另有聲明,本站採用共享創意姓名標示-相同方式分享 3.0 Unported許可協議進行許可。