zoukankan      html  css  js  c++  java
  • golang 六宫格、九宫格头像生成

    图片示例就不传了,在原WordPress上。

    //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
    }
    
    
    
  • 相关阅读:
    写了一个整人程序,较简单,有兴趣者可以看看
    Silverlight之我见——数据批示(2)
    Silverlight之我见——DataGrid数据验证
    28个HTML5特征、窍门和技术
    Silverlight之我见——数据批示(1)
    发现:Click事件也能获取鼠标单击的坐标
    用纯CSS3实现Path华丽动画
    IAP (内置购买) 服务器端代码
    Android ui utils简单实用的Android界面工具
    vue 路由部署服务器子目录问题
  • 原文地址:https://www.cnblogs.com/cqvoip/p/8078843.html
Copyright © 2011-2022 走看看