c - 在 C-windows 中截图

标签 c windows screenshot

我想在我的 Windows 机器上用 C 截屏并将其保存为 jpg 或 bmp 或其他格式。不管怎样,我试着自己做,它没问题,工作得很好,但它慢得令人难以忍受,不像 prt scr 键 - 我想知道是否有办法访问 prt scr剪贴板并以某种方式将其粘贴到 jpg/png 文件中,或者如果有更快的方法来获取所有屏幕像素。 那是我的代码:

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 做起来容易吗?

最佳答案

嗯... GetPixel() 本身真的很慢,然后将它组合在一个循环中并进行如此多的重做...不太好。 BitBlt 函数要快得多 - 这是一个示例:

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 - 在 C-windows 中截图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25200011/

相关文章:

c - 偏移量如何进入堆栈?

c - C中最大和最小指针地址

javascript - 使用 PhantomJS 的多个 HTML 页面的屏幕截图

c - 这些使我的程序停止运行的 for 循环出了什么问题?

c - Mac OS X 上 exuberant ctags 的问题

c++ - 如何声明库和应用程序之间共享的类

c# - 检测符号链接(symbolic link)、连接点、挂载点和硬链接(hard link)

python - 本地python简单http服务器在Windows中发送错误的mime类型,但在Linux中不发送错误的mime类型 for.svg

android - 如何以编程方式在警报对话框的 android 中截取屏幕截图

android - 在应用程序关闭时截取设备屏幕截图