package main import ( "bytes" "encoding/base64" "image" "image/color" _ "image/gif" "image/jpeg" _ "image/png" "io/ioutil" "log" "math/rand" "os" "strings" "unicode" "time" "git.fromouter.space/crunchy-rocks/draw2d" "git.fromouter.space/crunchy-rocks/draw2d/draw2dimg" "git.fromouter.space/crunchy-rocks/freetype" "git.fromouter.space/hamcha/tg" ) var snapFontData draw2d.FontData func snapchat_init() { rand.Seed(time.Now().Unix()) fontfile, err := os.Open(*sourcesans) assert(err) defer fontfile.Close() bytes, err := ioutil.ReadAll(fontfile) assert(err) font, err := freetype.ParseFont(bytes) assert(err) snapFontData = draw2d.FontData{"sourcesans", draw2d.FontFamilySans, draw2d.FontStyleBold} draw2d.RegisterFont(snapFontData, font) log.Println("[snapchat] Loaded!") } func snapchat_message(broker *tg.Broker, update tg.APIMessage) { // 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 { caption := *(update.Caption) if strings.HasPrefix(caption, "/snap ") && len(caption) > 6 { txt := strings.TrimSpace(caption[6:]) maxsz := 0 photo := tg.APIPhotoSize{} for _, curphoto := range update.Photo { if curphoto.Width > maxsz { maxsz = curphoto.Width photo = curphoto } } broker.GetFile(photo.FileID, func(broker *tg.Broker, data tg.BrokerUpdate) { if data.Type == tg.BError { log.Printf("[snapchat] Received error from broker: %s\n", *data.Error) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &update.MessageID) return } pbytes, err := base64.StdEncoding.DecodeString(*data.Bytes) if err != nil { log.Printf("[snapchat] Base64 decode error: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &update.MessageID) return } img, _, err := image.Decode(bytes.NewReader(pbytes)) if err != nil { log.Printf("[snapchat] Image decode error: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERROR: Non riesco a leggere l'immagine", &update.MessageID) return } broker.SendChatAction(update.Chat, tg.ActionUploadingPhoto) // Create target image bounds := img.Bounds() iwidth := float64(bounds.Size().Y) / 1.6 iheight := float64(bounds.Size().Y) repos := iwidth < float64(bounds.Size().X) if !repos { iwidth = float64(bounds.Size().X) } timg := image.NewRGBA(image.Rect(0, 0, int(iwidth), int(iheight))) gc := draw2dimg.NewGraphicContext(timg) gc.Emojis = emojis gc.SetFontData(snapFontData) gc.Save() if repos { gc.Translate(-(float64(bounds.Size().X)-iwidth)/2, 0) } gc.DrawImage(img) gc.Restore() scale := iwidth / 25 gc.SetFontSize(scale) lineMargin := scale / 3 boxMargin := lineMargin topMargin := lineMargin / 6 write := func(text string, startHeight float64) { texts := wordWrap(gc, strings.TrimSpace(text), iwidth*0.9) totalHeight := startHeight firstLine := 0. for _, txt := range texts { _, top, _, bottom := gc.GetStringBounds(txt) height := (bottom - top) if firstLine == 0 { firstLine = height } totalHeight += lineMargin + height } // Draw background starty := startHeight - boxMargin - topMargin - firstLine endy := totalHeight + boxMargin - firstLine gc.Save() gc.SetFillColor(color.RGBA{0, 0, 0, 160}) gc.BeginPath() gc.MoveTo(0, starty) gc.LineTo(iwidth, starty) gc.LineTo(iwidth, endy) gc.LineTo(0, endy) gc.Close() gc.Fill() gc.Restore() // Write lines gc.SetFillColor(image.White) height := startHeight for _, txt := range texts { left, top, right, bottom := gc.GetStringBounds(txt) width := right - left gc.FillStringAt(txt, (iwidth-width)/2, height) height += lineMargin + (bottom - top) } } write(txt, (rand.Float64()*0.4+0.3)*iheight) buf := new(bytes.Buffer) err = jpeg.Encode(buf, timg, &(jpeg.Options{Quality: 80})) if err != nil { log.Printf("[snapchat] Image encode error: %s\n", err.Error()) broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &update.MessageID) return } broker.SendPhoto(update.Chat, buf.Bytes(), "meme.jpg", "", &update.MessageID) }) } } } // Word wrapping code from https://github.com/fogleman/gg // Copyright (C) 2016 Michael Fogleman // Licensed under MIT (https://github.com/fogleman/gg/blob/master/LICENSE.md) func splitOnSpace(x string) []string { var result []string pi := 0 ps := false for i, c := range x { s := unicode.IsSpace(c) if s != ps && i > 0 { result = append(result, x[pi:i]) pi = i } ps = s } result = append(result, x[pi:]) return result } func wordWrap(gc draw2d.GraphicContext, s string, width float64) []string { var result []string for _, line := range strings.Split(s, "\n") { fields := splitOnSpace(line) if len(fields)%2 == 1 { fields = append(fields, "") } x := "" for i := 0; i < len(fields); i += 2 { left, _, right, _ := gc.GetStringBounds(x + fields[i]) w := right - left if w > width { if x == "" { result = append(result, fields[i]) x = "" continue } else { result = append(result, x) x = "" } } x += fields[i] + fields[i+1] } if x != "" { result = append(result, x) } } for i, line := range result { result[i] = strings.TrimSpace(line) } return result }