特别感谢原文博主 李不白。 原文上有个函数代码没有贴上来。联系上李不白之后补全给我了。所以特别感谢他的不吝赐教。

贴上原文代码

//Merge6Grid 6宫格
//rule NO1:至少3张图 最多6张图
// NO2:第一张大小 60*60 其他大小 28*28 间隔4px 合成图大小102*102
// NO3:排列顺序 从左至右 从上到小 再 从右到左
// ++|
// ++|
// --|
func Merge6Grid(src []io.Reader, dst io.Writer) error {
    defer func() {
        if r := recover(); r != nil {
            log.Println("Merge.recover:", r)
        }
    }()
    if len(src) < 3 || len(src) > 6 {
        panic("the pic num is between 3 and 6")
    }
    var err error
    imagePoints := getXy6Grid(len(src))

    //创建背景大图
    background := image.NewRGBA(image.Rect(0, 0, 100, 100))
    //设置背景为灰色
    for m := 0; m < 100; m++ {
        for n := 0; n < 100; n++ {
            //rgba := GetRGBA(0xC8CED4)
            background.SetRGBA(m, n, color.RGBA{127, 127, 127, 0})
        }
    }

    //背景图矩形圆角
    newBg, err := CreateRoundRectWithRGBA(background, 10)
    if err != nil {
        return err
    }

    //开始合成
    var width int
    for i, v := range imagePoints {
        x := v.x
        y := v.y

        if i == 0 {
            width = 60
        } else {
            width = 28
        }
        fOut := memory.NewWriter()

        //先缩略
        err = Scale(src[i], fOut, width, width, 100)
        if err != nil {
            return err
        }

        //矩形圆角
        rgba, err := CreateRoundRectWithoutColor(fOut, 6)
        if err != nil {
            return err
        }

        draw.Draw(newBg, newBg.Bounds(), rgba, rgba.Bounds().Min.Sub(image.Pt(x, y)), draw.Src)
    }

    return png.Encode(dst, newBg)
    //return jpeg.Encode(dst, newBg, nil)
}

//CreateRoundRect 创建圆角矩形 r为输入图像 r为圆角半径 color为圆角颜色
func CreateRoundRect(rd io.Reader, r int, c *color.RGBA) (*image.RGBA, error) {
    src, _, err := image.Decode(rd)
    if err != nil {
        return nil, err
    }

    b := src.Bounds()
    x := b.Dx()
    y := b.Dy()
    dst := image.NewRGBA(b)
    draw.Draw(dst, b, src, src.Bounds().Min, draw.Src)

    p1 := image.Point{r, r}
    p2 := image.Point{x - r, r}
    p3 := image.Point{r, y - r}
    p4 := image.Point{x - r, y - r}

    for m := 0; m < x; m++ {
        for n := 0; n < y; n++ {
            if (p1.X-m)*(p1.X-m)+(p1.Y-n)*(p1.Y-n) > r*r && m <= p1.X && n <= p1.Y {
                dst.Set(m, n, c)
            } else if (p2.X-m)*(p2.X-m)+(p2.Y-n)*(p2.Y-n) > r*r && m > p2.X && n <= p2.Y {
                dst.Set(m, n, c)
            } else if (p3.X-m)*(p3.X-m)+(p3.Y-n)*(p3.Y-n) > r*r && m <= p3.X && n > p3.Y {
                dst.Set(m, n, c)
            } else if (p4.X-m)*(p4.X-m)+(p4.Y-n)*(p4.Y-n) > r*r && m > p4.X && n > p4.Y {
                dst.Set(m, n, c)
            }
        }
    }
    return dst, nil
}

func CreateRoundRectWithoutColor(rd io.Reader, r int) (*image.RGBA, error) {
    src, _, err := image.Decode(rd)
    if err != nil {
        return nil, err
    }

    b := src.Bounds()
    x := b.Dx()
    y := b.Dy()
    dst := image.NewRGBA(b)

    p1 := image.Point{r, r}
    p2 := image.Point{x - r, r}
    p3 := image.Point{r, y - r}
    p4 := image.Point{x - r, y - r}

    for m := 0; m < x; m++ {
        for n := 0; n < y; n++ {
            if (p1.X-m)*(p1.X-m)+(p1.Y-n)*(p1.Y-n) > r*r && m <= p1.X && n <= p1.Y {
            } else if (p2.X-m)*(p2.X-m)+(p2.Y-n)*(p2.Y-n) > r*r && m > p2.X && n <= p2.Y {
            } else if (p3.X-m)*(p3.X-m)+(p3.Y-n)*(p3.Y-n) > r*r && m <= p3.X && n > p3.Y {
            } else if (p4.X-m)*(p4.X-m)+(p4.Y-n)*(p4.Y-n) > r*r && m > p4.X && n > p4.Y {
            } else {
                dst.Set(m, n, src.At(m, n))
            }
        }
    }
    return dst, nil
}

func CreateRoundRectWithRGBA(src *image.RGBA, r int) (*image.RGBA, error) {
    b := src.Bounds()
    x := b.Dx()
    y := b.Dy()
    dst := image.NewRGBA(b)

    p1 := image.Point{r, r}
    p2 := image.Point{x - r, r}
    p3 := image.Point{r, y - r}
    p4 := image.Point{x - r, y - r}

    for m := 0; m < x; m++ {
        for n := 0; n < y; n++ {
            if (p1.X-m)*(p1.X-m)+(p1.Y-n)*(p1.Y-n) > r*r && m <= p1.X && n <= p1.Y {
            } else if (p2.X-m)*(p2.X-m)+(p2.Y-n)*(p2.Y-n) > r*r && m > p2.X && n <= p2.Y {
            } else if (p3.X-m)*(p3.X-m)+(p3.Y-n)*(p3.Y-n) > r*r && m <= p3.X && n > p3.Y {
            } else if (p4.X-m)*(p4.X-m)+(p4.Y-n)*(p4.Y-n) > r*r && m > p4.X && n > p4.Y {
            } else {
                dst.Set(m, n, src.At(m, n))
            }
        }
    }
    return dst, nil
}

//0xC8CED4
func GetRGBA(c int) *color.RGBA {
    var cl color.RGBA
    cl.R = uint8((c >> 16) & 0xFF)
    cl.G = uint8((c >> 8) & 0xFF)
    cl.B = uint8(c & 0xFF)
    return &cl
}
func getXy6Grid(size int) []*Point {
    s := make([]*Point, size)
    _x, _y := 4, 4
    s[0] = &Point{_x, _y}
    s[1] = &Point{60 + 2*_x, _y}
    s[2] = &Point{60 + 2*_x, 28 + 2*_y}
    if size >= 4 {
        s[3] = &Point{60 + 2*_x, 28*2 + 3*_y}
    }
    if size >= 5 {
        s[4] = &Point{28 + 2*_x, 60 + 2*_y}
    }
    if size >= 6 {
        s[5] = &Point{_x, 60 + 2*_y}
    }

    return s
}
以下是仿微信群头像


//Merge 九宫格头像合成 固定新图大小132*132px 间隙3px
//至少一张图片
func Merge(src []io.Reader, dst io.Writer) error {
    defer func() {
        if r := recover(); r != nil {
            log.Println("Merge.recover:", r)
        }
    }()
    var err error
    imagePoints := getXy(len(src))
    width := getWidth(len(src))

    //创建背景图
    background := image.NewRGBA(image.Rect(0, 0, 132, 132))

    //设置背景为灰色
    for m := 0; m < 132; m++ {
        for n := 0; n < 132; n++ {
            background.SetRGBA(m, n, color.RGBA{127, 127, 127, 0})
        }
    }

    for i, v := range imagePoints {
        x := v.x
        y := v.y

        fOut := memory.NewWriter()

        err = Scale(src[i], fOut, width, width, 100)
        if err != nil {
            return err
        }

        //file2draw, err := jpeg.Decode(fOut)
        file2draw, _, err := image.Decode(fOut)
        if err != nil {
            return err
        }
        draw.Draw(background, background.Bounds(), file2draw, file2draw.Bounds().Min.Sub(image.Pt(x, y)), draw.Src)
    }

    return jpeg.Encode(dst, background, nil)
}

type Point struct {
    x, y int
}

func getXy(size int) []*Point {
    s := make([]*Point, size)
    var _x, _y int

    if size == 1 {
        _x, _y = 6, 6
        s[0] = &Point{_x, _y}
    }
    if size == 2 {
        _x, _y = 4, 4
        s[0] = &Point{_x, 132/2 - 60/2}
        s[1] = &Point{60 + 2*_x, 132/2 - 60/2}
    }
    if size == 3 {
        _x, _y = 4, 4
        s[0] = &Point{132/2 - 60/2, _y}
        s[1] = &Point{_x, 60 + 2*_y}
        s[2] = &Point{60 + 2*_y, 60 + 2*_y}
    }
    if size == 4 {
        _x, _y = 4, 4
        s[0] = &Point{_x, _y}
        s[1] = &Point{_x*2 + 60, _y}
        s[2] = &Point{_x, 60 + 2*_y}
        s[3] = &Point{60 + 2*_y, 60 + 2*_y}
    }
    if size == 5 {
        _x, _y = 3, 3
        s[0] = &Point{(132 - 40*2 - _x) / 2, (132 - 40*2 - _y) / 2}
        s[1] = &Point{((132-40*2-_x)/2 + 40 + _x), (132 - 40*2 - _y) / 2}
        s[2] = &Point{_x, ((132-40*2-_x)/2 + 40 + _y)}
        s[3] = &Point{(_x*2 + 40), ((132-40*2-_x)/2 + 40 + _y)}
        s[4] = &Point{(_x*3 + 40*2), ((132-40*2-_x)/2 + 40 + _y)}
    }
    if size == 6 {
        _x, _y = 3, 3
        s[0] = &Point{_x, ((132 - 40*2 - _x) / 2)}
        s[1] = &Point{(_x*2 + 40), ((132 - 40*2 - _x) / 2)}
        s[2] = &Point{(_x*3 + 40*2), ((132 - 40*2 - _x) / 2)}
        s[3] = &Point{_x, ((132-40*2-_x)/2 + 40 + _y)}
        s[4] = &Point{(_x*2 + 40), ((132-40*2-_x)/2 + 40 + _y)}
        s[5] = &Point{(_x*3 + 40*2), ((132-40*2-_x)/2 + 40 + _y)}
    }

    if size == 7 {
        _x, _y = 3, 3
        s[0] = &Point{(132 - 40) / 2, _y}
        s[1] = &Point{_x, (_y*2 + 40)}
        s[2] = &Point{(_x*2 + 40), (_y*2 + 40)}
        s[3] = &Point{(_x*3 + 40*2), (_y*2 + 40)}
        s[4] = &Point{_x, (_y*3 + 40*2)}
        s[5] = &Point{(_x*2 + 40), (_y*3 + 40*2)}
        s[6] = &Point{(_x*3 + 40*2), (_y*3 + 40*2)}
    }
    if size == 8 {
        _x, _y = 3, 3
        s[0] = &Point{(132 - 80 - _x) / 2, _y}
        s[1] = &Point{((132-80-_x)/2 + _x + 40), _y}
        s[2] = &Point{_x, (_y*2 + 40)}
        s[3] = &Point{(_x*2 + 40), (_y*2 + 40)}
        s[4] = &Point{(_x*3 + 40*2), (_y*2 + 40)}
        s[5] = &Point{_x, (_y*3 + 40*2)}
        s[6] = &Point{(_x*2 + 40), (_y*3 + 40*2)}
        s[7] = &Point{(_x*3 + 40*2), (_y*3 + 40*2)}
    }
    if size == 9 {
        _x, _y = 3, 3
        s[0] = &Point{_x, _y}
        s[1] = &Point{_x*2 + 40, _y}
        s[2] = &Point{_x*3 + 40*2, _y}
        s[3] = &Point{_x, (_y*2 + 40)}
        s[4] = &Point{(_x*2 + 40), (_y*2 + 40)}
        s[5] = &Point{(_x*3 + 40*2), (_y*2 + 40)}
        s[6] = &Point{_x, (_y*3 + 40*2)}
        s[7] = &Point{(_x*2 + 40), (_y*3 + 40*2)}
        s[8] = &Point{(_x*3 + 40*2), (_y*3 + 40*2)}
    }
    return s
}

func getWidth(size int) int {
    var width int
    if size == 1 {
        width = 120
    }
    if size > 1 && size <= 4 {
        width = 60
    }
    if size >= 5 {
        width = 40
    }
    return width
}

//补上缺失的代码
//* Clip 图片裁剪
//* 入参:图片输入、输出、缩略图宽、缩略图高、Rectangle{Pt(x0, y0), Pt(x1, y1)},精度
//* 规则:如果精度为0则精度保持不变
//*
//* 返回:error
// */
func Clip(in io.Reader, out io.Writer, wi, hi, x0, y0, x1, y1, quality int) (err error) {
	err = errors.New("unknow error")
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()
	var origin image.Image
	var fm string
	origin, fm, err = image.Decode(in)
	if err != nil {
		log.Println(err)
		return err
	}

	if wi == 0 || hi == 0 {
		wi = origin.Bounds().Max.X
		hi = origin.Bounds().Max.Y
	}
	var canvas image.Image
	if wi != origin.Bounds().Max.X {
		//先缩略
		canvas = resize.Thumbnail(uint(wi), uint(hi), origin, resize.Lanczos3)
	} else {
		canvas = origin
	}

	switch fm {
	case "jpeg":
		img := canvas.(*image.YCbCr)
		subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.YCbCr)
		return jpeg.Encode(out, subImg, &jpeg.Options{quality})
	case "png":
		switch canvas.(type) {
		case *image.NRGBA:
			img := canvas.(*image.NRGBA)
			subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.NRGBA)
			return png.Encode(out, subImg)
		case *image.RGBA:
			img := canvas.(*image.RGBA)
			subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.RGBA)
			return png.Encode(out, subImg)
		}
	case "gif":
		img := canvas.(*image.Paletted)
		subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.Paletted)
		return gif.Encode(out, subImg, &gif.Options{})
	//case "bmp":
	//	img := canvas.(*image.RGBA)
	//	subImg := img.SubImage(image.Rect(x0, y0, x1, y1)).(*image.RGBA)
	//	return bmp.Encode(out, subImg)
	default:
		return errors.New("ERROR FORMAT")
	}
	return nil
}

/*
* Scale 缩略图生成
* 入参:图片输入、输出,缩略图宽、高,精度
* 规则: 如果width 或 hight其中有一个为0,则大小不变 如果精度为0则精度保持不变
* 返回:缩略图真实宽、高、error
*/
func Scale(in io.Reader, out io.Writer, width, height, quality int) (int, int, error) {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()
	var (
		w, h int
	)
	origin, fm, err := image.Decode(in)
	if err != nil {
		log.Println(err)
		return 0, 0, err
	}
	if width == 0 || height == 0 {
		width = origin.Bounds().Max.X
		height = origin.Bounds().Max.Y
	}
	if quality == 0 {
		quality = 100
	}
	canvas := resize.Thumbnail(uint(width), uint(height), origin, resize.Lanczos3)

	//return jpeg.Encode(out, canvas, &jpeg.Options{quality})
	w = canvas.Bounds().Dx()
	h = canvas.Bounds().Dy()
	switch fm {
	case "jpeg":
		return w, h, jpeg.Encode(out, canvas, &jpeg.Options{quality})
	case "png":
		return w, h, png.Encode(out, canvas)
	case "gif":
		return w, h, gif.Encode(out, canvas, &gif.Options{})
	//case "bmp":  //被我注释掉的是x/image/bmp
	//	return w, h, bmp.Encode(out, canvas)
	default:
		return w, h, errors.New("ERROR FORMAT")
	}
	return w, h, nil
}

// Format2JPEG 将图片转换为JPEG格式
func Format2JPEG(in io.Reader, out io.Writer) error {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()
	origin, _, err := image.Decode(in)
	if err != nil {
		return err
	}
	return jpeg.Encode(out, origin, nil)
}

// Format2PNG 将图片转换为PNG格式
func Format2PNG(in io.Reader, out io.Writer) error {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()
	origin, _, err := image.Decode(in)
	if err != nil {
		return err
	}
	return png.Encode(out, origin)
}

// Format2GIF将图片转换为GIF格式
func Format2GIF(in io.Reader, out io.Writer) error {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()
	origin, _, err := image.Decode(in)
	if err != nil {
		return err
	}
	return gif.Encode(out, origin, nil)
}