Search code examples
c#.netlinuxxlibxorg

XGetImage C# linux Black screenshot


Why is the image saved completely black? (And yes, my screen resolution is 3520x1190, two monitors) The object that produces the XGetImage is not empty, that is, the problem is most likely somewhere in the processing of the XImage and converting it to a bitmap

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using Color = System.Drawing.Color;

public class ScreenCapture
{
    private readonly IntPtr display;
    private readonly IntPtr rootWindow;

    public ScreenCapture()
    {
        display = Xorg.API.XOpenDisplay(IntPtr.Zero);
        rootWindow = Xorg.API.XRootWindow(display, Xorg.API.DefaultScreen(display));
    }

    public Bitmap CaptureScreen()
    {
        IntPtr image = Xorg.API.XGetImage(display, rootWindow, 0, 0, (uint)ScreenWidth, (uint)ScreenHeight, AllPlanes, 2);

        if (image != IntPtr.Zero)
        {
            XImage ximage = (XImage)Marshal.PtrToStructure(image, typeof(XImage));

            
            Bitmap bitmap = new Bitmap(ximage.width, ximage.height, PixelFormat.Format32bppArgb);
            for (int y = 0; y < ximage.height; y++)
            {
                for (int x = 0; x < ximage.width; x++)
                {
                    int offset = y * ximage.bytes_per_line + x * ximage.bits_per_pixel / 8;
                    byte b = Marshal.ReadByte(ximage.data, offset + 2);
                    byte g = Marshal.ReadByte(ximage.data, offset + 1);
                    byte r = Marshal.ReadByte(ximage.data, offset);
                    
                    Color color = Color.FromArgb(r, g, b);

                  //  Console.WriteLine(color.R);
                    bitmap.SetPixel(x, y, color);
                }
            }

            Xorg.API.XDestroyImage(image);
            Xorg.API.XCloseDisplay(display);

            return bitmap;
        }

        Xorg.API.XCloseDisplay(display);

        return null;
    }

    [StructLayout(LayoutKind.Sequential)]
    unsafe struct XImage
    {
        public int width;
        public int height;
        public int xoffset;
        public int format;
        public IntPtr data;
        public int byte_order;
        public int bitmap_unit;
        public int bitmap_bit_order;
        public int bitmap_pad;
        public int depth;
        public int bytes_per_line;
        public int bits_per_pixel;
        public ulong red_mask;
        public ulong green_mask;
        public ulong blue_mask;
        public IntPtr obdata;
        public IntPtr f;
    }


 
    public const int AllPlanes = 0;


    public int ScreenWidth { get; } = 3520;
    public int ScreenHeight { get; } = 1190;
}

I tried changing the pixel format but it didn't work.Thank you all in advance

Bitmap bitmap = new Bitmap(ximage.width, ximage.height, PixelFormat.Format32bppArgb);

AND:

0 = Marshal.ReadByte(ximage.data, 100)

Solution

  • https://github.com/VlaanH/libScreenshotBase64Xlib Well, I did it, suddenly someone needs it. And yes, I needed it because the standard method from System.Drawing does not allow it to be used from multiple threads.