从编程上进行屏幕截图并保存为PNG



我已经使用以下代码了一段时间:

#include <fstream>
#include <gdiplus.h>
#include <windows.h>
#include <iostream>
using namespace std;
void CaptureScreen(const char* filename)
{
    HDC hScreenDC = GetDC(0);
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
    int upper_left_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
    int upper_left_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
    int bitmap_dx = GetSystemMetrics(SM_CXVIRTUALSCREEN ) * 1.25f;
    int bitmap_dy = GetSystemMetrics(SM_CYVIRTUALSCREEN ) * 1.25f;
    // create file
    ofstream file(filename, ios::binary);
    if(!file) return;
    // save bitmap file headers
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;
    fileHeader.bfType      = 0x4d42;
    fileHeader.bfSize      = 0;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    infoHeader.biSize          = sizeof(infoHeader);
    infoHeader.biWidth         = bitmap_dx;
    infoHeader.biHeight        = -bitmap_dy;
    infoHeader.biPlanes        = 1;
    infoHeader.biBitCount      = 16;
    infoHeader.biCompression   = BI_RGB;
    infoHeader.biSizeImage     = 0;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed       = 0;
    infoHeader.biClrImportant  = 0;
    file.write((char*)&fileHeader, sizeof(fileHeader));
    file.write((char*)&infoHeader, sizeof(infoHeader));
    // dibsection information
    BITMAPINFO info;
    info.bmiHeader = infoHeader;
    // ------------------
    // THE IMPORTANT CODE
    // ------------------
    // create a dibsection and blit the window contents to the bitmap
    BYTE* memory = 0;
    HBITMAP bitmap = CreateDIBSection(hScreenDC, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
    SelectObject(hMemoryDC, bitmap);
    BitBlt(hMemoryDC, 0, 0, bitmap_dx, bitmap_dy, hScreenDC, upper_left_x, upper_left_y, SRCCOPY);
    DeleteDC(hMemoryDC);
    ReleaseDC(NULL, hScreenDC);
    // save dibsection data
    int bytes = (((16*bitmap_dx + 31) & (~31))/8)*bitmap_dy;
    file.write((const char *)memory, bytes);
    DeleteObject(bitmap);
}
int main()
{
    CaptureScreen("ok.jpg");
    return 0;
}

,但它似乎会生成一个太大的BMP文件,因为将位图保存了未压缩。

我正在寻找一种捕获屏幕截图并将其保存到PNG格式的缓冲区,通过TCP连接发送并将其保存为PNG文件的方法。

我相信这与将BI_PNG分配给infoHeader.biCompressionbytes的不同计算有关。

http://lodev.org/lodepng/

#include <fstream>
#include <gdiplus.h>
#include <windows.h>
#include <iostream>
#include "lodepng.h"
const int bits_per_pixel = 24;

using namespace std;
void CaptureScreen(const char* filename)
{
    HDC hScreenDC = GetDC(0);
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
    int upper_left_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
    int upper_left_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
    int bitmap_dx = GetSystemMetrics(SM_CXVIRTUALSCREEN ) * 1.25f;
    int bitmap_dy = GetSystemMetrics(SM_CYVIRTUALSCREEN ) * 1.25f;
    // create file
    ofstream file(filename, ios::binary);
    if(!file) return;
    // save bitmap file headers
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;
    fileHeader.bfType      = 0x4d42;
    fileHeader.bfSize      = 0;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    infoHeader.biSize          = sizeof(infoHeader);
    infoHeader.biWidth         = bitmap_dx;
    infoHeader.biHeight        = -bitmap_dy;
    infoHeader.biPlanes        = 1;
    infoHeader.biBitCount      = bits_per_pixel;
    infoHeader.biCompression   = BI_RGB;
    infoHeader.biSizeImage     = 0;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed       = 0;
    infoHeader.biClrImportant  = 0;
    file.write((char*)&fileHeader, sizeof(fileHeader));
    file.write((char*)&infoHeader, sizeof(infoHeader));
    // dibsection information
    BITMAPINFO info;
    info.bmiHeader = infoHeader; 
    // ------------------
    // THE IMPORTANT CODE
    // ------------------
    // create a dibsection and blit the window contents to the bitmap
    BYTE* memory = 0;
    HBITMAP bitmap = CreateDIBSection(hScreenDC, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
    SelectObject(hMemoryDC, bitmap);
    BitBlt(hMemoryDC, 0, 0, bitmap_dx, bitmap_dy, hScreenDC, upper_left_x, upper_left_y, SRCCOPY);
    DeleteDC(hMemoryDC);
    ReleaseDC(NULL, hScreenDC);
    // save dibsection data
    int bytes = (((bits_per_pixel*bitmap_dx + 31) & (~31))/8)*bitmap_dy;
    file.write((const char *)memory, bytes);
    unsigned char *out_buffer;
    size_t out_buffer_len;
    unsigned error;
    if ( bits_per_pixel == 24 )
    {
        // convert memory from bgr format to rgb
        for ( unsigned i = 0; i< bytes-2; i+=3)
        {
            int tmp = memory[i+2];
            memory[i+2] = memory[i];
            memory[i] = tmp;
        }
        error = lodepng_encode24(&out_buffer,
                                          &out_buffer_len,
                                          memory,
                                          bitmap_dx,
                                          bitmap_dy);
    }
    if ( bits_per_pixel == 32 )
    {
        // convert memory from bgr format to rgb
        for ( unsigned i = 0; i< bytes-3; i+=4)
        {
            int tmp = memory[i+2];
            memory[i+2] = memory[i];
            memory[i] = tmp;
        }
        error = lodepng_encode32(&out_buffer,
                                          &out_buffer_len,
                                          memory,
                                          bitmap_dx,
                                          bitmap_dy);
    }

    if ( error )
    {
        std::cout << "error: " << error << 'n';
        return;
    }
    lodepng_save_file(out_buffer, out_buffer_len, "stam.png");


    // free(out);
    DeleteObject(bitmap);
}
int main()
{
    CaptureScreen("ok.jpg");
    return 0;
}

最新更新