72 lines
1.8 KiB
Go
72 lines
1.8 KiB
Go
package webcam
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
"image/png"
|
|
)
|
|
|
|
func encodeImage(img image.Image, format string, quality int) ([]byte, string, error) {
|
|
var buf bytes.Buffer
|
|
if format == "jpeg" {
|
|
err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality})
|
|
return buf.Bytes(), "image/jpeg", err
|
|
}
|
|
err := png.Encode(&buf, img)
|
|
return buf.Bytes(), "image/png", err
|
|
}
|
|
|
|
func decodeBMP(data []byte) (*image.RGBA, error) {
|
|
if len(data) < 54 || data[0] != 'B' || data[1] != 'M' {
|
|
return nil, errors.New("invalid bitmap")
|
|
}
|
|
offset := binary.LittleEndian.Uint32(data[10:14])
|
|
width := int(int32(binary.LittleEndian.Uint32(data[18:22])))
|
|
heightSigned := int32(binary.LittleEndian.Uint32(data[22:26]))
|
|
bits := binary.LittleEndian.Uint16(data[28:30])
|
|
compression := binary.LittleEndian.Uint32(data[30:34])
|
|
if compression != 0 {
|
|
return nil, fmt.Errorf("unsupported bmp compression %d", compression)
|
|
}
|
|
if bits != 24 && bits != 32 {
|
|
return nil, fmt.Errorf("unsupported bmp bit depth %d", bits)
|
|
}
|
|
topDown := heightSigned < 0
|
|
height := int(heightSigned)
|
|
if height < 0 {
|
|
height = -height
|
|
}
|
|
if width <= 0 || height <= 0 || int(offset) >= len(data) {
|
|
return nil, errors.New("invalid bmp dimensions")
|
|
}
|
|
bpp := int(bits / 8)
|
|
rowSize := (width*bpp + 3) &^ 3
|
|
need := int(offset) + rowSize*height
|
|
if need > len(data) {
|
|
return nil, errors.New("truncated bmp")
|
|
}
|
|
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
|
for y := 0; y < height; y++ {
|
|
srcY := y
|
|
if !topDown {
|
|
srcY = height - 1 - y
|
|
}
|
|
row := data[int(offset)+srcY*rowSize:]
|
|
for x := 0; x < width; x++ {
|
|
i := x * bpp
|
|
b, g, r := row[i], row[i+1], row[i+2]
|
|
a := byte(255)
|
|
if bpp == 4 {
|
|
a = row[i+3]
|
|
}
|
|
off := (y*width + x) * 4
|
|
img.Pix[off], img.Pix[off+1], img.Pix[off+2], img.Pix[off+3] = r, g, b, a
|
|
}
|
|
}
|
|
return img, nil
|
|
}
|