【问题标题】:How do take a screenshot correctly with xlib?如何使用 xlib 正确截屏?
【发布时间】:2012-01-05 04:28:40
【问题描述】:

我正在尝试捕获屏幕图像以用于截屏。因此我需要一个快速的解决方案,并且不能依赖诸如 import 或 xwd 之类的 shell 程序。

这是我到目前为止编写的代码,但它失败并给了我一个垃圾图像,它似乎只是显示了几张奇怪颜色的图像的碎片。

关于我做错了什么有什么想法吗?

#include <X11/Xlib.h>
#include <X11/X.h>

#include <cstdio>
#include <CImg.h>
using namespace cimg_library;

int main()
{
   Display *display = XOpenDisplay(NULL);
   Window root = DefaultRootWindow(display);

   XWindowAttributes gwa;

   XGetWindowAttributes(display, root, &gwa);
   int width = gwa.width;
   int height = gwa.height;


   XImage *image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap);

   unsigned char *array = new unsigned char[width * height * 3];

   unsigned long red_mask = image->red_mask;
   unsigned long green_mask = image->green_mask;
   unsigned long blue_mask = image->blue_mask;

   for (int x = 0; x < width; x++)
      for (int y = 0; y < height ; y++)
      {
         unsigned long pixel = XGetPixel(image,x,y);

         unsigned char blue = pixel & blue_mask;
         unsigned char green = (pixel & green_mask) >> 8;
         unsigned char red = (pixel & red_mask) >> 16;

         array[(x + width * y) * 3] = red;
         array[(x + width * y) * 3+1] = green;
         array[(x + width * y) * 3+2] = blue;
      }

   CImg<unsigned char> pic(array,width,height,1,3);
   pic.save_png("blah.png");

   printf("%ld %ld %ld\n",red_mask>> 16, green_mask>>8, blue_mask);

   return 0;
}

【问题讨论】:

  • 嗨@lalaland,你能分享你的最终代码吗,这支持多显示器吗?
  • @Noitidart 是的,我支持多个显示器。我认为github.com/Lalaland/ScreenCap/blob/master/src/… 可能是正确的文件。不过好几年没碰过代码了。代码写得不好,但如果你想使用它,我会在那里扔一个 BSD 许可证。
  • 非常感谢@lalaland 这么快的回复!如果你有时间,我可以在你的问题页面上发布,这样我就可以了解它如何与多显示器一起使用
  • @Noitidart 老实说,我不知道代码是如何工作的。我什至不知道代码是否可以在现代 Linux 系统上运行。
  • 啊哈哈谢谢你的注意,我想不是因为我找不到像XFixesGetCursorImage这样的一些函数

标签: c++ c screenshot xlib cimg


【解决方案1】:

您对array 在内存中的布局方式有误,您可以通过在循环之前声明img 并将此printf 添加到您的内部循环中来发现:

printf("%ld %ld %u %u %u\n",x,y,pic.offset(x,y,0),pic.offset(x,y,1),pic.offset(x,y,2));

这会产生(在我的 1920x1200 屏幕上):

0 0 0 2304000 4608000
0 1 1920 2305920 4609920
0 2 3840 2307840 4611840

以此类推,表示红/绿/蓝子图像保持“在一起”,而不是单个像素的三个颜色分量彼此相邻。

内置的 CImg 访问器将使您的代码工作:

pic(x,y,0) = red;
pic(x,y,1) = green;
pic(x,y,2) = blue;

【讨论】:

    【解决方案2】:

    你可以使用 libpng

    int code = 0;
    FILE *fp;
    png_structp png_ptr;
    png_infop png_info_ptr;
    png_bytep png_row;
    
    // Open file
    fp = fopen ("test.png", "wb");
    if (fp == NULL){
        fprintf (stderr, "Could not open file for writing\n");
        code = 1;
    }
    
    // Initialize write structure
    png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL){
        fprintf (stderr, "Could not allocate write struct\n");
        code = 1;
    }
    
    // Initialize info structure
    png_info_ptr = png_create_info_struct (png_ptr);
    if (png_info_ptr == NULL){
        fprintf (stderr, "Could not allocate info struct\n");
        code = 1;
     }
    
    // Setup Exception handling
    if (setjmp (png_jmpbuf (png_ptr))){
        fprintf(stderr, "Error during png creation\n");
       code = 1;
    }
    
    png_init_io (png_ptr, fp);
    
    // Write header (8 bit colour depth)
    png_set_IHDR (png_ptr, png_info_ptr, width, height,
         8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    
    // Set title
    char *title = "Screenshot";
    if (title != NULL){
        png_text title_text;
        title_text.compression = PNG_TEXT_COMPRESSION_NONE;
        title_text.key = "Title";
        title_text.text = title;
        png_set_text (png_ptr, png_info_ptr, &title_text, 1);
    }
    
    png_write_info (png_ptr, png_info_ptr);
    
    // Allocate memory for one row (3 bytes per pixel - RGB)
    png_row = (png_bytep) malloc (3 * width * sizeof (png_byte));
    
    // Write image data
    int x, y;
    for (y = 0; y < height; y++){
        for (x = 0; x < width; x++){
            unsigned long pixel = XGetPixel (image, x, y);
            unsigned char blue = pixel & blue_mask;
            unsigned char green = (pixel & green_mask) >> 8; 
            unsigned char red = (pixel & red_mask) >> 16;
            png_byte *ptr = &(png_row[x*3]);
            ptr[0] = red;
            ptr[1] = green;
            ptr[2] = blue;
        }
        png_write_row (png_ptr, png_row);
    }
    
    // End write
    png_write_end (png_ptr, NULL);
    
    // Free
    fclose (fp);
    if (png_info_ptr != NULL) png_free_data (png_ptr, png_info_ptr, PNG_FREE_ALL, -1);
    if (png_ptr != NULL) png_destroy_write_struct (&png_ptr, (png_infopp)NULL);
    if (png_row != NULL) free (png_row);
    

    【讨论】:

      【解决方案3】:

      图像必须以 R1R2R3R4R5R6......G1G2G3G4G5G6.......B1B2B3B4B5B6 的形式存储在内存中。 cimg storage

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-12
        • 1970-01-01
        • 2013-08-11
        • 1970-01-01
        相关资源
        最近更新 更多