C++ 如何使用xlib正确拍摄屏幕截图?

C++ 如何使用xlib正确拍摄屏幕截图?,c++,c,screenshot,xlib,cimg,C++,C,Screenshot,Xlib,Cimg,我正在尝试捕捉屏幕的图像,以便在屏幕广播中使用。因此,我需要一个快速的解决方案,不能依赖于诸如import或xwd之类的shell程序 这是我到目前为止编写的代码,但它失败了,给了我一个垃圾图像,它似乎只是显示了几个图像的片段,这些图像带有奇怪的颜色 你知道我做错了什么吗 #include <X11/Xlib.h> #include <X11/X.h> #include <cstdio> #include <CImg.h> using name

我正在尝试捕捉屏幕的图像,以便在屏幕广播中使用。因此,我需要一个快速的解决方案,不能依赖于诸如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;
}
#包括
#包括
#包括
#包括
使用名称空间cimg_库;
int main()
{
Display*Display=XOpenDisplay(空);
窗口根=默认根窗口(显示);
xgwa;
XGetWindowAttributes(显示、根目录和gwa);
int width=gwa.width;
int高度=gwa高度;
XImage*image=XGetImage(显示,根,0,0,宽度,高度,所有平面,ZPixmap);
无符号字符*数组=新的无符号字符[宽度*高度*3];
无符号长红色遮罩=图像->红色遮罩;
无符号长绿色遮罩=图像->绿色遮罩;
无符号长蓝色遮罩=图像->蓝色遮罩;
对于(int x=0;x>8;
无符号字符红色=(像素和红色遮罩)>>16;
阵列[(x+宽度*y)*3]=红色;
数组[(x+宽度*y)*3+1]=绿色;
阵列[(x+宽度*y)*3+2]=蓝色;
}
CImg pic(阵列、宽度、高度,1,3);
图.save_png(“blah.png”);
printf(“%ld%ld%ld\n”,红色遮罩>>16,绿色遮罩>>8,蓝色遮罩);
返回0;
}

您错误地理解了
数组在内存中的布局方式,您可以通过在循环前声明
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屏幕上):

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

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

pic(x,y,0) = red;
pic(x,y,1) = green;
pic(x,y,2) = blue;
您可以使用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);
int-code=0;
文件*fp;
png_structp png_ptr;
png_infop png_info_ptr;
png_bytep png_行;
//打开文件
fp=fopen(“test.png”、“wb”);
如果(fp==NULL){
fprintf(stderr,“无法打开文件进行写入\n”);
代码=1;
}
//初始化写结构
png_ptr=png_create_write_struct(png_LIBPNG_VER_STRING,NULL,NULL);
如果(png_ptr==NULL){
fprintf(stderr,“无法分配写结构\n”);
代码=1;
}
//初始化信息结构
png_info_ptr=png_create_info_struct(png_ptr);
如果(png\U info\U ptr==NULL){
fprintf(stderr,“无法分配信息结构\n”);
代码=1;
}
//设置异常处理
if(setjmp(png_jmpbuf(png_ptr))){
fprintf(stderr,“创建png时出错\n”);
代码=1;
}
png_init_io(png_ptr,fp);
//写入标题(8位颜色深度)
png_集_IHDR(png_ptr、png_信息_ptr、宽度、高度、,
8,PNG_颜色_类型_RGB,PNG_交错_无,
PNG_压缩_类型_基础、PNG_过滤器_类型_基础);
//定名
char*title=“屏幕截图”;
如果(标题!=NULL){
png_文本标题_文本;
title\u text.compression=PNG\u text\u compression\u NONE;
title\u text.key=“title”;
title_text.text=标题;
png_集_文本(png_ptr、png_info_ptr和title_text,1);
}
png_write_info(png_ptr,png_info_ptr);
//为一行分配内存(每像素3字节-RGB)
png_行=(png_字节)malloc(3*宽度*大小(png_字节));
//写入图像数据
int x,y;
对于(y=0;y<高度;y++){
对于(x=0;x>8;
无符号字符红色=(像素和红色遮罩)>>16;
png_字节*ptr=&(png_行[x*3]);
ptr[0]=红色;
ptr[1]=绿色;
ptr[2]=蓝色;
}
png_写入_行(png_ptr,png_行);
}
//结束写入
png_write_end(png_ptr,NULL);
//免费的
fclose(fp);
如果(png_info_ptr!=NULL)png_free_数据(png_ptr,png_info_ptr,png_free_ALL,-1);
如果(png_ptr!=NULL)png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
如果(png\U行!=NULL)自由(png\U行);

图像必须以R1R2R3R4R5R6……G1G2G3G4G5G6……B1B2B3B4BB6的形式存储在内存中。

Hi@lalaland你能分享你的最终代码吗?这个支持多监视器吗?@Noitidart是的,我支持多监视器。我想可能是正确的文件。但是已经好几年没有接触过代码了。代码写得很糟糕,但是如果你想使用它,我会在上面添加一个BSD许可证。非常感谢@lalaland这么快的回复!如果你有时间的话,我可以在你的问题页面上发布,这样我就可以了解它是如何与多个monitors@Noitidart老实说,我已经不知道代码是如何工作的了。我甚至不知道这些代码是否在现代Linux系统上运行。啊哈哈,谢谢你的提醒,我想不会,因为我找不到像
XFixesGetCursorImage
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);