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
}
golang 六宫格、九宫格头像生成的更多相关文章
- 宫格布局实例(注意jquery的版本号要统一)
<!DOCTYPE html><html><head><meta charset="utf-8" /><style> * ...
- 宫格布局实例(注意jquery的版本号要统一)2
<!DOCTYPE html><html><head><meta charset="utf-8" /><style> * ...
- 前端js实现九宫格模式抽奖(多宫格抽奖)
介绍: 前端九宫格是一种常见的抽奖方式,js实现如下,掌握其原理,不论多少宫格,都可以轻松应对.(代码可复制直接运行看效果). 该案例以四宫格入门,可扩展多宫格,奖品模块的布局可自由设置. <! ...
- css-九宫格自适应的实现
高度自适应使用padding 或 padding-bottom + 百分比来实现: 宽度自适应使用width + 百分比来实现. 下面是实现九宫格自适应的代码: <!DOCTYPE html&g ...
- HTML5 Canvas中9宫格的坑
近期小鸟情人游戏上了手机qq空间,一个3岁的游戏来了她的第二春.为了能有更好的表现,我们对其进行了一次改版. 改版当中一项就是对原来的弹出框样式进行改进.将大块木板材质改成纯色(边框为圆角金属材质)样 ...
- 微信小程序多宫格抽奖
最近闲来无事,做了一个多宫格抽奖的例子,有什么需要改进或者错误的地方,请留言,谢谢 首先看效果 思路是先让其转动2圈多,然后再进行抽奖,格子运动用的是setTimeout,让其运行的时间间隔不一样,然 ...
- Android自定义多宫格解锁控件
在此之前,一直在想九宫格的实现方法,经过一个上午的初步研究终于完成了一个简单的N*N的宫格解锁组件,代码略显粗糙,仅仅做到简单的实现,界面等后期在做优化,纯粹是学习的目的,在算法上有点缺陷,如果有错误 ...
- vue 如何拿到后台传回的富文本中的img,进行9宫格排列展示以及相关处理
描述: res.data.list 返回的数组, 数组中的每个对象有一个 content,就是传回来的富文本的内容,要拿到这里面的所有的img,进行9宫格排列处理: 1.let img = this. ...
- Python爬虫学习笔记之微信宫格验证码的识别(存在问题)
本节我们将介绍新浪微博宫格验证码的识别.微博宫格验证码是一种新型交互式验证码,每个宫格之间会有一条 指示连线,指示了应该的滑动轨迹.我们要按照滑动轨迹依次从起始宫格滑动到终止宫格,才可以完成验证,如 ...
随机推荐
- python dpkt 解析 pcap 文件
dpkt Tutorial #2: Parsing a PCAP File 原文链接:https://jon.oberheide.org/blog/2008/10/15/dpkt-tutorial-2 ...
- Python3各种进制之间的转换方法
一.2/8/10/16进制互转 1.1 2/8/10/16进制赋值 # 二进制赋值以0b打头 a = 0b1000 # 八进制赋值以0o打头,第一个是数字0第二个是字母o b = 0o1100 # 十 ...
- Windows和Linux创建软链接和硬链接
1.Wondows创建软链接和硬链接 mklink [/d] [/h] link target /d--创建目录软链接:默认为文件软链接:创建目录链接时必须使用该选项不然创出的软链接无效 /h--创建 ...
- python(5)之集合
集合是一个无序的,不重复的数据组合,它的主要作用如下: 1.去重,把一个列表变为集合就自动去重了 2.关系测试,测试两组数据之间的交集.并集.差集等 常用操作如下: #集合的操作 list_1={1, ...
- js中如何返回一个存放对象的数组?
我这边需要返回后台数据的形式是这样的 {[ { ", }, { ", }, { ", }, { ", }, { ", } ]} 页面是通过循环去获取每 ...
- 转Generative Model 与 Discriminative Model
没有完全看懂,以后再看,特别是hmm,CRF那里,以及生成模型产生的数据是序列还是一个值,hmm应该是序列,和图像的关系是什么. [摘要] - 生成模型(Generative Model) :无 ...
- select * from dim.dim_area_no@to_dw
应该是建的有database linksdim是用户名,dim_area_no是表名,to_dw 是建的database links的名,dim_area_no表属于dim用户创建database l ...
- 常用6种type的form表单的input标签分析及示例
<input> 标签用于搜集用户信息. 根据不同的 type 属性值,输入字段拥有很多种形式.输入字段可以是文本字段.复选框.掩码后的文本控件.单选按钮.按钮等等. 在这里博主介绍6中ty ...
- day03 is 与== 常量
is身份运算:比较的是id是否相等 ==判断值是否相等 ... 值相等id不一定相等 >>>x=1111111111111111111111111111111111111111111 ...
- 解决Tomcat v6.0 Server at localhost was unable to start within 45 seconds
eclipse 中tomcat启动超时报错如下: Starting Tomcat v7.0 Server at localhost' has encountered a problem Server ...