我不是C编程和Linux OS开发方面的专家,但是我的任务是在Ubuntu和Fedora OS上制作屏幕截图。在互联网上搜索后,我发现了很多主题和有关如何使用C语言和libX11进行操作的问题。最后,我将所有可以找到的方法结合起来,用一种方法来捕获屏幕截图并将其保存到.png文件中。
我安装了两个虚拟机-一个是Ubuntu 18.04,另一个是Fedora30。当我在Ubuntu上运行我的代码时-它运行良好,当我在Fedora上运行它时-我有一个黑色内容的屏幕快照文件。
我的代码是:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <stdlib.h>
int get_shift (int mask) {
int shift = 0;
while (mask) {
if (mask & 1) break;
shift++;
mask >>=1;
}
return shift;
}
void takeScreenshot() {
Display *d;
int s;
XImage *image;
XShmSegmentInfo shminfo;
d = XOpenDisplay(NULL);
s = DefaultScreen(d);
unsigned int width = DisplayWidth(d,s);
unsigned int height = DisplayHeight(d,s);
image = XShmCreateImage(d,
DefaultVisual(d,s), // Use a correct visual. Omitted for brevity
24, // Determine correct depth from the visual. Omitted for brevity
ZPixmap, NULL, &shminfo, width, height);
shminfo.shmid = shmget(IPC_PRIVATE,
image->bytes_per_line * image->height,
IPC_CREAT|0777);
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = False;
XShmAttach(d, &shminfo);
XShmGetImage(d,
RootWindow(d,s),
image,
0,
0,
AllPlanes);
cairo_surface_t *surface;
int stride;
stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width);
unsigned char *data = malloc(stride * height);
int redShift = get_shift(image->red_mask);
int greenShift = get_shift(image->green_mask);
int blueShift = get_shift(image->blue_mask);
printf("r_shift: %d; g_shift: %d; b_shift: %d\n",redShift, greenShift, blueShift);
printf("byte order: %d\n", image->byte_order);
printf("bytes per line: %d\n", image->bytes_per_line);
printf("bites per pixel: %d\n", image->bits_per_pixel);
printf("r_mask: %lu; g_mask: %lu; b_mask: %lu\n", image->red_mask, image->green_mask, image->blue_mask);
printf("bitmap_bit_order: %d bitmap_pad: %d format: %d xoffset: %d\n", image->bitmap_bit_order, image->bitmap_pad, image->format, image->xoffset);
int x, y;
for (y = 0; y < height; ++y){
for (x = 0; x < width; ++x) {
unsigned long pixel = XGetPixel(image, x, y);
unsigned char red = (image->red_mask & pixel)>>redShift;
unsigned char green = (image->green_mask & pixel)>>greenShift;
unsigned char blue = (image->blue_mask & pixel)>>blueShift;
data[y * stride + x * 4 + 0] = blue;
data[y * stride + x * 4 + 1] = green;
data[y * stride + x * 4 + 2] = red;
}
}
surface = cairo_image_surface_create_for_data(
data,
CAIRO_FORMAT_RGB24,
width, height,
stride);
cairo_status_t surfaceStatus = cairo_surface_status(surface);
const char *r = cairo_status_to_string (surfaceStatus);
printf("%s\n", &r[0]);
int writepngRes = cairo_surface_write_to_png(
surface,
"test.png");
printf("surf status: %d; write result: %d\n", surfaceStatus, writepngRes);
cairo_surface_destroy(surface);
}
int main(int argc, char* argv[]) {
takeScreenshot();
return 0;
}
然后我使用以下命令构建此代码:
gcc code.c -o code.so -lXss -lX11 -lXext -fPIC -I/usr/include/cairo -lcairo
两台计算机上的设置完全相同,我检查的是这两个系统的位掩码,字节顺序和每像素字节数相等。我正在寻求有关如何查找错误原因的建议,也许是建议调试哪些东西。谢谢!
更新:
在两个平台上运行此代码时,我看到的输出完全相同:
r_shift: 16; g_shift: 8; b_shift: 0
byte order: 0
bytes per line: 5464
bites per pixel: 32
r_mask: 16711680; g_mask: 65280; b_mask: 255
bitmap_bit_order: 0 bitmap_pad: 32 format: 2 xoffset: 0
no error has occurred
surf status: 0; write result: 0