Files
imgo/loader.go
2022-06-22 14:07:54 +08:00

216 lines
4.3 KiB
Go

package imgo
import (
"bytes"
"image"
"image/color"
"io/ioutil"
"net/http"
"os"
)
type ImageManager struct {
}
// Load an image from source.
// source can be a file path, a URL, a base64 encoded string, an *os.File, an image.Image or a byte slice.
func Load(source interface{}) *Image {
switch source.(type) {
case string:
return loadFromString(source.(string))
case *os.File:
return LoadFromFile(source.(*os.File))
case image.Image:
return LoadFromImage(source.(image.Image))
case []byte:
return loadFromString(string(source.([]byte)))
case *Image:
return LoadFromImgo(source.(*Image))
default:
i := &Image{}
i.addError(ErrSourceNotSupport)
return i
}
}
// loadFromString loads an image when the source is a string.
func loadFromString(source string) (i *Image) {
i = &Image{}
if len(source) == 0 {
i.addError(ErrSourceStringIsEmpty)
return
}
if len(source) > 4 && source[:4] == "http" {
return LoadFromUrl(source)
} else if len(source) > 10 && source[:10] == "data:image" {
return LoadFromBase64(source)
} else {
return LoadFromPath(source)
}
}
// LoadFromUrl loads an image when the source is an url.
func LoadFromUrl(url string) (i *Image) {
i = &Image{}
// Get the image response from the url.
resp, err := http.Get(url)
if err != nil {
i.addError(err)
return
}
defer resp.Body.Close()
// Read the image data from the response.
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
// Get the extension, mimetype and corresponding decoder function of the image.
ext, mime, decoder, err := GetImageType(bodyBytes[:8])
if err != nil {
i.addError(err)
return
}
// Decode the image.
file := bytes.NewReader(bodyBytes)
img, err := decoder(file)
if err != nil {
i.addError(ErrSourceNotSupport)
return
}
return &Image{
image: Image2RGBA(img),
width: img.Bounds().Dx(),
height: img.Bounds().Dy(),
extension: ext,
mimetype: mime,
}
}
// LoadFromPath loads an image from a path.
func LoadFromPath(path string) (i *Image) {
i = &Image{}
file, err := os.Open(path)
if err != nil {
i.addError(err)
return
}
defer file.Close()
return LoadFromFile(file)
}
// LoadFromFile loads an image from a file.
func LoadFromFile(file *os.File) (i *Image) {
i = &Image{}
// Read the first 8 bytes of the image.
buf := make([]byte, 8)
_, err := file.Read(buf)
if err != nil {
i.addError(err)
return
}
// After reading the first 8 bytes, we seek back to the beginning of the file.
_, err = file.Seek(0, 0)
if err != nil {
i.addError(err)
return
}
// Get the extension, mimetype and corresponding decoder function of the image.
ext, mime, decoder, err := GetImageType(buf)
if err != nil {
i.addError(err)
return
}
// Decode the image.
img, err := decoder(file)
if err != nil {
i.addError(err)
return
}
// Set the image properties.
stat, _ := file.Stat()
return &Image{
image: Image2RGBA(img),
width: img.Bounds().Dx(),
height: img.Bounds().Dy(),
extension: ext,
mimetype: mime,
filesize: stat.Size(),
}
}
// LoadFromImage loads an image from an instance of image.Image.
func LoadFromImage(img image.Image) (i *Image) {
i = &Image{}
if img == nil {
i.addError(ErrSourceImageIsNil)
return
}
var formatName string
switch img.(type) {
case *image.NRGBA: // png
formatName = "png"
case *image.RGBA: // bmp, tiff
formatName = "png"
case *image.YCbCr: // jpeg, webp
formatName = "jpg"
default:
i.addError(ErrSourceImageNotSupport)
return
}
return &Image{
image: Image2RGBA(img),
width: img.Bounds().Dx(),
height: img.Bounds().Dy(),
extension: formatName,
mimetype: "image/" + formatName,
}
}
// LoadFromImgo loads an image from an instance of Image.
func LoadFromImgo(i *Image) *Image {
return i
}
// Canvas create a new empty image.
func Canvas(width, height int, fillColor ...color.Color) *Image {
var c color.Color
if len(fillColor) == 0 {
c = color.Transparent
} else {
c = fillColor[0]
}
img := image.NewRGBA(image.Rect(0, 0, width, height))
for x := 0; x < img.Bounds().Dx(); x++ {
for y := 0; y < img.Bounds().Dy(); y++ {
img.Set(x, y, c)
}
}
return &Image{
image: img,
width: img.Bounds().Dx(),
height: img.Bounds().Dy(),
extension: "png",
mimetype: "image/png",
}
}