1
0
Fork 0
mirror of https://github.com/Luzifer/streamdeck.git synced 2024-12-20 09:41:19 +00:00

Add button caption rendering

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2020-08-09 18:34:06 +02:00
parent 90df45ac3d
commit 40ef541372
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
4 changed files with 83 additions and 7 deletions

View file

@ -1,9 +1,16 @@
package main package main
import "time" import (
"time"
)
type config struct { type config struct {
AutoReload bool `yaml:"auto_reload"` AutoReload bool `yaml:"auto_reload"`
CaptionBorder int `yaml:"caption_border"`
CaptionColor [4]int `yaml:"caption_color"`
CaptionFont string `yaml:"caption_font"`
CaptionFontSize float64 `yaml:"caption_font_size"`
CaptionPosition captionPosition `yaml:"caption_position"`
DefaultBrightness int `yaml:"default_brightness"` DefaultBrightness int `yaml:"default_brightness"`
DefaultPage string `yaml:"default_page"` DefaultPage string `yaml:"default_page"`
DisplayOffTime time.Duration `yaml:"display_off_time"` DisplayOffTime time.Duration `yaml:"display_off_time"`
@ -31,3 +38,10 @@ func newConfig() config {
AutoReload: true, AutoReload: true,
} }
} }
type captionPosition string
const (
captionPositionBottom = "bottom"
captionPositionTop = "top"
)

View file

@ -131,6 +131,12 @@ func (d displayElementExec) Display(ctx context.Context, idx int, attributes map
} }
} }
if caption, ok := attributes["caption"].(string); ok && strings.TrimSpace(caption) != "" {
if err = imgRenderer.DrawCaptionText(strings.TrimSpace(caption)); err != nil {
return errors.Wrap(err, "Unable to render caption")
}
}
if !d.running && d.NeedsLoop(attributes) { if !d.running && d.NeedsLoop(attributes) {
return nil return nil
} }

View file

@ -6,6 +6,7 @@ import (
"context" "context"
"fmt" "fmt"
"image/color" "image/color"
"strings"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -112,6 +113,12 @@ func (d displayElementPulseVolume) Display(ctx context.Context, idx int, attribu
return errors.Wrap(err, "Unable to draw text") return errors.Wrap(err, "Unable to draw text")
} }
if caption, ok := attributes["caption"].(string); ok && strings.TrimSpace(caption) != "" {
if err = img.DrawCaptionText(strings.TrimSpace(caption)); err != nil {
return errors.Wrap(err, "Unable to render caption")
}
}
if err = ctx.Err(); err != nil { if err = ctx.Err(); err != nil {
// Page context was cancelled, do not draw // Page context was cancelled, do not draw
return err return err

View file

@ -15,6 +15,14 @@ import (
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
type textDrawAnchor uint
const (
textDrawAnchorCenter textDrawAnchor = iota
textDrawAnchorBottom
textDrawAnchorTop
)
type textOnImageRenderer struct { type textOnImageRenderer struct {
img draw.Image img draw.Image
} }
@ -46,7 +54,7 @@ func (t *textOnImageRenderer) DrawBackgroundFromFile(filename string) error {
func (t *textOnImageRenderer) DrawBigText(text string, fontSizeHint float64, border int, textColor color.Color) error { func (t *textOnImageRenderer) DrawBigText(text string, fontSizeHint float64, border int, textColor color.Color) error {
// Render text // Render text
f, err := t.loadFont() f, err := t.loadFont(userConfig.RenderFont)
if err != nil { if err != nil {
return errors.Wrap(err, "Unable to load font") return errors.Wrap(err, "Unable to load font")
} }
@ -58,12 +66,44 @@ func (t *textOnImageRenderer) DrawBigText(text string, fontSizeHint float64, bor
c.SetFont(f) c.SetFont(f)
c.SetHinting(font.HintingNone) c.SetHinting(font.HintingNone)
return t.drawText(c, text, textColor, fontSizeHint, border) return t.drawText(c, text, textColor, fontSizeHint, border, textDrawAnchorCenter)
}
func (t *textOnImageRenderer) DrawCaptionText(text string) error {
// Render text
f, err := t.loadFont(userConfig.CaptionFont)
if err != nil {
return errors.Wrap(err, "Unable to load font")
}
var textColor color.Color = color.RGBA{0xff, 0xff, 0xff, 0xff}
if userConfig.CaptionColor[3] != 0x0 {
textColor = color.RGBA{
uint8(userConfig.CaptionColor[0]),
uint8(userConfig.CaptionColor[1]),
uint8(userConfig.CaptionColor[2]),
uint8(userConfig.CaptionColor[3]),
}
}
var anchor = textDrawAnchorBottom
if userConfig.CaptionPosition == "top" {
anchor = textDrawAnchorTop
}
c := freetype.NewContext()
c.SetClip(t.img.Bounds())
c.SetDPI(72)
c.SetDst(t.img)
c.SetFont(f)
c.SetHinting(font.HintingNone)
return t.drawText(c, text, textColor, userConfig.CaptionFontSize, userConfig.CaptionBorder, anchor)
} }
func (t textOnImageRenderer) GetImage() image.Image { return t.img } func (t textOnImageRenderer) GetImage() image.Image { return t.img }
func (t *textOnImageRenderer) drawText(c *freetype.Context, text string, textColor color.Color, fontsize float64, border int) error { func (t *textOnImageRenderer) drawText(c *freetype.Context, text string, textColor color.Color, fontsize float64, border int, anchor textDrawAnchor) error {
c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing
textLines := strings.Split(text, "\n") textLines := strings.Split(text, "\n")
@ -92,9 +132,18 @@ func (t *textOnImageRenderer) drawText(c *freetype.Context, text string, textCol
var ( var (
yTotal = (int(c.PointToFixed(fontsize)/64))*len(textLines) + (len(textLines)-1)*2 yTotal = (int(c.PointToFixed(fontsize)/64))*len(textLines) + (len(textLines)-1)*2
yLineTop = int(float64(sd.IconSize())/2.0 - float64(yTotal)/2.0) yLineTop int
) )
switch anchor {
case textDrawAnchorTop:
yLineTop = border
case textDrawAnchorCenter:
yLineTop = int(float64(sd.IconSize())/2.0 - float64(yTotal)/2.0)
case textDrawAnchorBottom:
yLineTop = sd.IconSize() - yTotal - border
}
for _, tl := range textLines { for _, tl := range textLines {
c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing
ext, err := c.DrawString(tl, freetype.Pt(0, 0)) ext, err := c.DrawString(tl, freetype.Pt(0, 0))
@ -132,8 +181,8 @@ func (textOnImageRenderer) getImageFromDisk(filename string) (image.Image, error
return img, nil return img, nil
} }
func (textOnImageRenderer) loadFont() (*truetype.Font, error) { func (textOnImageRenderer) loadFont(fontfile string) (*truetype.Font, error) {
fontRaw, err := ioutil.ReadFile(userConfig.RenderFont) fontRaw, err := ioutil.ReadFile(fontfile)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Unable to read font file") return nil, errors.Wrap(err, "Unable to read font file")
} }