diff --git a/examples/multisyswebcam/main.go b/examples/multisyswebcam/main.go new file mode 100644 index 0000000..890322e --- /dev/null +++ b/examples/multisyswebcam/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "strconv" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "git.martyn.berlin/martyn/fyne-widgets/pkg/multisyswebcam" + "git.martyn.berlin/martyn/fyne-widgets/pkg/layouts" +) + +var multisysWebcamID int +var multisysWebcamLabel *widget.Label +var multisysWebcamWidget *multisyswebcam.MultisysWebcam + +func switchMultisysWebcam(id int) { + multisysWebcamLabel.Text = "Webcam: " + strconv.Itoa(id) + multisysWebcamLabel.Refresh() + multisysWebcamWidget.MultisysWebcamID = int64(id) + multisysWebcamWidget.Refresh() +} + +func incWebCamID() { + multisysWebcamID = multisysWebcamID + 1 + switchMultisysWebcam(multisysWebcamID) +} + +func decWebCamID() { + multisysWebcamID = multisysWebcamID - 1 + switchMultisysWebcam(multisysWebcamID) +} + +func main() { + a := app.New() + w := a.NewWindow("MultisysWebcam") + + multisysWebcamWidget = multisyswebcam.NewMultisysWebcam() + layout := layouts.NewFloatingControlsLayout() + layout.FloatingControlsLocation = layouts.FloatingControlsCenter + multisysWebcamWidget.System = multisyswebcam.WebcamSystemGoCV + multisysWebcamID = 0 + multisysWebcamWidget.UpdateFPS = 50 + + multisysWebcamLabel = widget.NewLabel("Webcam: 0") + buttons := container.NewHBox(multisysWebcamLabel, widget.NewButton("-", decWebCamID), widget.NewButton("+", incWebCamID)) + + w.SetContent(container.New(&layout, multisysWebcamWidget, buttons)) + w.Resize(fyne.NewSize(640, 480)) + w.ShowAndRun() +} diff --git a/pkg/multisyswebcam/multisyswebcam.go b/pkg/multisyswebcam/multisyswebcam.go new file mode 100644 index 0000000..0838f5c --- /dev/null +++ b/pkg/multisyswebcam/multisyswebcam.go @@ -0,0 +1,136 @@ +package multisyswebcam + +import ( + "image" + "image/color" + "time" + "math/rand" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/widget" + "gocv.io/x/gocv" +) + +var _ fyne.WidgetRenderer = (*multisysMultisysWebcamRenderer)(nil) + +type WebcamSystem int64 + +const ( + WebcamSystemDisabled WebcamSystem = iota + WebcamSystemGoCV + WebcamSystemWinAviCapDll +) + + +type MultisysWebcam struct { + widget.BaseWidget + + System WebcamSystem + + MultisysWebcamID int64 + UpdateFPS int64 + fpsTimer *time.Ticker + +} + +func NewMultisysWebcam() *MultisysWebcam { + w := &MultisysWebcam{} + w.ExtendBaseWidget(w) + w.MultisysWebcamID = 0 + w.UpdateFPS = 25 + w.System = WebcamSystemDisabled + + return w +} + +func (w *MultisysWebcam) Resize(s fyne.Size) { + w.BaseWidget.Resize(s) +} + +func (w *MultisysWebcam) CreateRenderer() fyne.WidgetRenderer { + fpsTimer := time.NewTicker(time.Duration(1000/25) * time.Millisecond) + go func(w *MultisysWebcam) { + for { + _ = <-fpsTimer.C + if w != nil { + w.Refresh() + } + } + }(w) + return newMultisysWebcamRenderer(w) +} + +func staticNoiseImage(w, h int) *image.RGBA { + i := image.NewRGBA(image.Rect(0, 0, w, h)) + for x := 0; x < w; x++ { + for y := 0; y < h; y++ { + lum := uint8(rand.Float32() * 255) + i.Set(x, y, color.RGBA{lum, lum, lum, 255}) + } + } + return i +} + +func (w *MultisysWebcam) actualrenderframe(width, height int) image.Image { + switch w.System { + case WebcamSystemDisabled: + return staticNoiseImage(width,height) + case WebcamSystemGoCV: + gocvWebcam, _ := gocv.VideoCaptureDevice(int(w.MultisysWebcamID)) + img := gocv.NewMat() + gocvWebcam.Read(&img) + frameImage, err := img.ToImage() + if err != nil { + frameImage = image.NewRGBA(image.Rect(0, 0, width, height)) + } + return frameImage + } + return image.NewRGBA(image.Rect(0, 0, width, height)) +} + +func newMultisysWebcamRenderer(w *MultisysWebcam) *multisysMultisysWebcamRenderer { + renderer := &multisysMultisysWebcamRenderer{ + multisysMultisysWebcam: w, + background: canvas.NewRectangle(color.RGBA{255, 0, 255, 255}), + } + renderer.currentframe = canvas.NewRaster(w.actualrenderframe) + return renderer +} + +type multisysMultisysWebcamRenderer struct { + multisysMultisysWebcam *MultisysWebcam + background *canvas.Rectangle + currentframe *canvas.Raster + goCVVideoCapture *gocv.VideoCapture +} + +func (r *multisysMultisysWebcamRenderer) Objects() []fyne.CanvasObject { + // The order is critical, rect is drawn first then currentframe + return []fyne.CanvasObject{r.background, r.currentframe} +} + +func (r *multisysMultisysWebcamRenderer) Layout(s fyne.Size) { + r.background.Resize(s) + r.currentframe.Resize(s) +} + +func (r *multisysMultisysWebcamRenderer) MinSize() fyne.Size { + return fyne.NewSize(200, 200) +} + +func (r *multisysMultisysWebcamRenderer) Refresh() { + if r != nil { + if r.currentframe != nil { + r.currentframe.Refresh() + } + } +} + +func (r *multisysMultisysWebcamRenderer) Destroy() { + if r.multisysMultisysWebcam != nil { + if r.multisysMultisysWebcam.fpsTimer != nil { + r.multisysMultisysWebcam.fpsTimer.Stop() + } + } +} // Called when the renderer is destroyed