This repository has been archived on 2023-07-05. You can view files and clone it, but cannot push or open issues or pull requests.
clessy/mods/memegen.go

216 lines
5.2 KiB
Go
Raw Normal View History

2016-02-15 16:52:25 +00:00
package main
import (
2016-02-19 16:35:43 +00:00
"bytes"
"encoding/base64"
2016-02-19 16:35:43 +00:00
"image"
_ "image/gif"
"image/jpeg"
_ "image/png"
"io/ioutil"
"log"
2016-02-19 16:35:43 +00:00
"os"
2016-02-15 16:52:25 +00:00
"strings"
2016-02-19 16:35:43 +00:00
"github.com/golang/freetype"
2016-02-15 16:52:25 +00:00
"github.com/hamcha/clessy/tg"
2016-02-19 16:35:43 +00:00
"github.com/llgcode/draw2d"
"github.com/llgcode/draw2d/draw2dimg"
2016-02-15 16:52:25 +00:00
)
2016-02-19 16:35:43 +00:00
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)
2016-02-20 21:28:30 +00:00
memeFontData = draw2d.FontData{"impact", draw2d.FontFamilySans, 0}
2016-02-19 16:35:43 +00:00
draw2d.RegisterFont(memeFontData, font)
2017-03-15 20:20:07 +00:00
log.Println("[meme] Loaded!")
2016-02-19 16:35:43 +00:00
}
2016-02-15 16:52:25 +00:00
func memegen(broker *tg.Broker, update tg.APIMessage) {
2016-04-10 12:48:28 +00:00
// Make replies work
if update.ReplyTo != nil && update.Text != nil && update.ReplyTo.Photo != nil {
update.Photo = update.ReplyTo.Photo
update.Caption = update.Text
}
if update.Photo != nil && update.Caption != nil {
2016-02-19 16:35:43 +00:00
caption := *(update.Caption)
if strings.HasPrefix(caption, "/meme ") && len(caption) > 6 {
idx := strings.Index(caption, ";")
if idx < 0 {
broker.SendTextMessage(update.Chat, "<b>Formato</b>: /meme TESTO IN ALTO<b>;</b>TESTO IN BASSO", &update.MessageID)
2016-02-19 16:35:43 +00:00
return
}
txtup := caption[6:idx]
txtdw := caption[idx+1:]
maxsz := 0
photo := tg.APIPhotoSize{}
for _, curphoto := range update.Photo {
if curphoto.Width > maxsz {
maxsz = curphoto.Width
photo = curphoto
}
}
2016-02-20 20:57:04 +00:00
2016-02-19 16:35:43 +00:00
broker.GetFile(photo.FileID, func(broker *tg.Broker, data tg.BrokerUpdate) {
2016-02-20 21:33:09 +00:00
if data.Type == tg.BError {
2017-02-15 15:59:49 +00:00
log.Printf("[memegen] Received error from broker: %s\n", *data.Error)
2016-02-20 21:33:09 +00:00
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
return
}
pbytes, err := base64.StdEncoding.DecodeString(*data.Bytes)
2016-02-19 16:35:43 +00:00
if err != nil {
2017-02-15 15:59:49 +00:00
log.Printf("[memegen] Base64 decode error: %s\n", err.Error())
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
return
}
img, _, err := image.Decode(bytes.NewReader(pbytes))
if err != nil {
2017-02-15 15:59:49 +00:00
log.Printf("[memegen] Image decode error: %s\n", err.Error())
broker.SendTextMessage(update.Chat, "<b>ERROR</b>: Non riesco a leggere l'immagine", &update.MessageID)
2016-02-19 16:35:43 +00:00
return
}
broker.SendChatAction(update.Chat, tg.ActionUploadingPhoto)
2016-02-19 16:35:43 +00:00
//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
2016-02-20 22:18:25 +00:00
scale := iheight / iwidth * (iwidth / 10)
2016-02-19 16:35:43 +00:00
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 {
2016-02-20 22:18:25 +00:00
log.Println("Warning, resizing!")
gc.SetFontSize(scale * (0.8 - 0.1*float64(iter)))
2016-06-20 15:52:06 +00:00
left, top, right, bottom = gc.GetStringBounds(texts[longid])
2016-02-19 16:35:43 +00:00
width = right - left
iter++
}
}
height := bottom - top
2016-02-20 22:18:25 +00:00
margin := float64(height / 50)
2016-02-19 16:35:43 +00:00
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 {
2016-02-20 22:18:25 +00:00
y = (height+margin)*float64(id+1) + margin*5
2016-02-19 16:35:43 +00:00
} 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}))
if err != nil {
2017-02-15 15:59:49 +00:00
log.Printf("[memegen] Image encode error: %s\n", err.Error())
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
return
}
2016-09-01 12:05:32 +00:00
broker.SendPhoto(update.Chat, buf.Bytes(), "meme.jpg", "", &update.MessageID)
2016-02-19 16:35:43 +00:00
})
2016-02-15 16:52:25 +00:00
}
}
}
2016-02-19 16:35:43 +00:00
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
}