init
This commit is contained in:
commit
d69342b2e9
160 changed files with 28681 additions and 0 deletions
185
internal/og/og.go
Normal file
185
internal/og/og.go
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
package og
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
|
||||
"github.com/golang/freetype"
|
||||
"github.com/golang/freetype/truetype"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/font/gofont/goregular"
|
||||
"golang.org/x/image/font/gofont/gobold"
|
||||
)
|
||||
|
||||
const (
|
||||
imgWidth = 1200
|
||||
imgHeight = 630
|
||||
)
|
||||
|
||||
var (
|
||||
regularFont *truetype.Font
|
||||
boldFont *truetype.Font
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
regularFont, err = freetype.ParseFont(goregular.TTF)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
boldFont, err = freetype.ParseFont(gobold.TTF)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func parseHexColor(hex string) color.RGBA {
|
||||
if len(hex) == 0 {
|
||||
return color.RGBA{16, 185, 129, 255} // #10b981 emerald
|
||||
}
|
||||
if hex[0] == '#' {
|
||||
hex = hex[1:]
|
||||
}
|
||||
if len(hex) != 6 {
|
||||
return color.RGBA{16, 185, 129, 255} // #10b981 emerald
|
||||
}
|
||||
|
||||
var r, g, b uint8
|
||||
for i, c := range hex {
|
||||
var v uint8
|
||||
switch {
|
||||
case c >= '0' && c <= '9':
|
||||
v = uint8(c - '0')
|
||||
case c >= 'a' && c <= 'f':
|
||||
v = uint8(c - 'a' + 10)
|
||||
case c >= 'A' && c <= 'F':
|
||||
v = uint8(c - 'A' + 10)
|
||||
}
|
||||
switch i {
|
||||
case 0:
|
||||
r = v << 4
|
||||
case 1:
|
||||
r |= v
|
||||
case 2:
|
||||
g = v << 4
|
||||
case 3:
|
||||
g |= v
|
||||
case 4:
|
||||
b = v << 4
|
||||
case 5:
|
||||
b |= v
|
||||
}
|
||||
}
|
||||
return color.RGBA{r, g, b, 255}
|
||||
}
|
||||
|
||||
func Generate(title, siteName, accentColor string) ([]byte, error) {
|
||||
accent := parseHexColor(accentColor)
|
||||
|
||||
img := image.NewRGBA(image.Rect(0, 0, imgWidth, imgHeight))
|
||||
|
||||
for y := 0; y < imgHeight; y++ {
|
||||
ratio := float64(y) / float64(imgHeight)
|
||||
r := uint8(float64(accent.R) * (1 - ratio*0.3))
|
||||
g := uint8(float64(accent.G) * (1 - ratio*0.3))
|
||||
b := uint8(float64(accent.B) * (1 - ratio*0.3))
|
||||
for x := 0; x < imgWidth; x++ {
|
||||
img.Set(x, y, color.RGBA{r, g, b, 255})
|
||||
}
|
||||
}
|
||||
|
||||
c := freetype.NewContext()
|
||||
c.SetDPI(72)
|
||||
c.SetClip(img.Bounds())
|
||||
c.SetDst(img)
|
||||
c.SetSrc(image.White)
|
||||
c.SetHinting(font.HintingFull)
|
||||
|
||||
titleSize := 64.0
|
||||
if len(title) > 50 {
|
||||
titleSize = 48.0
|
||||
}
|
||||
if len(title) > 80 {
|
||||
titleSize = 40.0
|
||||
}
|
||||
|
||||
c.SetFont(boldFont)
|
||||
c.SetFontSize(titleSize)
|
||||
|
||||
wrapped := wrapText(title, 28)
|
||||
y := 200
|
||||
for _, line := range wrapped {
|
||||
pt := freetype.Pt(80, y)
|
||||
c.DrawString(line, pt)
|
||||
y += int(titleSize * 1.4)
|
||||
}
|
||||
|
||||
c.SetFont(regularFont)
|
||||
c.SetFontSize(28)
|
||||
pt := freetype.Pt(80, imgHeight-80)
|
||||
c.DrawString(siteName, pt)
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func wrapText(text string, maxChars int) []string {
|
||||
if len(text) <= maxChars {
|
||||
return []string{text}
|
||||
}
|
||||
|
||||
var lines []string
|
||||
words := splitWords(text)
|
||||
var current string
|
||||
|
||||
for _, word := range words {
|
||||
if current == "" {
|
||||
current = word
|
||||
} else if len(current)+1+len(word) <= maxChars {
|
||||
current += " " + word
|
||||
} else {
|
||||
lines = append(lines, current)
|
||||
current = word
|
||||
}
|
||||
}
|
||||
if current != "" {
|
||||
lines = append(lines, current)
|
||||
}
|
||||
|
||||
if len(lines) > 4 {
|
||||
lines = lines[:4]
|
||||
if len(lines[3]) > 3 {
|
||||
lines[3] = lines[3][:len(lines[3])-3] + "..."
|
||||
}
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func splitWords(s string) []string {
|
||||
var words []string
|
||||
var current string
|
||||
for _, r := range s {
|
||||
if r == ' ' || r == '\t' || r == '\n' {
|
||||
if current != "" {
|
||||
words = append(words, current)
|
||||
current = ""
|
||||
}
|
||||
} else {
|
||||
current += string(r)
|
||||
}
|
||||
}
|
||||
if current != "" {
|
||||
words = append(words, current)
|
||||
}
|
||||
return words
|
||||
}
|
||||
|
||||
var _ = draw.Draw
|
||||
Loading…
Add table
Add a link
Reference in a new issue