|
| 1 | +package rendercard |
| 2 | + |
| 3 | +import ( |
| 4 | + "image" |
| 5 | + "image/color" |
| 6 | + "strconv" |
| 7 | + "sync" |
| 8 | + |
| 9 | + "github.com/FloatTech/gg" |
| 10 | +) |
| 11 | + |
| 12 | +// RankInfo ... |
| 13 | +type RankInfo struct { |
| 14 | + Avatar image.Image |
| 15 | + TopLeftText string |
| 16 | + BottomLeftText string |
| 17 | + RightText string |
| 18 | +} |
| 19 | + |
| 20 | +// DrawRankingCard ... |
| 21 | +func DrawRankingCard(fontdata []byte, title string, rankinfo []*RankInfo) (img image.Image, err error) { |
| 22 | + line := len(rankinfo) |
| 23 | + const w = 672 |
| 24 | + h := 64 + (80+14)*line + 20 - 14 |
| 25 | + canvas := gg.NewContext(w, h) |
| 26 | + canvas.SetRGBA255(255, 255, 255, 255) |
| 27 | + canvas.Clear() |
| 28 | + |
| 29 | + ac := gg.NewLinearGradient(16, float64(h)/2, w-16, float64(h)/2) |
| 30 | + ac.AddColorStop(0, color.NRGBA{255, 255, 255, 95}) |
| 31 | + ac.AddColorStop(0.167, color.NRGBA{255, 255, 255, 127}) |
| 32 | + ac.AddColorStop(0.334, color.NRGBA{255, 255, 255, 159}) |
| 33 | + ac.AddColorStop(0.5, color.NRGBA{255, 255, 255, 255}) |
| 34 | + ac.AddColorStop(1, color.NRGBA{255, 255, 255, 255}) |
| 35 | + |
| 36 | + cardh, cardw := 80, 640 |
| 37 | + cardspac := 14 |
| 38 | + hspac, wspac := 64.0, 16.0 |
| 39 | + r := 16.0 |
| 40 | + |
| 41 | + wg := &sync.WaitGroup{} |
| 42 | + wg.Add(line) |
| 43 | + cardimgs := make([]image.Image, line) |
| 44 | + for i := 0; i < line; i++ { |
| 45 | + go func(i int) { |
| 46 | + defer wg.Done() |
| 47 | + card := gg.NewContext(w, cardh) |
| 48 | + |
| 49 | + card.NewSubPath() |
| 50 | + card.MoveTo(wspac+float64(cardh)/2, 0) |
| 51 | + |
| 52 | + card.LineTo(wspac+float64(cardw)-r, 0) |
| 53 | + card.DrawArc(wspac+float64(cardw)-r, r, r, gg.Radians(-90), gg.Radians(0)) |
| 54 | + card.LineTo(wspac+float64(cardw), float64(cardh)-r) |
| 55 | + card.DrawArc(wspac+float64(cardw)-r, float64(cardh)-r, r, gg.Radians(0), gg.Radians(90)) |
| 56 | + card.LineTo(wspac+float64(cardh)/2, float64(cardh)) |
| 57 | + |
| 58 | + card.DrawArc(wspac+float64(cardh)/2, float64(cardh)/2, float64(cardh)/2, gg.Radians(90), gg.Radians(270)) |
| 59 | + card.ClosePath() |
| 60 | + |
| 61 | + card.ClipPreserve() |
| 62 | + |
| 63 | + avatar := rankinfo[i].Avatar |
| 64 | + |
| 65 | + card.ScaleAbout(float64(cardw)/2/float64(avatar.Bounds().Dx()), float64(cardw)/2/float64(avatar.Bounds().Dy()), wspac, float64(cardh)/2) |
| 66 | + |
| 67 | + card.DrawImageAnchored(avatar, 0, cardh/2, 0, 0.5) |
| 68 | + card.Identity() |
| 69 | + card.ResetClip() |
| 70 | + |
| 71 | + card.SetFillStyle(ac) |
| 72 | + card.FillPreserve() |
| 73 | + |
| 74 | + card.SetRGBA255(0, 0, 0, 255) |
| 75 | + card.Stroke() |
| 76 | + card.DrawLine(wspac+float64(cardh)/2, float64(cardh), wspac+float64(cardw)-r, float64(cardh)) |
| 77 | + card.Stroke() |
| 78 | + |
| 79 | + card.DrawCircle(wspac+10+30, float64(cardh)/2, 30) |
| 80 | + card.ClipPreserve() |
| 81 | + card.ScaleAbout(60.0/float64(avatar.Bounds().Dx()), 60.0/float64(avatar.Bounds().Dy()), wspac+10+30, float64(cardh)/2) |
| 82 | + card.DrawImageAnchored(avatar, int(wspac)+10+30, cardh/2, 0.5, 0.5) |
| 83 | + card.Identity() |
| 84 | + |
| 85 | + card.ResetClip() |
| 86 | + card.SetRGBA255(0, 0, 0, 127) |
| 87 | + card.Stroke() |
| 88 | + |
| 89 | + card.SetRGB255(RandJPColor()) |
| 90 | + card.DrawCircle(wspac+float64(cardw-8-25), float64(cardh)/2, 25) |
| 91 | + card.Fill() |
| 92 | + cardimgs[i] = card.Image() |
| 93 | + }(i) |
| 94 | + } |
| 95 | + |
| 96 | + canvas.SetRGBA255(0, 0, 0, 255) |
| 97 | + err = canvas.ParseFontFace(fontdata, 32) |
| 98 | + if err != nil { |
| 99 | + return |
| 100 | + } |
| 101 | + canvas.DrawStringAnchored(title, w/2, 64/2, 0.5, 0.5) |
| 102 | + |
| 103 | + err = canvas.ParseFontFace(fontdata, 22) |
| 104 | + if err != nil { |
| 105 | + return |
| 106 | + } |
| 107 | + wg.Wait() |
| 108 | + for i := 0; i < line; i++ { |
| 109 | + canvas.DrawImageAnchored(cardimgs[i], w/2, int(hspac)+((cardh+cardspac)*i), 0.5, 0) |
| 110 | + canvas.DrawStringAnchored(rankinfo[i].TopLeftText, wspac+10+60+10, hspac+float64((cardspac+cardh)*i+cardh*3/8), 0, 0.5) |
| 111 | + } |
| 112 | + |
| 113 | + canvas.SetRGBA255(63, 63, 63, 255) |
| 114 | + err = canvas.ParseFontFace(fontdata, 12) |
| 115 | + if err != nil { |
| 116 | + return |
| 117 | + } |
| 118 | + for i := 0; i < line; i++ { |
| 119 | + canvas.DrawStringAnchored(rankinfo[i].BottomLeftText, wspac+10+60+10, hspac+float64((cardspac+cardh)*i+cardh*5/8), 0, 0.5) |
| 120 | + } |
| 121 | + canvas.SetRGBA255(0, 0, 0, 255) |
| 122 | + err = canvas.ParseFontFace(fontdata, 20) |
| 123 | + if err != nil { |
| 124 | + return |
| 125 | + } |
| 126 | + for i := 0; i < line; i++ { |
| 127 | + canvas.DrawStringAnchored(rankinfo[i].RightText, w-wspac-8-50-8, hspac+float64((cardspac+cardh)*i+cardh/2), 1, 0.5) |
| 128 | + } |
| 129 | + |
| 130 | + canvas.SetRGBA255(255, 255, 255, 255) |
| 131 | + err = canvas.ParseFontFace(fontdata, 28) |
| 132 | + if err != nil { |
| 133 | + return |
| 134 | + } |
| 135 | + for i := 0; i < line; i++ { |
| 136 | + canvas.DrawStringAnchored(strconv.Itoa(i+1), w-wspac-8-25, hspac+float64((cardspac+cardh)*i+cardh/2), 0.5, 0.5) |
| 137 | + } |
| 138 | + |
| 139 | + img = canvas.Image() |
| 140 | + return |
| 141 | +} |
0 commit comments