go-tg-screenshot-bot
134 строки · 2.8 Кб
1//go:build !s390x && !ppc64le && !darwin && !windows && (linux || freebsd || openbsd || netbsd)
2
3package screenshot4
5import (6"fmt"7"github.com/gen2brain/shm"8"github.com/jezek/xgb"9mshm "github.com/jezek/xgb/shm"10"github.com/jezek/xgb/xinerama"11"github.com/jezek/xgb/xproto"12"image"13"image/color"14)
15
16func captureXinerama(x, y, width, height int) (img *image.RGBA, e error) {17defer func() {18err := recover()19if err != nil {20img = nil21e = fmt.Errorf("%v", err)22}23}()24c, err := xgb.NewConn()25if err != nil {26return nil, err27}28defer c.Close()29
30err = xinerama.Init(c)31if err != nil {32return nil, err33}34
35reply, err := xinerama.QueryScreens(c).Reply()36if err != nil {37return nil, err38}39
40primary := reply.ScreenInfo[0]41x0 := int(primary.XOrg)42y0 := int(primary.YOrg)43
44useShm := true45err = mshm.Init(c)46if err != nil {47useShm = false48}49
50screen := xproto.Setup(c).DefaultScreen(c)51wholeScreenBounds := image.Rect(0, 0, int(screen.WidthInPixels), int(screen.HeightInPixels))52targetBounds := image.Rect(x+x0, y+y0, x+x0+width, y+y0+height)53intersect := wholeScreenBounds.Intersect(targetBounds)54
55rect := image.Rect(0, 0, width, height)56img, err = createImage(rect)57if err != nil {58return nil, err59}60
61// Paint with opaque black62index := 063for iy := 0; iy < height; iy++ {64j := index65for ix := 0; ix < width; ix++ {66img.Pix[j+3] = 25567j += 468}69index += img.Stride70}71
72if !intersect.Empty() {73var data []byte74
75if useShm {76shmSize := intersect.Dx() * intersect.Dy() * 477shmId, err := shm.Get(shm.IPC_PRIVATE, shmSize, shm.IPC_CREAT|0777)78if err != nil {79return nil, err80}81
82seg, err := mshm.NewSegId(c)83if err != nil {84return nil, err85}86
87data, err = shm.At(shmId, 0, 0)88if err != nil {89return nil, err90}91
92mshm.Attach(c, seg, uint32(shmId), false)93
94defer mshm.Detach(c, seg)95defer func() {96_ = shm.Rm(shmId)97}()98defer func() {99_ = shm.Dt(data)100}()101
102_, err = mshm.GetImage(c, xproto.Drawable(screen.Root),103int16(intersect.Min.X), int16(intersect.Min.Y),104uint16(intersect.Dx()), uint16(intersect.Dy()), 0xffffffff,105byte(xproto.ImageFormatZPixmap), seg, 0).Reply()106if err != nil {107return nil, err108}109} else {110xImg, err := xproto.GetImage(c, xproto.ImageFormatZPixmap, xproto.Drawable(screen.Root),111int16(intersect.Min.X), int16(intersect.Min.Y),112uint16(intersect.Dx()), uint16(intersect.Dy()), 0xffffffff).Reply()113if err != nil {114return nil, err115}116
117data = xImg.Data118}119
120// BitBlt by hand121offset := 0122for iy := intersect.Min.Y; iy < intersect.Max.Y; iy++ {123for ix := intersect.Min.X; ix < intersect.Max.X; ix++ {124r := data[offset+2]125g := data[offset+1]126b := data[offset]127img.SetRGBA(ix-(x+x0), iy-(y+y0), color.RGBA{r, g, b, 255})128offset += 4129}130}131}132
133return img, e134}
135