-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
419 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
config.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# cards-generator | ||
|
||
Generate cards for bot | ||
|
||
[](https://goreportcard.com/report/github.com/train-cat/cards-generator) | ||
|
||
## Exemple | ||
<img src="example.png" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package main | ||
|
||
import ( | ||
"image" | ||
|
||
"github.com/fogleman/gg" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
var cacheImages = map[int]image.Image{} | ||
|
||
func getBaseImage(week Days) image.Image { | ||
img, ok := cacheImages[int(week)] | ||
|
||
if !ok || refreshCache { | ||
img = generateBaseImage(week) | ||
|
||
log.Infof("miss cache") | ||
|
||
cacheImages[int(week)] = img | ||
} | ||
|
||
return img | ||
} | ||
|
||
func generateBaseImage(week Days) image.Image { | ||
dc := gg.NewContext(width, height) | ||
|
||
dc.SetColor(backgroundColor) | ||
dc.Clear() | ||
|
||
drawDays(dc, week) | ||
|
||
return dc.Image() | ||
} | ||
|
||
func drawDays(dc *gg.Context, week Days) { | ||
for _, d := range days { | ||
if week.HasFlag(d.Flag) { | ||
loadDayOn(dc) | ||
} else { | ||
loadDayOff(dc) | ||
} | ||
|
||
dc.DrawStringAnchored(d.Letter, float64(d.PosX), float64(centerCaseDays), 0.5, 0.5) | ||
} | ||
} | ||
|
||
func loadDayOn(dc *gg.Context) { | ||
dc.SetFontFace(fontBold) | ||
dc.SetColor(colorDayOn) | ||
} | ||
|
||
func loadDayOff(dc *gg.Context) { | ||
dc.SetFontFace(fontRegular) | ||
dc.SetColor(colorDayOff) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
{ | ||
"font": { | ||
"regular": { | ||
"size": 24, | ||
"path": "fonts/Roboto-Regular.ttf" | ||
}, | ||
"bold": { | ||
"size": 32, | ||
"path": "fonts/Roboto-Bold.ttf" | ||
} | ||
}, | ||
"text": { | ||
"limit": 24, | ||
"cut_after": 22 | ||
}, | ||
"image": { | ||
"color": { | ||
"background": { | ||
"R": 0, | ||
"G": 136, | ||
"B": 208, | ||
"A": 255 | ||
}, | ||
"day_on": { | ||
"R": 249, | ||
"G": 186, | ||
"B": 24, | ||
"A": 255 | ||
}, | ||
"day_off": { | ||
"R": 230, | ||
"G": 230, | ||
"B": 230, | ||
"A": 255 | ||
}, | ||
"text": { | ||
"R": 255, | ||
"G": 255, | ||
"B": 255, | ||
"A": 255 | ||
} | ||
}, | ||
"size": { | ||
"height": 200, | ||
"width": 382 | ||
}, | ||
"position": { | ||
"days": { | ||
"y": 150 | ||
}, | ||
"mission": { | ||
"x": 362, | ||
"y": 10 | ||
}, | ||
"schedule": { | ||
"x": 15, | ||
"y": 10 | ||
}, | ||
"origin": { | ||
"x": 15, | ||
"y": 60 | ||
}, | ||
"terminus": { | ||
"x": 15, | ||
"y": 95 | ||
} | ||
} | ||
}, | ||
"cache": { | ||
"force_refresh": false | ||
}, | ||
"http": { | ||
"port": 9090 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package main | ||
|
||
const ( | ||
Sunday = 1 << iota | ||
Saturday | ||
Friday | ||
Thursday | ||
Wednesday | ||
Tuesday | ||
Monday | ||
|
||
daysPerWeek = 7 | ||
) | ||
|
||
type ( | ||
// Days is binary representation | ||
Days uint8 | ||
|
||
Day struct { | ||
Flag Days | ||
Letter string | ||
PosX int | ||
} | ||
) | ||
|
||
var days []Day | ||
|
||
// HasFlag return true if mask has specific flag set | ||
func (d Days) HasFlag(flag Days) bool { return d&flag != 0 } | ||
|
||
// AddFlag to the binary representation | ||
func (d *Days) AddFlag(flag Days) { *d |= flag } | ||
|
||
// ClearFlag remove flag | ||
func (d *Days) ClearFlag(flag Days) { *d &= ^flag } | ||
|
||
// ToggleFlag inverse state of the flag | ||
func (d *Days) ToggleFlag(flag Days) { *d ^= flag } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"strconv" | ||
|
||
"github.com/fogleman/gg" | ||
) | ||
|
||
func serveImage(w http.ResponseWriter, r *http.Request) { | ||
v := r.URL.Query() | ||
|
||
mission := v.Get("mission") | ||
origin := formatStation(v.Get("origin")) | ||
terminus := formatStation(v.Get("terminus")) | ||
schedule := v.Get("schedule") | ||
days, err := strconv.Atoi(v.Get("days")) | ||
|
||
if mission == "" || origin == "" || terminus == "" || schedule == "" || days == 0 || days > 127 || err != nil { | ||
w.WriteHeader(http.StatusBadRequest) | ||
w.Write([]byte("{\"status\": \"bad request\"}")) | ||
return | ||
} | ||
|
||
dc := gg.NewContextForImage(getBaseImage(Days(days))) | ||
|
||
dc.SetColor(colorText) | ||
|
||
dc.SetFontFace(fontRegular) | ||
dc.DrawStringAnchored(mission, xMission, yMission, 1, 1) | ||
dc.DrawStringAnchored(schedule, xSchedule, ySchedule, 0, 1) | ||
|
||
dc.SetFontFace(fontBold) | ||
dc.DrawStringAnchored(origin, xOrigin, yOrigin, 0, 1) | ||
dc.DrawStringAnchored(terminus, xTerminus, yTerminus, 0, 1) | ||
|
||
dc.EncodePNG(w) | ||
} | ||
|
||
func formatStation(name string) string { | ||
if len(name) > limit { | ||
return fmt.Sprintf("%s...", name[:cutAfter]) | ||
} | ||
|
||
return name | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"image/color" | ||
|
||
"github.com/fogleman/gg" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/viper" | ||
"golang.org/x/image/font" | ||
) | ||
|
||
var ( | ||
refreshCache bool | ||
limit int | ||
cutAfter int | ||
|
||
fontRegular font.Face | ||
fontBold font.Face | ||
|
||
height int | ||
width int | ||
heightDays int | ||
widthPerCase int | ||
heightPerCase int | ||
centerCaseDays int | ||
|
||
backgroundColor color.Color | ||
colorDayOn color.Color | ||
colorDayOff color.Color | ||
colorText color.Color | ||
|
||
xMission float64 | ||
yMission float64 | ||
xSchedule float64 | ||
ySchedule float64 | ||
xOrigin float64 | ||
yOrigin float64 | ||
xTerminus float64 | ||
yTerminus float64 | ||
) | ||
|
||
func init() { | ||
initConfig() | ||
initFont() | ||
initVar() | ||
initDays() | ||
} | ||
|
||
func initConfig() { | ||
cfgFile := flag.String("config", "config.json", "config file") | ||
flag.Parse() | ||
|
||
viper.SetConfigFile(*cfgFile) | ||
viper.AutomaticEnv() // read in environment variables that match | ||
|
||
// If a config file is found, read it in. | ||
if err := viper.ReadInConfig(); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func initFont() { | ||
var err error | ||
|
||
fontRegular, err = gg.LoadFontFace(viper.GetString("font.regular.path"), viper.GetFloat64("font.regular.size")) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
fontBold, err = gg.LoadFontFace(viper.GetString("font.bold.path"), viper.GetFloat64("font.bold.size")) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func initVar() { | ||
// size | ||
height = viper.GetInt("image.size.height") | ||
width = viper.GetInt("image.size.width") | ||
heightDays = viper.GetInt("image.position.days.y") | ||
widthPerCase = width / daysPerWeek | ||
heightPerCase = height - heightDays | ||
centerCaseDays = height - heightPerCase/2 | ||
|
||
// color | ||
backgroundColor = color.RGBA{ | ||
R: uint8(viper.GetInt("image.color.background.R")), | ||
G: uint8(viper.GetInt("image.color.background.G")), | ||
B: uint8(viper.GetInt("image.color.background.B")), | ||
A: uint8(viper.GetInt("image.color.background.A")), | ||
} | ||
colorDayOn = color.RGBA{ | ||
R: uint8(viper.GetInt("image.color.day_on.R")), | ||
G: uint8(viper.GetInt("image.color.day_on.G")), | ||
B: uint8(viper.GetInt("image.color.day_on.B")), | ||
A: uint8(viper.GetInt("image.color.day_on.A")), | ||
} | ||
colorDayOff = color.RGBA{ | ||
R: uint8(viper.GetInt("image.color.day_off.R")), | ||
G: uint8(viper.GetInt("image.color.day_off.G")), | ||
B: uint8(viper.GetInt("image.color.day_off.B")), | ||
A: uint8(viper.GetInt("image.color.day_off.A")), | ||
} | ||
colorText = color.RGBA{ | ||
R: uint8(viper.GetInt("image.color.text.R")), | ||
G: uint8(viper.GetInt("image.color.text.G")), | ||
B: uint8(viper.GetInt("image.color.text.B")), | ||
A: uint8(viper.GetInt("image.color.text.A")), | ||
} | ||
|
||
// config | ||
refreshCache = viper.GetBool("cache.force_refresh") | ||
limit = viper.GetInt("text.limit") | ||
cutAfter = viper.GetInt("text.cut_after") | ||
|
||
// position | ||
xMission = viper.GetFloat64("image.position.mission.x") | ||
yMission = viper.GetFloat64("image.position.mission.y") | ||
|
||
xSchedule = viper.GetFloat64("image.position.schedule.x") | ||
ySchedule = viper.GetFloat64("image.position.schedule.y") | ||
|
||
xOrigin = viper.GetFloat64("image.position.origin.x") | ||
yOrigin = viper.GetFloat64("image.position.origin.y") | ||
|
||
xTerminus = viper.GetFloat64("image.position.terminus.x") | ||
yTerminus = viper.GetFloat64("image.position.terminus.y") | ||
} | ||
|
||
func initDays() { | ||
days = []Day{ | ||
{Monday, "L", widthPerCase / 2}, | ||
{Tuesday, "M", widthPerCase*1 + widthPerCase/2}, | ||
{Wednesday, "M", widthPerCase*2 + widthPerCase/2}, | ||
{Thursday, "J", widthPerCase*3 + widthPerCase/2}, | ||
{Friday, "V", widthPerCase*4 + widthPerCase/2}, | ||
{Saturday, "S", widthPerCase*5 + widthPerCase/2}, | ||
{Sunday, "D", widthPerCase*6 + widthPerCase/2}, | ||
} | ||
} |
Oops, something went wrong.