在 C-windows 中截取屏幕截图 [英] Take a screenshot in C - windows

查看:110
本文介绍了在 C-windows 中截取屏幕截图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的 Windows 机器上用 C 语言截取屏幕截图并将其保存为 jpg 或 bmp 或其他格式.无论如何,我尝试自己做,它可以并且运行良好,但速度慢得令人无法忍受,不像 prt scr 键 - 我想知道是否有办法访问 prt scr剪贴板并以某种方式将其粘贴到 jpg/png 文件中,或者是否有更快的方法来获取所有屏幕像素.这是我的代码:

I want to take a screenshot in C on my windows machine and save it as a jpg or bmp or whatever. Anyway, I tried to do it by my own, it's okay and working well but it's UNBEARABLY SLOW, unlike prt scr key - I wonder if there's a way to access prt scr clipboard and somehow paste it in a jpg/png file OR if there's a faster way to get all of the screen pixels. That's my code:

int main()
{
    bitmap_t pic;
    int i, j;
    pic.width = GetSystemMetrics(SM_CXSCREEN);
    pic.height = GetSystemMetrics(SM_CYSCREEN);

    pic.pixels = (pixel_t**)malloc(sizeof(pixel_t*)*pic.width);
    for(i = 0 ; i < pic.height ; i++)
    {
        pic.pixels[i] = (pixel_t*)malloc(sizeof(pixel_t)*pic.height);
    }

    HDC hdc = GetDC(NULL);
    COLORREF c;
    printf("Size of your monitor is %d by %d.\n", pic.width, pic.height);
    for(i = 0 ; i < pic.width ; i++)
    {
        for(j = 0 ; j < pic.height ; j++)
        {
            c = GetPixel(hdc, i, j);
            pic.pixels[i][j].red = (uint8_t)GetRValue(c);
            pic.pixels[i][j].green = (uint8_t)GetGValue(c);
            pic.pixels[i][j].blue = (uint8_t)GetBValue(c);
        }
    }

    ReleaseDC(NULL, hdc);
    save_png_to_file(&pic, "D:\\pic.png");

    for(i = 0 ; i < pic.height ; i++)
    {
        free(pic.pixels[i]);
    }
    free(pic.pixels);

    return 0;
}

函数 save_png_to_file 正常工作,循环时间太长(我的屏幕是 1366x768,它有超过一百万个循环条目) - 为什么当键 prt scr<时它这么慢/code> 做起来容易吗?

The function save_png_to_file is working propely, the loop is taking too long (my screen is 1366x768 and it's over million loop entries) - why is it so slow when the key prt scr is doing it easily?

推荐答案

嗯... GetPixel() 本身真的很慢,然后将它组合在一个循环中,并进行了多次重复...不能很好.函数 BitBlt 快了很多 - 这是一个例子:

Hmm... GetPixel() is really slow by itself, then combining it in a loop with this many do-overs... Can't be good. The function BitBlt is A LOT faster - here is an example:

BOOL SaveToFile(HBITMAP hBitmap3, LPCTSTR lpszFileName)
{   
  HDC hDC;
  int iBits;
  WORD wBitCount;
  DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
  BITMAP Bitmap0;
  BITMAPFILEHEADER bmfHdr;
  BITMAPINFOHEADER bi;
  LPBITMAPINFOHEADER lpbi;
  HANDLE fh, hDib, hPal,hOldPal2=NULL;
  hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
  iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
  DeleteDC(hDC);
  if (iBits <= 1)
    wBitCount = 1;
  else if (iBits <= 4)
    wBitCount = 4;
  else if (iBits <= 8)
    wBitCount = 8;
  else
    wBitCount = 24; 
  GetObject(hBitmap3, sizeof(Bitmap0), (LPSTR)&Bitmap0);
  bi.biSize = sizeof(BITMAPINFOHEADER);
  bi.biWidth = Bitmap0.bmWidth;
  bi.biHeight =-Bitmap0.bmHeight;
  bi.biPlanes = 1;
  bi.biBitCount = wBitCount;
  bi.biCompression = BI_RGB;
  bi.biSizeImage = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrImportant = 0;
  bi.biClrUsed = 256;
  dwBmBitsSize = ((Bitmap0.bmWidth * wBitCount +31) & ~31) /8
                                                * Bitmap0.bmHeight; 
  hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
  lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
  *lpbi = bi;

  hPal = GetStockObject(DEFAULT_PALETTE);
  if (hPal)
  { 
    hDC = GetDC(NULL);
    hOldPal2 = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
    RealizePalette(hDC);
  }


  GetDIBits(hDC, hBitmap3, 0, (UINT) Bitmap0.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) 
    +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);

  if (hOldPal2)
  {
    SelectPalette(hDC, (HPALETTE)hOldPal2, TRUE);
    RealizePalette(hDC);
    ReleaseDC(NULL, hDC);
  }

  fh = CreateFile(lpszFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, 
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); 

  if (fh == INVALID_HANDLE_VALUE)
    return FALSE; 

  bmfHdr.bfType = 0x4D42; // "BM"
  dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
  bmfHdr.bfSize = dwDIBSize;
  bmfHdr.bfReserved1 = 0;
  bmfHdr.bfReserved2 = 0;
  bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;

  WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);

  WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
  GlobalUnlock(hDib);
  GlobalFree(hDib);
  CloseHandle(fh);

  return TRUE;
} 

int screenCapture(int x, int y, int w, int h, LPCSTR fname)
{
    HDC hdcSource = GetDC(NULL);
    HDC hdcMemory = CreateCompatibleDC(hdcSource);

    int capX = GetDeviceCaps(hdcSource, HORZRES);
    int capY = GetDeviceCaps(hdcSource, VERTRES);

    HBITMAP hBitmap = CreateCompatibleBitmap(hdcSource, w, h);
    HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);

    BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
    hBitmap = (HBITMAP)SelectObject(hdcMemory, hBitmapOld);

    DeleteDC(hdcSource);
    DeleteDC(hdcMemory);

    HPALETTE hpal = NULL;
    if(SaveToFile(hBitmap, fname)) return 1;
    return 0;
}

int main()
{
    screenCapture(0, 0, GetSystemMetric, 768, "D:\\MyFirstScreeshot.bmp");

    return 0;
}

这篇关于在 C-windows 中截取屏幕截图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆