package webcam import ( "image" "image/color" "time" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/widget" "gocv.io/x/gocv" ) var _ fyne.WidgetRenderer = (*webcamRenderer)(nil) type Webcam struct { widget.BaseWidget WebcamID int64 UpdateFPS int64 fpsTimer *time.Ticker } func NewWebcam() *Webcam { w := &Webcam{} w.ExtendBaseWidget(w) w.WebcamID = 0 w.UpdateFPS = 25 return w } func (w *Webcam) Resize(s fyne.Size) { w.BaseWidget.Resize(s) } func (w *Webcam) CreateRenderer() fyne.WidgetRenderer { fpsTimer := time.NewTicker(time.Duration(1000/25) * time.Millisecond) go func(w *Webcam) { for { _ = <-fpsTimer.C w.Refresh() } }(w) return newWebcamRenderer(w) } type webcamRenderer struct { webcam *Webcam background *canvas.Rectangle currentframe *canvas.Raster goCVVideoCapture *gocv.VideoCapture } func (r *webcamRenderer) actualrenderframe(w, h int) image.Image { webcam, _ := gocv.VideoCaptureDevice(int(r.webcam.WebcamID)) img := gocv.NewMat() webcam.Read(&img) frameImage, _ := img.ToImage() //no point doing anything other than returning anyway! return frameImage } func newWebcamRenderer(w *Webcam) *webcamRenderer { renderer := &webcamRenderer{ webcam: w, background: canvas.NewRectangle(color.RGBA{255, 0, 255, 255}), } renderer.currentframe = canvas.NewRaster(renderer.actualrenderframe) return renderer } func (r *webcamRenderer) Objects() []fyne.CanvasObject { // The order is critical, rect is drawn first then currentframe return []fyne.CanvasObject{r.background, r.currentframe} } func (r *webcamRenderer) Layout(s fyne.Size) { r.background.Resize(s) r.currentframe.Resize(s) } func (r *webcamRenderer) MinSize() fyne.Size { return fyne.NewSize(200, 200) } func (r *webcamRenderer) Refresh() { r.currentframe.Refresh() } func (r *webcamRenderer) Destroy() { r.webcam.fpsTimer.Stop() } // Called when the renderer is destroyed