106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
|
package resize
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"github.com/anthonynsimon/bild/transform"
|
||
|
"image"
|
||
|
"image/jpeg"
|
||
|
"image/png"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
var mimeTypes = map[string]string{
|
||
|
"image/jpg": "image/jpg",
|
||
|
"image/jpeg": "image/jpeg",
|
||
|
"image/png": "image/png",
|
||
|
}
|
||
|
|
||
|
func IsResizable(mimeType string) bool {
|
||
|
_, present := mimeTypes[mimeType]
|
||
|
return present
|
||
|
}
|
||
|
|
||
|
type ResizeType int
|
||
|
|
||
|
const (
|
||
|
// Cover - resize preserving image aspect
|
||
|
// - resizes to the smallest image where both width and height are larger or equal to given size
|
||
|
Cover ResizeType = iota
|
||
|
// Contain - resize preserving image aspect
|
||
|
// - resizes to the largest image where both width and height are smaller or equal to given size
|
||
|
Contain ResizeType = iota
|
||
|
// ExactHeight - resize preserving image aspect
|
||
|
// - resizes to the image with given height
|
||
|
ExactHeight ResizeType = iota
|
||
|
// ExactWidth - resize preserving image aspect
|
||
|
// - resizes to the image with given width
|
||
|
ExactWidth ResizeType = iota
|
||
|
// Exact - resize without preserving image aspect
|
||
|
// - resizes to exact size defined in request
|
||
|
Exact ResizeType = iota
|
||
|
)
|
||
|
|
||
|
type Resize struct {
|
||
|
Height int
|
||
|
Width int
|
||
|
Type ResizeType
|
||
|
}
|
||
|
|
||
|
func ResizeImage(imageBytes []byte, resize Resize) ([]byte, error) {
|
||
|
img, format, err := image.Decode(bytes.NewReader(imageBytes))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var buffer bytes.Buffer
|
||
|
writer := io.Writer(&buffer)
|
||
|
|
||
|
resizeWidth, resizeHeight := calculateResizedDimensions(img.Bounds(), resize)
|
||
|
|
||
|
img = transform.Resize(img, resizeWidth, resizeHeight, transform.Gaussian)
|
||
|
switch format {
|
||
|
case "png":
|
||
|
err = png.Encode(writer, img)
|
||
|
case "jpeg":
|
||
|
err = jpeg.Encode(writer, img, nil)
|
||
|
default:
|
||
|
err = jpeg.Encode(writer, img, nil)
|
||
|
}
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return buffer.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
func calculateResizedDimensions(bounds image.Rectangle, resize Resize) (width int, height int) {
|
||
|
width = bounds.Dx()
|
||
|
height = bounds.Dy()
|
||
|
|
||
|
switch resize.Type {
|
||
|
case Cover:
|
||
|
rWidth := resize.Height * width / height
|
||
|
if rWidth >= resize.Width {
|
||
|
return rWidth, resize.Height
|
||
|
}
|
||
|
rHeight := resize.Width * height / width
|
||
|
if rHeight >= resize.Height {
|
||
|
return resize.Width, rHeight
|
||
|
}
|
||
|
case Contain:
|
||
|
rWidth := resize.Height * width / height
|
||
|
if rWidth <= resize.Width {
|
||
|
return rWidth, resize.Height
|
||
|
}
|
||
|
rHeight := resize.Width * height / width
|
||
|
if rHeight <= resize.Height {
|
||
|
return resize.Width, rHeight
|
||
|
}
|
||
|
case ExactHeight:
|
||
|
rWidth := resize.Height * width / height
|
||
|
return rWidth, resize.Height
|
||
|
case ExactWidth:
|
||
|
rHeight := resize.Width * height / width
|
||
|
return resize.Width, rHeight
|
||
|
}
|
||
|
return
|
||
|
}
|