diff --git a/Makefile b/Makefile
index e671976..f5cd0da 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ all: clessy-broker clessy-mods clessy-stats
deps:
go get github.com/boltdb/bolt/...
go get github.com/golang/freetype
+ go get github.com/llgcode/draw2d
install-tg:
go install github.com/hamcha/clessy/tg
diff --git a/mods/main.go b/mods/main.go
index f5589d6..3cf7a5c 100644
--- a/mods/main.go
+++ b/mods/main.go
@@ -9,6 +9,7 @@ import (
func initmods() {
initviaggi()
+ initmeme()
}
func dispatch(broker *tg.Broker, update tg.APIMessage) {
@@ -26,10 +27,12 @@ func isCommand(update tg.APIMessage, cmdname string) bool {
}
var botname *string
+var impact *string
func main() {
brokerAddr := flag.String("broker", "localhost:7314", "Broker address:port")
botname = flag.String("botname", "maudbot", "Bot name for /targetet@commands")
+ impact = flag.String("impact", "impact.ttf", "Path to impact.ttf (Impact font)")
flag.Parse()
initmods()
@@ -39,3 +42,9 @@ func main() {
panic(err)
}
}
+
+func assert(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/mods/memegen.go b/mods/memegen.go
index ea70c6c..487d269 100644
--- a/mods/memegen.go
+++ b/mods/memegen.go
@@ -1,15 +1,51 @@
package main
import (
- "fmt"
+ "bytes"
+ "image"
+ _ "image/gif"
+ "image/jpeg"
+ _ "image/png"
+ "io/ioutil"
+ "os"
"strings"
+ "github.com/golang/freetype"
"github.com/hamcha/clessy/tg"
+ "github.com/llgcode/draw2d"
+ "github.com/llgcode/draw2d/draw2dimg"
)
+var memeFontData draw2d.FontData
+
+func initmeme() {
+ fontfile, err := os.Open(*impact)
+ assert(err)
+ defer fontfile.Close()
+
+ bytes, err := ioutil.ReadAll(fontfile)
+ assert(err)
+
+ font, err := freetype.ParseFont(bytes)
+ assert(err)
+
+ memeFontData := draw2d.FontData{"impact", draw2d.FontFamilySans, 0}
+ draw2d.RegisterFont(memeFontData, font)
+}
+
func memegen(broker *tg.Broker, update tg.APIMessage) {
if update.Photo != nil && update.Caption != nil {
- if strings.HasPrefix(*(update.Caption), "/meme") {
+ caption := *(update.Caption)
+ if strings.HasPrefix(caption, "/meme ") && len(caption) > 6 {
+ idx := strings.Index(caption, ";")
+ if idx < 0 {
+ broker.SendTextMessage(update.Chat, "Formato: /meme TESTO IN ALTO;TESTO IN BASSO", &(update.MessageID))
+ return
+ }
+
+ txtup := caption[6:idx]
+ txtdw := caption[idx+1:]
+
maxsz := 0
photo := tg.APIPhotoSize{}
for _, curphoto := range update.Photo {
@@ -18,7 +54,128 @@ func memegen(broker *tg.Broker, update tg.APIMessage) {
photo = curphoto
}
}
- fmt.Println(photo)
+ broker.GetFile(photo.FileID, func(broker *tg.Broker, data tg.BrokerUpdate) {
+ img, _, err := image.Decode(bytes.NewReader(data.Bytes))
+ if err != nil {
+ broker.SendTextMessage(update.Chat, "ERROR: Non riesco a leggere l'immagine", &(update.MessageID))
+ return
+ }
+
+ //TODO Clean up this mess
+
+ // Create target image
+ bounds := img.Bounds()
+ iwidth := float64(bounds.Size().X)
+ iheight := float64(bounds.Size().Y)
+
+ timg := image.NewRGBA(bounds)
+ gc := draw2dimg.NewGraphicContext(timg)
+ gc.SetStrokeColor(image.Black)
+ gc.SetFillColor(image.White)
+ gc.SetFontData(memeFontData)
+ gc.DrawImage(img)
+
+ write := func(text string, istop bool) {
+ text = strings.ToUpper(strings.TrimSpace(text))
+ gc.Restore()
+ gc.Save()
+
+ // Detect appropriate font size
+ scale := iwidth / iheight * 200
+ gc.SetFontSize(scale)
+ gc.SetLineWidth(scale / 15)
+
+ // Get NEW bounds
+ left, top, right, bottom := gc.GetStringBounds(text)
+
+ width := right - left
+ texts := []string{text}
+ if width > iwidth {
+ // Split text
+ texts = splitCenter(text)
+
+ // Get longest line
+ longer := float64(0)
+ longid := 0
+ widths := make([]float64, len(texts))
+ for id := range texts {
+ tleft, _, tright, _ := gc.GetStringBounds(texts[id])
+ widths[id] = tright - tleft
+ if width > longer {
+ longer = widths[id]
+ longid = id
+ }
+ }
+
+ // Still too big? Decrease font size again
+ iter := 0
+ for width > iwidth && iter < 10 {
+ left, _, right, _ = gc.GetStringBounds(texts[longid])
+ gc.SetFontSize(scale * 0.8)
+ width = right - left
+ iter++
+ }
+ }
+
+ height := bottom - top
+ margin := float64(10)
+ lines := float64(len(texts) - 1)
+
+ gc.Save()
+ for id, txt := range texts {
+ gc.Save()
+ left, _, right, _ = gc.GetStringBounds(txt)
+ width = right - left
+
+ y := float64(0)
+ if istop {
+ y = (height-margin)*float64(id+1) + margin*5
+ } else {
+ y = iheight - (height * lines) + (height * float64(id)) - margin*5
+ }
+
+ gc.Translate((iwidth-width)/2, y)
+ gc.StrokeString(txt)
+ gc.FillString(txt)
+ gc.Restore()
+ }
+ }
+ write(txtup, true)
+ write(txtdw, false)
+
+ buf := new(bytes.Buffer)
+ err = jpeg.Encode(buf, timg, &(jpeg.Options{Quality: 80}))
+ })
}
}
}
+
+func splitCenter(text string) []string {
+ cindx := int(len(text) / 2)
+ bs := 0
+ md := 9999
+ id := -1
+ for i := 0; ; i++ {
+ idx := strings.Index(text[bs:], " ")
+ if idx < 0 {
+ break
+ }
+ bs += idx + 1
+ diff := abs(cindx - bs)
+ if diff < md {
+ md = diff
+ id = bs - 1
+ }
+ }
+ if id >= 0 {
+ return []string{text[0:id], text[id+1:]}
+ }
+ return []string{text}
+}
+
+func abs(i int) int {
+ if i < 0 {
+ return -i
+ }
+ return i
+}