diff --git a/assets/badge.png b/assets/badge.png
new file mode 100644
index 0000000..86c8497
Binary files /dev/null and b/assets/badge.png differ
diff --git a/config/cfg.go b/config/cfg.go
index 7048cc4..76c2d98 100644
--- a/config/cfg.go
+++ b/config/cfg.go
@@ -15,6 +15,7 @@ type (
EmailHost string
EmailHostAddr string
ManualRegistration bool
+ EmojiFolder string
}
)
@@ -27,5 +28,6 @@ func New() *Config {
KeyFile: os.Getenv("CERT_KEY_FILE"),
AssetsDir: os.Getenv("ASSETS_DIR"),
ManualRegistration: len(os.Getenv("MANUAL_REGISTRATION")) > 0,
+ EmojiFolder: os.Getenv("EMOJI_FOLDER"),
}
}
diff --git a/web/handler/handler.go b/web/handler/handler.go
index 5d7d042..e2372e7 100644
--- a/web/handler/handler.go
+++ b/web/handler/handler.go
@@ -82,8 +82,7 @@ func New(cfg *config.Config, sess *session.Session, data *storage.Storage) (http
router.HandleFunc("/users/{user}/status", h.showUserStatusView).Methods(http.MethodGet)
router.HandleFunc("/users/{user}/status.json", h.showUserStatusJSONView).Methods(http.MethodGet)
- //router.HandleFunc("/users/{user}/status.png", h.showUserStatusImageViewEmoji).Methods(http.MethodGet)
- //router.HandleFunc("/users/{user}/badge.png", h.showUserStatusBadgeView).Methods(http.MethodGet)
+ router.HandleFunc("/users/{user}/badge.png", h.showUserStatusImageViewEmoji).Methods(http.MethodGet)
router.PathPrefix("/assets/").Handler(
http.StripPrefix("/assets/",
http.FileServer(
diff --git a/web/handler/html.go b/web/handler/html.go
index 68719c1..6444e95 100644
--- a/web/handler/html.go
+++ b/web/handler/html.go
@@ -166,12 +166,13 @@ var TplMap = map[string]string{
status widget for your homepage
Subscribe via Atom
+ 
{{ else }}
Welcome!
status.cafe is a place to share your current status.
Register now!
{{ end }}
- 
+ 
Status stream
diff --git a/web/handler/html/index.html b/web/handler/html/index.html
index 23ca61e..1d71a72 100644
--- a/web/handler/html/index.html
+++ b/web/handler/html/index.html
@@ -15,12 +15,13 @@
status widget for your homepage
Subscribe via Atom
+ 
{{ else }}
Welcome!
status.cafe is a place to share your current status.
Register now!
{{ end }}
- 
+ 
Status stream
diff --git a/web/handler/login_check.go b/web/handler/login_check.go
index 9019ccd..29318d7 100644
--- a/web/handler/login_check.go
+++ b/web/handler/login_check.go
@@ -1,6 +1,7 @@
package handler
import (
+ "github.com/gorilla/csrf"
"net/http"
"status/model"
"status/web/handler/form"
@@ -15,7 +16,8 @@ func (h *Handler) checkLogin(w http.ResponseWriter, r *http.Request) {
if err != nil {
f.Error = err.Error()
h.renderLayout(w, "login", map[string]interface{}{
- "form": f,
+ "form": f,
+ csrf.TemplateTag: csrf.TemplateField(r),
}, "")
return
}
diff --git a/web/handler/user_show.go b/web/handler/user_show.go
index 2a6a819..79de4b3 100644
--- a/web/handler/user_show.go
+++ b/web/handler/user_show.go
@@ -6,22 +6,20 @@ import (
"encoding/xml"
"errors"
"fmt"
- "github.com/fogleman/gg"
- "github.com/golang/freetype"
"github.com/golang/freetype/truetype"
"github.com/gorilla/mux"
"golang.org/x/image/draw"
"golang.org/x/image/font"
+ "golang.org/x/image/font/gofont/gobold"
_ "golang.org/x/image/font/gofont/gobold"
- "golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/math/fixed"
"html/template"
"image"
- "image/color"
-
"image/jpeg"
+ "image/png"
"io"
"os"
+ "path/filepath"
"status/model"
"strconv"
"strings"
@@ -31,85 +29,19 @@ import (
"net/http"
)
-const (
- exitSuccess = 0
- exitFailure = 1
-)
-
-const (
- imagePath = "/home/m15o/Downloads/noto-emoji-main/png/128"
- aliasFile = "/home/m15o/Downloads/noto-emoji-main/emoji_aliases.txt"
- fontSize = 64 // point
- imageWidth = 640 // pixel
- imageHeight = 120 // pixel
- textTopMargin = 80 // fixed.I
- lineHeight = 70 // fixed.I
-)
-
-// emoji alias
-var alias = map[string]string{}
-
-//
-//func init() {
-// fp, err := os.Open(aliasFile)
-// if err != nil {
-// panic(err)
-// }
-//
-// s := bufio.NewScanner(fp)
-// for s.Scan() {
-// line := s.Text()
-//
-// /*
-// alias file format:
-// # 'fe0f' is not in these sequences
-// 1f3c3;1f3c3_200d_2642 # RUNNER -> man running
-// */
-//
-// if strings.HasPrefix(line, "#") {
-// continue
-// }
-//
-// s := strings.Split(line, ";")
-// if len(s) != 2 {
-// continue
-// }
-//
-// i := strings.Index(s[1], " ")
-// if i < 0 {
-// continue
-// }
-//
-// from := s[0]
-// to := s[1][:i]
-//
-// alias[from] = to
-// }
-//
-// if err := s.Err(); err != nil {
-// fmt.Fprintln(os.Stderr, "reading alias file:", err)
-// }
-//
-//}
-
func exist(path string) bool {
_, err := os.Stat(path)
return err == nil
}
-// GetPath if unicode codepoint is included in list and file exists return file path
-func getPath(r rune) (string, error) {
+func getPath(r rune, emojipath string) (string, error) {
if r > 47 && r < 58 {
return "", errors.New("numeric char")
}
name := fmt.Sprintf("%.4x", r)
var path string
- if v, ok := alias[name]; ok {
- path = fmt.Sprintf("%s/emoji_u%s.png", imagePath, v)
- } else {
- path = fmt.Sprintf("%s/emoji_u%s.png", imagePath, name)
- }
+ path = fmt.Sprintf("%s/emoji_u%s.png", emojipath, name)
if !exist(path) {
return "", fmt.Errorf("%s does NOT exist", path)
@@ -118,10 +50,10 @@ func getPath(r rune) (string, error) {
return path, nil
}
-func loadEmoji(r rune, size int) (image.Image, bool) {
+func loadEmoji(r rune, size int, emojipath string) (image.Image, bool) {
var img image.Image
- path, err := getPath(r)
+ path, err := getPath(r, emojipath)
if err != nil {
//fmt.Fprintln(os.Stderr, err)
return img, false
@@ -147,11 +79,10 @@ func loadEmoji(r rune, size int) (image.Image, bool) {
return dst, true
}
-func renderLine(img draw.Image, dr *font.Drawer, s string) {
+func renderLine(img image.Image, dr *font.Drawer, s, emojipath string) {
size := dr.Face.Metrics().Ascent.Floor() + dr.Face.Metrics().Descent.Floor()
-
for _, r := range s {
- emoji, ok := loadEmoji(r, size)
+ emoji, ok := loadEmoji(r, size, emojipath)
if ok {
// Drawer.Dot is glyph baseline of next glyph
@@ -160,36 +91,33 @@ func renderLine(img draw.Image, dr *font.Drawer, s string) {
rect := image.Rect(0, 0, size, size).Add(p)
// draw emoji and ascend baseline
- draw.Draw(img, rect, emoji, image.ZP, draw.Over)
+ draw.Draw(img.(draw.Image), rect, emoji, image.ZP, draw.Over)
dr.Dot.X += fixed.I(size)
} else {
// fallback: use normal glyph
- dr.DrawString(string(r))
}
}
}
-func renderText(img draw.Image, face font.Face, text string) error {
+func renderText(img image.Image, face font.Face, text, emojipath string) error {
dr := &font.Drawer{
- Dst: img,
+ Dst: img.(draw.Image),
Src: image.White,
Face: face,
Dot: fixed.Point26_6{},
}
+ for _, s := range strings.Split(text, "\n") {
+ dr.Dot.X = fixed.I(6)
+ dr.Dot.Y = fixed.I(13)
- for i, s := range strings.Split(text, "\n") {
- dr.Dot.X = (fixed.I(imageWidth) - dr.MeasureString(s)) / 2
- dr.Dot.Y = fixed.I(textTopMargin + i*lineHeight)
-
- renderLine(img, dr, s)
+ renderLine(img, dr, s, emojipath)
}
-
return nil
}
func outputJPEG(img image.Image, w io.Writer) error {
buf := new(bytes.Buffer)
- err := jpeg.Encode(buf, img, nil)
+ err := jpeg.Encode(buf, img, &jpeg.Options{Quality: 100})
if err != nil {
return err
}
@@ -316,50 +244,7 @@ func (h *Handler) showUserStatusView(w http.ResponseWriter, r *http.Request) {
h.view("status").Execute(w, map[string]interface{}{"status": status})
}
-func drawText(canvas *image.RGBA, text string) error {
- var (
- fgColor image.Image
- fontFace *truetype.Font
- err error
- fontSize = 12.0
- )
- fgColor = image.White
- fontFace, err = freetype.ParseFont(goregular.TTF)
- fontDrawer := &font.Drawer{
- Dst: canvas,
- Src: fgColor,
- Face: truetype.NewFace(fontFace, &truetype.Options{
- Size: fontSize,
- Hinting: font.HintingFull,
- }),
- }
- //textBounds, _ := fontDrawer.BoundString(text)
- xPosition := fixed.I(20)
- //textHeight := textBounds.Max.Y - textBounds.Min.Y
- yPosition := fixed.I(20)
- fontDrawer.Dot = fixed.Point26_6{
- X: xPosition,
- Y: yPosition,
- }
- fontDrawer.DrawString(text)
- return err
-}
-
-func createAvatar(text string) *image.RGBA {
- bgColor := color.RGBA{
- R: 255,
- G: 20,
- B: 100,
- A: 255,
- }
- background := image.NewRGBA(image.Rect(0, 0, 200, 100))
- draw.Draw(background, background.Bounds(), &image.Uniform{C: bgColor},
- image.Point{}, draw.Src)
- drawText(background, text)
- return background
-}
-
-func (h *Handler) showUserStatusBadgeView(w http.ResponseWriter, r *http.Request) {
+func (h *Handler) showUserStatusImageViewEmoji(w http.ResponseWriter, r *http.Request) {
user := mux.Vars(r)["user"]
if !h.storage.UserExists(user) {
notFound(w)
@@ -371,131 +256,49 @@ func (h *Handler) showUserStatusBadgeView(w http.ResponseWriter, r *http.Request
return
}
- var username string
+ face := "🙂"
if len(statuses) > 0 {
- username = statuses[0].User
+ face = statuses[0].Face
}
- background := "#f0ffff"
-
- dc := gg.NewContext(88, 31)
- dc.SetHexColor(background)
- dc.Clear()
- dc.SetHexColor("#191970")
- font, err := truetype.Parse(goregular.TTF)
- if err != nil {
- panic("")
- }
- face := truetype.NewFace(font, &truetype.Options{
- Size: 12,
- })
- dc.SetFontFace(face)
- if err != nil {
- fmt.Println(err)
- }
- //dc.DrawString(username, 10, 14)
- dc.DrawStringAnchored(username, 88/2, 8, 0.5, 0.5)
- dc.DrawStringAnchored("status.cafe", 88/2, 20, 0.5, 0.5)
- dc.EncodePNG(w)
-}
-
-//
-//func (h *Handler) showUserStatusImageViewEmoji(w http.ResponseWriter, r *http.Request) {
-// user := mux.Vars(r)["user"]
-// if !h.storage.UserExists(user) {
-// notFound(w)
-// return
-// }
-// statuses, _, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0)
-// if err != nil {
-// serverError(w, err)
-// return
-// }
-//
-// var username string
-// var face string
-// if len(statuses) > 0 {
-// username = statuses[0].User
-// face = statuses[0].Face
-// }
-//
-// img := image.NewRGBA(image.Rect(0, 0, imageWidth, imageHeight))
-//
-// ft, err := truetype.Parse(gobold.TTF)
-// if err != nil {
-// fmt.Fprintln(os.Stderr, err)
-// os.Exit(exitFailure)
-// }
-//
-// opt := truetype.Options{
-// Size: fontSize,
-// DPI: 0,
-// Hinting: 0,
-// GlyphCacheEntries: 0,
-// SubPixelsX: 0,
-// SubPixelsY: 0,
-// }
-//
-// renderText(img, truetype.NewFace(ft, &opt), fmt.Sprintf("%s %s", username, face))
-//
-// err = outputJPEG(img, w)
-// if err != nil {
-// fmt.Fprintln(os.Stderr, err)
-// os.Exit(exitFailure)
-// }
-//}
-
-func (h *Handler) showUserStatusImageView(w http.ResponseWriter, r *http.Request) {
- user := mux.Vars(r)["user"]
- if !h.storage.UserExists(user) {
- notFound(w)
- return
- }
- statuses, _, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0)
+ f, err := os.Open(filepath.Join(h.cfg.AssetsDir, "badge.png"))
if err != nil {
serverError(w, err)
return
}
- //w.Header().Set("Access-Control-Allow-Origin", "*")
- //w.Header().Set("Content-Type", "application/json")
- var text string
- if len(statuses) > 0 {
- text = statuses[0].Content
- }
- background := "#ffffff"
- foreground := "#000000"
-
- if c := r.URL.Query().Get("background"); c != "" {
- background = "#" + c
- }
-
- if c := r.URL.Query().Get("foreground"); c != "" {
- foreground = "#" + c
- }
-
- width := 125
- dc := gg.NewContext(width, 125)
- dc.SetHexColor(background)
- dc.Clear()
- dc.SetHexColor(foreground)
- font, err := truetype.Parse(goregular.TTF)
+ img, err := png.Decode(f)
if err != nil {
- panic("")
+ serverError(w, err)
+ return
}
- face := truetype.NewFace(font, &truetype.Options{
- Size: 9,
- })
- dc.SetFontFace(face)
- if err != nil {
- fmt.Println(err)
- }
- dc.DrawStringWrapped(text, 8, 4, 0, 0, float64(width-(2*8)), 1.5, gg.AlignLeft)
- dc.EncodePNG(w)
- //dc.SavePNG("out.png")
- //avatar := createAvatar(text)
- //png.Encode(w, avatar)
+ ft, err := truetype.Parse(gobold.TTF)
+ if err != nil {
+ serverError(w, err)
+ return
+ }
+
+ opt := truetype.Options{
+ Size: 14,
+ DPI: 0,
+ Hinting: 0,
+ GlyphCacheEntries: 0,
+ SubPixelsX: 0,
+ SubPixelsY: 0,
+ }
+
+ err = renderText(img, truetype.NewFace(ft, &opt), fmt.Sprintf("%s", face), h.cfg.EmojiFolder)
+ if err != nil {
+ serverError(w, err)
+ return
+ }
+
+ err = outputJPEG(img, w)
+ if err != nil {
+ serverError(w, err)
+ return
+ }
}
func truncate(s string, max int) string {