mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
generate screenshot using Xlib.
This commit is contained in:
parent
7ff6ada205
commit
afd3dd2f56
@ -61,7 +61,8 @@ func (h *RoomHandler) Route(r chi.Router) {
|
||||
})
|
||||
|
||||
r.Route("/screen", func(r chi.Router) {
|
||||
r.Get("/", h.screenConfiguration)
|
||||
r.With(auth.CanWatchOnly).Get("/", h.screenConfiguration)
|
||||
r.With(auth.CanWatchOnly).Get("/image", h.screenImageGet)
|
||||
|
||||
r.With(auth.AdminsOnly).Post("/", h.screenConfigurationChange)
|
||||
r.With(auth.AdminsOnly).Get("/configurations", h.screenConfigurationsList)
|
||||
|
@ -1,6 +1,9 @@
|
||||
package room
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image/jpeg"
|
||||
"strconv"
|
||||
"net/http"
|
||||
|
||||
"demodesk/neko/internal/types"
|
||||
@ -72,3 +75,23 @@ func (h *RoomHandler) screenConfigurationsList(w http.ResponseWriter, r *http.Re
|
||||
|
||||
utils.HttpSuccess(w, list)
|
||||
}
|
||||
|
||||
func (h *RoomHandler) screenImageGet(w http.ResponseWriter, r *http.Request) {
|
||||
var options *jpeg.Options
|
||||
if quality, err := strconv.Atoi(r.URL.Query().Get("quality")); err == nil {
|
||||
options = &jpeg.Options{ quality }
|
||||
} else {
|
||||
options = &jpeg.Options{ 90 }
|
||||
}
|
||||
|
||||
img := h.desktop.GetScreenshotImage()
|
||||
out := new(bytes.Buffer)
|
||||
err := jpeg.Encode(out, img, options)
|
||||
if err != nil {
|
||||
utils.HttpInternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "image/jpeg")
|
||||
w.Write(out.Bytes())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"image"
|
||||
"regexp"
|
||||
"os/exec"
|
||||
|
||||
@ -113,3 +114,7 @@ func (manager *DesktopManagerCtx) GetKeyboardModifiers() types.KeyboardModifiers
|
||||
func (manager *DesktopManagerCtx) GetCursorImage() *types.CursorImage {
|
||||
return xorg.GetCursorImage()
|
||||
}
|
||||
|
||||
func (manager *DesktopManagerCtx) GetScreenshotImage() *image.RGBA {
|
||||
return xorg.GetScreenshotImage()
|
||||
}
|
||||
|
@ -136,3 +136,33 @@ XFixesCursorImage *XGetCursorImage(void) {
|
||||
Display *display = getXDisplay();
|
||||
return XFixesGetCursorImage(display);
|
||||
}
|
||||
|
||||
char *XGetScreenshot(int *w, int *h) {
|
||||
Display *display = getXDisplay();
|
||||
Window root = DefaultRootWindow(display);
|
||||
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(display, root, &attr);
|
||||
int width = attr.width;
|
||||
int height = attr.height;
|
||||
|
||||
XImage *ximage = XGetImage(display, root, 0, 0, width, height, AllPlanes, ZPixmap);
|
||||
|
||||
*w = width;
|
||||
*h = height;
|
||||
char *pixels = (char *)malloc(width * height * 3);
|
||||
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
int pos = ((row * width) + col) * 3;
|
||||
unsigned long pixel = XGetPixel(ximage, col, row);
|
||||
|
||||
pixels[pos] = (pixel & ximage->red_mask) >> 16;
|
||||
pixels[pos+1] = (pixel & ximage->green_mask) >> 8;
|
||||
pixels[pos+2] = pixel & ximage->blue_mask;
|
||||
}
|
||||
}
|
||||
|
||||
XDestroyImage(ximage);
|
||||
return pixels;
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"demodesk/neko/internal/types"
|
||||
)
|
||||
|
||||
@ -244,6 +247,34 @@ func GetCursorImage() *types.CursorImage {
|
||||
}
|
||||
}
|
||||
|
||||
func GetScreenshotImage() *image.RGBA {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
var w, h C.int
|
||||
pixelsUnsafe := C.XGetScreenshot(&w, &h)
|
||||
pixels := C.GoBytes(unsafe.Pointer(pixelsUnsafe), w * h * 3)
|
||||
defer C.free(unsafe.Pointer(pixelsUnsafe))
|
||||
|
||||
width := int(w)
|
||||
height := int(h)
|
||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
for row := 0; row < height; row++ {
|
||||
for col := 0; col < width; col++ {
|
||||
pos := ((row * width) + col) * 3
|
||||
|
||||
img.SetRGBA(col, row, color.RGBA{
|
||||
R: uint8(pixels[pos]),
|
||||
G: uint8(pixels[pos+1]),
|
||||
B: uint8(pixels[pos+2]),
|
||||
A: 0xFF,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return img
|
||||
}
|
||||
|
||||
//export goCreateScreenSize
|
||||
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
||||
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/XTest.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
@ -27,3 +28,5 @@ short XGetScreenRate();
|
||||
void XSetKeyboardModifier(int mod, int on);
|
||||
char XGetKeyboardModifiers();
|
||||
XFixesCursorImage *XGetCursorImage(void);
|
||||
|
||||
char *XGetScreenshot(int *w, int *h);
|
||||
|
@ -66,3 +66,14 @@ func CanHostOnly(next http.Handler) http.Handler {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func CanWatchOnly(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
session := GetSession(r)
|
||||
if !session.CanWatch() {
|
||||
utils.HttpForbidden(w, "Only for members, that can watch.")
|
||||
} else {
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"image"
|
||||
)
|
||||
|
||||
type CursorImage struct {
|
||||
Width uint16
|
||||
Height uint16
|
||||
@ -53,6 +57,7 @@ type DesktopManager interface {
|
||||
SetKeyboardModifiers(mod KeyboardModifiers)
|
||||
GetKeyboardModifiers() KeyboardModifiers
|
||||
GetCursorImage() *CursorImage
|
||||
GetScreenshotImage() *image.RGBA
|
||||
|
||||
// xevent
|
||||
OnCursorChanged(listener func(serial uint64))
|
||||
|
Loading…
Reference in New Issue
Block a user