private static unsafe void PaintMousePointer(System.IntPtr dpy, XImage *image) //, struct x11grab *s) { // int x_off = s->x_off; // int y_off = s->y_off; // int width = s->width; // int height = s->height; // Display *dpy = s->dpy; int x_off = 0; int y_off = 0; int width = image->width; int height = image->height; XFixesCursorImage *xcim; int x, y; int line, column; int to_line, to_column; int pixstride = image->bits_per_pixel >> 3; // Warning: in its insanity, xlib provides unsigned image data through a // char* pointer, so we have to make it uint8_t to make things not break. // Anyone who performs further investigation of the xlib API likely risks // permanent brain damage. byte *pix = (byte *)image->data; // Cursor c; // Window w; // XSetWindowAttributes attr; // Code doesn't currently support 16-bit or PAL8 if (image->bits_per_pixel != 24 && image->bits_per_pixel != 32) { return; } // c = XCreateFontCursor(dpy, XC_left_ptr); // w = DefaultRootWindow(dpy); // attr.cursor = c; // XChangeWindowAttributes(dpy, w, CWCursor, &attr); xcim = LibXfixes.XFixesGetCursorImage(dpy); x = xcim->x - xcim->xhot; y = xcim->y - xcim->yhot; to_line = FFMIN((y + xcim->height), (height + y_off)); to_column = FFMIN((x + xcim->width), (width + x_off)); for (line = FFMAX(y, y_off); line < to_line; line++) { for (column = FFMAX(x, x_off); column < to_column; column++) { int xcim_addr = (line - y) * xcim->width + column - x; int image_addr = ((line - y_off) * width + column - x_off) * pixstride; byte r = (byte)(xcim->pixels[xcim_addr].ToUInt64() >> 0); byte g = (byte)(xcim->pixels[xcim_addr].ToUInt64() >> 8); byte b = (byte)(xcim->pixels[xcim_addr].ToUInt64() >> 16); byte a = (byte)(xcim->pixels[xcim_addr].ToUInt64() >> 24); if (a == 255) { pix[image_addr + 0] = r; pix[image_addr + 1] = g; pix[image_addr + 2] = b; } else if (a != 0) { byte aaa = pix[image_addr + 2]; // pixel values from XFixesGetCursorImage come premultiplied by alpha pix[image_addr + 0] = (byte)(r + (pix[image_addr + 0] * (255 - a) + 255 / 2) / 255); pix[image_addr + 1] = (byte)(g + (pix[image_addr + 1] * (255 - a) + 255 / 2) / 255); pix[image_addr + 2] = (byte)(b + (pix[image_addr + 2] * (255 - a) + 255 / 2) / 255); } } } LibX11Functions.XFree(xcim); xcim = null; }
private static unsafe byte[] SlowScreenshotWithCursor( System.IntPtr display , System.UIntPtr d , int x, int y , uint width , uint height , System.UIntPtr plane_mask , int format, bool withCursor) { byte[] result = null; XImage *img = LibX11Functions.XGetImage2(display, d, x, y, width, height, plane_mask, format); if (withCursor) { PaintMousePointer(display, img); } // End if (withCursor) int bitsPerPixel = img->bits_per_pixel; System.UIntPtr ptrImg = (System.UIntPtr)img; System.UIntPtr pixels = (System.UIntPtr)(&(img->data)); System.UIntPtr ptr_byte_order = (System.UIntPtr)(&(img->byte_order)); ulong int64 = pixels.ToUInt64() - ptrImg.ToUInt64(); ulong int642 = ptr_byte_order.ToUInt64() - ptrImg.ToUInt64(); System.Console.WriteLine("p1: {0}, p2: {1}", ptrImg.ToUInt64(), pixels.ToUInt64()); System.Console.WriteLine("Delta: {0}", int64); // 16 System.Console.WriteLine("Delta 2: {0}", int642); // 16 // https://stackoverflow.com/questions/30476131/c-sharp-read-pointer-address-value System.IntPtr ptr = (System.IntPtr)(ptrImg.ToUInt64() + 16); long longValue = System.Runtime.InteropServices.Marshal.ReadInt64(ptr); System.Console.WriteLine("pt1: {0}, pt2: {1}", ((System.UIntPtr)(img->data)).ToUInt64(), longValue); // BMPImage * foo = CreateBitmapFromScan0(uint16_t bitsPerPixel, int32_t w, int32_t h, uint8_t* scan0); // string filename = "/tmp/lol1.bmp"; // WriteBitmapToFile(filename, bitsPerPixel, width, height, ); System.Console.WriteLine("Format: {0}, bpp: {1}", format, bitsPerPixel); int bytesPerPixel = (bitsPerPixel + 7) / 8; int stride = 4 * (((int)width * bytesPerPixel + 3) / 4); // long size = height * stride; // byte[] managedArray = new byte[size]; // System.Runtime.InteropServices.Marshal.Copy((System.IntPtr)(img->data), managedArray, 0, (int)size); using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap((int)width, (int)height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (System.IntPtr)img->data)) { // bmp.Save("/tmp/lol1.bmp"); using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); result = ms.ToArray(); } // End Using ms } // End Using bmp LibX11Functions.XDestroyImage2(img); return(result); }
private static unsafe byte[] UnsafeX11ScreenshotWithCursor(bool withCursor) { byte[] result = null; int AllPlanes = ~0; System.UIntPtr AllPlanes2 = new System.UIntPtr((uint)AllPlanes); System.IntPtr display = LibX11Functions.XOpenDisplay(System.IntPtr.Zero); int defaultScreen = LibX11Functions.XDefaultScreen(display); System.UIntPtr window = LibX11Functions.XRootWindow(display, defaultScreen); XWindowAttributes xa = new XWindowAttributes(); LibX11Functions.XGetWindowAttributes(display, window, ref xa); Screen *screen = xa.screen; // struct screen XShmSegmentInfo shminfo = new XShmSegmentInfo(); XImage *ximg = LibXExt.XShmCreateImage(display, LibXExt.DefaultVisualOfScreen(screen) , (uint)LibXExt.DefaultDepthOfScreen(screen), LinScreen.ZPixmap , System.IntPtr.Zero, ref shminfo, (uint)xa.width, (uint)xa.height); shminfo.shmid = LibC.shmget(LibC.IPC_PRIVATE, new System.IntPtr(ximg->bytes_per_line * ximg->height), LibC.IPC_CREAT | 0777); ximg->data = (sbyte *)LibC.shmat(shminfo.shmid, System.IntPtr.Zero, 0); shminfo.shmaddr = (System.IntPtr)ximg->data; shminfo.readOnly = 0; if (shminfo.shmid < 0) { System.Console.WriteLine("Fatal shminfo error!"); } int s1 = LibXExt.XShmAttach(display, ref shminfo); // System.Console.WriteLine("XShmAttach() {0}\n", s1 != 0 ? "success!" : "failure!"); int res = LibXExt.XShmGetImage(display, window, ximg, 0, 0, AllPlanes2); // const char *filename = "/tmp/test.bmp"; // WriteBitmapToFile(filename, (int) ximg->bits_per_pixel, (int)window_attributes.width, (int)window_attributes.height, (const void*) ximg->data); int bytesPerPixel = (ximg->bits_per_pixel + 7) / 8; int stride = 4 * ((ximg->width * bytesPerPixel + 3) / 4); // long size = ximg->height * stride; // byte[] managedArray = new byte[size]; // Marshal.Copy((IntPtr)(ximg->data), managedArray, 0, (int)size); // System.Console.WriteLine(managedArray); if (withCursor) { PaintMousePointer(display, ximg); } // End if (withCursor) using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ximg->width, ximg->height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (System.IntPtr)ximg->data)) { // bmp.Save("/tmp/shtest.bmp"); #if false // ZERO compression at all ! // using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) // { // bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); // result = ms.ToArray(); // } // End Using ms #else result = CompressImage(bmp, 25); #endif } // End Using bmp LibX11Functions.XDestroyImage2(ximg); LibXExt.XShmDetach(display, ref shminfo); LibC.shmdt(shminfo.shmaddr); LibX11Functions.XCloseDisplay(display); return(result); } // End Function UnsafeX11ScreenshotWithCursor