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:
parent
90df45ac3d
commit
40ef541372
4 changed files with 83 additions and 7 deletions
|
@ -1,9 +1,16 @@
|
|||
package main
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
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"`
|
||||
DefaultPage string `yaml:"default_page"`
|
||||
DisplayOffTime time.Duration `yaml:"display_off_time"`
|
||||
|
@ -31,3 +38,10 @@ func newConfig() config {
|
|||
AutoReload: true,
|
||||
}
|
||||
}
|
||||
|
||||
type captionPosition string
|
||||
|
||||
const (
|
||||
captionPositionBottom = "bottom"
|
||||
captionPositionTop = "top"
|
||||
)
|
||||
|
|
|
@ -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) {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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")
|
||||
}
|
||||
|
||||
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 {
|
||||
// Page context was cancelled, do not draw
|
||||
return err
|
||||
|
|
|
@ -15,6 +15,14 @@ import (
|
|||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
type textDrawAnchor uint
|
||||
|
||||
const (
|
||||
textDrawAnchorCenter textDrawAnchor = iota
|
||||
textDrawAnchorBottom
|
||||
textDrawAnchorTop
|
||||
)
|
||||
|
||||
type textOnImageRenderer struct {
|
||||
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 {
|
||||
// Render text
|
||||
f, err := t.loadFont()
|
||||
f, err := t.loadFont(userConfig.RenderFont)
|
||||
if err != nil {
|
||||
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.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) 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
|
||||
|
||||
textLines := strings.Split(text, "\n")
|
||||
|
@ -92,9 +132,18 @@ func (t *textOnImageRenderer) drawText(c *freetype.Context, text string, textCol
|
|||
|
||||
var (
|
||||
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 {
|
||||
c.SetSrc(image.NewUniform(color.RGBA{0x0, 0x0, 0x0, 0x0})) // Transparent for text size guessing
|
||||
ext, err := c.DrawString(tl, freetype.Pt(0, 0))
|
||||
|
@ -132,8 +181,8 @@ func (textOnImageRenderer) getImageFromDisk(filename string) (image.Image, error
|
|||
return img, nil
|
||||
}
|
||||
|
||||
func (textOnImageRenderer) loadFont() (*truetype.Font, error) {
|
||||
fontRaw, err := ioutil.ReadFile(userConfig.RenderFont)
|
||||
func (textOnImageRenderer) loadFont(fontfile string) (*truetype.Font, error) {
|
||||
fontRaw, err := ioutil.ReadFile(fontfile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to read font file")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue