From 84476c3206c2488e615e6f63deea1f10fc829d7f Mon Sep 17 00:00:00 2001 From: Alex Eidt Date: Fri, 22 Apr 2022 14:17:39 -0700 Subject: [PATCH] Added optional buffer for image Read() --- README.md | 8 +++++++- imageio.go | 20 ++++++++++++++++---- test/bananas.jpg | Bin 0 -> 2367 bytes vidio_test.go | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 test/bananas.jpg diff --git a/README.md b/README.md index c59ae68..f81ab0a 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,13 @@ For the `SetFrameBuffer()` method, the `buffer` parameter must have a length of ## Images -Vidio provides some convenience functions for reading and writing to images using an array of bytes. Currently, only `png` and `jpeg` formats are supported. +Vidio provides some convenience functions for reading and writing to images using an array of bytes. Currently, only `png` and `jpeg` formats are supported. When reading images, an optional `buffer` can be passed in to avoid array reallocation. + +```go +Read(filename string, buffer ...[]byte) (int, int, []byte, error) +Write(filename string, width, height int, buffer []byte) error +``` +``` ```go w, h, img, err := vidio.Read("input.png") diff --git a/imageio.go b/imageio.go index cbe7d5c..167ce71 100644 --- a/imageio.go +++ b/imageio.go @@ -1,6 +1,8 @@ package vidio import ( + "errors" + "fmt" "image" "os" "strings" @@ -13,7 +15,7 @@ import ( ) // Reads an image from a file. Currently only supports png and jpeg. -func Read(filename string) (int, int, []byte, error) { +func Read(filename string, buffer ...[]byte) (int, int, []byte, error) { f, err := os.Open(filename) if err != nil { return 0, 0, nil, err @@ -28,7 +30,16 @@ func Read(filename string) (int, int, []byte, error) { bounds := image.Bounds().Max size := bounds.X * bounds.Y * 3 - data := make([]byte, size) + var data []byte + if len(buffer) > 0 { + if len(buffer[0]) < size { + errmsg := fmt.Sprintf("Buffer size (%d) is smaller than image size (%d)", len(buffer[0]), size) + return 0, 0, nil, errors.New(errmsg) + } + data = buffer[0] + } else { + data = make([]byte, size, size) + } index := 0 for h := 0; h < bounds.Y; h++ { @@ -47,17 +58,18 @@ func Read(filename string) (int, int, []byte, error) { } // Writes an image to a file. Currently only supports png and jpeg. -func Write(filename string, width, height int, data []byte) error { +func Write(filename string, width, height int, buffer []byte) error { f, err := os.Create(filename) if err != nil { return err } defer f.Close() + image := image.NewRGBA(image.Rect(0, 0, width, height)) index := 0 for h := 0; h < height; h++ { for w := 0; w < width; w++ { - r, g, b := data[index], data[index+1], data[index+2] + r, g, b := buffer[index], buffer[index+1], buffer[index+2] image.Set(w, h, color.RGBA{r, g, b, 255}) index += 3 } diff --git a/test/bananas.jpg b/test/bananas.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c8228af9bfc5eb712753625dad2fbc413a4b2360 GIT binary patch literal 2367 zcmbW!dsNbC8VB$nH$hF*!bH-%5hAIphJ~hu7trtusI{&;dC3w_c|=nYrv@}Hk+~Xq zBV|?O=1h%FRyO6PX+f5aB3jvGno3^ME?&y9wzb_ov*+yo)7j@a?_cltdC&7X@8`## z#{d%=bsrS~fj~gqdIO)I0{%e6E^n&0dj!>&8WR<9kfYAyq^5F~f4p9<{`_^d{s<^4 zCWgb}%;n|HecjCeq&fjp1W*8|As{;dYzl&yf> z=jj`4Hb+}vw&5J`js&8|&Rrx=FaH1vH85x&jTspgz5l=;V-gP~9X^uGO365$nU&4S z;pU$zC@d;IEjTAUUr||AT_b9gG)ZN0g|hjl%WYS#UTeSp^X=}QJ9ky;d%c=L?a=U} z$4^GaUrbC+>0VCH%)WiMxU{_T{=@2TUtAyn@-No!vj1|KuDifcCrCvvBdFhZ@ED-v1^09rhpB z2(SSHTK_zVDX2%?hb4<{!?JFx{Ge=Z1lDM9Zv{-H zXadJ~IJ%B%r9~HA)p)ctJWFO>Jl3B}VEk zxTK25E;TF=_ugM3933)Idw;RMWRwN}@+2VjW`w$-& znUu34BR@IFW?;&}W!-k7P7~jm&@)9zOT?9?PD&aHS34Bdo*@=56GIM|w2g`U!594F^3C>dq{@jlGF}^(iq2n4y#>3F(8RF!) zK+IU{E0(TG>h?56ceV%nty(A6o%0x}U2Zxm%tMg&kIydoP~qb3pp0a0|;!EqvS0lKD?Hn&y}hLo`0wK!EllroDG1Yopn zEP1Nsj?;sj8H#7JJk5DUF}Yf^e^eZbO~kf-Byi7pzaiXIWe`f2cVI5waGxBwfpKy% zBU>o}C(g_qy$Jc#SD6jCI&ygnsK}!kos!)bEOcVC{lE4@ak$wn@axJVaFxAA_!k-) z5lYQ}a7P@^hF#3T!E`w(-kMSfPm)Q{S5?`>2gaSRnlI(u(E{&Lkx`#yd zgL~S^FeItbz5=DQK!Kv{MtfG|Z2)oyU~%G2W_1mj2I8Ul|e%%D9HEP<7$~kKZ$is&w@oMT}s10l^E4g zTwgylHcKfh8EnDrkDSDuoE0Yfw4`j?5?eUAZ03xd=ybT^;xn_0{ zq@5HSGY*y^N@Z~cK)j_uSTDmEGC=x`5(jo?V_o5aciLrLRYGZ=Fw0a8L z?T-Y`>1Qlt6?)ay!?kFPA6R~ksP0-sj+YWbG@Dh#1<2)mfur#Qcdr4mahM4+M$Bch zg#vW(Bc0Hp{_mN1OU+SwKeLiw%(2mUu5zU83cKbUdF?Vv1NsFwJd%(5fm%R~ow`-w zn^J?Lek5e2q^e=gAtIoKqW!OdiJ>`2ugFt_8ta6^wSda=sF^(Q8 ztoCG6P@U&Q$&H1!`5k_Wi&{Db(J)F|!7@+zul21CP`0-s4dA}P6ci8NC;&b``3LUD BMvDLd literal 0 HcmV?d00001 diff --git a/vidio_test.go b/vidio_test.go index b01b3b1..e959ecb 100644 --- a/vidio_test.go +++ b/vidio_test.go @@ -6,7 +6,7 @@ import ( "testing" ) -func assertEquals(expected, actual interface{}) { +func assertEquals(actual, expected interface{}) { if expected != actual { panic(fmt.Sprintf("Expected %v, got %v", expected, actual)) } @@ -226,3 +226,42 @@ At least one output file must be specified`, fmt.Println("Webcam Parsing Test Passed") } + +func TestImageRead(t *testing.T) { + w, h, img, err := Read("test/bananas.jpg") + if err != nil { + panic(err) + } + + assertEquals(w, 200) + assertEquals(h, 133) + assertEquals(len(img), 200*133*3) + // [255 221 189 255 221 189 255 222 186 255] + assertEquals(img[0], uint8(255)) + assertEquals(img[1], uint8(221)) + assertEquals(img[2], uint8(189)) + assertEquals(img[3], uint8(255)) + assertEquals(img[4], uint8(221)) + assertEquals(img[5], uint8(189)) + assertEquals(img[6], uint8(255)) + assertEquals(img[7], uint8(222)) + assertEquals(img[8], uint8(186)) + assertEquals(img[9], uint8(255)) + + fmt.Println("Image Reading Test Passed") +} + +func TestImageWrite(t *testing.T) { + w, h, img, err := Read("test/bananas.jpg") + if err != nil { + panic(err) + } + err = Write("test/bananas-out.png", w, h, img) + if err != nil { + panic(err) + } + + os.Remove("test/bananas-out.png") + + fmt.Println("Image Writing Test Passed") +}