Added optional buffer for image Read()

This commit is contained in:
Alex Eidt 2022-04-22 14:17:39 -07:00
parent 9f884aeec1
commit 84476c3206
4 changed files with 63 additions and 6 deletions

View file

@ -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")

View file

@ -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
}

BIN
test/bananas.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -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")
}