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.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).Post("/", h.screenConfigurationChange)
|
||||||
r.With(auth.AdminsOnly).Get("/configurations", h.screenConfigurationsList)
|
r.With(auth.AdminsOnly).Get("/configurations", h.screenConfigurationsList)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package room
|
package room
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"image/jpeg"
|
||||||
|
"strconv"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
@ -72,3 +75,23 @@ func (h *RoomHandler) screenConfigurationsList(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
utils.HttpSuccess(w, list)
|
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
|
package desktop
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
"regexp"
|
"regexp"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
@ -113,3 +114,7 @@ func (manager *DesktopManagerCtx) GetKeyboardModifiers() types.KeyboardModifiers
|
|||||||
func (manager *DesktopManagerCtx) GetCursorImage() *types.CursorImage {
|
func (manager *DesktopManagerCtx) GetCursorImage() *types.CursorImage {
|
||||||
return xorg.GetCursorImage()
|
return xorg.GetCursorImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (manager *DesktopManagerCtx) GetScreenshotImage() *image.RGBA {
|
||||||
|
return xorg.GetScreenshotImage()
|
||||||
|
}
|
||||||
|
@ -136,3 +136,33 @@ XFixesCursorImage *XGetCursorImage(void) {
|
|||||||
Display *display = getXDisplay();
|
Display *display = getXDisplay();
|
||||||
return XFixesGetCursorImage(display);
|
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"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"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
|
//export goCreateScreenSize
|
||||||
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
||||||
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
|
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
#include <X11/extensions/Xrandr.h>
|
#include <X11/extensions/Xrandr.h>
|
||||||
#include <X11/extensions/XTest.h>
|
#include <X11/extensions/XTest.h>
|
||||||
#include <X11/extensions/Xfixes.h>
|
#include <X11/extensions/Xfixes.h>
|
||||||
@ -27,3 +28,5 @@ short XGetScreenRate();
|
|||||||
void XSetKeyboardModifier(int mod, int on);
|
void XSetKeyboardModifier(int mod, int on);
|
||||||
char XGetKeyboardModifiers();
|
char XGetKeyboardModifiers();
|
||||||
XFixesCursorImage *XGetCursorImage(void);
|
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
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
)
|
||||||
|
|
||||||
type CursorImage struct {
|
type CursorImage struct {
|
||||||
Width uint16
|
Width uint16
|
||||||
Height uint16
|
Height uint16
|
||||||
@ -53,6 +57,7 @@ type DesktopManager interface {
|
|||||||
SetKeyboardModifiers(mod KeyboardModifiers)
|
SetKeyboardModifiers(mod KeyboardModifiers)
|
||||||
GetKeyboardModifiers() KeyboardModifiers
|
GetKeyboardModifiers() KeyboardModifiers
|
||||||
GetCursorImage() *CursorImage
|
GetCursorImage() *CursorImage
|
||||||
|
GetScreenshotImage() *image.RGBA
|
||||||
|
|
||||||
// xevent
|
// xevent
|
||||||
OnCursorChanged(listener func(serial uint64))
|
OnCursorChanged(listener func(serial uint64))
|
||||||
|
Loading…
Reference in New Issue
Block a user