234 lines
5.9 KiB
Go
234 lines
5.9 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"golang.org/x/image/bmp"
|
|
"golang.org/x/image/tiff"
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
"image/jpeg"
|
|
"image/png"
|
|
"math"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
func BuffToImage(in []byte) image.Image {
|
|
buff := bytes.NewBuffer(in)
|
|
m, _, _ := image.Decode(buff)
|
|
return m
|
|
}
|
|
|
|
// Clip 图片裁剪
|
|
func Clip(buff *bytes.Buffer, wi, hi int, equalProportion bool) (out image.Image, imageType string, err error) {
|
|
//buff := bytes.NewBuffer(in)
|
|
m, imgType, err := image.Decode(buff)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
if equalProportion {
|
|
w := m.Bounds().Max.X
|
|
h := m.Bounds().Max.Y
|
|
if w > 0 && h > 0 && wi > 0 && hi > 0 {
|
|
wi, hi = fixSize(w, h, wi, hi)
|
|
}
|
|
}
|
|
switch imgType {
|
|
case "jpeg", "jpg":
|
|
rgbImg := m.(*image.YCbCr)
|
|
return rgbImg.SubImage(image.Rect(0, 0, wi, hi)), imgType, nil
|
|
case "bmp":
|
|
img := m.(*image.RGBA)
|
|
if equalProportion {
|
|
|
|
}
|
|
return img.SubImage(image.Rect(0, 0, wi, hi)).(*image.RGBA), imageType, nil
|
|
case "png":
|
|
switch m.(type) {
|
|
case *image.NRGBA:
|
|
img := m.(*image.NRGBA)
|
|
subImg := img.SubImage(image.Rect(0, 0, wi, hi)).(*image.NRGBA)
|
|
|
|
return subImg, imageType, nil
|
|
case *image.RGBA:
|
|
img := m.(*image.RGBA)
|
|
subImg := img.SubImage(image.Rect(0, 0, wi, hi)).(*image.RGBA)
|
|
return subImg, imageType, nil
|
|
}
|
|
case "gif":
|
|
img := m.(*image.Paletted)
|
|
subImg := img.SubImage(image.Rect(0, 0, wi, hi)).(*image.Paletted)
|
|
return subImg, imageType, nil
|
|
}
|
|
return nil, "", fmt.Errorf("未知的图片格式")
|
|
|
|
}
|
|
|
|
func fixSize(img1W, img2H, wi, hi int) (new1W, new2W int) {
|
|
var ( //为了方便计算,将图片的宽转为 float64
|
|
imgWidth, imgHeight = float64(img1W), float64(img2H)
|
|
ratio float64
|
|
)
|
|
if imgWidth >= imgHeight {
|
|
ratio = imgWidth / float64(wi)
|
|
return int(imgWidth * ratio), int(imgHeight * ratio)
|
|
}
|
|
ratio = imgHeight / float64(hi)
|
|
return int(imgWidth * ratio), int(imgHeight * ratio)
|
|
}
|
|
|
|
func Gray(buff *bytes.Buffer) (out image.Image, err error) {
|
|
m, _, _ := image.Decode(buff)
|
|
bounds := m.Bounds()
|
|
dx := bounds.Dx()
|
|
dy := bounds.Dy()
|
|
newRgba := image.NewRGBA(bounds)
|
|
for i := 0; i < dx; i++ {
|
|
for j := 0; j < dy; j++ {
|
|
colorRgb := m.At(i, j)
|
|
_, g, _, a := colorRgb.RGBA()
|
|
gUint8 := uint8(g >> 8)
|
|
aUint8 := uint8(a >> 8)
|
|
newRgba.SetRGBA(i, j, color.RGBA{R: gUint8, G: gUint8, B: gUint8, A: aUint8})
|
|
}
|
|
}
|
|
r := image.Rect(0, 0, dx, dy)
|
|
return newRgba.SubImage(r), nil
|
|
}
|
|
|
|
func Rotate90(buff *bytes.Buffer) image.Image {
|
|
m, _, _ := image.Decode(buff)
|
|
rotate90 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
|
|
// 矩阵旋转
|
|
for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
|
|
for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
|
|
// 设置像素点
|
|
rotate90.Set(m.Bounds().Max.Y-x, y, m.At(y, x))
|
|
}
|
|
}
|
|
return rotate90
|
|
}
|
|
|
|
// Rotate180 旋转180度
|
|
func Rotate180(buff *bytes.Buffer) image.Image {
|
|
m, _, _ := image.Decode(buff)
|
|
rotate180 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dx(), m.Bounds().Dy()))
|
|
// 矩阵旋转
|
|
for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
|
|
for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
|
|
// 设置像素点
|
|
rotate180.Set(m.Bounds().Max.X-x, m.Bounds().Max.Y-y, m.At(x, y))
|
|
}
|
|
}
|
|
return rotate180
|
|
}
|
|
|
|
// Rotate270 旋转270度
|
|
func Rotate270(buff *bytes.Buffer) image.Image {
|
|
m, _, _ := image.Decode(buff)
|
|
rotate270 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
|
|
// 矩阵旋转
|
|
for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
|
|
for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
|
|
// 设置像素点
|
|
rotate270.Set(x, m.Bounds().Max.X-y, m.At(y, x))
|
|
}
|
|
}
|
|
return rotate270
|
|
|
|
}
|
|
|
|
func ImageToBase64(img image.Image, imgType string) string {
|
|
buff := ImageToBuff(img, imgType)
|
|
return base64.StdEncoding.EncodeToString(buff.Bytes())
|
|
}
|
|
|
|
func ImageToBuff(img image.Image, imgType string) *bytes.Buffer {
|
|
buff := bytes.NewBuffer(nil)
|
|
switch imgType {
|
|
case "bmp":
|
|
imgType = "bmp"
|
|
_ = bmp.Encode(buff, img)
|
|
case "png":
|
|
imgType = "png"
|
|
_ = png.Encode(buff, img)
|
|
case "tiff", "tif":
|
|
imgType = "tiff"
|
|
_ = tiff.Encode(buff, img, nil)
|
|
default:
|
|
imgType = "jpeg"
|
|
_ = jpeg.Encode(buff, img, &jpeg.Options{
|
|
Quality: 100,
|
|
})
|
|
}
|
|
return buff
|
|
}
|
|
func SplitImage(buff *bytes.Buffer, w, h int) []image.Image {
|
|
img, _, _ := image.Decode(buff)
|
|
list := make([]image.Image, 0)
|
|
newWidth := int(math.Ceil(float64(img.Bounds().Dx()) / float64(w)))
|
|
newHeight := int(math.Ceil(float64(img.Bounds().Dy()) / float64(h)))
|
|
rect := image.Rect(0, 0, newWidth*w, newHeight*h)
|
|
newImage := image.NewRGBA(rect)
|
|
black := color.RGBA{A: 255}
|
|
draw.Draw(newImage, newImage.Bounds(), &image.Uniform{C: black}, image.Point{}, draw.Src)
|
|
draw.Draw(newImage, img.Bounds(), img, newImage.Bounds().Min, draw.Over)
|
|
sp := splitPattern(newImage, w, h)
|
|
spLen := len(sp)
|
|
var (
|
|
square image.Rectangle
|
|
)
|
|
for i := 0; i < spLen; i++ {
|
|
square = image.Rect(sp[i][0], sp[i][1], sp[i][2], sp[i][3])
|
|
imgPart := img.(interface {
|
|
SubImage(r image.Rectangle) image.Image
|
|
}).SubImage(square)
|
|
list = append(list, imgPart)
|
|
}
|
|
return list
|
|
}
|
|
func splitPattern(img image.Image, w, h int) [][]int {
|
|
ret := make([][]int, 0)
|
|
vOffSet := width(img) / w
|
|
hOffSet := height(img) / h
|
|
for r := 0; r < hOffSet; r++ {
|
|
for c := 0; c < vOffSet; c++ {
|
|
//行偏移,仅应用在x
|
|
x1 := w * c
|
|
y1 := h * r
|
|
|
|
x2 := w * (c + 1)
|
|
y2 := (r + 1) * h
|
|
el := []int{x1, y1, x2, y2}
|
|
ret = append(ret, el)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func width(i image.Image) int {
|
|
return i.Bounds().Max.X - i.Bounds().Min.X
|
|
}
|
|
|
|
func height(i image.Image) int {
|
|
return i.Bounds().Max.Y - i.Bounds().Min.Y
|
|
}
|
|
|
|
func IsImage(fileName string) bool {
|
|
fileType := path.Ext(fileName)
|
|
return InSlice([]string{".png", ".jpg", ".jpeg", ".bmp", ".tif", ".tiff"}, strings.ToLower(fileType))
|
|
}
|
|
|
|
// InSlice 判断字符串是否在 slice 中。
|
|
func InSlice(items []string, item string) bool {
|
|
for _, eachItem := range items {
|
|
if eachItem == item {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|