在Go中如何捕捉屏幕?

huangapple go评论74阅读模式
英文:

Capture the screen in Go?

问题

有没有一种跨平台的方法可以在Google的Go中捕获屏幕?或者说,无论如何都可以,但跨平台的方法更好。

英文:

Is there is a cross-platform way to capture the screen in Google's Go? Or any way for that matter, but cross platform would be preferred.

答案1

得分: 10

现在有:

https://github.com/vova616/screenshot

go get github.com/vova616/screenshot

示例:

package main

import "github.com/vova616/screenshot"

func main() {
    img, err := screenshot.CaptureScreen() // *image.RGBA
    myImg := image.Image(img) // 可以转换为image.Image,但不是必需的
}

如果您还需要macOS支持(直到合并拉取请求),请获取:

https://github.com/kesarion/screenshot

英文:

Now there is:

https://github.com/vova616/screenshot

go get github.com/vova616/screenshot

Example:

package main

import "github.com/vova616/screenshot"

func main() {
    img, err := screenshot.CaptureScreen() // *image.RGBA
    myImg := image.Image(img) // can cast to image.Image, but not necessary
}

If you need macOS support as well (until the pull request is merged), get:

https://github.com/kesarion/screenshot

答案2

得分: 6

很抱歉,没有库可以做到这一点。有一些与magickwand(C编程语言和ImageMagick图像处理库)相关的绑定,可以参考http://go-lang.cat-v.org/library-bindings,但这些绑定是不完整的,没有屏幕捕捉功能。

与此同时,正如GeertJohan建议的那样,您可以使用os.exec来运行外部程序并捕捉屏幕(请参见下面的示例代码)。例如,您可以使用imagemagick的import命令来捕捉屏幕(在可以运行imagemagick的平台上应该可以工作)。

package main

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
)

func main() {

	var buf bytes.Buffer

	path, err := exec.LookPath("import")
	if err != nil {
		log.Fatal("import not installed !")
	}
	fmt.Printf("import is available at %s\n", path)

	cmd := exec.Command("import", "-window", "root", "root.png")

	cmd.Stdout = &buf
	cmd.Stderr = &buf

	err = cmd.Run()
	if err != nil {
		panic(err)
	}
	fmt.Println(buf.String())
}
英文:

Unfortunately, there is no library to do this. There are a couple of bindings for magickwand (C programming language and the ImageMagick image processing libraries), see http://go-lang.cat-v.org/library-bindings but these are incomplete and do not have the screen capture feature.

Meanwhile as GeertJohan suggested, you can use os.exec to run an external program and capture the screen (see sample code below). For example, you can use import command from imagemagick to capture screen (should work on a platform that can run imagemagick)

package main

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
)

func main() {

	var buf bytes.Buffer

	path, err := exec.LookPath("import")
	if err != nil {
		log.Fatal("import not installed !")
	}
	fmt.Printf("import is available at %s\n", path)

	cmd := exec.Command("import", "-window", "root", "root.png")

	cmd.Stdout = &buf
	cmd.Stderr = &buf

	err = cmd.Run()
	if err != nil {
		panic(err)
	}
	fmt.Println(buf.String())
}

答案3

得分: 1

我不知道有任何跨平台的库,但是当存在X服务器时,你可以使用xgbutil库来实现这个功能。你可以在这里看到如何捕获屏幕截图的示例

如果你想在Mac/Windows系统上实现这个功能,我可能会先查看go.wde的源代码,它包含了Windows和Mac的后端。我怀疑你在那里直接找不到捕获屏幕截图的代码,但它可能会给你一些提示或者一个方向。

英文:

I don't know of any cross-platform library, but you can do this with the xgbutil library when an X server is present. You can see an example of how to capture a screenshot here.

If you wanted to get this working on Mac/Windows systems, I'd probably start by examining the source for go.wde, which includes backends for Windows and Mac. I doubt you'll directly find code to capture a screenshot in there, but it might give you some hints or a path to follow.

答案4

得分: 1

没有跨平台的方法可以在Google的Go语言中捕获屏幕,因为捕获屏幕依赖于底层操作系统的特定API。但是有一些适用于Go语言的库可以实现这个功能。

例如,https://github.com/vova616/screenshot

英文:

There is no cross-platform way to capture the screen in Google's Go, because capturing screen relies on a specific API of underlying operating systems. But there are libraries for Go that do this.

For example https://github.com/vova616/screenshot

答案5

得分: 1

这个库似乎符合您的需求:
https://godoc.org/github.com/kbinani/screenshot

> 它可以捕获屏幕截图并返回image.RGBA格式的图像。支持Mac、Windows、Linux、FreeBSD、OpenBSD、NetBSD和Solaris。

func Capture(x, y, width, height int) (*image.RGBA, error)
func CaptureDisplay(displayIndex int) (*image.RGBA, error)
func CaptureRect(rect image.Rectangle) (*image.RGBA, error)
func GetDisplayBounds(displayIndex int) image.Rectangle
func NumActiveDisplays() int
英文:

This library seems to meet your needs:
https://godoc.org/github.com/kbinani/screenshot

> captures screen-shot image as image.RGBA. Mac, Windows, Linux, FreeBSD, OpenBSD, NetBSD, and Solaris are supported.

func Capture(x, y, width, height int) (*image.RGBA, error)
func CaptureDisplay(displayIndex int) (*image.RGBA, error)
func CaptureRect(rect image.Rectangle) (*image.RGBA, error)
func GetDisplayBounds(displayIndex int) image.Rectangle
func NumActiveDisplays() int

答案6

得分: 0

我找不到一个可以做到这一点的库。稳定的跨平台屏幕捕获需要大量的工作。屏幕捕获需要与操作系统的显示管理器/服务器或帧缓冲区进行接口交互,这在许多操作系统和Linux发行版中是不同的。您需要为每个操作系统API编写接口(或包装提供功能的库),然后将所有不同的方法抽象到一个单一的包中,以便实现跨平台功能。

另一种方法是运行一个现有的屏幕捕获应用程序(命令行),以便为您执行屏幕捕获工作,包括保存到文件。然后在您的Go应用程序中读取该文件。要使Go应用程序运行第三方应用程序,请使用os/exec包,它在标准库中。对于Linux,您可以使用fbgrab将帧缓冲区保存为png文件。

英文:

I cannot find a library to do this. Stable cross-platform screen-capturing requires a lot of work. Screen capturing requires interfacing with the operating systems' display manager/server or frame-buffer, which is different for a lot of operating systems and Linux distributions. You would have to write interfaces for each OS API (or wrap the libraries that provide the functionality), and then abstract all the different methods in a single package so it works cross-platform.

Another way to do this would be to run a existing screen capture application (command-line) to do the screen-capture work for you, including saving to a file. Then read the file in your go application. To make a Go application run a third-party application, use the os/exec package, it is in the standard library. For Linux you might use fbgrab to save the frame-buffer to a png file.

答案7

得分: 0

这是一个两步骤的过程:

  1. 学习 https://github.com/ShareX/ShareX/tree/master/ShareX.ScreenCaptureLib,了解要调用哪些win32 API来捕获屏幕/窗口。
  2. 将这个逻辑翻译成Go语言。你可以使用现有的几个win32 API的Go绑定之一(例如https://github.com/AllenDang/w32)。如果它们缺少所需的功能,你可以添加更多的封装。
英文:

It is. It's a 2-step process:

Study https://github.com/ShareX/ShareX/tree/master/ShareX.ScreenCaptureLib to see which win32 API calls to make to capture the screen/window
Translate that logic to Go. You can use one of few existing win32 api Go bindings (e.g. https://github.com/AllenDang/w32). If they're missing needed functionality, you can add more wrappers.

答案8

得分: 0

package main

import (
    "runtime"
    "unsafe"

    "github.com/rodrigocfd/windigo/win"
    "github.com/rodrigocfd/windigo/win/co"
)

func main() {
    runtime.LockOSThread()

    cxScreen := win.GetSystemMetrics(co.SM_CXSCREEN)
    cyScreen := win.GetSystemMetrics(co.SM_CYSCREEN)

    hdcScreen := win.HWND(0).GetDC()
    defer win.HWND(0).ReleaseDC(hdcScreen)

    hBmp := hdcScreen.CreateCompatibleBitmap(cxScreen, cyScreen)
    defer hBmp.DeleteObject()

    hdcMem := hdcScreen.CreateCompatibleDC()
    defer hdcMem.DeleteDC()

    hBmpOld := hdcMem.SelectObjectBitmap(hBmp)
    defer hdcMem.SelectObjectBitmap(hBmpOld)

    hdcMem.BitBlt(
        win.POINT{X: 0, Y: 0},
        win.SIZE{Cx: cxScreen, Cy: cyScreen},
        hdcScreen,
        win.POINT{X: 0, Y: 0},
        co.ROP_SRCCOPY,
    )

    bi := win.BITMAPINFO{
        BmiHeader: win.BITMAPINFOHEADER{
            BiWidth:       cxScreen,
            BiHeight:      cyScreen,
            BiPlanes:      1,
            BiBitCount:    32,
            BiCompression: co.BI_RGB,
        },
    }
    bi.BmiHeader.SetBiSize()

    bmpObj := win.BITMAP{}
    hBmp.GetObject(&bmpObj)
    bmpSize := bmpObj.CalcBitmapSize(bi.BmiHeader.BiBitCount)

    rawMem := win.GlobalAlloc(co.GMEM_FIXED|co.GMEM_ZEROINIT, bmpSize)
    defer rawMem.GlobalFree()

    bmpSlice := rawMem.GlobalLock(int(bmpSize))
    defer rawMem.GlobalUnlock()

    hdcScreen.GetDIBits(hBmp, 0, int(cyScreen), bmpSlice, &bi, co.DIB_RGB_COLORS)

    bfh := win.BITMAPFILEHEADER{}
    bfh.SetBfType()
    bfh.SetBfOffBits(uint32(unsafe.Sizeof(bfh) + unsafe.Sizeof(bi.BmiHeader)))
    bfh.SetBfSize(bfh.BfOffBits() + uint32(bmpSize))

    fo, _ := win.FileOpen("C:\\users\\rodrigo\\desktop\\a.bmp", co.FILE_OPEN_RW_OPEN_OR_CREATE)
    defer fo.Close()

    fo.Write(bfh.Serialize())
    fo.Write(bi.BmiHeader.Serialize())
    fo.Write(bmpSlice)

    println("Done")
}
英文:

For a native Windows solution, there is an example in C from the official Windows docs:

Now, from this example, this is the code using Windigo library:

package main

import (
    "runtime"
    "unsafe"

    "github.com/rodrigocfd/windigo/win"
    "github.com/rodrigocfd/windigo/win/co"
)

func main() {
    runtime.LockOSThread()

    cxScreen := win.GetSystemMetrics(co.SM_CXSCREEN)
    cyScreen := win.GetSystemMetrics(co.SM_CYSCREEN)

    hdcScreen := win.HWND(0).GetDC()
    defer win.HWND(0).ReleaseDC(hdcScreen)

    hBmp := hdcScreen.CreateCompatibleBitmap(cxScreen, cyScreen)
    defer hBmp.DeleteObject()

    hdcMem := hdcScreen.CreateCompatibleDC()
    defer hdcMem.DeleteDC()

    hBmpOld := hdcMem.SelectObjectBitmap(hBmp)
    defer hdcMem.SelectObjectBitmap(hBmpOld)

    hdcMem.BitBlt(
        win.POINT{X: 0, Y: 0},
        win.SIZE{Cx: cxScreen, Cy: cyScreen},
        hdcScreen,
        win.POINT{X: 0, Y: 0},
        co.ROP_SRCCOPY,
    )

    bi := win.BITMAPINFO{
        BmiHeader: win.BITMAPINFOHEADER{
            BiWidth:       cxScreen,
            BiHeight:      cyScreen,
            BiPlanes:      1,
            BiBitCount:    32,
            BiCompression: co.BI_RGB,
        },
    }
    bi.BmiHeader.SetBiSize()

    bmpObj := win.BITMAP{}
    hBmp.GetObject(&bmpObj)
    bmpSize := bmpObj.CalcBitmapSize(bi.BmiHeader.BiBitCount)

    rawMem := win.GlobalAlloc(co.GMEM_FIXED|co.GMEM_ZEROINIT, bmpSize)
    defer rawMem.GlobalFree()

    bmpSlice := rawMem.GlobalLock(int(bmpSize))
    defer rawMem.GlobalUnlock()

    hdcScreen.GetDIBits(hBmp, 0, int(cyScreen), bmpSlice, &bi, co.DIB_RGB_COLORS)

    bfh := win.BITMAPFILEHEADER{}
    bfh.SetBfType()
    bfh.SetBfOffBits(uint32(unsafe.Sizeof(bfh) + unsafe.Sizeof(bi.BmiHeader)))
    bfh.SetBfSize(bfh.BfOffBits() + uint32(bmpSize))

    fo, _ := win.FileOpen("C:\\users\\rodrigo\\desktop\\a.bmp", co.FILE_OPEN_RW_OPEN_OR_CREATE)
    defer fo.Close()

    fo.Write(bfh.Serialize())
    fo.Write(bi.BmiHeader.Serialize())
    fo.Write(bmpSlice)

    println("Done")
}

huangapple
  • 本文由 发表于 2012年12月10日 03:22:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/13790852.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定