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 }