diff --git a/README.md b/README.md index bf3c7a8..f3de8fe 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Usage of cam2ip: Disable WebGL drawing of images (html handler) [CAM2IP_NOWEBGL] -rotate int Rotate image, valid values are 90, 180, 270 [CAM2IP_ROTATE] + -timestamp + Draws timestamp on images [CAM2IP_TIMESTAMP] -video-file string Use video file instead of camera [CAM2IP_VIDEO_FILE] -width float diff --git a/camera/camera.go b/camera/camera.go index 05f9144..c97b1ad 100644 --- a/camera/camera.go +++ b/camera/camera.go @@ -2,8 +2,9 @@ package camera // Options. type Options struct { - Index int - Rotate int - Width float64 - Height float64 + Index int + Rotate int + Width float64 + Height float64 + Timestamp bool } diff --git a/camera/camera_cv2.go b/camera/camera_cv2.go index b3813b7..e20767f 100644 --- a/camera/camera_cv2.go +++ b/camera/camera_cv2.go @@ -6,6 +6,11 @@ package camera import ( "fmt" "image" + "image/color" + "image/draw" + "time" + + "github.com/pbnjay/pixfont" "github.com/disintegration/imaging" "github.com/gen2brain/go-opencv/opencv" @@ -36,29 +41,37 @@ func New(opts Options) (camera *Camera, err error) { // Read reads next frame from camera and returns image. func (c *Camera) Read() (img image.Image, err error) { - if c.camera.GrabFrame() { - c.frame = c.camera.RetrieveFrame(1) - - if c.frame == nil { - err = fmt.Errorf("camera: can not retrieve frame") - return - } - - img = c.frame.ToImage() - if c.opts.Rotate == 0 { - return - } - - switch c.opts.Rotate { - case 90: - img = imaging.Rotate90(img) - case 180: - img = imaging.Rotate180(img) - case 270: - img = imaging.Rotate270(img) - } - } else { + if !c.camera.GrabFrame() { err = fmt.Errorf("camera: can not grab frame") + return + } + + c.frame = c.camera.RetrieveFrame(1) + if c.frame == nil { + err = fmt.Errorf("camera: can not retrieve frame") + return + } + + img = c.frame.ToImage() + + switch c.opts.Rotate { + case 90: + img = imaging.Rotate90(img) + case 180: + img = imaging.Rotate180(img) + case 270: + img = imaging.Rotate270(img) + } + + if c.opts.Timestamp { + dimg, ok := img.(draw.Image) + if !ok { + err = fmt.Errorf("camera: %T is not a drawable image type", img) + return + } + + pixfont.DrawString(dimg, 10, 10, time.Now().Format("2006-01-02 15:04:05"), color.White) + img = dimg } return diff --git a/camera/camera_cv4.go b/camera/camera_cv4.go index 9ad4e52..8e913b9 100644 --- a/camera/camera_cv4.go +++ b/camera/camera_cv4.go @@ -6,6 +6,11 @@ package camera import ( "fmt" "image" + "image/color" + "image/draw" + "time" + + "github.com/pbnjay/pixfont" "github.com/disintegration/imaging" "gocv.io/x/gocv" @@ -56,10 +61,6 @@ func (c *Camera) Read() (img image.Image, err error) { return } - if c.opts.Rotate == 0 { - return - } - switch c.opts.Rotate { case 90: img = imaging.Rotate90(img) @@ -69,6 +70,17 @@ func (c *Camera) Read() (img image.Image, err error) { img = imaging.Rotate270(img) } + if c.opts.Timestamp { + dimg, ok := img.(draw.Image) + if !ok { + err = fmt.Errorf("camera: %T is not a drawable image type", img) + return + } + + pixfont.DrawString(dimg, 10, 10, time.Now().Format("2006-01-02 15:04:05"), color.White) + img = dimg + } + return } diff --git a/camera/camera_linux.go b/camera/camera_linux.go index f052baf..4f6745f 100644 --- a/camera/camera_linux.go +++ b/camera/camera_linux.go @@ -6,10 +6,14 @@ package camera import ( "fmt" "image" + "image/color" + "image/draw" + "time" "github.com/disintegration/imaging" "github.com/korandiz/v4l" "github.com/korandiz/v4l/fmt/mjpeg" + "github.com/pbnjay/pixfont" im "github.com/gen2brain/cam2ip/image" ) @@ -82,10 +86,6 @@ func (c *Camera) Read() (img image.Image, err error) { return } - if c.opts.Rotate == 0 { - return - } - switch c.opts.Rotate { case 90: img = imaging.Rotate90(img) @@ -95,6 +95,17 @@ func (c *Camera) Read() (img image.Image, err error) { img = imaging.Rotate270(img) } + if c.opts.Timestamp { + dimg, ok := img.(draw.Image) + if !ok { + err = fmt.Errorf("camera: %T is not a drawable image type", img) + return + } + + pixfont.DrawString(dimg, 10, 10, time.Now().Format("2006-01-02 15:04:05"), color.White) + img = dimg + } + return } diff --git a/camera/camera_windows.go b/camera/camera_windows.go index 62ab057..4ee0a54 100644 --- a/camera/camera_windows.go +++ b/camera/camera_windows.go @@ -7,9 +7,14 @@ import ( "bytes" "fmt" "image" + "image/color" + "image/draw" "syscall" + "time" "unsafe" + "github.com/pbnjay/pixfont" + "github.com/disintegration/imaging" ) @@ -129,9 +134,6 @@ func (c *Camera) Read() (img image.Image, err error) { } img = c.frame - if c.opts.Rotate == 0 { - return - } switch c.opts.Rotate { case 90: @@ -142,6 +144,17 @@ func (c *Camera) Read() (img image.Image, err error) { img = imaging.Rotate270(img) } + if c.opts.Timestamp { + dimg, ok := img.(draw.Image) + if !ok { + err = fmt.Errorf("camera: %T is not a drawable image type", img) + return + } + + pixfont.DrawString(dimg, 10, 10, time.Now().Format("2006-01-02 15:04:05"), color.White) + img = dimg + } + return } diff --git a/cmd/cam2ip/main.go b/cmd/cam2ip/main.go index 2e32395..bb530f7 100644 --- a/cmd/cam2ip/main.go +++ b/cmd/cam2ip/main.go @@ -27,6 +27,7 @@ func main() { flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height") flag.IntVar(&srv.Rotate, "rotate", 0, "Rotate image, valid values are 90, 180, 270") flag.BoolVar(&srv.NoWebGL, "nowebgl", false, "Disable WebGL drawing of images (html handler)") + flag.BoolVar(&srv.Timestamp, "timestamp", false, "Draws timestamp on images") flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address") flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled") @@ -52,7 +53,7 @@ func main() { } } - cam, err := camera.New(camera.Options{srv.Index, srv.Rotate, srv.FrameWidth, srv.FrameHeight}) + cam, err := camera.New(camera.Options{srv.Index, srv.Rotate, srv.FrameWidth, srv.FrameHeight, srv.Timestamp}) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err.Error()) os.Exit(1) diff --git a/cmd/cam2ip/main_cv.go b/cmd/cam2ip/main_cv.go index 4e51c9b..af5db65 100644 --- a/cmd/cam2ip/main_cv.go +++ b/cmd/cam2ip/main_cv.go @@ -28,6 +28,7 @@ func main() { flag.Float64Var(&srv.FrameHeight, "height", 480, "Frame height") flag.IntVar(&srv.Rotate, "rotate", 0, "Rotate image, valid values are 90, 180, 270") flag.BoolVar(&srv.NoWebGL, "nowebgl", false, "Disable WebGL drawing of images (html handler)") + flag.BoolVar(&srv.Timestamp, "timestamp", false, "Draws timestamp on images") flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address") flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled") flag.StringVar(&srv.FileName, "video-file", "", "Use video file instead of camera") @@ -63,7 +64,7 @@ func main() { srv.Reader = vid } else { - cam, err := camera.New(camera.Options{srv.Index, srv.Rotate, srv.FrameWidth, srv.FrameHeight}) + cam, err := camera.New(camera.Options{srv.Index, srv.Rotate, srv.FrameWidth, srv.FrameHeight, srv.Timestamp}) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err.Error()) os.Exit(1) diff --git a/go.mod b/go.mod index 63d2c8b..99b4172 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/gen2brain/go-opencv v0.0.0-20191005190506-bf186fc94f7a github.com/jamiealquiza/envy v1.1.0 github.com/korandiz/v4l v0.0.0-20180520170035-995f703bfc89 + github.com/pbnjay/pixfont v0.0.0-20190130005054-401bb7c6aee2 github.com/spf13/cobra v0.0.5 // indirect gocv.io/x/gocv v0.20.0 golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad // indirect diff --git a/go.sum b/go.sum index 38cd4ce..01dc8e2 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pbnjay/pixfont v0.0.0-20190130005054-401bb7c6aee2 h1:Px7Nfku7x0pH6r2G+RlLI5AnXefcH2BAenMxDpZZfIs= +github.com/pbnjay/pixfont v0.0.0-20190130005054-401bb7c6aee2/go.mod h1:wG8B9TIIBxEYqwgBb9NEs/Gz5/ywV351SGZXRiVJJUA= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/server/server.go b/server/server.go index 7681ebb..f9a6567 100644 --- a/server/server.go +++ b/server/server.go @@ -28,7 +28,8 @@ type Server struct { Rotate int - NoWebGL bool + NoWebGL bool + Timestamp bool FileName string